Update to V9.0.0 (2009-12)
[obnox/wireshark/wip.git] / rawshark.c
index 03e20435a63933306ea7975ad24945332421b439..9b99b3a92b40686469b4a024a9f1e9f2c61caadb 100644 (file)
@@ -31,7 +31,7 @@
  * - Opens a specified file or named pipe
  * - Applies a specfied DLT or "decode as" encapsulation
  * - Reads frames prepended with a libpcap packet header.
- * - Prints a status line, followed by  fields from a specified list.
+ * - Prints a status line, followed by fields from a specified list.
  */
 
 #ifdef HAVE_CONFIG_H
 #include "strerror.h"
 #endif
 
-#ifdef NEED_GETOPT_H
-#include "getopt.h"
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+#include "wsgetopt.h"
 #endif
 
 #include <glib.h>
@@ -87,7 +89,6 @@
 #include "clopts_common.h"
 #include "cmdarg_err.h"
 #include "version_info.h"
-#include <epan/conversation.h>
 #include <epan/plugins.h>
 #include "register.h"
 #include "conditions.h"
  */
 static const gchar decode_as_arg_template[] = "<layer_type>==<selector>,<decode_as_protocol>";
 
+static guint32 cum_bytes;
 static nstime_t first_ts;
 static nstime_t prev_dis_ts;
 static nstime_t prev_cap_ts;
-static GString *comp_info_str, *runtime_info_str;
 
 /*
  * The way the packet decode is to be written.
@@ -135,8 +136,8 @@ typedef enum {
        WRITE_XML       /* PDML or PSML */
        /* Add CSV and the like here */
 } output_action_e;
+
 static gboolean line_buffered;
-static guint32 cum_bytes = 0;
 static print_format_e print_format = PR_FMT_TEXT;
 
 /*
@@ -155,6 +156,7 @@ 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 protocolinfo_init(char *field);
 static gboolean parse_field_string_format(char *format);
 
@@ -208,6 +210,7 @@ print_usage(gboolean print_ver)
   fprintf(output, "Processing:\n");
   fprintf(output, "  -R <read filter>         packet filter in Wireshark display filter syntax\n");
   fprintf(output, "  -F <field>               field to display\n");
+  fprintf(output, "  -s                       skip PCAP header on input\n");
   fprintf(output, "  -n                       disable all name resolution (def: all enabled)\n");
   fprintf(output, "  -N <name resolve flags>  enable specific name resolution(s): \"mntC\"\n");
   fprintf(output, "  -d <encap:dlt>|<proto:protoname>\n");
@@ -215,7 +218,7 @@ print_usage(gboolean print_ver)
 
   /*fprintf(output, "\n");*/
   fprintf(output, "Output:\n");
-  fprintf(output, "  -S                       format string for fields (%%D - name, %%S - stringval, %%N numval\n");
+  fprintf(output, "  -S                       format string for fields (%%D - name, %%S - stringval, %%N numval)\n");
   fprintf(output, "  -t ad|a|r|d|dd|e         output format of time stamps (def: r: rel. to first)\n");
   fprintf(output, "  -l                       flush output after each packet\n");
 
@@ -408,12 +411,25 @@ set_link_type(const char *lt_arg) {
   return FALSE;
 }
 
+static void
+show_version(GString *comp_info_str, GString *runtime_info_str)
+{
+  printf("Rawshark " VERSION "%s\n"
+         "\n"
+         "%s"
+         "\n"
+         "%s"
+         "\n"
+         "%s",
+         wireshark_svnversion, get_copyright_info(), comp_info_str->str,
+         runtime_info_str->str);
+}
+
 int
 main(int argc, char *argv[])
 {
   char                *init_progfile_dir_error;
   int                  opt, i;
-  extern char         *optarg;
   gboolean             arg_error = FALSE;
 
 #ifdef _WIN32
@@ -434,8 +450,9 @@ main(int argc, char *argv[])
   GLogLevelFlags       log_flags;
   GPtrArray           *disp_fields = g_ptr_array_new();
   guint                fc;
+  gboolean             skip_pcap_header = FALSE;
 
-  #define OPTSTRING_INIT "d:F:hlnN:o:r:R:S:t:v"
+  #define OPTSTRING_INIT "d:F:hlnN:o:r:R:sS:t:v"
 
   static const char    optstring[] = OPTSTRING_INIT;
 
@@ -460,7 +477,7 @@ main(int argc, char *argv[])
   /*
    * Attempt to get the pathname of the executable file.
    */
-  init_progfile_dir_error = init_progfile_dir(argv[0]);
+  init_progfile_dir_error = init_progfile_dir(argv[0], main);
   if (init_progfile_dir_error != NULL) {
     fprintf(stderr, "rawshark: Can't get pathname of rawshark program: %s.\n",
             init_progfile_dir_error);
@@ -493,7 +510,8 @@ main(int argc, char *argv[])
      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,
-            failure_message, open_failure_message, read_failure_message);
+            failure_message, open_failure_message, read_failure_message,
+            write_failure_message);
 
   /* Now register the preferences for any non-dissector modules.
      We must do that before we read the preferences as well. */
@@ -563,15 +581,7 @@ main(int argc, char *argv[])
   load_wpcap();
 #endif
 
-  init_cap_file(&cfile);
-
-  /* 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);
+  cap_file_init(&cfile);
 
   /* Print format defaults to this. */
   print_format = PR_FMT_TEXT;
@@ -654,6 +664,9 @@ main(int argc, char *argv[])
           exit(1);
         }
         break;
+      case 's':        /* Skip PCAP header */
+        skip_pcap_header = TRUE;
+        break;
       case 'S':        /* Print string representations */
         if (!parse_field_string_format(optarg)) {
           cmdarg_err("Invalid field string format");
@@ -682,18 +695,22 @@ main(int argc, char *argv[])
         }
         break;
       case 'v':        /* Show version and exit */
-        printf("Rawshark " VERSION "%s\n"
-               "\n"
-               "%s"
-               "\n"
-               "%s"
-               "\n"
-               "%s",
-               wireshark_svnversion, get_copyright_info(), comp_info_str->str,
-               runtime_info_str->str);
+      {
+        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);
         break;
-
+      }
       default:
       case '?':        /* Bad flag - print usage message */
         print_usage(TRUE);
@@ -702,6 +719,13 @@ main(int argc, char *argv[])
     }
   }
 
+  /* Notify all registered modules that have had any of their preferences
+     changed either from one of the preferences file or from the command
+     line that their preferences have changed.
+     Initialize preferences before display filters, otherwise modules
+     like MATE won't work. */
+  prefs_apply_all();
+
   /* Initialize our display fields */
   for (fc = 0; fc < disp_fields->len; fc++) {
        protocolinfo_init(g_ptr_array_index(disp_fields, fc));
@@ -742,11 +766,6 @@ main(int argc, char *argv[])
   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
 #endif /* _WIN32 */
 
-  /* Notify all registered modules that have had any of their preferences
-     changed either from one of the preferences file or from the command
-     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. */
@@ -758,35 +777,7 @@ main(int argc, char *argv[])
   }
 
   /* Build the column format array */
-  col_setup(&cfile.cinfo, prefs->num_cols);
-  for (i = 0; i < cfile.cinfo.num_cols; i++) {
-    cfile.cinfo.col_fmt[i] = get_column_format(i);
-    cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
-    cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
-      NUM_COL_FMTS);
-    get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
-    cfile.cinfo.col_data[i] = NULL;
-    if (cfile.cinfo.col_fmt[i] == COL_INFO)
-      cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
-    else
-      cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
-    cfile.cinfo.col_fence[i] = 0;
-    cfile.cinfo.col_expr.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
-    cfile.cinfo.col_expr.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
-  }
-
-  for (i = 0; i < cfile.cinfo.num_cols; i++) {
-      int j;
-
-      for (j = 0; j < NUM_COL_FMTS; j++) {
-         if (!cfile.cinfo.fmt_matx[i][j])
-             continue;
-
-         if (cfile.cinfo.col_first[j] == -1)
-             cfile.cinfo.col_first[j] = i;
-         cfile.cinfo.col_last[j] = i;
-      }
-  }
+  build_column_format_array(&cfile.cinfo, prefs->num_cols, TRUE);
 
   if (n_rfilters != 0) {
     for (i = 0; i < n_rfilters; i++) {
@@ -816,6 +807,20 @@ main(int argc, char *argv[])
       exit(2);
     }
 
+    /* Do we need to PCAP header and magic? */
+    if (skip_pcap_header) {
+      guint bytes_left = sizeof(struct pcap_hdr) + sizeof(guint32);
+      gchar buf[sizeof(struct pcap_hdr) + sizeof(guint32)];
+      while (bytes_left > 0) {
+          guint bytes = read(fd, buf, bytes_left);
+          if (bytes <= 0) {
+              cmdarg_err("Not enough bytes for pcap header.");
+              exit(2);
+          }
+          bytes_left -= bytes;
+      }
+    }
+
     /* Set timestamp precision; there should arguably be a command-line
        option to let the user set this. */
 #if 0
@@ -876,14 +881,15 @@ main(int argc, char *argv[])
  */
 static gboolean
 raw_pipe_read(struct wtap_pkthdr *phdr, guchar * pd, int *err, gchar **err_info, gint64 *data_offset) {
-  struct pcap_pkthdr hdr;
+  struct pcaprec_hdr hdr;
   int bytes_read = 0;
-  int bytes_needed = sizeof(struct pcap_pkthdr);
+  int bytes_needed = sizeof(struct pcaprec_hdr);
+  guchar *ptr = (guchar*)&hdr;
   static gchar err_str[100];
 
   /* Copied from capture_loop.c */
   while (bytes_needed > 0) {
-    bytes_read = read(fd, &hdr, bytes_needed);
+    bytes_read = read(fd, ptr, bytes_needed);
     if (bytes_read == 0) {
       *err = 0;
       return FALSE;
@@ -894,13 +900,13 @@ raw_pipe_read(struct wtap_pkthdr *phdr, guchar * pd, int *err, gchar **err_info,
     }
     bytes_needed -= bytes_read;
     *data_offset += bytes_read;
+    ptr += bytes_read;
   }
 
-  bytes_read = 0;
-  phdr->ts.secs = hdr.ts.tv_sec;
-  phdr->ts.nsecs = hdr.ts.tv_usec * 1000;
-  phdr->caplen = bytes_needed = hdr.caplen;
-  phdr->len = hdr.len;
+  phdr->ts.secs = hdr.ts_sec;
+  phdr->ts.nsecs = hdr.ts_usec * 1000;
+  phdr->caplen = bytes_needed = hdr.incl_len;
+  phdr->len = hdr.orig_len;
   phdr->pkt_encap = encap;
 
 #if 0
@@ -916,8 +922,9 @@ raw_pipe_read(struct wtap_pkthdr *phdr, guchar * pd, int *err, gchar **err_info,
     return FALSE;
   }
 
+  ptr = pd;
   while (bytes_needed > 0) {
-    bytes_read = read(fd, pd, bytes_needed);
+    bytes_read = read(fd, ptr, bytes_needed);
     if (bytes_read == 0) {
       *err = WTAP_ERR_SHORT_READ;
       *err_info = "Got zero bytes reading data from pipe";
@@ -929,6 +936,7 @@ raw_pipe_read(struct wtap_pkthdr *phdr, guchar * pd, int *err, gchar **err_info,
     }
     bytes_needed -= bytes_read;
     *data_offset += bytes_read;
+    ptr += bytes_read;
   }
   return TRUE;
 }
@@ -980,87 +988,13 @@ load_cap_file(capture_file *cf)
   return err;
 }
 
-static void
-fill_in_fdata(frame_data *fdata, capture_file *cf,
-              const struct wtap_pkthdr *phdr, gint64 offset)
-{
-  fdata->next = NULL;
-  fdata->prev = NULL;
-  fdata->pfd = NULL;
-  fdata->num = cf->count;
-  fdata->pkt_len = phdr->len;
-  cum_bytes += phdr->len;
-  fdata->cum_bytes  = cum_bytes;
-  fdata->cap_len = phdr->caplen;
-  fdata->file_off = offset;
-  fdata->lnk_t = phdr->pkt_encap;
-  fdata->abs_ts.secs = phdr->ts.secs;
-  fdata->abs_ts.nsecs = phdr->ts.nsecs;
-  fdata->flags.passed_dfilter = 0;
-  fdata->flags.encoding = CHAR_ASCII;
-  fdata->flags.visited = 0;
-  fdata->flags.marked = 0;
-  fdata->flags.ref_time = 0;
-  fdata->color_filter = NULL;
-
-  /* If we don't have the time stamp of the first packet in the
-     capture, it's because this is the first packet.  Save the time
-     stamp of this packet as the time stamp of the first packet. */
-  if (nstime_is_unset(&first_ts)) {
-    first_ts = fdata->abs_ts;
-  }
-
-  /* If we don't have the time stamp of the previous captured packet,
-     it's because this is the first packet.  Save the time
-     stamp of this packet as the time stamp of the previous captured
-     packet. */
-  if (nstime_is_unset(&prev_cap_ts)) {
-    prev_cap_ts = fdata->abs_ts;
-  }
-
-  /* Get the time elapsed between the first packet and this packet. */
-  nstime_delta(&fdata->rel_ts, &fdata->abs_ts, &first_ts);
-
-  /* If it's greater than the current elapsed time, set the elapsed time
-     to it (we check for "greater than" so as not to be confused by
-     time moving backwards). */
-  if ((gint32)cf->elapsed_time.secs < fdata->rel_ts.secs
-       || ((gint32)cf->elapsed_time.secs == fdata->rel_ts.secs && (gint32)cf->elapsed_time.nsecs < fdata->rel_ts.nsecs)) {
-    cf->elapsed_time = fdata->rel_ts;
-  }
-
-  /* If we don't have the time stamp of the previous displayed packet,
-     it's because this is the first packet that's being displayed.  Save the time
-     stamp of this packet as the time stamp of the previous displayed
-     packet. */
-  if (nstime_is_unset(&prev_dis_ts))
-    prev_dis_ts = fdata->abs_ts;
-
-  /* Get the time elapsed between the previous displayed packet and
-     this packet. */
-  nstime_delta(&fdata->del_dis_ts, &fdata->abs_ts, &prev_dis_ts);
-
-  /* Get the time elapsed between the previous captured packet and
-     this packet. */
-  nstime_delta(&fdata->del_cap_ts, &fdata->abs_ts, &prev_cap_ts);
-  prev_cap_ts = fdata->abs_ts;
-}
-
-/* Free up all data attached to a "frame_data" structure. */
-static void
-clear_fdata(frame_data *fdata)
-{
-  if (fdata->pfd)
-    g_slist_free(fdata->pfd);
-}
-
 static gboolean
 process_packet(capture_file *cf, gint64 offset, const struct wtap_pkthdr *whdr,
                const guchar *pd)
 {
   frame_data fdata;
   gboolean create_proto_tree;
-  epan_dissect_t *edt;
+  epan_dissect_t edt;
   gboolean passed;
   union wtap_pseudo_header pseudo_header;
   int i;
@@ -1087,7 +1021,7 @@ process_packet(capture_file *cf, gint64 offset, const struct wtap_pkthdr *whdr,
   /* 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. */
-  fill_in_fdata(&fdata, cf, whdr, offset);
+  frame_data_init(&fdata, cf->count, whdr, offset, cum_bytes);
 
   passed = TRUE;
   create_proto_tree = TRUE;
@@ -1095,31 +1029,36 @@ process_packet(capture_file *cf, gint64 offset, const struct wtap_pkthdr *whdr,
   /* The protocol tree will be "visible", i.e., printed, only if we're
      printing packet details, which is true if we're in verbose mode ("verbose"
      is true). */
-  edt = epan_dissect_new(create_proto_tree, FALSE);
+  epan_dissect_init(&edt, create_proto_tree, FALSE);
 
   /* If we're running a read filter, prime the epan_dissect_t with that
      filter. */
   if (n_rfilters > 0) {
     for(i = 0; i < n_rfcodes; i++) {
-      epan_dissect_prime_dfilter(edt, rfcodes[i]);
+      epan_dissect_prime_dfilter(&edt, rfcodes[i]);
     }
   }
 
-  tap_queue_init(edt);
+  tap_queue_init(&edt);
+
+  printf("%lu", (unsigned long int) cf->count);
 
-  printf("%lu", (unsigned long int)cf->count);
+  frame_data_set_before_dissect(&fdata, &cf->elapsed_time,
+                                &first_ts, &prev_dis_ts, &prev_cap_ts);
 
   /* We only need the columns if we're printing packet info but we're
      *not* verbose; in verbose mode, we print the protocol tree, not
      the protocol summary. */
-  epan_dissect_run(edt, &pseudo_header, pd, &fdata, &cf->cinfo);
+  epan_dissect_run(&edt, &pseudo_header, pd, &fdata, &cf->cinfo);
 
-  tap_push_tapped_queue(edt);
+  tap_push_tapped_queue(&edt);
+
+  frame_data_set_after_dissect(&fdata, &cum_bytes, &prev_dis_ts);
 
   for(i = 0; i < n_rfilters; i++) {
     /* Run the read filter if we have one. */
     if (rfcodes[i])
-      passed = dfilter_apply_edt(rfcodes[i], edt);
+      passed = dfilter_apply_edt(rfcodes[i], &edt);
     else
       passed = TRUE;
 
@@ -1157,8 +1096,8 @@ process_packet(capture_file *cf, gint64 offset, const struct wtap_pkthdr *whdr,
     exit(2);
   }
 
-  epan_dissect_free(edt);
-  clear_fdata(&fdata);
+  epan_dissect_cleanup(&edt);
+  frame_data_cleanup(&fdata);
 
   return passed;
 }
@@ -1250,7 +1189,19 @@ char* ftenum_to_string(header_field_info *hfi)
        };
 }
 
-char* base_display_e_to_string(base_display_e bd)
+static char* absolute_time_display_e_to_string(absolute_time_display_e atd)
+{
+       switch(atd) {
+       case ABSOLUTE_TIME_LOCAL:
+                       return "ABSOLUTE_TIME_LOCAL";
+       case ABSOLUTE_TIME_UTC:
+                       return "ABSOLUTE_TIME_UTC";
+       default:
+                       return "n.a.";
+       }
+}
+
+static char* base_display_e_to_string(base_display_e bd)
 {
        switch(bd) {
        case BASE_NONE:
@@ -1434,17 +1385,30 @@ protocolinfo_init(char *field)
                exit(1);
        }
 
-       printf("%u %s %s - ",
-               g_cmd_line_index,
-               ftenum_to_string(hfi),
-               base_display_e_to_string(hfi->display));
+       switch (hfi->type) {
+
+       case FT_ABSOLUTE_TIME:
+               printf("%u %s %s - ",
+                       g_cmd_line_index,
+                       ftenum_to_string(hfi),
+                       absolute_time_display_e_to_string(hfi->display));
+               break;
+               break;
+
+       default:
+               printf("%u %s %s - ",
+                       g_cmd_line_index,
+                       ftenum_to_string(hfi),
+                       base_display_e_to_string(hfi->display));
+               break;
+       }
 
        rs=g_malloc(sizeof(pci_t));
        rs->hf_index=hfi->id;
        rs->filter=field;
        rs->cmd_line_index = g_cmd_line_index++;
 
-       error_string=register_tap_listener("frame", rs, rs->filter, NULL, protocolinfo_packet, NULL);
+       error_string=register_tap_listener("frame", rs, rs->filter, TL_REQUIRES_PROTO_TREE, NULL, protocolinfo_packet, NULL);
        if(error_string){
                /* error, we failed to attach to the tap. complain and clean up */
                fprintf(stderr, "rawshark: Couldn't register field extraction tap: %s\n",
@@ -1477,8 +1441,8 @@ add_string_fmt(string_fmt_e format, gchar *plain) {
 static gboolean
 parse_field_string_format(gchar *format) {
        GString *plain_s = g_string_new("");
-       int len;
-       int pos = 0;
+       size_t len;
+       size_t pos = 0;
 
        if (!format) {
                return FALSE;
@@ -1573,6 +1537,8 @@ raw_cf_open(capture_file *cf, const char *fname)
 
   /* The open succeeded.  Fill in the information for this file. */
 
+  /* Cleanup all data structures used for dissection. */
+  cleanup_dissection();
   /* Initialize all data structures used for dissection. */
   init_dissection();
 
@@ -1626,6 +1592,16 @@ read_failure_message(const char *filename, int err)
           filename, strerror(err));
 }
 
+/*
+ * Write errors are reported with an console message in Rawshark.
+ */
+static void
+write_failure_message(const char *filename, int err)
+{
+  cmdarg_err("An error occurred while writing to the file \"%s\": %s.",
+          filename, strerror(err));
+}
+
 /*
  * Report an error in command-line arguments.
  */