# 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';
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";
'>' . mytmpfile ($filename_stdout),
"2>&1"
);
- $r = system (join ' ', @args) >> 8;
+ my $r = system (join ' ', @args) >> 8;
return {
char => CHAR_TIMED_OUT,
'>' . mytmpfile ($filename_stdout),
"2>&1",
);
- $r = system (join ' ', @args) >> 8;
+ my $r = system (join ' ', @args) >> 8;
return {
char => CHAR_FAILED,
reason => "filtertest status $r",
details => file_get_contents mytmpfile $filename_stdout
}
- } if $r != 1;
+ } if $r != EX_DATAERR;
return {
char => CHAR_FAILED,
#include "unix.h"
#else
#include <unistd.h>
+ #include <sysexits.h>
#endif
#include <fcntl.h>
#include <errno.h>
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);
/*
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
* 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 */
/* VARARGS */
static void
-error(const char *fmt, ...)
+error(const int status, const char *fmt, ...)
{
va_list ap;
if (fmt[-1] != '\n')
(void)fputc('\n', stderr);
}
- exit(1);
+ exit(status);
/* NOTREACHED */
}
buf = (char *)malloc(len);
if (buf == NULL)
- error("copy_argv: malloc");
+ error(EX_OSERR, "%s: malloc", __func__);
p = argv;
dst = buf;
{
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;
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;
++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':
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:
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;
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 */
}
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)
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) {
#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");
#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"
#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);
}