]> The Tcpdump Group git mirrors - libpcap/commitdiff
filtertest: Refine usage printing, exiting, etc.
authorDenis Ovsienko <[email protected]>
Wed, 29 Jan 2025 10:05:12 +0000 (10:05 +0000)
committerDenis Ovsienko <[email protected]>
Thu, 30 Jan 2025 18:21:18 +0000 (18:21 +0000)
usage() prints the synopsis only, always uses stderr and always exits
with an error code.  Add the "-h" flag with the standard behaviour of
printing a detailed usage message to stdout and exiting normally.
Condense the help screen so it fits into an 80-column terminal.  Use
various exit status codes from sysexits.h to make it easier to
differentiate various causes of failure and update TESTrun accordingly.
Initialize all variables at declaration time.  Use __func__ in an error
message.

testprogs/TESTrun
testprogs/filtertest.c
testprogs/unix.h

index ead349dfe5c94ad018e2a1aa2079a1cec1c8e8c9..6b1f3d50828bb90888d981ab645efc6dcef63c6e 100755 (executable)
@@ -5834,6 +5834,10 @@ my %reject_tests = (
 # On all platforms where timeout(1) is available it exits with status 124
 # if the command timed out.
 use constant TIMED_OUT => 124;
+# In this libpcap version filtertest exits with EX_DATAERR if the user input
+# is invalid and with other status codes for other (memory/file/etc) error
+# conditions.
+use constant EX_DATAERR => 65;
 
 my $tmpdir = File::Temp->newdir ('libpcap_TESTrun_XXXXXXXX', TMPDIR => 1); # Unlinks automatically.
 my $filename_expected = 'expected.txt';
@@ -5926,10 +5930,8 @@ sub print_result {
        printf "    %-40s: %s\n", @_;
 }
 
-# In this libpcap version a working filtertest, if invoked without arguments,
-# prints to stderr and exits with status 1.
-my $r = system ("$filtertest >/dev/null 2>&1") >> 8;
-if ($r != 1) {
+# In this libpcap version "filtertest -h" prints to stdout and exits normally.
+if (system ("$filtertest -h >/dev/null 2>&1") >> 8) {
        # Make it easier to see what the problem is.
        system $filtertest;
        print STDERR "ERROR: $filtertest is not usable\n";
@@ -5981,7 +5983,7 @@ sub run_accept_test {
                '>' . mytmpfile ($filename_stdout),
                "2>&1"
        );
-       $r = system (join ' ', @args) >> 8;
+       my $r = system (join ' ', @args) >> 8;
 
        return {
                char => CHAR_TIMED_OUT,
@@ -6022,7 +6024,7 @@ sub run_reject_test {
                '>' . mytmpfile ($filename_stdout),
                "2>&1",
        );
-       $r = system (join ' ', @args) >> 8;
+       my $r = system (join ' ', @args) >> 8;
 
        return {
                char => CHAR_FAILED,
@@ -6043,7 +6045,7 @@ sub run_reject_test {
                        reason => "filtertest status $r",
                        details => file_get_contents mytmpfile $filename_stdout
                }
-       } if $r != 1;
+       } if $r != EX_DATAERR;
 
        return {
                char => CHAR_FAILED,
index e669c1f62472bcf0be25c12bd36a34266d1bf531..be43de0e574bff1760b780719416d952a5683a05 100644 (file)
@@ -40,6 +40,7 @@ The Regents of the University of California.  All rights reserved.\n";
   #include "unix.h"
 #else
   #include <unistd.h>
+  #include <sysexits.h>
 #endif
 #include <fcntl.h>
 #include <errno.h>
@@ -86,8 +87,8 @@ PCAP_API void pcap_set_print_dot_graph(int);
 static char *program_name;
 
 /* Forwards */
-static void PCAP_NORETURN usage(void);
-static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2);
+static void PCAP_NORETURN usage(FILE *);
+static void PCAP_NORETURN error(const int, const char *, ...) PCAP_PRINTFLIKE(2, 3);
 static void warn(const char *, ...) PCAP_PRINTFLIKE(1, 2);
 
 /*
@@ -109,10 +110,10 @@ read_infile(char *fname)
 
        fd = open(fname, O_RDONLY|O_BINARY);
        if (fd < 0)
-               error("can't open %s: %s", fname, pcap_strerror(errno));
+               error(EX_NOINPUT, "can't open %s: %s", fname, pcap_strerror(errno));
 
        if (fstat(fd, &buf) < 0)
-               error("can't stat %s: %s", fname, pcap_strerror(errno));
+               error(EX_NOINPUT, "can't stat %s: %s", fname, pcap_strerror(errno));
 
        /*
         * _read(), on Windows, has an unsigned int byte count and an
@@ -122,17 +123,17 @@ read_infile(char *fname)
         * the end of the string.)
         */
        if (buf.st_size > INT_MAX - 1)
-               error("%s is larger than %d bytes; that's too large", fname,
+               error(EX_DATAERR, "%s is larger than %d bytes; that's too large", fname,
                    INT_MAX - 1);
        cp = malloc((u_int)buf.st_size + 1);
        if (cp == NULL)
-               error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
+               error(EX_OSERR, "malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
                        fname, pcap_strerror(errno));
        cc = (int)read(fd, cp, (u_int)buf.st_size);
        if (cc < 0)
-               error("read %s: %s", fname, pcap_strerror(errno));
+               error(EX_IOERR, "read %s: %s", fname, pcap_strerror(errno));
        if (cc != buf.st_size)
-               error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
+               error(EX_IOERR, "short read %s (%d != %d)", fname, cc, (int)buf.st_size);
 
        close(fd);
        /* replace "# comment" with spaces */
@@ -147,7 +148,7 @@ read_infile(char *fname)
 
 /* VARARGS */
 static void
-error(const char *fmt, ...)
+error(const int status, const char *fmt, ...)
 {
        va_list ap;
 
@@ -160,7 +161,7 @@ error(const char *fmt, ...)
                if (fmt[-1] != '\n')
                        (void)fputc('\n', stderr);
        }
-       exit(1);
+       exit(status);
        /* NOTREACHED */
 }
 
@@ -201,7 +202,7 @@ copy_argv(register char **argv)
 
        buf = (char *)malloc(len);
        if (buf == NULL)
-               error("copy_argv: malloc");
+               error(EX_OSERR, "%s: malloc", __func__);
 
        p = argv;
        dst = buf;
@@ -220,16 +221,16 @@ main(int argc, char **argv)
 {
        char *cp;
        int op;
-       int dflag;
+       int dflag = 1;
 #ifdef BDEBUG
-       int gflag;
+       int gflag = 0;
 #endif
-       char *infile;
-       int Oflag;
+       char *infile = NULL;
+       int Oflag = 1;
 #ifdef LINUX_BPF_EXT
        int lflag = 0;
 #endif
-       int snaplen;
+       int snaplen = MAXIMUM_SNAPLEN;
        char *p;
        int dlt;
        bpf_u_int32 netmask = PCAP_NETMASK_UNKNOWN;
@@ -243,24 +244,19 @@ main(int argc, char **argv)
                return 1;
 #endif /* _WIN32 */
 
-       dflag = 1;
-#ifdef BDEBUG
-       gflag = 0;
-#endif
-
-       infile = NULL;
-       Oflag = 1;
-       snaplen = MAXIMUM_SNAPLEN;
-
        if ((cp = strrchr(argv[0], '/')) != NULL)
                program_name = cp + 1;
        else
                program_name = argv[0];
 
        opterr = 0;
-       while ((op = getopt(argc, argv, "dF:gm:Os:l")) != -1) {
+       while ((op = getopt(argc, argv, "hdF:gm:Os:l")) != -1) {
                switch (op) {
 
+               case 'h':
+                       usage(stdout);
+                       /* NOTREACHED */
+
                case 'd':
                        ++dflag;
                        break;
@@ -270,7 +266,7 @@ main(int argc, char **argv)
                        ++gflag;
                        break;
 #else
-                       error("libpcap and filtertest not built with optimizer debugging enabled");
+                       error(EX_USAGE, "libpcap and filtertest not built with optimizer debugging enabled");
 #endif
 
                case 'F':
@@ -287,10 +283,10 @@ main(int argc, char **argv)
                        switch (inet_pton(AF_INET, optarg, &addr)) {
 
                        case 0:
-                               error("invalid netmask %s", optarg);
+                               error(EX_DATAERR, "invalid netmask %s", optarg);
 
                        case -1:
-                               error("invalid netmask %s: %s", optarg,
+                               error(EX_DATAERR, "invalid netmask %s: %s", optarg,
                                    pcap_strerror(errno));
 
                        case 1:
@@ -308,7 +304,7 @@ main(int argc, char **argv)
                        if (optarg == end || *end != '\0'
                            || long_snaplen < 0
                            || long_snaplen > MAXIMUM_SNAPLEN)
-                               error("invalid snaplen %s", optarg);
+                               error(EX_DATAERR, "invalid snaplen %s", optarg);
                        else {
                                if (snaplen == 0)
                                        snaplen = MAXIMUM_SNAPLEN;
@@ -324,17 +320,17 @@ main(int argc, char **argv)
                        lflag = 1;
                        break;
 #else
-                       error("libpcap and filtertest built without Linux BPF extensions");
+                       error(EX_USAGE, "libpcap and filtertest built without Linux BPF extensions");
 #endif
 
                default:
-                       usage();
+                       usage(stderr);
                        /* NOTREACHED */
                }
        }
 
        if (optind >= argc) {
-               usage();
+               usage(stderr);
                /* NOTREACHED */
        }
 
@@ -342,7 +338,7 @@ main(int argc, char **argv)
        if (dlt < 0) {
                dlt = (int)strtol(argv[optind], &p, 10);
                if (p == argv[optind] || *p != '\0')
-                       error("invalid data link type %s", argv[optind]);
+                       error(EX_DATAERR, "invalid data link type %s", argv[optind]);
        }
 
        if (infile)
@@ -357,7 +353,7 @@ main(int argc, char **argv)
 
        pd = pcap_open_dead(dlt, snaplen);
        if (pd == NULL)
-               error("Can't open fake pcap_t");
+               error(EX_SOFTWARE, "Can't open fake pcap_t");
 
 #ifdef LINUX_BPF_EXT
        if (lflag) {
@@ -367,7 +363,7 @@ main(int argc, char **argv)
 #endif
 
        if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
-               error("%s", pcap_geterr(pd));
+               error(EX_DATAERR, "%s", pcap_geterr(pd));
 
        if (!bpf_validate(fcode.bf_insns, fcode.bf_len))
                warn("Filter doesn't pass validation");
@@ -393,15 +389,15 @@ main(int argc, char **argv)
 #ifdef _WIN32
        WSACleanup();
 #endif
-       exit(0);
+       exit(EX_OK);
 }
 
 static void
-usage(void)
+usage(FILE *f)
 {
-       (void)fprintf(stderr, "%s, with %s\n", program_name,
+       (void)fprintf(f, "%s, with %s\n", program_name,
            pcap_lib_version());
-       (void)fprintf(stderr,
+       (void)fprintf(f,
            "Usage: %s [-d"
 #ifdef BDEBUG
            "g"
@@ -410,7 +406,31 @@ usage(void)
 #ifdef LINUX_BPF_EXT
            "l"
 #endif
-           "] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n",
+           "] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expr ]\n",
            program_name);
-       exit(1);
+       (void)fprintf(f, "       (print the filter program bytecode)\n");
+       (void)fprintf(f, "  or:  %s -h\n", program_name);
+       (void)fprintf(f, "       (print the detailed help screen)\n");
+       if (f == stdout) {
+               (void)fprintf(f, "\nOptions specific to %s:\n", program_name);
+               (void)fprintf(f, "  <dlt>           a valid DLT name, e.g. 'EN10MB'\n");
+               (void)fprintf(f, "  <expr>          a valid filter expression, e.g. 'tcp port 80'\n");
+#ifdef LINUX_BPF_EXT
+               (void)fprintf(f, "  -l              allow the use of Linux BPF extensions\n");
+#endif
+#ifdef BDEBUG
+               (void)fprintf(f, "  -g              print Graphviz dot graphs for the optimizer steps\n");
+#endif
+               (void)fprintf(f, "  -m <netmask>    use this netmask for pcap_compile(), e.g. 255.255.255.0\n");
+               (void)fprintf(f, "\n");
+               (void)fprintf(f, "Options common with tcpdump:\n");
+               (void)fprintf(f, "  -d              change output format (accumulates, one -d is implicit)\n");
+               (void)fprintf(f, "  -O              do not optimize the filter program\n");
+               (void)fprintf(f, "  -F <file>       read the filter expression from the specified file\n");
+               (void)fprintf(f, "  -s <snaplen>    set the snapshot length\n");
+               (void)fprintf(f, "\nIf no filter expression is specified, it defaults to an empty string, which\n");
+               (void)fprintf(f, "accepts all packets.  If the -F option is in use, it replaces any filter\n");
+               (void)fprintf(f, "expression specified as a command-line argument.\n");
+       }
+       exit(f == stdout ? EX_OK : EX_USAGE);
 }
index 68ef4cb92a6a941ec56c284ef710fbe5d272fc28..5603a503eb501428cd75b989dde2e27b6a5d87c5 100644 (file)
   #define close                _close
 #endif
 
+// No <sysexits.h> on Windows.
+#define EX_OK          0
+#define EX_USAGE       64
+#define EX_DATAERR     65
+#define EX_NOINPUT     66
+#define EX_NOUSER      67
+#define EX_NOHOST      68
+#define EX_UNAVAILABLE 69
+#define EX_SOFTWARE    70
+#define EX_OSERR       71
+#define EX_OSFILE      72
+#define EX_CANTCREAT   73
+#define EX_IOERR       74
+#define EX_TEMPFAIL    75
+#define EX_PROTOCOL    76
+#define EX_NOPERM      77
+#define EX_CONFIG      78
+
 #endif