wireshark/ui/commandline.c

924 lines
39 KiB
C

/* commandline.c
* Common command line handling between GUIs
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include <glib.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ws_exit_codes.h>
#include <wsutil/ws_getopt.h>
#include <wsutil/version_info.h>
#include <wsutil/application_flavor.h>
#include <wsutil/clopts_common.h>
#include <wsutil/cmdarg_err.h>
#include <wsutil/filesystem.h>
#include <wsutil/ws_assert.h>
#ifdef _WIN32
#include <wsutil/console_win32.h>
#endif
#include <epan/ex-opt.h>
#include <epan/packet.h>
#include <epan/proto.h>
#include <epan/prefs.h>
#include <epan/prefs-int.h>
#include <epan/stat_tap_ui.h>
#include "persfilepath_opt.h"
#include "preference_utils.h"
#include "recent.h"
#include "decode_as_utils.h"
#include "../file.h"
#include "ui/capture_opts.h"
#include "ui/dissect_opts.h"
#include "ui/commandline.h"
#include <wsutil/application_flavor.h>
commandline_param_info_t global_commandline_info;
capture_options global_capture_opts;
static void
commandline_print_usage(bool for_help_option) {
FILE *output;
#ifdef _WIN32
create_console();
#endif
if (for_help_option) {
if (application_flavor_is_wireshark()) {
show_help_header("Interactively dump and analyze network traffic.");
} else {
show_help_header("Interactively dump and analyze system calls and log messages.");
}
output = stdout;
} else {
output = stderr;
}
fprintf(output, "\n");
fprintf(output, "Usage: %s [options] ... [ <infile> ]\n", g_get_prgname());
fprintf(output, "\n");
#ifdef HAVE_LIBPCAP
if (application_flavor_is_wireshark()) {
fprintf(output, "Capture interface:\n");
fprintf(output, " -i <interface>, --interface <interface>\n");
fprintf(output, " name or idx of interface (def: first non-loopback)\n");
fprintf(output, " -f <capture filter> packet filter in libpcap filter syntax\n");
} else {
fprintf(output, "Capture source:\n");
fprintf(output, " -i <source>, --source <source>\n");
fprintf(output, " name or idx of source (def: first source listed by -D or --list-sources)\n");
fprintf(output, " -f <capture filter> filter in libsinsp/libscap filter syntax\n");
}
if (application_flavor_is_wireshark()) {
fprintf(output, " -s <snaplen>, --snapshot-length <snaplen>\n");
fprintf(output, " packet snapshot length (def: appropriate maximum)\n");
fprintf(output, " -p, --no-promiscuous-mode\n");
fprintf(output, " don't capture in promiscuous mode\n");
fprintf(output, " -I, --monitor-mode capture in monitor mode, if available\n");
fprintf(output, " -B <buffer size>, --buffer-size <buffer size>\n");
fprintf(output, " size of kernel buffer in MiB (def: %dMiB)\n", DEFAULT_CAPTURE_BUFFER_SIZE);
}
fprintf(output, " -y <link type>, --linktype <link type>\n");
fprintf(output, " link layer type (def: first appropriate)\n");
fprintf(output, " --time-stamp-type <type> timestamp method for interface\n");
if (application_flavor_is_wireshark()) {
fprintf(output, " -D, --list-interfaces print list of interfaces and exit\n");
} else {
fprintf(output, " -D, --list-sources print list of sources and exit\n");
}
fprintf(output, " -L, --list-data-link-types\n");
fprintf(output, " print list of link-layer types of iface and exit\n");
fprintf(output, " --list-time-stamp-types print list of timestamp types for iface and exit\n");
fprintf(output, "\n");
fprintf(output, "Capture display:\n");
fprintf(output, " -k start capturing immediately (def: do nothing)\n");
fprintf(output, " -S update display when new items are captured\n");
fprintf(output, " -l turn on automatic scrolling while -S is in use\n");
fprintf(output, " --update-interval interval between updates with new items, in milliseconds (def: %dms)\n", DEFAULT_UPDATE_INTERVAL);
fprintf(output, "Capture stop conditions:\n");
fprintf(output, " -c <item count> stop after n items (def: infinite)\n");
fprintf(output, " -a <autostop cond.> ..., --autostop <autostop cond.> ...\n");
fprintf(output, " duration:NUM - stop after NUM seconds\n");
fprintf(output, " filesize:NUM - stop this file after NUM KB\n");
fprintf(output, " files:NUM - stop after NUM files\n");
if (application_flavor_is_wireshark()) {
fprintf(output, " packets:NUM - stop after NUM packets\n");
} else {
fprintf(output, " events:NUM - stop after NUM packets\n");
}
/*fprintf(output, "\n");*/
// XXX libscap and libsinsp don't support this, so we should probably omit this if our flavor is Stratoshark.
fprintf(output, "Capture output:\n");
fprintf(output, " -b <ringbuffer opt.> ..., --ring-buffer <ringbuffer opt.>\n");
fprintf(output, " duration:NUM - switch to next file after NUM secs\n");
fprintf(output, " filesize:NUM - switch to next file after NUM KB\n");
fprintf(output, " files:NUM - ringbuffer: replace after NUM files\n");
if (application_flavor_is_wireshark()) {
fprintf(output, " packets:NUM - switch to next file after NUM packets\n");
} else {
fprintf(output, " events:NUM - switch to next file after NUM events\n");
}
fprintf(output, " interval:NUM - switch to next file when the time is\n");
fprintf(output, " an exact multiple of NUM secs\n");
#endif /* HAVE_LIBPCAP */
#ifdef HAVE_PCAP_REMOTE
fprintf(output, "RPCAP options:\n");
fprintf(output, " -A <user>:<password> use RPCAP password authentication\n");
#endif
/*fprintf(output, "\n");*/
fprintf(output, "Input file:\n");
fprintf(output, " -r <infile>, --read-file <infile>\n");
fprintf(output, " set the filename to read from (no pipes or stdin!)\n");
fprintf(output, "\n");
fprintf(output, "Processing:\n");
fprintf(output, " -R <read filter>, --read-filter <read filter>\n");
fprintf(output, " filter in display filter (wireshark-filter(4)) syntax\n");
fprintf(output, " -n disable all name resolutions (def: all enabled)\n");
// Note: the order of the flags here matches the options in the settings dialog e.g. "dsN" only have an effect if "n" is set
fprintf(output, " -N <name resolve flags> enable specific name resolution(s): \"mtndsNvg\"\n");
fprintf(output, " -d %s ...\n", DECODE_AS_ARG_TEMPLATE);
fprintf(output, " \"Decode As\", see the man page for details\n");
fprintf(output, " Example: tcp.port==8888,http\n");
fprintf(output, " --enable-protocol <proto_name>\n");
fprintf(output, " enable dissection of proto_name\n");
fprintf(output, " --disable-protocol <proto_name>\n");
fprintf(output, " disable dissection of proto_name\n");
fprintf(output, " --only-protocols <protocols>\n");
fprintf(output, " Only enable dissection of these protocols, comma\n");
fprintf(output, " separated. Disable everything else\n");
fprintf(output, " --disable-all-protocols\n");
fprintf(output, " Disable dissection of all protocols\n");
fprintf(output, " --enable-heuristic <short_name>\n");
fprintf(output, " enable dissection of heuristic protocol\n");
fprintf(output, " --disable-heuristic <short_name>\n");
fprintf(output, " disable dissection of heuristic protocol\n");
fprintf(output, "\n");
fprintf(output, "User interface:\n");
fprintf(output, " -C <config profile> start with specified configuration profile\n");
fprintf(output, " -H hide the capture info dialog during capture\n");
fprintf(output, " -Y <display filter>, --display-filter <display filter>\n");
fprintf(output, " start with the given display filter\n");
fprintf(output, " -g <item number> go to specified item number after \"-r\"\n");
fprintf(output, " -J <jump filter> jump to the first item matching the display\n");
fprintf(output, " filter\n");
fprintf(output, " -j search backwards for a matching item after \"-J\"\n");
fprintf(output, " -t (a|ad|adoy|d|dd|e|r|u|ud|udoy)[.[N]]|.[N]\n");
fprintf(output, " format of time stamps (def: r: rel. to first)\n");
fprintf(output, " -u s|hms output format of seconds (def: s: seconds)\n");
fprintf(output, " -X <key>:<value> eXtension options, see man page for details\n");
fprintf(output, " -z <statistics> show various statistics, see man page for details\n");
fprintf(output, "\n");
fprintf(output, "Output:\n");
fprintf(output, " -w <outfile|-> set the output filename (or '-' for stdout)\n");
#ifdef HAVE_LIBPCAP
fprintf(output, " -F <capture type> set the output file type; default is pcapng.\n");
fprintf(output, " an empty \"-F\" option will list the file types.\n");
fprintf(output, " --capture-comment <comment>\n");
fprintf(output, " add a capture file comment, if supported\n");
#endif
fprintf(output, " --temp-dir <directory> write temporary files to this directory\n");
fprintf(output, " (default: %s)\n", g_get_tmp_dir());
fprintf(output, "\n");
ws_log_print_usage(output);
fprintf(output, "\n");
fprintf(output, "Miscellaneous:\n");
fprintf(output, " -h, --help display this help and exit\n");
fprintf(output, " -v, --version display version info and exit\n");
fprintf(output, " -P <key>:<path> persconf:path - personal configuration files\n");
fprintf(output, " persdata:path - personal data files\n");
fprintf(output, " -o <name>:<value> ... override preference or recent setting\n");
fprintf(output, " -K <keytab> keytab file to use for kerberos decryption\n");
#ifndef _WIN32
fprintf(output, " --display <X display> X display to use\n");
#endif
fprintf(output, " --fullscreen start %s in full screen\n", application_flavor_name_proper());
#ifdef _WIN32
destroy_console();
#endif
}
#define LONGOPT_FULL_SCREEN LONGOPT_BASE_GUI+1
#define LONGOPT_CAPTURE_COMMENT LONGOPT_BASE_GUI+2
#define OPTSTRING OPTSTRING_CAPTURE_COMMON OPTSTRING_DISSECT_COMMON OPTSTRING_READ_CAPTURE_COMMON "C:g:HhjJ:klm:o:P:Svw:X:z:"
static const struct ws_option long_options[] = {
{"help", ws_no_argument, NULL, 'h'},
{"version", ws_no_argument, NULL, 'v'},
{"fullscreen", ws_no_argument, NULL, LONGOPT_FULL_SCREEN },
{"capture-comment", ws_required_argument, NULL, LONGOPT_CAPTURE_COMMENT},
LONGOPT_CAPTURE_COMMON
LONGOPT_DISSECT_COMMON
LONGOPT_READ_CAPTURE_COMMON
LONGOPT_WSLOG
{0, 0, 0, 0 }
};
static const char optstring[] = OPTSTRING;
const struct ws_option* commandline_long_options(void)
{
return long_options;
}
const char* commandline_optstring(void)
{
return optstring;
}
#ifndef HAVE_LIBPCAP
static void print_no_capture_support_error(void)
{
cmdarg_err("This version of %s was not built with support for capturing packets.", application_flavor_name_proper());
}
#endif
void commandline_early_options(int argc, char *argv[])
{
int opt;
#ifdef HAVE_LIBPCAP
int err;
GList *if_list;
char *err_str;
int exit_status;
#else
bool capture_option_specified;
#endif
/*
* 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 GUI
* if we're only showing command-line help or version information.
*
* XXX - this pre-scan is done before we start GUI, so we haven't
* run "GUI init function" on the arguments. That means that GUI-specific
* 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 "ws_opterr" to 0 to suppress the
* error messages.
*
* 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.
*/
ws_opterr = 0;
#ifndef HAVE_LIBPCAP
capture_option_specified = false;
#endif
while ((opt = ws_getopt_long(argc, argv, optstring, long_options, NULL)) != -1) {
switch (opt) {
case 'C': /* Configuration Profile */
if (profile_exists (ws_optarg, false)) {
set_profile_name (ws_optarg);
} else if (profile_exists (ws_optarg, true)) {
char *pf_dir_path, *pf_dir_path2, *pf_filename;
/* Copy from global profile */
if (create_persconffile_profile(ws_optarg, &pf_dir_path) == -1) {
cmdarg_err("Can't create directory\n\"%s\":\n%s.",
pf_dir_path, g_strerror(errno));
g_free(pf_dir_path);
exit(WS_EXIT_INVALID_FILE);
}
if (copy_persconffile_profile(ws_optarg, ws_optarg, true, &pf_filename,
&pf_dir_path, &pf_dir_path2) == -1) {
cmdarg_err("Can't copy file \"%s\" in directory\n\"%s\" to\n\"%s\":\n%s.",
pf_filename, pf_dir_path2, pf_dir_path, g_strerror(errno));
g_free(pf_filename);
g_free(pf_dir_path);
g_free(pf_dir_path2);
exit(WS_EXIT_INVALID_FILE);
}
set_profile_name (ws_optarg);
} else {
cmdarg_err("Configuration Profile \"%s\" does not exist", ws_optarg);
exit(1);
}
break;
case 'D': /* Print a list of capture devices and exit */
#ifdef HAVE_LIBPCAP
exit_status = EXIT_SUCCESS;
if_list = capture_interface_list(&err, &err_str, NULL);
if (err != 0) {
/*
* An error occurred when fetching the local
* interfaces. Report it.
*/
#ifdef _WIN32
create_console();
#endif /* _WIN32 */
cmdarg_err("%s", err_str);
g_free(err_str);
exit_status = WS_EXIT_PCAP_ERROR;
}
if (if_list == NULL) {
/*
* No interfaces were found. If that's not the
* result of an error when fetching the local
* interfaces, let the user know.
*/
if (err == 0) {
cmdarg_err("There are no interfaces on which a capture can be done");
exit_status = WS_EXIT_NO_INTERFACES;
}
exit(exit_status);
}
#ifdef _WIN32
create_console();
#endif /* _WIN32 */
capture_opts_print_interfaces(if_list);
free_interface_list(if_list);
#ifdef _WIN32
destroy_console();
#endif /* _WIN32 */
exit(exit_status);
#else /* HAVE_LIBPCAP */
capture_option_specified = true;
#endif /* HAVE_LIBPCAP */
break;
case 'h': /* Print help and exit */
commandline_print_usage(true);
exit(EXIT_SUCCESS);
break;
#ifdef _WIN32
case 'i':
if (strcmp(ws_optarg, "-") == 0)
set_stdin_capture(true);
break;
#endif
case 'P': /* Personal file directory path settings - change these before the Preferences and alike are processed */
if (!persfilepath_opt(opt, ws_optarg)) {
cmdarg_err("-P flag \"%s\" failed (hint: is it quoted and existing?)", ws_optarg);
exit(EXIT_SUCCESS);
}
break;
case 'v': /* Show version and exit */
#ifdef _WIN32
create_console();
#endif
show_version();
#ifdef _WIN32
destroy_console();
#endif
exit(EXIT_SUCCESS);
break;
case 'X':
/*
* Extension command line options have to be processed before
* we call epan_init() as they are supposed to be used by dissectors
* or taps very early in the registration process.
*/
ex_opt_add(ws_optarg);
break;
case '?': /* Ignore errors - the "real" scan will catch them. */
break;
}
}
#ifndef HAVE_LUA
if (ex_opt_count("lua_script") > 0) {
cmdarg_err("This version of %s was not built with support for Lua scripting.", application_flavor_name_proper());
exit(1);
}
#endif
#ifndef HAVE_LIBPCAP
if (capture_option_specified) {
print_no_capture_support_error();
commandline_print_usage(false);
exit(EXIT_SUCCESS);
}
#endif
}
void commandline_override_prefs(int argc, char *argv[], bool opt_reset)
{
int opt;
/*
* To reset the options parser, set ws_optreset to 1 and set ws_optind to 1.
*
* Ignore errors and keep ws_opterr as 0; error messages will be printed
* later by command_other_options()
*/
if (opt_reset) {
ws_optreset = 1;
ws_optind = 1;
ws_opterr = 0;
}
/* Initialize with default values */
global_commandline_info.user_opts = NULL;
while ((opt = ws_getopt_long(argc, argv, optstring, long_options, NULL)) != -1) {
switch (opt) {
case 'o': /* Override preference from command line */
{
char *errmsg = NULL;
switch (prefs_set_pref(ws_optarg, &errmsg)) {
case PREFS_SET_OK:
global_commandline_info.user_opts =
g_slist_prepend(global_commandline_info.user_opts,
g_strdup(ws_optarg));
break;
case PREFS_SET_SYNTAX_ERR:
cmdarg_err("Invalid -o flag \"%s\"%s%s", ws_optarg,
errmsg ? ": " : "", errmsg ? errmsg : "");
g_free(errmsg);
exit_application(1);
break;
case PREFS_SET_NO_SUCH_PREF:
/* not a preference, might be a recent setting */
switch (recent_set_arg(ws_optarg)) {
case PREFS_SET_OK:
break;
case PREFS_SET_SYNTAX_ERR:
/* shouldn't happen, checked already above */
cmdarg_err("Invalid -o flag \"%s\"", ws_optarg);
exit_application(1);
break;
case PREFS_SET_NO_SUCH_PREF:
case PREFS_SET_OBSOLETE:
cmdarg_err("-o flag \"%s\" specifies unknown preference/recent value",
ws_optarg);
exit_application(1);
break;
default:
ws_assert_not_reached();
}
break;
case PREFS_SET_OBSOLETE:
/* obsolete preference, might be a recent setting */
if (recent_set_arg(ws_optarg) != PREFS_SET_OK) {
cmdarg_err("-o flag \"%s\" specifies obsolete preference",
ws_optarg);
exit_application(1);
}
break;
default:
ws_assert_not_reached();
}
break;
}
default:
case '?': /* Ignore errors - the "real" scan will catch them. */
break;
}
}
/* Since we prepended each option when processing `-o`, reverse the list
* in case the order of options becomes meaningful.
*/
global_commandline_info.user_opts = g_slist_reverse(global_commandline_info.user_opts);
}
void commandline_other_options(int argc, char *argv[], bool opt_reset)
{
int opt;
bool arg_error = false;
#ifdef HAVE_LIBPCAP
const char *list_option_supplied = NULL;
int status;
#else
bool capture_option_specified;
#endif
/*
* To reset the options parser, set ws_optreset to 1 and set ws_optind to 1.
*
* Also reset ws_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 ws_opterr as 0, and produce our own messages using ws_optopt.
* We'd have to check the value of ws_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?
*/
if (opt_reset) {
ws_optreset = 1;
ws_optind = 1;
ws_opterr = 1;
}
/* Initialize with default values */
global_commandline_info.jump_backwards = SD_FORWARD;
global_commandline_info.go_to_packet = 0;
global_commandline_info.jfilter = NULL;
global_commandline_info.cf_name = NULL;
global_commandline_info.rfilter = NULL;
global_commandline_info.dfilter = NULL;
#ifdef HAVE_LIBPCAP
global_commandline_info.start_capture = false;
global_commandline_info.list_link_layer_types = false;
global_commandline_info.list_timestamp_types = false;
global_commandline_info.quit_after_cap = getenv("WIRESHARK_QUIT_AFTER_CAPTURE") ? true : false;
global_commandline_info.capture_comments = NULL;
#endif
global_commandline_info.full_screen = false;
while ((opt = ws_getopt_long(argc, argv, optstring, long_options, NULL)) != -1) {
switch (opt) {
/*** capture option specific ***/
case 'a': /* autostop criteria */
case 'b': /* Ringbuffer option */
case 'c': /* Capture xxx items */
case 'f': /* capture filter */
case 'F': /* capture file type */
case 'H': /* Hide capture info dialog box */
case 'p': /* Don't capture in promiscuous mode */
case 'i': /* Use interface x */
case LONGOPT_SET_TSTAMP_TYPE: /* Set capture timestamp type */
case LONGOPT_CAPTURE_TMPDIR: /* capture temp directory */
case LONGOPT_UPDATE_INTERVAL: /* sync pipe update interval */
case 'I': /* Capture in monitor mode, if available */
#ifdef HAVE_PCAP_REMOTE
case 'A': /* Authentication */
#endif
case 's': /* Set the snapshot (capture) length */
case 'S': /* "Sync" mode: used for following file ala tail -f */
case 'w': /* Write to capture file xxx */
case 'y': /* Set the pcap data link type */
case 'B': /* Buffer size */
#ifdef HAVE_LIBPCAP
status = capture_opts_add_opt(&global_capture_opts, opt, ws_optarg);
if(status != 0) {
exit_application(status);
}
#else
capture_option_specified = true;
arg_error = true;
#endif
break;
/*** all non capture option specific ***/
case 'C':
/* Configuration profile settings were already processed just ignore them this time*/
break;
case 'j': /* Search backwards for a matching item from filter in option J */
global_commandline_info.jump_backwards = SD_BACKWARD;
break;
case 'g': /* Go to item with the given item number */
global_commandline_info.go_to_packet = get_nonzero_uint32(ws_optarg, "go to packet");
break;
case 'J': /* Jump to the first item which matches the filter criteria */
global_commandline_info.jfilter = ws_optarg;
break;
case 'k': /* Start capture immediately */
#ifdef HAVE_LIBPCAP
global_commandline_info.start_capture = true;
#else
capture_option_specified = true;
arg_error = true;
#endif
break;
case 'l': /* Automatic scrolling in live capture mode */
#ifdef HAVE_LIBPCAP
recent.capture_auto_scroll = true;
#else
capture_option_specified = true;
arg_error = true;
#endif
break;
case 'L': /* Print list of link-layer types and exit */
#ifdef HAVE_LIBPCAP
global_commandline_info.list_link_layer_types = true;
list_option_supplied = "-L";
#else
capture_option_specified = true;
arg_error = true;
#endif
break;
case LONGOPT_LIST_TSTAMP_TYPES:
#ifdef HAVE_LIBPCAP
global_commandline_info.list_timestamp_types = true;
list_option_supplied = "--list-time-stamp-types";
#else
capture_option_specified = true;
arg_error = true;
#endif
break;
case 'o': /* Override preference from command line */
/* Pref overrides were already processed just ignore them this time*/
break;
case 'P':
/* Path settings were already processed just ignore them this time*/
break;
case 'r': /* Read capture file xxx */
/* We may set "last_open_dir" to "cf_name", and if we change
"last_open_dir" later, we free the old value, so we have to
set "cf_name" to something that's been allocated. */
global_commandline_info.cf_name = g_strdup(ws_optarg);
break;
case 'R': /* Read file filter */
global_commandline_info.rfilter = ws_optarg;
break;
case 'X':
/* ext ops were already processed just ignore them this time*/
break;
case 'Y':
global_commandline_info.dfilter = ws_optarg;
break;
case 'z':
/* We won't call the init function for the stat this soon
as it would disallow MATE's fields (which are registered
by the preferences set callback) from being used as
part of a tap filter. Instead, we just add the argument
to a list of stat arguments. */
if (strcmp("help", ws_optarg) == 0) {
fprintf(stderr, "%s: The available statistics for the \"-z\" option are:\n", g_get_prgname());
list_stat_cmd_args();
exit_application(0);
}
if (!process_stat_cmd_arg(ws_optarg)) {
cmdarg_err("Invalid -z argument.");
cmdarg_err_cont(" -z argument must be one of :");
list_stat_cmd_args();
exit_application(1);
}
break;
case 'd': /* Decode as rule */
case 'K': /* Kerberos keytab file */
case 'n': /* No name resolution */
case 'N': /* Select what types of addresses/port #s to resolve */
case 't': /* time stamp type */
case 'u': /* Seconds type */
case LONGOPT_DISABLE_PROTOCOL: /* disable dissection of protocol */
case LONGOPT_ENABLE_HEURISTIC: /* enable heuristic dissection of protocol */
case LONGOPT_DISABLE_HEURISTIC: /* disable heuristic dissection of protocol */
case LONGOPT_ENABLE_PROTOCOL: /* enable dissection of protocol (that is disabled by default) */
case LONGOPT_ONLY_PROTOCOLS: /* enable dissection of these comma separated protocols only */
case LONGOPT_DISABLE_ALL_PROTOCOLS: /* disable dissection of all protocols */
if (!dissect_opts_handle_opt(opt, ws_optarg))
exit_application(1);
break;
case LONGOPT_FULL_SCREEN:
global_commandline_info.full_screen = true;
break;
#ifdef HAVE_LIBPCAP
case LONGOPT_CAPTURE_COMMENT: /* capture comment */
if (global_commandline_info.capture_comments == NULL) {
global_commandline_info.capture_comments = g_ptr_array_new_with_free_func(g_free);
}
g_ptr_array_add(global_commandline_info.capture_comments, g_strdup(ws_optarg));
#else
capture_option_specified = true;
arg_error = true;
#endif
break;
default:
case '?': /* Bad flag - print usage message */
arg_error = true;
break;
}
}
if (!arg_error) {
argc -= ws_optind;
argv += ws_optind;
if (argc >= 1) {
if (global_commandline_info.cf_name != NULL) {
/*
* Input file name specified with "-r" *and* specified as a regular
* command-line argument.
*/
cmdarg_err("File name specified both with -r and regular argument");
arg_error = true;
} else {
/*
* Input file name not specified with "-r", and a command-line argument
* was specified; treat it as the input file name.
*
* Yes, this is different from tshark, where non-flag command-line
* arguments are a filter, but this works better on GUI desktops
* where a command can be specified to be run to open a particular
* file - yes, you could have "-r" as the last part of the command,
* but that's a bit ugly.
*/
global_commandline_info.cf_name = g_strdup(argv[0]);
}
argc--;
argv++;
}
if (argc != 0) {
/*
* Extra command line arguments were specified; complain.
*/
cmdarg_err("Invalid argument: %s", argv[0]);
arg_error = true;
}
}
if (arg_error) {
#ifdef HAVE_LIBPCAP
if (ws_optopt == 'F') {
capture_opts_list_file_types();
exit_application(1);
}
#else
if (capture_option_specified) {
print_no_capture_support_error();
}
#endif
commandline_print_usage(false);
exit_application(1);
}
#ifdef HAVE_LIBPCAP
if (global_commandline_info.start_capture && list_option_supplied) {
/* Specifying *both* is bogus. */
cmdarg_err("You can't specify both %s and a live capture.", list_option_supplied);
exit_application(1);
}
if (list_option_supplied) {
/* We're supposed to list the link-layer types for an interface;
did the user also specify a capture file to be read? */
if (global_commandline_info.cf_name) {
/* Yes - that's bogus. */
cmdarg_err("You can't specify %s and a capture file to be read.", list_option_supplied);
exit_application(1);
}
/* No - did they specify a ring buffer option? */
if (global_capture_opts.multi_files_on) {
cmdarg_err("Ring buffer requested, but a capture isn't being done.");
exit_application(1);
}
} else {
/* We're supposed to do a live capture; did the user also specify
a capture file to be read? */
if (global_commandline_info.start_capture && global_commandline_info.cf_name) {
/* Yes - that's bogus. */
cmdarg_err("You can't specify both a live capture and a capture file to be read.");
exit_application(1);
}
/* No - was the ring buffer option specified and, if so, does it make
sense? */
if (global_capture_opts.multi_files_on) {
/* Ring buffer works only under certain conditions:
a) ring buffer does not work with temporary files;
b) real_time_mode and multi_files_on are mutually exclusive -
real_time_mode takes precedence;
c) it makes no sense to enable the ring buffer if the maximum
file size is set to "infinite". */
if (global_capture_opts.save_file == NULL) {
cmdarg_err("Ring buffer requested, but capture isn't being saved to a permanent file.");
global_capture_opts.multi_files_on = false;
}
if (!global_capture_opts.has_autostop_filesize &&
!global_capture_opts.has_file_duration &&
!global_capture_opts.has_file_interval &&
!global_capture_opts.has_file_packets) {
cmdarg_err("Ring buffer requested, but no maximum capture file size, duration, interval or packets were specified.");
/* XXX - this must be redesigned as the conditions changed */
}
}
}
#endif
}
/* Local function used by commandline_options_drop */
static int cl_find_custom(const void *elem_data, const void *search_data) {
const char *prefix = (const char *)search_data;
const char *opt_and_val = (const char *)elem_data;
return strncmp(opt_and_val, prefix, strlen(prefix));
}
/* Drop any options the user specified on the command line with `-o`
* that have the given module and preference names
*/
void commandline_options_drop(const char *module_name, const char *pref_name) {
GSList *elem;
char *opt_prefix;
if (global_commandline_info.user_opts == NULL) return;
opt_prefix = ws_strdup_printf("%s.%s:", module_name, pref_name);
while (NULL != (elem = g_slist_find_custom(global_commandline_info.user_opts,
(const void *)opt_prefix, cl_find_custom))) {
global_commandline_info.user_opts =
g_slist_remove_link(global_commandline_info.user_opts, elem);
g_free(elem->data);
g_slist_free_1(elem);
}
g_free(opt_prefix);
}
/* Reapply any options the user specified on the command line with `-o`
* Called in the Qt UI when reloading Lua plugins
* For https://gitlab.com/wireshark/wireshark/-/issues/12331
*/
void commandline_options_reapply(void) {
char *errmsg = NULL;
GSList *entry = NULL;
for (entry = global_commandline_info.user_opts; entry != NULL; entry = g_slist_next(entry)) {
/* Although these options are from the user-supplied command line,
* they were checked for validity before we added them to user_opts,
* so we don't check them again here. In the worst case, a pref is
* specified for a lua plugin which has been edited after Wireshark
* started and has had that pref removed; not worth exiting over.
* See #12331
*/
prefs_set_pref((char *)entry->data, &errmsg);
if (errmsg != NULL) {
g_free(errmsg);
errmsg = NULL;
}
}
}
void commandline_options_apply_extcap(void) {
char *errmsg = NULL;
GSList *entry = NULL;
char *pref_arg;
if (prefs.capture_no_extcap)
return;
for (entry = global_commandline_info.user_opts; entry != NULL; entry = g_slist_next(entry)) {
pref_arg = (char *)entry->data;
if (g_str_has_prefix(pref_arg, "extcap.")) {
switch (prefs_set_pref(pref_arg, &errmsg)) {
case PREFS_SET_OK:
break;
case PREFS_SET_SYNTAX_ERR:
cmdarg_err("Invalid -o flag \"%s\"%s%s", pref_arg,
errmsg ? ": " : "", errmsg ? errmsg : "");
g_free(errmsg);
exit_application(1);
break;
case PREFS_SET_NO_SUCH_PREF:
cmdarg_err("-o flag \"%s\" specifies unknown preference/recent value",
pref_arg);
exit_application(1);
break;
case PREFS_SET_OBSOLETE:
cmdarg_err("-o flag \"%s\" specifies obsolete preference",
pref_arg);
exit_application(1);
break;
default:
ws_assert_not_reached();
}
}
}
}
/* Free memory used to hold user-specified command line options */
void commandline_options_free(void) {
g_slist_free_full(g_steal_pointer(&global_commandline_info.user_opts), g_free);
}