From Ronald Henderson, when closing IO-Stat window, also close any open Filter...
[obnox/wireshark/wip.git] / tethereal.c
index c842a277f2208c5c5bbbc3cabb8dcfde5ecdf760..4be098132fbfe99f5753ea75853f6bf4c5289e8d 100644 (file)
@@ -1,6 +1,6 @@
 /* tethereal.c
  *
- * $Id: tethereal.c,v 1.162 2002/10/23 03:49:10 guy Exp $
+ * $Id: tethereal.c,v 1.176 2003/01/01 03:51:02 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 #include <setjmp.h>
 #endif
 
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
 #ifdef HAVE_LIBZ
 #include <zlib.h>      /* to get the libz version number */
 #endif
 # include "snprintf.h"
 #endif
 
-#ifdef HAVE_UCD_SNMP_VERSION_H
+#ifdef HAVE_SOME_SNMP
+
+#ifdef HAVE_NET_SNMP
+#include <net-snmp/version.h>
+#endif /* HAVE_NET_SNMP */
+
+#ifdef HAVE_UCD_SNMP
 #include <ucd-snmp/version.h>
-#endif /* HAVE_UCD_SNMP_VERSION_H */
+#endif /* HAVE_UCD_SNMP */
+
+#endif /* HAVE_SOME_SNMP */
 
 #ifdef NEED_STRERROR_H
 #include "strerror.h"
 #include "ringbuffer.h"
 #include <epan/epan_dissect.h>
 #include "tap.h"
-#include "tap-rpcstat.h"
-#include "tap-rpcprogs.h"
-#include "packet-dcerpc.h"
-#include "tap-dcerpcstat.h"
 
 #ifdef HAVE_LIBPCAP
 #include <wiretap/wtap-capture.h>
+#include <wiretap/libpcap.h>
 #endif
 
-#ifdef WIN32
+#ifdef _WIN32
 #include "capture-wpcap.h"
 #endif
 
@@ -122,11 +131,23 @@ static gboolean line_buffered;
 typedef struct _loop_data {
   gboolean       go;           /* TRUE as long as we're supposed to keep capturing */
   gint           linktype;
+  gboolean       from_pipe;    /* TRUE if we are capturing data from a pipe */
   pcap_t        *pch;
   wtap_dumper   *pdh;
   jmp_buf        stopenv;
   gboolean       output_to_pipe;
   int            packet_count;
+#ifndef _WIN32
+  gboolean       modified;     /* TRUE if data in the pipe uses modified pcap headers */
+  gboolean       byte_swapped; /* TRUE if data in the pipe is byte swapped */
+  unsigned int   bytes_to_read, bytes_read; /* Used by pipe_dispatch */
+  enum {
+         STATE_EXPECT_REC_HDR, STATE_READ_REC_HDR,
+         STATE_EXPECT_DATA,     STATE_READ_DATA
+       } pipe_state;
+
+  enum { PIPOK, PIPEOF, PIPERR, PIPNEXIST } pipe_err;
+#endif
 } loop_data;
 
 static loop_data ld;
@@ -134,10 +155,14 @@ static loop_data ld;
 static int capture(int);
 static void capture_pcap_cb(guchar *, const struct pcap_pkthdr *,
   const guchar *);
+static void report_counts(void);
 #ifdef _WIN32
 static BOOL WINAPI capture_cleanup(DWORD);
 #else /* _WIN32 */
 static void capture_cleanup(int);
+#ifdef SIGINFO
+static void report_counts_siginfo(int);
+#endif /* SIGINFO */
 #endif /* _WIN32 */
 #endif /* HAVE_LIBPCAP */
 
@@ -152,6 +177,12 @@ static void wtap_dispatch_cb_write(guchar *, const struct wtap_pkthdr *, long,
 static void show_capture_file_io_error(const char *, int, gboolean);
 static void wtap_dispatch_cb_print(guchar *, const struct wtap_pkthdr *, long,
     union wtap_pseudo_header *, const guchar *);
+#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
 
 capture_file cfile;
 ts_type timestamp_type = RELATIVE;
@@ -186,7 +217,12 @@ static capture_options capture_opts = {
        RINGBUFFER_MIN_NUM_FILES        /* default number of ring buffer
                                           files */
 };
-#endif
+
+#ifdef SIGINFO
+static gboolean infodelay;     /* if TRUE, don't print capture info in SIGINFO handler */
+static gboolean infoprint;     /* if TRUE, print capture info after clearing infodelay */
+#endif /* SIGINFO */
+#endif /* HAVE_LIBPCAP */
 
 static void
 print_usage(gboolean print_ver)
@@ -299,6 +335,28 @@ set_autostop_criterion(const char *autostoparg)
 }
 #endif
 
+/* structure to keep track of what tap listeners have been registered.
+ */
+typedef struct _ethereal_tap_list {
+       struct _ethereal_tap_list *next;
+       char *cmd;
+       void (*func)(char *arg);
+} ethereal_tap_list;
+static ethereal_tap_list *tap_list=NULL;
+
+void
+register_ethereal_tap(char *cmd, void (*func)(char *arg), char *dummy _U_, void (*dummy2)(void) _U_)
+{
+       ethereal_tap_list *newtl;
+
+       newtl=malloc(sizeof(ethereal_tap_list));
+       newtl->next=tap_list;
+       tap_list=newtl;
+       newtl->cmd=cmd;
+       newtl->func=func;
+
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -311,14 +369,9 @@ main(int argc, char *argv[])
 #endif /* HAVE_PCAP_VERSION */
 #endif /* HAVE_LIBPCAP */
 
-#ifdef WIN32
+#ifdef _WIN32
   WSADATA              wsaData;
-
-# ifdef HAVE_UCD_SNMP
-  char                *mib_path;
-# define MIB_PATH_APPEND "\\snmp\\mibs"
-# endif        /* HAVE_UCD_SNMP */
-#endif /* WIN32 */
+#endif /* _WIN32 */
 
   char                *gpf_path;
   char                *pf_path;
@@ -339,12 +392,14 @@ main(int argc, char *argv[])
   dfilter_t           *rfcode = NULL;
   e_prefs             *prefs;
   char                 badopt;
+  ethereal_tap_list *tli;
 
   /* Register all dissectors; we must do this before checking for the
      "-G" flag, as the "-G" flag dumps information registered by the
      dissectors, and we must do it before we read the preferences, in
      case any dissectors register preferences. */
   epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs);
+  register_all_tap_listeners();
 
   /* Now register the preferences for any non-dissector modules.
      We must do that before we read the preferences as well. */
@@ -392,7 +447,7 @@ main(int argc, char *argv[])
   /* Set the name resolution code's flags from the preferences. */
   g_resolv_flags = prefs->name_resolve;
 
-#ifdef WIN32
+#ifdef _WIN32
   /* Load Wpcap, if possible */
   load_wpcap();
 #endif
@@ -433,17 +488,23 @@ main(int argc, char *argv[])
   g_string_append(comp_info_str, ", without libz");
 #endif /* HAVE_LIBZ */
 
-/* Oh, this is pretty */
+/* Oh, this is pretty. */
+/* Oh, ha.  you think that was pretty.  Try this:! --Wes */
+#ifdef HAVE_SOME_SNMP
+
 #ifdef HAVE_UCD_SNMP
-  g_string_append(comp_info_str, ", with UCD SNMP ");
-#ifdef HAVE_UCD_SNMP_VERSION_H
+  g_string_append(comp_info_str, ", with UCD-SNMP ");
   g_string_append(comp_info_str, VersionInfo);
-#else /* HAVE_UCD_SNMP_VERSION_H */
-  g_string_append(comp_info_str, "(version unknown)");
-#endif /* HAVE_UCD_SNMP_VERSION_H */
+#endif /* HAVE_UCD_SNMP */
+
+#ifdef HAVE_NET_SNMP
+  g_string_append(comp_info_str, ", with Net-SNMP ");
+  g_string_append(comp_info_str, netsnmp_get_version());
+#endif /* HAVE_NET_SNMP */
+
 #else /* no SNMP library */
-  g_string_append(comp_info_str, ", without UCD SNMP");
-#endif
+  g_string_append(comp_info_str, ", without UCD-SNMP or Net-SNMP");
+#endif /* HAVE_SOME_SNMP */
 
   /* Now get our args */
   while ((opt = getopt(argc, argv, "a:b:c:Df:F:hi:lnN:o:pqr:R:s:St:vw:Vxz:")) != -1) {
@@ -638,64 +699,18 @@ main(int argc, char *argv[])
         print_hex = TRUE;
         break;
       case 'z':
-        if(!strncmp(optarg,"rpc,",4)){
-          if(!strncmp(optarg,"rpc,rtt,",8)){
-            int rpcprogram, rpcversion;
-            int pos=0;
-            if(sscanf(optarg,"rpc,rtt,%d,%d,%n",&rpcprogram,&rpcversion,&pos)==2){
-              if(pos){
-                rpcstat_init(rpcprogram,rpcversion,optarg+pos);
-              } else {
-                rpcstat_init(rpcprogram,rpcversion,NULL);
-              }
-            } else {
-              fprintf(stderr, "tethereal: invalid \"-z rpc,rtt,<program>,<version>[,<filter>]\" argument\n");
-              exit(1);
-            }
-          } else if(!strncmp(optarg,"rpc,programs",12)){
-            rpcprogs_init();
-          } else {
-            fprintf(stderr, "tethereal: invalid -z argument. Argument must be one of:\n");
-            fprintf(stderr, "   \"-z rpc,rtt,<program>,<version>[,<filter>]\"\n");
-            fprintf(stderr, "   \"-z rpc,programs\"\n");
-            exit(1);
+        for(tli=tap_list;tli;tli=tli->next){
+          if(!strncmp(tli->cmd,optarg,strlen(tli->cmd))){
+            (*tli->func)(optarg);
+            break;
           }
-        } else if(!strncmp(optarg,"dcerpc,",7)){
-          if(!strncmp(optarg,"dcerpc,rtt,",11)){
-            e_uuid_t uuid;
-            int d1,d2,d3,d40,d41,d42,d43,d44,d45,d46,d47;
-            int major, minor;
-            int pos=0;
-            if(sscanf(optarg,"dcerpc,rtt,%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d%n", &d1,&d2,&d3,&d40,&d41,&d42,&d43,&d44,&d45,&d46,&d47,&major,&minor,&pos)==13){
-              uuid.Data1=d1;
-              uuid.Data2=d2;
-              uuid.Data3=d3;
-              uuid.Data4[0]=d40;
-              uuid.Data4[1]=d41;
-              uuid.Data4[2]=d42;
-              uuid.Data4[3]=d43;
-              uuid.Data4[4]=d44;
-              uuid.Data4[5]=d45;
-              uuid.Data4[6]=d46;
-              uuid.Data4[7]=d47;
-              if(pos){
-                dcerpcstat_init(&uuid,major,minor,optarg+pos);
-              } else {
-                dcerpcstat_init(&uuid,major,minor,NULL);
-              }
-            } else {
-              fprintf(stderr, "tethereal: invalid \"-z dcerpc,rtt,<uuid>,<major version>.<minor version>[,<filter>]\" argument\n");
-              exit(1);
-            }
-          } else {
-            fprintf(stderr, "tethereal: invalid -z argument. Argument must be one of:\n");
-            fprintf(stderr, "   \"-z dcerpc,rtt,<uuid>,<major version>.<minor version>[,<filter>]\"\n");
-            exit(1);
+        }
+        if(!tli){
+          fprintf(stderr,"tethereal: invalid -z argument.\n");
+          fprintf(stderr,"  -z argument must be one of :\n");
+          for(tli=tap_list;tli;tli=tli->next){
+            fprintf(stderr,"     %s\n",tli->cmd);
           }
-        } else {
-          fprintf(stderr, "tethereal: invalid -z argument. Argument must be one of:\n");
-          fprintf(stderr, "   \"-z rpc,...\"\n");
-          fprintf(stderr, "   \"-z dcerpc,...\"\n");
           exit(1);
         }
         break;
@@ -737,7 +752,7 @@ main(int argc, char *argv[])
   ld.output_to_pipe = FALSE;
 #endif
   if (cfile.save_file != NULL) {
-    if (!strcmp(cfile.save_file, "-")) {
+    if (strcmp(cfile.save_file, "-") == 0) {
       /* stdout */
       g_free(cfile.save_file);
       cfile.save_file = g_strdup("");
@@ -809,23 +824,10 @@ main(int argc, char *argv[])
   }
 #endif
 
-#ifdef WIN32
+#ifdef _WIN32
   /* Start windows sockets */
   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
-
-# ifdef HAVE_UCD_SNMP
-  /* Set MIBDIRS so that the SNMP library can find its mibs. */
-  /* XXX - Should we set MIBS or MIBFILES as well? */
-
-  mib_path = g_malloc (strlen(get_datafile_dir()) + strlen(MIB_PATH_APPEND) + 20);
-  sprintf (mib_path, "MIBDIRS=%s\\%s", get_datafile_dir(), MIB_PATH_APPEND);
-  /* Amazingly enough, Windows does not provide setenv(). */
-  if (getenv("MIBDIRS") == NULL)
-    _putenv(mib_path);
-  g_free(mib_path);
-
-# endif        /* HAVE_UCD_SNMP */
-#endif /* WIN32 */
+#endif /* _WIN32 */
 
   /* Notify all registered modules that have had any of their preferences
      changed either from one of the preferences file or from the command
@@ -965,6 +967,8 @@ main(int argc, char *argv[])
 static int
 capture(int out_file_type)
 {
+  int         pcap_encap;
+  int         file_snaplen;
   gchar       open_err_str[PCAP_ERRBUF_SIZE];
   gchar       lookup_net_err_str[PCAP_ERRBUF_SIZE];
   bpf_u_int32 netnum, netmask;
@@ -980,6 +984,10 @@ capture(int out_file_type)
 #ifndef _WIN32
   static const char ppamsg[] = "can't find PPA for ";
   char       *libpcap_warn;
+  volatile int pipe_fd = -1;
+  struct pcap_hdr hdr;
+  struct pcaprec_modified_hdr rechdr;
+  guchar pcap_data[WTAP_MAX_PACKET_SIZE];
 #endif
   struct pcap_stat stats;
   gboolean    write_err;
@@ -1000,49 +1008,69 @@ capture(int out_file_type)
                          capture_opts.promisc_mode, 1000, open_err_str);
 
   if (ld.pch == NULL) {
-    /* Well, we couldn't start the capture. */
+    /* We couldn't open "cfile.iface" as a network device. */
 #ifdef _WIN32
+    /* On Windows, we don't support capturing on pipes, so we give up. */
+
     /* On Win32 OSes, the capture devices are probably available to all
        users; don't warn about permissions problems.
 
-       Do, however, warn that Token Ring and PPP devices aren't supported. */
+       Do, however, warn that WAN devices aren't supported. */
     snprintf(errmsg, sizeof errmsg,
        "The capture session could not be initiated (%s).\n"
        "Please check that you have the proper interface specified.\n"
        "\n"
-       "Note that the driver Tethereal uses for packet capture on Windows\n"
-       "doesn't support capturing on Token Ring interfaces, and doesn't\n"
-       "support capturing on PPP/WAN interfaces in Windows NT/2000.\n",
+       "Note that the driver Tethereal uses for packet capture on Windows doesn't\n"
+       "support capturing on PPP/WAN interfaces in Windows NT/2000/XP/.NET Server.\n",
        open_err_str);
+    goto error;
 #else
-      /* If we got a "can't find PPA for XXX" message, warn the user (who
-         is running Ethereal on HP-UX) that they don't have a version
-        of libpcap that properly handles HP-UX (libpcap 0.6.x and later
-        versions, which properly handle HP-UX, say "can't find /dev/dlpi
-        PPA for XXX" rather than "can't find PPA for XXX"). */
-      if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
-       libpcap_warn =
-         "\n\n"
-         "You are running Tethereal with a version of the libpcap library\n"
-         "that doesn't handle HP-UX network devices well; this means that\n"
-         "Tethereal may not be able to capture packets.\n"
-         "\n"
-         "To fix this, you should install libpcap 0.6.2, or a later version\n"
-         "of libpcap, rather than libpcap 0.4 or 0.5.x.  It is available in\n"
-         "packaged binary form from the Software Porting And Archive Centre\n"
-         "for HP-UX; the Centre is at http://hpux.connect.org.uk/ - the page\n"
-         "at the URL lists a number of mirror sites.";
-      else
-       libpcap_warn = "";
-    snprintf(errmsg, sizeof errmsg,
-      "The capture session could not be initiated (%s).\n"
-      "Please check to make sure you have sufficient permissions, and that\n"
-      "you have the proper interface specified.%s", open_err_str, libpcap_warn);
+    /* try to open cfile.iface as a pipe */
+    pipe_fd = pipe_open_live(cfile.iface, &hdr, &ld, errmsg, sizeof errmsg);
+
+    if (pipe_fd == -1) {
+
+      if (ld.pipe_err == PIPNEXIST) {
+       /* Pipe doesn't exist, so output message for interface */
+
+       /* If we got a "can't find PPA for XXX" message, warn the user (who
+           is running Tethereal on HP-UX) that they don't have a version
+          of libpcap that properly handles HP-UX (libpcap 0.6.x and later
+          versions, which properly handle HP-UX, say "can't find /dev/dlpi
+          PPA for XXX" rather than "can't find PPA for XXX"). */
+       if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
+         libpcap_warn =
+           "\n\n"
+           "You are running Tethereal with a version of the libpcap library\n"
+           "that doesn't handle HP-UX network devices well; this means that\n"
+           "Tethereal may not be able to capture packets.\n"
+           "\n"
+           "To fix this, you should install libpcap 0.6.2, or a later version\n"
+           "of libpcap, rather than libpcap 0.4 or 0.5.x.  It is available in\n"
+           "packaged binary form from the Software Porting And Archive Centre\n"
+           "for HP-UX; the Centre is at http://hpux.connect.org.uk/ - the page\n"
+           "at the URL lists a number of mirror sites.";
+       else
+         libpcap_warn = "";
+       snprintf(errmsg, sizeof errmsg,
+         "The capture session could not be initiated (%s).\n"
+         "Please check to make sure you have sufficient permissions, and that\n"
+         "you have the proper interface or pipe specified.%s", open_err_str,
+         libpcap_warn);
+      }
+      /*
+       * Else pipe (or file) does exist and pipe_open_live() has
+       * filled in errmsg
+       */
+      goto error;
+    } else
+      /* pipe_open_live() succeeded; don't want
+         error message from pcap_open_live() */
+      open_err_str[0] = '\0';
 #endif
-    goto error;
   }
 
-  if (cfile.cfilter) {
+  if (cfile.cfilter && !ld.from_pipe) {
     /* A capture filter was specified; set it up. */
     if (pcap_lookupnet(cfile.iface, &netnum, &netmask, lookup_net_err_str) < 0) {
       /*
@@ -1066,8 +1094,18 @@ capture(int out_file_type)
     }
   }
 
-  ld.linktype = wtap_pcap_encap_to_wtap_encap(get_pcap_linktype(ld.pch,
-       cfile.iface));
+  /* Set up to write to the capture file. */
+#ifndef _WIN32
+  if (ld.from_pipe) {
+    pcap_encap = hdr.network;
+    file_snaplen = hdr.snaplen;
+  } else
+#endif
+  {
+    pcap_encap = get_pcap_linktype(ld.pch, cfile.iface);
+    file_snaplen = pcap_snapshot(ld.pch);
+  }
+  ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_encap);
   if (cfile.save_file != NULL) {
     /* Set up to write to the capture file. */
     if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
@@ -1115,6 +1153,12 @@ capture(int out_file_type)
   signal(SIGINT, capture_cleanup);
   if ((oldhandler = signal(SIGHUP, capture_cleanup)) != SIG_DFL)
     signal(SIGHUP, oldhandler);
+
+#ifdef SIGINFO
+  /* Catch SIGINFO and, if we get it and we're capturing to a file in
+     quiet mode, report the number of packets we've captured. */
+  signal(SIGINFO, report_counts_siginfo);
+#endif /* SIGINFO */
 #endif /* _WIN32 */
 
   /* Let the user know what interface was chosen. */
@@ -1124,17 +1168,17 @@ capture(int out_file_type)
   init_capture_stop_conditions();
   /* create stop conditions */
   if (capture_opts.has_autostop_filesize)
-    cnd_stop_capturesize = cnd_new((char*)CND_CLASS_CAPTURESIZE,
+    cnd_stop_capturesize = cnd_new((const char*)CND_CLASS_CAPTURESIZE,
                                    (long)capture_opts.autostop_filesize * 1000);
   if (capture_opts.has_autostop_duration)
-    cnd_stop_timeout = cnd_new((char*)CND_CLASS_TIMEOUT,
+    cnd_stop_timeout = cnd_new((const char*)CND_CLASS_TIMEOUT,
                                (gint32)capture_opts.autostop_duration);
 
-  if (!setjmp(ld.stopenv))
+  if (!setjmp(ld.stopenv)) {
     ld.go = TRUE;
-  else
+    ld.packet_count = 0;
+  } else
     ld.go = FALSE;
-  ld.packet_count = 0;
   while (ld.go) {
     /* We need to be careful with automatic variables defined in the
        outer scope which are changed inside the loop.  Most compilers
@@ -1194,9 +1238,16 @@ capture(int out_file_type)
          each packet. */
       pcap_cnt = 1;
     }
-    inpkts = pcap_dispatch(ld.pch, pcap_cnt, capture_pcap_cb, (guchar *) &ld);
+#ifndef _WIN32
+    if (ld.from_pipe) {
+      inpkts = pipe_dispatch(pipe_fd, &ld, &hdr, &rechdr, pcap_data,
+        errmsg, sizeof errmsg);
+    } else
+#endif
+      inpkts = pcap_dispatch(ld.pch, pcap_cnt, capture_pcap_cb, (guchar *) &ld);
     if (inpkts < 0) {
-      /* Error from "pcap_dispatch()". */
+      /* Error from "pcap_dispatch()", or error or "no more packets" from
+         "pipe_dispatch(). */
       ld.go = FALSE;
     } else if (cnd_stop_timeout != NULL && cnd_eval(cnd_stop_timeout)) {
       /* The specified capture time has elapsed; stop the capture. */
@@ -1255,8 +1306,18 @@ capture(int out_file_type)
 
   /* If we got an error while capturing, report it. */
   if (inpkts < 0) {
-    fprintf(stderr, "tethereal: Error while capturing packets: %s\n",
-       pcap_geterr(ld.pch));
+#ifndef _WIN32
+    if (ld.from_pipe) {
+      if (ld.pipe_err == PIPERR) {
+        fprintf(stderr, "tethereal: Error while capturing packets: %s\n",
+         errmsg);
+      }
+    } else
+#endif
+    {
+      fprintf(stderr, "tethereal: Error while capturing packets: %s\n",
+         pcap_geterr(ld.pch));
+    }
   }
 
   if (volatile_err == 0)
@@ -1279,23 +1340,28 @@ capture(int out_file_type)
       show_capture_file_io_error(cfile.save_file, err, TRUE);
   }
 
-  /* Get the capture statistics, and, if any packets were dropped, report
-     that. */
-  if (pcap_stats(ld.pch, &stats) >= 0) {
-    if (stats.ps_drop != 0) {
-      fprintf(stderr, "%u packets dropped\n", stats.ps_drop);
+#ifndef _WIN32
+  if (ld.from_pipe && pipe_fd >= 0)
+    close(pipe_fd);
+  else
+#endif
+  {
+    /* Get the capture statistics, and, if any packets were dropped, report
+       that. */
+    if (pcap_stats(ld.pch, &stats) >= 0) {
+      if (stats.ps_drop != 0) {
+        fprintf(stderr, "%u packets dropped\n", stats.ps_drop);
+      }
+    } else {
+      fprintf(stderr, "tethereal: Can't get packet-drop statistics: %s\n",
+         pcap_geterr(ld.pch));
     }
-  } else {
-    fprintf(stderr, "tethereal: Can't get packet-drop statistics: %s\n",
-       pcap_geterr(ld.pch));
+    pcap_close(ld.pch);
   }
+
   /* Report the number of captured packets if not reported during capture
      and we are saving to a file. */
-  if (quiet && (cfile.save_file != NULL)) {
-    fprintf(stderr, "%u packets captured\n", ld.packet_count);
-  }
-
-  pcap_close(ld.pch);
+  report_counts();
 
   return TRUE;
 
@@ -1306,8 +1372,16 @@ error:
   g_free(cfile.save_file);
   cfile.save_file = NULL;
   fprintf(stderr, "tethereal: %s\n", errmsg);
+#ifndef _WIN32
+  if (ld.from_pipe) {
+    if (pipe_fd >= 0)
+      close(pipe_fd);
+  } else
+#endif
+  {
   if (ld.pch != NULL)
     pcap_close(ld.pch);
+  }
 
   return FALSE;
 }
@@ -1393,6 +1467,41 @@ capture_cleanup(int signum _U_)
   longjmp(ld.stopenv, 1);
 }
 #endif /* _WIN32 */
+
+static void
+report_counts(void)
+{
+#ifdef SIGINFO
+  /* XXX - if we use sigaction, this doesn't have to be done.
+     (Yes, this isn't necessary on BSD, but just in case a system
+     where "signal()" has AT&T semantics adopts SIGINFO....) */
+  signal(SIGINFO, report_counts_siginfo);
+#endif /* SIGINFO */
+
+  if (cfile.save_file != NULL && quiet) {
+    /* Report the count only if we're capturing to a file (rather
+       than printing captured packet information out) and aren't
+       updating a count as packets arrive. */
+    fprintf(stderr, "%u packets captured\n", ld.packet_count);
+  }
+#ifdef SIGINFO
+  infoprint = FALSE;   /* we just reported it */
+#endif /* SIGINFO */
+}
+
+#ifdef SIGINFO
+static void
+report_counts_siginfo(int signum _U_)
+{
+  /* 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();
+}
+#endif /* SIGINFO */
 #endif /* HAVE_LIBPCAP */
 
 static int
@@ -1589,6 +1698,15 @@ wtap_dispatch_cb_write(guchar *user, const struct wtap_pkthdr *phdr,
   gboolean      passed;
   epan_dissect_t *edt;
 
+#ifdef SIGINFO
+  /*
+   * Prevent a SIGINFO handler from writing to stdout while we're
+   * doing so; instead, have it just set a flag telling us to print
+   * that information when we're done.
+   */
+  infodelay = TRUE;
+#endif /* SIGINFO */
+
   cf->count++;
   if (cf->rfcode) {
     fill_in_fdata(&fdata, cf, phdr, offset);
@@ -1626,6 +1744,19 @@ wtap_dispatch_cb_write(guchar *user, const struct wtap_pkthdr *phdr,
     epan_dissect_free(edt);
   if (cf->rfcode)
     clear_fdata(&fdata);
+
+#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 */
 }
 
 static void
@@ -1696,7 +1827,7 @@ wtap_dispatch_cb_print(guchar *user, const struct wtap_pkthdr *phdr,
   fill_in_fdata(&fdata, cf, phdr, offset);
 
   passed = TRUE;
-  if (cf->rfcode || verbose)
+  if (cf->rfcode || verbose || num_tap_filters!=0)
     create_proto_tree = TRUE;
   else
     create_proto_tree = FALSE;
@@ -1705,6 +1836,7 @@ wtap_dispatch_cb_print(guchar *user, const struct wtap_pkthdr *phdr,
 
      We only need the columns if we're *not* verbose; in verbose mode,
      we print the protocol tree, not the protocol summary. */
+
   edt = epan_dissect_new(create_proto_tree, verbose);
   if (cf->rfcode) {
     epan_dissect_prime_dfilter(edt, cf->rfcode);
@@ -2099,3 +2231,289 @@ fail:
   fprintf(stderr, "tethereal: %s\n", err_msg);
   return (err);
 }
+
+#ifndef _WIN32
+/* Take care of byte order in the libpcap headers read from pipes.
+ * (function taken from wiretap/libpcap.c) */
+static void
+adjust_header(loop_data *ld, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr)
+{
+  if (ld->byte_swapped) {
+    /* Byte-swap the record header fields. */
+    rechdr->ts_sec = BSWAP32(rechdr->ts_sec);
+    rechdr->ts_usec = BSWAP32(rechdr->ts_usec);
+    rechdr->incl_len = BSWAP32(rechdr->incl_len);
+    rechdr->orig_len = BSWAP32(rechdr->orig_len);
+  }
+
+  /* In file format version 2.3, the "incl_len" and "orig_len" fields were
+     swapped, in order to match the BPF header layout.
+
+     Unfortunately, some files were, according to a comment in the "libpcap"
+     source, written with version 2.3 in their headers but without the
+     interchanged fields, so if "incl_len" is greater than "orig_len" - which
+     would make no sense - we assume that we need to swap them.  */
+  if (hdr->version_major == 2 &&
+      (hdr->version_minor < 3 ||
+       (hdr->version_minor == 3 && rechdr->incl_len > rechdr->orig_len))) {
+    guint32 temp;
+
+    temp = rechdr->orig_len;
+    rechdr->orig_len = rechdr->incl_len;
+    rechdr->incl_len = temp;
+  }
+}
+
+/* Mimic pcap_open_live() for pipe captures
+ * We check if "pipename" is "-" (stdin) or a FIFO, open it, and read the
+ * header.
+ * N.B. : we can't read the libpcap formats used in RedHat 6.1 or SuSE 6.3
+ * because we can't seek on pipes (see wiretap/libpcap.c for details) */
+static int
+pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
+                 char *errmsg, int errmsgl)
+{
+  struct stat pipe_stat;
+  int         fd;
+  guint32     magic;
+  int         b;
+  unsigned int bytes_read;
+
+  /*
+   * XXX Tethereal blocks until we return
+   */
+  if (strcmp(pipename, "-") == 0)
+    fd = 0; /* read from stdin */
+  else {
+    if (stat(pipename, &pipe_stat) < 0) {
+      if (errno == ENOENT || errno == ENOTDIR)
+        ld->pipe_err = PIPNEXIST;
+      else {
+        snprintf(errmsg, errmsgl,
+          "The capture session could not be initiated "
+          "due to error on pipe: %s", strerror(errno));
+        ld->pipe_err = PIPERR;
+      }
+      return -1;
+    }
+    if (! S_ISFIFO(pipe_stat.st_mode)) {
+      if (S_ISCHR(pipe_stat.st_mode)) {
+        /*
+         * Assume the user specified an interface on a system where
+         * interfaces are in /dev.  Pretend we haven't seen it.
+         */
+         ld->pipe_err = PIPNEXIST;
+      } else {
+        snprintf(errmsg, errmsgl,
+            "The capture session could not be initiated because\n"
+            "\"%s\" is neither an interface nor a pipe", pipename);
+        ld->pipe_err = PIPERR;
+      }
+      return -1;
+    }
+    fd = open(pipename, O_RDONLY);
+    if (fd == -1) {
+      snprintf(errmsg, errmsgl,
+          "The capture session could not be initiated "
+          "due to error on pipe open: %s", strerror(errno));
+      ld->pipe_err = PIPERR;
+      return -1;
+    }
+  }
+
+  ld->from_pipe = TRUE;
+
+  /* read the pcap header */
+  bytes_read = 0;
+  while (bytes_read < sizeof magic) {
+    b = read(fd, ((char *)&magic)+bytes_read, sizeof magic-bytes_read);
+    if (b <= 0) {
+      if (b == 0)
+        snprintf(errmsg, errmsgl, "End of file on pipe during open");
+      else
+        snprintf(errmsg, errmsgl, "Error on pipe during open: %s",
+          strerror(errno));
+      goto error;
+    }
+    bytes_read += b;
+  }
+
+  switch (magic) {
+  case PCAP_MAGIC:
+    /* Host that wrote it has our byte order, and was running
+       a program using either standard or ss990417 libpcap. */
+    ld->byte_swapped = FALSE;
+    ld->modified = FALSE;
+    break;
+  case PCAP_MODIFIED_MAGIC:
+    /* Host that wrote it has our byte order, but was running
+       a program using either ss990915 or ss991029 libpcap. */
+    ld->byte_swapped = FALSE;
+    ld->modified = TRUE;
+    break;
+  case PCAP_SWAPPED_MAGIC:
+    /* Host that wrote it has a byte order opposite to ours,
+       and was running a program using either standard or
+       ss990417 libpcap. */
+    ld->byte_swapped = TRUE;
+    ld->modified = FALSE;
+    break;
+  case PCAP_SWAPPED_MODIFIED_MAGIC:
+    /* Host that wrote it out has a byte order opposite to
+       ours, and was running a program using either ss990915
+       or ss991029 libpcap. */
+    ld->byte_swapped = TRUE;
+    ld->modified = TRUE;
+    break;
+  default:
+    /* Not a "libpcap" type we know about. */
+    snprintf(errmsg, errmsgl, "Unrecognized libpcap format");
+    goto error;
+  }
+
+  /* Read the rest of the header */
+  bytes_read = 0;
+  while (bytes_read < sizeof(struct pcap_hdr)) {
+    b = read(fd, ((char *)hdr)+bytes_read,
+          sizeof(struct pcap_hdr) - bytes_read);
+    if (b <= 0) {
+      if (b == 0)
+        snprintf(errmsg, errmsgl, "End of file on pipe during open");
+      else
+        snprintf(errmsg, errmsgl, "Error on pipe during open: %s",
+          strerror(errno));
+      goto error;
+    }
+    bytes_read += b;
+  }
+
+  if (ld->byte_swapped) {
+    /* Byte-swap the header fields about which we care. */
+    hdr->version_major = BSWAP16(hdr->version_major);
+    hdr->version_minor = BSWAP16(hdr->version_minor);
+    hdr->snaplen = BSWAP32(hdr->snaplen);
+    hdr->network = BSWAP32(hdr->network);
+  }
+
+  if (hdr->version_major < 2) {
+    snprintf(errmsg, errmsgl, "Unable to read old libpcap format");
+    goto error;
+  }
+
+  ld->pipe_state = STATE_EXPECT_REC_HDR;
+  ld->pipe_err = PIPOK;
+  return fd;
+
+error:
+  ld->pipe_err = PIPERR;
+  close(fd);
+  return -1;
+
+}
+/* We read one record from the pipe, take care of byte order in the record
+ * header, write the record in the capture file, and update capture statistics. */
+
+static int
+pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
+                struct pcaprec_modified_hdr *rechdr, guchar *data,
+                char *errmsg, int errmsgl)
+{
+  struct pcap_pkthdr phdr;
+  int b;
+  enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR,
+          PD_ERR } result;
+
+  switch (ld->pipe_state) {
+
+  case STATE_EXPECT_REC_HDR:
+    ld->bytes_to_read = ld->modified ?
+      sizeof(struct pcaprec_modified_hdr) : sizeof(struct pcaprec_hdr);
+    ld->bytes_read = 0;
+    ld->pipe_state = STATE_READ_REC_HDR;
+    /* Fall through */
+
+  case STATE_READ_REC_HDR:
+    b = read(fd, ((char *)rechdr)+ld->bytes_read,
+      ld->bytes_to_read - ld->bytes_read);
+    if (b <= 0) {
+      if (b == 0)
+        result = PD_PIPE_EOF;
+      else
+        result = PD_PIPE_ERR;
+      break;
+    }
+    if ((ld->bytes_read += b) < ld->bytes_to_read)
+        return 0;
+    result = PD_REC_HDR_READ;
+    break;
+
+  case STATE_EXPECT_DATA:
+    ld->bytes_read = 0;
+    ld->pipe_state = STATE_READ_DATA;
+    /* Fall through */
+
+  case STATE_READ_DATA:
+    b = read(fd, data+ld->bytes_read, rechdr->hdr.incl_len - ld->bytes_read);
+    if (b <= 0) {
+      if (b == 0)
+        result = PD_PIPE_EOF;
+      else
+        result = PD_PIPE_ERR;
+      break;
+    }
+    if ((ld->bytes_read += b) < rechdr->hdr.incl_len)
+      return 0;
+    result = PD_DATA_READ;
+    break;
+
+  default:
+    snprintf(errmsg, errmsgl, "pipe_dispatch: invalid state");
+    result = PD_ERR;
+
+  } /* switch (ld->pipe_state) */
+
+  /*
+   * We've now read as much data as we were expecting, so process it.
+   */
+  switch (result) {
+
+  case PD_REC_HDR_READ:
+    /* We've read the header. Take care of byte order. */
+    adjust_header(ld, hdr, &rechdr->hdr);
+    if (rechdr->hdr.incl_len > WTAP_MAX_PACKET_SIZE) {
+      snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)",
+        ld->packet_count+1, rechdr->hdr.incl_len);
+      break;
+    }
+    ld->pipe_state = STATE_EXPECT_DATA;
+    return 0;
+
+  case PD_DATA_READ:
+    /* Fill in a "struct pcap_pkthdr", and process the packet. */
+    phdr.ts.tv_sec = rechdr->hdr.ts_sec;
+    phdr.ts.tv_usec = rechdr->hdr.ts_usec;
+    phdr.caplen = rechdr->hdr.incl_len;
+    phdr.len = rechdr->hdr.orig_len;
+
+    capture_pcap_cb((guchar *)ld, &phdr, data);
+
+    ld->pipe_state = STATE_EXPECT_REC_HDR;
+    return 1;
+
+  case PD_PIPE_EOF:
+    ld->pipe_err = PIPEOF;
+    return -1;
+
+  case PD_PIPE_ERR:
+    snprintf(errmsg, errmsgl, "Error reading from pipe: %s",
+      strerror(errno));
+    /* Fall through */
+  case PD_ERR:
+    break;
+  }
+
+  ld->pipe_err = PIPERR;
+  /* Return here rather than inside the switch to prevent GCC warning */
+  return -1;
+}
+#endif