]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
[v4_1_esv] Emit better error messages for command line issues
authorShawn Routhier <sar@isc.org>
Thu, 7 Jan 2016 01:27:31 +0000 (17:27 -0800)
committerShawn Routhier <sar@isc.org>
Thu, 7 Jan 2016 01:27:31 +0000 (17:27 -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 0bb6db6bafc9863e0a265a40d02e85b1a986c444..958d5347fad8f362199bb83511ceadf4bd840bf4 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -120,6 +120,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.1-ESV-R12b1
 
 - None
index 1912e2d90cfe02077196b276397e9d2884e32f15..75fd94d57cd1418629e6613818fe829f7268aa38 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
@@ -93,8 +93,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);
 
@@ -103,6 +101,52 @@ static int check_domain_name_list(const char *ptr, size_t len, int dots);
 static int check_option_values(struct universe *universe, unsigned int opt,
                               const char *ptr, size_t len);
 
+/*!
+ *
+ * \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_v6command[] = "Command not used for DHCPv4: %s";
+
+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] [-SNTPR1dvrx] [-nw] [-p <port>]\n"
+#else /* DHCPv6 */
+                 "[-1dvrx] [-nw] [-p <port>]\n"
+#endif /* DHCPv6 */
+                 "                [-s server-addr] [-cf config-file] "
+                 "[-lf lease-file]\n"
+                 "                [-pf pid-file] [--no-pid] [-e VAR=val]\n"
+                 "                [-sf script-file] [interface]",
+                 isc_file_basename(progname));
+}
+
 int
 main(int argc, char **argv) {
        int fd;
@@ -201,7 +245,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));
@@ -210,24 +254,24 @@ 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], "-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")) {
@@ -236,11 +280,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;
@@ -253,7 +297,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]);
@@ -264,7 +308,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;
@@ -272,7 +316,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;
@@ -282,7 +326,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;
@@ -292,7 +336,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;
@@ -302,7 +346,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;
@@ -320,9 +364,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;
 
@@ -351,7 +396,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"))) {
@@ -488,7 +533,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;
@@ -714,27 +760,6 @@ main(int argc, char **argv) {
        return 0;
 }
 
-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] [-SNTPR1dvrx] [-nw] [-p <port>]\n"
-#else /* DHCPv6 */
-                 "[-1dvrx] [-nw] [-p <port>]\n"
-#endif /* DHCPv6 */
-                 "                [-s server-addr] [-cf config-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
@@ -746,7 +771,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 829657c9105b0c670c67026ea519a7fd13685a2e..009c7bad670bf11c1a97f70eb190adb1b537a163 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
index 8ab1d0878ca6f34aaf83a675958fae1e0599e8d4..d894045ff10a2e0f45677d6179ff8b50409f3263 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
@@ -157,7 +157,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),
@@ -227,13 +255,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;
@@ -245,29 +273,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 "
@@ -286,7 +314,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;
@@ -295,13 +323,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]);
 
@@ -312,13 +340,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")) {
@@ -328,11 +356,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;
@@ -341,39 +369,39 @@ 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;
 #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")) {
@@ -390,14 +418,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;
@@ -509,7 +537,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. */
@@ -1170,8 +1198,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 51f4ae52c2ce4aa4598150a2ffd4edf48e5be5e3..934057cfbdb8a3017d325965d7f51b4ba770f23e 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
@@ -56,10 +56,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;
 
@@ -214,6 +210,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.
  */
@@ -320,7 +364,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));
@@ -335,35 +379,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")) {
@@ -408,16 +452,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;
@@ -1208,34 +1252,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;