put some exchange tracking info in scsi CDBs and DATA pdus
[metze/wireshark/wip.git] / tethereal.c
index d016dc823f7f7927e2208885a73aa0941bd94dd6..b2fb7a091303681be6dd3d35a01fc438b3c58bd9 100644 (file)
@@ -62,6 +62,7 @@
 #include <glib.h>
 #include <epan/epan.h>
 #include <epan/filesystem.h>
+#include <epan/privileges.h>
 #include <wiretap/file_util.h>
 
 #include "globals.h"
@@ -75,6 +76,7 @@
 #include <epan/addr_resolv.h>
 #include "util.h"
 #include "clopts_common.h"
+#include "cmdarg_err.h"
 #include "version_info.h"
 #include <epan/conversation.h>
 #include <epan/plugins.h>
 #include <epan/tap.h>
 #include <epan/stat_cmd_args.h>
 #include <epan/timestamp.h>
+#include <epan/ex-opt.h>
 
 #ifdef HAVE_LIBPCAP
 #include <pcap.h>
 #include <setjmp.h>
-#include "pcap-util.h"
+#include "capture-pcap-util.h"
+#include "pcapio.h"
 #include <wiretap/wtap-capture.h>
-#include <wiretap/libpcap.h>
 #ifdef _WIN32
 #include "capture-wpcap.h"
 #include "capture_errs.h"
 #endif /* _WIN32 */
 #include "capture.h"
+#include "capture_loop.h"
+#include "capture_sync.h"
 #endif /* HAVE_LIBPCAP */
 #include "epan/emem.h"
+#include "log.h"
+#include <epan/funnel.h>
 
 /*
  * This is the template for the decode as option; it is shared between the
@@ -130,33 +137,18 @@ static guint32 cum_bytes = 0;
 static print_format_e print_format = PR_FMT_TEXT;
 static print_stream_t *print_stream;
 
+/*
+ * Standard secondary message for unexpected errors.
+ */
+static const char please_report[] =
+    "Please report this to the Ethereal developers";
+
 #ifdef HAVE_LIBPCAP
 /*
  * TRUE if we're to print packet counts to keep track of captured packets.
  */
 static gboolean print_packet_counts;
 
-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;
-  char          *save_file;    /* Name of file to which we're writing */
-  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;
 
@@ -171,7 +163,7 @@ static gboolean infoprint;  /* if TRUE, print capture info after clearing infodel
 #endif /* HAVE_LIBPCAP */
 
 
-static int capture(char *, int);
+static int capture(void);
 static void capture_pcap_cb(u_char *, const struct pcap_pkthdr *,
   const u_char *);
 static void report_counts(void);
@@ -186,9 +178,9 @@ static void report_counts_siginfo(int);
 #endif /* HAVE_LIBPCAP */
 
 static int load_cap_file(capture_file *, char *, int);
-static gboolean process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
+static gboolean process_packet(capture_file *cf, long offset,
     const struct wtap_pkthdr *whdr, union wtap_pseudo_header *pseudo_header,
-    const guchar *pd, int *err);
+    const guchar *pd);
 static void show_capture_file_io_error(const char *, int, gboolean);
 static void show_print_file_io_error(int err);
 static gboolean write_preamble(capture_file *cf);
@@ -196,14 +188,6 @@ static gboolean print_packet(capture_file *cf, epan_dissect_t *edt);
 static gboolean write_finale(void);
 static const char *cf_open_error_message(int err, gchar *err_info,
     gboolean for_writing, int file_type);
-#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
 
 static void open_failure_message(const char *filename, int err,
     gboolean for_writing);
@@ -213,48 +197,95 @@ static void read_failure_message(const char *filename, int err);
 capture_file cfile;
 
 
+static void list_capture_types(void) {
+    int i;
+
+    fprintf(stderr, "editcap: The available capture file types for \"F\":\n");
+    for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
+      if (wtap_dump_can_open(i))
+        fprintf(stderr, "    %s - %s\n",
+          wtap_file_type_short_string(i), wtap_file_type_string(i));
+    }
+}
+
 static void
 print_usage(gboolean print_ver)
 {
-  int i;
   FILE *output;
 
   if (print_ver) {
     output = stdout;
-    fprintf(output, "This is t" PACKAGE " " VERSION "%s"
-        "\n (C) 1998-2005 Gerald Combs <gerald@ethereal.com>"
-       "\n%s\n%s\n",
-
-       svnversion, comp_info_str->str, runtime_info_str->str);
+    fprintf(output, 
+        "Tethereal " VERSION "%s\n"
+        "Dump and analyze network traffic.\n"
+        "See http://www.ethereal.com for more information.\n"
+        "\n"
+        "%s",
+       svnversion, get_copyright_info());
   } else {
     output = stderr;
   }
+  fprintf(output, "\n");
+  fprintf(output, "Usage: tethereal [options] ...\n");
+  fprintf(output, "\n");
+
 #ifdef HAVE_LIBPCAP
-  fprintf(output, "\nt%s [ -vh ] [ -DlLnpqSVx ] [ -a <capture autostop condition> ] ...\n",
-         PACKAGE);
-  fprintf(output, "\t[ -b <capture ring buffer option> ] ... [ -c <capture packet count> ]\n");
-  fprintf(output, "\t[ -d %s ] ...\n", decode_as_arg_template);
-  fprintf(output, "\t[ -f <capture filter> ] [ -F <output file type> ]\n");
-  fprintf(output, "\t[ -i <capture interface> ] [ -N <name resolving flags> ]\n");
-  fprintf(output, "\t[ -o <preference setting> ] ... [ -r <infile> ]\n");
-  fprintf(output, "\t[ -R <read (display) filter> ] [ -s <capture snaplen> ]\n");
-  fprintf(output, "\t[ -t <time stamp format> ] [ -T pdml|ps|psml|text ]\n");
-  fprintf(output, "\t[ -w <savefile> ] [ -y <capture link type> ] [ -z <statistics> ]\n");
-#else
-  fprintf(output, "\nt%s [ -vh ] [ -lnVx ]\n", PACKAGE);
-  fprintf(output, "\t[ -d %s ] ...\n", decode_as_arg_template);
-  fprintf(output, "\t[ -F <output file type> ] [ -N <name resolving flags> ]\n");
-  fprintf(output, "\t[ -o <preference setting> ] ... [ -r <infile> ]\n");
-  fprintf(output, "\t[ -R <read (display) filter> ] \t[ -t <time stamp format> ]\n");
-  fprintf(output, "\t[ -T pdml|ps|psml|text ] [ -w <savefile> ] [ -z <statistics ]\n");
+  fprintf(output, "Capture interface:\n");
+  fprintf(output, "  -i <interface>           name or idx of interface (def: first none loopback)\n");
+  fprintf(output, "  -f <capture filter>      packet filter in libpcap filter syntax\n");
+  fprintf(output, "  -s <snaplen>             packet snapshot length (def: 65535)\n");
+  fprintf(output, "  -p                       don't capture in promiscuous mode\n");
+#ifdef _WIN32
+  fprintf(output, "  -B <buffer size>         size of kernel buffer (def: 1MB)\n");
 #endif
-  fprintf(output, "Valid file type arguments to the \"-F\" flag:\n");
-  for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
-    if (wtap_dump_can_open(i))
-      fprintf(output, "\t%s - %s\n",
-        wtap_file_type_short_string(i), wtap_file_type_string(i));
-  }
-  fprintf(output, "\tdefault is libpcap\n");
+  fprintf(output, "  -y <link type>           link layer type (def: first appropriate)\n");
+  fprintf(output, "  -D                       print list of interfaces and exit\n");
+  fprintf(output, "  -L                       print list of link-layer types of iface and exit\n");
+  fprintf(output, "\n");
+  fprintf(output, "Capture stop conditions:\n");
+  fprintf(output, "  -c <packet count>        stop after n packets (def: infinite)\n");
+  fprintf(output, "  -a <autostop cond.> ...  duration:NUM - stop after NUM seconds\n");
+  fprintf(output, "                           filesize:NUM - stop this file after NUM KB\n");
+  fprintf(output, "                              files:NUM - stop after NUM files\n");
+  /*fprintf(output, "\n");*/
+  fprintf(output, "Capture output:\n");
+  fprintf(output, "  -b <ringbuffer opt.> ... duration:NUM - switch to next file after NUM secs\n");
+  fprintf(output, "                           filesize:NUM - switch to next file after NUM KB\n");
+  fprintf(output, "                              files:NUM - ringbuffer: replace after NUM files\n");
+#endif  /* HAVE_LIBPCAP */
+
+  /*fprintf(output, "\n");*/
+  fprintf(output, "Input file:\n");
+  fprintf(output, "  -r <infile>              set the filename to read from (no pipes or stdin!)\n");
+
+  fprintf(output, "\n");
+  fprintf(output, "Processing:\n");
+  fprintf(output, "  -R <read filter>         packet filter in Ethereal display filter syntax\n");
+  fprintf(output, "  -n                       disable all name resolutions (def: all enabled)\n");
+  fprintf(output, "  -N <name resolve flags>  enable specific name resolution(s): \"mntC\"\n");
+  fprintf(output, "  -d %s ...\n", decode_as_arg_template);
+  fprintf(output, "                           \"Decode As\", see the man page for details\n");
+  fprintf(output, "                           Example: tcp.port==8888,http\n");
+
+  /*fprintf(output, "\n");*/
+  fprintf(output, "Output:\n");
+  fprintf(stderr, "  -w <outfile|->           set the output filename (or '-' for stdout)\n");
+  fprintf(stderr, "  -F <output file type>    set the output file type, default is libpcap\n");
+  fprintf(stderr, "                           an empty \"-F\" option will list the file types\n");
+  fprintf(output, "  -V                       add output of packet tree        (Packet Details)\n");
+  fprintf(output, "  -x                       add output of hex and ASCII dump (Packet Bytes)\n");
+  fprintf(output, "  -T pdml|ps|psml|text     output format of text output (def: text)\n");
+  fprintf(output, "  -t ad|a|r|d              output format of time stamps (def: r: rel. to first)\n");
+  fprintf(output, "  -l                       flush output after each packet\n");
+  fprintf(output, "  -q                       be more quiet on stdout (e.g. when using statistics)\n");
+  fprintf(output, "  -X <key>:<value>         eXtension options, see the man page for details\n");
+  fprintf(output, "  -z <statistics>          various statistics, see the man page for details\n");
+
+  fprintf(output, "\n");
+  fprintf(stderr, "Miscellaneous:\n");
+  fprintf(stderr, "  -h                       display this help and exit\n");
+  fprintf(stderr, "  -v                       display version info and exit\n");
+  fprintf(output, "  -o <name>:<value> ...   override preference setting\n");
 }
 
 /*
@@ -409,7 +440,7 @@ add_decode_as(const gchar *cl_param)
 
   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);
+    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 */
@@ -429,19 +460,19 @@ add_decode_as(const gchar *cl_param)
 
 /* 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 */
+    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) {
-      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 */
+      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 */
-    fprintf(stderr, "tethereal: Valid layer types are:\n");
+    cmdarg_err("Valid layer types are:");
     fprint_all_layer_types(stderr);
   }
   if (remaining_param == NULL || !table_matching) {
@@ -452,7 +483,7 @@ add_decode_as(const gchar *cl_param)
   }
   
   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);
+    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 '=' */
@@ -466,7 +497,7 @@ add_decode_as(const gchar *cl_param)
 
   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);
+    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 */
@@ -487,7 +518,7 @@ add_decode_as(const gchar *cl_param)
        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);
+      cmdarg_err("Invalid selector number \"%s\"", selector_str);
       g_free(decoded_param);
       return FALSE;
     }
@@ -506,7 +537,7 @@ add_decode_as(const gchar *cl_param)
 
   if (remaining_param == NULL) {
     /* Exit if no ',' separator was found (see above) */
-    fprintf(stderr, "tethereal: Valid protocols for layer type \"%s\" are:\n", table_name);
+    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;
@@ -528,7 +559,7 @@ add_decode_as(const gchar *cl_param)
   
   /* 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 */
+    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;
@@ -540,7 +571,7 @@ add_decode_as(const gchar *cl_param)
     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);
+        cmdarg_err("WARNING: Protocol \"%s\" matched %u dissectors, first one will be used", dissector_str, user_protocol_name.nb_match);
       }
     }
     else {
@@ -551,16 +582,16 @@ add_decode_as(const gchar *cl_param)
          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);
+        cmdarg_err("Unknown protocol -- \"%s\"", dissector_str);
       } else {
-        fprintf(stderr, "tethereal: Protocol \"%s\" isn't valid for layer type \"%s\"\n",
+        cmdarg_err("Protocol \"%s\" isn't valid for layer type \"%s\"",
                dissector_str, table_name);
       }
     }
   }
 
   if (!dissector_matching) {
-    fprintf(stderr, "tethereal: Valid protocols for layer type \"%s\" are:\n", table_name);
+    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;
@@ -604,6 +635,28 @@ add_decode_as(const gchar *cl_param)
   return TRUE;
 }
 
+static void
+log_func_ignore (const gchar *log_domain _U_, GLogLevelFlags log_level _U_,
+    const gchar *message _U_, gpointer user_data _U_)
+{
+}
+
+static char *
+output_file_description(const char *fname)
+{
+  char *save_file_string;
+
+  /* Get a string that describes what we're writing to */
+  if (strcmp(fname, "-") == 0) {
+    /* We're writing to the standard output */
+    save_file_string = g_strdup("standard output");
+  } else {
+    /* We're writing to a file with the name in save_file */
+    save_file_string = g_strdup_printf("file \"%s\"", fname);
+  }
+  return save_file_string;
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -624,37 +677,64 @@ main(int argc, char *argv[])
   int                  err;
 #ifdef HAVE_LIBPCAP
   gboolean             capture_filter_specified = FALSE;
-  GList               *if_list, *if_entry;
-  if_info_t           *if_info;
-  long                 adapter_index;
-  char                *p;
-  gchar                err_str[PCAP_ERRBUF_SIZE];
-  gchar               *cant_get_if_list_errstr;
   gboolean             list_link_layer_types = FALSE;
+  gboolean             start_capture = FALSE;
 #else
   gboolean             capture_option_specified = FALSE;
 #endif
   gboolean             quiet = FALSE;
-  gchar               *save_file = NULL;
   int                  out_file_type = WTAP_FILE_PCAP;
   gchar               *cf_name = NULL, *rfilter = NULL;
-#ifdef HAVE_LIBPCAP
-  gboolean             start_capture = FALSE;
-  gchar               *if_text;
-  GList               *lt_list, *lt_entry;
-  data_link_info_t    *data_link_info;
-#endif
 #ifdef HAVE_PCAP_OPEN_DEAD
   struct bpf_program   fcode;
 #endif
   dfilter_t           *rfcode = NULL;
   e_prefs             *prefs;
   char                 badopt;
+  GLogLevelFlags       log_flags;
+  int                  status;
+
+#define OPTSTRING_INIT "a:b:c:d:Df:F:hi:lLnN:o:pqr:R:s:St:T:vVw:xX:y:z:"
+#ifdef HAVE_LIBPCAP
+#ifdef _WIN32
+#define OPTSTRING_WIN32 "B:"
+#else
+#define OPTSTRING_WIN32 ""
+#endif  /* _WIN32 */
+#else
+#define OPTSTRING_WIN32 ""
+#endif  /* HAVE_LIBPCAP */
+
+  static const char    optstring[] = OPTSTRING_INIT OPTSTRING_WIN32;
+
+  /*
+   * Get credential information for later use.
+   */
+  get_credential_info();
+
+  /* nothing more than the standard GLib handler, but without a warning */
+  log_flags = 
+                   G_LOG_LEVEL_ERROR|
+                   G_LOG_LEVEL_CRITICAL|
+                   G_LOG_LEVEL_WARNING|
+                   G_LOG_LEVEL_MESSAGE|
+                   G_LOG_LEVEL_INFO|
+                   G_LOG_LEVEL_DEBUG|
+                   G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
+
+  g_log_set_handler(NULL,
+                   log_flags,
+                   log_func_ignore, NULL /* user_data */);
+  g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
+                   log_flags,
+                   log_func_ignore, NULL /* user_data */);
 
   /* initialize memory allocation subsystem */
   ep_init_chunk();
   se_init_chunk();
   
+  initialize_funnel_ops();
+  
 #ifdef HAVE_LIBPCAP
   capture_opts_init(&capture_opts, NULL /* cfile */);
 #endif
@@ -673,8 +753,8 @@ main(int argc, char *argv[])
      as the "-z" argument can specify a registered tap. */
   
   /* we register the plugin taps before the other taps because
-         stats_tree taps plugins will be registered as tap listeners
-         by stats_tree_stat.c and need to registered before that */
+     stats_tree taps plugins will be registered as tap listeners
+     by stats_tree_stat.c and need to registered before that */
 #ifdef HAVE_PLUGINS
   register_all_plugin_tap_listeners();
 #endif
@@ -689,9 +769,38 @@ main(int argc, char *argv[])
      for backwards compatibility we dump out a glossary of display
      filter symbols.
 
-     We do this here to mirror what happens in the GTK+ version, although
-     it's not necessary here. */
-  handle_dashG_option(argc, argv, "tethereal");
+     XXX - we do this here, for now, to support "-G" with no arguments.
+     If none of our build or other processes uses "-G" with no arguments,
+     we can just process it with the other arguments. */
+  if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
+    if (argc == 2)
+      proto_registrar_dump_fields(1);
+    else {
+      if (strcmp(argv[2], "fields") == 0)
+        proto_registrar_dump_fields(1);
+      else if (strcmp(argv[2], "fields2") == 0)
+        proto_registrar_dump_fields(2);
+      else if (strcmp(argv[2], "fields3") == 0)
+        proto_registrar_dump_fields(3);
+      else if (strcmp(argv[2], "protocols") == 0)
+        proto_registrar_dump_protocols();
+      else if (strcmp(argv[2], "values") == 0)
+        proto_registrar_dump_values();
+      else if (strcmp(argv[2], "decodes") == 0)
+        dissector_dump_decodes();
+      else if (strcmp(argv[2], "defaultprefs") == 0)
+        write_prefs(NULL);
+      else if (strcmp(argv[2], "currentprefs") == 0) {
+        read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
+            &pf_open_errno, &pf_read_errno, &pf_path);
+        write_prefs(NULL);
+      } else {
+        cmdarg_err("Invalid \"%s\" option for -G flag", argv[2]);
+        exit(1);
+      }
+    }
+    exit(0);
+  }
 
   /* Set the C-language locale to the native environment. */
   setlocale(LC_ALL, "");
@@ -700,21 +809,21 @@ main(int argc, char *argv[])
                      &pf_open_errno, &pf_read_errno, &pf_path);
   if (gpf_path != NULL) {
     if (gpf_open_errno != 0) {
-      fprintf(stderr, "Can't open global preferences file \"%s\": %s.\n",
+      cmdarg_err("Can't open global preferences file \"%s\": %s.",
               pf_path, strerror(gpf_open_errno));
     }
     if (gpf_read_errno != 0) {
-      fprintf(stderr, "I/O error reading global preferences file \"%s\": %s.\n",
+      cmdarg_err("I/O error reading global preferences file \"%s\": %s.",
               pf_path, strerror(gpf_read_errno));
     }
   }
   if (pf_path != NULL) {
     if (pf_open_errno != 0) {
-      fprintf(stderr, "Can't open your preferences file \"%s\": %s.\n", pf_path,
+      cmdarg_err("Can't open your preferences file \"%s\": %s.", pf_path,
               strerror(pf_open_errno));
     }
     if (pf_read_errno != 0) {
-      fprintf(stderr, "I/O error reading your preferences file \"%s\": %s.\n",
+      cmdarg_err("I/O error reading your preferences file \"%s\": %s.",
               pf_path, strerror(pf_read_errno));
     }
     g_free(pf_path);
@@ -726,29 +835,27 @@ main(int argc, char *argv[])
 
   /* 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);
+                            &dp_path, &dp_open_errno, &dp_read_errno);
   if (gdp_path != NULL) {
     if (gdp_open_errno != 0) {
-      fprintf(stderr,
-        "Could not open global disabled protocols file\n\"%s\": %s.\n",
-       gdp_path, strerror(gdp_open_errno));
+      cmdarg_err("Could not open global disabled protocols file\n\"%s\": %s.",
+                 gdp_path, strerror(gdp_open_errno));
     }
     if (gdp_read_errno != 0) {
-      fprintf(stderr,
-        "I/O error reading global disabled protocols file\n\"%s\": %s.\n",
-       gdp_path, strerror(gdp_read_errno));
+      cmdarg_err("I/O error reading global disabled protocols file\n\"%s\": %s.",
+                 gdp_path, strerror(gdp_read_errno));
     }
     g_free(gdp_path);
   }
   if (dp_path != NULL) {
     if (dp_open_errno != 0) {
-      fprintf(stderr,
-        "Could not open your disabled protocols file\n\"%s\": %s.\n", dp_path,
+      cmdarg_err(
+        "Could not open your disabled protocols file\n\"%s\": %s.", dp_path,
         strerror(dp_open_errno));
     }
     if (dp_read_errno != 0) {
-      fprintf(stderr,
-        "I/O error reading your disabled protocols file\n\"%s\": %s.\n", dp_path,
+      cmdarg_err(
+        "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path,
         strerror(dp_read_errno));
     }
     g_free(dp_path);
@@ -773,17 +880,25 @@ main(int argc, char *argv[])
   print_format = PR_FMT_TEXT;
 
   /* Now get our args */
-  while ((opt = getopt(argc, argv, "a:b:c:d:Df:F:hi:lLnN:o:pqr:R:s:St:T:vw:Vxy:z:")) != -1) {
+  while ((opt = getopt(argc, argv, optstring)) != -1) {
     switch (opt) {
       case 'a':        /* autostop criteria */
       case 'b':        /* Ringbuffer option */
       case 'c':        /* Capture xxx packets */
       case 'f':        /* capture filter */
+      case 'i':        /* Use interface xxx */
       case 'p':        /* Don't capture in promiscuous mode */
       case 's':        /* Set the snapshot (capture) length */
+      case 'w':        /* Write to capture file xxx */
       case 'y':        /* Set the pcap data link type */
+#ifdef _WIN32
+      case 'B':        /* Buffer size */
+#endif /* _WIN32 */
 #ifdef HAVE_LIBPCAP
-        capture_opts_add_opt(&capture_opts, "tethereal", opt, optarg, &start_capture);
+        status = capture_opts_add_opt(&capture_opts, opt, optarg, &start_capture);
+        if(status != 0) {
+            exit(status);
+        }
 #else
         capture_option_specified = TRUE;
         arg_error = TRUE;
@@ -792,37 +907,11 @@ main(int argc, char *argv[])
       case 'd':        /* Decode as rule */
         if (!add_decode_as(optarg))
           exit(1);
-       break;
-      case 'D':        /* Print a list of capture devices */
+        break;
+      case 'D':        /* Print a list of capture devices and exit */
 #ifdef HAVE_LIBPCAP
-        if_list = get_interface_list(&err, err_str);
-        if (if_list == NULL) {
-            switch (err) {
-
-            case CANT_GET_INTERFACE_LIST:
-                cant_get_if_list_errstr =
-                    cant_get_if_list_error_message(err_str);
-                fprintf(stderr, "tethereal: %s\n", cant_get_if_list_errstr);
-                g_free(cant_get_if_list_errstr);
-                break;
-
-            case NO_INTERFACES_FOUND:
-                fprintf(stderr, "tethereal: There are no interfaces on which a capture can be done\n");
-                break;
-            }
-            exit(2);
-        }
-        i = 1;  /* Interface id number */
-        for (if_entry = g_list_first(if_list); if_entry != NULL;
-               if_entry = g_list_next(if_entry)) {
-         if_info = if_entry->data;
-          printf("%d. %s", i++, if_info->name);
-          if (if_info->description != NULL)
-            printf(" (%s)", if_info->description);
-          printf("\n");
-        }
-        free_interface_list(if_list);
-        exit(0);
+        status = capture_opts_list_interfaces();
+        exit(status);
 #else
         capture_option_specified = TRUE;
         arg_error = TRUE;
@@ -831,88 +920,30 @@ main(int argc, char *argv[])
       case 'F':
         out_file_type = wtap_short_string_to_file_type(optarg);
         if (out_file_type < 0) {
-          fprintf(stderr, "tethereal: \"%s\" isn't a valid capture file type\n",
-                       optarg);
+          cmdarg_err("\"%s\" isn't a valid capture file type", optarg);
+          list_capture_types();
           exit(1);
         }
         break;
       case 'h':        /* Print help and exit */
-       print_usage(TRUE);
-       exit(0);
-        break;
-      case 'i':        /* Use interface xxx */
-#ifdef HAVE_LIBPCAP
-        /*
-         * If the argument is a number, treat it as an index into the list
-         * of adapters, as printed by "tethereal -D".
-         *
-         * This should be OK on UNIX systems, as interfaces shouldn't have
-         * names that begin with digits.  It can be useful on Windows, where
-         * more than one interface can have the same name.
-         */
-        adapter_index = strtol(optarg, &p, 10);
-        if (p != NULL && *p == '\0') {
-          if (adapter_index < 0) {
-            fprintf(stderr,
-                "tethereal: The specified adapter index is a negative number\n");
-           exit(1);
-          }
-          if (adapter_index > INT_MAX) {
-            fprintf(stderr,
-                "tethereal: The specified adapter index is too large (greater than %d)\n",
-                INT_MAX);
-            exit(1);
-          }
-          if (adapter_index == 0) {
-            fprintf(stderr, "tethereal: there is no interface with that adapter index\n");
-            exit(1);
-          }
-          if_list = get_interface_list(&err, err_str);
-          if (if_list == NULL) {
-            switch (err) {
-
-            case CANT_GET_INTERFACE_LIST:
-                cant_get_if_list_errstr =
-                    cant_get_if_list_error_message(err_str);
-                fprintf(stderr, "tethereal: %s\n", cant_get_if_list_errstr);
-                g_free(cant_get_if_list_errstr);
-                break;
-
-            case NO_INTERFACES_FOUND:
-                fprintf(stderr, "tethereal: There are no interfaces on which a capture can be done\n");
-                break;
-            }
-            exit(2);
-          }
-          if_info = g_list_nth_data(if_list, adapter_index - 1);
-          if (if_info == NULL) {
-            fprintf(stderr, "tethereal: there is no interface with that adapter index\n");
-            exit(1);
-          }
-          capture_opts.iface = g_strdup(if_info->name);
-          free_interface_list(if_list);
-        } else
-          capture_opts.iface = g_strdup(optarg);
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
+        print_usage(TRUE);
+        exit(0);
         break;
       case 'l':        /* "Line-buffer" standard output */
-       /* This isn't line-buffering, strictly speaking, it's just
-          flushing the standard output after the information for
-          each packet is printed; however, that should be good
-          enough for all the purposes to which "-l" is put (and
-          is probably actually better for "-V", as it does fewer
-          writes).
-
-          See the comment in "process_packet()" for an explanation of
-          why we do that, and why we don't just use "setvbuf()" to
-          make the standard output line-buffered (short version: in
-          Windows, "line-buffered" is the same as "fully-buffered",
-          and the output buffer is only flushed when it fills up). */
-       line_buffered = TRUE;
-       break;
+        /* This isn't line-buffering, strictly speaking, it's just
+           flushing the standard output after the information for
+           each packet is printed; however, that should be good
+           enough for all the purposes to which "-l" is put (and
+           is probably actually better for "-V", as it does fewer
+           writes).
+
+           See the comment in "process_packet()" for an explanation of
+           why we do that, and why we don't just use "setvbuf()" to
+           make the standard output line-buffered (short version: in
+           Windows, "line-buffered" is the same as "fully-buffered",
+           and the output buffer is only flushed when it fills up). */
+        line_buffered = TRUE;
+        break;
       case 'L':        /* Print list of link-layer types and exit */
 #ifdef HAVE_LIBPCAP
         list_link_layer_types = TRUE;
@@ -930,23 +961,22 @@ main(int argc, char *argv[])
           g_resolv_flags = RESOLV_NONE;
         badopt = string_to_name_resolve(optarg, &g_resolv_flags);
         if (badopt != '\0') {
-          fprintf(stderr, "tethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'\n",
-                       badopt);
+          cmdarg_err("-N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'",
+                     badopt);
           exit(1);
         }
         break;
       case 'o':        /* Override preference from command line */
         switch (prefs_set_pref(optarg)) {
 
-       case PREFS_SET_SYNTAX_ERR:
-          fprintf(stderr, "tethereal: Invalid -o flag \"%s\"\n", optarg);
+        case PREFS_SET_SYNTAX_ERR:
+          cmdarg_err("Invalid -o flag \"%s\"", optarg);
           exit(1);
           break;
 
         case PREFS_SET_NO_SUCH_PREF:
         case PREFS_SET_OBSOLETE:
-          fprintf(stderr, "tethereal: -o flag \"%s\" specifies unknown preference\n",
-                       optarg);
+          cmdarg_err("-o flag \"%s\" specifies unknown preference", optarg);
           exit(1);
           break;
         }
@@ -973,46 +1003,53 @@ main(int argc, char *argv[])
         else if (strcmp(optarg, "d") == 0)
           timestamp_set_type(TS_DELTA);
         else {
-          fprintf(stderr, "tethereal: Invalid time stamp type \"%s\"\n",
+          cmdarg_err("Invalid time stamp type \"%s\"",
             optarg);
-          fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
-          fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
+          cmdarg_err_cont("It must be \"r\" for relative, \"a\" for absolute,");
+          cmdarg_err_cont("\"ad\" for absolute with date, or \"d\" for delta.");
           exit(1);
         }
         break;
       case 'T':        /* printing Type */
         if (strcmp(optarg, "text") == 0) {
-         output_action = WRITE_TEXT;
-         print_format = PR_FMT_TEXT;
-       } else if (strcmp(optarg, "ps") == 0) {
-         output_action = WRITE_TEXT;
-         print_format = PR_FMT_PS;
-       } else if (strcmp(optarg, "pdml") == 0) {
-         output_action = WRITE_XML;
-         verbose = TRUE;
-       } else if (strcmp(optarg, "psml") == 0) {
-         output_action = WRITE_XML;
-         verbose = FALSE;
-       } else {
-         fprintf(stderr, "tethereal: Invalid -T parameter.\n");
-         fprintf(stderr, "It must be \"ps\", \"text\", \"pdml\", or \"psml\".\n");
-         exit(1);
-       }
-       break;
+          output_action = WRITE_TEXT;
+          print_format = PR_FMT_TEXT;
+        } else if (strcmp(optarg, "ps") == 0) {
+          output_action = WRITE_TEXT;
+          print_format = PR_FMT_PS;
+        } else if (strcmp(optarg, "pdml") == 0) {
+          output_action = WRITE_XML;
+          verbose = TRUE;
+        } else if (strcmp(optarg, "psml") == 0) {
+          output_action = WRITE_XML;
+          verbose = FALSE;
+        } else {
+          cmdarg_err("Invalid -T parameter.");
+          cmdarg_err_cont("It must be \"ps\", \"text\", \"pdml\", or \"psml\".");
+          exit(1);
+        }
+        break;
       case 'v':        /* Show version and exit */
-        printf("t" PACKAGE " " VERSION "%s\n%s\n%s\n",
-           svnversion, comp_info_str->str, runtime_info_str->str);
+        printf("Tethereal " VERSION "%s\n"
+               "\n"
+               "%s"
+               "\n"
+               "%s"
+               "\n"
+               "%s",
+               svnversion, get_copyright_info(), comp_info_str->str,
+               runtime_info_str->str);
         exit(0);
         break;
-      case 'w':        /* Write to capture file xxx */
-        save_file = g_strdup(optarg);
-       break;
       case 'V':        /* Verbose */
         verbose = TRUE;
         break;
       case 'x':        /* Print packet data in hex (and ASCII) */
-        print_hex = TRUE;
-        break;
+          print_hex = TRUE;
+          break;
+      case 'X':
+          ex_opt_add(optarg);
+          break;
       case 'z':
         /* We won't call the init function for the stat this soon
            as it would disallow MATE's fields (which are registered
@@ -1020,15 +1057,22 @@ main(int argc, char *argv[])
            part of a tap filter.  Instead, we just add the argument
            to a list of stat arguments. */
         if (!process_stat_cmd_arg(optarg)) {
-         fprintf(stderr,"tethereal: invalid -z argument.\n");
-         fprintf(stderr,"  -z argument must be one of :\n");
-         list_stat_cmd_args();
-         exit(1);
-       }
+          cmdarg_err("invalid -z argument.");
+          cmdarg_err_cont("  -z argument must be one of :");
+          list_stat_cmd_args();
+          exit(1);
+        }
         break;
       default:
       case '?':        /* Bad flag - print usage message */
-        arg_error = TRUE;
+        switch(optopt) {
+        case'F':
+          list_capture_types();
+          break;
+        default:
+          print_usage(TRUE);
+        }
+        exit(1);
         break;
     }
   }
@@ -1040,17 +1084,17 @@ main(int argc, char *argv[])
   if (optind < argc) {
     if (cf_name != NULL) {
       if (rfilter != NULL) {
-        fprintf(stderr,
-"tethereal: Read filters were specified both with \"-R\" and with additional command-line arguments\n");
-        exit(2);
+        cmdarg_err("Read filters were specified both with \"-R\" "
+            "and with additional command-line arguments");
+        exit(1);
       }
       rfilter = get_args_as_string(argc, argv, optind);
     } else {
 #ifdef HAVE_LIBPCAP
       if (capture_filter_specified) {
-        fprintf(stderr,
-"tethereal: Capture filters were specified both with \"-f\" and with additional command-line arguments\n");
-        exit(2);
+        cmdarg_err("Capture filters were specified both with \"-f\""
+            " and with additional command-line arguments");
+        exit(1);
       }
       capture_opts.cfilter = get_args_as_string(argc, argv, optind);
 #else
@@ -1059,56 +1103,27 @@ main(int argc, char *argv[])
     }
   }
 
-  /* See if we're writing a capture file and the file is a pipe */
-#ifdef HAVE_LIBPCAP
-  ld.output_to_pipe = FALSE;
-#endif
-  if (save_file != NULL) {
-    /* We're writing to a capture file. */
-    if (strcmp(save_file, "-") == 0) {
-      /* Write to the standard output. */
-      g_free(save_file);
-      save_file = g_strdup("");
-#ifdef HAVE_LIBPCAP
-      /* XXX - should we check whether it's a pipe?  It's arguably
-         silly to do "-w - >output_file" rather than "-w output_file",
-         but by not checking we might be violating the Principle Of
-         Least Astonishment. */
-      ld.output_to_pipe = TRUE;
-#endif
-    }
-#ifdef HAVE_LIBPCAP
-    else {
-      err = test_for_fifo(save_file);
-      switch (err) {
-
-      case ENOENT:     /* it doesn't exist, so we'll be creating it,
-                          and it won't be a FIFO */
-      case 0:          /* found it, but it's not a FIFO */
-        break;
-
-      case ESPIPE:     /* it is a FIFO */
-        ld.output_to_pipe = TRUE;
-        break;
-
-      default:         /* couldn't stat it */
-        fprintf(stderr,
-                "tethereal: Error testing whether capture file is a pipe: %s\n",
-                strerror(errno));
-        exit(2);
-      }
-    }
-#endif
-  } else {
-    /* We're not writing to a file, so we should print packet information
-       unless "-q" was specified. */
+  if (!capture_opts.saving_to_file) {
+    /* We're not saving the capture to a file; if "-q" wasn't specified,
+       we should print packet information */
     if (!quiet)
       print_packet_info = TRUE;
+  } else {
+    /* We're saving to a file; if we're writing to the standard output.
+       and we'll also be writing dissected packets to the standard
+       output, reject the request.  At best, we could redirect that
+       to the standard error; we *can't* write both to the standard
+       output and have either of them be useful. */
+    if (strcmp(capture_opts.save_file, "-") == 0 && print_packet_info) {
+      cmdarg_err("You can't write both raw packet data and dissected packets"
+          " to the standard output.");
+      exit(1);
+    }
   }
 
 #ifndef HAVE_LIBPCAP
   if (capture_option_specified)
-    fprintf(stderr, "This version of Tethereal was not built with support for capturing packets.\n");
+    cmdarg_err("This version of Tethereal was not built with support for capturing packets.");
 #endif
   if (arg_error) {
     print_usage(FALSE);
@@ -1121,16 +1136,16 @@ main(int argc, char *argv[])
 #ifdef HAVE_LIBPCAP
   if (cf_name != NULL) {
     if (capture_filter_specified) {
-      fprintf(stderr,
-"tethereal: Only read filters, not capture filters, can be specified when reading a capture file.\n");
-      exit(2);
+      cmdarg_err("Only read filters, not capture filters, "
+          "can be specified when reading a capture file.");
+      exit(1);
     }
   }
 #endif
 
   if (print_hex) {
     if (output_action != WRITE_TEXT) {
-      fprintf(stderr, "tethereal: Raw packet hex data can only be printed as text or PostScript\n");
+      cmdarg_err("Raw packet hex data can only be printed as text or PostScript");
       exit(1);
     }
   }
@@ -1141,50 +1156,113 @@ main(int argc, char *argv[])
        did the user also specify a capture file to be read? */
     if (cf_name) {
       /* Yes - that's bogus. */
-      fprintf(stderr, "tethereal: You can't specify -L and a capture file to be read.\n");
+      cmdarg_err("You can't specify -L and a capture file to be read.");
       exit(1);
     }
     /* No - did they specify a ring buffer option? */
     if (capture_opts.multi_files_on) {
-      fprintf(stderr, "tethereal: Ring buffer requested, but a capture isn't being done.\n");
+      cmdarg_err("Ring buffer requested, but a capture isn't being done.");
       exit(1);
     }
   } else {
     /* If they didn't specify a "-w" flag, but specified a maximum capture
        file size, tell them that this doesn't work, and exit. */
-    if (capture_opts.has_autostop_filesize && save_file == NULL) {
-      fprintf(stderr, "tethereal: Maximum capture file size specified, but "
-        "capture isn't being saved to a file.\n");
+    if (capture_opts.has_autostop_filesize && capture_opts.save_file == NULL) {
+      cmdarg_err("Maximum capture file size specified, but "
+        "capture isn't being saved to a file.");
       exit(1);
     }
 
-    if (capture_opts.multi_files_on) {
-      /* Ring buffer works only under certain conditions:
-        a) ring buffer does not work if you're not saving the capture to
-           a file;
-        b) ring buffer only works if you're saving in libpcap format;
-        c) it makes no sense to enable the ring buffer if the maximum
-           file size is set to "infinite";
-        d) file must not be a pipe. */
-      if (save_file == NULL) {
-       fprintf(stderr, "tethereal: Ring buffer requested, but "
-         "capture isn't being saved to a file.\n");
-       exit(1);
+    if (cf_name) {
+      /*
+       * "-r" was specified, so we're reading a capture file.
+       * Capture options don't apply here.
+       */
+      if (capture_opts.multi_files_on) {
+        cmdarg_err("Multiple capture files requested, but "
+                   "a capture isn't being done.");
+        exit(1);
+      }
+      if (capture_opts.has_file_duration) {
+        cmdarg_err("Switching capture files after a time interval was specified, but "
+                   "a capture isn't being done.");
+        exit(1);
+      }
+      if (capture_opts.has_ring_num_files) {
+        cmdarg_err("A ring buffer of capture files was specified, but "
+          "a capture isn't being done.");
+        exit(1);
+      }
+      if (capture_opts.has_autostop_files) {
+        cmdarg_err("A maximum number of capture files was specified, but "
+          "a capture isn't being done.");
+        exit(1);
+      }
+      if (capture_opts.has_autostop_packets) {
+        cmdarg_err("A maximum number of captured packets was specified, but "
+          "a capture isn't being done.");
+        exit(1);
       }
-      if (out_file_type != WTAP_FILE_PCAP) {
-       fprintf(stderr, "tethereal: Ring buffer requested, but "
-         "capture isn't being saved in libpcap format.\n");
-       exit(2);
+      if (capture_opts.has_autostop_filesize) {
+        cmdarg_err("A maximum capture file size was specified, but "
+          "a capture isn't being done.");
+        exit(1);
       }
-      if (!capture_opts.has_autostop_filesize) {
-       fprintf(stderr, "tethereal: Ring buffer requested, but "
-         "no maximum capture file size was specified.\n");
-       exit(2);
+      if (capture_opts.has_autostop_duration) {
+        cmdarg_err("A maximum capture time was specified, but "
+          "a capture isn't being done.");
+        exit(1);
       }
-      if (ld.output_to_pipe) {
-       fprintf(stderr, "tethereal: Ring buffer requested, but "
-         "capture file is a pipe.\n");
-       exit(2);
+    } else {
+      /*
+       * "-r" wasn't specified, so we're doing a live capture.
+       */
+      if (capture_opts.saving_to_file) {
+        /* They specified a "-w" flag, so we'll be saving to a capture file. */
+  
+        /* When capturing, we only support writing libpcap format. */
+        if (out_file_type != WTAP_FILE_PCAP) {
+          cmdarg_err("Live captures can only be saved in libpcap format.");
+          exit(1);
+        }
+        if (capture_opts.multi_files_on) {
+          /* Multiple-file mode works only under certain conditions:
+             a) it doesn't work if you're writing to the standard output;
+             b) it doesn't work if you're writing to a pipe;
+             c) it makes no sense if the maximum file size is set to "infinite"
+                (XXX - shouldn't that be "if there is no stop criterion",
+                as you might want to switch files based on a packet count
+                or a time). */
+          if (strcmp(capture_opts.save_file, "-") == 0) {
+            cmdarg_err("Multiple capture files requested, but "
+              "the capture is being written to the standard output.");
+            exit(1);
+          }
+          if (capture_opts.output_to_pipe) {
+            cmdarg_err("Multiple capture files requested, but "
+              "the capture file is a pipe.");
+            exit(1);
+          }
+          if (!capture_opts.has_autostop_filesize) {
+            cmdarg_err("Multiple capture files requested, but "
+              "no maximum capture file size was specified.");
+            exit(1);
+          }
+        }
+      } else {
+        /* They didn't specify a "-w" flag, so we won't be saving to a
+           capture file.  Check for options that only make sense if
+           we're saving to a file. */
+        if (capture_opts.has_autostop_filesize) {
+          cmdarg_err("Maximum capture file size specified, but "
+           "capture isn't being saved to a file.");
+          exit(1);
+        }
+        if (capture_opts.multi_files_on) {
+          cmdarg_err("Multiple capture files requested, but "
+            "the capture isn't being saved to a file.");
+          exit(1);
+        }
       }
     }
   }
@@ -1193,7 +1271,7 @@ main(int argc, char *argv[])
 #ifdef _WIN32
   /* Start windows sockets */
   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
-#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
@@ -1242,23 +1320,13 @@ main(int argc, char *argv[])
   }
 
 #ifdef HAVE_LIBPCAP
-  if (capture_opts.snaplen < 1)
-    capture_opts.snaplen = WTAP_MAX_PACKET_SIZE;
-  else if (capture_opts.snaplen < MIN_PACKET_SIZE)
-    capture_opts.snaplen = MIN_PACKET_SIZE;
-
-  /* Check the value range of the ring_num_files parameter */
-  if (capture_opts.ring_num_files > RINGBUFFER_MAX_NUM_FILES)
-    capture_opts.ring_num_files = RINGBUFFER_MAX_NUM_FILES;
-#if RINGBUFFER_MIN_NUM_FILES > 0
-  else if (capture_opts.ring_num_files < RINGBUFFER_MIN_NUM_FILES)
-    capture_opts.ring_num_files = RINGBUFFER_MIN_NUM_FILES;
-#endif
+  capture_opts_trim_snaplen(&capture_opts, MIN_PACKET_SIZE);
+  capture_opts_trim_ring_num_files(&capture_opts);
 #endif
 
   if (rfilter != NULL) {
     if (!dfilter_compile(rfilter, &rfcode)) {
-      fprintf(stderr, "tethereal: %s\n", dfilter_error_msg);
+      cmdarg_err("%s", dfilter_error_msg);
       epan_cleanup();
 #ifdef HAVE_PCAP_OPEN_DEAD
       {
@@ -1267,9 +1335,10 @@ main(int argc, char *argv[])
         pc = pcap_open_dead(DLT_EN10MB, MIN_PACKET_SIZE);
         if (pc != NULL) {
           if (pcap_compile(pc, &fcode, rfilter, 0, 0) != -1) {
-            fprintf(stderr,
-              "  Note: That display filter code looks like a valid capture filter;\n"
-              "        maybe you mixed them up?\n");
+            cmdarg_err_cont(
+              "  Note: That display filter code looks like a valid capture filter;");
+            cmdarg_err_cont(
+              "        maybe you mixed them up?");
           }
           pcap_close(pc);
         }
@@ -1302,11 +1371,11 @@ main(int argc, char *argv[])
 
   /* We have to dissect each packet if:
 
-       we're printing information about each packet;
+        we're printing information about each packet;
 
-       we're using a read filter on the packets;
+        we're using a read filter on the packets;
 
-       we're using any taps. */
+        we're using any taps. */
   do_dissection = print_packet_info || rfcode || have_tap_listeners();
 
   if (cf_name) {
@@ -1314,15 +1383,12 @@ main(int argc, char *argv[])
      * We're reading a capture file.
      */
 
-#ifndef _WIN32
     /*
-     * Immediately relinquish any set-UID or set-GID privileges we have;
-     * we must not be allowed to read any capture files the user running
-     * Tethereal can't open.
+     * Immediately relinquish any special privileges we have; we must not
+     * be allowed to read any capture files the user running Tethereal
+     * can't open.
      */
-    setuid(getuid());
-    setgid(getgid());
-#endif
+    relinquish_special_privs_perm();
 
     if (cf_open(&cfile, cf_name, FALSE, &err) != CF_OK) {
       epan_cleanup();
@@ -1355,7 +1421,7 @@ main(int argc, char *argv[])
     }
 
     /* Process the packets in the file */
-    err = load_cap_file(&cfile, save_file, out_file_type);
+    err = load_cap_file(&cfile, capture_opts.save_file, out_file_type);
     if (err != 0) {
       epan_cleanup();
       exit(2);
@@ -1371,81 +1437,36 @@ main(int argc, char *argv[])
     if (!has_wpcap) {
       char *detailed_err;
 
-      fprintf(stderr, "tethereal: WinPcap couldn't be found.\n");
+      cmdarg_err("WinPcap couldn't be found.");
       detailed_err = cant_load_winpcap_err("Tethereal");
-      fprintf(stderr, "%s\n", detailed_err);
+      cmdarg_err_cont("%s", detailed_err);
       g_free(detailed_err);
       exit(2);
     }
 #endif
 
-    /* Yes; did the user specify an interface to use? */
-    if (capture_opts.iface == NULL) {
-      /* No - is a default specified in the preferences file? */
-      if (prefs->capture_device != NULL) {
-        /* Yes - use it. */
-        if_text = strrchr(prefs->capture_device, ' ');
-       if (if_text == NULL) {
-          capture_opts.iface = g_strdup(prefs->capture_device);
-       } else {
-          capture_opts.iface = g_strdup(if_text + 1); /* Skip over space */
-       }
-      } else {
-        /* No - pick the first one from the list of interfaces. */
-        if_list = get_interface_list(&err, err_str);
-        if (if_list == NULL) {
-          switch (err) {
-
-          case CANT_GET_INTERFACE_LIST:
-            cant_get_if_list_errstr = cant_get_if_list_error_message(err_str);
-            fprintf(stderr, "tethereal: %s\n", cant_get_if_list_errstr);
-            g_free(cant_get_if_list_errstr);
-            break;
-
-          case NO_INTERFACES_FOUND:
-            fprintf(stderr, "tethereal: There are no interfaces on which a capture can be done\n");
-            break;
-         }
-          exit(2);
-       }
-        if_info = if_list->data;       /* first interface */
-       capture_opts.iface = g_strdup(if_info->name);
-        free_interface_list(if_list);
-      }
+    /* trim the interface name and exit if that failed */
+    if (!capture_opts_trim_iface(&capture_opts, 
+        (prefs->capture_device) ? get_if_name(prefs->capture_device) : NULL)) {
+        exit(2);
     }
 
+    /* if requested, list the link layer types and exit */
     if (list_link_layer_types) {
-      /* We were asked to list the link-layer types for an interface.
-         Get the list of link-layer types for the capture device. */
-      lt_list = get_pcap_linktype_list(capture_opts.iface, err_str);
-      if (lt_list == NULL) {
-       if (err_str[0] != '\0') {
-         fprintf(stderr, "tethereal: The list of data link types for the capture device could not be obtained (%s).\n"
-           "Please check to make sure you have sufficient permissions, and that\n"
-           "you have the proper interface or pipe specified.\n", err_str);
-       } else
-         fprintf(stderr, "tethereal: The capture device has no data link types.\n");
-       exit(2);
-      }
-      fprintf(stderr, "Data link types (use option -y to set):\n");
-      for (lt_entry = lt_list; lt_entry != NULL;
-          lt_entry = g_list_next(lt_entry)) {
-       data_link_info = lt_entry->data;
-       fprintf(stderr, "  %s", data_link_info->name);
-       if (data_link_info->description != NULL)
-         fprintf(stderr, " (%s)", data_link_info->description);
-       else
-         fprintf(stderr, " (not supported)");
-       putchar('\n');
-      }
-      free_pcap_linktype_list(lt_list);
-      exit(0);
+        status = capture_opts_list_link_layer_types(&capture_opts);
+        exit(status);
     }
 
-    if (!quiet) {
+    if (!print_packet_info && !quiet) {
       /*
-       * The user didn't ask us not to print a count of packets as
-       * they arrive, so do so.
+       * We're not printing information for each packet, and the user
+       * didn't ask us not to print a count of packets as they arrive,
+       * so print that count so the user knows that packets are arriving.
+       *
+       * XXX - what if the user wants to do a live capture, doesn't want
+       * to save it to a file, doesn't want information printed for each
+       * packet, does want some "-z" statistic, and wants packet counts
+       * so they know whether they're seeing any packets?
        */
       print_packet_counts = TRUE;
     }
@@ -1453,19 +1474,20 @@ main(int argc, char *argv[])
     /* For now, assume libpcap gives microsecond precision. */
     timestamp_set_precision(TS_PREC_AUTO_USEC);
 
-    capture(save_file, out_file_type);
+    capture();
 
     if (capture_opts.multi_files_on) {
       ringbuf_free();
     }
 #else
     /* No - complain. */
-    fprintf(stderr, "This version of Tethereal was not built with support for capturing packets.\n");
+    cmdarg_err("This version of Tethereal was not built with support for capturing packets.");
     exit(2);
 #endif
   }
 
   draw_tap_listeners(TRUE);
+  funnel_dump_all_text_windows();
   epan_cleanup();
 
   return 0;
@@ -1475,246 +1497,95 @@ main(int argc, char *argv[])
 /* Do the low-level work of a capture.
    Returns TRUE if it succeeds, FALSE otherwise. */
 
-static condition  *volatile cnd_ring_timeout = NULL; /* this must be visible in process_packet */
+static condition  *volatile cnd_file_duration = NULL; /* this must be visible in process_packet */
 
 static int
-capture(char *save_file, int out_file_type)
+capture(void)
 {
-  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;
-  struct bpf_program fcode;
-  const char *set_linktype_err_str;
   int         err = 0;
   int         volatile volatile_err = 0;
   int         volatile inpkts = 0;
   int         pcap_cnt;
-  char        errmsg[1024+1];
-  condition  *volatile cnd_stop_capturesize = NULL;
-  condition  *volatile cnd_stop_timeout = NULL;
+  condition  *volatile cnd_autostop_size = NULL;
+  condition  *volatile cnd_autostop_duration = NULL;
   char       *descr;
 #ifndef _WIN32
   void        (*oldhandler)(int);
-  static const char ppamsg[] = "can't find PPA for ";
-  const 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;
-  gboolean    dump_ok;
-  dfilter_t   *rfcode = NULL;
+  gboolean    write_ok;
+  gboolean    close_ok;
+  gboolean    cfilter_error = FALSE;
+  char        errmsg[1024+1];
+  char        secondary_errmsg[4096+1];
   int         save_file_fd;
 
   /* Initialize all data structures used for dissection. */
   init_dissection();
 
-  ld.linktype       = WTAP_ENCAP_UNKNOWN;
+  ld.wtap_linktype  = WTAP_ENCAP_UNKNOWN;
   ld.pdh            = NULL;
+  ld.packet_cb      = capture_pcap_cb;
 
-  /* Open the network interface to capture from it.
-     Some versions of libpcap may put warnings into the error buffer
-     if they succeed; to tell if that's happened, we have to clear
-     the error buffer, and check if it's still a null string.  */
-  open_err_str[0] = '\0';
-  ld.pch = pcap_open_live(capture_opts.iface, capture_opts.snaplen,
-                         capture_opts.promisc_mode, 1000, open_err_str);
-
-  if (ld.pch != NULL) {
-    /* setting the data link type only works on real interfaces */
-    if (capture_opts.linktype != -1) {
-      set_linktype_err_str = set_pcap_linktype(ld.pch, capture_opts.iface,
-       capture_opts.linktype);
-      if (set_linktype_err_str != NULL) {
-       g_snprintf(errmsg, sizeof errmsg, "Unable to set data link type (%s).",
-         set_linktype_err_str);
-       goto error;
-      }
-    }
-  } else {
-    /* 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 about the lack of 64-bit support, and warn that
-       WAN devices aren't supported. */
-    g_snprintf(errmsg, sizeof errmsg,
-"The capture session could not be initiated (%s).\n"
-"Please check that you have the proper interface specified.\n"
-"\n"
-"Help can be found at: http://wiki.ethereal.com/CaptureSetup\n"
-"\n"
-"WinPcap does not support 64-bit Windows, so you will not be able to capture\n"
-"traffic with Tethereal on 64-bit Windows.  You will have to use some other\n"
-"tool to capture traffic, such as netcap; see\n"
-"\n"
-"       http://support.microsoft.com/?id=310875\n"
-"\n"
-"for information about netcap.\n"
-"\n"
-"Note that version 3.0 of WinPcap, and earlier versions of WinPcap, don't\n"
-"support capturing on PPP/WAN interfaces on Windows NT 4.0 / 2000 / XP /\n"
-"Server 2003.\n"
-"WinPcap 3.1 has support for it on Windows 2000 / XP / Server 2003, but has no\n"
-"support for it on Windows NT 4.0 or Windows Vista (Beta 1).\n",
-       open_err_str);
+
+  /* open the "input file" from network interface or capture pipe */
+  if (!capture_loop_open_input(&capture_opts, &ld, errmsg, sizeof(errmsg),
+                               secondary_errmsg, sizeof(secondary_errmsg))) {
     goto error;
-#else
-    /* try to open cfile.iface as a pipe */
-    pipe_fd = pipe_open_live(capture_opts.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 = "";
-       g_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
   }
 
-#ifndef _WIN32
   /*
-   * We've opened the capture device, so, if we're set-UID or set-GID,
-   * relinquish those privileges.
+   * We've opened the capture device, so we shouldn't need any special
+   * privileges any more; relinquish those privileges.
    *
    * XXX - if we have saved set-user-ID support, we should give up those
    * privileges immediately, and then reclaim them long enough to get
    * a list of network interfaces and to open one, and then give them
    * up again, so that stuff we do while processing the argument list,
-   * reading the user's preferences, etc. is done as the real user and
-   * group, not the effective user and group.
+   * reading the user's preferences, loading and starting plugins
+   * (especially *user* plugins), etc. is done with the user's privileges,
+   * not special privileges.
    */
-  setuid(getuid());
-  setgid(getgid());
-#endif
+  relinquish_special_privs_perm();
 
-  if (capture_opts.cfilter && !ld.from_pipe) {
-    /* A capture filter was specified; set it up. */
-    if (pcap_lookupnet(capture_opts.iface, &netnum, &netmask, lookup_net_err_str) < 0) {
-      /*
-       * Well, we can't get the netmask for this interface; it's used
-       * only for filters that check for broadcast IP addresses, so
-       * we just warn the user, and punt and use 0.
-       */
-      fprintf(stderr,
-        "Warning:  Couldn't obtain netmask info (%s).\n", lookup_net_err_str);
-      netmask = 0;
-    }
-    if (pcap_compile(ld.pch, &fcode, capture_opts.cfilter, 1, netmask) < 0) {
-      if (dfilter_compile(capture_opts.cfilter, &rfcode)) {
-        g_snprintf(errmsg, sizeof errmsg,
-         "Unable to parse capture filter string (%s).\n"
-          "  Interestingly enough, this looks like a valid display filter\n"
-         "  Are you sure you didn't mix them up?",
-         pcap_geterr(ld.pch));
-      } else {
-        g_snprintf(errmsg, sizeof errmsg,
-         "Unable to parse capture filter string (%s).",
-         pcap_geterr(ld.pch));
-      }
-      goto error;
-    }
-    if (pcap_setfilter(ld.pch, &fcode) < 0) {
-      g_snprintf(errmsg, sizeof errmsg, "Can't install filter (%s).",
-       pcap_geterr(ld.pch));
-#ifdef HAVE_PCAP_FREECODE
-      pcap_freecode(&fcode);
-#endif
-      goto error;
-    }
-#ifdef HAVE_PCAP_FREECODE
-    pcap_freecode(&fcode);
-#endif
-  }
+  /* init the input filter from the network interface (capture pipe will do nothing) */
+  switch (capture_loop_init_filter(ld.pcap_h, ld.from_cap_pipe, capture_opts.iface, capture_opts.cfilter)) {
 
-  /* 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, capture_opts.iface);
-    file_snaplen = pcap_snapshot(ld.pch);
+  case INITFILTER_NO_ERROR:
+    break;
+
+  case INITFILTER_BAD_FILTER:
+    cfilter_error = TRUE;
+    g_snprintf(errmsg, sizeof(errmsg), "%s", pcap_geterr(ld.pcap_h));
+    *secondary_errmsg = '\0';
+    goto error;
+
+  case INITFILTER_OTHER_ERROR:
+    g_snprintf(errmsg, sizeof(errmsg), "Can't install filter (%s).",
+               pcap_geterr(ld.pcap_h));
+    g_snprintf(secondary_errmsg, sizeof(secondary_errmsg), "%s", please_report);
+    goto error;
   }
-  ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_encap);
-  if (save_file != NULL) {
-    /* Set up to write to the capture file. */
-    if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
-      strcpy(errmsg, "The network you're capturing from is of a type"
-               " that Tethereal doesn't support.");
-      goto error;
-    }
-    ld.save_file = save_file;
-    if (capture_opts.multi_files_on) {
-      save_file_fd = ringbuf_init(save_file,
-        capture_opts.ring_num_files);
-      if (save_file_fd != -1) {
-        ld.pdh = ringbuf_init_wtap_dump_fdopen(out_file_type, ld.linktype,
-          file_snaplen, &err);
-      } else {
-       err = errno;    /* "ringbuf_init()" failed */
-        ld.pdh = NULL;
-      }
-    } else {
-      ld.pdh = wtap_dump_open(save_file, out_file_type,
-                ld.linktype, file_snaplen, FALSE /* compress */, &err);
+
+  if (capture_opts.saving_to_file) {
+    /* open the output file (temporary/specified name/ringbuffer/named pipe/stdout) */
+    if (!capture_loop_open_output(&capture_opts, &save_file_fd, errmsg, sizeof(errmsg))) {
+      *secondary_errmsg = '\0';
+      goto error;    
     }
 
-    if (ld.pdh == NULL) {
-      g_snprintf(errmsg, sizeof errmsg,
-              cf_open_error_message(err, NULL, TRUE, out_file_type),
-              *save_file == '\0' ? "stdout" : save_file);
+    /* set up to write to the already-opened capture output file/files */
+    if(!capture_loop_init_output(&capture_opts, save_file_fd, &ld, errmsg, sizeof errmsg)) {
+      *secondary_errmsg = '\0';
       goto error;
     }
+
+    /* Save the capture file name. */
+    ld.save_file = capture_opts.save_file;
   }
 
-  /* Does "open_err_str" contain a non-empty string?  If so, "pcap_open_live()"
-     returned a warning; print it, but keep capturing. */
-  if (open_err_str[0] != '\0')
-    fprintf(stderr, "tethereal: WARNING: %s.\n", open_err_str);
+  ld.wtap_linktype = wtap_pcap_encap_to_wtap_encap(ld.linktype);
 
 #ifdef _WIN32
   /* Catch a CTRL+C event and, if we get it, clean up and exit. */
@@ -1745,21 +1616,21 @@ capture(char *save_file, int out_file_type)
   init_capture_stop_conditions();
   /* create stop conditions */
   if (capture_opts.has_autostop_filesize)
-    cnd_stop_capturesize = cnd_new((const char*)CND_CLASS_CAPTURESIZE,
+    cnd_autostop_size = cnd_new((const char*)CND_CLASS_CAPTURESIZE,
                                    (long)capture_opts.autostop_filesize * 1024);
   if (capture_opts.has_autostop_duration)
-    cnd_stop_timeout = cnd_new((const char*)CND_CLASS_TIMEOUT,
+    cnd_autostop_duration = cnd_new((const char*)CND_CLASS_TIMEOUT,
                                (gint32)capture_opts.autostop_duration);
 
   if (capture_opts.multi_files_on && capture_opts.has_file_duration)
-    cnd_ring_timeout = cnd_new(CND_CLASS_TIMEOUT, 
-                              capture_opts.file_duration);
+    cnd_file_duration = cnd_new(CND_CLASS_TIMEOUT, capture_opts.file_duration);
 
   if (!setjmp(ld.stopenv)) {
     ld.go = TRUE;
     ld.packet_count = 0;
   } else
     ld.go = FALSE;
+
   while (ld.go) {
     /* We need to be careful with automatic variables defined in the
        outer scope which are changed inside the loop.  Most compilers
@@ -1788,7 +1659,7 @@ capture(char *save_file, int out_file_type)
     int loop_err = 0;
     int packet_count_prev = 0;
 
-    if (cnd_stop_capturesize == NULL && cnd_stop_timeout == NULL) {
+    if (cnd_autostop_size == NULL && cnd_autostop_duration == NULL) {
       /* We're not stopping at a particular capture file size, and we're
          not stopping after some particular amount of time has expired,
          so either we have no stop condition or the only stop condition
@@ -1820,17 +1691,16 @@ capture(char *save_file, int out_file_type)
       pcap_cnt = 1;
     }
 #ifndef _WIN32
-    if (ld.from_pipe) {
-      inpkts = pipe_dispatch(pipe_fd, &ld, &hdr, &rechdr, pcap_data,
-        errmsg, sizeof errmsg);
+    if (ld.from_cap_pipe) {
+      inpkts = cap_pipe_dispatch(&ld, pcap_data, errmsg, sizeof errmsg);
     } else
 #endif
-      inpkts = pcap_dispatch(ld.pch, pcap_cnt, capture_pcap_cb, (u_char *) &ld);
+      inpkts = pcap_dispatch(ld.pcap_h, pcap_cnt, ld.packet_cb, (u_char *) &ld);
     if (inpkts < 0) {
       /* Error from "pcap_dispatch()", or error or "no more packets" from
-         "pipe_dispatch(). */
+         "cap_pipe_dispatch(). */
       ld.go = FALSE;
-    } else if (cnd_stop_timeout != NULL && cnd_eval(cnd_stop_timeout)) {
+    } else if (cnd_autostop_duration != NULL && cnd_eval(cnd_autostop_duration)) {
       /* The specified capture time has elapsed; stop the capture. */
       ld.go = FALSE;
     } else if (inpkts > 0) {
@@ -1840,19 +1710,18 @@ capture(char *save_file, int out_file_type)
            passed both any capture filter in effect and any read filter
            in effect. */
         ld.go = FALSE;
-      } else if (cnd_stop_capturesize != NULL &&
-                    cnd_eval(cnd_stop_capturesize,
-                              (guint32)wtap_get_bytes_dumped(ld.pdh))) {
+      } else if (cnd_autostop_size != NULL &&
+                    cnd_eval(cnd_autostop_size, (guint32)ld.bytes_written)) {
         /* We're saving the capture to a file, and the capture file reached
            its maximum size. */
         if (capture_opts.multi_files_on) {
           /* Switch to the next ringbuffer file */
-          if (ringbuf_switch_file(&ld.pdh, &save_file, &save_file_fd, &loop_err)) {
+          if (ringbuf_switch_file(&ld.pdh, &capture_opts.save_file, &save_file_fd, &loop_err)) {
             /* File switch succeeded: reset the condition */
-            cnd_reset(cnd_stop_capturesize);
-           if (cnd_ring_timeout) {
-             cnd_reset(cnd_ring_timeout);
-           }
+            cnd_reset(cnd_autostop_size);
+            if (cnd_file_duration) {
+              cnd_reset(cnd_file_duration);
+            }
           } else {
             /* File switch failed: stop here */
             volatile_err = loop_err;
@@ -1863,9 +1732,9 @@ capture(char *save_file, int out_file_type)
           ld.go = FALSE;
         }
       }
-      if (ld.output_to_pipe) {
+      if (capture_opts.output_to_pipe) {
         if (ld.packet_count > packet_count_prev) {
-          wtap_dump_flush(ld.pdh);
+          libpcap_dump_flush(ld.pdh, NULL);
           packet_count_prev = ld.packet_count;
         }
       }
@@ -1873,12 +1742,12 @@ capture(char *save_file, int out_file_type)
   } /* while (ld.go) */
 
   /* delete stop conditions */
-  if (cnd_stop_capturesize != NULL)
-    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 (cnd_autostop_size != NULL)
+    cnd_delete(cnd_autostop_size);
+  if (cnd_autostop_duration != NULL)
+    cnd_delete(cnd_autostop_duration);
+  if (cnd_file_duration != NULL)
+    cnd_delete(cnd_file_duration);
 
   if (print_packet_counts) {
     /* We're printing packet counts to stderr.
@@ -1889,56 +1758,50 @@ capture(char *save_file, int out_file_type)
   /* If we got an error while capturing, report it. */
   if (inpkts < 0) {
 #ifndef _WIN32
-    if (ld.from_pipe) {
-      if (ld.pipe_err == PIPERR) {
-        fprintf(stderr, "tethereal: Error while capturing packets: %s\n",
-         errmsg);
+    if (ld.from_cap_pipe) {
+      if (ld.cap_pipe_err == PIPERR) {
+        cmdarg_err("Error while capturing packets: %s", errmsg);
       }
     } else
 #endif
     {
-      fprintf(stderr, "tethereal: Error while capturing packets: %s\n",
-         pcap_geterr(ld.pch));
+      cmdarg_err("Error while capturing packets: %s", pcap_geterr(ld.pcap_h));
     }
   }
 
   if (volatile_err == 0)
-    write_err = FALSE;
+    write_ok = TRUE;
   else {
-    show_capture_file_io_error(save_file, volatile_err, FALSE);
-    write_err = TRUE;
+    show_capture_file_io_error(capture_opts.save_file, volatile_err, FALSE);
+    write_ok = FALSE;
   }
 
-  if (save_file != NULL) {
+  if (capture_opts.save_file != NULL) {
     /* We're saving to a file or files; close all files. */
-    if (capture_opts.multi_files_on) {
-      dump_ok = ringbuf_wtap_dump_close(&save_file, &err);
-    } else {
-      dump_ok = wtap_dump_close(ld.pdh, &err);
-    }
+    close_ok = capture_loop_close_output(&capture_opts, &ld, &err);
+
     /* If we've displayed a message about a write error, there's no point
        in displaying another message about an error on close. */
-    if (!dump_ok && !write_err)
-      show_capture_file_io_error(save_file, err, TRUE);
+    if (!close_ok && write_ok)
+      show_capture_file_io_error(capture_opts.save_file, err, TRUE);
   }
 
 #ifndef _WIN32
-  if (ld.from_pipe && pipe_fd >= 0)
-    eth_close(pipe_fd);
+  if (ld.from_cap_pipe && ld.cap_pipe_fd >= 0)
+    eth_close(ld.cap_pipe_fd);
   else
 #endif
   {
     /* Get the capture statistics, and, if any packets were dropped, report
        that. */
-    if (pcap_stats(ld.pch, &stats) >= 0) {
+    if (pcap_stats(ld.pcap_h, &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));
+      cmdarg_err("Can't get packet-drop statistics: %s", pcap_geterr(ld.pcap_h));
     }
-    pcap_close(ld.pch);
+    pcap_close(ld.pcap_h);
   }
 
   /* Report the number of captured packets if not reported during capture
@@ -1951,18 +1814,47 @@ error:
   if (capture_opts.multi_files_on) {
     ringbuf_error_cleanup();
   }
-  g_free(save_file);
-  save_file = NULL;
-  fprintf(stderr, "tethereal: %s\n", errmsg);
+  g_free(capture_opts.save_file);
+  capture_opts.save_file = NULL;
+  if (cfilter_error) {
+    dfilter_t   *rfcode = NULL;
+    if (dfilter_compile(capture_opts.cfilter, &rfcode) && rfcode != NULL) {
+      cmdarg_err(
+        "Invalid capture filter: \"%s\"!\n"
+        "\n"
+        "That string looks like a valid display filter; however, it isn't a valid\n"
+        "capture filter (%s).\n"
+        "\n"
+        "Note that display filters and capture filters don't have the same syntax,\n"
+        "so you can't use most display filter expressions as capture filters.\n"
+        "\n"
+        "See the User's Guide for a description of the capture filter syntax.",
+        capture_opts.cfilter, errmsg);
+      dfilter_free(rfcode);
+    } else {
+      cmdarg_err(
+        "Invalid capture filter: \"%s\"!\n"
+        "\n"
+        "That string isn't a valid capture filter (%s).\n"
+        "See the User's Guide for a description of the capture filter syntax.",
+        capture_opts.cfilter, errmsg);
+    }
+  } else {
+    cmdarg_err("%s", errmsg);
+    if (*secondary_errmsg != '\0') {
+      fprintf(stderr, "\n");
+      cmdarg_err_cont("%s", secondary_errmsg);
+    }
+  }
 #ifndef _WIN32
-  if (ld.from_pipe) {
-    if (pipe_fd >= 0)
-      eth_close(pipe_fd);
+  if (ld.from_cap_pipe) {
+    if (ld.cap_pipe_fd >= 0)
+      eth_close(ld.cap_pipe_fd);
   } else
 #endif
   {
-  if (ld.pch != NULL)
-    pcap_close(ld.pch);
+  if (ld.pcap_h != NULL)
+    pcap_close(ld.pcap_h);
   }
 
   return FALSE;
@@ -1974,18 +1866,12 @@ capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
 {
   struct wtap_pkthdr whdr;
   union wtap_pseudo_header pseudo_header;
-  loop_data *ldat = (loop_data *) user;
+  const guchar *wtap_pd;
+  loop_data *ld = (loop_data *) user;
   int loop_err;
   int err;
   int save_file_fd;
-
-  /* Convert from libpcap to Wiretap format.
-     If that fails, ignore the packet (wtap_process_pcap_packet has
-     written an error message). */
-  pd = wtap_process_pcap_packet(ldat->linktype, phdr, pd, &pseudo_header,
-                               &whdr, &err);
-  if (pd == NULL)
-    return;
+  gboolean packet_accepted;
 
 #ifdef SIGINFO
   /*
@@ -2001,29 +1887,63 @@ capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
    * the first packet of a new series of events as the last
    * [or only] packet in the file, switch before writing!
    */
-  if (cnd_ring_timeout != NULL && cnd_eval(cnd_ring_timeout)) {
+  if (cnd_file_duration != NULL && cnd_eval(cnd_file_duration)) {
     /* time elapsed for this ring file, switch to the next */
-    if (ringbuf_switch_file(&ldat->pdh, &ldat->save_file, &save_file_fd, &loop_err)) {
+    if (ringbuf_switch_file(&ld->pdh, &ld->save_file, &save_file_fd, &loop_err)) {
       /* File switch succeeded: reset the condition */
-      cnd_reset(cnd_ring_timeout);
+      cnd_reset(cnd_file_duration);
     } else {
       /* File switch failed: stop here */
       /* XXX - we should do something with "loop_err" */
-      ldat->go = FALSE;
+      ld->go = FALSE;
     }
   }
 
-  if (!process_packet(&cfile, ldat->pdh, 0, &whdr, &pseudo_header, pd, &err)) {
-    /* Error writing to a capture file */
+  if (do_dissection) {
+    /* We're goint to print packet information, run a read filter, or
+       process taps.  Use process_packet() to handle that; in order
+       to do that, we need to convert from libpcap to Wiretap format.
+       If that fails, ignore the packet (wtap_process_pcap_packet has
+       written an error message). */
+    wtap_pd = wtap_process_pcap_packet(ld->wtap_linktype, phdr, pd,
+                                       &pseudo_header, &whdr, &err);
+    if (wtap_pd == NULL)
+      return;
+
+    packet_accepted = process_packet(&cfile, 0, &whdr, &pseudo_header, wtap_pd);
+  } else {
+    /* We're just writing out packets. */
+    packet_accepted = TRUE;
+  }
+
+  if (packet_accepted) {
+    /* Count this packet. */
+#ifdef HAVE_LIBPCAP
+    ld->packet_count++;
+#endif
+
+    if (ld->pdh != NULL) {
+      if (!libpcap_write_packet(ld->pdh, phdr, pd, &ld->bytes_written, &err)) {
+        /* Error writing to a capture file */
+        if (print_packet_counts) {
+          /* We're printing counts of packets captured; move to the line after
+             the count. */
+          fprintf(stderr, "\n");
+        }
+        show_capture_file_io_error(ld->save_file, err, FALSE);
+        pcap_close(ld->pcap_h);
+        libpcap_dump_close(ld->pdh, &err);
+        exit(2);
+      }
+    }
     if (print_packet_counts) {
-      /* We're printing counts of packets captured; move to the line after
-         the count. */
-      fprintf(stderr, "\n");
+      /* We're printing packet counts. */
+      if (ld->packet_count != 0) {
+        fprintf(stderr, "\r%u ", ld->packet_count);
+        /* stderr could be line buffered */
+        fflush(stderr);
+      }
     }
-    show_capture_file_io_error(ldat->save_file, err, FALSE);
-    pcap_close(ldat->pch);
-    wtap_dump_close(ldat->pdh, &err);
-    exit(2);
   }
 
 #ifdef SIGINFO
@@ -2097,7 +2017,7 @@ report_counts(void)
     fprintf(stderr, "%u packets captured\n", ld.packet_count);
   }
 #ifdef SIGINFO
-  infoprint = FALSE;   /* we just reported it */
+  infoprint = FALSE; /* we just reported it */
 #endif /* SIGINFO */
 }
 
@@ -2127,52 +2047,49 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type)
   int          err;
   gchar        *err_info;
   long         data_offset;
+  char         *save_file_string = NULL;
 
   linktype = wtap_file_encap(cf->wth);
   if (save_file != NULL) {
+    /* Get a string that describes what we're writing to */
+    save_file_string = output_file_description(save_file);
+
     /* Set up to write to the capture file. */
     snapshot_length = wtap_snapshot_length(cf->wth);
     if (snapshot_length == 0) {
       /* Snapshot length of input file not known. */
       snapshot_length = WTAP_MAX_PACKET_SIZE;
     }
-    pdh = wtap_dump_open(save_file, out_file_type,
-               linktype, snapshot_length, FALSE /* compressed */, &err);
+    pdh = wtap_dump_open(save_file, out_file_type, linktype, snapshot_length,
+                         FALSE /* compressed */, &err);
 
     if (pdh == NULL) {
       /* We couldn't set up to write to the capture file. */
       switch (err) {
 
       case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
-        fprintf(stderr,
-               "tethereal: Capture files can't be written in that format.\n");
+        cmdarg_err("Capture files can't be written in that format.");
         break;
 
       case WTAP_ERR_UNSUPPORTED_ENCAP:
       case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
-        fprintf(stderr,
-          "tethereal: The capture file being read can't be written in "
-          "that format.\n");
+        cmdarg_err("The capture file being read can't be written in "
+          "that format.");
         break;
 
       case WTAP_ERR_CANT_OPEN:
-        fprintf(stderr,
-          "tethereal: The file \"%s\" couldn't be created for some "
-          "unknown reason.\n",
-            *save_file == '\0' ? "stdout" : save_file);
+        cmdarg_err("The %s couldn't be created for some "
+          "unknown reason.", save_file_string);
         break;
 
       case WTAP_ERR_SHORT_WRITE:
-        fprintf(stderr,
-          "tethereal: A full header couldn't be written to the file \"%s\".\n",
-               *save_file == '\0' ? "stdout" : save_file);
+        cmdarg_err("A full header couldn't be written to the %s.",
+                   save_file_string);
         break;
 
       default:
-        fprintf(stderr,
-          "tethereal: The file \"%s\" could not be created: %s\n.",
-               *save_file == '\0' ? "stdout" : save_file,
-               wtap_strerror(err));
+        cmdarg_err("The %s could not be created: %s.", save_file_string,
+                   wtap_strerror(err));
         break;
       }
       goto out;
@@ -2188,13 +2105,21 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type)
     pdh = NULL;
   }
   while (wtap_read(cf->wth, &err, &err_info, &data_offset)) {
-    if (!process_packet(cf, pdh, data_offset, wtap_phdr(cf->wth),
-                        wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth),
-                        &err)) {
-      /* Error writing to a capture file */
-      show_capture_file_io_error(save_file, err, FALSE);
-      wtap_dump_close(pdh, &err);
-      exit(2);
+    if (process_packet(cf, data_offset, wtap_phdr(cf->wth),
+                       wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth))) {
+      /* Either there's no read filtering or this packet passed the
+         filter, so, if we're writing to a capture file, write
+         this packet out. */
+      if (pdh != NULL) {
+        if (!wtap_dump(pdh, wtap_phdr(cf->wth),
+                       wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth),
+                       &err)) {
+          /* Error writing to a capture file */
+          show_capture_file_io_error(save_file, err, FALSE);
+          wtap_dump_close(pdh, &err);
+          exit(2);
+        }
+      }
     }
   }
   if (err != 0) {
@@ -2202,33 +2127,28 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type)
     switch (err) {
 
     case WTAP_ERR_UNSUPPORTED_ENCAP:
-      fprintf(stderr,
-"tethereal: \"%s\" has a packet with a network type that Tethereal doesn't support.\n(%s)\n",
-       cf->filename, err_info);
+      cmdarg_err("\"%s\" has a packet with a network type that Tethereal doesn't support.\n(%s)",
+                 cf->filename, err_info);
       break;
 
     case WTAP_ERR_CANT_READ:
-      fprintf(stderr,
-"tethereal: An attempt to read from \"%s\" failed for some unknown reason.\n",
-       cf->filename);
+      cmdarg_err("An attempt to read from \"%s\" failed for some unknown reason.",
+                 cf->filename);
       break;
 
     case WTAP_ERR_SHORT_READ:
-      fprintf(stderr,
-"tethereal: \"%s\" appears to have been cut short in the middle of a packet.\n",
-       cf->filename);
+      cmdarg_err("\"%s\" appears to have been cut short in the middle of a packet.",
+                 cf->filename);
       break;
 
     case WTAP_ERR_BAD_RECORD:
-      fprintf(stderr,
-"tethereal: \"%s\" appears to be damaged or corrupt.\n(%s)\n",
-       cf->filename, err_info);
+      cmdarg_err("\"%s\" appears to be damaged or corrupt.\n(%s)",
+                 cf->filename, err_info);
       break;
 
     default:
-      fprintf(stderr,
-"tethereal: An error occurred while reading \"%s\": %s.\n",
-       cf->filename, wtap_strerror(err));
+      cmdarg_err("An error occurred while reading \"%s\": %s.",
+                 cf->filename, wtap_strerror(err));
       break;
     }
     if (save_file != NULL) {
@@ -2255,12 +2175,15 @@ out:
   wtap_close(cf->wth);
   cf->wth = NULL;
 
+  if (save_file_string != NULL)
+    g_free(save_file_string);
+
   return err;
 }
 
 static void
 fill_in_fdata(frame_data *fdata, capture_file *cf,
-       const struct wtap_pkthdr *phdr, long offset)
+              const struct wtap_pkthdr *phdr, long offset)
 {
   fdata->next = NULL;
   fdata->prev = NULL;
@@ -2278,6 +2201,7 @@ fill_in_fdata(frame_data *fdata, capture_file *cf,
   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
@@ -2320,10 +2244,8 @@ clear_fdata(frame_data *fdata)
 }
 
 static gboolean
-process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
-               const struct wtap_pkthdr *whdr,
-               union wtap_pseudo_header *pseudo_header, const guchar *pd,
-               int *err)
+process_packet(capture_file *cf, long offset, const struct wtap_pkthdr *whdr,
+               union wtap_pseudo_header *pseudo_header, const guchar *pd)
 {
   frame_data fdata;
   gboolean create_proto_tree;
@@ -2387,27 +2309,7 @@ process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
   }
 
   if (passed) {
-    /* Count this packet. */
-#ifdef HAVE_LIBPCAP
-    ld.packet_count++;
-#endif
-
     /* Process this packet. */
-    if (pdh != NULL) {
-      /* We're writing to a capture file; write this packet. */
-      if (!wtap_dump(pdh, whdr, pseudo_header, pd, err))
-        return FALSE;
-#ifdef HAVE_LIBPCAP
-      if (print_packet_counts) {
-       /* We're printing packet counts. */
-        if (ld.packet_count != 0) {
-          fprintf(stderr, "\r%u ", ld.packet_count);
-          /* stderr could be line buffered */
-          fflush(stderr);
-        }
-      }
-#endif
-    }
     if (print_packet_info) {
       /* We're printing packet information; print the information for
          this packet. */
@@ -2447,57 +2349,53 @@ process_packet(capture_file *cf, wtap_dumper *pdh, long offset,
     epan_dissect_free(edt);
     clear_fdata(&fdata);
   }
-  return TRUE;
+  return passed;
 }
 
 static void
 show_capture_file_io_error(const char *fname, int err, gboolean is_close)
 {
-  if (*fname == '\0')
-    fname = "stdout";
+  char *save_file_string;
+
+  save_file_string = output_file_description(fname);
 
   switch (err) {
 
   case ENOSPC:
-    fprintf(stderr,
-"tethereal: Not all the packets could be written to \"%s\" because there is "
-"no space left on the file system.\n",
-       fname);
+    cmdarg_err("Not all the packets could be written to the %s because there is "
+               "no space left on the file system.",
+               save_file_string);
     break;
 
 #ifdef EDQUOT
   case EDQUOT:
-    fprintf(stderr,
-"tethereal: Not all the packets could be written to \"%s\" because you are "
-"too close to, or over your disk quota.\n",
-       fname);
+    cmdarg_err("Not all the packets could be written to the %s because you are "
+               "too close to, or over your disk quota.",
+               save_file_string);
   break;
 #endif
 
   case WTAP_ERR_CANT_CLOSE:
-    fprintf(stderr,
-"tethereal: \"%s\" couldn't be closed for some unknown reason.\n",
-       fname);
+    cmdarg_err("The %s couldn't be closed for some unknown reason.",
+               save_file_string);
     break;
 
   case WTAP_ERR_SHORT_WRITE:
-    fprintf(stderr,
-"tethereal: Not all the packets could be written to \"%s\".\n",
-       fname);
+    cmdarg_err("Not all the packets could be written to the %s.",
+               save_file_string);
     break;
 
   default:
     if (is_close) {
-      fprintf(stderr,
-"tethereal: \"%s\" could not be closed: %s.\n",
-       fname, wtap_strerror(err));
+      cmdarg_err("The %s could not be closed: %s.", save_file_string,
+                 wtap_strerror(err));
     } else {
-      fprintf(stderr,
-"tethereal: An error occurred while writing to \"%s\": %s.\n",
-       fname, wtap_strerror(err));
+      cmdarg_err("An error occurred while writing to the %s: %s.",
+                 save_file_string, wtap_strerror(err));
     }
     break;
   }
+  g_free(save_file_string);
 }
 
 static gboolean
@@ -2583,7 +2481,7 @@ print_columns(capture_file *cf)
     case COL_CLS_TIME:
     case COL_REL_TIME:
     case COL_ABS_TIME:
-    case COL_ABS_DATE_TIME:    /* XXX - wider */
+    case COL_ABS_DATE_TIME: /* XXX - wider */
       column_len = strlen(cf->cinfo.col_data[i]);
       if (column_len < 10)
         column_len = 10;
@@ -2862,22 +2760,19 @@ show_print_file_io_error(int err)
   switch (err) {
 
   case ENOSPC:
-    fprintf(stderr,
-"tethereal: Not all the packets could be printed because there is "
-"no space left on the file system.\n");
+    cmdarg_err("Not all the packets could be printed because there is "
+"no space left on the file system.");
     break;
 
 #ifdef EDQUOT
   case EDQUOT:
-    fprintf(stderr,
-"tethereal: Not all the packets could be printed because you are "
-"too close to, or over your disk quota.\n");
+    cmdarg_err("Not all the packets could be printed because you are "
+"too close to, or over your disk quota.");
   break;
 #endif
 
   default:
-    fprintf(stderr,
-"tethereal: An error occurred while printing packets: %s.\n",
+    cmdarg_err("An error occurred while printing packets: %s.",
       strerror(err));
     break;
   }
@@ -2915,8 +2810,8 @@ cf_open_error_message(int err, gchar *err_info, gboolean for_writing,
     case WTAP_ERR_CANT_WRITE_TO_PIPE:
       /* Seen only when opening a capture file for writing. */
       g_snprintf(errmsg_errno, sizeof(errmsg_errno),
-              "The file \"%%s\" is a pipe, and %s capture files can't be "
-              "written to a pipe.", wtap_file_type_string(file_type));
+                 "The file \"%%s\" is a pipe, and %s capture files can't be "
+                 "written to a pipe.", wtap_file_type_string(file_type));
       errmsg = errmsg_errno;
       break;
 
@@ -2971,9 +2866,9 @@ cf_open_error_message(int err, gchar *err_info, gboolean for_writing,
 
     default:
       g_snprintf(errmsg_errno, sizeof(errmsg_errno),
-              "The file \"%%s\" could not be %s: %s.",
-              for_writing ? "created" : "opened",
-              wtap_strerror(err));
+                 "The file \"%%s\" could not be %s: %s.",
+                 for_writing ? "created" : "opened",
+                 wtap_strerror(err));
       errmsg = errmsg_errno;
       break;
     }
@@ -3010,7 +2905,7 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
   init_dissection();
 
   cf->wth = wth;
-  cf->f_datalen = 0;   /* not used, but set it anyway */
+  cf->f_datalen = 0; /* not used, but set it anyway */
 
   /* Set the file name because we need it to set the follow stream filter.
      XXX - is that still true?  We need it for other reasons, though,
@@ -3042,316 +2937,128 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
 
 fail:
   g_snprintf(err_msg, sizeof err_msg,
-           cf_open_error_message(*err, err_info, FALSE, 0), fname);
-  fprintf(stderr, "tethereal: %s\n", err_msg);
+             cf_open_error_message(*err, err_info, FALSE, cf->cd_t), fname);
+  cmdarg_err("%s", err_msg);
   return CF_ERROR;
 }
 
-#ifdef HAVE_LIBPCAP
-#ifndef _WIN32
-/* Take care of byte order in the libpcap headers read from pipes.
- * (function taken from wiretap/libpcap.c) */
+
+/*
+ * General errors are reported with an console message in Tethereal.
+ */
 static void
-adjust_header(loop_data *ldat, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr)
+failure_message(const char *msg_format, va_list ap)
 {
-  if (ldat->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;
-  }
+  fprintf(stderr, "tethereal: ");
+  vfprintf(stderr, msg_format, ap);
+  fprintf(stderr, "\n");
 }
 
-/* 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 *ldat,
-                 char *errmsg, int errmsgl)
+/*
+ * Read errors are reported with an console message in Tethereal.
+ */
+static void
+read_failure_message(const char *filename, int err)
 {
-  struct stat pipe_stat;
-  int         fd;
-  guint32     magic;
-  int         b;
-  unsigned int bytes_read;
+  cmdarg_err("An error occurred while reading from the file \"%s\": %s.",
+          filename, strerror(err));
+}
 
-  /*
-   * XXX Tethereal blocks until we return
-   */
-  if (strcmp(pipename, "-") == 0)
-    fd = 0; /* read from stdin */
-  else {
-    if (eth_stat(pipename, &pipe_stat) < 0) {
-      if (errno == ENOENT || errno == ENOTDIR)
-        ldat->pipe_err = PIPNEXIST;
-      else {
-        g_snprintf(errmsg, errmsgl,
-          "The capture session could not be initiated "
-          "due to error on pipe: %s", strerror(errno));
-        ldat->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.
-         */
-         ldat->pipe_err = PIPNEXIST;
-      } else {
-        g_snprintf(errmsg, errmsgl,
-            "The capture session could not be initiated because\n"
-            "\"%s\" is neither an interface nor a pipe", pipename);
-        ldat->pipe_err = PIPERR;
-      }
-      return -1;
-    }
-    fd = eth_open(pipename, O_RDONLY, 0000 /* no creation so don't matter */);
-    if (fd == -1) {
-      g_snprintf(errmsg, errmsgl,
-          "The capture session could not be initiated "
-          "due to error on pipe open: %s", strerror(errno));
-      ldat->pipe_err = PIPERR;
-      return -1;
-    }
-  }
+/*
+ * Report an error in command-line arguments.
+ */
+void
+cmdarg_err(const char *fmt, ...)
+{
+  va_list ap;
 
-  ldat->from_pipe = TRUE;
+  va_start(ap, fmt);
+  fprintf(stderr, "tethereal: ");
+  vfprintf(stderr, fmt, ap);
+  fprintf(stderr, "\n");
+  va_end(ap);
+}
 
-  /* 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)
-        g_snprintf(errmsg, errmsgl, "End of file on pipe during open");
-      else
-        g_snprintf(errmsg, errmsgl, "Error on pipe during open: %s",
-          strerror(errno));
-      goto error;
-    }
-    bytes_read += b;
-  }
+/*
+ * Report additional information for an error in command-line arguments.
+ */
+void
+cmdarg_err_cont(const char *fmt, ...)
+{
+  va_list ap;
 
-  switch (magic) {
-  case PCAP_MAGIC:
-    /* Host that wrote it has our byte order, and was running
-       a program using either standard or ss990417 libpcap. */
-    ldat->byte_swapped = FALSE;
-    ldat->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. */
-    ldat->byte_swapped = FALSE;
-    ldat->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. */
-    ldat->byte_swapped = TRUE;
-    ldat->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. */
-    ldat->byte_swapped = TRUE;
-    ldat->modified = TRUE;
-    break;
-  default:
-    /* Not a "libpcap" type we know about. */
-    g_snprintf(errmsg, errmsgl, "Unrecognized libpcap format");
-    goto error;
-  }
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  fprintf(stderr, "\n");
+  va_end(ap);
+}
 
-  /* 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)
-        g_snprintf(errmsg, errmsgl, "End of file on pipe during open");
-      else
-        g_snprintf(errmsg, errmsgl, "Error on pipe during open: %s",
-          strerror(errno));
-      goto error;
-    }
-    bytes_read += b;
-  }
 
-  if (ldat->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);
-  }
+/****************************************************************************************************************/
+/* indication report "dummies", needed for capture_loop.c */
 
-  if (hdr->version_major < 2) {
-    g_snprintf(errmsg, errmsgl, "Unable to read old libpcap format");
-    goto error;
-  }
+#ifdef HAVE_LIBPCAP
 
-  ldat->pipe_state = STATE_EXPECT_REC_HDR;
-  ldat->pipe_err = PIPOK;
-  return fd;
+/** Report a new capture file having been opened. */
+void
+report_new_capture_file(const char *filename)
+{
+    /* shouldn't happen */
+    g_assert_not_reached();
+}
 
-error:
-  ldat->pipe_err = PIPERR;
-  eth_close(fd);
-  return -1;
+/** Report a number of new packets captured. */
+void
+report_packet_count(int packet_count)
+{
+    /* shouldn't happen */
+    g_assert_not_reached();
+}
 
+/** Report the packet drops once the capture finishes. */
+void
+report_packet_drops(int drops)
+{
+    /* shouldn't happen */
+    g_assert_not_reached();
 }
-/* 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 *ldat, struct pcap_hdr *hdr,
-                struct pcaprec_modified_hdr *rechdr, guchar *data,
-                char *errmsg, int errmsgl)
+/** Report an error in the capture. */
+void 
+report_capture_error(const char *errmsg, const char *secondary_error_msg)
 {
-  struct pcap_pkthdr phdr;
-  int b;
-  enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR,
-          PD_ERR } result;
-
-  switch (ldat->pipe_state) {
-
-  case STATE_EXPECT_REC_HDR:
-    ldat->bytes_to_read = ldat->modified ?
-      sizeof(struct pcaprec_modified_hdr) : sizeof(struct pcaprec_hdr);
-    ldat->bytes_read = 0;
-    ldat->pipe_state = STATE_READ_REC_HDR;
-    /* Fall through */
-
-  case STATE_READ_REC_HDR:
-    b = read(fd, ((char *)rechdr)+ldat->bytes_read,
-      ldat->bytes_to_read - ldat->bytes_read);
-    if (b <= 0) {
-      if (b == 0)
-        result = PD_PIPE_EOF;
-      else
-        result = PD_PIPE_ERR;
-      break;
-    }
-    if ((ldat->bytes_read += b) < ldat->bytes_to_read)
-        return 0;
-    result = PD_REC_HDR_READ;
-    break;
+    cmdarg_err(errmsg);
+    cmdarg_err_cont(secondary_error_msg);
+}
 
-  case STATE_EXPECT_DATA:
-    ldat->bytes_read = 0;
-    ldat->pipe_state = STATE_READ_DATA;
-    /* Fall through */
+/** Report an error with a capture filter. */
+void
+report_cfilter_error(const char *cfilter, const char *errmsg)
+{
 
-  case STATE_READ_DATA:
-    b = read(fd, data+ldat->bytes_read, rechdr->hdr.incl_len - ldat->bytes_read);
-    if (b <= 0) {
-      if (b == 0)
-        result = PD_PIPE_EOF;
-      else
-        result = PD_PIPE_ERR;
-      break;
-    }
-    if ((ldat->bytes_read += b) < rechdr->hdr.incl_len)
-      return 0;
-    result = PD_DATA_READ;
-    break;
+    cmdarg_err(
+      "Invalid capture filter: \"%s\"!\n"
+      "\n"
+      "That string isn't a valid capture filter (%s).\n"
+      "See the User's Guide for a description of the capture filter syntax.",
+      cfilter, errmsg);
+}
 
-  default:
-    g_snprintf(errmsg, errmsgl, "pipe_dispatch: invalid state");
-    result = PD_ERR;
+#endif /* HAVE_LIBPCAP */
 
-  } /* switch (ldat->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(ldat, hdr, &rechdr->hdr);
-    if (rechdr->hdr.incl_len > WTAP_MAX_PACKET_SIZE) {
-      g_snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)",
-        ldat->packet_count+1, rechdr->hdr.incl_len);
-      break;
-    }
-    ldat->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((u_char *)ldat, &phdr, data);
-
-    ldat->pipe_state = STATE_EXPECT_REC_HDR;
-    return 1;
-
-  case PD_PIPE_EOF:
-    ldat->pipe_err = PIPEOF;
-    return -1;
-
-  case PD_PIPE_ERR:
-    g_snprintf(errmsg, errmsgl, "Error reading from pipe: %s",
-      strerror(errno));
-    /* Fall through */
-  case PD_ERR:
-    break;
-  }
+/****************************************************************************************************************/
+/* signal pipe "dummies", needed for capture_loop.c */
 
-  ldat->pipe_err = PIPERR;
-  /* Return here rather than inside the switch to prevent GCC warning */
-  return -1;
-}
-#endif /* _WIN32 */
-#endif /* HAVE_LIBPCAP */
+#ifdef HAVE_LIBPCAP
 
-/*
- * General errors are reported with an console message in Tethereal.
- */
-static void
-failure_message(const char *msg_format, va_list ap)
+#ifdef _WIN32
+gboolean
+signal_pipe_check_running(void)
 {
-  fprintf(stderr, "tethereal: ");
-  vfprintf(stderr, msg_format, ap);
-  fprintf(stderr, "\n");
+    /* currently, no check required */
+    return TRUE;
 }
+#endif  /* _WIN32 */
 
-/*
- * Read errors are reported with an console message in Tethereal.
- */
-static void
-read_failure_message(const char *filename, int err)
-{
-  fprintf(stderr, "tethereal: An error occurred while reading from the file \"%s\": %s.\n",
-          filename, strerror(err));
-}
+#endif /* HAVE_LIBPCAP */