Ethereal-dev: [Ethereal-dev] [PATCH] Flush tethereal capture file if FIFO

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Graeme Hewson <ghewson@xxxxxxxxxxxxxxxxxxx>
Date: Sun, 23 Jun 2002 20:37:42 +0100
The patch to tethereal.c flushes the buffer after every frame if the
capture file is a FIFO.  Together with the patch to ringbuffer.c, error
handling is also improved.


Graeme Hewson
--- tethereal.c.orig	Fri Jun  7 22:11:22 2002
+++ tethereal.c	Sat Jun 22 21:22:32 2002
@@ -111,6 +111,26 @@
 #include "capture-wpcap.h"
 #endif
 
+/* XXX this code is duplicated in epan/filesystem.c and wiretap/file.c */
+/*
+ * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
+ * define them either.)
+ *
+ * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
+ */
+#ifndef S_ISREG
+#define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
+#endif
+#ifndef S_IFIFO
+#define S_IFIFO _S_IFIFO
+#endif
+#ifndef S_ISFIFO
+#define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
+#endif
+
 static guint32 firstsec, firstusec;
 static guint32 prevsec, prevusec;
 static GString *comp_info_str;
@@ -126,6 +146,7 @@
   pcap_t        *pch;
   wtap_dumper   *pdh;
   jmp_buf        stopenv;
+  gboolean       output_to_pipe;
 } loop_data;
 
 static loop_data ld;
@@ -325,6 +346,7 @@
   dfilter_t           *rfcode = NULL;
   e_prefs             *prefs;
   char                 badopt;
+  struct stat          sstat;
 
   /* Register all dissectors; we must do this before checking for the
      "-G" flag, as the "-G" flag dumps information registered by the
@@ -670,6 +692,21 @@
     }
   }
 
+  /* See if capture file is a pipe */
+  ld.output_to_pipe = FALSE;
+  if (cfile.save_file != NULL) {
+    if (stat(cfile.save_file, &sstat) < 0) {
+      if (errno != ENOENT && errno != ENOTDIR) {
+        fprintf(stderr, "tethereal: error on output capture file: %s\n",
+                  strerror(errno));
+        exit(2);
+      }
+    } else {
+      if (S_ISFIFO(sstat.st_mode))
+        ld.output_to_pipe = TRUE;
+    }
+  }
+
 #ifdef HAVE_LIBPCAP
   /* If they didn't specify a "-w" flag, but specified a maximum capture
      file size, tell them that this doesn't work, and exit. */
@@ -684,17 +721,26 @@
           a file;
        b) ring buffer only works if you're saving in libpcap format;
        c) it makes no sense to enable the ring buffer if the maximum
-          file size is set to "infinite". */
+          file size is set to "infinite";
+       d) file must not be a pipe. */
     if (cfile.save_file == NULL) {
-      fprintf(stderr, "tethereal: Ring buffer requested, but capture isn't being saved to a file.\n");
+      fprintf(stderr, "tethereal: Ring buffer requested, but "
+        "capture isn't being saved to a file.\n");
       exit(2);
     }
     if (out_file_type != WTAP_FILE_PCAP) {
-      fprintf(stderr, "tethereal: Ring buffer requested, but capture isn't being saved in libpcap format.\n");
+      fprintf(stderr, "tethereal: Ring buffer requested, but "
+        "capture isn't being saved in libpcap format.\n");
       exit(2);
     }
     if (!capture_opts.has_autostop_filesize) {
-      fprintf(stderr, "tethereal: Ring buffer requested, but no maximum capture file size was specified.\n");
+      fprintf(stderr, "tethereal: Ring buffer requested, but "
+        "no maximum capture file size was specified.\n");
+      exit(2);
+    }
+    if (ld.output_to_pipe) {
+      fprintf(stderr, "tethereal: Ring buffer requested, but "
+        "capture file is a pipe.\n");
       exit(2);
     }
   }
@@ -836,7 +882,7 @@
   bpf_u_int32 netnum, netmask;
   struct bpf_program fcode;
   void        (*oldhandler)(int);
-  int         err;
+  int         err = 0;
   volatile int inpkts = 0;
   char        errmsg[1024+1];
   condition  *volatile cnd_stop_capturesize = NULL;
@@ -846,6 +892,7 @@
   char       *libpcap_warn;
 #endif
   struct pcap_stat stats;
+  gboolean    write_err = FALSE;
   gboolean    dump_ok;
 
   /* Initialize all data structures used for dissection. */
@@ -977,7 +1024,6 @@
 
   /* Let the user know what interface was chosen. */
   fprintf(stderr, "Capturing on %s\n", cfile.iface);
-  fflush(stderr);
 
   /* initialize capture stop conditions */ 
   init_capture_stop_conditions();
@@ -1011,8 +1057,8 @@
          its maximum size. */
       if (capture_opts.ringbuffer_on) {
         /* Switch to the next ringbuffer file */
-        if (ringbuf_switch_file(&cfile, &ld.pdh, &err) == TRUE) {
-          /* File switch failed: reset the condition */
+        if (ringbuf_switch_file(&cfile, &ld.pdh, &err)) {
+          /* File switch succeeded: reset the condition */
           cnd_reset(cnd_stop_capturesize);
         } else {
           /* File switch failed: stop here */
@@ -1045,6 +1091,22 @@
 	pcap_geterr(ld.pch));
   }
 
+  if (err != 0) {
+    show_capture_file_io_error(cfile.save_file, err, FALSE);
+    write_err = TRUE;
+  }
+
+  if (cfile.save_file != NULL) {
+    /* We're saving to a file or files; close all files. */
+    if (capture_opts.ringbuffer_on) {
+      dump_ok = ringbuf_wtap_dump_close(&cfile, &err);
+    } else {
+      dump_ok = wtap_dump_close(ld.pdh, &err);
+    }
+    if (!dump_ok && ! write_err)
+      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) {
@@ -1056,24 +1118,13 @@
 	pcap_geterr(ld.pch));
   }
 /* Report the number of captured packets if not reported during capture and
-   we are not saving to a file. */
+   we are saving to a file. */
   if (quiet && (cfile.save_file != NULL)) {
-    fprintf(stderr, "\r%u packets captured\n", cfile.count);
+    fprintf(stderr, "%u packets captured\n", cfile.count);
   }
 
   pcap_close(ld.pch);
 
-  if (cfile.save_file != NULL) {
-    /* We're saving to a file or files; close all files. */
-    if (capture_opts.ringbuffer_on) {
-      dump_ok = ringbuf_wtap_dump_close(&cfile, &err);
-    } else {
-      dump_ok = wtap_dump_close(ld.pdh, &err);
-    }
-    if (!dump_ok)
-      show_capture_file_io_error(cfile.save_file, err, TRUE);
-  }
-
   return TRUE;
 
 error:
@@ -1115,7 +1166,8 @@
 /* Report packet capture count if not quiet */
     if (!quiet) {
       fprintf(stderr, "\r%u ", cfile.count);
-      fflush(stdout);
+      /* stderr could be line buffered */
+      fflush(stderr);
     }
   } else {
     wtap_dispatch_cb_print((u_char *)&args, &whdr, 0, &pseudo_header, pd);
@@ -1327,6 +1379,7 @@
   wtap_dumper  *pdh = args->pdh;
   frame_data    fdata;
   int           err;
+  gboolean      io_ok;
   gboolean      passed;
   epan_dissect_t *edt;
 
@@ -1342,11 +1395,17 @@
     edt = NULL;
   }
   if (passed) {
-    if (!wtap_dump(pdh, phdr, pseudo_header, buf, &err)) {
-#ifdef HAVE_LIBPCAP
-      if (ld.pch != NULL) {
-      	/* We're capturing packets, so we're printing a count of packets
-	   captured; move to the line after the count. */
+    io_ok = wtap_dump(pdh, phdr, pseudo_header, buf, &err);
+    if (io_ok && ld.output_to_pipe) {
+      io_ok = ! fflush(wtap_dump_file(ld.pdh));
+      if (!io_ok)
+        err = errno;
+    }
+    if (!io_ok) {
+#ifdef HAVE_LIBPCAP
+      if (ld.pch != NULL && !quiet) {
+      	/* We're capturing packets, so (if -q not specified) we're printing
+           a count of packets captured; move to the line after the count. */
         fprintf(stderr, "\n");
       }
 #endif
--- ringbuffer.c.orig	Sat May  4 11:10:42 2002
+++ ringbuffer.c	Sun Jun 16 00:09:55 2002
@@ -219,7 +219,12 @@
         }
         return NULL;
       }
-      rb_data.files[i].start_pos = ftell(fh);
+      if ((rb_data.files[i].start_pos = ftell(fh)) < 0) {
+        if (err != NULL) {
+          *err = errno;
+        }
+        return NULL;
+      }
       clearerr(fh);
     }
   }
@@ -236,6 +241,7 @@
 {
   int   next_file_num;
   FILE *fh;
+  gboolean err_on_next = FALSE;
 
   /* flush the current file */
   fh = wtap_dump_file(rb_data.files[rb_data.curr_file_num].pdh);
@@ -254,7 +260,11 @@
   if (!rb_data.files[next_file_num].is_new) {
     /* rewind to the position after the file header */
     fh = wtap_dump_file(rb_data.files[next_file_num].pdh);
-    fseek(fh, rb_data.files[next_file_num].start_pos, SEEK_SET);
+    if (fseek(fh, rb_data.files[next_file_num].start_pos, SEEK_SET) < 0) {
+      *err = errno;
+      /* Don't return straight away: have caller report correct save_file */
+      err_on_next = TRUE;
+    }
     wtap_set_bytes_dumped(rb_data.files[next_file_num].pdh,
       rb_data.files[next_file_num].start_pos);
     /* set the absolute file number */
@@ -272,6 +282,9 @@
   rb_data.files[next_file_num].is_new = FALSE;
   /* finally set the current file number */
   rb_data.curr_file_num = next_file_num;
+
+  if (err_on_next)
+    return FALSE;
 
   return TRUE;
 }