The Styleguide section has been moved to the Wireshark Developer's Guide.
[obnox/wireshark/wip.git] / dumpcap.c
index d6070f45f7b61ba936f7b30aa3e5e0f4ff318951..4e2f1325e4320e519cf07a3fa8ff66e7d5d95f08 100644 (file)
--- a/dumpcap.c
+++ b/dumpcap.c
@@ -278,11 +278,12 @@ static loop_data   global_ld;
 
 
 /*
- * Timeout, in milliseconds, for reads from the stream of captured packets.
+ * Timeout, in milliseconds, for reads from the stream of captured packets
+ * from a capture device.
  *
  * A bug in Mac OS X 10.6 and 10.6.1 causes calls to pcap_open_live(), in
  * 64-bit applications, with sub-second timeouts not to work.  The bug is
- * fixed in 10.6.2.
+ * fixed in 10.6.2, re-broken in 10.6.3, and again fixed in 10.6.5.
  */
 #if defined(__APPLE__) && defined(__LP64__)
 static gboolean need_timeout_workaround;
@@ -293,9 +294,21 @@ static gboolean need_timeout_workaround;
 #endif
 
 /*
- * Timeout, in microseconds, for threaded reads from a pipe.
+ * Timeout, in microseconds, for reads from the stream of captured packets
+ * from a pipe.  Pipes don't have the same problem that BPF devices do
+ * in OS X 10.6, 10.6.1, 10.6.3, and 10.6.4, so we always use a timeout
+ * of 250ms, i.e. the same value as CAP_READ_TIMEOUT when not on one
+ * of the offending versions of Snow Leopard.
+ *
+ * On Windows this value is converted to milliseconds and passed to
+ * WaitForSingleObject. If it's less than 1000 WaitForSingleObject
+ * will return immediately.
  */
-#define THREAD_READ_TIMEOUT   100
+#ifndef USE_THREADS
+#define PIPE_READ_TIMEOUT   250000
+#else
+#define PIPE_READ_TIMEOUT   100000
+#endif
 static const char *cap_pipe_err_str;
 
 static void
@@ -378,6 +391,7 @@ print_usage(gboolean print_ver) {
   /*fprintf(output, "\n");*/
   fprintf(output, "Output (files):\n");
   fprintf(output, "  -w <filename>            name of file to save (def: tempfile)\n");
+  fprintf(output, "  -g                       enable group read access on the output file(s)\n");
   fprintf(output, "  -b <ringbuffer opt.> ... duration:NUM - switch to next file after NUM secs\n");
   fprintf(output, "                           filesize:NUM - switch to next file after NUM KB\n");
   fprintf(output, "                              files:NUM - ringbuffer: replace after NUM files\n");
@@ -661,7 +675,7 @@ set_pcap_linktype(pcap_t *pcap_h, capture_options *capture_opts,
   char *set_linktype_err_str;
 
   if (capture_opts->linktype == -1)
-    return TRUE; /* just use the default */ 
+    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 */
@@ -712,6 +726,7 @@ compile_capture_filter(const char *iface, pcap_t *pcap_h,
   return TRUE;
 }
 
+#ifdef HAVE_BPF_IMAGE
 static gboolean
 show_filter_code(capture_options *capture_opts)
 {
@@ -765,6 +780,7 @@ show_filter_code(capture_options *capture_opts)
     printf("%s\n", bpf_image(insn, i));
   return TRUE;
 }
+#endif
 
 /*
  * capture_interface_list() is expected to do the right thing to get
@@ -1566,7 +1582,7 @@ static void *cap_pipe_read(void *ld_ptr) {
 static int
 cap_pipe_select(int pipe_fd) {
   fd_set      rfds;
-  struct timeval timeout, *pto;
+  struct timeval timeout;
   int sel_ret;
 
   cap_pipe_err_str = "Unknown error";
@@ -1574,11 +1590,10 @@ cap_pipe_select(int pipe_fd) {
   FD_ZERO(&rfds);
   FD_SET(pipe_fd, &rfds);
 
-  timeout.tv_sec = 0;
-  timeout.tv_usec = CAP_READ_TIMEOUT * 1000;
-  pto = &timeout;
+  timeout.tv_sec = PIPE_READ_TIMEOUT / 1000000;
+  timeout.tv_usec = PIPE_READ_TIMEOUT % 1000000;
 
-  sel_ret = select(pipe_fd+1, &rfds, NULL, NULL, pto);
+  sel_ret = select(pipe_fd+1, &rfds, NULL, NULL, &timeout);
   if (sel_ret < 0)
     cap_pipe_err_str = strerror(errno);
   return sel_ret;
@@ -1977,7 +1992,7 @@ cap_pipe_dispatch(loop_data *ld, guchar *data, char *errmsg, int errmsgl)
     ld->cap_pipe_bytes_read += b;
 #else /* USE_THREADS */
     g_get_current_time(&wait_time);
-    g_time_val_add(&wait_time, THREAD_READ_TIMEOUT);
+    g_time_val_add(&wait_time, PIPE_READ_TIMEOUT);
     q_status = g_async_queue_timed_pop(cap_pipe_done_q, &wait_time);
     if (ld->cap_pipe_err == PIPEOF) {
       result = PD_PIPE_EOF;
@@ -2026,7 +2041,7 @@ cap_pipe_dispatch(loop_data *ld, guchar *data, char *errmsg, int errmsgl)
     ld->cap_pipe_bytes_read += b;
 #else /* USE_THREADS */
     g_get_current_time(&wait_time);
-    g_time_val_add(&wait_time, THREAD_READ_TIMEOUT);
+    g_time_val_add(&wait_time, PIPE_READ_TIMEOUT);
     q_status = g_async_queue_timed_pop(cap_pipe_done_q, &wait_time);
     if (ld->cap_pipe_err == PIPEOF) {
       result = PD_PIPE_EOF;
@@ -2620,6 +2635,29 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld,
   return ld->packet_count - packet_count_before;
 }
 
+#ifdef _WIN32
+/* Isolate the Universally Unique Identifier from the interface.  Basically, we
+ * want to grab only the characters between the '{' and '}' delimiters. 
+ * 
+ * Returns a GString that must be freed with g_string_free(). */
+static GString *isolate_uuid(const char *iface)
+{
+    gchar *ptr;
+    GString *gstr;
+
+    ptr = strchr(iface, '{');
+    if (ptr == NULL)
+        return g_string_new(iface);
+    gstr = g_string_new(ptr + 1);
+
+    ptr = strchr(gstr->str, '}');
+    if (ptr == NULL)
+        return gstr;
+
+    gstr = g_string_truncate(gstr, ptr - gstr->str);
+    return gstr;
+}
+#endif
 
 /* open the output file (temporary/specified name/ringbuffer/named pipe/stdout) */
 /* Returns TRUE if the file opened successfully, FALSE otherwise. */
@@ -2629,6 +2667,7 @@ capture_loop_open_output(capture_options *capture_opts, int *save_file_fd,
 
   char *tmpname;
   gchar *capfile_name;
+  gchar *prefix;
   gboolean is_tempfile;
 #ifndef _WIN32
   int ret;
@@ -2666,7 +2705,8 @@ capture_loop_open_output(capture_options *capture_opts, int *save_file_fd,
       if (capture_opts->multi_files_on) {
         /* ringbuffer is enabled */
         *save_file_fd = ringbuf_init(capfile_name,
-            (capture_opts->has_ring_num_files) ? capture_opts->ring_num_files : 0);
+            (capture_opts->has_ring_num_files) ? capture_opts->ring_num_files : 0,
+            capture_opts->group_read_access);
 
         /* we need the ringbuf name */
         if(*save_file_fd != -1) {
@@ -2676,13 +2716,23 @@ capture_loop_open_output(capture_options *capture_opts, int *save_file_fd,
       } else {
         /* Try to open/create the specified file for use as a capture buffer. */
         *save_file_fd = ws_open(capfile_name, O_RDWR|O_BINARY|O_TRUNC|O_CREAT,
-                             0600);
+                             (capture_opts->group_read_access) ? 0640 : 0600);
       }
     }
     is_tempfile = FALSE;
   } else {
     /* Choose a random name for the temporary capture buffer */
-    *save_file_fd = create_tempfile(&tmpname, "wireshark");
+#ifdef _WIN32
+    GString *iface;
+
+    iface = isolate_uuid(capture_opts->iface);
+    prefix = g_strconcat("wireshark_", g_basename(iface->str), NULL);
+    g_string_free(iface, TRUE);
+#else
+    prefix = g_strconcat("wireshark_", g_basename(capture_opts->iface), NULL);
+#endif
+    *save_file_fd = create_tempfile(&tmpname, prefix);
+    g_free(prefix);
     capfile_name = g_strdup(tmpname);
     is_tempfile = TRUE;
   }
@@ -2747,6 +2797,9 @@ do_file_switch_or_stop(capture_options *capture_opts,
     if (ringbuf_switch_file(&global_ld.pdh, &capture_opts->save_file,
                             &global_ld.save_file_fd, &global_ld.err)) {
       gboolean successful;
+#ifndef _WIN32
+      int ret;
+#endif
 
       /* File switch succeeded: reset the conditions */
       global_ld.bytes_written = 0;
@@ -2775,6 +2828,10 @@ do_file_switch_or_stop(capture_options *capture_opts,
         report_packet_count(global_ld.inpkts_to_sync_pipe);
       global_ld.inpkts_to_sync_pipe = 0;
       report_new_capture_file(capture_opts->save_file);
+
+#ifndef _WIN32
+      ret = fchown(global_ld.save_file_fd, capture_opts->owner, capture_opts->group);
+#endif
     } else {
       /* File switch failed: stop here */
       global_ld.go = FALSE;
@@ -3042,7 +3099,8 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
     cap_err_str = pcap_geterr(global_ld.pcap_h);
     if (strcmp(cap_err_str, "recvfrom: Network is down") == 0 ||
         strcmp(cap_err_str, "read: Device not configured") == 0 ||
-        strcmp(cap_err_str, "read: I/O error") == 0) {
+        strcmp(cap_err_str, "read: I/O error") == 0 ||
+        strcmp(cap_err_str, "read error: PacketReceivePacket failed") == 0) {
       report_capture_error("The network adapter on which the capture was being done "
                            "is no longer running; the capture has stopped.",
                            "");
@@ -3292,6 +3350,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"
@@ -3326,7 +3392,7 @@ main(int argc, char *argv[])
 #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:"
+#define OPTSTRING "a:" OPTSTRING_A "b:" OPTSTRING_B "c:" OPTSTRING_d "Df:ghi:" 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) {
@@ -3337,12 +3403,12 @@ main(int argc, char *argv[])
 
 #if defined(__APPLE__) && defined(__LP64__)
   /*
-   * Is this Mac OS X 10.6.x, other than 10.6.2?  If so, we need a bug
-   * workaround - timeouts less than 1 second don't work with libpcap
+   * Is this Mac OS X 10.6.0, 10.6.1, 10.6.3, or 10.6.4?  If so, we need
+   * a bug workaround - timeouts less than 1 second don't work with libpcap
    * in 64-bit code.  (The bug was introduced in 10.6, fixed in 10.6.2,
-   * and re-introduced in 10.6.3.  We don't know whether it'll be fixed
-   * again in a later 10.6.x release; we'll assume that it'll be fixed
-   * in any future major releases.)
+   * re-introduced in 10.6.3, not fixed in 10.6.4, and fixed in 10.6.5.
+   * The problem is extremely unlikely to be reintroduced in a future
+   * release.)
    */
   if (uname(&osinfo) == 0) {
     /*
@@ -3350,15 +3416,10 @@ main(int argc, char *argv[])
      * {x+4}.y.0 (except that 10.6.1 appears to have a uname version
      * number of 10.0.0, not 10.1.0 - go figure).
      */
-    if (strncmp(osinfo.release, "10.", 3) == 0) {
-      /*
-       * OK, it's Snow Leopard - which version?
-       */
-      if (strcmp(osinfo.release, "10.2.0") != 0) {
-        /* Not 10.6.2. */
-        need_timeout_workaround = TRUE;
-      }
-    }
+    if (strcmp(osinfo.release, "10.0.0") == 0 ||       /* 10.6, 10.6.1 */
+        strcmp(osinfo.release, "10.3.0") == 0 ||       /* 10.6.3 */
+        strcmp(osinfo.release, "10.4.0") == 0)         /* 10.6.4 */
+      need_timeout_workaround = TRUE;
   }
 #endif
 
@@ -3550,7 +3611,7 @@ main(int argc, char *argv[])
   /*                                                                   */
   /* ----------------------------------------------------------------- */
 
-  get_credential_info();
+  init_process_policies();
 
 #ifdef HAVE_LIBCAP
   /* If 'started with special privileges' (and using libcap)  */
@@ -3584,7 +3645,7 @@ main(int argc, char *argv[])
         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);
+        get_compiled_version_info(comp_info_str, NULL, NULL);
 
         /* Assemble the run-time version information string */
         runtime_info_str = g_string_new("Running ");
@@ -3605,6 +3666,7 @@ main(int argc, char *argv[])
       case 'p':        /* Don't capture in promiscuous mode */
       case 's':        /* Set the snapshot (capture) length */
       case 'w':        /* Write to capture file x */
+      case 'g':        /* enable group read accesson file(s) */
       case 'y':        /* Set the pcap data link type */
 #ifdef HAVE_PCAP_REMOTE
       case 'u':        /* Use UDP for data transfer */