Update some links.
[obnox/wireshark/wip.git] / dumpcap.c
index 28c31ea4e273cd385f23bbf8bb09ba47b224a70b..30454d308aec631981f3745928156271fcca41df 100644 (file)
--- a/dumpcap.c
+++ b/dumpcap.c
@@ -62,7 +62,7 @@
 #ifdef HAVE_GETOPT_H
 #include <getopt.h>
 #else
-#include "wsgetopt.h"
+#include "wsutil/wsgetopt.h"
 #endif
 
 #ifdef HAVE_NETDB_H
@@ -95,7 +95,7 @@
 #endif
 
 #ifdef NEED_INET_V6DEFS_H
-# include "inet_v6defs.h"
+# include "wsutil/inet_v6defs.h"
 #endif
 
 #include <wsutil/privileges.h>
@@ -144,6 +144,11 @@ static GAsyncQueue *cap_pipe_pending_q, *cap_pipe_done_q;
 static GMutex *cap_pipe_read_mtx;
 #endif
 
+#ifdef SIGINFO
+static gboolean infodelay;     /* if TRUE, don't print capture info in SIGINFO handler */
+static gboolean infoprint;     /* if TRUE, print capture info after clearing infodelay */
+#endif /* SIGINFO */
+
 /** Stop a low-level capture (stops the capture child). */
 static void capture_loop_stop(void);
 
@@ -212,6 +217,10 @@ typedef struct _loop_data {
   int            err;                   /* if non-zero, error seen while capturing */
   gint           packet_count;          /* Number of packets we have already captured */
   gint           packet_max;            /* Number of packets we're supposed to capture - 0 means infinite */
+  gint           inpkts_to_sync_pipe;   /* Packets not already send out to the sync_pipe */
+#ifdef SIGINFO
+  gboolean       report_packet_count;   /* Set by SIGINFO handler; print packet count */
+#endif
 
   /* pcap "input file" */
   pcap_t        *pcap_h;                /* pcap handle */
@@ -244,13 +253,14 @@ typedef struct _loop_data {
        } cap_pipe_state;
   enum { PIPOK, PIPEOF, PIPERR, PIPNEXIST } cap_pipe_err;
 
-  /* output file */
+  /* output file(s) */
   FILE          *pdh;
+  int            save_file_fd;
   int            linktype;
   int            file_snaplen;
   gint           wtap_linktype;
   long           bytes_written;
-
+  guint32        autostop_files;
 } loop_data;
 
 /*
@@ -294,6 +304,7 @@ console_log_handler(const char *log_domain, GLogLevelFlags log_level,
 
 /* capture related options */
 static capture_options global_capture_opts;
+static gboolean quiet;
 
 static void capture_loop_packet_cb(u_char *user, const struct pcap_pkthdr *phdr,
   const u_char *pd);
@@ -308,6 +319,8 @@ static void report_packet_drops(guint32 drops);
 static void report_capture_error(const char *error_msg, const char *secondary_error_msg);
 static void report_cfilter_error(const char *cfilter, const char *errmsg);
 
+#define MSG_MAX_LENGTH 4096
+
 static void
 print_usage(gboolean print_ver) {
 
@@ -340,8 +353,11 @@ print_usage(gboolean print_ver) {
   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");
+#ifdef HAVE_BPF_IMAGE
+  fprintf(output, "  -d                       print generated BPF code for capture filter\n");
+#endif
   fprintf(output, "  -S                       print statistics for each interface once every second\n");
-  fprintf(output, "  -M                       for -D, -L, and -S produce machine-readable output\n");
+  fprintf(output, "  -M                       for -D, -L, and -S, produce machine-readable output\n");
   fprintf(output, "\n");
 #ifdef HAVE_PCAP_REMOTE
   fprintf(output, "\nRPCAP options:\n");
@@ -368,6 +384,7 @@ print_usage(gboolean print_ver) {
   fprintf(output, "  -n                       use pcapng format instead of pcap\n");
   /*fprintf(output, "\n");*/
   fprintf(output, "Miscellaneous:\n");
+  fprintf(output, "  -q                       don't report packet capture counts\n");
   fprintf(output, "  -v                       print version information and exit\n");
   fprintf(output, "  -h                       display this help and exit\n");
   fprintf(output, "\n");
@@ -459,6 +476,298 @@ cmdarg_err_cont(const char *fmt, ...)
   }
 }
 
+#ifdef HAVE_LIBCAP
+static void
+#if 0 /* Set to enable capability debugging */
+/* see 'man cap_to_text()' for explanation of output                         */
+/* '='   means 'all= '  ie: no capabilities                                  */
+/* '=ip' means 'all=ip' ie: all capabilities are permissible and inheritable */
+/* ....                                                                      */
+print_caps(const char *pfx) {
+    cap_t caps = cap_get_proc();
+    g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+          "%s: EUID: %d  Capabilities: %s", pfx,
+          geteuid(), cap_to_text(caps, NULL));
+    cap_free(caps);
+#else
+print_caps(const char *pfx _U_) {
+#endif
+}
+
+static void
+relinquish_all_capabilities(void)
+{
+    /* Drop any and all capabilities this process may have.            */
+    /* Allowed whether or not process has any privileges.              */
+    cap_t caps = cap_init();    /* all capabilities initialized to off */
+    print_caps("Pre-clear");
+    if (cap_set_proc(caps)) {
+        cmdarg_err("cap_set_proc() fail return: %s", strerror(errno));
+    }
+    print_caps("Post-clear");
+    cap_free(caps);
+}
+#endif
+
+static pcap_t *
+open_capture_device(capture_options *capture_opts,
+                    char (*open_err_str)[PCAP_ERRBUF_SIZE])
+{
+  pcap_t *pcap_h;
+#ifdef HAVE_PCAP_CREATE
+  int         err;
+#endif
+#ifdef HAVE_PCAP_REMOTE
+  struct pcap_rmtauth auth;
+#endif
+
+  /* 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';
+#ifdef HAVE_PCAP_OPEN
+  /*
+   * If we're opening a remote device, use pcap_open(); that's currently
+   * the only open routine that supports remote devices.
+   */
+  if (strncmp (capture_opts->iface, "rpcap://", 8) == 0) {
+    auth.type = capture_opts->auth_type == CAPTURE_AUTH_PWD ?
+      RPCAP_RMTAUTH_PWD : RPCAP_RMTAUTH_NULL;
+    auth.username = capture_opts->auth_username;
+    auth.password = capture_opts->auth_password;
+
+    pcap_h = pcap_open(capture_opts->iface,
+                       capture_opts->has_snaplen ? capture_opts->snaplen :
+                                                   WTAP_MAX_PACKET_SIZE,
+                       /* flags */
+                       (capture_opts->promisc_mode ? PCAP_OPENFLAG_PROMISCUOUS : 0) |
+                       (capture_opts->datatx_udp ? PCAP_OPENFLAG_DATATX_UDP : 0) |
+                       (capture_opts->nocap_rpcap ? PCAP_OPENFLAG_NOCAPTURE_RPCAP : 0),
+                       CAP_READ_TIMEOUT, &auth, *open_err_str);
+  } else
+#endif /* HAVE_PCAP_OPEN */
+  {
+    /*
+     * If we're not opening a remote device, use pcap_create() and
+     * pcap_activate() if we have them, so that we can set the buffer
+     * size, otherwise use pcap_open_live().
+     */
+#ifdef HAVE_PCAP_CREATE
+    pcap_h = pcap_create(capture_opts->iface, *open_err_str);
+    if (pcap_h != NULL) {
+      pcap_set_snaplen(pcap_h, capture_opts->has_snaplen ? capture_opts->snaplen : WTAP_MAX_PACKET_SIZE);
+      pcap_set_promisc(pcap_h, capture_opts->promisc_mode);
+      pcap_set_timeout(pcap_h, CAP_READ_TIMEOUT);
+
+      if (capture_opts->buffer_size > 1) {
+        pcap_set_buffer_size(pcap_h, capture_opts->buffer_size * 1024 * 1024);
+      }
+      if (capture_opts->monitor_mode)
+        pcap_set_rfmon(pcap_h, 1);
+      err = pcap_activate(pcap_h);
+      if (err < 0) {
+        /* Failed to activate, set to NULL */
+        if (err == PCAP_ERROR)
+          g_strlcpy(*open_err_str, pcap_geterr(pcap_h), sizeof *open_err_str);
+        else
+          g_strlcpy(*open_err_str, pcap_statustostr(err), sizeof *open_err_str);
+        pcap_close(pcap_h);
+        pcap_h = NULL;
+      }
+    }
+#else
+    pcap_h = pcap_open_live(capture_opts->iface,
+                            capture_opts->has_snaplen ? capture_opts->snaplen :
+                                                        WTAP_MAX_PACKET_SIZE,
+                            capture_opts->promisc_mode, CAP_READ_TIMEOUT,
+                            *open_err_str);
+#endif
+  }
+
+  /* If not using libcap: we now can now set euid/egid to ruid/rgid         */
+  /*  to remove any suid privileges.                                        */
+  /* If using libcap: we can now remove NET_RAW and NET_ADMIN capabilities  */
+  /*  (euid/egid have already previously been set to ruid/rgid.             */
+  /* (See comment in main() for details)                                    */
+#ifndef HAVE_LIBCAP
+  relinquish_special_privs_perm();
+#else
+  relinquish_all_capabilities();
+#endif
+
+  return pcap_h;
+}
+
+static void
+get_capture_device_open_failure_messages(const char *open_err_str,
+                                         const char *iface
+#ifndef _WIN32
+                                                           _U_
+#endif
+                                         ,
+                                         char *errmsg, size_t errmsg_len,
+                                         char *secondary_errmsg,
+                                         size_t secondary_errmsg_len)
+{
+  const char *libpcap_warn;
+  static const char ppamsg[] = "can't find PPA for ";
+
+  /* If we got a "can't find PPA for X" message, warn the user (who
+     is running dumcap 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 X" rather than "can't find PPA for X"). */
+  if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
+    libpcap_warn =
+      "\n\n"
+      "You are running (T)Wireshark with a version of the libpcap library\n"
+      "that doesn't handle HP-UX network devices well; this means that\n"
+      "(T)Wireshark 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, (gulong) errmsg_len,
+             "The capture session could not be initiated (%s).", open_err_str);
+#ifndef _WIN32
+  g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len,
+"Please check to make sure you have sufficient permissions, and that you have "
+"the proper interface or pipe specified.%s", libpcap_warn);
+#else
+  g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len,
+"\n"
+"Please check that \"%s\" is the proper interface.\n"
+"\n"
+"\n"
+"Help can be found at:\n"
+"\n"
+"       http://wiki.wireshark.org/WinPcap\n"
+"       http://wiki.wireshark.org/CaptureSetup\n",
+             iface);
+#endif /* _WIN32 */
+}
+
+/* Set the data link type on a pcap. */
+static gboolean
+set_pcap_linktype(pcap_t *pcap_h, capture_options *capture_opts,
+                  char *errmsg, size_t errmsg_len,
+                  char *secondary_errmsg, size_t secondary_errmsg_len)
+{
+  char *set_linktype_err_str;
+
+  if (capture_opts->linktype == -1)
+    return TRUE; /* just use the default */
+#ifdef HAVE_PCAP_SET_DATALINK
+  if (pcap_set_datalink(pcap_h, capture_opts->linktype) == 0)
+    return TRUE; /* no error */
+  set_linktype_err_str = pcap_geterr(pcap_h);
+#else
+  /* Let them set it to the type it is; reject any other request. */
+  if (get_pcap_linktype(pcap_h, capture_opts->iface) == capture_opts->linktype)
+    return TRUE; /* no error */
+  set_linktype_err_str =
+    "That DLT isn't one of the DLTs supported by this device";
+#endif
+  g_snprintf(errmsg, (gulong) errmsg_len, "Unable to set data link type (%s).",
+             set_linktype_err_str);
+  /*
+   * If the error isn't "XXX is not one of the DLTs supported by this device",
+   * tell the user to tell the Wireshark developers about it.
+   */
+  if (strstr(set_linktype_err_str, "is not one of the DLTs supported by this device") == NULL)
+    g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len, please_report);
+  else
+    secondary_errmsg[0] = '\0';
+  return FALSE;
+}
+
+static gboolean
+compile_capture_filter(const char *iface, pcap_t *pcap_h,
+                       struct bpf_program *fcode, char *cfilter)
+{
+  bpf_u_int32 netnum, netmask;
+  gchar       lookup_net_err_str[PCAP_ERRBUF_SIZE];
+
+  if (pcap_lookupnet(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 punt and use 0.  It might be nice to warn the user,
+     * but that's a pain in a GUI application, as it'd involve popping
+     * up a message box, and it's not clear how often this would make
+     * a difference (only filters that check for IP broadcast addresses
+     * use the netmask).
+     */
+    /*cmdarg_err(
+      "Warning:  Couldn't obtain netmask info (%s).", lookup_net_err_str);*/
+    netmask = 0;
+  }
+  if (pcap_compile(pcap_h, fcode, cfilter, 1, netmask) < 0)
+    return FALSE;
+  return TRUE;
+}
+
+#ifdef HAVE_BPF_IMAGE
+static gboolean
+show_filter_code(capture_options *capture_opts)
+{
+  pcap_t *pcap_h;
+  gchar open_err_str[PCAP_ERRBUF_SIZE];
+  char errmsg[MSG_MAX_LENGTH+1];
+  char secondary_errmsg[MSG_MAX_LENGTH+1];
+  struct bpf_program fcode;
+  struct bpf_insn *insn;
+  u_int i;
+
+  pcap_h = open_capture_device(capture_opts, &open_err_str);
+  if (pcap_h == NULL) {
+    /* Open failed; get messages */
+    get_capture_device_open_failure_messages(open_err_str,
+                                             capture_opts->iface,
+                                             errmsg, sizeof errmsg,
+                                             secondary_errmsg,
+                                             sizeof secondary_errmsg);
+    /* And report them */
+    report_capture_error(errmsg, secondary_errmsg);
+    return FALSE;
+  }
+
+  /* Set the link-layer type. */
+  if (!set_pcap_linktype(pcap_h, capture_opts, errmsg, sizeof errmsg,
+                         secondary_errmsg, sizeof secondary_errmsg)) {
+    pcap_close(pcap_h);
+    report_capture_error(errmsg, secondary_errmsg);
+    return FALSE;
+  }
+
+  /* OK, try to compile the capture filter. */
+  if (!compile_capture_filter(capture_opts->iface, pcap_h, &fcode,
+                              capture_opts->cfilter)) {
+    pcap_close(pcap_h);
+    report_cfilter_error(capture_opts->cfilter, errmsg);
+    return FALSE;
+  }
+  pcap_close(pcap_h);
+
+  if (capture_child) {
+    /* Let our parent know we succeeded. */
+    pipe_write_block(2, SP_SUCCESS, NULL);
+ }
+
+  /* Now print the filter code. */
+  insn = fcode.bf_insns;
+
+  for (i = 0; i < fcode.bf_len; insn++, i++)
+    printf("%s\n", bpf_image(insn, i));
+  return TRUE;
+}
+#endif
+
 /*
  * capture_interface_list() is expected to do the right thing to get
  * a list of interfaces.
@@ -478,30 +787,6 @@ capture_interface_list(int *err, char **err_str)
   return get_interface_list(err, err_str);
 }
 
-/*
- * Get the data-link types available for a libpcap device.
- */
-static data_link_info_t *
-create_data_link_info(int dlt)
-{
-    data_link_info_t *data_link_info;
-    const char *text;
-
-    data_link_info = (data_link_info_t *)g_malloc(sizeof (data_link_info_t));
-    data_link_info->dlt = dlt;
-    text = pcap_datalink_val_to_name(dlt);
-    if (text != NULL)
-        data_link_info->name = g_strdup(text);
-    else
-        data_link_info->name = g_strdup_printf("DLT %d", dlt);
-    text = pcap_datalink_val_to_description(dlt);
-    if (text != NULL)
-        data_link_info->description = g_strdup(text);
-    else
-        data_link_info->description = NULL;
-    return data_link_info;
-}
-
 /*
  * Get the data-link type for a libpcap device.
  * This works around AIX 5.x's non-standard and incompatible-with-the-
@@ -514,117 +799,136 @@ get_pcap_linktype(pcap_t *pch, const char *devname
 #endif
 )
 {
-       int linktype;
+  int linktype;
 #ifdef _AIX
-       const char *ifacename;
+  const char *ifacename;
 #endif
 
-       linktype = pcap_datalink(pch);
+  linktype = pcap_datalink(pch);
 #ifdef _AIX
 
-       /*
-        * The libpcap that comes with AIX 5.x uses RFC 1573 ifType values
-        * rather than DLT_ values for link-layer types; the ifType values
-        * for LAN devices are:
-        *
-        *      Ethernet        6
-        *      802.3           7
-        *      Token Ring      9
-        *      FDDI            15
-        *
-        * and the ifType value for a loopback device is 24.
-        *
-        * The AIX names for LAN devices begin with:
-        *
-        *      Ethernet                en
-        *      802.3                   et
-        *      Token Ring              tr
-        *      FDDI                    fi
-        *
-        * and the AIX names for loopback devices begin with "lo".
-        *
-        * (The difference between "Ethernet" and "802.3" is presumably
-        * whether packets have an Ethernet header, with a packet type,
-        * or an 802.3 header, with a packet length, followed by an 802.2
-        * header and possibly a SNAP header.)
-        *
-        * If the device name matches "linktype" interpreted as an ifType
-        * value, rather than as a DLT_ value, we will assume this is AIX's
-        * non-standard, incompatible libpcap, rather than a standard libpcap,
-        * and will map the link-layer type to the standard DLT_ value for
-        * that link-layer type, as that's what the rest of Wireshark expects.
-        *
-        * (This means the capture files won't be readable by a tcpdump
-        * linked with AIX's non-standard libpcap, but so it goes.  They
-        * *will* be readable by standard versions of tcpdump, Wireshark,
-        * and so on.)
-        *
-        * XXX - if we conclude we're using AIX libpcap, should we also
-        * set a flag to cause us to assume the time stamps are in
-        * seconds-and-nanoseconds form, and to convert them to
-        * seconds-and-microseconds form before processing them and
-        * writing them out?
-        */
-
-       /*
-        * Find the last component of the device name, which is the
-        * interface name.
-        */
-       ifacename = strchr(devname, '/');
-       if (ifacename == NULL)
-               ifacename = devname;
-
-       /* See if it matches any of the LAN device names. */
-       if (strncmp(ifacename, "en", 2) == 0) {
-               if (linktype == 6) {
-                       /*
-                        * That's the RFC 1573 value for Ethernet; map it
-                        * to DLT_EN10MB.
-                        */
-                       linktype = 1;
-               }
-       } else if (strncmp(ifacename, "et", 2) == 0) {
-               if (linktype == 7) {
-                       /*
-                        * That's the RFC 1573 value for 802.3; map it to
-                        * DLT_EN10MB.
-                        * (libpcap, tcpdump, Wireshark, etc. don't care if
-                        * it's Ethernet or 802.3.)
-                        */
-                       linktype = 1;
-               }
-       } else if (strncmp(ifacename, "tr", 2) == 0) {
-               if (linktype == 9) {
-                       /*
-                        * That's the RFC 1573 value for 802.5 (Token Ring);
-                        * map it to DLT_IEEE802, which is what's used for
-                        * Token Ring.
-                        */
-                       linktype = 6;
-               }
-       } else if (strncmp(ifacename, "fi", 2) == 0) {
-               if (linktype == 15) {
-                       /*
-                        * That's the RFC 1573 value for FDDI; map it to
-                        * DLT_FDDI.
-                        */
-                       linktype = 10;
-               }
-       } else if (strncmp(ifacename, "lo", 2) == 0) {
-               if (linktype == 24) {
-                       /*
-                        * That's the RFC 1573 value for "software loopback"
-                        * devices; map it to DLT_NULL, which is what's used
-                        * for loopback devices on BSD.
-                        */
-                       linktype = 0;
-               }
-       }
-#endif
-
-       return linktype;
+  /*
+   * The libpcap that comes with AIX 5.x uses RFC 1573 ifType values
+   * rather than DLT_ values for link-layer types; the ifType values
+   * for LAN devices are:
+   *
+   *   Ethernet        6
+   *   802.3           7
+   *   Token Ring      9
+   *   FDDI            15
+   *
+   * and the ifType value for a loopback device is 24.
+   *
+   * The AIX names for LAN devices begin with:
+   *
+   *   Ethernet                en
+   *   802.3                   et
+   *   Token Ring              tr
+   *   FDDI                    fi
+   *
+   * and the AIX names for loopback devices begin with "lo".
+   *
+   * (The difference between "Ethernet" and "802.3" is presumably
+   * whether packets have an Ethernet header, with a packet type,
+   * or an 802.3 header, with a packet length, followed by an 802.2
+   * header and possibly a SNAP header.)
+   *
+   * If the device name matches "linktype" interpreted as an ifType
+   * value, rather than as a DLT_ value, we will assume this is AIX's
+   * non-standard, incompatible libpcap, rather than a standard libpcap,
+   * and will map the link-layer type to the standard DLT_ value for
+   * that link-layer type, as that's what the rest of Wireshark expects.
+   *
+   * (This means the capture files won't be readable by a tcpdump
+   * linked with AIX's non-standard libpcap, but so it goes.  They
+   * *will* be readable by standard versions of tcpdump, Wireshark,
+   * and so on.)
+   *
+   * XXX - if we conclude we're using AIX libpcap, should we also
+   * set a flag to cause us to assume the time stamps are in
+   * seconds-and-nanoseconds form, and to convert them to
+   * seconds-and-microseconds form before processing them and
+   * writing them out?
+   */
+
+  /*
+   * Find the last component of the device name, which is the
+   * interface name.
+   */
+  ifacename = strchr(devname, '/');
+  if (ifacename == NULL)
+    ifacename = devname;
+
+  /* See if it matches any of the LAN device names. */
+  if (strncmp(ifacename, "en", 2) == 0) {
+    if (linktype == 6) {
+      /*
+       * That's the RFC 1573 value for Ethernet; map it to DLT_EN10MB.
+       */
+      linktype = 1;
+    }
+  } else if (strncmp(ifacename, "et", 2) == 0) {
+    if (linktype == 7) {
+      /*
+       * That's the RFC 1573 value for 802.3; map it to DLT_EN10MB.
+       * (libpcap, tcpdump, Wireshark, etc. don't care if it's Ethernet
+       * or 802.3.)
+       */
+      linktype = 1;
+    }
+  } else if (strncmp(ifacename, "tr", 2) == 0) {
+    if (linktype == 9) {
+      /*
+       * That's the RFC 1573 value for 802.5 (Token Ring); map it to
+       * DLT_IEEE802, which is what's used for Token Ring.
+       */
+      linktype = 6;
+    }
+  } else if (strncmp(ifacename, "fi", 2) == 0) {
+    if (linktype == 15) {
+      /*
+       * That's the RFC 1573 value for FDDI; map it to DLT_FDDI.
+       */
+      linktype = 10;
+    }
+  } else if (strncmp(ifacename, "lo", 2) == 0) {
+    if (linktype == 24) {
+      /*
+       * That's the RFC 1573 value for "software loopback" devices; map it
+       * to DLT_NULL, which is what's used for loopback devices on BSD.
+       */
+      linktype = 0;
+    }
+  }
+#endif
+
+  return linktype;
 }
 
+static data_link_info_t *
+create_data_link_info(int dlt)
+{
+  data_link_info_t *data_link_info;
+  const char *text;
+
+  data_link_info = (data_link_info_t *)g_malloc(sizeof (data_link_info_t));
+  data_link_info->dlt = dlt;
+  text = pcap_datalink_val_to_name(dlt);
+  if (text != NULL)
+    data_link_info->name = g_strdup(text);
+  else
+    data_link_info->name = g_strdup_printf("DLT %d", dlt);
+  text = pcap_datalink_val_to_description(dlt);
+  if (text != NULL)
+    data_link_info->description = g_strdup(text);
+  else
+    data_link_info->description = NULL;
+  return data_link_info;
+}
+
+/*
+ * Get the capabilities of a network device.
+ */
 static if_capabilities_t *
 get_if_capabilities(const char *devname, gboolean monitor_mode
 #ifndef HAVE_PCAP_CREATE
@@ -667,38 +971,29 @@ get_if_capabilities(const char *devname, gboolean monitor_mode
         g_free(caps);
         return NULL;
     }
-    status = pcap_can_set_rfmon(pch); 
-    switch (status) {
-
-    case 0:
-        caps->can_set_rfmon = FALSE;
-        break;
-
-    case 1:
-        caps->can_set_rfmon = TRUE;
-        if (monitor_mode)
-               pcap_set_rfmon(pch, 1);
-        break;
-
-    case PCAP_ERROR_NO_SUCH_DEVICE:
-        if (err_str != NULL)
-            *err_str = g_strdup_printf("There is no capture device named \"%s\"", devname);
-        pcap_close(pch);
-        g_free(caps);
-        return NULL;
-
-    case PCAP_ERROR:
-        if (err_str != NULL)
-            *err_str = g_strdup_printf("pcap_can_set_rfmon on \"%s\" failed: %s",
-                                       devname, pcap_geterr(pch));
+    status = pcap_can_set_rfmon(pch);
+    if (status < 0) {
+        /* Error. */
+        if (status == PCAP_ERROR)
+            *err_str = g_strdup_printf("pcap_can_set_rfmon() failed: %s",
+                                       pcap_geterr(pch));
+        else
+            *err_str = g_strdup(pcap_statustostr(status));
         pcap_close(pch);
         g_free(caps);
         return NULL;
-
-    default:
-        if (err_str != NULL)
-            *err_str = g_strdup_printf("pcap_can_set_rfmon on \"%s\" failed: %s",
-                                       devname, pcap_statustostr(status));
+    }
+    if (status == 0)
+        caps->can_set_rfmon = FALSE;
+    else if (status == 1) {
+        caps->can_set_rfmon = TRUE;
+        if (monitor_mode)
+            pcap_set_rfmon(pch, 1);
+    } else {
+        if (err_str != NULL) {
+            *err_str = g_strdup_printf("pcap_can_set_rfmon() returned %d",
+                                       status);
+        }
         pcap_close(pch);
         g_free(caps);
         return NULL;
@@ -708,13 +1003,11 @@ get_if_capabilities(const char *devname, gboolean monitor_mode
     if (status < 0) {
         /* Error.  We ignore warnings (status > 0). */
         if (err_str != NULL) {
-            if (status == PCAP_ERROR) {
-                *err_str = g_strdup_printf("pcap_activate on %s failed: %s",
-                                           devname, pcap_geterr(pch));
-            } else {
-                *err_str = g_strdup_printf("pcap_activate on %s failed: %s",
-                                           devname, pcap_statustostr(status));
-            }
+            if (status == PCAP_ERROR)
+                *err_str = g_strdup_printf("pcap_activate() failed: %s",
+                                           pcap_geterr(pch));
+            else
+                *err_str = g_strdup(pcap_statustostr(status));
         }
         pcap_close(pch);
         g_free(caps);
@@ -1046,6 +1339,39 @@ capture_cleanup_handler(int signum _U_)
 }
 #endif
 
+
+#ifdef SIGINFO
+static void
+report_counts(void)
+{
+  /* Don't print this if we're a capture child. */
+  if (!capture_child) {
+    if (quiet) {
+      /* Report the count only if we aren't printing a packet count
+         as packets arrive. */
+      fprintf(stderr, "%u packet%s captured\n", global_ld.packet_count,
+              plurality(global_ld.packet_count, "", "s"));
+    }
+  }
+  infoprint = FALSE; /* we just reported it */
+}
+
+static void
+report_counts_siginfo(int signum _U_)
+{
+  int sav_errno = errno;
+
+  /* If we've been told to delay printing, just set a flag asking
+     that we print counts (if we're supposed to), otherwise print
+     the count of packets captured (if we're supposed to). */
+  if (infodelay)
+    infoprint = TRUE;
+  else
+    report_counts();
+  errno = sav_errno;
+}
+#endif /* SIGINFO */
+
 static void exit_main(int status)
 {
 #ifdef _WIN32
@@ -1069,24 +1395,6 @@ static void exit_main(int status)
  * CAP_NET_ADMIN and CAP_NET_RAW, then relinquish our permissions.
  * (See comment in main() for details)
  */
-
-static void
-#if 0 /* Set to enable capability debugging */
-/* see 'man cap_to_text()' for explanation of output                         */
-/* '='   means 'all= '  ie: no capabilities                                  */
-/* '=ip' means 'all=ip' ie: all capabilities are permissible and inheritable */
-/* ....                                                                      */
-print_caps(const char *pfx) {
-    cap_t caps = cap_get_proc();
-    g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
-          "%s: EUID: %d  Capabilities: %s", pfx,
-          geteuid(), cap_to_text(caps, NULL));
-    cap_free(caps);
-#else
-print_caps(const char *pfx _U_) {
-#endif
-}
-
 static void
 relinquish_privs_except_capture(void)
 {
@@ -1132,43 +1440,8 @@ relinquish_privs_except_capture(void)
     }
 }
 
-
-static void
-relinquish_all_capabilities(void)
-{
-    /* Drop any and all capabilities this process may have.            */
-    /* Allowed whether or not process has any privileges.              */
-    cap_t caps = cap_init();    /* all capabilities initialized to off */
-    print_caps("Pre-clear");
-    if (cap_set_proc(caps)) {
-        cmdarg_err("cap_set_proc() fail return: %s", strerror(errno));
-    }
-    print_caps("Post-clear");
-    cap_free(caps);
-}
-
 #endif /* HAVE_LIBCAP */
 
-/* Set the data link type on a pcap. */
-static const char *
-set_pcap_linktype(pcap_t *pch, char *devname
-#ifdef HAVE_PCAP_SET_DATALINK
-       _U_
-#endif
-       , int dlt)
-{
-#ifdef HAVE_PCAP_SET_DATALINK
-       if (pcap_set_datalink(pch, dlt) == 0)
-               return NULL;    /* no error */
-       return pcap_geterr(pch);
-#else
-       /* Let them set it to the type it is; reject any other request. */
-       if (get_pcap_linktype(pch, devname) == dlt)
-               return NULL;    /* no error */
-       return "That DLT isn't one of the DLTs supported by this device";
-#endif
-}
-
 /* Take care of byte order in the libpcap headers read from pipes.
  * (function taken from wiretap/libpcap.c) */
 static void
@@ -1844,19 +2117,12 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
 {
   gchar       open_err_str[PCAP_ERRBUF_SIZE];
   gchar      *sync_msg_str;
-  static const char ppamsg[] = "can't find PPA for ";
-  const char *set_linktype_err_str;
-  const char *libpcap_warn;
-  int         err;
 #ifdef _WIN32
+  int         err;
   gchar      *sync_secondary_msg_str;
   WORD        wVersionRequested;
   WSADATA     wsaData;
 #endif
-#ifdef HAVE_PCAP_REMOTE
-  struct pcap_rmtauth auth;
-#endif
-
 
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_open_input : %s", capture_opts->iface);
 
@@ -1909,80 +2175,7 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
   }
 #endif
 
-  /* 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';
-#ifdef HAVE_PCAP_OPEN
-  /*
-   * If we're opening a remote device, use pcap_open(); that's currently
-   * the only open routine that supports remote devices.
-   */
-  if (strncmp (capture_opts->iface, "rpcap://", 8) == 0) {
-    auth.type = capture_opts->auth_type == CAPTURE_AUTH_PWD ?
-      RPCAP_RMTAUTH_PWD : RPCAP_RMTAUTH_NULL;
-    auth.username = capture_opts->auth_username;
-    auth.password = capture_opts->auth_password;
-
-    ld->pcap_h = pcap_open(capture_opts->iface,
-                 capture_opts->has_snaplen ? capture_opts->snaplen :
-                            WTAP_MAX_PACKET_SIZE,
-                 /* flags */
-                 (capture_opts->promisc_mode ? PCAP_OPENFLAG_PROMISCUOUS : 0) |
-                 (capture_opts->datatx_udp ? PCAP_OPENFLAG_DATATX_UDP : 0) |
-                 (capture_opts->nocap_rpcap ? PCAP_OPENFLAG_NOCAPTURE_RPCAP : 0),
-                 CAP_READ_TIMEOUT, &auth, open_err_str);
-  } else
-#endif /* HAVE_PCAP_OPEN */
-  {
-    /*
-     * If we're not opening a remote device, use pcap_create() and
-     * pcap_activate() if we have them, so that we can set the buffer
-     * size, otherwise use pcap_open_live().
-     */
-#ifdef HAVE_PCAP_CREATE
-    ld->pcap_h = pcap_create(capture_opts->iface, open_err_str);
-    if (ld->pcap_h != NULL) {
-      pcap_set_snaplen(ld->pcap_h, capture_opts->has_snaplen ? capture_opts->snaplen : WTAP_MAX_PACKET_SIZE);
-      pcap_set_promisc(ld->pcap_h, capture_opts->promisc_mode);
-      pcap_set_timeout(ld->pcap_h, CAP_READ_TIMEOUT);
-
-      if (capture_opts->buffer_size > 1) {
-        pcap_set_buffer_size(ld->pcap_h, capture_opts->buffer_size * 1024 * 1024);
-      }
-      if (capture_opts->monitor_mode)
-        pcap_set_rfmon(ld->pcap_h, 1);
-      err = pcap_activate(ld->pcap_h);
-      if (err < 0) {
-        /* Failed to activate, set to NULL */
-        if (err == PCAP_ERROR)
-          g_strlcpy(open_err_str, pcap_geterr(ld->pcap_h), sizeof open_err_str);
-        else
-          g_strlcpy(open_err_str, pcap_statustostr(err), sizeof open_err_str);
-        pcap_close(ld->pcap_h);
-        ld->pcap_h = NULL;
-      }
-    }
-#else
-    ld->pcap_h = pcap_open_live(capture_opts->iface,
-                                capture_opts->has_snaplen ? capture_opts->snaplen :
-                                                            WTAP_MAX_PACKET_SIZE,
-                                capture_opts->promisc_mode, CAP_READ_TIMEOUT,
-                                open_err_str);
-#endif
-  }
-
-  /* If not using libcap: we now can now set euid/egid to ruid/rgid         */
-  /*  to remove any suid privileges.                                        */
-  /* If using libcap: we can now remove NET_RAW and NET_ADMIN capabilities  */
-  /*  (euid/egid have already previously been set to ruid/rgid.             */
-  /* (See comment in main() for details)                                    */
-#ifndef HAVE_LIBCAP
-  relinquish_special_privs_perm();
-#else
-  relinquish_all_capabilities();
-#endif
+  ld->pcap_h = open_capture_device(capture_opts, &open_err_str);
 
   if (ld->pcap_h != NULL) {
     /* we've opened "iface" as a network device */
@@ -2041,16 +2234,9 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
 #endif
 
     /* setting the data link type only works on real interfaces */
-    if (capture_opts->linktype != -1) {
-      set_linktype_err_str = set_pcap_linktype(ld->pcap_h, capture_opts->iface,
-        capture_opts->linktype);
-      if (set_linktype_err_str != NULL) {
-        g_snprintf(errmsg, (gulong) errmsg_len, "Unable to set data link type (%s).",
-                set_linktype_err_str);
-        g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len, please_report);
-        return FALSE;
-      }
-    }
+    if (!set_pcap_linktype(ld->pcap_h, capture_opts, errmsg, errmsg_len,
+                           secondary_errmsg, secondary_errmsg_len))
+      return FALSE;
     ld->linktype = get_pcap_linktype(ld->pcap_h, capture_opts->iface);
   } else {
     /* We couldn't open "iface" as a network device. */
@@ -2065,44 +2251,12 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
 
       if (ld->cap_pipe_err == PIPNEXIST) {
         /* Pipe doesn't exist, so output message for interface */
-
-        /* If we got a "can't find PPA for X" message, warn the user (who
-           is running (T)Wireshark 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 X" rather than "can't find PPA for X"). */
-        if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
-          libpcap_warn =
-            "\n\n"
-            "You are running (T)Wireshark with a version of the libpcap library\n"
-            "that doesn't handle HP-UX network devices well; this means that\n"
-            "(T)Wireshark 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, (gulong) errmsg_len,
-          "The capture session could not be initiated (%s).", open_err_str);
-#ifndef _WIN32
-        g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len,
-"Please check to make sure you have sufficient permissions, and that you have "
-"the proper interface or pipe specified.%s", libpcap_warn);
-#else
-    g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len,
-"\n"
-"Please check that \"%s\" is the proper interface.\n"
-"\n"
-"\n"
-"Help can be found at:\n"
-"\n"
-"       http://wiki.wireshark.org/WinPcap\n"
-"       http://wiki.wireshark.org/CaptureSetup\n",
-    capture_opts->iface);
-#endif /* _WIN32 */
+        get_capture_device_open_failure_messages(open_err_str,
+                                                 capture_opts->iface,
+                                                 errmsg,
+                                                 errmsg_len,
+                                                 secondary_errmsg,
+                                                 secondary_errmsg_len);
       }
       /*
        * Else pipe (or file) does exist and cap_pipe_open_live() has
@@ -2137,7 +2291,6 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
   return TRUE;
 }
 
-
 /* close the capture input file (pcap or capture pipe) */
 static void capture_loop_close_input(loop_data *ld) {
 
@@ -2176,32 +2329,17 @@ static void capture_loop_close_input(loop_data *ld) {
 
 /* init the capture filter */
 static initfilter_status_t
-capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, gchar * iface, gchar * cfilter) {
-  bpf_u_int32 netnum, netmask;
-  gchar       lookup_net_err_str[PCAP_ERRBUF_SIZE];
+capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe,
+                         gchar * iface, gchar * cfilter)
+{
   struct bpf_program fcode;
 
-
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_init_filter: %s", cfilter);
 
   /* capture filters only work on real interfaces */
   if (cfilter && !from_cap_pipe) {
     /* A capture filter was specified; set it up. */
-    if (pcap_lookupnet(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 punt and use 0.  It might be nice to warn the user,
-       * but that's a pain in a GUI application, as it'd involve popping
-       * up a message box, and it's not clear how often this would make
-       * a difference (only filters that check for IP broadcast addresses
-       * use the netmask).
-       */
-      /*cmdarg_err(
-        "Warning:  Couldn't obtain netmask info (%s).", lookup_net_err_str);*/
-      netmask = 0;
-    }
-    if (pcap_compile(pcap_h, &fcode, cfilter, 1, netmask) < 0) {
+    if (!compile_capture_filter(iface, pcap_h, &fcode, cfilter)) {
       /* Treat this specially - our caller might try to compile this
          as a display filter and, if that succeeds, warn the user that
          the display and capture filter syntaxes are different. */
@@ -2224,7 +2362,7 @@ capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, gchar * iface,
 
 /* set up to write to the already-opened capture output file/files */
 static gboolean
-capture_loop_init_output(capture_options *capture_opts, int save_file_fd, loop_data *ld, char *errmsg, int errmsg_len) {
+capture_loop_init_output(capture_options *capture_opts, loop_data *ld, char *errmsg, int errmsg_len) {
   int         err;
 
 
@@ -2242,7 +2380,7 @@ capture_loop_init_output(capture_options *capture_opts, int save_file_fd, loop_d
   if (capture_opts->multi_files_on) {
     ld->pdh = ringbuf_init_libpcap_fdopen(&err);
   } else {
-    ld->pdh = libpcap_fdopen(save_file_fd, &err);
+    ld->pdh = libpcap_fdopen(ld->save_file_fd, &err);
   }
   if (ld->pdh) {
     gboolean successful;
@@ -2591,6 +2729,67 @@ capture_loop_open_output(capture_options *capture_opts, int *save_file_fd,
 #define TIME_GET() time(NULL)
 #endif
 
+/* Do the work of handling either the file size or file duration capture
+   conditions being reached, and switching files or stopping. */
+static gboolean
+do_file_switch_or_stop(capture_options *capture_opts,
+                       condition *cnd_autostop_files,
+                       condition *cnd_autostop_size,
+                       condition *cnd_file_duration)
+{
+  if (capture_opts->multi_files_on) {
+    if (cnd_autostop_files != NULL &&
+        cnd_eval(cnd_autostop_files, ++global_ld.autostop_files)) {
+      /* no files left: stop here */
+      global_ld.go = FALSE;
+      return FALSE;
+    }
+
+    /* Switch to the next ringbuffer file */
+    if (ringbuf_switch_file(&global_ld.pdh, &capture_opts->save_file,
+                            &global_ld.save_file_fd, &global_ld.err)) {
+      gboolean successful;
+
+      /* File switch succeeded: reset the conditions */
+      global_ld.bytes_written = 0;
+      if (capture_opts->use_pcapng) {
+        char appname[100];
+
+        g_snprintf(appname, sizeof(appname), "Dumpcap " VERSION "%s", wireshark_svnversion);
+        successful = libpcap_write_session_header_block(global_ld.pdh, appname, &global_ld.bytes_written, &global_ld.err) &&
+                     libpcap_write_interface_description_block(global_ld.pdh, capture_opts->iface, capture_opts->cfilter, global_ld.linktype, global_ld.file_snaplen, &global_ld.bytes_written, &global_ld.err);
+      } else {
+        successful = libpcap_write_file_header(global_ld.pdh, global_ld.linktype, global_ld.file_snaplen,
+                                               &global_ld.bytes_written, &global_ld.err);
+      }
+      if (!successful) {
+        fclose(global_ld.pdh);
+        global_ld.pdh = NULL;
+        global_ld.go = FALSE;
+        return FALSE;
+      }
+      if(cnd_autostop_size)
+        cnd_reset(cnd_autostop_size);
+      if(cnd_file_duration)
+        cnd_reset(cnd_file_duration);
+      libpcap_dump_flush(global_ld.pdh, NULL);
+      if (!quiet)
+        report_packet_count(global_ld.inpkts_to_sync_pipe);
+      global_ld.inpkts_to_sync_pipe = 0;
+      report_new_capture_file(capture_opts->save_file);
+    } else {
+      /* File switch failed: stop here */
+      global_ld.go = FALSE;
+      return FALSE;
+    }
+  } else {
+    /* single file, stop now */
+    global_ld.go = FALSE;
+    return FALSE;
+  }
+  return TRUE;
+}
+
 /* Do the low-level work of a capture.
    Returns TRUE if it succeeds, FALSE otherwise. */
 static gboolean
@@ -2600,43 +2799,45 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
   time_t      start_time;
   int         err_close;
   int         inpkts;
-  gint        inpkts_to_sync_pipe = 0;     /* packets not already send out to the sync_pipe */
   condition  *cnd_file_duration = NULL;
   condition  *cnd_autostop_files = NULL;
   condition  *cnd_autostop_size = NULL;
   condition  *cnd_autostop_duration = NULL;
-  guint32     autostop_files = 0;
   gboolean    write_ok;
   gboolean    close_ok;
   gboolean    cfilter_error = FALSE;
-#define MSG_MAX_LENGTH 4096
   char        errmsg[MSG_MAX_LENGTH+1];
   char        secondary_errmsg[MSG_MAX_LENGTH+1];
-  int         save_file_fd = -1;
 
   *errmsg           = '\0';
   *secondary_errmsg = '\0';
 
   /* init the loop data */
-  global_ld.go                 = TRUE;
-  global_ld.packet_count       = 0;
+  global_ld.go                  = TRUE;
+  global_ld.packet_count        = 0;
+#ifdef SIGINFO
+  global_ld.report_packet_count = FALSE;
+#endif
   if (capture_opts->has_autostop_packets)
-    global_ld.packet_max       = capture_opts->autostop_packets;
+    global_ld.packet_max        = capture_opts->autostop_packets;
   else
-    global_ld.packet_max       = 0;    /* no limit */
-  global_ld.err                = 0;    /* no error seen yet */
-  global_ld.wtap_linktype      = WTAP_ENCAP_UNKNOWN;
-  global_ld.pcap_err           = FALSE;
-  global_ld.from_cap_pipe      = FALSE;
-  global_ld.pdh                = NULL;
+    global_ld.packet_max        = 0;   /* no limit */
+  global_ld.inpkts_to_sync_pipe = 0;
+  global_ld.err                 = 0;   /* no error seen yet */
+  global_ld.wtap_linktype       = WTAP_ENCAP_UNKNOWN;
+  global_ld.pcap_err            = FALSE;
+  global_ld.from_cap_pipe       = FALSE;
+  global_ld.pdh                 = NULL;
 #ifndef _WIN32
-  global_ld.cap_pipe_fd        = -1;
+  global_ld.cap_pipe_fd         = -1;
 #else
-  global_ld.cap_pipe_h         = INVALID_HANDLE_VALUE;
+  global_ld.cap_pipe_h          = INVALID_HANDLE_VALUE;
 #endif
 #ifdef MUST_DO_SELECT
-  global_ld.pcap_fd            = 0;
+  global_ld.pcap_fd             = 0;
 #endif
+  global_ld.autostop_files      = 0;
+  global_ld.save_file_fd        = -1;
 
   /* We haven't yet gotten the capture statistics. */
   *stats_known      = FALSE;
@@ -2673,13 +2874,14 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
   /* If we're supposed to write to a capture file, open it for output
      (temporary/specified name/ringbuffer) */
   if (capture_opts->saving_to_file) {
-    if (!capture_loop_open_output(capture_opts, &save_file_fd, errmsg, sizeof(errmsg))) {
+    if (!capture_loop_open_output(capture_opts, &global_ld.save_file_fd,
+                                  errmsg, sizeof(errmsg))) {
       goto error;
     }
 
     /* set up to write to the already-opened capture output file/files */
-    if (!capture_loop_init_output(capture_opts, save_file_fd, &global_ld,
-                                  errmsg, sizeof(errmsg))) {
+    if (!capture_loop_init_output(capture_opts, &global_ld, errmsg,
+                                  sizeof(errmsg))) {
       goto error;
     }
 
@@ -2733,6 +2935,15 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
     inpkts = capture_loop_dispatch(capture_opts, &global_ld, errmsg,
                                    sizeof(errmsg));
 
+#ifdef SIGINFO
+    /* Were we asked to print packet counts by the SIGINFO handler? */
+    if (global_ld.report_packet_count) {
+        fprintf(stderr, "%u packet%s captured\n", global_ld.packet_count,
+                plurality(global_ld.packet_count, "", "s"));
+        global_ld.report_packet_count = FALSE;
+    }
+#endif
+
 #ifdef _WIN32
     /* any news from our parent (signal pipe)? -> just stop the capture */
     if (!signal_pipe_check_running()) {
@@ -2741,61 +2952,15 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
 #endif
 
     if (inpkts > 0) {
-      inpkts_to_sync_pipe += inpkts;
+      global_ld.inpkts_to_sync_pipe += inpkts;
 
       /* check capture size condition */
       if (cnd_autostop_size != NULL &&
-          cnd_eval(cnd_autostop_size, (guint32)global_ld.bytes_written)){
+          cnd_eval(cnd_autostop_size, (guint32)global_ld.bytes_written)) {
         /* Capture size limit reached, do we have another file? */
-        if (capture_opts->multi_files_on) {
-          if (cnd_autostop_files != NULL &&
-              cnd_eval(cnd_autostop_files, ++autostop_files)) {
-             /* no files left: stop here */
-            global_ld.go = FALSE;
-            continue;
-          }
-
-          /* Switch to the next ringbuffer file */
-          if (ringbuf_switch_file(&global_ld.pdh, &capture_opts->save_file,
-                                  &save_file_fd, &global_ld.err)) {
-            gboolean successful;
-
-            /* File switch succeeded: reset the conditions */
-            global_ld.bytes_written = 0;
-            if (capture_opts->use_pcapng) {
-              char appname[100];
-
-              g_snprintf(appname, sizeof(appname), "Dumpcap " VERSION "%s", wireshark_svnversion);
-              successful = libpcap_write_session_header_block(global_ld.pdh, appname, &global_ld.bytes_written, &global_ld.err) &&
-                           libpcap_write_interface_description_block(global_ld.pdh, capture_opts->iface, capture_opts->cfilter, global_ld.linktype, global_ld.file_snaplen, &global_ld.bytes_written, &global_ld.err);
-            } else {
-              successful = libpcap_write_file_header(global_ld.pdh, global_ld.linktype, global_ld.file_snaplen,
-                                                     &global_ld.bytes_written, &global_ld.err);
-            }
-            if (!successful) {
-              fclose(global_ld.pdh);
-              global_ld.pdh = NULL;
-              global_ld.go = FALSE;
-              continue;
-            }
-            cnd_reset(cnd_autostop_size);
-            if (cnd_file_duration) {
-              cnd_reset(cnd_file_duration);
-            }
-            libpcap_dump_flush(global_ld.pdh, NULL);
-            report_packet_count(inpkts_to_sync_pipe);
-            inpkts_to_sync_pipe = 0;
-            report_new_capture_file(capture_opts->save_file);
-          } else {
-            /* File switch failed: stop here */
-            global_ld.go = FALSE;
-            continue;
-          }
-        } else {
-          /* single file, stop now */
-          global_ld.go = FALSE;
+        if (!do_file_switch_or_stop(capture_opts, cnd_autostop_files,
+                                    cnd_autostop_size, cnd_file_duration))
           continue;
-        }
       } /* cnd_autostop_size */
       if (capture_opts->output_to_pipe) {
         libpcap_dump_flush(global_ld.pdh, NULL);
@@ -2818,15 +2983,16 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
       }*/
 
       /* Let the parent process know. */
-      if (inpkts_to_sync_pipe) {
+      if (global_ld.inpkts_to_sync_pipe) {
         /* do sync here */
         libpcap_dump_flush(global_ld.pdh, NULL);
 
-        /* Send our parent a message saying we've written out "inpkts_to_sync_pipe"
-           packets to the capture file. */
-        report_packet_count(inpkts_to_sync_pipe);
+        /* Send our parent a message saying we've written out
+           "global_ld.inpkts_to_sync_pipe" packets to the capture file. */
+        if (!quiet)
+          report_packet_count(global_ld.inpkts_to_sync_pipe);
 
-        inpkts_to_sync_pipe = 0;
+        global_ld.inpkts_to_sync_pipe = 0;
       }
 
       /* check capture duration condition */
@@ -2839,54 +3005,9 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
       /* check capture file duration condition */
       if (cnd_file_duration != NULL && cnd_eval(cnd_file_duration)) {
         /* duration limit reached, do we have another file? */
-        if (capture_opts->multi_files_on) {
-          if (cnd_autostop_files != NULL &&
-              cnd_eval(cnd_autostop_files, ++autostop_files)) {
-            /* no files left: stop here */
-            global_ld.go = FALSE;
-            continue;
-          }
-
-          /* Switch to the next ringbuffer file */
-          if (ringbuf_switch_file(&global_ld.pdh, &capture_opts->save_file,
-                                  &save_file_fd, &global_ld.err)) {
-            gboolean successful;
-
-            /* file switch succeeded: reset the conditions */
-            global_ld.bytes_written = 0;
-            if (capture_opts->use_pcapng) {
-              char appname[100];
-
-              g_snprintf(appname, sizeof(appname), "Dumpcap " VERSION "%s", wireshark_svnversion);
-              successful = libpcap_write_session_header_block(global_ld.pdh, appname, &global_ld.bytes_written, &global_ld.err) &&
-                           libpcap_write_interface_description_block(global_ld.pdh, capture_opts->iface, capture_opts->cfilter, global_ld.linktype, global_ld.file_snaplen, &global_ld.bytes_written, &global_ld.err);
-            } else {
-              successful = libpcap_write_file_header(global_ld.pdh, global_ld.linktype, global_ld.file_snaplen,
-                                                     &global_ld.bytes_written, &global_ld.err);
-            }
-            if (!successful) {
-              fclose(global_ld.pdh);
-              global_ld.pdh = NULL;
-              global_ld.go = FALSE;
-              continue;
-            }
-            cnd_reset(cnd_file_duration);
-            if(cnd_autostop_size)
-              cnd_reset(cnd_autostop_size);
-            libpcap_dump_flush(global_ld.pdh, NULL);
-            report_packet_count(inpkts_to_sync_pipe);
-            inpkts_to_sync_pipe = 0;
-            report_new_capture_file(capture_opts->save_file);
-          } else {
-            /* File switch failed: stop here */
-            global_ld.go = FALSE;
-            continue;
-          }
-        } else {
-          /* single file, stop now */
-          global_ld.go = FALSE;
+        if (!do_file_switch_or_stop(capture_opts, cnd_autostop_files,
+                                    cnd_autostop_size, cnd_file_duration))
           continue;
-        }
       } /* cnd_file_duration */
     }
 
@@ -2954,9 +3075,10 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
 
   /* there might be packets not yet notified to the parent */
   /* (do this after closing the file, so all packets are already flushed) */
-  if(inpkts_to_sync_pipe) {
-    report_packet_count(inpkts_to_sync_pipe);
-    inpkts_to_sync_pipe = 0;
+  if(global_ld.inpkts_to_sync_pipe) {
+    if (!quiet)
+      report_packet_count(global_ld.inpkts_to_sync_pipe);
+    global_ld.inpkts_to_sync_pipe = 0;
   }
 
   /* If we've displayed a message about a write error, there's no point
@@ -3008,8 +3130,8 @@ error:
   } else {
     /* We can't use the save file, and we have no FILE * for the stream
        to close in order to close it, so close the FD directly. */
-    if(save_file_fd != -1) {
-      ws_close(save_file_fd);
+    if(global_ld.save_file_fd != -1) {
+      ws_close(global_ld.save_file_fd);
     }
 
     /* We couldn't even start the capture, so get rid of the capture
@@ -3159,9 +3281,11 @@ main(int argc, char *argv[])
   gboolean             stats_known;
   struct pcap_stat     stats;
   GLogLevelFlags       log_flags;
-  gboolean             print_version_info = FALSE;
   gboolean             list_interfaces = FALSE;
   gboolean             list_link_layer_types = FALSE;
+#ifdef HAVE_BPF_IMAGE
+  gboolean             print_bpf_code = FALSE;
+#endif
   gboolean             machine_readable = FALSE;
   gboolean             print_statistics = FALSE;
   int                  status, run_once_args = 0;
@@ -3170,6 +3294,14 @@ main(int argc, char *argv[])
   struct utsname       osinfo;
 #endif
 
+#ifdef _WIN32
+  /*
+   * Initialize our DLL search path. MUST be called before LoadLibrary
+   * or g_module_open.
+   */
+  ws_init_dll_search_path();
+#endif
+
 #ifdef HAVE_PCAP_REMOTE
 #define OPTSTRING_A "A:"
 #define OPTSTRING_r "r"
@@ -3198,7 +3330,13 @@ main(int argc, char *argv[])
 #define OPTSTRING_I ""
 #endif
 
-#define OPTSTRING "a:" OPTSTRING_A "b:" OPTSTRING_B "c:Df:hi:" OPTSTRING_I "L" OPTSTRING_m "Mnp" OPTSTRING_r "Ss:" OPTSTRING_u "vw:y:Z:"
+#ifdef HAVE_BPF_IMAGE
+#define OPTSTRING_d "d"
+#else
+#define OPTSTRING_d ""
+#endif
+
+#define OPTSTRING "a:" OPTSTRING_A "b:" OPTSTRING_B "c:" OPTSTRING_d "Df:hi:" OPTSTRING_I "L" OPTSTRING_m "Mnpq" OPTSTRING_r "Ss:" OPTSTRING_u "vw:y:Z:"
 
 #ifdef DEBUG_CHILD_DUMPCAP
   if ((debug_log = ws_fopen("dumpcap_debug_log.tmp","w")) == NULL) {
@@ -3338,6 +3476,15 @@ main(int argc, char *argv[])
   sigaction(SIGHUP, NULL, &oldaction);
   if (oldaction.sa_handler == SIG_DFL)
     sigaction(SIGHUP, &action, NULL);
+
+#ifdef SIGINFO
+  /* Catch SIGINFO and, if we get it and we're capturing in
+     quiet mode, report the number of packets we've captured. */
+  action.sa_handler = report_counts_siginfo;
+  action.sa_flags = SA_RESTART;
+  sigemptyset(&action.sa_mask);
+  sigaction(SIGINFO, &action, NULL);
+#endif /* SIGINFO */
 #endif  /* _WIN32 */
 
   /* ----------------------------------------------------------------- */
@@ -3442,9 +3589,22 @@ main(int argc, char *argv[])
         exit_main(0);
         break;
       case 'v':        /* Show version and exit */
-        print_version_info = TRUE;
-        run_once_args++;
+      {
+        GString             *comp_info_str;
+        GString             *runtime_info_str;
+        /* Assemble the compile-time version information string */
+        comp_info_str = g_string_new("Compiled ");
+        get_compiled_version_info(comp_info_str, NULL);
+
+        /* Assemble the run-time version information string */
+        runtime_info_str = g_string_new("Running ");
+        get_runtime_version_info(runtime_info_str, NULL);
+        show_version(comp_info_str, runtime_info_str);
+        g_string_free(comp_info_str, TRUE);
+        g_string_free(runtime_info_str, TRUE);
+        exit_main(0);
         break;
+      }
       /*** capture option specific ***/
       case 'a':        /* autostop criteria */
       case 'b':        /* Ringbuffer option */
@@ -3500,6 +3660,10 @@ main(int argc, char *argv[])
 #endif
         break;
 
+      case 'q':        /* Quiet */
+        quiet = TRUE;
+        break;
+
       /*** all non capture option specific ***/
       case 'D':        /* Print a list of capture devices and exit */
         list_interfaces = TRUE;
@@ -3509,11 +3673,17 @@ main(int argc, char *argv[])
         list_link_layer_types = TRUE;
         run_once_args++;
         break;
+#ifdef HAVE_BPF_IMAGE
+      case 'd':        /* Print BPF code for capture filter and exit */
+        print_bpf_code = TRUE;
+        run_once_args++;
+        break;
+#endif
       case 'S':        /* Print interface statistics once a second */
         print_statistics = TRUE;
         run_once_args++;
         break;
-      case 'M':        /* For -D and -L, print machine-readable output */
+      case 'M':        /* For -D, -L, and -S, print machine-readable output */
         machine_readable = TRUE;
         break;
       default:
@@ -3547,7 +3717,7 @@ main(int argc, char *argv[])
   }
 
   if (run_once_args > 1) {
-    cmdarg_err("Only one of -v, -D, -L, or -S may be supplied.");
+    cmdarg_err("Only one of -D, -L, or -S may be supplied.");
     exit_main(1);
   } else if (run_once_args == 1) {
     /* We're supposed to print some information, rather than
@@ -3576,41 +3746,10 @@ main(int argc, char *argv[])
     }
   }
 
-  if (print_version_info) {
-    GString             *comp_info_str;
-    GString             *runtime_info_str;
-
-    if (machine_readable) {
-      /* Print only the *pcap version information. */
-      comp_info_str = g_string_new("");
-      get_compiled_pcap_version(comp_info_str);
-
-      runtime_info_str = g_string_new("");
-      get_runtime_pcap_version(runtime_info_str);
-
-      if (capture_child) {
-        /* Let our parent know we succeeded. */
-        pipe_write_block(2, SP_SUCCESS, NULL);
-      }
-
-      /* Print the two version strings on separate lines. */
-      printf("%s\n", comp_info_str->str);
-      printf("%s\n", runtime_info_str->str);
-    } else {
-      /* Assemble the compile-time version information string */
-      comp_info_str = g_string_new("Compiled ");
-      get_compiled_version_info(comp_info_str, NULL);
-
-      /* Assemble the run-time version information string */
-      runtime_info_str = g_string_new("Running ");
-      get_runtime_version_info(runtime_info_str, NULL);
-      show_version(comp_info_str, runtime_info_str);
-    }
-    g_string_free(comp_info_str, TRUE);
-    g_string_free(runtime_info_str, TRUE);
-    exit_main(0);
-  }
-
+  /*
+   * "-D" requires no interface to be selected; it's supposed to list
+   * all interfaces.
+   */
   if (list_interfaces) {
     /* Get the list of interfaces */
     GList       *if_list;
@@ -3650,11 +3789,17 @@ main(int argc, char *argv[])
   }
 
   /*
-   * "-D" requires no interface to be selected; it's supposed to list
-   * all interfaces.
-   *
-   * If -D wasn't specified, we have to have an interface; if none
-   * was specified, pick a default.
+   * "-S" requires no interface to be selected; it gives statistics
+   * for all interfaces.
+   */
+  if (print_statistics) {
+    status = print_statistics_loop(machine_readable);
+    exit_main(status);
+  }
+
+  /*
+   * "-L", "-d", and capturing act on a particular interface, so we have to
+   * have an interface; if none was specified, pick a default.
    */
   if (capture_opts_trim_iface(&global_capture_opts, NULL) == FALSE) {
     /* cmdarg_err() already called .... */
@@ -3692,13 +3837,18 @@ main(int argc, char *argv[])
     exit_main(0);
   }
 
-  if (print_statistics) {
-    status = print_statistics_loop(machine_readable);
-    exit_main(status);
+  /* We're supposed to do a capture, or print the BPF code for a filter.
+     Process the snapshot length, as that affects the generated BPF code. */
+  capture_opts_trim_snaplen(&global_capture_opts, MIN_PACKET_SIZE);
+
+#ifdef HAVE_BPF_IMAGE
+  if (print_bpf_code) {
+    show_filter_code(&global_capture_opts);
+    exit_main(0);
   }
+#endif
 
-  /* We're supposed to do a capture.  Process the remaining arguments. */
-  capture_opts_trim_snaplen(&global_capture_opts, MIN_PACKET_SIZE);
+  /* We're supposed to do a capture.  Process the ring buffer arguments. */
   capture_opts_trim_ring_num_files(&global_capture_opts);
 
   /* Now start the capture. */
@@ -3802,7 +3952,7 @@ console_log_handler(const char *log_domain, GLogLevelFlags log_level,
 /* indication report routines */
 
 
-void
+static void
 report_packet_count(int packet_count)
 {
     char tmp[SP_DECISIZE+1+1];
@@ -3827,9 +3977,30 @@ report_new_capture_file(const char *filename)
         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "File: %s", filename);
         pipe_write_block(2, SP_FILE, filename);
     } else {
+#ifdef SIGINFO
+        /*
+         * Prevent a SIGINFO handler from writing to the standard error
+         * while we're doing so; instead, have it just set a flag telling
+         * us to print that information when we're done.
+         */
+        infodelay = TRUE;
+#endif /* SIGINFO */
         fprintf(stderr, "File: %s\n", filename);
         /* stderr could be line buffered */
         fflush(stderr);
+
+#ifdef SIGINFO
+        /*
+         * Allow SIGINFO handlers to write.
+         */
+        infodelay = FALSE;
+
+        /*
+         * If a SIGINFO handler asked us to write out capture counts, do so.
+         */
+        if (infoprint)
+          report_counts();
+#endif /* SIGINFO */
     }
 }
 
@@ -3859,7 +4030,9 @@ report_capture_error(const char *error_msg, const char *secondary_error_msg)
             "Secondary Error: %s", secondary_error_msg);
        sync_pipe_errmsg_to_parent(2, error_msg, secondary_error_msg);
     } else {
-        fprintf(stderr, "%s\n%s\n", error_msg, secondary_error_msg);
+        fprintf(stderr, "%s\n", error_msg);
+        if (secondary_error_msg[0] != '\0')
+          fprintf(stderr, "%s\n", secondary_error_msg);
     }
 }