X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=tfshark.c;h=a7e36a952ac41723f92464d9661ac4551a0784a3;hb=f0fb6ee50c953ac07eb76d47036a761a57f35491;hp=2d4315d9a2943789dbeaffc64b9ab5571225adfa;hpb=741db4c751b44bfa4ab2dc0cb4bd882d4732c55c;p=metze%2Fwireshark%2Fwip.git diff --git a/tfshark.c b/tfshark.c index 2d4315d9a2..a7e36a952a 100644 --- a/tfshark.c +++ b/tfshark.c @@ -6,19 +6,7 @@ * By Gerald Combs * Copyright 1998 Gerald Combs * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * SPDX-License-Identifier: GPL-2.0-or-later */ #include @@ -29,49 +17,29 @@ #include #include -#ifdef HAVE_UNISTD_H -#include -#endif - #ifdef HAVE_GETOPT_H #include #endif #include -#ifdef HAVE_FCNTL_H -#include -#endif - -#include - -#ifdef HAVE_SYS_STAT_H -# include -#endif - -#ifdef HAVE_LIBZ -#include /* to get the libz version number */ -#endif - -#ifndef HAVE_GETOPT +#ifndef HAVE_GETOPT_LONG #include "wsutil/wsgetopt.h" #endif #include #include -#include #include #include #include #include -#include -#include #include -#include -#include -#include +#include +#include +#include +#include #include "globals.h" #include @@ -87,13 +55,15 @@ #include #include #include "ui/util.h" -#include "version_info.h" -#include "register.h" +#include "ui/decode_as_utils.h" +#include "ui/dissect_opts.h" +#include "epan/register.h" #include #include #include -#include #include +#include "extcap.h" + #include #include @@ -108,21 +78,20 @@ #include #endif -/* - * This is the template for the decode as option; it is shared between the - * various functions that output the usage for this parameter. - */ -static const gchar decode_as_arg_template[] = "==,"; +#define INVALID_OPTION 1 +#define NO_FILE_SPECIFIED 1 +#define INIT_ERROR 2 +#define INVALID_FILTER 2 +#define OPEN_ERROR 2 + +capture_file cfile; static guint32 cum_bytes; -static const frame_data *ref; static frame_data ref_frame; -static frame_data *prev_dis; static frame_data prev_dis_frame; -static frame_data *prev_cap; static frame_data prev_cap_frame; -static const char* prev_display_dissector_name = NULL; +static gboolean prefs_loaded = FALSE; static gboolean perform_two_pass_analysis; @@ -153,9 +122,10 @@ static output_fields_t* output_fields = NULL; /* The line separator used between packets, changeable via the -S option */ static const char *separator = ""; -static int load_cap_file(capture_file *, int, gint64); -static gboolean process_packet(capture_file *cf, epan_dissect_t *edt, gint64 offset, - struct wtap_pkthdr *whdr, const guchar *pd, guint tap_flags); +static gboolean process_file(capture_file *, int, gint64); +static gboolean process_packet_single_pass(capture_file *cf, + epan_dissect_t *edt, gint64 offset, wtap_rec *rec, + const guchar *pd, guint tap_flags); static void show_print_file_io_error(int err); static gboolean write_preamble(capture_file *cf); static gboolean print_packet(capture_file *cf, epan_dissect_t *edt); @@ -163,15 +133,13 @@ static gboolean write_finale(void); static const char *cf_open_error_message(int err, gchar *err_info, gboolean for_writing, int file_type); +static void failure_warning_message(const char *msg_format, va_list ap); static void open_failure_message(const char *filename, int err, gboolean for_writing); -static void failure_message(const char *msg_format, va_list ap); static void read_failure_message(const char *filename, int err); static void write_failure_message(const char *filename, int err); static void failure_message_cont(const char *msg_format, va_list ap); -capture_file cfile; - static GHashTable *output_only_tables = NULL; #if 0 @@ -205,15 +173,16 @@ print_usage(FILE *output) /*fprintf(output, "\n");*/ fprintf(output, "Input file:\n"); - fprintf(output, " -r set the filename to read from (no pipes or stdin!)\n"); + fprintf(output, " -r set the filename to read from (no pipes or stdin)\n"); fprintf(output, "\n"); fprintf(output, "Processing:\n"); fprintf(output, " -2 perform a two-pass analysis\n"); fprintf(output, " -R packet Read filter in Wireshark display filter syntax\n"); + fprintf(output, " (requires -2)\n"); fprintf(output, " -Y packet displaY filter in Wireshark display filter\n"); fprintf(output, " syntax\n"); - fprintf(output, " -d %s ...\n", decode_as_arg_template); + 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"); @@ -285,420 +254,13 @@ glossary_option_help(void) fprintf(output, "\n"); } -/* - * For a dissector table, print on the stream described by output, - * its short name (which is what's used in the "-d" option) and its - * descriptive name. - */ -static void -display_dissector_table_names(const char *table_name, const char *ui_name, - gpointer output) -{ - if ((prev_display_dissector_name == NULL) || - (strcmp(prev_display_dissector_name, table_name) != 0)) { - fprintf((FILE *)output, "\t%s (%s)\n", table_name, ui_name); - prev_display_dissector_name = table_name; - } -} - -/* - * For a dissector handle, print on the stream described by output, - * the filter name (which is what's used in the "-d" option) and the full - * name for the protocol that corresponds to this handle. - */ -static void -display_dissector_names(const gchar *table _U_, gpointer handle, gpointer output) -{ - int proto_id; - const gchar *proto_filter_name; - const gchar *proto_ui_name; - - proto_id = dissector_handle_get_protocol_index((dissector_handle_t)handle); - - if (proto_id != -1) { - proto_filter_name = proto_get_protocol_filter_name(proto_id); - proto_ui_name = proto_get_protocol_name(proto_id); - g_assert(proto_filter_name != NULL); - g_assert(proto_ui_name != NULL); - - if ((prev_display_dissector_name == NULL) || - (strcmp(prev_display_dissector_name, proto_filter_name) != 0)) { - fprintf((FILE *)output, "\t%s (%s)\n", - proto_filter_name, - proto_ui_name); - prev_display_dissector_name = proto_filter_name; - } - } -} - -/* - * The protocol_name_search structure is used by find_protocol_name_func() - * to pass parameters and store results - */ -struct protocol_name_search{ - gchar *searched_name; /* Protocol filter name we are looking for */ - dissector_handle_t matched_handle; /* Handle for a dissector whose protocol has the specified filter name */ - guint nb_match; /* How many dissectors matched searched_name */ -}; -typedef struct protocol_name_search *protocol_name_search_t; - -/* - * This function parses all dissectors associated with a table to find the - * one whose protocol has the specified filter name. It is called - * as a reference function in a call to dissector_table_foreach_handle. - * The name we are looking for, as well as the results, are stored in the - * protocol_name_search struct pointed to by user_data. - * If called using dissector_table_foreach_handle, we actually parse the - * whole list of dissectors. - */ -static void -find_protocol_name_func(const gchar *table _U_, gpointer handle, gpointer user_data) - -{ - int proto_id; - const gchar *protocol_filter_name; - protocol_name_search_t search_info; - - g_assert(handle); - - search_info = (protocol_name_search_t)user_data; - - proto_id = dissector_handle_get_protocol_index((dissector_handle_t)handle); - if (proto_id != -1) { - protocol_filter_name = proto_get_protocol_filter_name(proto_id); - g_assert(protocol_filter_name != NULL); - if (strcmp(protocol_filter_name, search_info->searched_name) == 0) { - /* Found a match */ - if (search_info->nb_match == 0) { - /* Record this handle only if this is the first match */ - search_info->matched_handle = (dissector_handle_t)handle; /* Record the handle for this matching dissector */ - } - search_info->nb_match++; - } - } -} - -/* - * Allow dissector key names to be sorted alphabetically - */ - -static gint -compare_dissector_key_name(gconstpointer dissector_a, gconstpointer dissector_b) -{ - return strcmp((const char*)dissector_a, (const char*)dissector_b); -} - -/* - * Print all layer type names supported. - * We send the output to the stream described by the handle output. - */ - -static void -fprint_all_layer_types(FILE *output) - -{ - prev_display_dissector_name = NULL; - dissector_all_tables_foreach_table(display_dissector_table_names, (gpointer)output, (GCompareFunc)compare_dissector_key_name); -} - -/* - * Print all protocol names supported for a specific layer type. - * table_name contains the layer type name in which the search is performed. - * We send the output to the stream described by the handle output. - */ - -static void -fprint_all_protocols_for_layer_types(FILE *output, gchar *table_name) - -{ - prev_display_dissector_name = NULL; - dissector_table_foreach_handle(table_name, - display_dissector_names, - (gpointer)output); -} - -/* - * The function below parses the command-line parameters for the decode as - * feature (a string pointer by cl_param). - * It checks the format of the command-line, searches for a matching table - * and dissector. If a table/dissector match is not found, we display a - * summary of the available tables/dissectors (on stderr) and return FALSE. - * If everything is fine, we get the "Decode as" preference activated, - * then we return TRUE. - */ -static gboolean -add_decode_as(const gchar *cl_param) -{ - gchar *table_name; - guint32 selector, selector2; - gchar *decoded_param; - gchar *remaining_param; - gchar *selector_str; - gchar *dissector_str; - dissector_handle_t dissector_matching; - dissector_table_t table_matching; - ftenum_t dissector_table_selector_type; - struct protocol_name_search user_protocol_name; - guint64 i; - char op; - - /* The following code will allocate and copy the command-line options in a string pointed by decoded_param */ - - g_assert(cl_param); - decoded_param = g_strdup(cl_param); - g_assert(decoded_param); - - - /* The lines below will parse this string (modifying it) to extract all - necessary information. Note that decoded_param is still needed since - strings are not copied - we just save pointers. */ - - /* This section extracts a layer type (table_name) from decoded_param */ - table_name = decoded_param; /* Layer type string starts from beginning */ - - remaining_param = strchr(table_name, '='); - if (remaining_param == NULL) { - cmdarg_err("Parameter \"%s\" doesn't follow the template \"%s\"", cl_param, decode_as_arg_template); - /* If the argument does not follow the template, carry on anyway to check - if the table name is at least correct. If remaining_param is NULL, - we'll exit anyway further down */ - } - else { - *remaining_param = '\0'; /* Terminate the layer type string (table_name) where '=' was detected */ - } - - /* Remove leading and trailing spaces from the table name */ - while ( table_name[0] == ' ' ) - table_name++; - while ( table_name[strlen(table_name) - 1] == ' ' ) - table_name[strlen(table_name) - 1] = '\0'; /* Note: if empty string, while loop will eventually exit */ - -/* The following part searches a table matching with the layer type specified */ - table_matching = NULL; - -/* Look for the requested table */ - if ( !(*(table_name)) ) { /* Is the table name empty, if so, don't even search for anything, display a message */ - cmdarg_err("No layer type specified"); /* Note, we don't exit here, but table_matching will remain NULL, so we exit below */ - } - else { - table_matching = find_dissector_table(table_name); - if (!table_matching) { - cmdarg_err("Unknown layer type -- %s", table_name); /* Note, we don't exit here, but table_matching will remain NULL, so we exit below */ - } - } - - if (!table_matching) { - /* Display a list of supported layer types to help the user, if the - specified layer type was not found */ - cmdarg_err("Valid layer types are:"); - fprint_all_layer_types(stderr); - } - if (remaining_param == NULL || !table_matching) { - /* Exit if the layer type was not found, or if no '=' separator was found - (see above) */ - g_free(decoded_param); - return FALSE; - } - - if (*(remaining_param + 1) != '=') { /* Check for "==" and not only '=' */ - cmdarg_err("WARNING: -d requires \"==\" instead of \"=\". Option will be treated as \"%s==%s\"", table_name, remaining_param + 1); - } - else { - remaining_param++; /* Move to the second '=' */ - *remaining_param = '\0'; /* Remove the second '=' */ - } - remaining_param++; /* Position after the layer type string */ - - /* This section extracts a selector value (selector_str) from decoded_param */ - - selector_str = remaining_param; /* Next part starts with the selector number */ - - remaining_param = strchr(selector_str, ','); - if (remaining_param == NULL) { - cmdarg_err("Parameter \"%s\" doesn't follow the template \"%s\"", cl_param, decode_as_arg_template); - /* If the argument does not follow the template, carry on anyway to check - if the selector value is at least correct. If remaining_param is NULL, - we'll exit anyway further down */ - } - else { - *remaining_param = '\0'; /* Terminate the selector number string (selector_str) where ',' was detected */ - } - - dissector_table_selector_type = get_dissector_table_selector_type(table_name); - - switch (dissector_table_selector_type) { - - case FT_UINT8: - case FT_UINT16: - case FT_UINT24: - case FT_UINT32: - /* The selector for this table is an unsigned number. Parse it as such. - There's no need to remove leading and trailing spaces from the - selector number string, because sscanf will do that for us. */ - switch (sscanf(selector_str, "%u%c%u", &selector, &op, &selector2)) { - case 1: - op = '\0'; - break; - case 3: - if (op != ':' && op != '-') { - cmdarg_err("Invalid selector numeric range \"%s\"", selector_str); - g_free(decoded_param); - return FALSE; - } - if (op == ':') { - if ((selector2 == 0) || ((guint64)selector + selector2 - 1) > G_MAXUINT32) { - cmdarg_err("Invalid selector numeric range \"%s\"", selector_str); - g_free(decoded_param); - return FALSE; - } - } - else if (selector2 < selector) { - /* We could swap them for the user, but maybe it's better to call - * this out as an error in case it's not what was intended? */ - cmdarg_err("Invalid selector numeric range \"%s\"", selector_str); - g_free(decoded_param); - return FALSE; - } - break; - default: - cmdarg_err("Invalid selector number \"%s\"", selector_str); - g_free(decoded_param); - return FALSE; - } - break; - - case FT_STRING: - case FT_STRINGZ: - case FT_UINT_STRING: - case FT_STRINGZPAD: - /* The selector for this table is a string. */ - break; - - default: - /* There are currently no dissector tables with any types other - than the ones listed above. */ - g_assert_not_reached(); - } - - if (remaining_param == NULL) { - /* Exit if no ',' separator was found (see above) */ - cmdarg_err("Valid protocols for layer type \"%s\" are:", table_name); - fprint_all_protocols_for_layer_types(stderr, table_name); - g_free(decoded_param); - return FALSE; - } - - remaining_param++; /* Position after the selector number string */ - - /* This section extracts a protocol filter name (dissector_str) from decoded_param */ - - dissector_str = remaining_param; /* All the rest of the string is the dissector (decode as protocol) name */ - - /* Remove leading and trailing spaces from the dissector name */ - while ( dissector_str[0] == ' ' ) - dissector_str++; - while ( dissector_str[strlen(dissector_str) - 1] == ' ' ) - dissector_str[strlen(dissector_str) - 1] = '\0'; /* Note: if empty string, while loop will eventually exit */ - - dissector_matching = NULL; - - /* We now have a pointer to the handle for the requested table inside the variable table_matching */ - if ( ! (*dissector_str) ) { /* Is the dissector name empty, if so, don't even search for a matching dissector and display all dissectors found for the selected table */ - cmdarg_err("No protocol name specified"); /* Note, we don't exit here, but dissector_matching will remain NULL, so we exit below */ - } - else { - user_protocol_name.nb_match = 0; - user_protocol_name.searched_name = dissector_str; - user_protocol_name.matched_handle = NULL; - - dissector_table_foreach_handle(table_name, find_protocol_name_func, &user_protocol_name); /* Go and perform the search for this dissector in the this table's dissectors' names and shortnames */ - - if (user_protocol_name.nb_match != 0) { - dissector_matching = user_protocol_name.matched_handle; - if (user_protocol_name.nb_match > 1) { - cmdarg_err("WARNING: Protocol \"%s\" matched %u dissectors, first one will be used", dissector_str, user_protocol_name.nb_match); - } - } - else { - /* OK, check whether the problem is that there isn't any such - protocol, or that there is but it's not specified as a protocol - that's valid for that dissector table. - Note, we don't exit here, but dissector_matching will remain NULL, - so we exit below */ - if (proto_get_id_by_filter_name(dissector_str) == -1) { - /* No such protocol */ - cmdarg_err("Unknown protocol -- \"%s\"", dissector_str); - } else { - cmdarg_err("Protocol \"%s\" isn't valid for layer type \"%s\"", - dissector_str, table_name); - } - } - } - - if (!dissector_matching) { - cmdarg_err("Valid protocols for layer type \"%s\" are:", table_name); - fprint_all_protocols_for_layer_types(stderr, table_name); - g_free(decoded_param); - return FALSE; - } - -/* This is the end of the code that parses the command-line options. - All information is now stored in the variables: - table_name - selector - dissector_matching - The above variables that are strings are still pointing to areas within - decoded_parm. decoded_parm thus still needs to be kept allocated in - until we stop needing these variables - decoded_param will be deallocated at each exit point of this function */ - - - /* We now have a pointer to the handle for the requested dissector - (requested protocol) inside the variable dissector_matching */ - switch (dissector_table_selector_type) { - - case FT_UINT8: - case FT_UINT16: - case FT_UINT24: - case FT_UINT32: - /* The selector for this table is an unsigned number. */ - if (op == '\0') { - dissector_change_uint(table_name, selector, dissector_matching); - } else if (op == ':') { - for (i = selector; i < (guint64)selector + selector2; i++) { - dissector_change_uint(table_name, (guint32)i, dissector_matching); - } - } else { /* op == '-' */ - for (i = selector; i <= selector2; i++) { - dissector_change_uint(table_name, (guint32)i, dissector_matching); - } - } - break; - - case FT_STRING: - case FT_STRINGZ: - case FT_UINT_STRING: - case FT_STRINGZPAD: - /* The selector for this table is a string. */ - dissector_change_string(table_name, selector_str, dissector_matching); - break; - - default: - /* There are currently no dissector tables with any types other - than the ones listed above. */ - g_assert_not_reached(); - } - g_free(decoded_param); /* "Decode As" rule has been successfully added */ - return TRUE; -} - static void tfshark_log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { /* ignore log message, if log_level isn't interesting based upon the console log preferences. - If the preferences haven't been loaded loaded yet, display the + If the preferences haven't been loaded yet, display the message anyway. The default console_log_level preference value is such that only @@ -709,8 +271,7 @@ tfshark_log_handler (const gchar *log_domain, GLogLevelFlags log_level, ERROR and CRITICAL level messages so the current code is a behavioral change. The current behavior is the same as in Wireshark. */ - if ((log_level & G_LOG_LEVEL_MASK & prefs.console_log_level) == 0 && - prefs.console_log_level != 0) { + if (prefs_loaded && (log_level & G_LOG_LEVEL_MASK & prefs.console_log_level) == 0) { return; } @@ -736,44 +297,9 @@ print_current_user(void) { } } -static void -show_version(GString *comp_info_str, GString *runtime_info_str) -{ - printf("TFShark (Wireshark) %s\n" - "\n" - "%s" - "\n" - "%s" - "\n" - "%s", - get_ws_vcs_version_info(), get_copyright_info(), comp_info_str->str, - runtime_info_str->str); -} - -static void -get_tfshark_compiled_version_info(GString *str) -{ - /* LIBZ */ -#ifdef HAVE_LIBZ - g_string_append(str, "with libz "); -#ifdef ZLIB_VERSION - g_string_append(str, ZLIB_VERSION); -#else /* ZLIB_VERSION */ - g_string_append(str, "(version unknown)"); -#endif /* ZLIB_VERSION */ -#else /* HAVE_LIBZ */ - g_string_append(str, "without libz"); -#endif /* HAVE_LIBZ */ -} - static void get_tfshark_runtime_version_info(GString *str) { - /* zlib */ -#if defined(HAVE_LIBZ) && !defined(_WIN32) - g_string_append_printf(str, ", with libz %s", zlibVersion()); -#endif - /* stuff used by libwireshark */ epan_get_runtime_version_info(str); } @@ -786,19 +312,14 @@ main(int argc, char *argv[]) char *init_progfile_dir_error; int opt; static const struct option long_options[] = { - {(char *)"help", no_argument, NULL, 'h'}, - {(char *)"version", no_argument, NULL, 'v'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, {0, 0, 0, 0 } }; gboolean arg_error = FALSE; - char *gpf_path, *pf_path; - char *gdp_path, *dp_path; - int gpf_open_errno, gpf_read_errno; - int pf_open_errno, pf_read_errno; - int gdp_open_errno, gdp_read_errno; - int dp_open_errno, dp_read_errno; int err; + volatile gboolean success; volatile int exit_status = 0; gboolean quiet = FALSE; gchar *volatile cf_name = NULL; @@ -806,19 +327,38 @@ main(int argc, char *argv[]) gchar *dfilter = NULL; dfilter_t *rfcode = NULL; dfilter_t *dfcode = NULL; + gchar *err_msg; e_prefs *prefs_p; int log_flags; - int optind_initial; gchar *output_only = NULL; -/* the leading - ensures that getopt() does not permute the argv[] entries - we have to make sure that the first getopt() preserves the content of argv[] - for the subsequent getopt_long() call */ -#define OPTSTRING "-2C:d:e:E:hK:lo:O:qQr:R:S:t:T:u:vVxX:Y:z:" +/* + * The leading + ensures that getopt_long() does not permute the argv[] + * entries. + * + * We have to make sure that the first getopt_long() preserves the content + * of argv[] for the subsequent getopt_long() call. + * + * We use getopt_long() in both cases to ensure that we're using a routine + * whose permutation behavior we can control in the same fashion on all + * platforms, and so that, if we ever need to process a long argument before + * doing further initialization, we can do so. + * + * Glibc and Solaris libc document that a leading + disables permutation + * of options, regardless of whether POSIXLY_CORRECT is set or not; *BSD + * and macOS don't document it, but do so anyway. + * + * We do *not* use a leading - because the behavior of a leading - is + * platform-dependent. + */ +#define OPTSTRING "+2C:d:e:E:hK:lo:O:qQr:R:S:t:T:u:vVxX:Y:z:" static const char optstring[] = OPTSTRING; - cmdarg_err_init(failure_message, failure_message_cont); + /* Set the C-language locale to the native environment. */ + setlocale(LC_ALL, ""); + + cmdarg_err_init(failure_warning_message, failure_message_cont); #ifdef _WIN32 arg_list_utf_16to8(argc, argv); @@ -838,24 +378,24 @@ main(int argc, char *argv[]) print_current_user(); /* - * Attempt to get the pathname of the executable file. + * Attempt to get the pathname of the directory containing the + * executable file. */ init_progfile_dir_error = init_progfile_dir(argv[0], main); if (init_progfile_dir_error != NULL) { - fprintf(stderr, "tfshark: Can't get pathname of tfshark program: %s.\n", + fprintf(stderr, + "tfshark: Can't get pathname of directory containing the tfshark program: %s.\n", init_progfile_dir_error); + g_free(init_progfile_dir_error); } initialize_funnel_ops(); - /* Assemble the compile-time version information string */ - comp_info_str = g_string_new("Compiled "); - get_compiled_version_info(comp_info_str, get_tfshark_compiled_version_info, - epan_get_compiled_version_info); + /* Get the compile-time version information string */ + comp_info_str = get_compiled_version_info(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, get_tfshark_runtime_version_info); + /* Get the run-time version information string */ + runtime_info_str = get_runtime_version_info(get_tfshark_runtime_version_info); /* Add it to the information to be reported on a crash. */ ws_add_crash_info("TFShark (Wireshark) %s\n" @@ -864,15 +404,24 @@ main(int argc, char *argv[]) "\n" "%s", get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str); + g_string_free(comp_info_str, TRUE); + g_string_free(runtime_info_str, TRUE); /* * In order to have the -X opts assigned before the wslua machine starts * we need to call getopts before epan_init() gets called. + * + * In order to handle, for example, -o options, we also need to call it + * *after* epan_init() gets called, so that the dissectors have had a + * chance to register their preferences. + * + * XXX - can we do this all with one getopt_long() call, saving the + * arguments we can't handle until after initializing libwireshark, + * and then process them after initializing libwireshark? */ opterr = 0; - optind_initial = optind; - while ((opt = getopt(argc, argv, optstring)) != -1) { + while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { switch (opt) { case 'C': /* Configuration Profile */ if (profile_exists (optarg, FALSE)) { @@ -913,11 +462,6 @@ main(int argc, char *argv[]) if (print_summary == -1) print_summary = (print_details || print_hex) ? FALSE : TRUE; - optind = optind_initial; - opterr = 1; - - - /** Send All g_log messages to our own handler **/ log_flags = @@ -936,30 +480,25 @@ main(int argc, char *argv[]) (GLogLevelFlags)log_flags, tfshark_log_handler, NULL /* user_data */); - init_report_err(failure_message, open_failure_message, read_failure_message, - write_failure_message); + init_report_message(failure_warning_message, failure_warning_message, + open_failure_message, read_failure_message, + write_failure_message); timestamp_set_type(TS_RELATIVE); timestamp_set_precision(TS_PREC_AUTO); timestamp_set_seconds_type(TS_SECONDS_DEFAULT); - init_open_routines(); - -#ifdef HAVE_PLUGINS - /* Register all the plugin types we have. */ - epan_register_plugin_types(); /* Types known to libwireshark */ - - /* Scan for plugins. This does *not* call their registration routines; - that's done later. */ - scan_plugins(); - -#endif + wtap_init(TRUE); /* Register all dissectors; we must do this before checking for the "-G" flag, as the "-G" flag dumps information registered by the dissectors, and we must do it before we read the preferences, in case any dissectors register preferences. */ - epan_init(register_all_protocols, register_all_protocol_handoffs, NULL, NULL); + if (!epan_init(register_all_protocols, register_all_protocol_handoffs, NULL, + NULL)) { + exit_status = INIT_ERROR; + goto clean_exit; + } /* Register all tap listeners; we do this before we parse the arguments, as the "-z" argument can specify a registered tap. */ @@ -993,8 +532,7 @@ main(int argc, char *argv[]) if (strcmp(argv[2], "column-formats") == 0) column_dump_column_formats(); 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); + epan_load_settings(); write_prefs(NULL); } else if (strcmp(argv[2], "decodes") == 0) @@ -1027,67 +565,16 @@ main(int argc, char *argv[]) glossary_option_help(); else { cmdarg_err("Invalid \"%s\" option for -G flag, enter -G ? for more help.", argv[2]); - return 1; + exit_status = INVALID_OPTION; + goto clean_exit; } } - return 0; - } - - /* Set the C-language locale to the native environment. */ - setlocale(LC_ALL, ""); - - prefs_p = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path, - &pf_open_errno, &pf_read_errno, &pf_path); - if (gpf_path != NULL) { - if (gpf_open_errno != 0) { - cmdarg_err("Can't open global preferences file \"%s\": %s.", - pf_path, g_strerror(gpf_open_errno)); - } - if (gpf_read_errno != 0) { - cmdarg_err("I/O error reading global preferences file \"%s\": %s.", - pf_path, g_strerror(gpf_read_errno)); - } - } - if (pf_path != NULL) { - if (pf_open_errno != 0) { - cmdarg_err("Can't open your preferences file \"%s\": %s.", pf_path, - g_strerror(pf_open_errno)); - } - if (pf_read_errno != 0) { - cmdarg_err("I/O error reading your preferences file \"%s\": %s.", - pf_path, g_strerror(pf_read_errno)); - } - g_free(pf_path); - pf_path = NULL; + goto clean_exit; } - /* Read the disabled protocols file. */ - read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno, - &dp_path, &dp_open_errno, &dp_read_errno); - if (gdp_path != NULL) { - if (gdp_open_errno != 0) { - cmdarg_err("Could not open global disabled protocols file\n\"%s\": %s.", - gdp_path, g_strerror(gdp_open_errno)); - } - if (gdp_read_errno != 0) { - cmdarg_err("I/O error reading global disabled protocols file\n\"%s\": %s.", - gdp_path, g_strerror(gdp_read_errno)); - } - g_free(gdp_path); - } - if (dp_path != NULL) { - if (dp_open_errno != 0) { - cmdarg_err( - "Could not open your disabled protocols file\n\"%s\": %s.", dp_path, - g_strerror(dp_open_errno)); - } - if (dp_read_errno != 0) { - cmdarg_err( - "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path, - g_strerror(dp_read_errno)); - } - g_free(dp_path); - } + /* Load libwireshark settings from the current profile. */ + prefs_p = epan_load_settings(); + prefs_loaded = TRUE; cap_file_init(&cfile); @@ -1096,6 +583,28 @@ main(int argc, char *argv[]) output_fields = output_fields_new(); + /* + * To reset the options parser, set optreset to 1 on platforms that + * have optreset (documented in *BSD and macOS, apparently present but + * not documented in Solaris - the Illumos repository seems to + * suggest that the first Solaris getopt_long(), at least as of 2004, + * was based on the NetBSD one, it had optreset) and set optind to 1, + * and set optind to 0 otherwise (documented as working in the GNU + * getopt_long(). Setting optind to 0 didn't originally work in the + * NetBSD one, but that was added later - we don't want to depend on + * it if we have optreset). + * + * Also reset opterr to 1, so that error messages are printed by + * getopt_long(). + */ +#ifdef HAVE_OPTRESET + optreset = 1; + optind = 1; +#else + optind = 0; +#endif + opterr = 1; + /* Now get our args */ while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { switch (opt) { @@ -1103,17 +612,8 @@ main(int argc, char *argv[]) perform_two_pass_analysis = TRUE; 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); + /* already processed; just ignore it now */ break; -#endif case 'e': /* Field entry */ output_fields_add(output_fields, optarg); @@ -1123,51 +623,70 @@ main(int argc, char *argv[]) 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; + exit_status = INVALID_OPTION; + goto clean_exit; } break; case 'h': /* Print help and exit */ printf("TFShark (Wireshark) %s\n" "Dump and analyze network traffic.\n" - "See http://www.wireshark.org for more information.\n", + "See https://www.wireshark.org for more information.\n", get_ws_vcs_version_info()); print_usage(stdout); - return 0; + goto clean_exit; 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). */ + /* The ANSI C standard does not appear to *require* that a line-buffered + stream be flushed to the host environment whenever a newline is + written, it just says that, on such a stream, characters "are + intended to be transmitted to or from the host environment as a + block when a new-line character is encountered". + + The Visual C++ 6.0 C implementation doesn't do what is intended; + even if you set a stream to be line-buffered, it still doesn't + flush the buffer at the end of every line. + + The whole reason for the "-l" flag in either tcpdump or TShark + is to allow the output of a live capture to be piped to a program + or script and to have that script see the information for the + packet as soon as it's printed, rather than having to wait until + a standard I/O buffer fills up. + + So, if the "-l" flag is specified, we flush the standard output + at the end of a packet. This will do the right thing if we're + printing packet summary lines, and, as we print the entire protocol + tree for a single packet without waiting for anything to happen, + it should be as good as line-buffered mode if we're printing + protocol trees - arguably even better, as it may do fewer + writes. */ line_buffered = TRUE; break; case 'o': /* Override preference from command line */ - switch (prefs_set_pref(optarg)) { + { + char *errmsg = NULL; + + switch (prefs_set_pref(optarg, &errmsg)) { case PREFS_SET_OK: break; case PREFS_SET_SYNTAX_ERR: - cmdarg_err("Invalid -o flag \"%s\"", optarg); + cmdarg_err("Invalid -o flag \"%s\"%s%s", optarg, + errmsg ? ": " : "", errmsg ? errmsg : ""); + g_free(errmsg); return 1; break; case PREFS_SET_NO_SUCH_PREF: case PREFS_SET_OBSOLETE: cmdarg_err("-o flag \"%s\" specifies unknown preference", optarg); - return 1; + exit_status = INVALID_OPTION; + goto clean_exit; break; } break; + } case 'q': /* Quiet */ quiet = TRUE; break; @@ -1184,42 +703,6 @@ main(int argc, char *argv[]) case 'S': /* Set the line Separator to be printed between packets */ separator = g_strdup(optarg); 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_YMD); - else if (strcmp(optarg, "adoy") == 0) - timestamp_set_type(TS_ABSOLUTE_WITH_YDOY); - 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 if (strcmp(optarg, "u") == 0) - timestamp_set_type(TS_UTC); - else if (strcmp(optarg, "ud") == 0) - timestamp_set_type(TS_UTC_WITH_YMD); - else if (strcmp(optarg, "udoy") == 0) - timestamp_set_type(TS_UTC_WITH_YDOY); - else { - cmdarg_err("Invalid time stamp type \"%s\"; it must be one of:", optarg); - cmdarg_err_cont("\t\"a\" for absolute\n" - "\t\"ad\" for absolute with YYYY-MM-DD date\n" - "\t\"adoy\" for absolute with YYYY/DOY date\n" - "\t\"d\" for delta\n" - "\t\"dd\" for delta displayed\n" - "\t\"e\" for epoch\n" - "\t\"r\" for relative\n" - "\t\"u\" for absolute UTC\n" - "\t\"ud\" for absolute UTC with YYYY-MM-DD date\n" - "\t\"udoy\" for absolute UTC with YYYY/DOY date"); - return 1; - } - break; case 'T': /* printing Type */ if (strcmp(optarg, "text") == 0) { output_action = WRITE_TEXT; @@ -1257,34 +740,17 @@ main(int argc, char *argv[]) "\t packets, or a multi-line view of the details of each of the\n" "\t packets, depending on whether the -V flag was specified.\n" "\t This is the default."); - 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\"; it must be one of:", optarg); - cmdarg_err_cont("\t\"s\" for seconds\n" - "\t\"hms\" for hours, minutes and seconds"); - return 1; + exit_status = INVALID_OPTION; + goto clean_exit; } break; case 'v': /* Show version and exit */ - { - show_version(comp_info_str, runtime_info_str); + comp_info_str = get_compiled_version_info(NULL, epan_get_compiled_version_info); + runtime_info_str = get_runtime_version_info(get_tfshark_runtime_version_info); + show_version("TFShark (Wireshark)", comp_info_str, runtime_info_str); g_string_free(comp_info_str, TRUE); g_string_free(runtime_info_str, TRUE); - /* We don't really have to cleanup here, but it's a convenient way to test - * start-up and shut-down of the epan library without any UI-specific - * cruft getting in the way. Makes the results of running - * $ ./tools/valgrind-wireshark -n - * much more useful. */ - epan_cleanup(); - return 0; - } + goto clean_exit; case 'O': /* Only output these protocols */ /* already processed; just ignore it now */ break; @@ -1295,6 +761,7 @@ main(int argc, char *argv[]) /* already processed; just ignore it now */ break; case 'X': + /* already processed; just ignore it now */ break; case 'Y': dfilter = optarg; @@ -1308,18 +775,33 @@ main(int argc, char *argv[]) if (strcmp("help", optarg) == 0) { fprintf(stderr, "tfshark: The available statistics for the \"-z\" option are:\n"); list_stat_cmd_args(); - return 0; + goto clean_exit; } if (!process_stat_cmd_arg(optarg)) { cmdarg_err("Invalid -z argument \"%s\"; it must be one of:", optarg); list_stat_cmd_args(); - return 1; + exit_status = INVALID_OPTION; + goto clean_exit; + } + break; + case 'd': /* Decode as rule */ + case 'K': /* Kerberos keytab file */ + 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) */ + if (!dissect_opts_handle_opt(opt, optarg)) { + exit_status = INVALID_OPTION; + goto clean_exit; } break; default: case '?': /* Bad flag - print usage message */ print_usage(stderr); - return 1; + exit_status = INVALID_OPTION; + goto clean_exit; break; } } @@ -1333,22 +815,27 @@ main(int argc, char *argv[]) cmdarg_err("\"-Tfields\" was specified, but no fields were " "specified with \"-e\"."); - return 1; + exit_status = INVALID_OPTION; + goto clean_exit; } - /* If no capture filter or display filter has been specified, and there are - still command-line arguments, treat them as the tokens of a capture - filter (if no "-r" flag was specified) or a display filter (if a "-r" - flag was specified. */ + /* We require a -r flag specifying a file to read. */ + if (cf_name == NULL) { + cmdarg_err("A file to read must be specified with \"-r\"."); + exit_status = NO_FILE_SPECIFIED; + goto clean_exit; + } + + /* If no display filter has been specified, and there are still command- + line arguments, treat them as the tokens of a display filter. */ if (optind < argc) { - if (cf_name != NULL) { - if (dfilter != NULL) { - cmdarg_err("Display filters were specified both with \"-d\" " - "and with additional command-line arguments."); - return 1; - } - dfilter = get_args_as_string(argc, argv, optind); + if (dfilter != NULL) { + cmdarg_err("Display filters were specified both with \"-d\" " + "and with additional command-line arguments."); + exit_status = INVALID_OPTION; + goto clean_exit; } + dfilter = get_args_as_string(argc, argv, optind); } /* if "-q" wasn't specified, we should print packet information */ @@ -1357,13 +844,15 @@ main(int argc, char *argv[]) if (arg_error) { print_usage(stderr); - return 1; + exit_status = INVALID_OPTION; + goto clean_exit; } if (print_hex) { if (output_action != WRITE_TEXT) { cmdarg_err("Raw packet hex data can only be printed as text or PostScript"); - return 1; + exit_status = INVALID_OPTION; + goto clean_exit; } } @@ -1372,7 +861,8 @@ main(int argc, char *argv[]) if (!print_details) { cmdarg_err("-O requires -V"); - return 1; + exit_status = INVALID_OPTION; + goto clean_exit; } output_only_tables = g_hash_table_new (g_str_hash, g_str_equal); @@ -1383,7 +873,8 @@ main(int argc, char *argv[]) if (rfilter != NULL && !perform_two_pass_analysis) { cmdarg_err("-R without -2 is deprecated. For single-pass filtering use -Y."); - return 1; + exit_status = INVALID_OPTION; + goto clean_exit; } /* Notify all registered modules that have had any of their preferences @@ -1391,33 +882,34 @@ main(int argc, char *argv[]) line that their preferences have changed. */ prefs_apply_all(); - /* At this point MATE will have registered its field array so we can - have a tap filter with one of MATE's late-registered fields as part - of the filter. We can now process all the "-z" arguments. */ - start_requested_stats(); - - /* disabled protocols as per configuration file */ - if (gdp_path == NULL && dp_path == NULL) { - set_disabled_protos_list(); + /* + * Enabled and disabled protocols and heuristic dissectors as per + * command-line options. + */ + if (!setup_enabled_and_disabled_protocols()) { + exit_status = INVALID_OPTION; + goto clean_exit; } /* Build the column format array */ build_column_format_array(&cfile.cinfo, prefs_p->num_cols, TRUE); if (rfilter != NULL) { - if (!dfilter_compile(rfilter, &rfcode)) { - cmdarg_err("%s", dfilter_error_msg); - epan_cleanup(); - return 2; + if (!dfilter_compile(rfilter, &rfcode, &err_msg)) { + cmdarg_err("%s", err_msg); + g_free(err_msg); + exit_status = INVALID_FILTER; + goto clean_exit; } } cfile.rfcode = rfcode; if (dfilter != NULL) { - if (!dfilter_compile(dfilter, &dfcode)) { - cmdarg_err("%s", dfilter_error_msg); - epan_cleanup(); - return 2; + if (!dfilter_compile(dfilter, &dfcode, &err_msg)) { + cmdarg_err("%s", err_msg); + g_free(err_msg); + exit_status = INVALID_FILTER; + goto clean_exit; } } cfile.dfcode = dfcode; @@ -1453,76 +945,86 @@ main(int argc, char *argv[]) we're using any taps that need dissection. */ do_dissection = print_packet_info || rfcode || dfcode || tap_listeners_require_dissection(); - if (cf_name) { - /* - * We're reading a capture file. - */ + /* + * Read the file. + */ - /* TODO: if tfshark is ever changed to give the user a choice of which - open_routine reader to use, then the following needs to change. */ - if (cf_open(&cfile, cf_name, WTAP_TYPE_AUTO, FALSE, &err) != CF_OK) { - epan_cleanup(); - return 2; - } + /* TODO: if tfshark is ever changed to give the user a choice of which + open_routine reader to use, then the following needs to change. */ + if (cf_open(&cfile, cf_name, WTAP_TYPE_AUTO, FALSE, &err) != CF_OK) { + exit_status = OPEN_ERROR; + goto clean_exit; + } - /* Process the packets in the file */ - TRY { - /* XXX - for now there is only 1 packet */ - err = load_cap_file(&cfile, 1, 0); - } - CATCH(OutOfMemoryError) { - fprintf(stderr, - "Out Of Memory!\n" - "\n" - "Sorry, but TFShark has to terminate now!\n" - "\n" - "Some infos / workarounds can be found at:\n" - "http://wiki.wireshark.org/KnownBugs/OutOfMemory\n"); - err = ENOMEM; - } - ENDTRY; + /* Start statistics taps; we do so after successfully opening the + capture file, so we know we have something to compute stats + on, and after registering all dissectors, so that MATE will + have registered its field array so we can have a tap filter + with one of MATE's late-registered fields as part of the + filter. */ + start_requested_stats(); - if (err != 0) { - /* 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; - } + /* Process the packets in the file */ + TRY { + /* XXX - for now there is only 1 packet */ + success = process_file(&cfile, 1, 0); + } + CATCH(OutOfMemoryError) { + fprintf(stderr, + "Out Of Memory.\n" + "\n" + "Sorry, but TFShark has to terminate now.\n" + "\n" + "Some infos / workarounds can be found at:\n" + "https://wiki.wireshark.org/KnownBugs/OutOfMemory\n"); + success = FALSE; + } + ENDTRY; + + if (!success) { + /* 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; } g_free(cf_name); - if (cfile.frames != NULL) { - free_frame_data_sequence(cfile.frames); - cfile.frames = NULL; + if (cfile.provider.frames != NULL) { + free_frame_data_sequence(cfile.provider.frames); + cfile.provider.frames = NULL; } draw_tap_listeners(TRUE); funnel_dump_all_text_windows(); + +clean_exit: + destroy_print_stream(print_stream); epan_free(cfile.epan); epan_cleanup(); + extcap_cleanup(); output_fields_free(output_fields); output_fields = NULL; + col_cleanup(&cfile.cinfo); + wtap_cleanup(); return exit_status; } static const nstime_t * -tfshark_get_frame_ts(void *data, guint32 frame_num) +tfshark_get_frame_ts(struct packet_provider_data *prov, guint32 frame_num) { - capture_file *cf = (capture_file *) data; - - if (ref && ref->num == frame_num) - return &ref->abs_ts; + if (prov->ref && prov->ref->num == frame_num) + return &prov->ref->abs_ts; - if (prev_dis && prev_dis->num == frame_num) - return &prev_dis->abs_ts; + if (prov->prev_dis && prov->prev_dis->num == frame_num) + return &prov->prev_dis->abs_ts; - if (prev_cap && prev_cap->num == frame_num) - return &prev_cap->abs_ts; + if (prov->prev_cap && prov->prev_cap->num == frame_num) + return &prov->prev_cap->abs_ts; - if (cf->frames) { - frame_data *fd = frame_data_sequence_find(cf->frames, frame_num); + if (prov->frames) { + frame_data *fd = frame_data_sequence_find(prov->frames, frame_num); return (fd) ? &fd->abs_ts : NULL; } @@ -1531,7 +1033,7 @@ tfshark_get_frame_ts(void *data, guint32 frame_num) } static const char * -no_interface_name(void *data _U_, guint32 interface_id _U_) +no_interface_name(struct packet_provider_data *prov _U_, guint32 interface_id _U_) { return ""; } @@ -1539,20 +1041,20 @@ no_interface_name(void *data _U_, guint32 interface_id _U_) static epan_t * tfshark_epan_new(capture_file *cf) { - epan_t *epan = epan_new(); - - epan->data = cf; - epan->get_frame_ts = tfshark_get_frame_ts; - epan->get_interface_name = no_interface_name; - epan->get_user_comment = NULL; + static const struct packet_provider_funcs funcs = { + tfshark_get_frame_ts, + no_interface_name, + NULL, + NULL, + }; - return epan; + return epan_new(&cf->provider, &funcs); } static gboolean process_packet_first_pass(capture_file *cf, epan_dissect_t *edt, - gint64 offset, struct wtap_pkthdr *whdr, - const guchar *pd) + gint64 offset, wtap_rec *rec, + const guchar *pd) { frame_data fdlocal; guint32 framenum; @@ -1567,7 +1069,7 @@ process_packet_first_pass(capture_file *cf, epan_dissect_t *edt, that all packets can be marked as 'passed'. */ passed = TRUE; - frame_data_init(&fdlocal, framenum, whdr, offset, cum_bytes); + frame_data_init(&fdlocal, framenum, rec, offset, cum_bytes); /* If we're going to print packet information, or we're going to run a read filter, or display filter, or we're going to process taps, set up to @@ -1576,16 +1078,22 @@ process_packet_first_pass(capture_file *cf, epan_dissect_t *edt, /* If we're running a read filter, prime the epan_dissect_t with that filter. */ if (cf->rfcode) - epan_dissect_prime_dfilter(edt, cf->rfcode); + epan_dissect_prime_with_dfilter(edt, cf->rfcode); + + /* This is the first pass, so prime the epan_dissect_t with the + hfids postdissectors want on the first pass. */ + prime_epan_dissect_with_postdissector_wanted_hfids(edt); frame_data_set_before_dissect(&fdlocal, &cf->elapsed_time, - &ref, prev_dis); - if (ref == &fdlocal) { + &cf->provider.ref, cf->provider.prev_dis); + if (cf->provider.ref == &fdlocal) { ref_frame = fdlocal; - ref = &ref_frame; + cf->provider.ref = &ref_frame; } - epan_dissect_file_run(edt, whdr, file_tvbuff_new(&fdlocal, pd), &fdlocal, NULL); + epan_dissect_file_run(edt, rec, + file_tvbuff_new(&cf->provider, &fdlocal, pd), + &fdlocal, NULL); /* Run the read filter if we have one. */ if (cf->rfcode) @@ -1594,14 +1102,14 @@ process_packet_first_pass(capture_file *cf, epan_dissect_t *edt, if (passed) { frame_data_set_after_dissect(&fdlocal, &cum_bytes); - prev_cap = prev_dis = frame_data_sequence_add(cf->frames, &fdlocal); + cf->provider.prev_cap = cf->provider.prev_dis = frame_data_sequence_add(cf->provider.frames, &fdlocal); /* If we're not doing dissection then there won't be any dependent frames. * More importantly, edt.pi.dependent_frames won't be initialized because * epan hasn't been initialized. */ if (edt) { - g_slist_foreach(edt->pi.dependent_frames, find_and_mark_frame_depended_upon, cf->frames); + g_slist_foreach(edt->pi.dependent_frames, find_and_mark_frame_depended_upon, cf->provider.frames); } cf->count++; @@ -1618,9 +1126,9 @@ process_packet_first_pass(capture_file *cf, epan_dissect_t *edt, } static gboolean -process_packet_second_pass(capture_file *cf, epan_dissect_t *edt, frame_data *fdata, - struct wtap_pkthdr *phdr, Buffer *buf, - guint tap_flags) +process_packet_second_pass(capture_file *cf, epan_dissect_t *edt, + frame_data *fdata, wtap_rec *rec, + Buffer *buf, guint tap_flags) { column_info *cinfo; gboolean passed; @@ -1638,7 +1146,11 @@ process_packet_second_pass(capture_file *cf, epan_dissect_t *edt, frame_data *fd /* If we're running a display filter, prime the epan_dissect_t with that filter. */ if (cf->dfcode) - epan_dissect_prime_dfilter(edt, cf->dfcode); + epan_dissect_prime_with_dfilter(edt, cf->dfcode); + + /* This is the first and only pass, so prime the epan_dissect_t + with the hfids postdissectors want on the first pass. */ + prime_epan_dissect_with_postdissector_wanted_hfids(edt); col_custom_prime_edt(edt, &cf->cinfo); @@ -1654,13 +1166,14 @@ process_packet_second_pass(capture_file *cf, epan_dissect_t *edt, frame_data *fd cinfo = NULL; frame_data_set_before_dissect(fdata, &cf->elapsed_time, - &ref, prev_dis); - if (ref == fdata) { + &cf->provider.ref, cf->provider.prev_dis); + if (cf->provider.ref == fdata) { ref_frame = *fdata; - ref = &ref_frame; + cf->provider.ref = &ref_frame; } - epan_dissect_file_run_with_taps(edt, phdr, file_tvbuff_new_buffer(fdata, buf), fdata, cinfo); + epan_dissect_file_run_with_taps(edt, rec, + file_tvbuff_new_buffer(&cf->provider, fdata, buf), fdata, cinfo); /* Run the read/display filter if we have one. */ if (cf->dfcode) @@ -1675,37 +1188,20 @@ process_packet_second_pass(capture_file *cf, epan_dissect_t *edt, frame_data *fd this packet. */ print_packet(cf, edt); - /* The ANSI C standard does not appear to *require* that a line-buffered - stream be flushed to the host environment whenever a newline is - written, it just says that, on such a stream, characters "are - intended to be transmitted to or from the host environment as a - block when a new-line character is encountered". - - The Visual C++ 6.0 C implementation doesn't do what is intended; - even if you set a stream to be line-buffered, it still doesn't - flush the buffer at the end of every line. - - So, if the "-l" flag was specified, we flush the standard output - at the end of a packet. This will do the right thing if we're - printing packet summary lines, and, as we print the entire protocol - tree for a single packet without waiting for anything to happen, - it should be as good as line-buffered mode if we're printing - protocol trees. (The whole reason for the "-l" flag in either - tcpdump or TShark is to allow the output of a live capture to - be piped to a program or script and to have that script see the - information for the packet as soon as it's printed, rather than - having to wait until a standard I/O buffer fills up. */ + /* If we're doing "line-buffering", flush the standard output + after every packet. See the comment above, for the "-l" + option, for an explanation of why we do that. */ if (line_buffered) fflush(stdout); if (ferror(stdout)) { show_print_file_io_error(errno); - exit(2); + return FALSE; } } - prev_dis = fdata; + cf->provider.prev_dis = fdata; } - prev_cap = fdata; + cf->provider.prev_cap = fdata; if (edt) { epan_dissect_reset(edt); @@ -1713,18 +1209,18 @@ process_packet_second_pass(capture_file *cf, epan_dissect_t *edt, frame_data *fd return passed || fdata->flags.dependent_of_displayed; } -gboolean -local_wtap_read(capture_file *cf, struct wtap_pkthdr* file_phdr _U_, int *err, gchar **err_info _U_, gint64 *data_offset _U_, guint8** data_buffer) +static gboolean +local_wtap_read(capture_file *cf, wtap_rec *file_rec _U_, int *err, gchar **err_info _U_, gint64 *data_offset _U_, guint8** data_buffer) { /* int bytes_read; */ - gint64 packet_size = wtap_file_size(cf->wth, err); + gint64 packet_size = wtap_file_size(cf->provider.wth, err); *data_buffer = (guint8*)g_malloc((gsize)packet_size); - /* bytes_read =*/ file_read(*data_buffer, (unsigned int)packet_size, cf->wth->fh); + /* bytes_read =*/ file_read(*data_buffer, (unsigned int)packet_size, cf->provider.wth->fh); #if 0 /* no more filetap */ if (bytes_read < 0) { - *err = file_error(cf->wth->fh, err_info); + *err = file_error(cf->provider.wth->fh, err_info); if (*err == 0) *err = FTAP_ERR_SHORT_READ; return FALSE; @@ -1735,8 +1231,8 @@ local_wtap_read(capture_file *cf, struct wtap_pkthdr* file_phdr _U_, int *err, g /* XXX - SET FRAME SIZE EQUAL TO TOTAL FILE SIZE */ - file_phdr->caplen = (guint32)packet_size; - file_phdr->len = (guint32)packet_size; + file_rec->rec_header.packet_header.caplen = (guint32)packet_size; + file_rec->rec_header.packet_header.len = (guint32)packet_size; /* * Set the packet encapsulation to the file's encapsulation @@ -1746,7 +1242,7 @@ local_wtap_read(capture_file *cf, struct wtap_pkthdr* file_phdr _U_, int *err, g * *is* WTAP_ENCAP_PER_PACKET, the caller needs to set it * anyway. */ - wth->phdr.pkt_encap = wth->file_encap; + wth->rec.rec_header.packet_header.pkt_encap = wth->file_encap; if (!wth->subtype_read(wth, err, err_info, data_offset)) { /* @@ -1767,8 +1263,8 @@ local_wtap_read(capture_file *cf, struct wtap_pkthdr* file_phdr _U_, int *err, g * It makes no sense for the captured data length to be bigger * than the actual data length. */ - if (wth->phdr.caplen > wth->phdr.len) - wth->phdr.caplen = wth->phdr.len; + if (wth->rec.rec_header.packet_header.caplen > wth->rec.rec_header.packet_header.len) + wth->rec.rec_header.packet_header.caplen = wth->rec.rec_header.packet_header.len; /* * Make sure that it's not WTAP_ENCAP_PER_PACKET, as that @@ -1776,14 +1272,14 @@ local_wtap_read(capture_file *cf, struct wtap_pkthdr* file_phdr _U_, int *err, g * but the read routine didn't set this packet's * encapsulation type. */ - g_assert(wth->phdr.pkt_encap != WTAP_ENCAP_PER_PACKET); + g_assert(wth->rec.rec_header.packet_header.pkt_encap != WTAP_ENCAP_PER_PACKET); #endif return TRUE; /* success */ } -static int -load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count) +static gboolean +process_file(capture_file *cf, int max_packet_count, gint64 max_byte_count) { guint32 framenum; int err; @@ -1793,7 +1289,7 @@ load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count) guint tap_flags; Buffer buf; epan_dissect_t *edt = NULL; - struct wtap_pkthdr file_phdr; + wtap_rec file_rec; guint8* raw_data; if (print_packet_info) { @@ -1810,32 +1306,39 @@ load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count) /* Get the union of the flags for all tap listeners. */ tap_flags = union_of_tap_listener_flags(); - memset(&file_phdr, 0, sizeof(file_phdr)); + wtap_rec_init(&file_rec); /* XXX - TEMPORARY HACK TO ELF DISSECTOR */ - file_phdr.pkt_encap = 1234; + file_rec.rec_header.packet_header.pkt_encap = 1234; if (perform_two_pass_analysis) { frame_data *fdata; /* Allocate a frame_data_sequence for all the frames. */ - cf->frames = new_frame_data_sequence(); + cf->provider.frames = new_frame_data_sequence(); if (do_dissection) { - gboolean create_proto_tree = FALSE; + gboolean create_proto_tree; - /* If we're going to be applying a filter, we'll need to - create a protocol tree against which to apply the filter. */ - if (cf->rfcode) - create_proto_tree = TRUE; + /* + * Determine whether we need to create a protocol tree. + * We do if: + * + * we're going to apply a read filter; + * + * a postdissector wants field values or protocols + * on the first pass. + */ + create_proto_tree = + (cf->rfcode != NULL || postdissectors_want_hfids()); /* We're not going to display the protocol tree on this pass, so it's not going to be "visible". */ edt = epan_dissect_new(cf->epan, create_proto_tree, FALSE); } - while (local_wtap_read(cf, &file_phdr, &err, &err_info, &data_offset, &raw_data)) { - if (process_packet_first_pass(cf, edt, data_offset, &file_phdr/*wtap_phdr(cf->wth)*/, - wtap_buf_ptr(cf->wth))) { + while (local_wtap_read(cf, &file_rec, &err, &err_info, &data_offset, &raw_data)) { + if (process_packet_first_pass(cf, edt, data_offset, &file_rec/*wtap_get_rec(cf->provider.wth)*/, + wtap_get_buf_ptr(cf->provider.wth))) { /* Stop reading if we have the maximum number of packets; * When the -c option has not been used, max_packet_count @@ -1856,25 +1359,36 @@ load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count) #if 0 /* Close the sequential I/O side, to free up memory it requires. */ - wtap_sequential_close(cf->wth); + wtap_sequential_close(cf->provider.wth); #endif /* Allow the protocol dissectors to free up memory that they * don't need after the sequential run-through of the packets. */ postseq_cleanup_all_protocols(); - prev_dis = NULL; - prev_cap = NULL; + cf->provider.prev_dis = NULL; + cf->provider.prev_cap = NULL; ws_buffer_init(&buf, 1500); if (do_dissection) { gboolean create_proto_tree; - if (cf->dfcode || print_details || filtering_tap_listeners || - (tap_flags & TL_REQUIRES_PROTO_TREE) || have_custom_cols(&cf->cinfo)) - create_proto_tree = TRUE; - else - create_proto_tree = FALSE; + /* + * Determine whether we need to create a protocol tree. + * We do if: + * + * we're going to apply a display filter; + * + * we're going to print the protocol tree; + * + * one of the tap listeners requires a protocol tree; + * + * we have custom columns (which require field values, which + * currently requires that we build a protocol tree). + */ + create_proto_tree = + (cf->dfcode || print_details || filtering_tap_listeners || + (tap_flags & TL_REQUIRES_PROTO_TREE) || have_custom_cols(&cf->cinfo)); /* The protocol tree will be "visible", i.e., printed, only if we're printing packet details, which is true if we're printing stuff @@ -1884,14 +1398,16 @@ load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count) } for (framenum = 1; err == 0 && framenum <= cf->count; framenum++) { - fdata = frame_data_sequence_find(cf->frames, framenum); + fdata = frame_data_sequence_find(cf->provider.frames, framenum); #if 0 - if (wtap_seek_read(cf->wth, fdata->file_off, + if (wtap_seek_read(cf->provider.wth, fdata->file_off, &buf, fdata->cap_len, &err, &err_info)) { - process_packet_second_pass(cf, edt, fdata, &cf->phdr, &buf, tap_flags); + process_packet_second_pass(cf, edt, fdata, &cf->rec, &buf, tap_flags); } #else - process_packet_second_pass(cf, edt, fdata, &cf->phdr, &buf, tap_flags); + if (!process_packet_second_pass(cf, edt, fdata, &cf->rec, &buf, + tap_flags)) + return FALSE; #endif } @@ -1908,11 +1424,30 @@ load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count) if (do_dissection) { gboolean create_proto_tree; - if (cf->rfcode || cf->dfcode || print_details || filtering_tap_listeners || - (tap_flags & TL_REQUIRES_PROTO_TREE) || have_custom_cols(&cf->cinfo)) - create_proto_tree = TRUE; - else - create_proto_tree = FALSE; + /* + * Determine whether we need to create a protocol tree. + * We do if: + * + * we're going to apply a read filter; + * + * we're going to apply a display filter; + * + * we're going to print the protocol tree; + * + * one of the tap listeners is going to apply a filter; + * + * one of the tap listeners requires a protocol tree; + * + * a postdissector wants field values or protocols + * on the first pass; + * + * we have custom columns (which require field values, which + * currently requires that we build a protocol tree). + */ + create_proto_tree = + (cf->rfcode || cf->dfcode || print_details || filtering_tap_listeners || + (tap_flags & TL_REQUIRES_PROTO_TREE) || postdissectors_want_hfids() || + have_custom_cols(&cf->cinfo)); /* The protocol tree will be "visible", i.e., printed, only if we're printing packet details, which is true if we're printing stuff @@ -1921,22 +1456,24 @@ load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count) edt = epan_dissect_new(cf->epan, create_proto_tree, print_packet_info && print_details); } - while (local_wtap_read(cf, &file_phdr, &err, &err_info, &data_offset, &raw_data)) { + while (local_wtap_read(cf, &file_rec, &err, &err_info, &data_offset, &raw_data)) { framenum++; - process_packet(cf, edt, data_offset, &file_phdr/*wtap_phdr(cf->wth)*/, - raw_data, tap_flags); + if (!process_packet_single_pass(cf, edt, data_offset, + &file_rec/*wtap_get_rec(cf->provider.wth)*/, + raw_data, tap_flags)) + return FALSE; - /* Stop reading if we have the maximum number of packets; - * When the -c option has not been used, max_packet_count - * starts at 0, which practically means, never stop reading. - * (unless we roll over max_packet_count ?) - */ - if ( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) { - err = 0; /* This is not an error */ - break; - } + /* Stop reading if we have the maximum number of packets; + * When the -c option has not been used, max_packet_count + * starts at 0, which practically means, never stop reading. + * (unless we roll over max_packet_count ?) + */ + if ( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) { + err = 0; /* This is not an error */ + break; + } } if (edt) { @@ -1945,6 +1482,8 @@ load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count) } } + wtap_rec_cleanup(&file_rec); + if (err != 0) { /* * Print a message noting that the read failed somewhere along the line. @@ -2022,15 +1561,16 @@ load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count) } out: - wtap_close(cf->wth); - cf->wth = NULL; + wtap_close(cf->provider.wth); + cf->provider.wth = NULL; - return err; + return (err != 0); } static gboolean -process_packet(capture_file *cf, epan_dissect_t *edt, gint64 offset, - struct wtap_pkthdr *whdr, const guchar *pd, guint tap_flags) +process_packet_single_pass(capture_file *cf, epan_dissect_t *edt, gint64 offset, + wtap_rec *rec, const guchar *pd, + guint tap_flags) { frame_data fdata; column_info *cinfo; @@ -2044,7 +1584,7 @@ process_packet(capture_file *cf, epan_dissect_t *edt, gint64 offset, that all packets can be marked as 'passed'. */ passed = TRUE; - frame_data_init(&fdata, cf->count, whdr, offset, cum_bytes); + frame_data_init(&fdata, cf->count, rec, 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 @@ -2053,7 +1593,7 @@ process_packet(capture_file *cf, epan_dissect_t *edt, gint64 offset, /* If we're running a filter, prime the epan_dissect_t with that filter. */ if (cf->dfcode) - epan_dissect_prime_dfilter(edt, cf->dfcode); + epan_dissect_prime_with_dfilter(edt, cf->dfcode); col_custom_prime_edt(edt, &cf->cinfo); @@ -2070,13 +1610,15 @@ process_packet(capture_file *cf, epan_dissect_t *edt, gint64 offset, cinfo = NULL; frame_data_set_before_dissect(&fdata, &cf->elapsed_time, - &ref, prev_dis); - if (ref == &fdata) { + &cf->provider.ref, cf->provider.prev_dis); + if (cf->provider.ref == &fdata) { ref_frame = fdata; - ref = &ref_frame; + cf->provider.ref = &ref_frame; } - epan_dissect_file_run_with_taps(edt, whdr, frame_tvbuff_new(&fdata, pd), &fdata, cinfo); + epan_dissect_file_run_with_taps(edt, rec, + frame_tvbuff_new(&cf->provider, &fdata, pd), + &fdata, cinfo); /* Run the filter if we have it. */ if (cf->dfcode) @@ -2092,42 +1634,25 @@ process_packet(capture_file *cf, epan_dissect_t *edt, gint64 offset, this packet. */ print_packet(cf, edt); - /* The ANSI C standard does not appear to *require* that a line-buffered - stream be flushed to the host environment whenever a newline is - written, it just says that, on such a stream, characters "are - intended to be transmitted to or from the host environment as a - block when a new-line character is encountered". - - The Visual C++ 6.0 C implementation doesn't do what is intended; - even if you set a stream to be line-buffered, it still doesn't - flush the buffer at the end of every line. - - So, if the "-l" flag was specified, we flush the standard output - at the end of a packet. This will do the right thing if we're - printing packet summary lines, and, as we print the entire protocol - tree for a single packet without waiting for anything to happen, - it should be as good as line-buffered mode if we're printing - protocol trees. (The whole reason for the "-l" flag in either - tcpdump or TShark is to allow the output of a live capture to - be piped to a program or script and to have that script see the - information for the packet as soon as it's printed, rather than - having to wait until a standard I/O buffer fills up. */ + /* If we're doing "line-buffering", flush the standard output + after every packet. See the comment above, for the "-l" + option, for an explanation of why we do that. */ if (line_buffered) fflush(stdout); if (ferror(stdout)) { show_print_file_io_error(errno); - exit(2); + return FALSE; } } /* this must be set after print_packet() [bug #8160] */ prev_dis_frame = fdata; - prev_dis = &prev_dis_frame; + cf->provider.prev_dis = &prev_dis_frame; } prev_cap_frame = fdata; - prev_cap = &prev_cap_frame; + cf->provider.prev_cap = &prev_cap_frame; if (edt) { epan_dissect_reset(edt); @@ -2142,13 +1667,13 @@ write_preamble(capture_file *cf) switch (output_action) { case WRITE_TEXT: - return print_preamble(print_stream, cf ? cf->filename : NULL, get_ws_vcs_version_info()); + return print_preamble(print_stream, cf->filename, get_ws_vcs_version_info()); case WRITE_XML: if (print_details) - write_pdml_preamble(stdout, cf ? cf->filename : NULL); + write_pdml_preamble(stdout, cf->filename); else - write_psml_preamble(cf, stdout); + write_psml_preamble(&cf->cinfo, stdout); return !ferror(stdout); case WRITE_FIELDS: @@ -2221,21 +1746,23 @@ print_columns(capture_file *cf) size_t buf_offset; size_t column_len; size_t col_len; + col_item_t* col_item; line_bufp = get_line_buf(256); buf_offset = 0; *line_bufp = '\0'; for (i = 0; i < cf->cinfo.num_cols; i++) { + col_item = &cf->cinfo.columns[i]; /* Skip columns not marked as visible. */ if (!get_column_visible(i)) continue; - switch (cf->cinfo.col_fmt[i]) { + switch (col_item->col_fmt) { case COL_NUMBER: - column_len = col_len = strlen(cf->cinfo.col_data[i]); + column_len = col_len = strlen(col_item->col_data); if (column_len < 3) column_len = 3; line_bufp = get_line_buf(buf_offset + column_len); - put_spaces_string(line_bufp + buf_offset, cf->cinfo.col_data[i], col_len, column_len); + put_spaces_string(line_bufp + buf_offset, col_item->col_data, col_len, column_len); break; case COL_CLS_TIME: @@ -2246,11 +1773,11 @@ print_columns(capture_file *cf) case COL_UTC_TIME: case COL_UTC_YMD_TIME: /* XXX - wider */ case COL_UTC_YDOY_TIME: /* XXX - wider */ - column_len = col_len = strlen(cf->cinfo.col_data[i]); + column_len = col_len = strlen(col_item->col_data); if (column_len < 10) column_len = 10; line_bufp = get_line_buf(buf_offset + column_len); - put_spaces_string(line_bufp + buf_offset, cf->cinfo.col_data[i], col_len, column_len); + put_spaces_string(line_bufp + buf_offset, col_item->col_data, col_len, column_len); break; case COL_DEF_SRC: @@ -2262,11 +1789,11 @@ print_columns(capture_file *cf) case COL_DEF_NET_SRC: case COL_RES_NET_SRC: case COL_UNRES_NET_SRC: - column_len = col_len = strlen(cf->cinfo.col_data[i]); + column_len = col_len = strlen(col_item->col_data); if (column_len < 12) column_len = 12; line_bufp = get_line_buf(buf_offset + column_len); - put_spaces_string(line_bufp + buf_offset, cf->cinfo.col_data[i], col_len, column_len); + put_spaces_string(line_bufp + buf_offset, col_item->col_data, col_len, column_len); break; case COL_DEF_DST: @@ -2278,17 +1805,17 @@ print_columns(capture_file *cf) case COL_DEF_NET_DST: case COL_RES_NET_DST: case COL_UNRES_NET_DST: - column_len = col_len = strlen(cf->cinfo.col_data[i]); + column_len = col_len = strlen(col_item->col_data); if (column_len < 12) column_len = 12; line_bufp = get_line_buf(buf_offset + column_len); - put_string_spaces(line_bufp + buf_offset, cf->cinfo.col_data[i], col_len, column_len); + put_string_spaces(line_bufp + buf_offset, col_item->col_data, col_len, column_len); break; default: - column_len = strlen(cf->cinfo.col_data[i]); + column_len = strlen(col_item->col_data); line_bufp = get_line_buf(buf_offset + column_len); - put_string(line_bufp + buf_offset, cf->cinfo.col_data[i], column_len); + put_string(line_bufp + buf_offset, col_item->col_data, column_len); break; } buf_offset += column_len; @@ -2308,12 +1835,12 @@ print_columns(capture_file *cf) * even if we're only adding " ". */ line_bufp = get_line_buf(buf_offset + 4); - switch (cf->cinfo.col_fmt[i]) { + switch (col_item->col_fmt) { case COL_DEF_SRC: case COL_RES_SRC: case COL_UNRES_SRC: - switch (cf->cinfo.col_fmt[i + 1]) { + switch (cf->cinfo.columns[i+1].col_fmt) { case COL_DEF_DST: case COL_RES_DST: @@ -2332,7 +1859,7 @@ print_columns(capture_file *cf) case COL_DEF_DL_SRC: case COL_RES_DL_SRC: case COL_UNRES_DL_SRC: - switch (cf->cinfo.col_fmt[i + 1]) { + switch (cf->cinfo.columns[i+1].col_fmt) { case COL_DEF_DL_DST: case COL_RES_DL_DST: @@ -2351,7 +1878,7 @@ print_columns(capture_file *cf) case COL_DEF_NET_SRC: case COL_RES_NET_SRC: case COL_UNRES_NET_SRC: - switch (cf->cinfo.col_fmt[i + 1]) { + switch (cf->cinfo.columns[i+1].col_fmt) { case COL_DEF_NET_DST: case COL_RES_NET_DST: @@ -2370,7 +1897,7 @@ print_columns(capture_file *cf) case COL_DEF_DST: case COL_RES_DST: case COL_UNRES_DST: - switch (cf->cinfo.col_fmt[i + 1]) { + switch (cf->cinfo.columns[i+1].col_fmt) { case COL_DEF_SRC: case COL_RES_SRC: @@ -2389,7 +1916,7 @@ print_columns(capture_file *cf) case COL_DEF_DL_DST: case COL_RES_DL_DST: case COL_UNRES_DL_DST: - switch (cf->cinfo.col_fmt[i + 1]) { + switch (cf->cinfo.columns[i+1].col_fmt) { case COL_DEF_DL_SRC: case COL_RES_DL_SRC: @@ -2408,7 +1935,7 @@ print_columns(capture_file *cf) case COL_DEF_NET_DST: case COL_RES_NET_DST: case COL_UNRES_NET_DST: - switch (cf->cinfo.col_fmt[i + 1]) { + switch (cf->cinfo.columns[i+1].col_fmt) { case COL_DEF_NET_SRC: case COL_RES_NET_SRC: @@ -2437,8 +1964,6 @@ print_columns(capture_file *cf) static gboolean print_packet(capture_file *cf, epan_dissect_t *edt) { - print_args_t print_args; - if (print_summary || output_fields_has_cols(output_fields)) { /* Just fill in the columns. */ epan_dissect_fill_in_columns(edt, FALSE, TRUE); @@ -2453,7 +1978,7 @@ print_packet(capture_file *cf, epan_dissect_t *edt) break; case WRITE_XML: - proto_tree_write_psml(edt, stdout); + write_psml_columns(edt, stdout, FALSE); return !ferror(stdout); case WRITE_FIELDS: /*No non-verbose "fields" format */ g_assert_not_reached(); @@ -2466,19 +1991,8 @@ print_packet(capture_file *cf, epan_dissect_t *edt) switch (output_action) { case WRITE_TEXT: - /* Only initialize the fields that are actually used in proto_tree_print. - * This is particularly important for .range, as that's heap memory which - * we would otherwise have to g_free(). - print_args.to_file = TRUE; - print_args.format = print_format; - print_args.print_summary = print_summary; - print_args.print_formfeed = FALSE; - packet_range_init(&print_args.range, &cfile); - */ - print_args.print_hex = print_hex; - print_args.print_dissections = print_details ? print_dissections_expanded : print_dissections_none; - - if (!proto_tree_print(&print_args, edt, output_only_tables, print_stream)) + if (!proto_tree_print(print_details ? print_dissections_expanded : print_dissections_none, + print_hex, edt, output_only_tables, print_stream)) return FALSE; if (!print_hex) { if (!print_line(print_stream, 0, separator)) @@ -2487,11 +2001,11 @@ print_packet(capture_file *cf, epan_dissect_t *edt) break; case WRITE_XML: - proto_tree_write_pdml(edt, stdout); + write_pdml_proto_tree(NULL, NULL, PF_NONE, edt, &cf->cinfo, stdout, FALSE); printf("\n"); return !ferror(stdout); case WRITE_FIELDS: - proto_tree_write_fields(output_fields, edt, &cf->cinfo, stdout); + write_fields_proto_tree(output_fields, edt, &cf->cinfo, stdout); printf("\n"); return !ferror(stdout); } @@ -2546,7 +2060,7 @@ cf_open(capture_file *cf, const char *fname, unsigned int type, gboolean is_temp epan_free(cf->epan); cf->epan = tfshark_epan_new(cf); - cf->wth = NULL; /**** XXX - DOESN'T WORK RIGHT NOW!!!! */ + cf->provider.wth = NULL; /**** XXX - DOESN'T WORK RIGHT NOW!!!! */ cf->f_datalen = 0; /* not used, but set it anyway */ /* Set the file name because we need it to set the follow stream filter. @@ -2566,16 +2080,10 @@ cf_open(capture_file *cf, const char *fname, unsigned int type, gboolean is_temp cf->drops_known = FALSE; cf->drops = 0; cf->snap = 0; /**** XXX - DOESN'T WORK RIGHT NOW!!!! */ - if (cf->snap == 0) { - /* Snapshot length not known. */ - cf->has_snap = FALSE; - cf->snap = 0; - } else - cf->has_snap = TRUE; nstime_set_zero(&cf->elapsed_time); - ref = NULL; - prev_dis = NULL; - prev_cap = NULL; + cf->provider.ref = NULL; + cf->provider.prev_dis = NULL; + cf->provider.prev_cap = NULL; cf->state = FILE_READ_IN_PROGRESS; @@ -2619,9 +2127,9 @@ cf_open_error_message(int err, gchar *err_info _U_, gboolean for_writing, const char *errmsg; /* static char errmsg_errno[1024+1]; */ +#if 0 if (err < 0) { /* Wiretap error. */ -#if 0 switch (err) { case FTAP_ERR_NOT_REGULAR_FILE: @@ -2730,32 +2238,32 @@ cf_open_error_message(int err, gchar *err_info _U_, gboolean for_writing, errmsg = errmsg_errno; break; } -#endif } else +#endif errmsg = file_open_error_message(err, for_writing); return errmsg; } /* - * Open/create errors are reported with an console message in TFShark. + * General errors and warnings are reported with an console message + * in TFShark. */ static void -open_failure_message(const char *filename, int err, gboolean for_writing) +failure_warning_message(const char *msg_format, va_list ap) { fprintf(stderr, "tfshark: "); - fprintf(stderr, file_open_error_message(err, for_writing), filename); + vfprintf(stderr, msg_format, ap); fprintf(stderr, "\n"); } - /* - * General errors are reported with an console message in TFShark. + * Open/create errors are reported with an console message in TFShark. */ static void -failure_message(const char *msg_format, va_list ap) +open_failure_message(const char *filename, int err, gboolean for_writing) { fprintf(stderr, "tfshark: "); - vfprintf(stderr, msg_format, ap); + fprintf(stderr, file_open_error_message(err, for_writing), filename); fprintf(stderr, "\n"); } @@ -2790,7 +2298,7 @@ failure_message_cont(const char *msg_format, va_list ap) } /* - * Editor modelines - http://www.wireshark.org/tools/modelines.html + * Editor modelines - https://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 2