]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
[master] Emit better error messages for command line issues
authorShawn Routhier <sar@isc.org>
Thu, 7 Jan 2016 00:32:25 +0000 (16:32 -0800)
committerShawn Routhier <sar@isc.org>
Thu, 7 Jan 2016 00:32:25 +0000 (16:32 -0800)
When emitting an error message due to a bad command line try to
include information about the argument that is at fault.

RELNOTES
client/dhclient.c
includes/site.h
relay/dhcrelay.c
server/dhcpd.c

index 7f69f55862cdf5fdf9eac89d5892975b062c7158..3b5435c27537777b8d805a37b19aba9eb9fd22f8 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -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
 
index 5583ca1709c7468dd49a9d1577086c29e9110686..7a4ee1eb8b82d77244af1c29868e24d4662c5ef7 100644 (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();
index 7c6d843133945c76bce2cf6218214776772892a0..a36e322ce5d37e5254c6628b61737f505d02b8b7 100644 (file)
    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 
index 67933de1155e9225a27c91dcc7d0524a8e494f61..6095ebcf2948fe8bff7ae7264b57ba406c99638c 100644 (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. */
index 792684d1531225ad6d27dc98de1a06935961184f..abc63df9bb4a6736f9ee900607425f150f9721ac 100644 (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;