Ringbuffer rework.
[obnox/wireshark/wip.git] / tethereal.c
index e307576bc87a2bba99d6be26e9af7b5ae8a1d0d2..4d3835fca929a9c3af0b414b76dd520f090f7dc8 100644 (file)
@@ -1,6 +1,6 @@
 /* tethereal.c
  *
- * $Id: tethereal.c,v 1.168 2002/11/01 01:11:59 sahlberg Exp $
+ * $Id: tethereal.c,v 1.188 2003/06/22 16:06:03 deniel Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 #include <setjmp.h>
 #endif
 
-#ifdef HAVE_LIBZ
-#include <zlib.h>      /* to get the libz version number */
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
 #endif
 
 #ifdef NEED_SNPRINTF_H
 # include "snprintf.h"
 #endif
 
-#ifdef HAVE_SOME_SNMP
-
-#ifdef HAVE_NET_SNMP
-#include <net-snmp/version.h>
-#endif /* HAVE_NET_SNMP */
-
-#ifdef HAVE_UCD_SNMP
-#include <ucd-snmp/version.h>
-#endif /* HAVE_UCD_SNMP */
-
-#endif /* HAVE_SOME_SNMP */
-
 #ifdef NEED_STRERROR_H
 #include "strerror.h"
 #endif
 
 #ifdef HAVE_LIBPCAP
 #include <wiretap/wtap-capture.h>
+#include <wiretap/libpcap.h>
 #endif
 
-#ifdef WIN32
+#ifdef _WIN32
 #include "capture-wpcap.h"
 #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[] = "<layer_type>==<selector>,<decode_as_protocol>";
 static guint32 firstsec, firstusec;
 static guint32 prevsec, prevusec;
-static GString *comp_info_str;
+static GString *comp_info_str, *runtime_info_str;
 static gboolean quiet;
 static gboolean decode;
 static gboolean verbose;
@@ -126,11 +120,23 @@ static gboolean line_buffered;
 typedef struct _loop_data {
   gboolean       go;           /* TRUE as long as we're supposed to keep capturing */
   gint           linktype;
+  gboolean       from_pipe;    /* TRUE if we are capturing data from a pipe */
   pcap_t        *pch;
   wtap_dumper   *pdh;
   jmp_buf        stopenv;
   gboolean       output_to_pipe;
   int            packet_count;
+#ifndef _WIN32
+  gboolean       modified;     /* TRUE if data in the pipe uses modified pcap headers */
+  gboolean       byte_swapped; /* TRUE if data in the pipe is byte swapped */
+  unsigned int   bytes_to_read, bytes_read; /* Used by pipe_dispatch */
+  enum {
+         STATE_EXPECT_REC_HDR, STATE_READ_REC_HDR,
+         STATE_EXPECT_DATA,     STATE_READ_DATA
+       } pipe_state;
+
+  enum { PIPOK, PIPEOF, PIPERR, PIPNEXIST } pipe_err;
+#endif
 } loop_data;
 
 static loop_data ld;
@@ -138,10 +144,14 @@ static loop_data ld;
 static int capture(int);
 static void capture_pcap_cb(guchar *, const struct pcap_pkthdr *,
   const guchar *);
+static void report_counts(void);
 #ifdef _WIN32
 static BOOL WINAPI capture_cleanup(DWORD);
 #else /* _WIN32 */
 static void capture_cleanup(int);
+#ifdef SIGINFO
+static void report_counts_siginfo(int);
+#endif /* SIGINFO */
 #endif /* _WIN32 */
 #endif /* HAVE_LIBPCAP */
 
@@ -156,6 +166,14 @@ static void wtap_dispatch_cb_write(guchar *, const struct wtap_pkthdr *, long,
 static void show_capture_file_io_error(const char *, int, gboolean);
 static void wtap_dispatch_cb_print(guchar *, const struct wtap_pkthdr *, long,
     union wtap_pseudo_header *, const guchar *);
+#ifdef HAVE_LIBPCAP
+#ifndef _WIN32
+static void adjust_header(loop_data *, struct pcap_hdr *, struct pcaprec_hdr *);
+static int pipe_open_live(char *, struct pcap_hdr *, loop_data *, char *, int);
+static int pipe_dispatch(int, loop_data *, struct pcap_hdr *, \
+                struct pcaprec_modified_hdr *, guchar *, char *, int);
+#endif /* _WIN32 */
+#endif
 
 capture_file cfile;
 ts_type timestamp_type = RELATIVE;
@@ -172,6 +190,8 @@ typedef struct {
        gint32 autostop_filesize;       /* Maximum capture file size */
        gboolean ringbuffer_on;         /* TRUE if ring buffer in use */
        guint32 ringbuffer_num_files;   /* Number of ring buffer files */
+       gboolean has_ring_duration;     /* TRUE if ring duration specified */
+       gint32 ringbuffer_duration;     /* Switch file after n seconds */
 } capture_options;
 
 static capture_options capture_opts = {
@@ -187,10 +207,17 @@ static capture_options capture_opts = {
                                           specified by default */
        0,                              /* maximum capture file size */
        FALSE,                          /* ring buffer off by default */
-       RINGBUFFER_MIN_NUM_FILES        /* default number of ring buffer
+       RINGBUFFER_MIN_NUM_FILES,       /* default number of ring buffer
                                           files */
+       FALSE,                          /* Switch ring file after some */
+       0                               /* specified time is off by default */
 };
-#endif
+
+#ifdef SIGINFO
+static gboolean infodelay;     /* if TRUE, don't print capture info in SIGINFO handler */
+static gboolean infoprint;     /* if TRUE, print capture info after clearing infodelay */
+#endif /* SIGINFO */
+#endif /* HAVE_LIBPCAP */
 
 static void
 print_usage(gboolean print_ver)
@@ -198,23 +225,25 @@ print_usage(gboolean print_ver)
   int i;
 
   if (print_ver) {
-    fprintf(stderr, "This is GNU t%s %s, compiled %s\n", PACKAGE, VERSION,
-       comp_info_str->str);
+    fprintf(stderr, "This is GNU t%s %s\n%s\n%s\n", PACKAGE, VERSION,
+       comp_info_str->str, runtime_info_str->str);
   }
 #ifdef HAVE_LIBPCAP
-  fprintf(stderr, "\nt%s [ -DvVhqSlp ] [ -a <capture autostop condition> ] ...\n",
+  fprintf(stderr, "\nt%s [ -vh ] [ -DlnpqSVx ] [ -a <capture autostop condition> ] ...\n",
          PACKAGE);
-  fprintf(stderr, "\t[ -b <number of ring buffer files> ] [ -c <count> ]\n");
-  fprintf(stderr, "\t[ -f <capture filter> ] [ -F <output file type> ]\n");
-  fprintf(stderr, "\t[ -i <interface> ] [ -n ] [ -N <resolving> ]\n");
-  fprintf(stderr, "\t[ -o <preference setting> ] ... [ -r <infile> ] [ -R <read filter> ]\n");
-  fprintf(stderr, "\t[ -s <snaplen> ] [ -t <time stamp format> ] [ -w <savefile> ] [ -x ]\n");
+  fprintf(stderr, "\t[ -b <number of ring buffer files>[:<duration>] ] [ -c <count> ]\n");
+  fprintf(stderr, "\t[ -d %s ] ...\n", decode_as_arg_template);
+  fprintf(stderr, "\t[ -f <capture filter> ] [ -F <output file type> ] [ -i <interface> ]\n");
+  fprintf(stderr, "\t[ -N <resolving> ] [ -o <preference setting> ] ... [ -r <infile> ]\n");
+  fprintf(stderr, "\t[ -R <read filter> ] [ -s <snaplen> ] [ -t <time stamp format> ]\n");
+  fprintf(stderr, "\t[ -w <savefile> ] [ -Z <statistics string> ]\n");
 #else
-  fprintf(stderr, "\nt%s [ -vVhl ] [ -F <output file type> ] [ -n ] [ -N <resolving> ]\n", PACKAGE);
+  fprintf(stderr, "\nt%s [ -vh ] [ -lnVx ]\n", PACKAGE);
+  fprintf(stderr, "\t[ -d %s ] ...\n", decode_as_arg_template);
+  fprintf(stderr, "\t[ -F <output file type> ] [ -N <resolving> ]\n");
   fprintf(stderr, "\t[ -o <preference setting> ] ... [ -r <infile> ] [ -R <read filter> ]\n");
-  fprintf(stderr, "\t[ -t <time stamp format> ] [ -w <savefile> ] [ -x ]\n");
+  fprintf(stderr, "\t[ -t <time stamp format> ] [ -w <savefile> ] [ -Z <statistics string> ]\n");
 #endif
-  fprintf(stderr, "\t[ -Z <statistics string> ]\n");
   fprintf(stderr, "Valid file type arguments to the \"-F\" flag:\n");
   for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
     if (wtap_dump_can_open(i))
@@ -226,7 +255,7 @@ print_usage(gboolean print_ver)
 
 #ifdef HAVE_LIBPCAP
 static int
-get_positive_int(const char *string, const char *name)
+get_natural_int(const char *string, const char *name)
 {
   long number;
   char *p;
@@ -242,11 +271,6 @@ get_positive_int(const char *string, const char *name)
            name);
     exit(1);
   }
-  if (number == 0) {
-    fprintf(stderr, "tethereal: The specified %s is zero\n",
-           name);
-    exit(1);
-  }
   if (number > INT_MAX) {
     fprintf(stderr, "tethereal: The specified %s is too large (greater than %d)\n",
            name, INT_MAX);
@@ -255,6 +279,22 @@ get_positive_int(const char *string, const char *name)
   return number;
 }
 
+static int
+get_positive_int(const char *string, const char *name)
+{
+  long number;
+
+  number = get_natural_int(string, name);
+
+  if (number == 0) {
+    fprintf(stderr, "tethereal: The specified %s is zero\n",
+           name);
+    exit(1);
+  }
+
+  return number;
+}
+
 /*
  * Given a string of the form "<autostop criterion>:<value>", as might appear
  * as an argument to a "-a" option, parse it and set the criterion in
@@ -301,6 +341,55 @@ set_autostop_criterion(const char *autostoparg)
   *colonp = ':';       /* put the colon back */
   return TRUE;
 }
+
+/*
+ * Given a string of the form "<ring buffer file>:<duration>", as might appear
+ * as an argument to a "-b" option, parse it and set the arguments in
+ * question.  Return an indication of whether it succeeded or failed
+ * in some fashion.
+ */
+static gboolean
+get_ring_arguments(const char *arg)
+{
+  guchar *p = NULL, *colonp;
+
+  colonp = strchr(arg, ':');
+
+  if (colonp != NULL) {
+    p = colonp;
+    *p++ = '\0';
+  }
+
+  capture_opts.ringbuffer_num_files = 
+    get_natural_int(arg, "number of ring buffer files");
+
+  if (colonp == NULL)
+    return TRUE;
+
+  /*
+   * Skip over any white space (there probably won't be any, but
+   * as we allow it in the preferences file, we might as well
+   * allow it here).
+   */
+  while (isspace(*p))
+    p++;
+  if (*p == '\0') {
+    /*
+     * Put the colon back, so if our caller uses, in an
+     * error message, the string they passed us, the message
+     * looks correct.
+     */
+    *colonp = ':';
+    return FALSE;
+  }
+
+  capture_opts.has_ring_duration = TRUE;
+  capture_opts.ringbuffer_duration = get_positive_int(p,
+                                                     "ring buffer duration");
+
+  *colonp = ':';       /* put the colon back */
+  return TRUE;
+}
 #endif
 
 /* structure to keep track of what tap listeners have been registered.
@@ -313,7 +402,7 @@ typedef struct _ethereal_tap_list {
 static ethereal_tap_list *tap_list=NULL;
 
 void
-register_ethereal_tap(char *cmd, void (*func)(char *arg), char *dummy _U_, void (*dummy2)(void) _U_)
+register_ethereal_tap(char *cmd, void (*func)(char *arg))
 {
        ethereal_tap_list *newtl;
 
@@ -325,26 +414,270 @@ register_ethereal_tap(char *cmd, void (*func)(char *arg), char *dummy _U_, void
 
 }
 
+/*
+ * For a dissector table, display, on the standard error, its short name
+ * (which is what's used in the "-d" option) and its descriptive name.
+ */
+static void
+display_dissector_table_names(char *table_name, char *ui_name,
+                              gpointer user_data _U_)
+{
+  fprintf(stderr, "\t%s (%s)\n", table_name, ui_name);
+}
+
+/*
+ * For a dissector handle, display, on the standard error, the filter name
+ * (which is what's used in the "-d" option) and the full name for the
+ * protocol for the handle.
+ */
+static void
+display_dissector_names(gchar *table _U_, gpointer handle, gpointer data _U_)
+{
+  int                proto_id;
+
+  proto_id = dissector_handle_get_protocol_index((dissector_handle_t)handle);
+
+  fprintf(stderr, "\t%s (%s)\n", proto_get_protocol_filter_name(proto_id),
+          proto_get_protocol_name(proto_id));
+}
+
+/*
+ * The protocol_name_search structure is used by find_name_shortname_func()
+ * to pass parameters and store results
+ */
+struct protocol_name_search{
+  gchar              *searched_name;  /* Protocol 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 only once here.
+ */
+static void
+find_name_func(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);
+  protocol_filter_name = proto_get_protocol_filter_name(proto_id);
+  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++;
+  }
+}
+
+/*
+ * 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;
+  gchar                        *decoded_param;
+  gchar                        *remaining_param;
+  gchar                        *selector_str;
+  gchar                        *dissector_str;
+  dissector_handle_t            dissector_matching;
+  dissector_table_t             table_matching;
+  struct protocol_name_search   user_protocol_name;
+
+/* 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_malloc( sizeof(gchar) * strlen(cl_param) + 1 ); /* Allocate enough space to have a working copy of the command-line parameter */
+  g_assert(decoded_param);
+  strcpy(decoded_param, cl_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. */
+
+  table_name = decoded_param; /* Layer type string starts from beginning */
+
+  remaining_param = strchr(table_name, '=');
+  if (remaining_param == NULL) {
+    fprintf(stderr, "tethereal: Parameter \"%s\" doesn't follow the template \"%s\"\n", cl_param, decode_as_arg_template);
+    g_free(decoded_param);
+    return FALSE;
+  }
+
+  *remaining_param = '\0'; /* Terminate the layer type string (table_name) where '=' was detected */
+  
+  if (*(remaining_param + 1) != '=') { /* Check for "==" and not only '=' */
+    fprintf(stderr, "tethereal: Warning: -d requires \"==\" instead of \"=\". Option will be treated as \"%s==%s\"\n", 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 */
+
+  selector_str = remaining_param; /* Next part starts with the selector number */
+
+  /* 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 */
+
+
+  remaining_param = strchr(selector_str, ',');
+  if (remaining_param == NULL) {
+    fprintf(stderr, "tethereal: Parameter \"%s\" doesn't follow the template \"%s\"\n", cl_param, decode_as_arg_template);
+    g_free(decoded_param);
+    return FALSE;
+  }
+
+  *remaining_param = '\0'; /* Terminate the selector number string (selector_str) where ',' was detected */
+  
+  remaining_param++; /* Position after the selector number string */
+
+
+  dissector_str = remaining_param; /* All the rest of the string is the dissector (decode as protocol) name */
+
+/* The following part looks for the layer type part of the parameter */
+  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 */
+    fprintf(stderr, "tethereal: No layer type specified\n"); /* 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) {
+      fprintf(stderr, "tethereal: Unknown layer type -- %s\n", table_name); /* Note, we don't exit here, but table_matching will remain NULL, so we exit below */
+    }
+  }
+
+  if (!table_matching) {
+    fprintf(stderr, "tethereal: Valid layer types are:\n");
+    dissector_all_tables_foreach_table(display_dissector_table_names, NULL);
+
+    g_free(decoded_param); 
+    return FALSE;
+  }
+
+  switch (get_dissector_table_type(table_name)) {
+
+  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. */
+    if ( sscanf(selector_str, "%u", &selector) != 1 ) {
+      fprintf(stderr, "tethereal: Invalid selector number \"%s\"\n", selector_str);
+      g_free(decoded_param);
+      return FALSE;
+    }
+    break;
+
+  default:
+    /* There are currently no dissector tables with any types other
+       than the ones listed above, but we might, for example, have
+       string-based dissector tables at some point. */
+    g_assert_not_reached();
+  }
+
+  /* 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 */
+
+
+#ifdef DEBUG
+  fprintf(stderr, "tethereal: Debug info: table=\"%s\", selector=\"%d\", dissector=\"%s\"\n", table_name, selector, dissector_str); // For debug only!
+#endif
+
+/* The is the end of the code that parses the command-line options. All information have now been stored in the structure preference. All strings are still pointing to decoded_parm that needs to be kept in memory as long as preference is needed, and decoded_param needs to be deallocated at each exit point of this function */
+
+
+  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 */
+    fprintf(stderr, "tethereal: No protocol name specified\n"); /* 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_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) {
+        fprintf(stderr, "tethereal: Warning: Protocol \"%s\" matched %u dissectors, first one will be used\n", 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 */
+        fprintf(stderr, "tethereal: Unknown protocol -- \"%s\"\n", dissector_str);
+      } else {
+        fprintf(stderr, "tethereal: Protocol \"%s\" isn't valid for layer type \"%s\"\n",
+               dissector_str, table_name);
+      }
+    }
+  }
+
+  if (!dissector_matching) {
+    fprintf(stderr, "tethereal: Valid protocols for layer type \"%s\" are:\n", table_name);
+    dissector_table_foreach_handle(table_name, display_dissector_names, NULL);
+    g_free(decoded_param); 
+    return FALSE;
+  }
+
+  /* We now have a pointer to the handle for the requested dissector
+     (requested protocol) inside the variable dissector_matching */
+  dissector_change(table_name, selector, dissector_matching);
+  g_free(decoded_param); /* "Decode As" rule has been succesfully added */
+  return TRUE;
+}
+
 int
 main(int argc, char *argv[])
 {
   int                  opt, i;
   extern char         *optarg;
   gboolean             arg_error = FALSE;
-#ifdef HAVE_LIBPCAP
-#ifdef HAVE_PCAP_VERSION
-  extern char          pcap_version[];
-#endif /* HAVE_PCAP_VERSION */
-#endif /* HAVE_LIBPCAP */
 
-#ifdef WIN32
+#ifdef _WIN32
   WSADATA              wsaData;
-
-# ifdef HAVE_SOME_SNMP
-  char                *mib_path;
-# define MIB_PATH_APPEND "\\snmp\\mibs"
-# endif        /* HAVE_UCD_SNMP */
-#endif /* WIN32 */
+#endif /* _WIN32 */
 
   char                *gpf_path;
   char                *pf_path;
@@ -372,6 +705,9 @@ main(int argc, char *argv[])
      dissectors, and we must do it before we read the preferences, in
      case any dissectors register preferences. */
   epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs);
+
+  /* Register all tap listeners; we do this before we parse the arguments,
+     as the "-z" argument can specify a registered tap. */
   register_all_tap_listeners();
 
   /* Now register the preferences for any non-dissector modules.
@@ -420,72 +756,28 @@ main(int argc, char *argv[])
   /* Set the name resolution code's flags from the preferences. */
   g_resolv_flags = prefs->name_resolve;
 
-#ifdef WIN32
+#ifdef _WIN32
   /* Load Wpcap, if possible */
   load_wpcap();
 #endif
 
   init_cap_file(&cfile);
 
-  /* Assemble the compile-time options */
-  comp_info_str = g_string_new("");
-
-  g_string_append(comp_info_str, "with ");
-  g_string_sprintfa(comp_info_str,
-#ifdef GLIB_MAJOR_VERSION
-    "GLib %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
-    GLIB_MICRO_VERSION);
-#else
-    "GLib (version unknown)");
-#endif
-
-#ifdef HAVE_LIBPCAP
-  g_string_append(comp_info_str, ", with libpcap ");
-#ifdef HAVE_PCAP_VERSION
-  g_string_append(comp_info_str, pcap_version);
-#else /* HAVE_PCAP_VERSION */
-  g_string_append(comp_info_str, "(version unknown)");
-#endif /* HAVE_PCAP_VERSION */
-#else /* HAVE_LIBPCAP */
-  g_string_append(comp_info_str, ", without libpcap");
-#endif /* HAVE_LIBPCAP */
+  /* Assemble the compile-time version information string */
+  comp_info_str = g_string_new("Compiled ");
+  get_compiled_version_info(comp_info_str);
 
-#ifdef HAVE_LIBZ
-  g_string_append(comp_info_str, ", with libz ");
-#ifdef ZLIB_VERSION
-  g_string_append(comp_info_str, ZLIB_VERSION);
-#else /* ZLIB_VERSION */
-  g_string_append(comp_info_str, "(version unknown)");
-#endif /* ZLIB_VERSION */
-#else /* HAVE_LIBZ */
-  g_string_append(comp_info_str, ", without libz");
-#endif /* HAVE_LIBZ */
-
-/* Oh, this is pretty. */
-/* Oh, ha.  you think that was pretty.  Try this:! --Wes */
-#ifdef HAVE_SOME_SNMP
-
-#ifdef HAVE_UCD_SNMP
-  g_string_append(comp_info_str, ", with UCD-SNMP ");
-  g_string_append(comp_info_str, VersionInfo);
-#endif /* HAVE_UCD_SNMP */
-
-#ifdef HAVE_NET_SNMP
-  g_string_append(comp_info_str, ", with Net-SNMP ");
-  g_string_append(comp_info_str, netsnmp_get_version());
-#endif /* HAVE_NET_SNMP */
-
-#else /* no SNMP library */
-  g_string_append(comp_info_str, ", without UCD-SNMP or Net-SNMP");
-#endif /* HAVE_SOME_SNMP */
+  /* Assemble the run-time version information string */
+  runtime_info_str = g_string_new("Running ");
+  get_runtime_version_info(runtime_info_str);
 
   /* Now get our args */
-  while ((opt = getopt(argc, argv, "a:b:c:Df:F:hi:lnN:o:pqr:R:s:St:vw:Vxz:")) != -1) {
+  while ((opt = getopt(argc, argv, "a:b:c:d:Df:F:hi:lnN:o:pqr:R:s:St:vw:Vxz:")) != -1) {
     switch (opt) {
       case 'a':        /* autostop criteria */
 #ifdef HAVE_LIBPCAP
         if (set_autostop_criterion(optarg) == FALSE) {
-          fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
+          fprintf(stderr, "tethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
           exit(1);
         }
 #else
@@ -496,8 +788,10 @@ main(int argc, char *argv[])
       case 'b':        /* Ringbuffer option */
 #ifdef HAVE_LIBPCAP
         capture_opts.ringbuffer_on = TRUE;
-        capture_opts.ringbuffer_num_files =
-            get_positive_int(optarg, "number of ring buffer files");
+       if (get_ring_arguments(optarg) == FALSE) {
+          fprintf(stderr, "tethereal: Invalid or unknown -b arg \"%s\"\n", optarg);
+          exit(1);
+       }
 #else
         capture_option_specified = TRUE;
         arg_error = TRUE;
@@ -512,6 +806,10 @@ main(int argc, char *argv[])
         arg_error = TRUE;
 #endif
         break;
+      case 'd':        /* Decode as rule */
+        if (!add_decode_as(optarg))
+          exit(1);
+       break;
       case 'D':        /* Print a list of capture devices */
 #ifdef HAVE_LIBPCAP
         if_list = get_interface_list(&err, err_str);
@@ -659,7 +957,8 @@ main(int argc, char *argv[])
         }
         break;
       case 'v':        /* Show version and exit */
-        printf("t%s %s, %s\n", PACKAGE, VERSION, comp_info_str->str);
+        printf("t%s %s\n%s\n%s\n", PACKAGE, VERSION, comp_info_str->str,
+               runtime_info_str->str);
         exit(0);
         break;
       case 'w':        /* Write to capture file xxx */
@@ -725,7 +1024,7 @@ main(int argc, char *argv[])
   ld.output_to_pipe = FALSE;
 #endif
   if (cfile.save_file != NULL) {
-    if (!strcmp(cfile.save_file, "-")) {
+    if (strcmp(cfile.save_file, "-") == 0) {
       /* stdout */
       g_free(cfile.save_file);
       cfile.save_file = g_strdup("");
@@ -797,23 +1096,10 @@ main(int argc, char *argv[])
   }
 #endif
 
-#ifdef WIN32
+#ifdef _WIN32
   /* Start windows sockets */
   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
-
-# ifdef HAVE_SOME_SNMP
-  /* Set MIBDIRS so that the SNMP library can find its mibs. */
-  /* XXX - Should we set MIBS or MIBFILES as well? */
-
-  mib_path = g_malloc (strlen(get_datafile_dir()) + strlen(MIB_PATH_APPEND) + 20);
-  sprintf (mib_path, "MIBDIRS=%s\\%s", get_datafile_dir(), MIB_PATH_APPEND);
-  /* Amazingly enough, Windows does not provide setenv(). */
-  if (getenv("MIBDIRS") == NULL)
-    _putenv(mib_path);
-  g_free(mib_path);
-
-# endif        /* HAVE_UCD_SNMP */
-#endif /* WIN32 */
+#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
@@ -830,7 +1116,7 @@ main(int argc, char *argv[])
   }
 
   /* Build the column format array */
-  col_init(&cfile.cinfo, prefs->num_cols);
+  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));
@@ -842,7 +1128,7 @@ main(int argc, char *argv[])
       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[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
     cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
   }
@@ -953,6 +1239,8 @@ main(int argc, char *argv[])
 static int
 capture(int out_file_type)
 {
+  int         pcap_encap;
+  int         file_snaplen;
   gchar       open_err_str[PCAP_ERRBUF_SIZE];
   gchar       lookup_net_err_str[PCAP_ERRBUF_SIZE];
   bpf_u_int32 netnum, netmask;
@@ -965,9 +1253,14 @@ capture(int out_file_type)
   char        errmsg[1024+1];
   condition  *volatile cnd_stop_capturesize = NULL;
   condition  *volatile cnd_stop_timeout = NULL;
+  condition  *volatile cnd_ring_timeout = NULL;
 #ifndef _WIN32
   static const char ppamsg[] = "can't find PPA for ";
   char       *libpcap_warn;
+  volatile int pipe_fd = -1;
+  struct pcap_hdr hdr;
+  struct pcaprec_modified_hdr rechdr;
+  guchar pcap_data[WTAP_MAX_PACKET_SIZE];
 #endif
   struct pcap_stat stats;
   gboolean    write_err;
@@ -988,49 +1281,69 @@ capture(int out_file_type)
                          capture_opts.promisc_mode, 1000, open_err_str);
 
   if (ld.pch == NULL) {
-    /* Well, we couldn't start the capture. */
+    /* We couldn't open "cfile.iface" as a network device. */
 #ifdef _WIN32
+    /* On Windows, we don't support capturing on pipes, so we give up. */
+
     /* On Win32 OSes, the capture devices are probably available to all
        users; don't warn about permissions problems.
 
-       Do, however, warn that Token Ring and PPP devices aren't supported. */
+       Do, however, warn that WAN devices aren't supported. */
     snprintf(errmsg, sizeof errmsg,
        "The capture session could not be initiated (%s).\n"
        "Please check that you have the proper interface specified.\n"
        "\n"
-       "Note that the driver Tethereal uses for packet capture on Windows\n"
-       "doesn't support capturing on Token Ring interfaces, and doesn't\n"
-       "support capturing on PPP/WAN interfaces in Windows NT/2000.\n",
+       "Note that the driver Tethereal uses for packet capture on Windows doesn't\n"
+       "support capturing on PPP/WAN interfaces in Windows NT/2000/XP/.NET Server.\n",
        open_err_str);
+    goto error;
 #else
-      /* If we got a "can't find PPA for XXX" message, warn the user (who
-         is running Ethereal on HP-UX) that they don't have a version
-        of libpcap that properly handles HP-UX (libpcap 0.6.x and later
-        versions, which properly handle HP-UX, say "can't find /dev/dlpi
-        PPA for XXX" rather than "can't find PPA for XXX"). */
-      if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
-       libpcap_warn =
-         "\n\n"
-         "You are running Tethereal with a version of the libpcap library\n"
-         "that doesn't handle HP-UX network devices well; this means that\n"
-         "Tethereal may not be able to capture packets.\n"
-         "\n"
-         "To fix this, you should install libpcap 0.6.2, or a later version\n"
-         "of libpcap, rather than libpcap 0.4 or 0.5.x.  It is available in\n"
-         "packaged binary form from the Software Porting And Archive Centre\n"
-         "for HP-UX; the Centre is at http://hpux.connect.org.uk/ - the page\n"
-         "at the URL lists a number of mirror sites.";
-      else
-       libpcap_warn = "";
-    snprintf(errmsg, sizeof errmsg,
-      "The capture session could not be initiated (%s).\n"
-      "Please check to make sure you have sufficient permissions, and that\n"
-      "you have the proper interface specified.%s", open_err_str, libpcap_warn);
+    /* try to open cfile.iface as a pipe */
+    pipe_fd = pipe_open_live(cfile.iface, &hdr, &ld, errmsg, sizeof errmsg);
+
+    if (pipe_fd == -1) {
+
+      if (ld.pipe_err == PIPNEXIST) {
+       /* Pipe doesn't exist, so output message for interface */
+
+       /* If we got a "can't find PPA for XXX" message, warn the user (who
+           is running Tethereal on HP-UX) that they don't have a version
+          of libpcap that properly handles HP-UX (libpcap 0.6.x and later
+          versions, which properly handle HP-UX, say "can't find /dev/dlpi
+          PPA for XXX" rather than "can't find PPA for XXX"). */
+       if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
+         libpcap_warn =
+           "\n\n"
+           "You are running Tethereal with a version of the libpcap library\n"
+           "that doesn't handle HP-UX network devices well; this means that\n"
+           "Tethereal may not be able to capture packets.\n"
+           "\n"
+           "To fix this, you should install libpcap 0.6.2, or a later version\n"
+           "of libpcap, rather than libpcap 0.4 or 0.5.x.  It is available in\n"
+           "packaged binary form from the Software Porting And Archive Centre\n"
+           "for HP-UX; the Centre is at http://hpux.connect.org.uk/ - the page\n"
+           "at the URL lists a number of mirror sites.";
+       else
+         libpcap_warn = "";
+       snprintf(errmsg, sizeof errmsg,
+         "The capture session could not be initiated (%s).\n"
+         "Please check to make sure you have sufficient permissions, and that\n"
+         "you have the proper interface or pipe specified.%s", open_err_str,
+         libpcap_warn);
+      }
+      /*
+       * Else pipe (or file) does exist and pipe_open_live() has
+       * filled in errmsg
+       */
+      goto error;
+    } else
+      /* pipe_open_live() succeeded; don't want
+         error message from pcap_open_live() */
+      open_err_str[0] = '\0';
 #endif
-    goto error;
   }
 
-  if (cfile.cfilter) {
+  if (cfile.cfilter && !ld.from_pipe) {
     /* A capture filter was specified; set it up. */
     if (pcap_lookupnet(cfile.iface, &netnum, &netmask, lookup_net_err_str) < 0) {
       /*
@@ -1054,8 +1367,18 @@ capture(int out_file_type)
     }
   }
 
-  ld.linktype = wtap_pcap_encap_to_wtap_encap(get_pcap_linktype(ld.pch,
-       cfile.iface));
+  /* Set up to write to the capture file. */
+#ifndef _WIN32
+  if (ld.from_pipe) {
+    pcap_encap = hdr.network;
+    file_snaplen = hdr.snaplen;
+  } else
+#endif
+  {
+    pcap_encap = get_pcap_linktype(ld.pch, cfile.iface);
+    file_snaplen = pcap_snapshot(ld.pch);
+  }
+  ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_encap);
   if (cfile.save_file != NULL) {
     /* Set up to write to the capture file. */
     if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
@@ -1103,6 +1426,12 @@ capture(int out_file_type)
   signal(SIGINT, capture_cleanup);
   if ((oldhandler = signal(SIGHUP, capture_cleanup)) != SIG_DFL)
     signal(SIGHUP, oldhandler);
+
+#ifdef SIGINFO
+  /* Catch SIGINFO and, if we get it and we're capturing to a file in
+     quiet mode, report the number of packets we've captured. */
+  signal(SIGINFO, report_counts_siginfo);
+#endif /* SIGINFO */
 #endif /* _WIN32 */
 
   /* Let the user know what interface was chosen. */
@@ -1112,12 +1441,16 @@ capture(int out_file_type)
   init_capture_stop_conditions();
   /* create stop conditions */
   if (capture_opts.has_autostop_filesize)
-    cnd_stop_capturesize = cnd_new((char*)CND_CLASS_CAPTURESIZE,
+    cnd_stop_capturesize = cnd_new((const char*)CND_CLASS_CAPTURESIZE,
                                    (long)capture_opts.autostop_filesize * 1000);
   if (capture_opts.has_autostop_duration)
-    cnd_stop_timeout = cnd_new((char*)CND_CLASS_TIMEOUT,
+    cnd_stop_timeout = cnd_new((const char*)CND_CLASS_TIMEOUT,
                                (gint32)capture_opts.autostop_duration);
 
+  if (capture_opts.ringbuffer_on && capture_opts.has_ring_duration)
+    cnd_ring_timeout = cnd_new(CND_CLASS_TIMEOUT, 
+                              capture_opts.ringbuffer_duration);
+
   if (!setjmp(ld.stopenv)) {
     ld.go = TRUE;
     ld.packet_count = 0;
@@ -1182,13 +1515,29 @@ capture(int out_file_type)
          each packet. */
       pcap_cnt = 1;
     }
-    inpkts = pcap_dispatch(ld.pch, pcap_cnt, capture_pcap_cb, (guchar *) &ld);
+#ifndef _WIN32
+    if (ld.from_pipe) {
+      inpkts = pipe_dispatch(pipe_fd, &ld, &hdr, &rechdr, pcap_data,
+        errmsg, sizeof errmsg);
+    } else
+#endif
+      inpkts = pcap_dispatch(ld.pch, pcap_cnt, capture_pcap_cb, (guchar *) &ld);
     if (inpkts < 0) {
-      /* Error from "pcap_dispatch()". */
+      /* Error from "pcap_dispatch()", or error or "no more packets" from
+         "pipe_dispatch(). */
       ld.go = FALSE;
     } else if (cnd_stop_timeout != NULL && cnd_eval(cnd_stop_timeout)) {
       /* The specified capture time has elapsed; stop the capture. */
       ld.go = FALSE;
+    } else if (cnd_ring_timeout != NULL && cnd_eval(cnd_ring_timeout)) {
+      /* time elasped for this ring file, swith to the next */
+      if (ringbuf_switch_file(&cfile, &ld.pdh, &loop_err)) {
+       /* File switch succeeded: reset the condition */
+       cnd_reset(cnd_ring_timeout);
+      } else {
+       /* File switch failed: stop here */
+       ld.go = FALSE;
+      }
     } else if (inpkts > 0) {
       if (capture_opts.autostop_count != 0 &&
                  ld.packet_count >= capture_opts.autostop_count) {
@@ -1206,6 +1555,9 @@ capture(int out_file_type)
           if (ringbuf_switch_file(&cfile, &ld.pdh, &loop_err)) {
             /* File switch succeeded: reset the condition */
             cnd_reset(cnd_stop_capturesize);
+           if (cnd_ring_timeout) {
+             cnd_reset(cnd_ring_timeout);
+           }
           } else {
             /* File switch failed: stop here */
             volatile_err = loop_err;
@@ -1233,6 +1585,8 @@ capture(int out_file_type)
     cnd_delete(cnd_stop_capturesize);
   if (cnd_stop_timeout != NULL)
     cnd_delete(cnd_stop_timeout);
+  if (cnd_ring_timeout != NULL)
+    cnd_delete(cnd_ring_timeout);
 
   if ((cfile.save_file != NULL) && !quiet) {
     /* We're saving to a file, which means we're printing packet counts
@@ -1243,8 +1597,18 @@ capture(int out_file_type)
 
   /* If we got an error while capturing, report it. */
   if (inpkts < 0) {
-    fprintf(stderr, "tethereal: Error while capturing packets: %s\n",
-       pcap_geterr(ld.pch));
+#ifndef _WIN32
+    if (ld.from_pipe) {
+      if (ld.pipe_err == PIPERR) {
+        fprintf(stderr, "tethereal: Error while capturing packets: %s\n",
+         errmsg);
+      }
+    } else
+#endif
+    {
+      fprintf(stderr, "tethereal: Error while capturing packets: %s\n",
+         pcap_geterr(ld.pch));
+    }
   }
 
   if (volatile_err == 0)
@@ -1267,23 +1631,28 @@ capture(int out_file_type)
       show_capture_file_io_error(cfile.save_file, err, TRUE);
   }
 
-  /* Get the capture statistics, and, if any packets were dropped, report
-     that. */
-  if (pcap_stats(ld.pch, &stats) >= 0) {
-    if (stats.ps_drop != 0) {
-      fprintf(stderr, "%u packets dropped\n", stats.ps_drop);
+#ifndef _WIN32
+  if (ld.from_pipe && pipe_fd >= 0)
+    close(pipe_fd);
+  else
+#endif
+  {
+    /* Get the capture statistics, and, if any packets were dropped, report
+       that. */
+    if (pcap_stats(ld.pch, &stats) >= 0) {
+      if (stats.ps_drop != 0) {
+        fprintf(stderr, "%u packets dropped\n", stats.ps_drop);
+      }
+    } else {
+      fprintf(stderr, "tethereal: Can't get packet-drop statistics: %s\n",
+         pcap_geterr(ld.pch));
     }
-  } else {
-    fprintf(stderr, "tethereal: Can't get packet-drop statistics: %s\n",
-       pcap_geterr(ld.pch));
+    pcap_close(ld.pch);
   }
+
   /* Report the number of captured packets if not reported during capture
      and we are saving to a file. */
-  if (quiet && (cfile.save_file != NULL)) {
-    fprintf(stderr, "%u packets captured\n", ld.packet_count);
-  }
-
-  pcap_close(ld.pch);
+  report_counts();
 
   return TRUE;
 
@@ -1294,8 +1663,16 @@ error:
   g_free(cfile.save_file);
   cfile.save_file = NULL;
   fprintf(stderr, "tethereal: %s\n", errmsg);
+#ifndef _WIN32
+  if (ld.from_pipe) {
+    if (pipe_fd >= 0)
+      close(pipe_fd);
+  } else
+#endif
+  {
   if (ld.pch != NULL)
     pcap_close(ld.pch);
+  }
 
   return FALSE;
 }
@@ -1381,6 +1758,43 @@ capture_cleanup(int signum _U_)
   longjmp(ld.stopenv, 1);
 }
 #endif /* _WIN32 */
+
+static void
+report_counts(void)
+{
+#ifdef SIGINFO
+  /* XXX - if we use sigaction, this doesn't have to be done.
+     (Yes, this isn't necessary on BSD, but just in case a system
+     where "signal()" has AT&T semantics adopts SIGINFO....) */
+  signal(SIGINFO, report_counts_siginfo);
+#endif /* SIGINFO */
+
+  if (cfile.save_file != NULL && quiet) {
+    /* Report the count only if we're capturing to a file (rather
+       than printing captured packet information out) and aren't
+       updating a count as packets arrive. */
+    fprintf(stderr, "%u packets captured\n", ld.packet_count);
+  }
+#ifdef SIGINFO
+  infoprint = FALSE;   /* we just reported it */
+#endif /* SIGINFO */
+}
+
+#ifdef SIGINFO
+static void
+report_counts_siginfo(int signum _U_)
+{
+  int sav_errno = errno;
+  /* If we've been told to delay printing, just set a flag asking
+     that we print counts (if we're supposed to), otherwise print
+     the count of packets captured (if we're supposed to). */
+  if (infodelay)
+    infoprint = TRUE;
+  else
+    report_counts();
+  errno = sav_errno;
+}
+#endif /* SIGINFO */
 #endif /* HAVE_LIBPCAP */
 
 static int
@@ -1577,6 +1991,17 @@ wtap_dispatch_cb_write(guchar *user, const struct wtap_pkthdr *phdr,
   gboolean      passed;
   epan_dissect_t *edt;
 
+#ifdef HAVE_LIBPCAP
+#ifdef SIGINFO
+  /*
+   * Prevent a SIGINFO handler from writing to stdout while we're
+   * doing so; instead, have it just set a flag telling us to print
+   * that information when we're done.
+   */
+  infodelay = TRUE;
+#endif /* SIGINFO */
+#endif /* HAVE_LIBPCAP */
+
   cf->count++;
   if (cf->rfcode) {
     fill_in_fdata(&fdata, cf, phdr, offset);
@@ -1614,6 +2039,21 @@ wtap_dispatch_cb_write(guchar *user, const struct wtap_pkthdr *phdr,
     epan_dissect_free(edt);
   if (cf->rfcode)
     clear_fdata(&fdata);
+
+#ifdef HAVE_LIBPCAP
+#ifdef SIGINFO
+  /*
+   * Allow SIGINFO handlers to write.
+   */
+  infodelay = FALSE;
+
+  /*
+   * If a SIGINFO handler asked us to write out capture counts, do so.
+   */
+  if (infoprint)
+    report_counts();
+#endif /* SIGINFO */
+#endif /* HAVE_LIBPCAP */
 }
 
 static void
@@ -1683,6 +2123,11 @@ wtap_dispatch_cb_print(guchar *user, const struct wtap_pkthdr *phdr,
 
   fill_in_fdata(&fdata, cf, phdr, offset);
 
+  /* Grab any resolved addresses */
+  if (g_resolv_flags) {
+    host_name_lookup_process(NULL);
+  }
+
   passed = TRUE;
   if (cf->rfcode || verbose || num_tap_filters!=0)
     create_proto_tree = TRUE;
@@ -2088,3 +2533,291 @@ fail:
   fprintf(stderr, "tethereal: %s\n", err_msg);
   return (err);
 }
+
+#ifdef HAVE_LIBPCAP
+#ifndef _WIN32
+/* Take care of byte order in the libpcap headers read from pipes.
+ * (function taken from wiretap/libpcap.c) */
+static void
+adjust_header(loop_data *ld, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr)
+{
+  if (ld->byte_swapped) {
+    /* Byte-swap the record header fields. */
+    rechdr->ts_sec = BSWAP32(rechdr->ts_sec);
+    rechdr->ts_usec = BSWAP32(rechdr->ts_usec);
+    rechdr->incl_len = BSWAP32(rechdr->incl_len);
+    rechdr->orig_len = BSWAP32(rechdr->orig_len);
+  }
+
+  /* In file format version 2.3, the "incl_len" and "orig_len" fields were
+     swapped, in order to match the BPF header layout.
+
+     Unfortunately, some files were, according to a comment in the "libpcap"
+     source, written with version 2.3 in their headers but without the
+     interchanged fields, so if "incl_len" is greater than "orig_len" - which
+     would make no sense - we assume that we need to swap them.  */
+  if (hdr->version_major == 2 &&
+      (hdr->version_minor < 3 ||
+       (hdr->version_minor == 3 && rechdr->incl_len > rechdr->orig_len))) {
+    guint32 temp;
+
+    temp = rechdr->orig_len;
+    rechdr->orig_len = rechdr->incl_len;
+    rechdr->incl_len = temp;
+  }
+}
+
+/* Mimic pcap_open_live() for pipe captures
+ * We check if "pipename" is "-" (stdin) or a FIFO, open it, and read the
+ * header.
+ * N.B. : we can't read the libpcap formats used in RedHat 6.1 or SuSE 6.3
+ * because we can't seek on pipes (see wiretap/libpcap.c for details) */
+static int
+pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
+                 char *errmsg, int errmsgl)
+{
+  struct stat pipe_stat;
+  int         fd;
+  guint32     magic;
+  int         b;
+  unsigned int bytes_read;
+
+  /*
+   * XXX Tethereal blocks until we return
+   */
+  if (strcmp(pipename, "-") == 0)
+    fd = 0; /* read from stdin */
+  else {
+    if (stat(pipename, &pipe_stat) < 0) {
+      if (errno == ENOENT || errno == ENOTDIR)
+        ld->pipe_err = PIPNEXIST;
+      else {
+        snprintf(errmsg, errmsgl,
+          "The capture session could not be initiated "
+          "due to error on pipe: %s", strerror(errno));
+        ld->pipe_err = PIPERR;
+      }
+      return -1;
+    }
+    if (! S_ISFIFO(pipe_stat.st_mode)) {
+      if (S_ISCHR(pipe_stat.st_mode)) {
+        /*
+         * Assume the user specified an interface on a system where
+         * interfaces are in /dev.  Pretend we haven't seen it.
+         */
+         ld->pipe_err = PIPNEXIST;
+      } else {
+        snprintf(errmsg, errmsgl,
+            "The capture session could not be initiated because\n"
+            "\"%s\" is neither an interface nor a pipe", pipename);
+        ld->pipe_err = PIPERR;
+      }
+      return -1;
+    }
+    fd = open(pipename, O_RDONLY);
+    if (fd == -1) {
+      snprintf(errmsg, errmsgl,
+          "The capture session could not be initiated "
+          "due to error on pipe open: %s", strerror(errno));
+      ld->pipe_err = PIPERR;
+      return -1;
+    }
+  }
+
+  ld->from_pipe = TRUE;
+
+  /* read the pcap header */
+  bytes_read = 0;
+  while (bytes_read < sizeof magic) {
+    b = read(fd, ((char *)&magic)+bytes_read, sizeof magic-bytes_read);
+    if (b <= 0) {
+      if (b == 0)
+        snprintf(errmsg, errmsgl, "End of file on pipe during open");
+      else
+        snprintf(errmsg, errmsgl, "Error on pipe during open: %s",
+          strerror(errno));
+      goto error;
+    }
+    bytes_read += b;
+  }
+
+  switch (magic) {
+  case PCAP_MAGIC:
+    /* Host that wrote it has our byte order, and was running
+       a program using either standard or ss990417 libpcap. */
+    ld->byte_swapped = FALSE;
+    ld->modified = FALSE;
+    break;
+  case PCAP_MODIFIED_MAGIC:
+    /* Host that wrote it has our byte order, but was running
+       a program using either ss990915 or ss991029 libpcap. */
+    ld->byte_swapped = FALSE;
+    ld->modified = TRUE;
+    break;
+  case PCAP_SWAPPED_MAGIC:
+    /* Host that wrote it has a byte order opposite to ours,
+       and was running a program using either standard or
+       ss990417 libpcap. */
+    ld->byte_swapped = TRUE;
+    ld->modified = FALSE;
+    break;
+  case PCAP_SWAPPED_MODIFIED_MAGIC:
+    /* Host that wrote it out has a byte order opposite to
+       ours, and was running a program using either ss990915
+       or ss991029 libpcap. */
+    ld->byte_swapped = TRUE;
+    ld->modified = TRUE;
+    break;
+  default:
+    /* Not a "libpcap" type we know about. */
+    snprintf(errmsg, errmsgl, "Unrecognized libpcap format");
+    goto error;
+  }
+
+  /* Read the rest of the header */
+  bytes_read = 0;
+  while (bytes_read < sizeof(struct pcap_hdr)) {
+    b = read(fd, ((char *)hdr)+bytes_read,
+          sizeof(struct pcap_hdr) - bytes_read);
+    if (b <= 0) {
+      if (b == 0)
+        snprintf(errmsg, errmsgl, "End of file on pipe during open");
+      else
+        snprintf(errmsg, errmsgl, "Error on pipe during open: %s",
+          strerror(errno));
+      goto error;
+    }
+    bytes_read += b;
+  }
+
+  if (ld->byte_swapped) {
+    /* Byte-swap the header fields about which we care. */
+    hdr->version_major = BSWAP16(hdr->version_major);
+    hdr->version_minor = BSWAP16(hdr->version_minor);
+    hdr->snaplen = BSWAP32(hdr->snaplen);
+    hdr->network = BSWAP32(hdr->network);
+  }
+
+  if (hdr->version_major < 2) {
+    snprintf(errmsg, errmsgl, "Unable to read old libpcap format");
+    goto error;
+  }
+
+  ld->pipe_state = STATE_EXPECT_REC_HDR;
+  ld->pipe_err = PIPOK;
+  return fd;
+
+error:
+  ld->pipe_err = PIPERR;
+  close(fd);
+  return -1;
+
+}
+/* We read one record from the pipe, take care of byte order in the record
+ * header, write the record in the capture file, and update capture statistics. */
+
+static int
+pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
+                struct pcaprec_modified_hdr *rechdr, guchar *data,
+                char *errmsg, int errmsgl)
+{
+  struct pcap_pkthdr phdr;
+  int b;
+  enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR,
+          PD_ERR } result;
+
+  switch (ld->pipe_state) {
+
+  case STATE_EXPECT_REC_HDR:
+    ld->bytes_to_read = ld->modified ?
+      sizeof(struct pcaprec_modified_hdr) : sizeof(struct pcaprec_hdr);
+    ld->bytes_read = 0;
+    ld->pipe_state = STATE_READ_REC_HDR;
+    /* Fall through */
+
+  case STATE_READ_REC_HDR:
+    b = read(fd, ((char *)rechdr)+ld->bytes_read,
+      ld->bytes_to_read - ld->bytes_read);
+    if (b <= 0) {
+      if (b == 0)
+        result = PD_PIPE_EOF;
+      else
+        result = PD_PIPE_ERR;
+      break;
+    }
+    if ((ld->bytes_read += b) < ld->bytes_to_read)
+        return 0;
+    result = PD_REC_HDR_READ;
+    break;
+
+  case STATE_EXPECT_DATA:
+    ld->bytes_read = 0;
+    ld->pipe_state = STATE_READ_DATA;
+    /* Fall through */
+
+  case STATE_READ_DATA:
+    b = read(fd, data+ld->bytes_read, rechdr->hdr.incl_len - ld->bytes_read);
+    if (b <= 0) {
+      if (b == 0)
+        result = PD_PIPE_EOF;
+      else
+        result = PD_PIPE_ERR;
+      break;
+    }
+    if ((ld->bytes_read += b) < rechdr->hdr.incl_len)
+      return 0;
+    result = PD_DATA_READ;
+    break;
+
+  default:
+    snprintf(errmsg, errmsgl, "pipe_dispatch: invalid state");
+    result = PD_ERR;
+
+  } /* switch (ld->pipe_state) */
+
+  /*
+   * We've now read as much data as we were expecting, so process it.
+   */
+  switch (result) {
+
+  case PD_REC_HDR_READ:
+    /* We've read the header. Take care of byte order. */
+    adjust_header(ld, hdr, &rechdr->hdr);
+    if (rechdr->hdr.incl_len > WTAP_MAX_PACKET_SIZE) {
+      snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)",
+        ld->packet_count+1, rechdr->hdr.incl_len);
+      break;
+    }
+    ld->pipe_state = STATE_EXPECT_DATA;
+    return 0;
+
+  case PD_DATA_READ:
+    /* Fill in a "struct pcap_pkthdr", and process the packet. */
+    phdr.ts.tv_sec = rechdr->hdr.ts_sec;
+    phdr.ts.tv_usec = rechdr->hdr.ts_usec;
+    phdr.caplen = rechdr->hdr.incl_len;
+    phdr.len = rechdr->hdr.orig_len;
+
+    capture_pcap_cb((guchar *)ld, &phdr, data);
+
+    ld->pipe_state = STATE_EXPECT_REC_HDR;
+    return 1;
+
+  case PD_PIPE_EOF:
+    ld->pipe_err = PIPEOF;
+    return -1;
+
+  case PD_PIPE_ERR:
+    snprintf(errmsg, errmsgl, "Error reading from pipe: %s",
+      strerror(errno));
+    /* Fall through */
+  case PD_ERR:
+    break;
+  }
+
+  ld->pipe_err = PIPERR;
+  /* Return here rather than inside the switch to prevent GCC warning */
+  return -1;
+}
+#endif /* _WIN32 */
+#endif /* HAVE_LIBPCAP */