X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=tshark.c;h=528d6e801ab709adc3d36630cd9d76651c95beb5;hb=5934fb198447b7c5748ba6c632cbd9ab4800b185;hp=329423d4cd9e3c7e047cf702fbe9b7f027b48171;hpb=7a1872e5dac7e2090eb2a7b816fa936457146cb7;p=obnox%2Fwireshark%2Fwip.git diff --git a/tshark.c b/tshark.c index 329423d4cd..528d6e801a 100644 --- a/tshark.c +++ b/tshark.c @@ -52,19 +52,20 @@ #endif #ifdef NEED_STRERROR_H -#include "strerror.h" +#include "wsutil/strerror.h" #endif #ifdef HAVE_GETOPT_H #include #else -#include "wsgetopt.h" +#include "wsutil/wsgetopt.h" #endif #include #include #include #include +#include #include "globals.h" #include @@ -95,6 +96,7 @@ #ifdef _WIN32 #include "capture-wpcap.h" #include "capture_errs.h" +#include #endif /* _WIN32 */ #include "capture_sync.h" #endif /* HAVE_LIBPCAP */ @@ -113,7 +115,7 @@ static nstime_t first_ts; static nstime_t prev_dis_ts; static nstime_t prev_cap_ts; -static gboolean print_packet_info; /* TRUE if we're to print packet information */ +static gboolean print_packet_info; /* TRUE if we're to print packet information */ static gboolean perform_two_pass_analysis; @@ -121,14 +123,14 @@ static gboolean perform_two_pass_analysis; * The way the packet decode is to be written. */ typedef enum { - WRITE_TEXT, /* summary or detail text */ - WRITE_XML, /* PDML or PSML */ - WRITE_FIELDS /* User defined list of fields */ - /* Add CSV and the like here */ + WRITE_TEXT, /* summary or detail text */ + WRITE_XML, /* PDML or PSML */ + WRITE_FIELDS /* User defined list of fields */ + /* Add CSV and the like here */ } output_action_e; static output_action_e output_action; -static gboolean do_dissection; /* TRUE if we have to dissect each packet */ +static gboolean do_dissection; /* TRUE if we have to dissect each packet */ static gboolean verbose; static gboolean print_hex; static gboolean line_buffered; @@ -138,12 +140,6 @@ static print_stream_t *print_stream; static output_fields_t* output_fields = NULL; -/* - * Standard secondary message for unexpected errors. - */ -static const char please_report[] = - "Please report this to the Wireshark developers"; - #ifdef HAVE_LIBPCAP /* * TRUE if we're to print packet counts to keep track of captured packets. @@ -154,11 +150,11 @@ static gboolean print_packet_counts; static capture_options global_capture_opts; #ifdef SIGINFO -static gboolean infodelay; /* if TRUE, don't print capture info in SIGINFO handler */ -static gboolean infoprint; /* if TRUE, print capture info after clearing infodelay */ +static gboolean infodelay; /* if TRUE, don't print capture info in SIGINFO handler */ +static gboolean infoprint; /* if TRUE, print capture info after clearing infodelay */ #endif /* SIGINFO */ -static int capture(void); +static gboolean capture(void); static void report_counts(void); #ifdef _WIN32 static BOOL WINAPI capture_cleanup(DWORD); @@ -170,7 +166,7 @@ static void report_counts_siginfo(int); #endif /* _WIN32 */ #endif /* HAVE_LIBPCAP */ -static int load_cap_file(capture_file *, char *, int, int, gint64); +static int load_cap_file(capture_file *, char *, int, gboolean, int, gint64); static gboolean process_packet(capture_file *cf, gint64 offset, const struct wtap_pkthdr *whdr, union wtap_pseudo_header *pseudo_header, const guchar *pd, gboolean filtering_tap_listeners, guint tap_flags); @@ -190,21 +186,45 @@ static void write_failure_message(const char *filename, int err); capture_file cfile; -void -cf_mark_frame(capture_file *cf _U_, frame_data *frame _U_) +struct string_elem { + const char *sstr; /* The short string */ + const char *lstr; /* The long string */ +}; + +static gint +string_compare(gconstpointer a, gconstpointer b) { - g_assert_not_reached(); + return strcmp(((struct string_elem *)a)->sstr, + ((struct string_elem *)b)->sstr); } -static void list_capture_types(void) { - int i; +static void +string_elem_print(gpointer data, gpointer not_used _U_) +{ + fprintf(stderr, " %s - %s\n", + ((struct string_elem *)data)->sstr, + ((struct string_elem *)data)->lstr); +} + +static void +list_capture_types(void) { + int i; + struct string_elem *captypes; + GSList *list = NULL; + + captypes = g_malloc(sizeof(struct string_elem) * WTAP_NUM_FILE_TYPES); - fprintf(stderr, "editcap: The available capture file types for \"F\":\n"); - for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) { - if (wtap_dump_can_open(i)) - fprintf(stderr, " %s - %s\n", - wtap_file_type_short_string(i), wtap_file_type_string(i)); + fprintf(stderr, "tshark: The available capture file types for the \"-F\" flag are:\n"); + for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) { + if (wtap_dump_can_open(i)) { + captypes[i].sstr = wtap_file_type_short_string(i); + captypes[i].lstr = wtap_file_type_string(i); + list = g_slist_insert_sorted(list, &captypes[i], string_compare); } + } + g_slist_foreach(list, string_elem_print, NULL); + g_slist_free(list); + g_free(captypes); } static void @@ -220,7 +240,7 @@ print_usage(gboolean print_ver) "See http://www.wireshark.org for more information.\n" "\n" "%s", - wireshark_svnversion, get_copyright_info()); + wireshark_svnversion, get_copyright_info()); } else { output = stderr; } @@ -286,6 +306,9 @@ print_usage(gboolean print_ver) fprintf(output, " -E= set options for output when -Tfields selected:\n"); fprintf(output, " header=y|n switch headers on and off\n"); fprintf(output, " separator=/t|/s| select tab, space, printable character as separator\n"); + fprintf(output, " occurrence=f|l|a print first, last or all occurrences of each field\n"); + fprintf(output, " aggregator=,|/s| select comma, space, printable character as\n"); + fprintf(output, " aggregator\n"); fprintf(output, " quote=d|s|n select double, single, no quotes for values\n"); fprintf(output, " -t ad|a|r|d|dd|e output format of time stamps (def: r: rel. to first)\n"); fprintf(output, " -u s|hms output format of seconds (def: s: seconds)\n"); @@ -300,6 +323,36 @@ print_usage(gboolean print_ver) fprintf(output, " -v display version info and exit\n"); fprintf(output, " -o : ... override preference setting\n"); fprintf(output, " -K keytab file to use for kerberos decryption\n"); + fprintf(output, " -G [report] dump one of several available reports and exit\n"); + fprintf(output, " default report=\"fields\"\n"); + fprintf(output, " use \"-G ?\" for more help\n"); +} + +static void +glossary_option_help(void) +{ + FILE *output; + + output = stdout; + + fprintf(output, "TShark " VERSION "%s\n", wireshark_svnversion); + + fprintf(output, "\n"); + fprintf(output, "Usage: tshark -G [report]\n"); + fprintf(output, "\n"); + fprintf(output, "Glossary table reports:\n"); + fprintf(output, " -G [fields] dump glossary in original format and exit\n"); + fprintf(output, " -G fields2 dump glossary in format 2 and exit\n"); + fprintf(output, " -G fields3 dump glossary in format 3 and exit\n"); + fprintf(output, " -G protocols dump protocols in registration database and exit\n"); + fprintf(output, " -G values dump value, range, true/false strings and exit\n"); + fprintf(output, " -G decodes dump \"layer type\"/\"decode as\" associations and exit\n"); + fprintf(output, "\n"); + fprintf(output, "Preference reports:\n"); + fprintf(output, " -G defaultprefs dump default preferences and exit\n"); + fprintf(output, " -G currentprefs dump current preferences and exit\n"); + fprintf(output, "\n"); + } /* @@ -599,7 +652,7 @@ add_decode_as(const gchar *cl_param) cmdarg_err("Unknown protocol -- \"%s\"", dissector_str); } else { cmdarg_err("Protocol \"%s\" isn't valid for layer type \"%s\"", - dissector_str, table_name); + dissector_str, table_name); } } } @@ -631,7 +684,7 @@ add_decode_as(const gchar *cl_param) case FT_UINT24: case FT_UINT32: /* The selector for this table is an unsigned number. */ - dissector_change(table_name, selector, dissector_matching); + dissector_change_uint(table_name, selector, dissector_matching); break; case FT_STRING: @@ -646,7 +699,7 @@ add_decode_as(const gchar *cl_param) than the ones listed above. */ g_assert_not_reached(); } - g_free(decoded_param); /* "Decode As" rule has been succesfully added */ + g_free(decoded_param); /* "Decode As" rule has been successfully added */ return TRUE; } @@ -743,8 +796,10 @@ main(int argc, char *argv[]) gboolean arg_error = FALSE; #ifdef _WIN32 - WSADATA wsaData; -#endif /* _WIN32 */ + WSADATA wsaData; + LPWSTR *wc_argv; + int wc_argc, i; +#endif /* _WIN32 */ char *gpf_path, *pf_path; char *gdp_path, *dp_path; @@ -753,6 +808,7 @@ main(int argc, char *argv[]) int gdp_open_errno, gdp_read_errno; int dp_open_errno, dp_read_errno; int err; + int exit_status = 0; #ifdef HAVE_LIBPCAP gboolean list_link_layer_types = FALSE; gboolean start_capture = FALSE; @@ -762,7 +818,9 @@ main(int argc, char *argv[]) #else gboolean capture_option_specified = FALSE; #endif + gboolean quiet = FALSE; int out_file_type = WTAP_FILE_PCAP; + gboolean out_file_name_res = FALSE; gchar *cf_name = NULL, *rfilter = NULL; #ifdef HAVE_PCAP_OPEN_DEAD struct bpf_program fcode; @@ -789,14 +847,24 @@ main(int argc, char *argv[]) #define OPTSTRING_I "" #endif -#define OPTSTRING "a:b:" OPTSTRING_B "c:C:d:De:E:f:F:G:hi:" OPTSTRING_I "K:lLnN:o:pPqr:R:s:St:T:u:vVw:xX:y:z:" +#define OPTSTRING "a:b:" OPTSTRING_B "c:C:d:De:E:f:F:G:hH:i:" OPTSTRING_I "K:lLnN:o:pPqr:R:s:St:T:u:vVw:W:xX:y:z:" static const char optstring[] = OPTSTRING; +#ifdef _WIN32 + /* Convert our arg list to UTF-8. */ + wc_argv = CommandLineToArgvW(GetCommandLineW(), &wc_argc); + if (wc_argv && wc_argc == argc) { + for (i = 0; i < argc; i++) { + argv[i] = g_utf16_to_utf8(wc_argv[i], -1, NULL, NULL, NULL); + } + } /* XXX else bail because something is horribly, horribly wrong? */ +#endif /* _WIN32 */ + /* * Get credential information for later use. */ - get_credential_info(); + init_process_policies(); /* * Attempt to get the pathname of the executable file. @@ -815,21 +883,21 @@ main(int argc, char *argv[]) optind_initial = optind; while ((opt = getopt(argc, argv, optstring)) != -1) { - switch (opt) { - case 'C': /* Configuration Profile */ - if (profile_exists (optarg)) { - set_profile_name (optarg); - } else { - cmdarg_err("Configuration Profile \"%s\" does not exist", optarg); - exit(1); - } - break; - case 'X': - ex_opt_add(optarg); - break; - default: - break; - } + switch (opt) { + case 'C': /* Configuration Profile */ + if (profile_exists (optarg, FALSE)) { + set_profile_name (optarg); + } else { + cmdarg_err("Configuration Profile \"%s\" does not exist", optarg); + return 1; + } + break; + case 'X': + ex_opt_add(optarg); + break; + default: + break; + } } optind = optind_initial; @@ -840,28 +908,28 @@ main(int argc, char *argv[]) /** Send All g_log messages to our own handler **/ log_flags = - G_LOG_LEVEL_ERROR| - G_LOG_LEVEL_CRITICAL| - G_LOG_LEVEL_WARNING| - G_LOG_LEVEL_MESSAGE| - G_LOG_LEVEL_INFO| - G_LOG_LEVEL_DEBUG| - G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION; + G_LOG_LEVEL_ERROR| + G_LOG_LEVEL_CRITICAL| + G_LOG_LEVEL_WARNING| + G_LOG_LEVEL_MESSAGE| + G_LOG_LEVEL_INFO| + G_LOG_LEVEL_DEBUG| + G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION; g_log_set_handler(NULL, - log_flags, - tshark_log_handler, NULL /* user_data */); + log_flags, + tshark_log_handler, NULL /* user_data */); g_log_set_handler(LOG_DOMAIN_MAIN, - log_flags, - tshark_log_handler, NULL /* user_data */); + log_flags, + tshark_log_handler, NULL /* user_data */); #ifdef HAVE_LIBPCAP g_log_set_handler(LOG_DOMAIN_CAPTURE, - log_flags, - tshark_log_handler, NULL /* user_data */); + log_flags, + tshark_log_handler, NULL /* user_data */); g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD, - log_flags, - tshark_log_handler, NULL /* user_data */); + log_flags, + tshark_log_handler, NULL /* user_data */); #endif initialize_funnel_ops(); @@ -906,7 +974,7 @@ main(int argc, char *argv[]) If none of our build or other processes uses "-G" with no arguments, we can just process it with the other arguments. */ if (argc >= 2 && strcmp(argv[1], "-G") == 0) { - proto_initialize_all_prefixes(); + proto_initialize_all_prefixes(); if (argc == 2) proto_registrar_dump_fields(1); @@ -925,16 +993,20 @@ main(int argc, char *argv[]) dissector_dump_decodes(); else if (strcmp(argv[2], "defaultprefs") == 0) write_prefs(NULL); + else if (strcmp(argv[2], "?") == 0) + glossary_option_help(); + else if (strcmp(argv[2], "-?") == 0) + glossary_option_help(); else if (strcmp(argv[2], "currentprefs") == 0) { read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path, &pf_open_errno, &pf_read_errno, &pf_path); write_prefs(NULL); } else { - cmdarg_err("Invalid \"%s\" option for -G flag", argv[2]); - exit(1); + cmdarg_err("Invalid \"%s\" option for -G flag, enter -G ? for more help.", argv[2]); + return 1; } } - exit(0); + return 0; } /* Set the C-language locale to the native environment. */ @@ -966,7 +1038,7 @@ main(int argc, char *argv[]) } /* Set the name resolution code's flags from the preferences. */ - g_resolv_flags = prefs_p->name_resolve; + gbl_resolv_flags = prefs_p->name_resolve; /* Read the disabled protocols file. */ read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno, @@ -1008,272 +1080,286 @@ main(int argc, char *argv[]) /* Now get our args */ while ((opt = getopt(argc, argv, optstring)) != -1) { switch (opt) { - case 'a': /* autostop criteria */ - case 'b': /* Ringbuffer option */ - case 'c': /* Capture x packets */ - case 'f': /* capture filter */ - case 'i': /* Use interface x */ - case 'p': /* Don't capture in promiscuous mode */ + case 'a': /* autostop criteria */ + case 'b': /* Ringbuffer option */ + case 'c': /* Capture x packets */ + case 'f': /* capture filter */ + case 'i': /* Use interface x */ + case 'p': /* Don't capture in promiscuous mode */ #ifdef HAVE_PCAP_CREATE - case 'I': /* Capture in monitor mode, if available */ + case 'I': /* Capture in monitor mode, if available */ #endif - case 'q': /* Don't print packet counts */ - case 's': /* Set the snapshot (capture) length */ - case 'w': /* Write to capture file x */ - case 'y': /* Set the pcap data link type */ + case 's': /* Set the snapshot (capture) length */ + case 'w': /* Write to capture file x */ + case 'y': /* Set the pcap data link type */ #if defined(_WIN32) || defined(HAVE_PCAP_CREATE) - case 'B': /* Buffer size */ + case 'B': /* Buffer size */ #endif /* _WIN32 or HAVE_PCAP_CREATE */ #ifdef HAVE_LIBPCAP - status = capture_opts_add_opt(&global_capture_opts, opt, optarg, &start_capture); - if(status != 0) { - exit(status); - } + status = capture_opts_add_opt(&global_capture_opts, opt, optarg, &start_capture); + if(status != 0) { + return status; + } #else - capture_option_specified = TRUE; - arg_error = TRUE; + capture_option_specified = TRUE; + arg_error = TRUE; #endif - break; - case 'C': - /* Configuration profile settings were already processed just ignore them this time*/ - break; - case 'd': /* Decode as rule */ - if (!add_decode_as(optarg)) - exit(1); - break; + break; + case 'C': + /* Configuration profile settings were already processed just ignore them this time*/ + break; + case 'd': /* Decode as rule */ + if (!add_decode_as(optarg)) + return 1; + break; #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS) - case 'K': /* Kerberos keytab file */ - read_keytab_file(optarg); - break; + case 'K': /* Kerberos keytab file */ + read_keytab_file(optarg); + break; #endif - case 'D': /* Print a list of capture devices and exit */ + case 'D': /* Print a list of capture devices and exit */ #ifdef HAVE_LIBPCAP - if_list = capture_interface_list(&err, &err_str); - if (if_list == NULL) { - switch (err) { - case CANT_GET_INTERFACE_LIST: - cmdarg_err("%s", err_str); - g_free(err_str); - break; + if_list = capture_interface_list(&err, &err_str); + if (if_list == NULL) { + switch (err) { + case CANT_GET_INTERFACE_LIST: + cmdarg_err("%s", err_str); + g_free(err_str); + break; - case NO_INTERFACES_FOUND: - cmdarg_err("There are no interfaces on which a capture can be done"); - break; - } - exit(2); + case NO_INTERFACES_FOUND: + cmdarg_err("There are no interfaces on which a capture can be done"); + break; } - capture_opts_print_interfaces(if_list); - free_interface_list(if_list); - exit(0); + return 2; + } + capture_opts_print_interfaces(if_list); + free_interface_list(if_list); + return 0; #else - capture_option_specified = TRUE; - arg_error = TRUE; + capture_option_specified = TRUE; + arg_error = TRUE; #endif - break; - case 'e': - /* Field entry */ - output_fields_add(output_fields, optarg); - break; - case 'E': - /* Field option */ - if(!output_fields_set_option(output_fields, optarg)) { - cmdarg_err("\"%s\" is not a valid field output option=value pair.", optarg); - output_fields_list_options(stderr); - exit(1); - } - break; - case 'F': - out_file_type = wtap_short_string_to_file_type(optarg); - if (out_file_type < 0) { - cmdarg_err("\"%s\" isn't a valid capture file type", optarg); - list_capture_types(); - exit(1); - } - break; - case 'h': /* Print help and exit */ - print_usage(TRUE); - exit(0); - break; - case 'l': /* "Line-buffer" standard output */ - /* This isn't line-buffering, strictly speaking, it's just - flushing the standard output after the information for - each packet is printed; however, that should be good - enough for all the purposes to which "-l" is put (and - is probably actually better for "-V", as it does fewer - writes). - - See the comment in "process_packet()" for an explanation of - why we do that, and why we don't just use "setvbuf()" to - make the standard output line-buffered (short version: in - Windows, "line-buffered" is the same as "fully-buffered", - and the output buffer is only flushed when it fills up). */ - line_buffered = TRUE; - break; - case 'L': /* Print list of link-layer types and exit */ + break; + case 'e': + /* Field entry */ + output_fields_add(output_fields, optarg); + break; + case 'E': + /* Field option */ + if(!output_fields_set_option(output_fields, optarg)) { + cmdarg_err("\"%s\" is not a valid field output option=value pair.", optarg); + output_fields_list_options(stderr); + return 1; + } + break; + case 'F': + out_file_type = wtap_short_string_to_file_type(optarg); + if (out_file_type < 0) { + cmdarg_err("\"%s\" isn't a valid capture file type", optarg); + list_capture_types(); + return 1; + } + break; + case 'W': /* Select extra information to save in our capture file */ + /* This is patterned after the -N flag which may not be the best idea. */ + if (strchr(optarg, 'n')) + out_file_name_res = TRUE; + break; + case 'H': /* Read address to name mappings from a hosts file */ + if (! read_hosts_file(optarg)) + { + cmdarg_err("Can't read host entries from \"%s\"", optarg); + return 1; + } + out_file_name_res = TRUE; + break; + + case 'h': /* Print help and exit */ + print_usage(TRUE); + return 0; + break; + case 'l': /* "Line-buffer" standard output */ + /* This isn't line-buffering, strictly speaking, it's just + flushing the standard output after the information for + each packet is printed; however, that should be good + enough for all the purposes to which "-l" is put (and + is probably actually better for "-V", as it does fewer + writes). + + See the comment in "process_packet()" for an explanation of + why we do that, and why we don't just use "setvbuf()" to + make the standard output line-buffered (short version: in + Windows, "line-buffered" is the same as "fully-buffered", + and the output buffer is only flushed when it fills up). */ + line_buffered = TRUE; + break; + case 'L': /* Print list of link-layer types and exit */ #ifdef HAVE_LIBPCAP - list_link_layer_types = TRUE; + list_link_layer_types = TRUE; #else - capture_option_specified = TRUE; - arg_error = TRUE; -#endif - break; -#if GLIB_CHECK_VERSION(2,10,0) - case 'P': /* Perform two pass analysis */ - perform_two_pass_analysis = TRUE; - break; + capture_option_specified = TRUE; + arg_error = TRUE; #endif - case 'n': /* No name resolution */ - g_resolv_flags = RESOLV_NONE; - break; - case 'N': /* Select what types of addresses/port #s to resolve */ - if (g_resolv_flags == RESOLV_ALL) - g_resolv_flags = RESOLV_NONE; - badopt = string_to_name_resolve(optarg, &g_resolv_flags); - if (badopt != '\0') { - cmdarg_err("-N specifies unknown resolving option '%c';", - badopt); - cmdarg_err_cont( " Valid options are 'm', 'n', 't', and 'C'"); - exit(1); - } - break; - case 'o': /* Override preference from command line */ - switch (prefs_set_pref(optarg)) { - - case PREFS_SET_OK: - break; - - case PREFS_SET_SYNTAX_ERR: - cmdarg_err("Invalid -o flag \"%s\"", optarg); - exit(1); - break; + break; + case 'P': /* Perform two pass analysis */ + perform_two_pass_analysis = TRUE; + break; + case 'n': /* No name resolution */ + gbl_resolv_flags = RESOLV_NONE; + break; + case 'N': /* Select what types of addresses/port #s to resolve */ + if (gbl_resolv_flags == RESOLV_ALL) + gbl_resolv_flags = RESOLV_NONE; + badopt = string_to_name_resolve(optarg, &gbl_resolv_flags); + if (badopt != '\0') { + cmdarg_err("-N specifies unknown resolving option '%c';", + badopt); + cmdarg_err_cont( " Valid options are 'm', 'n', 't', and 'C'"); + return 1; + } + break; + case 'o': /* Override preference from command line */ + switch (prefs_set_pref(optarg)) { - case PREFS_SET_NO_SUCH_PREF: - case PREFS_SET_OBSOLETE: - cmdarg_err("-o flag \"%s\" specifies unknown preference", optarg); - exit(1); - break; - } + case PREFS_SET_OK: break; - case 'r': /* Read capture file x */ - cf_name = g_strdup(optarg); - break; - case 'R': /* Read file filter */ - rfilter = optarg; - break; - case 'S': /* show packets in real time */ - print_packet_info = TRUE; - break; - case 't': /* Time stamp type */ - if (strcmp(optarg, "r") == 0) - timestamp_set_type(TS_RELATIVE); - else if (strcmp(optarg, "a") == 0) - timestamp_set_type(TS_ABSOLUTE); - else if (strcmp(optarg, "ad") == 0) - timestamp_set_type(TS_ABSOLUTE_WITH_DATE); - else if (strcmp(optarg, "d") == 0) - timestamp_set_type(TS_DELTA); - else if (strcmp(optarg, "dd") == 0) - timestamp_set_type(TS_DELTA_DIS); - else if (strcmp(optarg, "e") == 0) - timestamp_set_type(TS_EPOCH); - else { - cmdarg_err("Invalid time stamp type \"%s\"", - optarg); - cmdarg_err_cont("It must be \"r\" for relative, \"a\" for absolute,"); - cmdarg_err_cont("\"ad\" for absolute with date, or \"d\" for delta."); - exit(1); - } - break; - case 'T': /* printing Type */ - if (strcmp(optarg, "text") == 0) { - output_action = WRITE_TEXT; - print_format = PR_FMT_TEXT; - } else if (strcmp(optarg, "ps") == 0) { - output_action = WRITE_TEXT; - print_format = PR_FMT_PS; - } else if (strcmp(optarg, "pdml") == 0) { - output_action = WRITE_XML; - verbose = TRUE; - } else if (strcmp(optarg, "psml") == 0) { - output_action = WRITE_XML; - verbose = FALSE; - } else if(strcmp(optarg, "fields") == 0) { - output_action = WRITE_FIELDS; - verbose = TRUE; /* Need full tree info */ - } else { - cmdarg_err("Invalid -T parameter."); - cmdarg_err_cont("It must be \"ps\", \"text\", \"pdml\", \"psml\" or \"fields\"."); - exit(1); - } - break; - case 'u': /* Seconds type */ - if (strcmp(optarg, "s") == 0) - timestamp_set_seconds_type(TS_SECONDS_DEFAULT); - else if (strcmp(optarg, "hms") == 0) - timestamp_set_seconds_type(TS_SECONDS_HOUR_MIN_SEC); - else { - cmdarg_err("Invalid seconds type \"%s\"", optarg); - cmdarg_err_cont("It must be \"s\" for seconds or \"hms\" for hours, minutes and seconds."); - exit(1); - } + + case PREFS_SET_SYNTAX_ERR: + cmdarg_err("Invalid -o flag \"%s\"", optarg); + return 1; break; - case 'v': /* Show version and exit */ - { - GString *comp_info_str; - GString *runtime_info_str; - /* Assemble the compile-time version information string */ - comp_info_str = g_string_new("Compiled "); - get_compiled_version_info(comp_info_str, get_epan_compiled_version_info); - - /* Assemble the run-time version information string */ - runtime_info_str = g_string_new("Running "); - get_runtime_version_info(runtime_info_str, NULL); - show_version(comp_info_str, runtime_info_str); - g_string_free(comp_info_str, TRUE); - g_string_free(runtime_info_str, TRUE); - exit(0); + + case PREFS_SET_NO_SUCH_PREF: + case PREFS_SET_OBSOLETE: + cmdarg_err("-o flag \"%s\" specifies unknown preference", optarg); + return 1; break; } - case 'V': /* Verbose */ + break; + case 'q': /* Quiet */ + quiet = TRUE; + break; + case 'r': /* Read capture file x */ + cf_name = g_strdup(optarg); + break; + case 'R': /* Read file filter */ + rfilter = optarg; + break; + case 'S': /* show packets in real time */ + print_packet_info = TRUE; + break; + case 't': /* Time stamp type */ + if (strcmp(optarg, "r") == 0) + timestamp_set_type(TS_RELATIVE); + else if (strcmp(optarg, "a") == 0) + timestamp_set_type(TS_ABSOLUTE); + else if (strcmp(optarg, "ad") == 0) + timestamp_set_type(TS_ABSOLUTE_WITH_DATE); + else if (strcmp(optarg, "d") == 0) + timestamp_set_type(TS_DELTA); + else if (strcmp(optarg, "dd") == 0) + timestamp_set_type(TS_DELTA_DIS); + else if (strcmp(optarg, "e") == 0) + timestamp_set_type(TS_EPOCH); + else { + cmdarg_err("Invalid time stamp type \"%s\"", + optarg); + cmdarg_err_cont("It must be \"r\" for relative, \"a\" for absolute,"); + cmdarg_err_cont("\"ad\" for absolute with date, or \"d\" for delta."); + return 1; + } + break; + case 'T': /* printing Type */ + if (strcmp(optarg, "text") == 0) { + output_action = WRITE_TEXT; + print_format = PR_FMT_TEXT; + } else if (strcmp(optarg, "ps") == 0) { + output_action = WRITE_TEXT; + print_format = PR_FMT_PS; + } else if (strcmp(optarg, "pdml") == 0) { + output_action = WRITE_XML; verbose = TRUE; - /* The user asked for a verbose output, so let's ensure they get it, - * even if they're writing to a file. - */ - print_packet_info = TRUE; - break; - case 'x': /* Print packet data in hex (and ASCII) */ - print_hex = TRUE; - /* The user asked for hex output, so let's ensure they get it, - * even if they're writing to a file. - */ - print_packet_info = TRUE; - break; - case 'X': - 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 (!process_stat_cmd_arg(optarg)) { - cmdarg_err("invalid -z argument."); - cmdarg_err_cont(" -z argument must be one of :"); - list_stat_cmd_args(); - exit(1); - } + } else if (strcmp(optarg, "psml") == 0) { + output_action = WRITE_XML; + verbose = FALSE; + } else if(strcmp(optarg, "fields") == 0) { + output_action = WRITE_FIELDS; + verbose = TRUE; /* Need full tree info */ + } else { + cmdarg_err("Invalid -T parameter."); + cmdarg_err_cont("It must be \"ps\", \"text\", \"pdml\", \"psml\" or \"fields\"."); + return 1; + } + break; + case 'u': /* Seconds type */ + if (strcmp(optarg, "s") == 0) + timestamp_set_seconds_type(TS_SECONDS_DEFAULT); + else if (strcmp(optarg, "hms") == 0) + timestamp_set_seconds_type(TS_SECONDS_HOUR_MIN_SEC); + else { + cmdarg_err("Invalid seconds type \"%s\"", optarg); + cmdarg_err_cont("It must be \"s\" for seconds or \"hms\" for hours, minutes and seconds."); + return 1; + } + break; + case 'v': /* Show version and exit */ + { + GString *comp_info_str; + GString *runtime_info_str; + /* Assemble the compile-time version information string */ + comp_info_str = g_string_new("Compiled "); + get_compiled_version_info(comp_info_str, NULL, epan_get_compiled_version_info); + + /* Assemble the run-time version information string */ + runtime_info_str = g_string_new("Running "); + get_runtime_version_info(runtime_info_str, NULL); + show_version(comp_info_str, runtime_info_str); + g_string_free(comp_info_str, TRUE); + g_string_free(runtime_info_str, TRUE); + return 0; + break; + } + case 'V': /* Verbose */ + verbose = TRUE; + /* The user asked for a verbose output, so let's ensure they get it, + * even if they're writing to a file. + */ + print_packet_info = TRUE; + break; + case 'x': /* Print packet data in hex (and ASCII) */ + print_hex = TRUE; + /* The user asked for hex output, so let's ensure they get it, + * even if they're writing to a file. + */ + print_packet_info = TRUE; + break; + case 'X': + 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 (!process_stat_cmd_arg(optarg)) { + cmdarg_err("invalid -z argument."); + cmdarg_err_cont(" -z argument must be one of :"); + list_stat_cmd_args(); + return 1; + } + break; + default: + case '?': /* Bad flag - print usage message */ + switch(optopt) { + case 'F': + list_capture_types(); break; default: - case '?': /* Bad flag - print usage message */ - switch(optopt) { - case 'F': - list_capture_types(); - break; - default: - print_usage(TRUE); - } - exit(1); - break; + print_usage(TRUE); + } + return 1; + break; } } @@ -1281,12 +1367,12 @@ main(int argc, char *argv[]) if(WRITE_FIELDS != output_action && 0 != output_fields_num_fields(output_fields)) { cmdarg_err("Output fields were specified with \"-e\", " "but \"-Tfields\" was not specified."); - exit(1); + return 1; } else if(WRITE_FIELDS == output_action && 0 == output_fields_num_fields(output_fields)) { cmdarg_err("\"-Tfields\" was specified, but no fields were " "specified with \"-e\"."); - exit(1); + return 1; } /* If no capture filter or read filter has been specified, and there are @@ -1298,7 +1384,7 @@ main(int argc, char *argv[]) if (rfilter != NULL) { cmdarg_err("Read filters were specified both with \"-R\" " "and with additional command-line arguments"); - exit(1); + return 1; } rfilter = get_args_as_string(argc, argv, optind); } else { @@ -1306,7 +1392,7 @@ main(int argc, char *argv[]) if (global_capture_opts.has_cfilter) { cmdarg_err("Capture filters were specified both with \"-f\"" " and with additional command-line arguments"); - exit(1); + return 1; } global_capture_opts.has_cfilter = TRUE; global_capture_opts.cfilter = get_args_as_string(argc, argv, optind); @@ -1320,7 +1406,7 @@ main(int argc, char *argv[]) if (!global_capture_opts.saving_to_file) { /* We're not saving the capture to a file; if "-q" wasn't specified, we should print packet information */ - if (!global_capture_opts.quiet) + if (!quiet) print_packet_info = TRUE; } else { /* We're saving to a file; if we're writing to the standard output. @@ -1331,7 +1417,7 @@ main(int argc, char *argv[]) if (strcmp(global_capture_opts.save_file, "-") == 0 && print_packet_info) { cmdarg_err("You can't write both raw packet data and dissected packets" " to the standard output."); - exit(1); + return 1; } } #else @@ -1347,7 +1433,7 @@ main(int argc, char *argv[]) #endif if (arg_error) { print_usage(FALSE); - exit(1); + return 1; } /* We don't support capture filters when reading from a capture file @@ -1358,7 +1444,7 @@ main(int argc, char *argv[]) if (global_capture_opts.has_cfilter) { cmdarg_err("Only read filters, not capture filters, " "can be specified when reading a capture file."); - exit(1); + return 1; } } #endif @@ -1366,7 +1452,7 @@ main(int argc, char *argv[]) if (print_hex) { if (output_action != WRITE_TEXT) { cmdarg_err("Raw packet hex data can only be printed as text or PostScript"); - exit(1); + return 1; } } @@ -1377,12 +1463,12 @@ main(int argc, char *argv[]) if (cf_name) { /* Yes - that's bogus. */ cmdarg_err("You can't specify -L and a capture file to be read."); - exit(1); + return 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(1); + return 1; } } else { if (cf_name) { @@ -1393,22 +1479,22 @@ main(int argc, char *argv[]) if (global_capture_opts.multi_files_on) { cmdarg_err("Multiple capture files requested, but " "a capture isn't being done."); - exit(1); + return 1; } if (global_capture_opts.has_file_duration) { cmdarg_err("Switching capture files after a time interval was specified, but " "a capture isn't being done."); - exit(1); + return 1; } if (global_capture_opts.has_ring_num_files) { cmdarg_err("A ring buffer of capture files was specified, but " "a capture isn't being done."); - exit(1); + return 1; } if (global_capture_opts.has_autostop_files) { cmdarg_err("A maximum number of capture files was specified, but " "a capture isn't being done."); - exit(1); + return 1; } /* Note: TShark now allows the restriction of a _read_ file by packet count @@ -1418,7 +1504,7 @@ main(int argc, char *argv[]) if (global_capture_opts.has_autostop_duration) { cmdarg_err("A maximum capture time was specified, but " "a capture isn't being done."); - exit(1); + return 1; } } else { /* @@ -1430,30 +1516,36 @@ main(int argc, char *argv[]) /* When capturing, we only support writing libpcap format. */ if (out_file_type != WTAP_FILE_PCAP) { cmdarg_err("Live captures can only be saved in libpcap format."); - exit(1); + return 1; } if (global_capture_opts.multi_files_on) { /* Multiple-file mode doesn't work under certain conditions: a) it doesn't work if you're writing to the standard output; b) it doesn't work if you're writing to a pipe; - */ + */ if (strcmp(global_capture_opts.save_file, "-") == 0) { cmdarg_err("Multiple capture files requested, but " "the capture is being written to the standard output."); - exit(1); + return 1; } if (global_capture_opts.output_to_pipe) { cmdarg_err("Multiple capture files requested, but " "the capture file is a pipe."); - exit(1); + return 1; } if (!global_capture_opts.has_autostop_filesize && - !global_capture_opts.has_file_duration) { + !global_capture_opts.has_file_duration) { cmdarg_err("Multiple capture files requested, but " "no maximum capture file size or duration was specified."); - exit(1); + return 1; } } + /* Currently, we don't support read filters when capturing + and saving the packets. */ + if (rfilter != NULL) { + cmdarg_err("Read filters aren't supported when capturing and saving the captured packets."); + return 1; + } } else { /* They didn't specify a "-w" flag, so we won't be saving to a capture file. Check for options that only make sense if @@ -1461,12 +1553,12 @@ main(int argc, char *argv[]) if (global_capture_opts.has_autostop_filesize) { cmdarg_err("Maximum capture file size specified, but " "capture isn't being saved to a file."); - exit(1); + return 1; } if (global_capture_opts.multi_files_on) { cmdarg_err("Multiple capture files requested, but " "the capture isn't being saved to a file."); - exit(1); + return 1; } } } @@ -1488,6 +1580,22 @@ main(int argc, char *argv[]) of the filter. We can now process all the "-z" arguments. */ start_requested_stats(); +#ifdef HAVE_LIBPCAP + /* We currently don't support taps, or printing dissected packets, + if we're writing to a pipe. */ + if (global_capture_opts.saving_to_file && + global_capture_opts.output_to_pipe) { + if (have_tap_listeners()) { + cmdarg_err("Taps aren't supported when saving to a pipe."); + return 1; + } + if (print_packet_info) { + cmdarg_err("Printing dissected packets isn't supported when saving to a pipe."); + return 1; + } + } +#endif + /* disabled protocols as per configuration file */ if (gdp_path == NULL && dp_path == NULL) { set_disabled_protos_list(); @@ -1521,7 +1629,7 @@ main(int argc, char *argv[]) } } #endif - exit(2); + return 2; } } cfile.rfcode = rfcode; @@ -1570,7 +1678,7 @@ main(int argc, char *argv[]) if (cf_open(&cfile, cf_name, FALSE, &err) != CF_OK) { epan_cleanup(); - exit(2); + return 2; } /* Set timestamp precision; there should arguably be a command-line @@ -1600,15 +1708,16 @@ main(int argc, char *argv[]) /* Process the packets in the file */ #ifdef HAVE_LIBPCAP - err = load_cap_file(&cfile, global_capture_opts.save_file, out_file_type, + err = load_cap_file(&cfile, global_capture_opts.save_file, out_file_type, out_file_name_res, global_capture_opts.has_autostop_packets ? global_capture_opts.autostop_packets : 0, global_capture_opts.has_autostop_filesize ? global_capture_opts.autostop_filesize : 0); #else - err = load_cap_file(&cfile, NULL, out_file_type, 0, 0); + err = load_cap_file(&cfile, NULL, out_file_type, out_file_name_res, 0, 0); #endif if (err != 0) { - epan_cleanup(); - exit(2); + /* We still dump out the results of taps, etc., as we might have + read some packets; however, we exit with an error status. */ + exit_status = 2; } } else { /* No capture file specified, so we're supposed to do a live capture @@ -1624,14 +1733,14 @@ main(int argc, char *argv[]) detailed_err = cant_load_winpcap_err("TShark"); cmdarg_err_cont("%s", detailed_err); g_free(detailed_err); - exit(2); + return 2; } #endif /* trim the interface name and exit if that failed */ if (!capture_opts_trim_iface(&global_capture_opts, (prefs_p->capture_device) ? get_if_name(prefs_p->capture_device) : NULL)) { - exit(2); + return 2; } /* if requested, list the link layer types and exit */ @@ -1645,25 +1754,24 @@ main(int argc, char *argv[]) if (caps == NULL) { cmdarg_err("%s", err_str); g_free(err_str); - exit(2); + return 2; } if (caps->data_link_types == NULL) { cmdarg_err("The capture device \"%s\" has no data link types.", global_capture_opts.iface); - exit(2); + return 2; } capture_opts_print_if_capabilities(caps, global_capture_opts.monitor_mode); free_if_capabilities(caps); - exit(0); + return 0; } if (print_packet_info) { if (!write_preamble(NULL)) { - err = errno; - show_print_file_io_error(err); - return err; + show_print_file_io_error(errno); + return 2; } - } else if (!global_capture_opts.quiet) { + } else if (!quiet) { /* * We're not printing information for each packet, and the user * didn't ask us not to print a count of packets as they arrive, @@ -1680,7 +1788,18 @@ main(int argc, char *argv[]) /* For now, assume libpcap gives microsecond precision. */ timestamp_set_precision(TS_PREC_AUTO_USEC); + /* + * XXX - this returns FALSE if an error occurred, but it also + * returns FALSE if the capture stops because a time limit + * was reached (and possibly other limits), so we can't assume + * it means an error. + * + * The capture code is a bit twisty, so it doesn't appear to + * be an easy fix. We just ignore the return value for now. + * Instead, pass on the exit status from the capture child. + */ capture(); + exit_status = global_capture_opts.fork_child_status; if (print_packet_info) { if (!write_finale()) { @@ -1691,16 +1810,13 @@ main(int argc, char *argv[]) #else /* No - complain. */ cmdarg_err("This version of TShark was not built with support for capturing packets."); - exit(2); + return 2; #endif } g_free(cf_name); -#if GLIB_CHECK_VERSION(2,10,0) - if (cfile.plist_start != NULL) - g_slice_free_chain(frame_data, cfile.plist_start, next); -#endif + cap_file_free_frames(&cfile); draw_tap_listeners(TRUE); funnel_dump_all_text_windows(); @@ -1709,7 +1825,7 @@ main(int argc, char *argv[]) output_fields_free(output_fields); output_fields = NULL; - return 0; + return exit_status; } /*#define USE_BROKEN_G_MAIN_LOOP*/ @@ -1727,13 +1843,13 @@ main(int argc, char *argv[]) typedef gboolean (*pipe_input_cb_t) (gint source, gpointer user_data); typedef struct pipe_input_tag { - gint source; - gpointer user_data; - int *child_process; - pipe_input_cb_t input_cb; - guint pipe_input_id; + gint source; + gpointer user_data; + int *child_process; + pipe_input_cb_t input_cb; + guint pipe_input_id; #ifdef _WIN32 - GStaticMutex callback_running; + GStaticMutex callback_running; #endif } pipe_input_t; @@ -1749,55 +1865,55 @@ pipe_timer_cb(gpointer data) DWORD avail = 0; gboolean result, result1; DWORD childstatus; - pipe_input_t *pipe_input = data; + pipe_input_t *pipe_input_p = data; gint iterations = 0; - g_static_mutex_lock (&pipe_input->callback_running); + g_static_mutex_lock (&pipe_input_p->callback_running); /* try to read data from the pipe only 5 times, to avoid blocking */ while(iterations < 5) { - /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: new iteration");*/ + /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: new iteration");*/ - /* Oddly enough although Named pipes don't work on win9x, - PeekNamedPipe does !!! */ - handle = (HANDLE) _get_osfhandle (pipe_input->source); - result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL); + /* Oddly enough although Named pipes don't work on win9x, + PeekNamedPipe does !!! */ + handle = (HANDLE) _get_osfhandle (pipe_input_p->source); + result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL); - /* Get the child process exit status */ - result1 = GetExitCodeProcess((HANDLE)*(pipe_input->child_process), - &childstatus); + /* Get the child process exit status */ + result1 = GetExitCodeProcess((HANDLE)*(pipe_input_p->child_process), + &childstatus); - /* If the Peek returned an error, or there are bytes to be read - or the childwatcher thread has terminated then call the normal - callback */ - if (!result || avail > 0 || childstatus != STILL_ACTIVE) { + /* If the Peek returned an error, or there are bytes to be read + or the childwatcher thread has terminated then call the normal + callback */ + if (!result || avail > 0 || childstatus != STILL_ACTIVE) { - /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: data avail");*/ + /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: data avail");*/ - /* And call the real handler */ - if (!pipe_input->input_cb(pipe_input->source, pipe_input->user_data)) { - g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: input pipe closed, iterations: %u", iterations); - /* pipe closed, return false so that the timer is stopped */ - g_static_mutex_unlock (&pipe_input->callback_running); - return FALSE; - } - } - else { - /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: no data avail");*/ - /* No data, stop now */ - break; - } + /* And call the real handler */ + if (!pipe_input_p->input_cb(pipe_input_p->source, pipe_input_p->user_data)) { + g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: input pipe closed, iterations: %u", iterations); + /* pipe closed, return false so that the timer is stopped */ + g_static_mutex_unlock (&pipe_input_p->callback_running); + return FALSE; + } + } + else { + /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: no data avail");*/ + /* No data, stop now */ + break; + } - iterations++; + iterations++; } - /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: finished with iterations: %u, new timer", iterations);*/ + /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: finished with iterations: %u, new timer", iterations);*/ - g_static_mutex_unlock (&pipe_input->callback_running); + g_static_mutex_unlock (&pipe_input_p->callback_running); - /* we didn't stopped the timer, so let it run */ - return TRUE; + /* we didn't stopped the timer, so let it run */ + return TRUE; } #endif @@ -1806,26 +1922,26 @@ void pipe_input_set_handler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb) { - pipe_input.source = source; - pipe_input.child_process = child_process; - pipe_input.user_data = user_data; - pipe_input.input_cb = input_cb; + pipe_input.source = source; + pipe_input.child_process = child_process; + pipe_input.user_data = user_data; + pipe_input.input_cb = input_cb; #ifdef _WIN32 - g_static_mutex_init(&pipe_input.callback_running); - /* Tricky to use pipes in win9x, as no concept of wait. NT can - do this but that doesn't cover all win32 platforms. GTK can do - this but doesn't seem to work over processes. Attempt to do - something similar here, start a timer and check for data on every - timeout. */ - /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/ - pipe_input.pipe_input_id = g_timeout_add(200, pipe_timer_cb, &pipe_input); + g_static_mutex_init(&pipe_input.callback_running); + /* Tricky to use pipes in win9x, as no concept of wait. NT can + do this but that doesn't cover all win32 platforms. GTK can do + this but doesn't seem to work over processes. Attempt to do + something similar here, start a timer and check for data on every + timeout. */ + /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/ + pipe_input.pipe_input_id = g_timeout_add(200, pipe_timer_cb, &pipe_input); #endif } #ifdef HAVE_LIBPCAP -static int +static gboolean capture(void) { gboolean ret; @@ -1869,10 +1985,17 @@ capture(void) /* Catch a CTRL+C event and, if we get it, clean up and exit. */ SetConsoleCtrlHandler(capture_cleanup, TRUE); #else /* _WIN32 */ - /* Catch SIGINT and SIGTERM and, if we get either of them, clean up - and exit. */ + /* Catch SIGINT and SIGTERM and, if we get either of them, + clean up and exit. If SIGHUP isn't being ignored, catch + it too and, if we get it, clean up and exit. + + We restart any read that was in progress, so that it doesn't + disrupt reading from the sync pipe. The signal handler tells + the capture child to finish; it will report that it finished, + or will exit abnormally, so we'll stop reading from the sync + pipe, pick up the exit status, and quit. */ action.sa_handler = capture_cleanup; - action.sa_flags = 0; + action.sa_flags = SA_RESTART; sigemptyset(&action.sa_mask); sigaction(SIGTERM, &action, NULL); sigaction(SIGINT, &action, NULL); @@ -1882,9 +2005,12 @@ capture(void) #ifdef SIGINFO /* Catch SIGINFO and, if we get it and we're capturing to a file in - quiet mode, report the number of packets we've captured. */ + quiet mode, report the number of packets we've captured. + + Again, restart any read that was in progress, so that it doesn't + disrupt reading from the sync pipe. */ action.sa_handler = report_counts_siginfo; - action.sa_flags = 0; + action.sa_flags = SA_RESTART; sigemptyset(&action.sa_mask); sigaction(SIGINFO, &action, NULL); #endif /* SIGINFO */ @@ -1939,8 +2065,8 @@ capture(void) #endif /* Call the real handler */ if (!pipe_input.input_cb(pipe_input.source, pipe_input.user_data)) { - g_log(NULL, G_LOG_LEVEL_DEBUG, "input pipe closed"); - return FALSE; + g_log(NULL, G_LOG_LEVEL_DEBUG, "input pipe closed"); + return FALSE; } #ifdef USE_TSHARK_SELECT } @@ -1961,8 +2087,8 @@ void main_window_update(void) void capture_input_error_message(capture_options *capture_opts _U_, char *error_msg, char *secondary_error_msg) { - cmdarg_err("%s", error_msg); - cmdarg_err_cont("%s", secondary_error_msg); + cmdarg_err("%s", error_msg); + cmdarg_err_cont("%s", secondary_error_msg); } @@ -1970,30 +2096,30 @@ capture_input_error_message(capture_options *capture_opts _U_, char *error_msg, void capture_input_cfilter_error_message(capture_options *capture_opts, char *error_message) { - dfilter_t *rfcode = NULL; - - - if (dfilter_compile(capture_opts->cfilter, &rfcode) && rfcode != NULL) { - cmdarg_err( - "Invalid capture filter: \"%s\"!\n" - "\n" - "That string looks like a valid display filter; however, it isn't a valid\n" - "capture filter (%s).\n" - "\n" - "Note that display filters and capture filters don't have the same syntax,\n" - "so you can't use most display filter expressions as capture filters.\n" - "\n" - "See the User's Guide for a description of the capture filter syntax.", - capture_opts->cfilter, error_message); - dfilter_free(rfcode); - } else { - cmdarg_err( - "Invalid capture filter: \"%s\"!\n" - "\n" - "That string isn't a valid capture filter (%s).\n" - "See the User's Guide for a description of the capture filter syntax.", - capture_opts->cfilter, error_message); - } + dfilter_t *rfcode = NULL; + + + if (dfilter_compile(capture_opts->cfilter, &rfcode) && rfcode != NULL) { + cmdarg_err( + "Invalid capture filter: \"%s\"!\n" + "\n" + "That string looks like a valid display filter; however, it isn't a valid\n" + "capture filter (%s).\n" + "\n" + "Note that display filters and capture filters don't have the same syntax,\n" + "so you can't use most display filter expressions as capture filters.\n" + "\n" + "See the User's Guide for a description of the capture filter syntax.", + capture_opts->cfilter, error_message); + dfilter_free(rfcode); + } else { + cmdarg_err( + "Invalid capture filter: \"%s\"!\n" + "\n" + "That string isn't a valid capture filter (%s).\n" + "See the User's Guide for a description of the capture filter syntax.", + capture_opts->cfilter, error_message); + } } @@ -2004,7 +2130,6 @@ capture_input_new_file(capture_options *capture_opts, gchar *new_file) gboolean is_tempfile; int err; - if(capture_opts->state == CAPTURE_PREPARING) { g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture started!"); } @@ -2083,6 +2208,7 @@ capture_input_new_packets(capture_options *capture_opts, int to_read) if(do_dissection) { while (to_read-- && cf->wth) { + wtap_cleareof(cf->wth); ret = wtap_read(cf->wth, &err, &err_info, &data_offset); if(ret == FALSE) { /* read from file failed, tell the capture child to stop */ @@ -2095,7 +2221,7 @@ capture_input_new_packets(capture_options *capture_opts, int to_read) filtering_tap_listeners, tap_flags); } if (ret != FALSE) { - /* packet sucessfully read and gone through the "Read Filter" */ + /* packet successfully read and gone through the "Read Filter" */ packet_count++; } } @@ -2179,14 +2305,23 @@ capture_input_drops(capture_options *capture_opts _U_, guint32 dropped) } -/* capture child closed its side of the pipe, do the required cleanup */ +/* + * Capture child closed its side of the pipe, report any error and + * do the required cleanup. + */ void -capture_input_closed(capture_options *capture_opts) +capture_input_closed(capture_options *capture_opts, gchar *msg) { + if (msg != NULL) + fprintf(stderr, "tshark: %s\n", msg); + report_counts(); if(capture_opts->cf != NULL && ((capture_file *) capture_opts->cf)->wth != NULL) { wtap_close(((capture_file *) capture_opts->cf)->wth); + if(((capture_file *) capture_opts->cf)->user_saved == FALSE){ + ws_unlink(((capture_file *) capture_opts->cf)->filename); + } } #ifdef USE_BROKEN_G_MAIN_LOOP /*g_main_loop_quit(loop);*/ @@ -2212,10 +2347,8 @@ capture_cleanup(DWORD ctrltype _U_) and quit, just as we handle SIGINT, SIGHUP, and SIGTERM in that way on UNIX. - However, as handlers run in a new thread, we can't just longjmp - out; we have to set "ld.go" to FALSE, and must return TRUE so that - no other handler - such as one that would terminate the process - - gets called. + We must return TRUE so that no other handler - such as one that would + terminate the process - gets called. XXX - for some reason, typing ^C to TShark, if you run this in a Cygwin console window in at least some versions of Cygwin, @@ -2241,35 +2374,40 @@ capture_cleanup(int signum _U_) { /* tell the capture child to stop */ sync_pipe_stop(&global_capture_opts); + + /* don't stop our own loop already here, otherwise status messages and + * cleanup wouldn't be done properly. The child will indicate the stop of + * everything by calling capture_input_closed() later */ } #endif /* _WIN32 */ #endif /* HAVE_LIBPCAP */ -#if GLIB_CHECK_VERSION(2,10,0) static gboolean process_packet_first_pass(capture_file *cf, gint64 offset, const struct wtap_pkthdr *whdr, union wtap_pseudo_header *pseudo_header, const guchar *pd) { - frame_data *fdata = g_slice_new(frame_data); + frame_data fdlocal; + guint32 framenum; epan_dissect_t edt; gboolean passed; - /* Count this packet. */ - cf->count++; + /* The frame number of this packet is one more than the count of + frames in this packet. */ + framenum = cf->count + 1; /* If we're not running a display filter and we're not printing any packet information, we don't need to do a dissection. This means that all packets can be marked as 'passed'. */ passed = TRUE; - frame_data_init(fdata, cf->count, whdr, offset, cum_bytes); + frame_data_init(&fdlocal, framenum, whdr, offset, cum_bytes); /* If we're going to print packet information, or we're going to run a read filter, or we're going to process taps, set up to do a dissection and do so. */ if (do_dissection) { - if (g_resolv_flags) + if (gbl_resolv_flags) /* Grab any resolved addresses */ host_name_lookup_process(NULL); @@ -2284,10 +2422,10 @@ process_packet_first_pass(capture_file *cf, if (cf->rfcode) epan_dissect_prime_dfilter(&edt, cf->rfcode); - frame_data_set_before_dissect(fdata, &cf->elapsed_time, + frame_data_set_before_dissect(&fdlocal, &cf->elapsed_time, &first_ts, &prev_dis_ts, &prev_cap_ts); - epan_dissect_run(&edt, pseudo_header, pd, fdata, NULL); + epan_dissect_run(&edt, pseudo_header, pd, &fdlocal, NULL); /* Run the read filter if we have one. */ if (cf->rfcode) @@ -2295,11 +2433,9 @@ process_packet_first_pass(capture_file *cf, } if (passed) { - frame_data_set_after_dissect(fdata, &cum_bytes, &prev_dis_ts); - cap_file_add_fdata(cf, fdata); + frame_data_set_after_dissect(&fdlocal, &cum_bytes, &prev_dis_ts); + cap_file_add_fdata(cf, &fdlocal); } - else - g_slice_free(frame_data, fdata); if (do_dissection) epan_dissect_cleanup(&edt); @@ -2326,7 +2462,7 @@ process_packet_second_pass(capture_file *cf, frame_data *fdata, run a read filter, or we're going to process taps, set up to do a dissection and do so. */ if (do_dissection) { - if (g_resolv_flags) + if (gbl_resolv_flags) /* Grab any resolved addresses */ host_name_lookup_process(NULL); @@ -2418,17 +2554,16 @@ process_packet_second_pass(capture_file *cf, frame_data *fdata, } return passed; } -#endif static int load_cap_file(capture_file *cf, char *save_file, int out_file_type, - int max_packet_count, gint64 max_byte_count) + gboolean out_file_name_res, int max_packet_count, gint64 max_byte_count) { gint linktype; int snapshot_length; wtap_dumper *pdh; int err; - gchar *err_info; + gchar *err_info = NULL; gint64 data_offset; char *save_file_string = NULL; gboolean filtering_tap_listeners; @@ -2490,6 +2625,13 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type, pdh = NULL; } + if (pdh && out_file_name_res) { + if (!wtap_dump_set_addrinfo_list(pdh, get_addrinfo_list())) { + cmdarg_err("The file format \"%s\" doesn't support name resolution information.", + wtap_file_type_short_string(out_file_type)); + } + } + /* Do we have any tap listeners with filters? */ filtering_tap_listeners = have_filtering_tap_listeners(); @@ -2497,7 +2639,7 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type, tap_flags = union_of_tap_listener_flags(); if (perform_two_pass_analysis) { -#if GLIB_CHECK_VERSION(2,10,0) + guint32 framenum; frame_data *fdata; int old_max_packet_count = max_packet_count; @@ -2525,7 +2667,8 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type, max_packet_count = old_max_packet_count; - for (fdata = cf->plist_start; err == 0 && fdata != NULL; fdata = fdata->next) { + for (framenum = 1; err == 0 && framenum <= cf->count; framenum++) { + fdata = cap_file_find_fdata(cf, framenum); if (wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header, cf->pd, fdata->cap_len, &err, &err_info)) { if (process_packet_second_pass(cf, fdata, @@ -2556,7 +2699,6 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type, } } } -#endif } else { while (wtap_read(cf->wth, &err, &err_info, &data_offset)) { @@ -2590,33 +2732,61 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type, } if (err != 0) { - /* Print a message noting that the read failed somewhere along the line. */ + /* + * Print a message noting that the read failed somewhere along the line. + * + * If we're printing packet data, and the standard output and error are + * going to the same place, flush the standard output, so everything + * buffered up is written, and then print a newline to the standard error + * before printing the error message, to separate it from the packet + * data. (Alas, that only works on UN*X; st_dev is meaningless, and + * the _fstat() documentation at Microsoft doesn't indicate whether + * st_ino is even supported.) + */ +#ifndef _WIN32 + if (print_packet_info) { + struct stat stat_stdout, stat_stderr; + + if (fstat(1, &stat_stdout) == 0 && fstat(2, &stat_stderr) == 0) { + if (stat_stdout.st_dev == stat_stderr.st_dev && + stat_stdout.st_ino == stat_stderr.st_ino) { + fflush(stdout); + fprintf(stderr, "\n"); + } + } + } +#endif switch (err) { case WTAP_ERR_UNSUPPORTED_ENCAP: - cmdarg_err("\"%s\" has a packet with a network type that TShark doesn't support.\n(%s)", + cmdarg_err("The file \"%s\" has a packet with a network type that TShark doesn't support.\n(%s)", cf->filename, err_info); g_free(err_info); break; case WTAP_ERR_CANT_READ: - cmdarg_err("An attempt to read from \"%s\" failed for some unknown reason.", + cmdarg_err("An attempt to read from the file \"%s\" failed for some unknown reason.", cf->filename); break; case WTAP_ERR_SHORT_READ: - cmdarg_err("\"%s\" appears to have been cut short in the middle of a packet.", + cmdarg_err("The file \"%s\" appears to have been cut short in the middle of a packet.", cf->filename); break; case WTAP_ERR_BAD_RECORD: - cmdarg_err("\"%s\" appears to be damaged or corrupt.\n(%s)", + cmdarg_err("The file \"%s\" appears to be damaged or corrupt.\n(%s)", cf->filename, err_info); g_free(err_info); break; + case WTAP_ERR_DECOMPRESS: + cmdarg_err("The compressed file \"%s\" appears to be damaged or corrupt.\n" + "(%s)", cf->filename, err_info); + break; + default: - cmdarg_err("An error occurred while reading \"%s\": %s.", + cmdarg_err("An error occurred while reading the file \"%s\": %s.", cf->filename, wtap_strerror(err)); break; } @@ -2674,7 +2844,7 @@ process_packet(capture_file *cf, gint64 offset, const struct wtap_pkthdr *whdr, run a read filter, or we're going to process taps, set up to do a dissection and do so. */ if (do_dissection) { - if (print_packet_info && g_resolv_flags) + if (print_packet_info && gbl_resolv_flags) /* Grab any resolved addresses */ host_name_lookup_process(NULL); @@ -2853,7 +3023,7 @@ print_columns(capture_file *cf) if (column_len < 3) column_len = 3; line_bufp = get_line_buf(buf_offset + column_len); - sprintf(line_bufp + buf_offset, "%3s", cf->cinfo.col_data[i]); + g_snprintf(line_bufp + buf_offset, (int)column_len + 1, "%3s", cf->cinfo.col_data[i]); break; case COL_CLS_TIME: @@ -2864,7 +3034,7 @@ print_columns(capture_file *cf) if (column_len < 10) column_len = 10; line_bufp = get_line_buf(buf_offset + column_len); - sprintf(line_bufp + buf_offset, "%10s", cf->cinfo.col_data[i]); + g_snprintf(line_bufp + buf_offset, (int)column_len + 1, "%10s", cf->cinfo.col_data[i]); break; case COL_DEF_SRC: @@ -2880,7 +3050,7 @@ print_columns(capture_file *cf) if (column_len < 12) column_len = 12; line_bufp = get_line_buf(buf_offset + column_len); - sprintf(line_bufp + buf_offset, "%12s", cf->cinfo.col_data[i]); + g_snprintf(line_bufp + buf_offset, (int)column_len + 1, "%12s", cf->cinfo.col_data[i]); break; case COL_DEF_DST: @@ -2896,13 +3066,13 @@ print_columns(capture_file *cf) if (column_len < 12) column_len = 12; line_bufp = get_line_buf(buf_offset + column_len); - sprintf(line_bufp + buf_offset, "%-12s", cf->cinfo.col_data[i]); + g_snprintf(line_bufp + buf_offset, (int)column_len + 1, "%-12s", cf->cinfo.col_data[i]); break; default: column_len = strlen(cf->cinfo.col_data[i]); line_bufp = get_line_buf(buf_offset + column_len); - strcat(line_bufp + buf_offset, cf->cinfo.col_data[i]); + g_strlcat(line_bufp + buf_offset, cf->cinfo.col_data[i], column_len + 1); break; } buf_offset += column_len; @@ -2913,9 +3083,9 @@ print_columns(capture_file *cf) * * If we printed a network source and are printing a * network destination of the same type next, separate - * them with "->"; if we printed a network destination + * them with " -> "; if we printed a network destination * and are printing a network source of the same type - * next, separate them with "<-"; otherwise separate them + * next, separate them with " <- "; otherwise separate them * with a space. * * We add enough space to the buffer for " <- " or " -> ", @@ -2932,12 +3102,12 @@ print_columns(capture_file *cf) case COL_DEF_DST: case COL_RES_DST: case COL_UNRES_DST: - strcat(line_bufp + buf_offset, " -> "); + g_strlcat(line_bufp + buf_offset, " -> ", 5); buf_offset += 4; break; default: - strcat(line_bufp + buf_offset, " "); + g_strlcat(line_bufp + buf_offset, " ", 5); buf_offset += 1; break; } @@ -2951,12 +3121,12 @@ print_columns(capture_file *cf) case COL_DEF_DL_DST: case COL_RES_DL_DST: case COL_UNRES_DL_DST: - strcat(line_bufp + buf_offset, " -> "); + g_strlcat(line_bufp + buf_offset, " -> ", 5); buf_offset += 4; break; default: - strcat(line_bufp + buf_offset, " "); + g_strlcat(line_bufp + buf_offset, " ", 5); buf_offset += 1; break; } @@ -2970,12 +3140,12 @@ print_columns(capture_file *cf) case COL_DEF_NET_DST: case COL_RES_NET_DST: case COL_UNRES_NET_DST: - strcat(line_bufp + buf_offset, " -> "); + g_strlcat(line_bufp + buf_offset, " -> ", 5); buf_offset += 4; break; default: - strcat(line_bufp + buf_offset, " "); + g_strlcat(line_bufp + buf_offset, " ", 5); buf_offset += 1; break; } @@ -2989,12 +3159,12 @@ print_columns(capture_file *cf) case COL_DEF_SRC: case COL_RES_SRC: case COL_UNRES_SRC: - strcat(line_bufp + buf_offset, " <- "); + g_strlcat(line_bufp + buf_offset, " <- ", 5); buf_offset += 4; break; default: - strcat(line_bufp + buf_offset, " "); + g_strlcat(line_bufp + buf_offset, " ", 5); buf_offset += 1; break; } @@ -3008,12 +3178,12 @@ print_columns(capture_file *cf) case COL_DEF_DL_SRC: case COL_RES_DL_SRC: case COL_UNRES_DL_SRC: - strcat(line_bufp + buf_offset, " <- "); + g_strlcat(line_bufp + buf_offset, " <- ", 5); buf_offset += 4; break; default: - strcat(line_bufp + buf_offset, " "); + g_strlcat(line_bufp + buf_offset, " ", 5); buf_offset += 1; break; } @@ -3027,19 +3197,19 @@ print_columns(capture_file *cf) case COL_DEF_NET_SRC: case COL_RES_NET_SRC: case COL_UNRES_NET_SRC: - strcat(line_bufp + buf_offset, " <- "); + g_strlcat(line_bufp + buf_offset, " <- ", 5); buf_offset += 4; break; default: - strcat(line_bufp + buf_offset, " "); + g_strlcat(line_bufp + buf_offset, " ", 5); buf_offset += 1; break; } break; default: - strcat(line_bufp + buf_offset, " "); + g_strlcat(line_bufp + buf_offset, " ", 5); buf_offset += 1; break; } @@ -3192,6 +3362,9 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err) cf->state = FILE_READ_IN_PROGRESS; + wtap_set_cb_new_ipv4(cf->wth, add_ipv4_name); + wtap_set_cb_new_ipv6(cf->wth, (wtap_new_ipv6_callback_t) add_ipv6_name); + return CF_OK; fail: @@ -3357,6 +3530,15 @@ cf_open_error_message(int err, gchar *err_info, gboolean for_writing, errmsg = "A full header couldn't be written to the file \"%s\"."; break; + case WTAP_ERR_DECOMPRESS: + /* Seen only when opening a capture file for reading. */ + g_snprintf(errmsg_errno, sizeof(errmsg_errno), + "The compressed file \"%%s\" appears to be damaged or corrupt.\n" + "(%s)", err_info); + g_free(err_info); + errmsg = errmsg_errno; + break; + default: g_snprintf(errmsg_errno, sizeof(errmsg_errno), "The file \"%%s\" could not be %s: %s.",