diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index 918a628..dfdad33 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -81,7 +81,14 @@ check_function_exists("dladdr" HAVE_DLADDR) cmake_pop_check_state() check_function_exists("gethostbyname2" HAVE_GETHOSTBYNAME2) -check_function_exists("getopt" HAVE_GETOPT) +check_function_exists("getopt_long" HAVE_GETOPT_LONG) +if(HAVE_GETOPT_LONG) + if(HAVE_GETOPT_H) + check_symbol_exists("optreset" "getopt.h" HAVE_OPTRESET) + else() + check_symbol_exists("optreset" HAVE_OPTRESET) + endif() +endif() check_function_exists("getprotobynumber" HAVE_GETPROTOBYNUMBER) check_function_exists("inet_ntop" HAVE_INET_NTOP_PROTO) check_function_exists("issetugid" HAVE_ISSETUGID) diff --git a/capinfos.c b/capinfos.c index c4daebc..523a303 100644 --- a/capinfos.c +++ b/capinfos.c @@ -90,7 +90,7 @@ #include #endif -#ifndef HAVE_GETOPT +#ifndef HAVE_GETOPT_LONG #include "wsutil/wsgetopt.h" #endif diff --git a/capture_opts.h b/capture_opts.h index 704242f..e67a027 100644 --- a/capture_opts.h +++ b/capture_opts.h @@ -50,6 +50,39 @@ extern "C" { #define LONGOPT_NUM_CAP_COMMENT 2 +#if defined(_WIN32) || defined(HAVE_PCAP_CREATE) +#define LONGOPT_BUFFER_SIZE \ + {(char *)"buffer-size", required_argument, NULL, 'B'}, +#define OPTSTRING_B "B:" +#else +#define LONGOPT_BUFFER_SIZE +#define OPTSTRING_B "" +#endif + +#ifdef HAVE_PCAP_CREATE +#define LONGOPT_MONITOR_MODE {(char *)"monitor-mode", no_argument, NULL, 'I'}, +#define OPTSTRING_I "I" +#else +#define LONGOPT_MONITOR_MODE +#define OPTSTRING_I "" +#endif + +#define LONGOPT_CAPTURE_COMMON \ + {(char *)"capture-comment", required_argument, NULL, LONGOPT_NUM_CAP_COMMENT}, \ + {(char *)"autostop", required_argument, NULL, 'a'}, \ + {(char *)"ring-buffer", required_argument, NULL, 'b'}, \ + LONGOPT_BUFFER_SIZE \ + {(char *)"list-interfaces", no_argument, NULL, 'D'}, \ + {(char *)"interface", required_argument, NULL, 'i'}, \ + LONGOPT_MONITOR_MODE \ + {(char *)"list-data-link-types", no_argument, NULL, 'L'}, \ + {(char *)"no-promiscuous-mode", no_argument, NULL, 'p'}, \ + {(char *)"snapshot-length", required_argument, NULL, 's'}, \ + {(char *)"linktype", required_argument, NULL, 'y'}, + +#define OPTSTRING_CAPTURE_COMMON \ + "a:" OPTSTRING_A "b:" OPTSTRING_B "c:Df:i:" OPTSTRING_I "Lps:y:" + #ifdef HAVE_PCAP_REMOTE /* Type of capture source */ typedef enum { diff --git a/cmakeconfig.h.in b/cmakeconfig.h.in index a809e77..f1a5d44 100644 --- a/cmakeconfig.h.in +++ b/cmakeconfig.h.in @@ -63,8 +63,8 @@ /* Define to 1 if you have the `gethostbyname2' function. */ #cmakedefine HAVE_GETHOSTBYNAME2 1 -/* Define to 1 if you have the getopt function. */ -#cmakedefine HAVE_GETOPT 1 +/* Define to 1 if you have the getopt_long function. */ +#cmakedefine HAVE_GETOPT_LONG 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_GETOPT_H 1 @@ -234,6 +234,9 @@ /* Define if python devel package available */ #cmakedefine HAVE_PYTHON 1 +/* Define to 1 if you have the optreset variable */ +#cmakedefine HAVE_OPTRESET 1 + /* Define to 1 to enable remote capturing feature in WinPcap library */ #cmakedefine HAVE_REMOTE 1 diff --git a/configure.ac b/configure.ac index 6bcdcab..4ecdab6 100644 --- a/configure.ac +++ b/configure.ac @@ -2553,9 +2553,28 @@ AC_C_BIGENDIAN AC_PROG_GCC_TRADITIONAL GETOPT_LO="" -AC_CHECK_FUNC(getopt, +AC_CHECK_FUNC(getopt_long, [GETOPT_LO="" - AC_DEFINE(HAVE_GETOPT, 1, [Define to 1 if you have the getopt function.]) + AC_DEFINE(HAVE_GETOPT_LONG, 1, [Define to 1 if you have the getopt_long function.]) + + # + # Do we have optreset? + # + AC_MSG_CHECKING(whether optreset is defined) + AC_TRY_LINK([], + [ + extern int optreset; + + return optreset; + ], + ac_cv_pcap_debug_defined=yes, + ac_cv_pcap_debug_defined=no) + if test "$ac_cv_pcap_debug_defined" = yes ; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_OPTRESET, 1, [Define to 1 if you have the optreset variable]) + else + AC_MSG_RESULT(no) + fi ], GETOPT_LO="wsgetopt.lo" ) diff --git a/dumpcap.c b/dumpcap.c index 2ceed86..329c1d3 100644 --- a/dumpcap.c +++ b/dumpcap.c @@ -69,7 +69,7 @@ #include -#ifndef HAVE_GETOPT +#ifndef HAVE_GETOPT_LONG #include "wsutil/wsgetopt.h" #endif diff --git a/editcap.c b/editcap.c index 9197e62..a081238 100644 --- a/editcap.c +++ b/editcap.c @@ -56,7 +56,7 @@ #include "wtap.h" -#ifndef HAVE_GETOPT +#ifndef HAVE_GETOPT_LONG #include "wsutil/wsgetopt.h" #endif diff --git a/mergecap.c b/mergecap.c index a9c1ef9..14092eb 100644 --- a/mergecap.c +++ b/mergecap.c @@ -41,7 +41,7 @@ #include #include "wtap.h" -#ifndef HAVE_GETOPT +#ifndef HAVE_GETOPT_LONG #include #endif diff --git a/randpkt.c b/randpkt.c index 5393fa9..726f11e 100644 --- a/randpkt.c +++ b/randpkt.c @@ -27,7 +27,7 @@ #include #endif -#ifndef HAVE_GETOPT +#ifndef HAVE_GETOPT_LONG #include "wsutil/wsgetopt.h" #endif diff --git a/rawshark.c b/rawshark.c index b4eccb8..d672bde 100644 --- a/rawshark.c +++ b/rawshark.c @@ -56,7 +56,7 @@ # include #endif -#ifndef HAVE_GETOPT +#ifndef HAVE_GETOPT_LONG #include "wsutil/wsgetopt.h" #endif diff --git a/reordercap.c b/reordercap.c index ce563be..8589230 100644 --- a/reordercap.c +++ b/reordercap.c @@ -34,7 +34,7 @@ #include "wtap.h" -#ifndef HAVE_GETOPT +#ifndef HAVE_GETOPT_LONG #include "wsutil/wsgetopt.h" #endif diff --git a/text2pcap.c b/text2pcap.c index ae47e4d..c07d5d2 100644 --- a/text2pcap.c +++ b/text2pcap.c @@ -122,7 +122,7 @@ #include #include -#ifndef HAVE_GETOPT +#ifndef HAVE_GETOPT_LONG #include "wsutil/wsgetopt.h" #endif diff --git a/tfshark.c b/tfshark.c index e623504..2a54d39 100644 --- a/tfshark.c +++ b/tfshark.c @@ -50,7 +50,7 @@ # include #endif -#ifndef HAVE_GETOPT +#ifndef HAVE_GETOPT_LONG #include "wsutil/wsgetopt.h" #endif @@ -780,13 +780,28 @@ main(int argc, char *argv[]) dfilter_t *dfcode = NULL; e_prefs *prefs_p; int log_flags; - int optind_initial; gchar *output_only = NULL; -/* the leading - ensures that getopt() does not permute the argv[] entries - we have to make sure that the first getopt() preserves the content of argv[] - for the subsequent getopt_long() call */ -#define OPTSTRING "-2C:d:e:E:hK:lo:O:qQr:R:S:t:T:u:vVxX:Y:z:" +/* + * The leading + ensures that getopt_long() does not permute the argv[] + * entries. + * + * We have to make sure that the first getopt_long() preserves the content + * of argv[] for the subsequent getopt_long() call. + * + * We use getopt_long() in both cases to ensure that we're using a routine + * whose permutation behavior we can control in the same fashion on all + * platforms, and so that, if we ever need to process a long argument before + * doing further initialization, we can do so. + * + * Glibc and Solaris libc document that a leading + disables permutation + * of options, regardless of whether POSIXLY_CORRECT is set or not; *BSD + * and OS X don't document it, but do so anyway. + * + * We do *not* use a leading - because the behavior of a leading - is + * platform-dependent. + */ +#define OPTSTRING "+2C:d:e:E:hK:lo:O:qQr:R:S:t:T:u:vVxX:Y:z:" static const char optstring[] = OPTSTRING; @@ -831,11 +846,18 @@ main(int argc, char *argv[]) /* * In order to have the -X opts assigned before the wslua machine starts * we need to call getopts before epan_init() gets called. + * + * In order to handle, for example, -o options, we also need to call it + * *after* epan_init() gets called, so that the dissectors have had a + * chance to register their preferences. + * + * XXX - can we do this all with one getopt_long() call, saving the + * arguments we can't handle until after initializing libwireshark, + * and then process them after initializing libwireshark? */ opterr = 0; - optind_initial = optind; - while ((opt = getopt(argc, argv, optstring)) != -1) { + while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { switch (opt) { case 'C': /* Configuration Profile */ if (profile_exists (optarg, FALSE)) { @@ -876,11 +898,6 @@ main(int argc, char *argv[]) if (print_summary == -1) print_summary = (print_details || print_hex) ? FALSE : TRUE; - optind = optind_initial; - opterr = 1; - - - /** Send All g_log messages to our own handler **/ log_flags = @@ -1063,6 +1080,28 @@ main(int argc, char *argv[]) output_fields = output_fields_new(); + /* + * To reset the options parser, set optreset to 1 on platforms that + * have optreset (documented in *BSD and OS X, apparently present but + * not documented in Solaris - the Illumos repository seems to + * suggest that the first Solaris getopt_long(), at least as of 2004, + * was based on the NetBSD one, it had optreset) and set optind to 1, + * and set optind to 0 otherwise (documented as working in the GNU + * getopt_long(). Setting optind to 0 didn't originally work in the + * NetBSD one, but that was added later - we don't want to depend on + * it if we have optreset). + * + * Also reset opterr to 1, so that error messages are printed by + * getopt_long(). + */ +#ifdef HAVE_OPTRESET + optreset = 1; + optind = 1; +#else + optind = 0; +#endif + opterr = 1; + /* Now get our args */ while ((opt = getopt(argc, argv, optstring)) != -1) { switch (opt) { @@ -1070,7 +1109,7 @@ main(int argc, char *argv[]) perform_two_pass_analysis = TRUE; break; case 'C': - /* Configuration profile settings were already processed just ignore them this time*/ + /* already processed; just ignore it now */ break; case 'd': /* Decode as rule */ if (!add_decode_as(optarg)) @@ -1258,6 +1297,7 @@ main(int argc, char *argv[]) /* already processed; just ignore it now */ break; case 'X': + /* already processed; just ignore it now */ break; case 'Y': dfilter = optarg; diff --git a/tshark.c b/tshark.c index 8de15c6..fcaffcb 100644 --- a/tshark.c +++ b/tshark.c @@ -51,7 +51,7 @@ # include #endif -#ifndef HAVE_GETOPT +#ifndef HAVE_GETOPT_LONG #include "wsutil/wsgetopt.h" #endif @@ -973,7 +973,6 @@ main(int argc, char *argv[]) e_prefs *prefs_p; char badopt; int log_flags; - int optind_initial; gchar *output_only = NULL; #ifdef HAVE_PCAP_REMOTE @@ -997,10 +996,22 @@ main(int argc, char *argv[]) #define OPTSTRING_I "" #endif -/* the leading - ensures that getopt() does not permute the argv[] entries - we have to make sure that the first getopt() preserves the content of argv[] - for the subsequent getopt_long() call */ -#define OPTSTRING "-2a:" OPTSTRING_A "b:" OPTSTRING_B "c:C:d:De:E:f:F:gG:hH:i:" OPTSTRING_I "K:lLnN:o:O:pPqQr:R:s:S:t:T:u:vVw:W:xX:y:Y:z:" +/* + * The leading + ensures that getopt_long() does not permute the argv[] entries. + * + * We have to make sure that the first getopt_long() preserves the content + * of argv[] for the subsequent getopt_long() call. + * + * We use getopt_long() in both cases to ensure that we're using a routine + * whose permutation behavior we can control in the same fashion on all + * platforms, and so that, if we ever need to process a long argument before + * doing further initialization, we can do so. + * + * Glibc and Solaris libc document that a leading + disables permutation + * of options, regardless of whether POSIXLY_CORRECT is set or not; *BSD + * and OS X don't document it, but do so anyway. + */ +#define OPTSTRING "+2a:" OPTSTRING_A "b:" OPTSTRING_B "c:C:d:De:E:f:F:gG:hH:i:" OPTSTRING_I "K:lLnN:o:O:pPqQr:R:s:S:t:T:u:vVw:W:xX:y:Y:z:" static const char optstring[] = OPTSTRING; @@ -1044,12 +1055,19 @@ main(int argc, char *argv[]) /* * In order to have the -X opts assigned before the wslua machine starts - * we need to call getopts before epan_init() gets called. + * we need to call getopt_long before epan_init() gets called. + * + * In order to handle, for example, -o options, we also need to call it + * *after* epan_init() gets called, so that the dissectors have had a + * chance to register their preferences. + * + * XXX - can we do this all with one getopt_long() call, saving the + * arguments we can't handle until after initializing libwireshark, + * and then process them after initializing libwireshark? */ opterr = 0; - optind_initial = optind; - while ((opt = getopt(argc, argv, optstring)) != -1) { + while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { switch (opt) { case 'C': /* Configuration Profile */ if (profile_exists (optarg, FALSE)) { @@ -1094,11 +1112,6 @@ main(int argc, char *argv[]) if (print_summary == -1) print_summary = (print_details || print_hex) ? FALSE : TRUE; - optind = optind_initial; - opterr = 1; - - - /** Send All g_log messages to our own handler **/ log_flags = @@ -1292,6 +1305,28 @@ main(int argc, char *argv[]) output_fields = output_fields_new(); + /* + * To reset the options parser, set optreset to 1 on platforms that + * have optreset (documented in *BSD and OS X, apparently present but + * not documented in Solaris - the Illumos repository seems to + * suggest that the first Solaris getopt_long(), at least as of 2004, + * was based on the NetBSD one, it had optreset) and set optind to 1, + * and set optind to 0 otherwise (documented as working in the GNU + * getopt_long(). Setting optind to 0 didn't originally work in the + * NetBSD one, but that was added later - we don't want to depend on + * it if we have optreset). + * + * Also reset opterr to 1, so that error messages are printed by + * getopt_long(). + */ +#ifdef HAVE_OPTRESET + optreset = 1; + optind = 1; +#else + optind = 0; +#endif + opterr = 1; + /* Now get our args */ while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { switch (opt) { @@ -1337,7 +1372,7 @@ main(int argc, char *argv[]) #endif break; case 'C': - /* Configuration profile settings were already processed just ignore them this time*/ + /* already processed; just ignore it now */ break; case 'd': /* Decode as rule */ if (!add_decode_as(optarg)) @@ -1608,6 +1643,7 @@ main(int argc, char *argv[]) /* already processed; just ignore it now */ break; case 'X': + /* already processed; just ignore it now */ break; case 'Y': dfilter = optarg; diff --git a/ui/gtk/main.c b/ui/gtk/main.c index f0edc8e..b28d992 100644 --- a/ui/gtk/main.c +++ b/ui/gtk/main.c @@ -41,7 +41,11 @@ #include #endif -#ifndef HAVE_GETOPT +#ifdef HAVE_GETOPT_H +# include +#endif + +#ifndef HAVE_GETOPT_LONG #include "wsutil/wsgetopt.h" #endif @@ -2150,7 +2154,6 @@ main(int argc, char *argv[]) guint go_to_packet = 0; search_direction jump_backwards = SD_FORWARD; dfilter_t *jump_to_filter = NULL; - int optind_initial; unsigned int in_file_type = WTAP_TYPE_AUTO; #ifdef HAVE_GTKOSXAPPLICATION GtkosxApplication *theApp; @@ -2178,6 +2181,16 @@ main(int argc, char *argv[]) #define OPTSTRING "a:" OPTSTRING_A "b:" OPTSTRING_B "c:C:Df:g:Hhi:" OPTSTRING_I "jJ:kK:lLm:nN:o:P:pr:R:Ss:t:u:vw:X:y:Y:z:" + static const struct option long_options[] = { + {(char *)"help", no_argument, NULL, 'h'}, + {(char *)"read-file", required_argument, NULL, 'r' }, + {(char *)"read-filter", required_argument, NULL, 'R' }, + {(char *)"display-filter", required_argument, NULL, 'Y' }, + {(char *)"version", no_argument, NULL, 'v'}, + LONGOPT_CAPTURE_COMMON + {0, 0, 0, 0 } + }; + static const char optstring[] = OPTSTRING; @@ -2288,20 +2301,41 @@ main(int argc, char *argv[]) rf_path, g_strerror(rf_open_errno)); } - /* "pre-scan" the command line parameters, if we have "console only" - parameters. We do this so we don't start GTK+ if we're only showing - command-line help or version information. + /* + * In order to have the -X opts assigned before the wslua machine starts + * we need to call getopt_long before epan_init() gets called. + + * In addition, we process "console only" parameters (ones where we + * send output to the console and exit) here, so we don't start GTK+ + * if we're only showing command-line help or version information. - XXX - this pre-scan is done before we start GTK+, so we haven't - run gtk_init() on the arguments. That means that GTK+ arguments - have not been removed from the argument list; those arguments - begin with "--", and will be treated as an error by getopt(). + * XXX - this pre-scan is done before we start GTK+, so we haven't + * run gtk_init() on the arguments. That means that GTK+ arguments + * have not been removed from the argument list; those arguments + * begin with "--", and will be treated as an error by getopt_long(). - We thus ignore errors - *and* set "opterr" to 0 to suppress the - error messages. */ + * We thus ignore errors - *and* set "opterr" to 0 to suppress the + * error messages. + + * XXX - should we, instead, first call gtk_parse_args(), without + * calling gtk_init(), and then call this? + + * In order to handle, for example, -o options, we also need to call it + * *after* epan_init() gets called, so that the dissectors have had a + * chance to register their preferences, so we have another getopt_long() + * call later. + + * XXX - can we do this all with one getopt_long() call, saving the + * arguments we can't handle until after initializing libwireshark, + * and then process them after initializing libwireshark? + + * Note that we don't want to initialize libwireshark until after the + * GUI is up, as that can take a while, and we want a window of some + * sort up to show progress while that's happening. + */ opterr = 0; - optind_initial = optind; - while ((opt = getopt(argc, argv, optstring)) != -1) { + + while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { switch (opt) { case 'C': /* Configuration Profile */ if (profile_exists (optarg, FALSE)) { @@ -2402,42 +2436,6 @@ main(int argc, char *argv[]) set_last_open_dir(get_persdatafile_dir()); } - /* Set getopt index back to initial value, so it will start with the - first command line parameter again. Also reset opterr to 1, so that - error messages are printed by getopt(). - - XXX - this seems to work on most platforms, but time will tell. - The Single UNIX Specification says "The getopt() function need - not be reentrant", so this isn't guaranteed to work. The Mac - OS X 10.4[.x] getopt() man page says - - In order to use getopt() to evaluate multiple sets of arguments, or to - evaluate a single set of arguments multiple times, the variable optreset - must be set to 1 before the second and each additional set of calls to - getopt(), and the variable optind must be reinitialized. - - ... - - The optreset variable was added to make it possible to call the getopt() - function multiple times. This is an extension to the IEEE Std 1003.2 - (``POSIX.2'') specification. - - which I think comes from one of the other BSDs. - - XXX - if we want to control all the command-line option errors, so - that we can display them where we choose (e.g., in a window), we'd - want to leave opterr as 0, and produce our own messages using optopt. - We'd have to check the value of optopt to see if it's a valid option - letter, in which case *presumably* the error is "this option requires - an argument but none was specified", or not a valid option letter, - in which case *presumably* the error is "this option isn't valid". - Some versions of getopt() let you supply a option string beginning - with ':', which means that getopt() will return ':' rather than '?' - for "this option requires an argument but none was specified", but - not all do. */ - optind = optind_initial; - opterr = 1; - #if !GLIB_CHECK_VERSION(2,31,0) g_thread_init(NULL); #endif @@ -2587,8 +2585,42 @@ main(int argc, char *argv[]) /*#ifdef HAVE_LIBPCAP fill_in_local_interfaces(); #endif*/ + /* + * To reset the options parser, set optreset to 1 on platforms that + * have optreset (documented in *BSD and OS X, apparently present but + * not documented in Solaris - the Illumos repository seems to + * suggest that the first Solaris getopt_long(), at least as of 2004, + * was based on the NetBSD one, it had optreset) and set optind to 1, + * and set optind to 0 otherwise (documented as working in the GNU + * getopt_long(). Setting optind to 0 didn't originally work in the + * NetBSD one, but that was added later - we don't want to depend on + * it if we have optreset). + * + * Also reset opterr to 1, so that error messages are printed by + * getopt_long(). + * + * XXX - if we want to control all the command-line option errors, so + * that we can display them where we choose (e.g., in a window), we'd + * want to leave opterr as 0, and produce our own messages using optopt. + * We'd have to check the value of optopt to see if it's a valid option + * letter, in which case *presumably* the error is "this option requires + * an argument but none was specified", or not a valid option letter, + * in which case *presumably* the error is "this option isn't valid". + * Some versions of getopt() let you supply a option string beginning + * with ':', which means that getopt() will return ':' rather than '?' + * for "this option requires an argument but none was specified", but + * not all do. But we're now using getopt_long() - what does it do? + */ +#ifdef HAVE_OPTRESET + optreset = 1; + optind = 1; +#else + optind = 0; +#endif + opterr = 1; + /* Now get our args */ - while ((opt = getopt(argc, argv, optstring)) != -1) { + while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { switch (opt) { /*** capture option specific ***/ case 'a': /* autostop criteria */