When dumpcap is run to get an interface list, interface capabilities, or
authorguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>
Mon, 17 May 2010 18:40:23 +0000 (18:40 +0000)
committerguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>
Mon, 17 May 2010 18:40:23 +0000 (18:40 +0000)
interface statistics, have its error messages come out as sync-pipe
errors, have it send a sync-pipe "success" message on success, and have
the callers get that message and display it.

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@32843 f5534014-38df-0310-8fa8-9805f1628bb7

capture.c
capture_ifinfo.c
capture_ifinfo.h
capture_sync.c
capture_sync.h
dumpcap.c
gtk/main.c
sync_pipe.h
tshark.c

index 6b799e0e24e626a743ec6022d89003d6eb5acd01..ad3bb3458ba347c1c39d3f68bc91ec6a98073eef 100644 (file)
--- a/capture.c
+++ b/capture.c
@@ -721,12 +721,17 @@ void
 capture_stat_stop(if_stat_cache_t *sc) {
     GList *sc_entry;
     if_stat_cache_item_t *sc_item;
+    int ret;
     gchar *msg;
 
     if (!sc)
         return;
 
-    sync_interface_stats_close(&sc->stat_fd, &sc->fork_child, &msg);
+    ret = sync_interface_stats_close(&sc->stat_fd, &sc->fork_child, &msg);
+    if (ret == -1) {
+       /* XXX - report failure? */
+        g_free(msg);
+    }
 
     for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
         sc_item = sc_entry->data;
index e9fc5347a0263c26e4e64e9b6e9b5dfc792100b3..a9648753bdf16343e782d0dccfe9c87f6f77aaf6 100644 (file)
@@ -70,7 +70,7 @@ capture_interface_list(int *err, char **err_str)
     int        ret;
     GList     *if_list = NULL;
     int        i, j;
-    gchar     *msg;
+    gchar     *data, *primary_msg, *secondary_msg;
     gchar    **raw_list, **if_parts, **addr_parts;
     gchar     *name;
     if_info_t *if_info;
@@ -79,25 +79,26 @@ capture_interface_list(int *err, char **err_str)
     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List ...");
 
     /* Try to get our interface list */
-    ret = sync_interface_list_open(&msg);
+    ret = sync_interface_list_open(&data, &primary_msg, &secondary_msg);
     if (ret != 0) {
         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List failed!");
         if (err_str) {
-            *err_str = msg;
+            *err_str = primary_msg;
         } else {
-            g_free(msg);
+            g_free(primary_msg);
         }
-        *err = CANT_RUN_DUMPCAP;
+        g_free(secondary_msg);
+        *err = CANT_GET_INTERFACE_LIST;
         return NULL;
     }
 
     /* Split our lines */
 #ifdef _WIN32
-    raw_list = g_strsplit(msg, "\r\n", 0);
+    raw_list = g_strsplit(data, "\r\n", 0);
 #else
-    raw_list = g_strsplit(msg, "\n", 0);
+    raw_list = g_strsplit(data, "\n", 0);
 #endif
-    g_free(msg);
+    g_free(data);
 
     for (i = 0; raw_list[i] != NULL; i++) {
         if_parts = g_strsplit(raw_list[i], "\t", 4);
@@ -162,31 +163,33 @@ capture_get_if_capabilities(const gchar *ifname, gboolean monitor_mode,
     if_capabilities_t *caps;
     GList              *linktype_list = NULL;
     int                 err, i;
-    gchar              *msg;
+    gchar              *data, *primary_msg, *secondary_msg;
     gchar             **raw_list, **lt_parts;
     data_link_info_t   *data_link_info;
 
     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities ...");
 
     /* Try to get our interface list */
-    err = sync_if_capabilities_open(ifname, monitor_mode, &msg);
+    err = sync_if_capabilities_open(ifname, monitor_mode, &data,
+                                    &primary_msg, &secondary_msg);
     if (err != 0) {
         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities failed!");
         if (err_str) {
-            *err_str = msg;
+            *err_str = primary_msg;
         } else {
-            g_free(msg);
+            g_free(primary_msg);
         }
+        g_free(secondary_msg);
         return NULL;
     }
 
     /* Split our lines */
 #ifdef _WIN32
-    raw_list = g_strsplit(msg, "\r\n", 0);
+    raw_list = g_strsplit(data, "\r\n", 0);
 #else
-    raw_list = g_strsplit(msg, "\n", 0);
+    raw_list = g_strsplit(data, "\n", 0);
 #endif
-    g_free(msg);
+    g_free(data);
 
     /*
      * First line is 0 if monitor mode isn't supported, 1 if it is.
index 31414c74ae2e7763b0b03d16528b09cfa0e26caa..2528b6b6ecfaa98d0b58ec3369b023778dc024ea 100644 (file)
@@ -60,7 +60,6 @@ extern GList *capture_interface_list(int *err, char **err_str);
 /* Error values from "get_interface_list()/capture_interface_list()". */
 #define        CANT_GET_INTERFACE_LIST 1       /* error getting list */
 #define        NO_INTERFACES_FOUND     2       /* list is empty */
-#define        CANT_RUN_DUMPCAP        3       /* problem running dumpcap */
 
 void free_interface_list(GList *if_list);
 
index f412c4e51af9ab727a49023a1033184ca2305577..639bebff70c42ace75ac2f944b695bf47cb307c4 100644 (file)
@@ -113,7 +113,9 @@ static const char *sync_pipe_signame(int);
 
 
 static gboolean sync_pipe_input_cb(gint source, gpointer user_data);
-static void sync_pipe_wait_for_child(capture_options *capture_opts);
+static int sync_pipe_wait_for_child(int fork_child, gchar **msgp);
+static void pipe_convert_header(const guchar *header, int header_len, char *indicator, int *block_len);
+static int pipe_read_block(int pipe_fd, char *indicator, int len, char *msg);
 
 
 
@@ -576,19 +578,31 @@ sync_pipe_start(capture_options *capture_opts) {
 }
 
 /*
- * Open a pipe to dumpcap with the supplied arguments.  On success, *msg
- * is unchanged and 0 is returned; read_fd and fork_child point to the
- * pipe's file descriptor and child PID/handle, respectively.  On failure,
- * *msg points to an error message for the failure, and -1 is returned.
- * In the latter case, *msg must be freed with g_free().
+ * Open two pipes to dumpcap with the supplied arguments, one for its
+ * standard output and one for its standard error.
+ *
+ * On success, *msg is unchanged and 0 is returned; data_read_fd,
+ * messsage_read_fd, and fork_child point to the standard output pipe's
+ * file descriptor, the standard error pipe's file descriptor, and
+ * the child's PID/handle, respectively.
+ *
+ * On failure, *msg points to an error message for the failure, and -1 is
+ * returned, in which case *msg must be freed with g_free().
+ *
+ * XXX - this doesn't check the exit status of dumpcap if it can be
+ * started and its return status could be fetched.
  */
 /* XXX - This duplicates a lot of code in sync_pipe_start() */
+/* XXX - assumes PIPE_BUF_SIZE > SP_MAX_MSG_LEN */
 #define PIPE_BUF_SIZE 5120
 static int
-sync_pipe_open_command(const char** argv, int *read_fd, int *fork_child, gchar **msg) {
+sync_pipe_open_command(const char** argv, int *data_read_fd,
+                       int *message_read_fd, int *fork_child, gchar **msg)
+{
+    enum PIPES { PIPE_READ, PIPE_WRITE };   /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
 #ifdef _WIN32
-    HANDLE sync_pipe_read;                  /* pipe used to send messages from child to parent */
-    HANDLE sync_pipe_write;                 /* pipe used to send messages from parent to child */
+    HANDLE sync_pipe[2];                    /* pipe used to send messages from child to parent */
+    HANDLE data_pipe[2];                    /* pipe used to send data from child to parent */
     GString *args = g_string_sized_new(200);
     gchar *quoted_arg;
     SECURITY_ATTRIBUTES sa;
@@ -598,12 +612,13 @@ sync_pipe_open_command(const char** argv, int *read_fd, int *fork_child, gchar *
 #else
     char errmsg[1024+1];
     int sync_pipe[2];                       /* pipe used to send messages from child to parent */
-    enum PIPES { PIPE_READ, PIPE_WRITE };   /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
+    int data_pipe[2];                       /* pipe used to send data from child to parent */
 #endif
 
     *fork_child = -1;
-    *read_fd = -1;
-    g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_run_command");
+    *data_read_fd = -1;
+    *message_read_fd = -1;
+    g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_open_command");
 
     if (!msg) {
         /* We can't return anything */
@@ -619,16 +634,28 @@ sync_pipe_open_command(const char** argv, int *read_fd, int *fork_child, gchar *
     sa.bInheritHandle = TRUE;
     sa.lpSecurityDescriptor = NULL;
 
-    /* Create a pipe for the child process */
+    /* Create a pipe for the child process to send us messages */
     /* (increase this value if you have trouble while fast capture file switches) */
-    if (! CreatePipe(&sync_pipe_read, &sync_pipe_write, &sa, 5120)) {
-        /* Couldn't create the pipe between parent and child. */
+    if (! CreatePipe(&sync_pipe[PIPE_READ], &sync_pipe[PIPE_WRITE], &sa, 5120)) {
+        /* Couldn't create the message pipe between parent and child. */
         *msg = g_strdup_printf("Couldn't create sync pipe: %s", strerror(errno));
         g_free( (gpointer) argv[0]);
         g_free( (gpointer) argv);
         return -1;
     }
 
+    /* Create a pipe for the child process to send us data */
+    /* (increase this value if you have trouble while fast capture file switches) */
+    if (! CreatePipe(&data_pipe[PIPE_READ], &data_pipe[PIPE_WRITE], &sa, 5120)) {
+        /* Couldn't create the message pipe between parent and child. */
+        *msg = g_strdup_printf("Couldn't create data pipe: %s", strerror(errno));
+        CloseHandle(sync_pipe[PIPE_READ]);
+        CloseHandle(sync_pipe[PIPE_WRITE]);
+        g_free( (gpointer) argv[0]);
+        g_free( (gpointer) argv);
+        return -1;
+    }
+
     /* init STARTUPINFO */
     memset(&si, 0, sizeof(si));
     si.cb           = sizeof(si);
@@ -639,9 +666,8 @@ sync_pipe_open_command(const char** argv, int *read_fd, int *fork_child, gchar *
     si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
     si.wShowWindow  = SW_HIDE;  /* this hides the console window */
     si.hStdInput = NULL;
-    si.hStdOutput = sync_pipe_write;
-    si.hStdError = sync_pipe_write;
-    /*si.hStdError = (HANDLE) _get_osfhandle(2);*/
+    si.hStdOutput = data_pipe[PIPE_WRITE];
+    si.hStdError = sync_pipe[PIPE_WRITE];
 #endif
 
     /* convert args array into a single string */
@@ -658,9 +684,11 @@ sync_pipe_open_command(const char** argv, int *read_fd, int *fork_child, gchar *
     if(!CreateProcess(NULL, utf_8to16(args->str), NULL, NULL, TRUE,
                       CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
         *msg = g_strdup_printf("Couldn't run %s in child process: error %u",
-                        args->str, GetLastError());
-        CloseHandle(sync_pipe_read);
-        CloseHandle(sync_pipe_write);
+                               args->str, GetLastError());
+        CloseHandle(data_pipe[PIPE_READ]);
+        CloseHandle(data_pipe[PIPE_WRITE]);
+        CloseHandle(sync_pipe[PIPE_READ]);
+        CloseHandle(sync_pipe[PIPE_WRITE]);
         g_free( (gpointer) argv[0]);
         g_free( (gpointer) argv);
         return -1;
@@ -668,30 +696,46 @@ sync_pipe_open_command(const char** argv, int *read_fd, int *fork_child, gchar *
     *fork_child = (int) pi.hProcess;
     g_string_free(args, TRUE);
 
-    /* associate the operating system filehandle to a C run-time file handle */
+    /* associate the operating system filehandles to C run-time file handles */
     /* (good file handle infos at: http://www.flounder.com/handles.htm) */
-    *read_fd = _open_osfhandle( (long) sync_pipe_read, _O_BINARY);
-
+    *data_read_fd = _open_osfhandle( (long) data_pipe[PIPE_READ], _O_BINARY);
+    *message_read_fd = _open_osfhandle( (long) sync_pipe[PIPE_READ], _O_BINARY);
 #else /* _WIN32 */
+    /* Create a pipe for the child process to send us messages */
     if (pipe(sync_pipe) < 0) {
-        /* Couldn't create the pipe between parent and child. */
+        /* Couldn't create the message pipe between parent and child. */
         *msg = g_strdup_printf("Couldn't create sync pipe: %s", strerror(errno));
         g_free( (gpointer) argv[0]);
         g_free(argv);
         return -1;
     }
 
+    /* Create a pipe for the child process to send us data */
+    if (pipe(data_pipe) < 0) {
+        /* Couldn't create the data pipe between parent and child. */
+        *msg = g_strdup_printf("Couldn't create data pipe: %s", strerror(errno));
+        ws_close(sync_pipe[PIPE_READ]);
+        ws_close(sync_pipe[PIPE_WRITE]);
+        g_free( (gpointer) argv[0]);
+        g_free(argv);
+        return -1;
+    }
+
     if ((*fork_child = fork()) == 0) {
         /*
          * Child process - run dumpcap with the right arguments to make
          * it just capture with the specified capture parameters
          */
-        dup2(sync_pipe[PIPE_WRITE], 1);
+        dup2(data_pipe[PIPE_WRITE], 1);
+        ws_close(data_pipe[PIPE_READ]);
+        ws_close(data_pipe[PIPE_WRITE]);
+        dup2(sync_pipe[PIPE_WRITE], 2);
         ws_close(sync_pipe[PIPE_READ]);
+        ws_close(sync_pipe[PIPE_WRITE]);
         execv(argv[0], (gpointer)argv);
         g_snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
                   argv[0], strerror(errno));
-        sync_pipe_errmsg_to_parent(1, errmsg, "");
+        sync_pipe_errmsg_to_parent(2, errmsg, "");
 
         /* Exit with "_exit()", so that we don't close the connection
            to the X server (and cause stuff buffered up by our parent but
@@ -703,7 +747,8 @@ sync_pipe_open_command(const char** argv, int *read_fd, int *fork_child, gchar *
         _exit(1);
     }
 
-    *read_fd = sync_pipe[PIPE_READ];
+    *data_read_fd = data_pipe[PIPE_READ];
+    *message_read_fd = sync_pipe[PIPE_READ];
 #endif
 
     g_free( (gpointer) argv[0]);  /* exename */
@@ -712,20 +757,23 @@ sync_pipe_open_command(const char** argv, int *read_fd, int *fork_child, gchar *
        sync pipe. */
     g_free( (gpointer) argv);  /* free up arg array */
 
-    /* Close the write side of the pipe, so that only the child has it
-       open, and thus it completely closes, and thus returns to us
-       an EOF indication, if the child closes it (either deliberately
+    /* Close the write sides of the pipes, so that only the child has them
+       open, and thus they completely close, and thus return to us
+       an EOF indication, if the child closes them (either deliberately
        or by exiting abnormally). */
 #ifdef _WIN32
-    CloseHandle(sync_pipe_write);
+    CloseHandle(data_pipe[PIPE_WRITE]);
+    CloseHandle(sync_pipe[PIPE_WRITE]);
 #else
+    ws_close(data_pipe[PIPE_WRITE]);
     ws_close(sync_pipe[PIPE_WRITE]);
 #endif
 
     if (*fork_child == -1) {
         /* We couldn't even create the child process. */
         *msg = g_strdup_printf("Couldn't create child process: %s", strerror(errno));
-        ws_close(*read_fd);
+        ws_close(*data_read_fd);
+        ws_close(*message_read_fd);
         return -1;
     }
 
@@ -741,125 +789,222 @@ sync_pipe_open_command(const char** argv, int *read_fd, int *fork_child, gchar *
  * freed with g_free().
  */
 static int
-#ifdef _WIN32
-sync_pipe_close_command(int *read_fd, int *fork_child, gchar **msg) {
-#else
-sync_pipe_close_command(int *read_fd, gchar **msg) {
-#endif
-    int fork_child_status;
-
-    ws_close(*read_fd);
-
-    g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_close_command: wait till child closed");
+sync_pipe_close_command(int *data_read_fd, int *message_read_fd,
+                        int *fork_child, gchar **msg)
+{
+    ws_close(*data_read_fd);
+    if (message_read_fd != NULL)
+        ws_close(*message_read_fd);
 
 #ifdef _WIN32
     /* XXX - Should we signal the child somehow? */
     sync_pipe_kill(*fork_child);
-    if (_cwait(&fork_child_status, *fork_child, _WAIT_CHILD) == -1) {
-        *msg = g_strdup_printf("Child capture process stopped unexpectedly "
-            "(errno:%u)", errno);
-        return -1;
-    }
-#else
-    if (wait(&fork_child_status) != -1) {
-        if (WIFEXITED(fork_child_status)) {
-            /* The child exited. */
-            fork_child_status = WEXITSTATUS(fork_child_status);
-        } else {
-            if (WIFSTOPPED(fork_child_status)) {
-                /* It stopped, rather than exiting.  "Should not happen." */
-                *msg = g_strdup_printf("Child capture process stopped: %s",
-                    sync_pipe_signame(WSTOPSIG(fork_child_status)));
-            } else if (WIFSIGNALED(fork_child_status)) {
-                /* It died with a signal. */
-                *msg = g_strdup_printf("Child capture process died: %s%s",
-                   sync_pipe_signame(WTERMSIG(fork_child_status)),
-                   WCOREDUMP(fork_child_status) ? " - core dumped" : "");
-            } else {
-                /* What?  It had to either have exited, or stopped, or died with
-                   a signal; what happened here? */
-                *msg = g_strdup_printf("Child capture process died: wait status %#o",
-                    fork_child_status);
-            }
-            return -1;
-        }
-    } else {
-      *msg = g_strdup_printf("Child capture process stopped unexpectedly "
-        "(errno:%u)", errno);
-      return -1;
-    }
 #endif
-    return 0;
+
+    return sync_pipe_wait_for_child(*fork_child, msg);
 }
 
 /*
- * Run dumpcap with the supplied arguments.  On success, *msg points to
- * a buffer containing the dumpcap output, and 0 is returned.  On failure,
- * *msg points to an error message, and -1 is returned.  In either case,
- * *msg must be freed with g_free().
+ * Run dumpcap with the supplied arguments.
  *
- * XXX - this doesn't check the exit status of dumpcap if it can be
- * started and its return status could be fetched.
+ * On success, *data points to a buffer containing the dumpcap output,
+ * *primary_msg and *secondary_message are NULL, and 0 is returned; *data
+ * must be freed with g_free().
+ *
+ * On failure, *data is NULL, *primary_msg points to an error message,
+ * *secondary_msg either points to an additional error message or is
+ * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
+ * must be freed with g_free().
  */
 /* XXX - This duplicates a lot of code in sync_pipe_start() */
+/* XXX - assumes PIPE_BUF_SIZE > SP_MAX_MSG_LEN */
 #define PIPE_BUF_SIZE 5120
 static int
-sync_pipe_run_command(const char** argv, gchar **msg) {
-    int sync_pipe_read_fd, fork_child, ret;
-    gchar buf[PIPE_BUF_SIZE+1];
-    GString *msg_buf = NULL;
-    int count;
-
-    ret = sync_pipe_open_command(argv, &sync_pipe_read_fd, &fork_child, msg);
-
-    if (ret)
-       return ret;
-
-    /* We were able to set up to read dumpcap's output.  Do so. */
-    msg_buf = g_string_new("");
-    while ((count = ws_read(sync_pipe_read_fd, buf, PIPE_BUF_SIZE)) > 0) {
-        buf[count] = '\0';
-        g_string_append(msg_buf, buf);
+sync_pipe_run_command(const char** argv, gchar **data, gchar **primary_msg,
+                      gchar **secondary_msg)
+{
+  gchar *msg;
+  int data_pipe_read_fd, sync_pipe_read_fd, fork_child, ret;
+  gchar buffer[PIPE_BUF_SIZE+1];
+  int  nread;
+  char indicator;
+  int  primary_msg_len;
+  char *primary_msg_text;
+  int  secondary_msg_len;
+  char *secondary_msg_text;
+  GString *data_buf = NULL;
+  int count;
+
+  ret = sync_pipe_open_command(argv, &data_pipe_read_fd, &sync_pipe_read_fd,
+                               &fork_child, &msg);
+  if (ret == -1) {
+    *primary_msg = msg;
+    *secondary_msg = NULL;
+    *data = NULL;
+    return -1;
+  }
+
+  /*
+   * We were able to set up to read dumpcap's output.  Do so.
+   *
+   * First, wait for an SP_ERROR_MESSAGE or SP_SUCCESS message.
+   */
+  nread = pipe_read_block(sync_pipe_read_fd, &indicator, SP_MAX_MSG_LEN,
+                          buffer);
+  if(nread <= 0) {
+    /* We got a read error from the sync pipe, or we got no data at
+       all from the sync pipe, so we're not going to be getting any
+       data or error message from the child process.  Pick up its
+       exit status, and complain.
+
+       We don't have to worry about killing the child, if the sync pipe
+       returned an error. Usually this error is caused as the child killed
+       itself while going down. Even in the rare cases that this isn't the
+       case, the child will get an error when writing to the broken pipe
+       the next time, cleaning itself up then. */
+    ret = sync_pipe_wait_for_child(fork_child, primary_msg);
+    if (ret == 0) {
+      /* No unusual exit status; just report the read problem. */
+      if (nread == 0)
+        *primary_msg = g_strdup("Child dumpcap closed sync pipe prematurely");
+      else
+        *primary_msg = g_strdup("Error reading from sync pipe");
     }
+    *secondary_msg = NULL;
 
-#ifdef _WIN32
-    ret = sync_pipe_close_command(&sync_pipe_read_fd, &fork_child, msg);
-#else
-    ret = sync_pipe_close_command(&sync_pipe_read_fd, msg);
-#endif
+    return -1;
+  }
+
+  /* we got a valid message block from the child, process it */
+  switch(indicator) {
+
+  case SP_ERROR_MSG:
+    /*
+     * Error from dumpcap; there will be a primary message and a
+     * secondary message.
+     */
+
+    /* convert primary message */
+    pipe_convert_header(buffer, 4, &indicator, &primary_msg_len);
+    primary_msg_text = buffer+4;
+    /* convert secondary message */
+    pipe_convert_header(primary_msg_text + primary_msg_len, 4, &indicator,
+                        &secondary_msg_len);
+    secondary_msg_text = primary_msg_text + primary_msg_len + 4;
+    /* the capture child will close the sync_pipe, nothing to do */
 
-    if (ret) {
-       g_string_free(msg_buf, TRUE);
-       return ret;
+    /*
+     * Pick up the child status.
+     */
+    ret = sync_pipe_close_command(&data_pipe_read_fd, &sync_pipe_read_fd,
+                                  &fork_child, &msg);
+    if (ret == -1) {
+      /*
+       * Child process failed unexpectedly, or wait failed; msg is the
+       * error message.
+       */
+      *primary_msg = msg;
+      *secondary_msg = NULL;
+    } else {
+      /*
+       * Child process failed, but returned the expected exit status.
+       * Return the messages it gave us, and indicate failure.
+       */
+      *primary_msg = g_strdup(primary_msg_text);
+      *secondary_msg = g_strdup(secondary_msg_text);
+      ret = -1;
     }
+    *data = NULL;
+    break;
 
-    *msg = msg_buf->str;
-    g_string_free(msg_buf, FALSE);
-    return 0;
+  case SP_SUCCESS:
+    /* read the output from the command */
+    data_buf = g_string_new("");
+    while ((count = ws_read(data_pipe_read_fd, buffer, PIPE_BUF_SIZE)) > 0) {
+      buffer[count] = '\0';
+      g_string_append(data_buf, buffer);
+    }
+
+    /*
+     * Pick up the child status.
+     */
+    ret = sync_pipe_close_command(&data_pipe_read_fd, &sync_pipe_read_fd,
+                                  &fork_child, &msg);
+    if (ret == -1) {
+      /*
+       * Child process failed unexpectedly, or wait failed; msg is the
+       * error message.
+       */
+      *primary_msg = msg;
+      *secondary_msg = NULL;
+      g_string_free(data_buf, TRUE);
+      *data = NULL;
+    } else {
+      /*
+       * Child process succeeded.
+       */
+      *primary_msg = NULL;
+      *secondary_msg = NULL;
+      *data = data_buf->str;
+      g_string_free(data_buf, FALSE);
+    }
+    break;
+
+  default:
+    /*
+     * Pick up the child status.
+     */
+    ret = sync_pipe_close_command(&data_pipe_read_fd, &sync_pipe_read_fd,
+                                  &fork_child, &msg);
+    if (ret == -1) {
+      /*
+       * Child process failed unexpectedly, or wait failed; msg is the
+       * error message.
+       */
+      *primary_msg = msg;
+      *secondary_msg = NULL;
+    } else {
+      /*
+       * Child process returned an unknown status.
+       */
+      *primary_msg = g_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",
+                                     indicator);
+      *secondary_msg = NULL;
+      ret = -1;
+    }
+    *data = NULL;
+    break;
+  }
+  return ret;
 }
 
 /*
- * Get an interface list using dumpcap.  On success, *msg points to
- * a buffer containing the dumpcap output, and 0 is returned.  On failure,
- * *msg points to an error message, and -1 is returned.  In either case,
- * msg must be freed with g_free().
+ * Get the list of interfaces using dumpcap.
+ *
+ * On success, *data points to a buffer containing the dumpcap output,
+ * *primary_msg and *secondary_msg are NULL, and 0 is returned.  *data
+ * must be freed with g_free().
+ *
+ * On failure, *data is NULL, *primary_msg points to an error message,
+ * *secondary_msg either points to an additional error message or is
+ * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
+ * must be freed with g_free().
  */
 int
-sync_interface_list_open(gchar **msg) {
+sync_interface_list_open(gchar **data, gchar **primary_msg,
+                         gchar **secondary_msg)
+{
     int argc;
     const char **argv;
 
-    if (!msg) {
-        /* We can't return anything */
-        return -1;
-    }
-
     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_interface_list_open");
 
     argv = init_pipe_args(&argc);
 
     if (!argv) {
-        *msg = g_strdup_printf("We don't know where to find dumpcap.");
+        *primary_msg = g_strdup("We don't know where to find dumpcap.");
+        *secondary_msg = NULL;
+        *data = NULL;
         return -1;
     }
 
@@ -867,51 +1012,42 @@ sync_interface_list_open(gchar **msg) {
     argv = sync_pipe_add_arg(argv, &argc, "-D");
     argv = sync_pipe_add_arg(argv, &argc, "-M");
 
-#if 0
-    /* dumpcap should be running in capture child mode (hidden feature)                   */
-    /* XXX: Actually: don't run dumpcap in capture_child_mode.                            */
-    /*     Instead run dumpcap in 'normal' mode so that dumpcap err msgs are sent to      */
-    /*     stderr in normal format and are then sent to whereever our stderr goes.        */
-    /*     Note: Using 'dumpcap -D -M -Z' (capture_child mode) changes only the format of */
-    /*           dumpcap err msgs. That is: dumpcap in capture_child mode outputs err     */
-    /*           msgs to stderr in a special type/len/string format which would then      */
-    /*           currently be sent as is to stderr resulting in garbled output.           */
-    /*     ToDo: Revise this code to be similar to sync_pipe_start so that 'dumpcap -Z'   */
-    /*     special format error messages to stderr are captured and returned to caller    */
-    /*     (eg: so can be processed and displayed in a pop-up box).                       */
 #ifndef DEBUG_CHILD
+    /* Run dumpcap in capture child mode */
     argv = sync_pipe_add_arg(argv, &argc, "-Z");
     argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
 #endif
-#endif
-
-    return sync_pipe_run_command(argv, msg);
+    return sync_pipe_run_command(argv, data, primary_msg, secondary_msg);
 }
 
 /*
- * Get interface capabilities using dumpcap.  On success, *msg points to
- * a buffer containing the dumpcap output, and 0 is returned.  On failure,
- * *msg points to an error message, and -1 is returned.  In either case,
- * *msg must be freed with g_free().
+ * Get the capabilities of an interface using dumpcap.
+ *
+ * On success, *data points to a buffer containing the dumpcap output,
+ * *primary_msg and *secondary_msg are NULL, and 0 is returned.  *data
+ * must be freed with g_free().
+ *
+ * On failure, *data is NULL, *primary_msg points to an error message,
+ * *secondary_msg either points to an additional error message or is
+ * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
+ * must be freed with g_free().
  */
 int
 sync_if_capabilities_open(const gchar *ifname, gboolean monitor_mode,
-                          gchar **msg)
+                          gchar **data, gchar **primary_msg,
+                          gchar **secondary_msg)
 {
     int argc;
     const char **argv;
 
-    if (!msg) {
-        /* We can't return anything */
-        return -1;
-    }
-
     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_linktype_list_open");
 
     argv = init_pipe_args(&argc);
 
     if (!argv) {
-        *msg = g_strdup_printf("We don't know where to find dumpcap.");
+        *primary_msg = g_strdup("We don't know where to find dumpcap.");
+        *secondary_msg = NULL;
+        *data = NULL;
         return -1;
     }
 
@@ -923,24 +1059,12 @@ sync_if_capabilities_open(const gchar *ifname, gboolean monitor_mode,
         argv = sync_pipe_add_arg(argv, &argc, "-I");
     argv = sync_pipe_add_arg(argv, &argc, "-M");
 
-#if 0
-    /* dumpcap should be running in capture child mode (hidden feature)                   */
-    /* XXX: Actually: don't run dumpcap in capture_child_mode.                            */
-    /*     Instead run dumpcap in 'normal' mode so that dumpcap err msgs are sent to      */
-    /*     stderr in normal format and are then sent to whereever our stderr goes.        */
-    /*     Note: Using 'dumpcap -L -M -Z' (capture_child mode) changes only the format of */
-    /*           dumpcap err msgs. That is: dumpcap in capture_child mode outputs err     */
-    /*           msgs to stderr in a special type/len/string format which would then      */
-    /*           currently be sent as is to stderr resulting in garbled output.           */
-    /*     ToDo: Revise this code to be similar to sync_pipe_start so that 'dumpcap -Z'   */
-    /*     special format error messages to stderr are captured and returned to caller    */
-    /*     (eg: so can be processed and displayed in a pop-up box).                       */
 #ifndef DEBUG_CHILD
+    /* Run dumpcap in capture child mode */
     argv = sync_pipe_add_arg(argv, &argc, "-Z");
     argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
 #endif
-#endif
-    return sync_pipe_run_command(argv, msg);
+    return sync_pipe_run_command(argv, data, primary_msg, secondary_msg);
 }
 
 /*
@@ -950,66 +1074,150 @@ sync_if_capabilities_open(const gchar *ifname, gboolean monitor_mode,
  * that must be g_free()d, and -1 will be returned.
  */
 int
-sync_interface_stats_open(int *read_fd, int *fork_child, gchar **msg) {
-    int argc;
-    const char **argv;
+sync_interface_stats_open(int *data_read_fd, int *fork_child, gchar **msg)
+{
+  int argc;
+  const char **argv;
+  int message_read_fd, ret;
+  gchar buffer[PIPE_BUF_SIZE+1];
+  int  nread;
+  char indicator;
+  int  primary_msg_len;
+  char *primary_msg_text;
+  int  secondary_msg_len;
+  char *secondary_msg_text;
 
-    if (!msg) {
-        /* We can't return anything */
-        return -1;
+  g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_interface_stats_open");
+
+  argv = init_pipe_args(&argc);
+
+  if (!argv) {
+    *msg = g_strdup("We don't know where to find dumpcap.");
+    return -1;
+  }
+
+  /* Ask for the interface statistics */
+  argv = sync_pipe_add_arg(argv, &argc, "-S");
+  argv = sync_pipe_add_arg(argv, &argc, "-M");
+
+#ifndef DEBUG_CHILD
+  argv = sync_pipe_add_arg(argv, &argc, "-Z");
+  argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
+#endif
+  ret = sync_pipe_open_command(argv, data_read_fd, &message_read_fd,
+                                 fork_child, msg);
+  if (ret == -1)
+    return -1;
+
+  /*
+   * We were able to set up to read dumpcap's output.  Do so.
+   *
+   * First, wait for an SP_ERROR_MESSAGE or SP_SUCCESS message.
+   */
+  nread = pipe_read_block(message_read_fd, &indicator, SP_MAX_MSG_LEN,
+                          buffer);
+  if(nread <= 0) {
+    /* We got a read error from the sync pipe, or we got no data at
+       all from the sync pipe, so we're not going to be getting any
+       data or error message from the child process.  Pick up its
+       exit status, and complain.
+
+       We don't have to worry about killing the child, if the sync pipe
+       returned an error. Usually this error is caused as the child killed
+       itself while going down. Even in the rare cases that this isn't the
+       case, the child will get an error when writing to the broken pipe
+       the next time, cleaning itself up then. */
+    ret = sync_pipe_wait_for_child(*fork_child, msg);
+    if (ret == 0) {
+      /* No unusual exit status; just report the read problem. */
+      if (nread == 0)
+        *msg = g_strdup("Child dumpcap closed sync pipe prematurely");
+      else
+        *msg = g_strdup("Error reading from sync pipe");
     }
 
-    g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_interface_stats_open");
+    return -1;
+  }
 
-    argv = init_pipe_args(&argc);
+  /* we got a valid message block from the child, process it */
+  switch(indicator) {
 
-    if (!argv) {
-        *msg = g_strdup_printf("We don't know where to find dumpcap.");
-        return -1;
+  case SP_ERROR_MSG:
+    /*
+     * Error from dumpcap; there will be a primary message and a
+     * secondary message.
+     */
+
+    /* convert primary message */
+    pipe_convert_header(buffer, 4, &indicator, &primary_msg_len);
+    primary_msg_text = buffer+4;
+    /* convert secondary message */
+    pipe_convert_header(primary_msg_text + primary_msg_len, 4, &indicator,
+                        &secondary_msg_len);
+    secondary_msg_text = primary_msg_text + primary_msg_len + 4;
+    /* the capture child will close the sync_pipe, nothing to do */
+
+    /*
+     * Pick up the child status.
+     */
+    ret = sync_pipe_close_command(data_read_fd, &message_read_fd,
+                                  fork_child, msg);
+    if (ret == -1) {
+      /*
+       * Child process failed unexpectedly, or wait failed; msg is the
+       * error message.
+       */
+    } else {
+      /*
+       * Child process failed, but returned the expected exit status.
+       * Return the messages it gave us, and indicate failure.
+       */
+      *msg = g_strdup(primary_msg_text);
+      ret = -1;
     }
+    break;
 
-    /* Ask for the interface statistics */
-    argv = sync_pipe_add_arg(argv, &argc, "-S");
-    argv = sync_pipe_add_arg(argv, &argc, "-M");
+  case SP_SUCCESS:
+    /* Close the message pipe. */
+    ws_close(message_read_fd);
+    break;
 
-#if 0
-    /* dumpcap should be running in capture child mode (hidden feature)                   */
-    /* XXX: Actually: don't run dumpcap in capture_child_mode.                            */
-    /*     Instead run dumpcap in 'normal' mode so that dumpcap err msgs are sent to      */
-    /*     stderr in normal format and are then sent to whereever our stderr goes.        */
-    /*     Note: Using 'dumpcap -S -M -Z' (capture_child mode) changes only the format of */
-    /*           dumpcap err msgs. That is: dumpcap in capture_child mode outputs err     */
-    /*           msgs to stderr in a special type/len/string format which would then      */
-    /*           currently be sent as is to stderr resulting in garbled output.           */
-    /*     ToDo: Revise this code to be similar to sync_pipe_start so that 'dumpcap -Z'   */
-    /*     special format error messages to stderr are captured and returned to caller    */
-    /*     (eg: so can be processed and displayed in a pop-up box).                       */
-#ifndef DEBUG_CHILD
-    argv = sync_pipe_add_arg(argv, &argc, "-Z");
-    argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
-#endif
-#endif
-    return sync_pipe_open_command(argv, read_fd, fork_child, msg);
+  default:
+    /*
+     * Pick up the child status.
+     */
+    ret = sync_pipe_close_command(data_read_fd, &message_read_fd,
+                                  fork_child, msg);
+    if (ret == -1) {
+      /*
+       * Child process failed unexpectedly, or wait failed; msg is the
+       * error message.
+       */
+    } else {
+      /*
+       * Child process returned an unknown status.
+       */
+      *msg = g_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",
+                             indicator);
+      ret = -1;
+    }
+    break;
+  }
+  return ret;
 }
 
 /* Close down the stats process */
 int
-sync_interface_stats_close(int *read_fd, int *fork_child
-#ifndef _WIN32
-_U_
-#endif
-, gchar **msg) {
-#ifdef _WIN32
-    return sync_pipe_close_command(read_fd, fork_child, msg);
-#else
-    return sync_pipe_close_command(read_fd, msg);
-#endif
+sync_interface_stats_close(int *read_fd, int *fork_child, gchar **msg)
+{
+    return sync_pipe_close_command(read_fd, NULL, fork_child, msg);
 }
 
 /* read a number of bytes from a pipe */
 /* (blocks until enough bytes read or an error occurs) */
 static int
-pipe_read_bytes(int pipe_fd, char *bytes, int required) {
+pipe_read_bytes(int pipe_fd, char *bytes, int required)
+{
     int newly;
     int offset = 0;
 
@@ -1096,7 +1304,7 @@ sync_pipe_gets_nonblock(int pipe_fd, char *bytes, int max) {
 }
 
 
-/* convert header values (indicator and 4-byte length) */
+/* convert header values (indicator and 3-byte length) */
 static void
 pipe_convert_header(const guchar *header, int header_len, char *indicator, int *block_len) {
 
@@ -1111,12 +1319,12 @@ pipe_convert_header(const guchar *header, int header_len, char *indicator, int *
    (1-byte message indicator, 3-byte message length (excluding length
    and indicator field), and the rest is the message) */
 static int
-pipe_read_block(int pipe_fd, char *indicator, int len, char *msg) {
+pipe_read_block(int pipe_fd, char *indicator, int len, char *msg)
+{
     int required;
     int newly;
     guchar header[4];
 
-
     /* read header (indicator and 3-byte length) */
     newly = pipe_read_bytes(pipe_fd, header, 4);
     if(newly != 4) {
@@ -1171,6 +1379,7 @@ static gboolean
 sync_pipe_input_cb(gint source, gpointer user_data)
 {
   capture_options *capture_opts = (capture_options *)user_data;
+  int  ret;
   char buffer[SP_MAX_MSG_LEN+1];
   int  nread;
   char indicator;
@@ -1179,26 +1388,30 @@ sync_pipe_input_cb(gint source, gpointer user_data)
   int  secondary_len;
   char * secondary_msg;
 
-
   nread = pipe_read_block(source, &indicator, SP_MAX_MSG_LEN, buffer);
   if(nread <= 0) {
-    if (nread == 0)
-      g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
-            "sync_pipe_input_cb: child has closed sync_pipe");
-    else
-      g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
-            "sync_pipe_input_cb: error reading from sync pipe");
-
-    /* The child has closed the sync pipe, meaning it's not going to be
-       capturing any more packets.  Pick up its exit status, and
-       complain if it did anything other than exit with status 0.
+    /* We got a read error from the sync pipe, or we got no data at
+       all from the sync pipe, so we're not going to be getting any
+       data or error message from the child process.  Pick up its
+       exit status, and complain.
 
        We don't have to worry about killing the child, if the sync pipe
        returned an error. Usually this error is caused as the child killed itself
        while going down. Even in the rare cases that this isn't the case,
        the child will get an error when writing to the broken pipe the next time,
        cleaning itself up then. */
-    sync_pipe_wait_for_child(capture_opts);
+    ret = sync_pipe_wait_for_child(capture_opts->fork_child, &primary_msg);
+    if (ret == 0) {
+      /* No unusual exit status; just report the read problem. */
+      if (nread == 0)
+        primary_msg = g_strdup("Child dumpcap closed sync pipe prematurely");
+      else
+        primary_msg = g_strdup("Error reading from sync pipe");
+    }
+    g_free(primary_msg); /* XXX - display this */
+
+    /* No more child process. */
+    capture_opts->fork_child = -1;
 
 #ifdef _WIN32
     ws_close(capture_opts->signal_pipe_write_fd);
@@ -1259,54 +1472,69 @@ sync_pipe_input_cb(gint source, gpointer user_data)
 
 
 /* the child process is going down, wait until it's completely terminated */
-static void
-sync_pipe_wait_for_child(capture_options *capture_opts)
+static int
+sync_pipe_wait_for_child(int fork_child, gchar **msgp)
 {
-  int  wstatus;
-
+  int fork_child_status;
+  int ret;
 
   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_wait_for_child: wait till child closed");
-  g_assert(capture_opts->fork_child != -1);
+  g_assert(fork_child != -1);
 
+  *msgp = NULL; /* assume no error */
+  ret = 0;
 #ifdef _WIN32
-  if (_cwait(&wstatus, capture_opts->fork_child, _WAIT_CHILD) == -1) {
-    report_failure("Child capture process stopped unexpectedly (errno:%u)",
-                   errno);
+  if (_cwait(&fork_child_status, fork_child, _WAIT_CHILD) == -1) {
+    *msgp = g_strdup_printf("Error from cwait(): %u", errno);
+    ret = -1;
   }
 #else
-  if (wait(&wstatus) != -1) {
-    if (WIFEXITED(wstatus)) {
-      /* The child exited; display its exit status, if it seems uncommon (0=ok, 1=error) */
-      /* the child will inform us about errors through the sync_pipe, which will popup */
-      /* an error message, so don't popup another one */
-
-      /* If there are situations where the child won't send us such an error message, */
-      /* this should be fixed in the child and not here! */
-      if (WEXITSTATUS(wstatus) != 0 && WEXITSTATUS(wstatus) != 1) {
-        report_failure("Child capture process exited: exit status %d",
-                      WEXITSTATUS(wstatus));
+  if (waitpid(fork_child, &fork_child_status, 0) != -1) {
+    if (WIFEXITED(fork_child_status)) {
+      /*
+       * The child exited; return its exit status, if it seems uncommon
+       * (0=ok, 1=command syntax error, 2=other error).
+       *
+       * For an exit status of 0, there's no error to tell the user about.
+       * For an exit status of 1 or 2, the child will inform us about errors
+       * through the sync_pipe, so don't return an error.
+       * If there are situations where the child won't send us such an error
+       * message, this should be fixed in the child and not worked around
+       * here!
+       */
+      if (WEXITSTATUS(fork_child_status) != 0 &&
+          WEXITSTATUS(fork_child_status) != 1 &&
+          WEXITSTATUS(fork_child_status) != 2) {
+        *msgp = g_strdup_printf("Child dumpcap process exited: exit status %d",
+                                WEXITSTATUS(fork_child_status));
+        ret = -1;
       }
-    } else if (WIFSTOPPED(wstatus)) {
+    } else if (WIFSTOPPED(fork_child_status)) {
       /* It stopped, rather than exiting.  "Should not happen." */
-      report_failure("Child capture process stopped: %s",
-                    sync_pipe_signame(WSTOPSIG(wstatus)));
-    } else if (WIFSIGNALED(wstatus)) {
+      *msgp = g_strdup_printf("Child dumpcap process stopped: %s",
+                              sync_pipe_signame(WSTOPSIG(fork_child_status)));
+      ret = -1;
+    } else if (WIFSIGNALED(fork_child_status)) {
       /* It died with a signal. */
-      report_failure("Child capture process died: %s%s",
-                    sync_pipe_signame(WTERMSIG(wstatus)),
-                    WCOREDUMP(wstatus) ? " - core dumped" : "");
+      *msgp = g_strdup_printf("Child dumpcap process died: %s%s",
+                              sync_pipe_signame(WTERMSIG(fork_child_status)),
+                              WCOREDUMP(fork_child_status) ? " - core dumped" : "");
+      ret = -1;
     } else {
       /* What?  It had to either have exited, or stopped, or died with
          a signal; what happened here? */
-      report_failure("Child capture process died: wait status %#o", wstatus);
+      *msgp = g_strdup_printf("Bad status from wait(): %#o",
+                              fork_child_status);
+      ret = -1;
     }
+  } else {
+    *msgp = g_strdup_printf("Error from wait(): %s", strerror(errno));
+    ret = -1;
   }
 #endif
 
-  /* No more child process. */
-  capture_opts->fork_child = -1;
-
   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_wait_for_child: capture child closed");
+  return ret;
 }
 
 
index 826c20d12d9b9b16359a6df40cb501db620a8742..ff1bd31ab4567ca0bbb5e5087a2bb505cc5ab66e 100644 (file)
@@ -65,12 +65,14 @@ sync_pipe_kill(int fork_child);
 
 /** Get an interface list using dumpcap */
 extern int
-sync_interface_list_open(gchar **msg);
+sync_interface_list_open(gchar **data, gchar **primary_msg,
+                         gchar **secondary_msg);
 
 /** Get interface capabilities using dumpcap */
 extern int
 sync_if_capabilities_open(const gchar *ifname, gboolean monitor_mode,
-                          gchar **msg);
+                          gchar **data, gchar **primary_msg,
+                          gchar **secondary_msg);
 
 /** Start getting interface statistics using dumpcap. */
 extern int
index ef865b97e73b98e0288136c8a988eb3710585490..0a6f5fff10072b30a79b797b8f0d65379c4a7683 100644 (file)
--- a/dumpcap.c
+++ b/dumpcap.c
@@ -682,6 +682,9 @@ print_machine_readable_interfaces(GList *if_list)
     if_addr_t   *if_addr;
     char        addr_str[ADDRSTRLEN];
 
+    /* Let our parent know we succeeded. */
+    pipe_write_block(2, SP_SUCCESS, NULL);
+
     i = 1;  /* Interface id number */
     for (if_entry = g_list_first(if_list); if_entry != NULL;
          if_entry = g_list_next(if_entry)) {
@@ -747,6 +750,9 @@ print_machine_readable_if_capabilities(if_capabilities_t *caps)
     data_link_info_t *data_link_info;
     const gchar *desc_str;
 
+    /* Let our parent know we succeeded. */
+    pipe_write_block(2, SP_SUCCESS, NULL);
+
     if (caps->can_set_rfmon)
         printf("1\n");
     else
@@ -817,6 +823,9 @@ print_statistics_loop(gboolean machine_readable)
         return 2;
     }
 
+    /* Let our parent know we succeeded. */
+    pipe_write_block(2, SP_SUCCESS, NULL);
+
     if (!machine_readable) {
         printf("%-15s  %10s  %10s\n", "Interface", "Received",
             "Dropped");
@@ -3478,9 +3487,9 @@ main(int argc, char *argv[])
     caps = get_if_capabilities(global_capture_opts.iface,
                                global_capture_opts.monitor_mode, &err_str);
     if (caps == NULL) {
-      cmdarg_err("The capabilities of the capture device \"%s\" could not be obtained (%s)."
+      cmdarg_err("The capabilities of the capture device \"%s\" could not be obtained (%s).\n"
        "Please check to make sure you have sufficient permissions, and that\n"
-       "you have the proper interface or pipe specified.\n", global_capture_opts.iface, err_str);
+       "you have the proper interface or pipe specified.", global_capture_opts.iface, err_str);
       g_free(err_str);
       exit_main(2);
     }
index 183c8e84c3d3c596ce454aa31c589e0c1a5674b9..c496e250ceefb8548a22e5a5a92d7b01d959cee3 100644 (file)
@@ -2746,9 +2746,7 @@ main(int argc, char *argv[])
                                        global_capture_opts.monitor_mode,
                                        &err_str);
     if (caps == NULL) {
-      cmdarg_err("The capabilities of the capture device \"%s\" could not be obtained (%s)."
-       "Please check to make sure you have sufficient permissions, and that\n"
-       "you have the proper interface or pipe specified.\n", global_capture_opts.iface, err_str);
+      cmdarg_err("%s", err_str);
       g_free(err_str);
       exit(2);
     }
index 5b1062f7aba8d8a6d2966d626e006d9e0424ad31..b5d80cb706312a0dfe5d2378741abf9d61d36e8c 100644 (file)
@@ -55,6 +55,7 @@
 #define SP_BAD_FILTER   'B'     /* error message for bad capture filter */
 #define SP_PACKET_COUNT 'P'     /* count of packets captured since last message */
 #define SP_DROPS        'D'     /* count of packets dropped in capture */
+#define SP_SUCCESS      'S'     /* success indication, no extra data */
 /*
  * Win32 only: Indications sent out on the signal pipe (from parent to child)
  * (UNIX-like sends signals for this)
index 46d211377de0aec6fa66f4dd6769686262487c63..553388121908b4ea32e7dd0267d66b16107a2b90 100644 (file)
--- a/tshark.c
+++ b/tshark.c
@@ -1646,9 +1646,7 @@ main(int argc, char *argv[])
                                            global_capture_opts.monitor_mode,
                                            &err_str);
         if (caps == NULL) {
-            cmdarg_err("The list of data link types for the capture device \"%s\" could not be obtained (%s)."
-             "Please check to make sure you have sufficient permissions, and that\n"
-             "you have the proper interface or pipe specified.\n", global_capture_opts.iface, err_str);
+            cmdarg_err("%s", err_str);
             g_free(err_str);
             exit(2);
         }