2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-22 01:49:35 +00:00

[master] Emit better error messages for command line issues

When emitting an error message due to a bad command line try to
include information about the argument that is at fault.
This commit is contained in:
Shawn Routhier 2016-01-06 16:32:25 -08:00
parent 4ce21cb630
commit b2cb745bd4
5 changed files with 203 additions and 118 deletions

View File

@ -130,6 +130,11 @@ by Eric Young (eay@cryptsoft.com).
patch.
[ISC-Bugs #41267]
- When handling an incorrect command line for dhcpd, dhclient or dhcrelay
print out a specific error message about the first error in addition
to the usage string. This may be disabled by editing includes/site.h.
[ISC-Bugs #40321]
Changes since 4.3.3b1
- None

View File

@ -3,7 +3,7 @@
DHCP Client. */
/*
* Copyright (c) 2004-2015 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 2004-2016 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1995-2003 by Internet Software Consortium
*
* Permission to use, copy, modify, and distribute this software for any
@ -97,8 +97,6 @@ char *progname = NULL;
void run_stateless(int exit_mode);
static void usage(void);
static isc_result_t write_duid(struct data_string *duid);
static void add_reject(struct packet *packet);
@ -110,6 +108,57 @@ static int check_option_values(struct universe *universe, unsigned int opt,
static void dhclient_ddns_cb_free(dhcp_ddns_cb_t *ddns_cb,
char* file, int line);
/*!
*
* \brief Print the generic usage message
*
* If the user has provided an incorrect command line print out
* the description of the command line. The arguments provide
* a way for the caller to request more specific information about
* the error be printed as well. Mostly this will be that some
* comamnd doesn't include its argument.
*
* \param sfmt - The basic string and format for the specific error
* \param sarg - Generally the offending argument from the comamnd line.
*
* \return Nothing
*/
#ifndef UNIT_TEST
/* These are only used when we call usage() from the main routine
* which isn't compiled when building for unit tests
*/
static const char use_noarg[] = "No argument for command: %s";
static const char use_v6command[] = "Command not used for DHCPv4: %s";
#endif /* !UNIT_TEST */
static void
usage(const char *sfmt, const char *sarg)
{
log_info("%s %s", message, PACKAGE_VERSION);
log_info(copyright);
log_info(arr);
log_info(url);
/* If desired print out the specific error message */
#ifdef PRINT_SPECIFIC_CL_ERRORS
if (sfmt != NULL)
log_error(sfmt, sarg);
#endif
log_fatal("Usage: %s "
#ifdef DHCPv6
"[-4|-6] [-SNTPRI1dvrxi] [-nw] [-p <port>] [-D LL|LLT] \n"
#else /* DHCPv6 */
"[-I1dvrxi] [-nw] [-p <port>] [-D LL|LLT] \n"
#endif /* DHCPv6 */
" [-s server-addr] [-cf config-file]\n"
" [-df duid-file] [-lf lease-file]\n"
" [-pf pid-file] [--no-pid] [-e VAR=val]\n"
" [-sf script-file] [interface]",
isc_file_basename(progname));
}
#ifndef UNIT_TEST
int
main(int argc, char **argv) {
@ -208,7 +257,7 @@ main(int argc, char **argv) {
exit_mode = 1;
} else if (!strcmp(argv[i], "-p")) {
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
local_port = validate_port(argv[i]);
log_debug("binding to user-specified port %d",
ntohs(local_port));
@ -217,28 +266,28 @@ main(int argc, char **argv) {
quiet = 0;
} else if (!strcmp(argv[i], "-pf")) {
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
path_dhclient_pid = argv[i];
no_dhclient_pid = 1;
} else if (!strcmp(argv[i], "--no-pid")) {
no_pid_file = ISC_TRUE;
} else if (!strcmp(argv[i], "-cf")) {
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
path_dhclient_conf = argv[i];
no_dhclient_conf = 1;
} else if (!strcmp(argv[i], "-df")) {
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
path_dhclient_duid = argv[i];
} else if (!strcmp(argv[i], "-lf")) {
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
path_dhclient_db = argv[i];
no_dhclient_db = 1;
} else if (!strcmp(argv[i], "-sf")) {
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
path_dhclient_script = argv[i];
no_dhclient_script = 1;
} else if (!strcmp(argv[i], "-1")) {
@ -247,11 +296,11 @@ main(int argc, char **argv) {
quiet = 1;
} else if (!strcmp(argv[i], "-s")) {
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
server = argv[i];
} else if (!strcmp(argv[i], "-g")) {
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
mockup_relay = argv[i];
} else if (!strcmp(argv[i], "-nw")) {
nowait = 1;
@ -264,7 +313,7 @@ main(int argc, char **argv) {
} else if (!strcmp(argv[i], "-e")) {
struct string_list *tmp;
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
tmp = dmalloc(strlen(argv[i]) + sizeof *tmp, MDL);
if (!tmp)
log_fatal("No memory for %s", argv[i]);
@ -275,7 +324,7 @@ main(int argc, char **argv) {
#ifdef DHCPv6
} else if (!strcmp(argv[i], "-S")) {
if (local_family_set && (local_family == AF_INET)) {
usage();
usage(use_v6command, argv[i]);
}
local_family_set = 1;
local_family = AF_INET6;
@ -283,7 +332,7 @@ main(int argc, char **argv) {
stateless = 1;
} else if (!strcmp(argv[i], "-N")) {
if (local_family_set && (local_family == AF_INET)) {
usage();
usage(use_v6command, argv[i]);
}
local_family_set = 1;
local_family = AF_INET6;
@ -293,7 +342,7 @@ main(int argc, char **argv) {
wanted_ia_na++;
} else if (!strcmp(argv[i], "-T")) {
if (local_family_set && (local_family == AF_INET)) {
usage();
usage(use_v6command, argv[i]);
}
local_family_set = 1;
local_family = AF_INET6;
@ -303,7 +352,7 @@ main(int argc, char **argv) {
wanted_ia_ta++;
} else if (!strcmp(argv[i], "-P")) {
if (local_family_set && (local_family == AF_INET)) {
usage();
usage(use_v6command, argv[i]);
}
local_family_set = 1;
local_family = AF_INET6;
@ -313,7 +362,7 @@ main(int argc, char **argv) {
wanted_ia_pd++;
} else if (!strcmp(argv[i], "-R")) {
if (local_family_set && (local_family == AF_INET)) {
usage();
usage(use_v6command, argv[i]);
}
local_family_set = 1;
local_family = AF_INET6;
@ -322,13 +371,13 @@ main(int argc, char **argv) {
} else if (!strcmp(argv[i], "-D")) {
duid_v4 = 1;
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
if (!strcasecmp(argv[i], "LL")) {
duid_type = DUID_LL;
} else if (!strcasecmp(argv[i], "LLT")) {
duid_type = DUID_LLT;
} else {
usage();
usage("Unknown argument to -D: %s", argv[i]);
}
} else if (!strcmp(argv[i], "-i")) {
/* enable DUID support for DHCPv4 clients */
@ -348,9 +397,10 @@ main(int argc, char **argv) {
IGNORE_RET(write(STDERR_FILENO, "\n", 1));
exit(0);
} else if (argv[i][0] == '-') {
usage();
usage("Unknown command: %s", argv[i]);
} else if (interfaces_requested < 0) {
usage();
usage("No interfaces comamnd -n and "
" requested interface %s", argv[i]);
} else {
struct interface_info *tmp = NULL;
@ -379,7 +429,7 @@ main(int argc, char **argv) {
/* Support only one (requested) interface for Prefix Delegation. */
if (wanted_ia_pd && (interfaces_requested != 1)) {
usage();
usage("PD %s only supports one requested interface", "-P");
}
if (!no_dhclient_conf && (s = getenv("PATH_DHCLIENT_CONF"))) {
@ -517,7 +567,8 @@ main(int argc, char **argv) {
if (release_mode || (wanted_ia_na > 0) ||
wanted_ia_ta || wanted_ia_pd ||
(interfaces_requested != 1)) {
usage();
usage("Stateless commnad: %s incompatibile with "
"other commands", "-S");
}
run_stateless(exit_mode);
return 0;
@ -761,27 +812,6 @@ main(int argc, char **argv) {
}
#endif /* !UNIT_TEST */
static void usage()
{
log_info("%s %s", message, PACKAGE_VERSION);
log_info(copyright);
log_info(arr);
log_info(url);
log_fatal("Usage: %s "
#ifdef DHCPv6
"[-4|-6] [-SNTPRI1dvrxi] [-nw] [-p <port>] [-D LL|LLT] \n"
#else /* DHCPv6 */
"[-I1dvrxi] [-nw] [-p <port>] [-D LL|LLT] \n"
#endif /* DHCPv6 */
" [-s server-addr] [-cf config-file]\n"
" [-df duid-file] [-lf lease-file]\n"
" [-pf pid-file] [--no-pid] [-e VAR=val]\n"
" [-sf script-file] [interface]",
isc_file_basename(progname));
}
void run_stateless(int exit_mode)
{
#ifdef DHCPv6
@ -793,7 +823,7 @@ void run_stateless(int exit_mode)
discover_interfaces(DISCOVER_REQUESTED);
if (!interfaces)
usage();
usage("No interfaces available for stateless command: %s", "-S");
/* Parse the dhclient.conf file. */
read_client_conf();

View File

@ -305,6 +305,13 @@
from a single server and there won't be a difference. */
/* #define USE_ORIGINAL_CLIENT_LEASE_WEIGHTS */
/* Print out specific error messages for dhclient, dhcpd
or dhcrelay when processing an incorrect command line. This
is included for those that might require the exact error
messages, as we don't expect that is necessary it is on by
default. */
#define PRINT_SPECIFIC_CL_ERRORS
/* Include definitions for various options. In general these
should be left as is, but if you have already defined one
of these and prefer your definition you can comment the

View File

@ -3,7 +3,7 @@
DHCP/BOOTP Relay Agent. */
/*
* Copyright(c) 2004-2015 by Internet Systems Consortium, Inc.("ISC")
* Copyright(c) 2004-2016 by Internet Systems Consortium, Inc.("ISC")
* Copyright(c) 1997-2003 by Internet Software Consortium
*
* Permission to use, copy, modify, and distribute this software for any
@ -167,7 +167,35 @@ char *progname;
" server0 [ ... serverN]\n\n"
#endif
static void usage() {
/*!
*
* \brief Print the generic usage message
*
* If the user has provided an incorrect command line print out
* the description of the command line. The arguments provide
* a way for the caller to request more specific information about
* the error be printed as well. Mostly this will be that some
* comamnd doesn't include its argument.
*
* \param sfmt - The basic string and format for the specific error
* \param sarg - Generally the offending argument from the comamnd line.
*
* \return Nothing
*/
static const char use_noarg[] = "No argument for command: %s";
static const char use_badproto[] = "Protocol already set, %s inappropriate";
static const char use_v4command[] = "Command not used for DHCPv6: %s";
static const char use_v6command[] = "Command not used for DHCPv4: %s";
static void
usage(const char *sfmt, const char *sarg) {
/* If desired print out the specific error message */
#ifdef PRINT_SPECIFIC_CL_ERRORS
if (sfmt != NULL)
log_error(sfmt, sarg);
#endif
log_fatal(DHCRELAY_USAGE,
#ifdef DHCPv6
isc_file_basename(progname),
@ -236,13 +264,13 @@ main(int argc, char **argv) {
if (!strcmp(argv[i], "-4")) {
#ifdef DHCPv6
if (local_family_set && (local_family == AF_INET6)) {
usage();
usage(use_badproto, "-4");
}
local_family_set = 1;
local_family = AF_INET;
} else if (!strcmp(argv[i], "-6")) {
if (local_family_set && (local_family == AF_INET)) {
usage();
usage(use_badproto, "-6");
}
local_family_set = 1;
local_family = AF_INET6;
@ -254,29 +282,29 @@ main(int argc, char **argv) {
quiet_interface_discovery = 1;
} else if (!strcmp(argv[i], "-p")) {
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
local_port = validate_port(argv[i]);
log_debug("binding to user-specified port %d",
ntohs(local_port));
} else if (!strcmp(argv[i], "-c")) {
int hcount;
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
hcount = atoi(argv[i]);
if (hcount <= 255)
max_hop_count= hcount;
else
usage();
usage("Bad hop count to -c: %s", argv[i]);
} else if (!strcmp(argv[i], "-i")) {
#ifdef DHCPv6
if (local_family_set && (local_family == AF_INET6)) {
usage();
usage(use_v4command, argv[i]);
}
local_family_set = 1;
local_family = AF_INET;
#endif
if (++i == argc) {
usage();
usage(use_noarg, argv[i-1]);
}
if (strlen(argv[i]) >= sizeof(tmp->name)) {
log_fatal("%s: interface name too long "
@ -295,7 +323,7 @@ main(int argc, char **argv) {
} else if (!strcmp(argv[i], "-a")) {
#ifdef DHCPv6
if (local_family_set && (local_family == AF_INET6)) {
usage();
usage(use_v4command, argv[i]);
}
local_family_set = 1;
local_family = AF_INET;
@ -304,13 +332,13 @@ main(int argc, char **argv) {
} else if (!strcmp(argv[i], "-A")) {
#ifdef DHCPv6
if (local_family_set && (local_family == AF_INET6)) {
usage();
usage(use_v4command, argv[i]);
}
local_family_set = 1;
local_family = AF_INET;
#endif
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
dhcp_max_agent_option_packet_length = atoi(argv[i]);
@ -321,13 +349,13 @@ main(int argc, char **argv) {
} else if (!strcmp(argv[i], "-m")) {
#ifdef DHCPv6
if (local_family_set && (local_family == AF_INET6)) {
usage();
usage(use_v4command, argv[i]);
}
local_family_set = 1;
local_family = AF_INET;
#endif
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
if (!strcasecmp(argv[i], "append")) {
agent_relay_mode = forward_and_append;
} else if (!strcasecmp(argv[i], "replace")) {
@ -337,11 +365,11 @@ main(int argc, char **argv) {
} else if (!strcasecmp(argv[i], "discard")) {
agent_relay_mode = discard;
} else
usage();
usage("Unknown argument to -m: %s", argv[i]);
} else if (!strcmp(argv[i], "-D")) {
#ifdef DHCPv6
if (local_family_set && (local_family == AF_INET6)) {
usage();
usage(use_v4command, argv[i]);
}
local_family_set = 1;
local_family = AF_INET;
@ -350,48 +378,48 @@ main(int argc, char **argv) {
#ifdef DHCPv6
} else if (!strcmp(argv[i], "-I")) {
if (local_family_set && (local_family == AF_INET)) {
usage();
usage(use_v6command, argv[i]);
}
local_family_set = 1;
local_family = AF_INET6;
use_if_id = ISC_TRUE;
} else if (!strcmp(argv[i], "-l")) {
if (local_family_set && (local_family == AF_INET)) {
usage();
usage(use_v6command, argv[i]);
}
local_family_set = 1;
local_family = AF_INET6;
if (downstreams != NULL)
use_if_id = ISC_TRUE;
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
sl = parse_downstream(argv[i]);
sl->next = downstreams;
downstreams = sl;
} else if (!strcmp(argv[i], "-u")) {
if (local_family_set && (local_family == AF_INET)) {
usage();
usage(use_v6command, argv[i]);
}
local_family_set = 1;
local_family = AF_INET6;
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
sl = parse_upstream(argv[i]);
sl->next = upstreams;
upstreams = sl;
} else if (!strcmp(argv[i], "-s")) {
if (local_family_set && (local_family == AF_INET)) {
usage();
usage(use_v6command, argv[i]);
}
local_family_set = 1;
local_family = AF_INET6;
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
dhcrelay_sub_id = argv[i];
#endif
} else if (!strcmp(argv[i], "-pf")) {
if (++i == argc)
usage();
usage(use_noarg, argv[i-1]);
path_dhcrelay_pid = argv[i];
no_dhcrelay_pid = ISC_TRUE;
} else if (!strcmp(argv[i], "--no-pid")) {
@ -408,14 +436,14 @@ main(int argc, char **argv) {
isc_file_basename(progname));
exit(0);
} else if (argv[i][0] == '-') {
usage();
usage("Unknown command: %s", argv[i]);
} else {
struct hostent *he;
struct in_addr ia, *iap = NULL;
#ifdef DHCPv6
if (local_family_set && (local_family == AF_INET6)) {
usage();
usage(use_v4command, argv[i]);
}
local_family_set = 1;
local_family = AF_INET;
@ -527,7 +555,7 @@ main(int argc, char **argv) {
if (upstreams == NULL || downstreams == NULL) {
log_info("Must specify at least one lower "
"and one upper interface.\n");
usage();
usage(NULL, NULL);
}
/* Set up the initial dhcp option universe. */
@ -1195,8 +1223,7 @@ parse_downstream(char *arg) {
*iid++ = '\0';
}
if (strlen(ifname) >= sizeof(ifp->name)) {
log_error("Interface name '%s' too long", ifname);
usage();
usage("Interface name '%s' too long", ifname);
}
/* Don't declare twice. */

View File

@ -3,7 +3,7 @@
DHCP Server Daemon. */
/*
* Copyright (c) 2004-2015 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 2004-2016 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996-2003 by Internet Software Consortium
*
* Permission to use, copy, modify, and distribute this software for any
@ -57,10 +57,6 @@ uid_t set_uid = 0;
gid_t set_gid = 0;
#endif /* PARANOIA */
#ifndef UNIT_TEST
static void usage(void);
#endif
struct iaddr server_identifier;
int server_identifier_matched;
@ -137,6 +133,54 @@ static void omapi_listener_start (void *foo)
#ifndef UNIT_TEST
/*!
*
* \brief Print the generic usage message
*
* If the user has provided an incorrect command line print out
* the description of the command line. The arguments provide
* a way for the caller to request more specific information about
* the error be printed as well. Mostly this will be that some
* comamnd doesn't include its argument.
*
* \param sfmt - The basic string and format for the specific error
* \param sarg - Generally the offending argument from the comamnd line.
*
* \return Nothing
*/
static char use_noarg[] = "No argument for command: %s ";
static void
usage(const char *sfmt, const char *sarg) {
log_info("%s %s", message, PACKAGE_VERSION);
log_info(copyright);
log_info(arr);
/* If desired print out the specific error message */
#ifdef PRINT_SPECIFIC_CL_ERRORS
if (sfmt != NULL)
log_error(sfmt, sarg);
#endif
log_fatal("Usage: %s [-p <UDP port #>] [-f] [-d] [-q] [-t|-T]\n"
#ifdef DHCPv6
" [-4|-6] [-cf config-file] [-lf lease-file]\n"
#else /* !DHCPv6 */
" [-cf config-file] [-lf lease-file]\n"
#endif /* DHCPv6 */
#if defined (PARANOIA)
/* meld into the following string */
" [-user user] [-group group] [-chroot dir]\n"
#endif /* PARANOIA */
#if defined (TRACING)
" [-tf trace-output-file]\n"
" [-play trace-input-file]\n"
#endif /* TRACING */
" [-pf pid-file] [--no-pid] [-s server]\n"
" [if0 [...ifN]]",
isc_file_basename(progname));
}
/* Note: If we add unit tests to test setup_chroot it will
* need to be moved to be outside the ifndef UNIT_TEST block.
*/
@ -244,7 +288,7 @@ main(int argc, char **argv) {
for (i = 1; i < argc; i++) {
if (!strcmp (argv [i], "-p")) {
if (++i == argc)
usage ();
usage(use_noarg, argv[i-1]);
local_port = validate_port (argv [i]);
log_debug ("binding to user-specified port %d",
ntohs (local_port));
@ -259,35 +303,35 @@ main(int argc, char **argv) {
log_perror = -1;
} else if (!strcmp (argv [i], "-s")) {
if (++i == argc)
usage ();
usage(use_noarg, argv[i-1]);
server = argv [i];
#if defined (PARANOIA)
} else if (!strcmp (argv [i], "-user")) {
if (++i == argc)
usage ();
usage(use_noarg, argv[i-1]);
set_user = argv [i];
} else if (!strcmp (argv [i], "-group")) {
if (++i == argc)
usage ();
usage(use_noarg, argv[i-1]);
set_group = argv [i];
} else if (!strcmp (argv [i], "-chroot")) {
if (++i == argc)
usage ();
usage(use_noarg, argv[i-1]);
set_chroot = argv [i];
#endif /* PARANOIA */
} else if (!strcmp (argv [i], "-cf")) {
if (++i == argc)
usage ();
usage(use_noarg, argv[i-1]);
path_dhcpd_conf = argv [i];
no_dhcpd_conf = 1;
} else if (!strcmp (argv [i], "-lf")) {
if (++i == argc)
usage ();
usage(use_noarg, argv[i-1]);
path_dhcpd_db = argv [i];
no_dhcpd_db = 1;
} else if (!strcmp (argv [i], "-pf")) {
if (++i == argc)
usage ();
usage(use_noarg, argv[i-1]);
path_dhcpd_pid = argv [i];
no_dhcpd_pid = 1;
} else if (!strcmp(argv[i], "--no-pid")) {
@ -338,16 +382,16 @@ main(int argc, char **argv) {
#if defined (TRACING)
} else if (!strcmp (argv [i], "-tf")) {
if (++i == argc)
usage ();
usage(use_noarg, argv[i-1]);
traceoutfile = argv [i];
} else if (!strcmp (argv [i], "-play")) {
if (++i == argc)
usage ();
usage(use_noarg, argv[i-1]);
traceinfile = argv [i];
trace_replay_init ();
#endif /* TRACING */
} else if (argv [i][0] == '-') {
usage ();
usage("Unknown command %s", argv[i]);
} else {
struct interface_info *tmp =
(struct interface_info *)0;
@ -1166,34 +1210,6 @@ void postdb_startup (void)
schedule_all_ipv6_lease_timeouts();
}
/* Print usage message. */
#ifndef UNIT_TEST
static void
usage(void) {
log_info("%s %s", message, PACKAGE_VERSION);
log_info(copyright);
log_info(arr);
log_fatal("Usage: %s [-p <UDP port #>] [-f] [-d] [-q] [-t|-T]\n"
#ifdef DHCPv6
" [-4|-6] [-cf config-file] [-lf lease-file]\n"
#else /* !DHCPv6 */
" [-cf config-file] [-lf lease-file]\n"
#endif /* DHCPv6 */
#if defined (PARANOIA)
/* meld into the following string */
" [-user user] [-group group] [-chroot dir]\n"
#endif /* PARANOIA */
#if defined (TRACING)
" [-tf trace-output-file]\n"
" [-play trace-input-file]\n"
#endif /* TRACING */
" [-pf pid-file] [--no-pid] [-s server]\n"
" [if0 [...ifN]]",
isc_file_basename(progname));
}
#endif
void lease_pinged (from, packet, length)
struct iaddr from;
u_int8_t *packet;