Generalize our process spawning code.
authorGerald Combs <gerald@wireshark.org>
Thu, 1 Mar 2018 23:31:45 +0000 (15:31 -0800)
committerAnders Broman <a.broman58@gmail.com>
Fri, 2 Mar 2018 05:22:20 +0000 (05:22 +0000)
Move the contents of extcap_spawn to ws_pipe. Rename various extcap_*
prefixes to ws_pipe_*. Open stdin when we spawn processes.

Change-Id: I9286295443ee955bb6328b0ed6f945ee0bb2a798
Reviewed-on: https://code.wireshark.org/review/26216
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Petri-Dish: Gerald Combs <gerald@wireshark.org>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
CMakeLists.txt
Makefile.am
capture_opts.c
capture_opts.h
extcap.c
extcap_spawn.c [deleted file]
extcap_spawn.h [deleted file]
wsutil/ws_pipe.c
wsutil/ws_pipe.h

index 0a4824a6011d87eccc28ee33feb74d61379fe0f0..406b34e388493a075cf04bf7e9b09870d83cb6c0 100644 (file)
@@ -1577,7 +1577,6 @@ set(SHARK_COMMON_SRC
        version_info.c
        extcap.c
        extcap_parser.c
-       extcap_spawn.c
 )
 
 set(TSHARK_TAP_SRC
index f93cad4c15f3bdee925699fe61869e4e116c21bf..7d9ca8de470e6b9aeb0cbbcd7e05501c65fec81e 100644 (file)
@@ -380,8 +380,7 @@ SHARK_COMMON_SRC = \
        frame_tvbuff.c          \
        sync_pipe_write.c       \
        extcap.c                \
-       extcap_parser.c         \
-       extcap_spawn.c
+       extcap_parser.c
 
 # wireshark specifics
 WIRESHARK_COMMON_SRC = \
@@ -722,7 +721,6 @@ noinst_HEADERS = \
        conditions.h            \
        extcap.h                \
        extcap_parser.h         \
-       extcap_spawn.h          \
        fileset.h               \
        frame_tvbuff.h          \
        ringbuffer.h            \
index 5d6e84d64184cff84c3f69275939f7504bdeeb70..a8bddee36f87fe73df7add8c82003c3dda03401f 100644 (file)
@@ -27,6 +27,7 @@
 #include <wsutil/clopts_common.h>
 #include <wsutil/cmdarg_err.h>
 #include <wsutil/file_util.h>
+#include <wsutil/ws_pipe.h>
 
 #include "caputils/capture_ifinfo.h"
 #include "caputils/capture-pcap-util.h"
@@ -53,7 +54,7 @@ capture_opts_init(capture_options *capture_opts)
     capture_opts->default_options.extcap          = NULL;
     capture_opts->default_options.extcap_fifo     = NULL;
     capture_opts->default_options.extcap_args     = NULL;
-    capture_opts->default_options.extcap_userdata = NULL;
+    capture_opts->default_options.extcap_pipedata = NULL;
     capture_opts->default_options.extcap_pid      = INVALID_EXTCAP_PID;
 #ifdef _WIN32
     capture_opts->default_options.extcap_pipe_h   = INVALID_HANDLE_VALUE;
@@ -684,7 +685,7 @@ capture_opts_add_iface_opt(capture_options *capture_opts, const char *optarg_str
     interface_opts.extcap_fifo = g_strdup(capture_opts->default_options.extcap_fifo);
     interface_opts.extcap_args = NULL;
     interface_opts.extcap_pid = INVALID_EXTCAP_PID;
-    interface_opts.extcap_userdata = NULL;
+    interface_opts.extcap_pipedata = NULL;
 #ifdef _WIN32
     interface_opts.extcap_pipe_h = INVALID_HANDLE_VALUE;
     interface_opts.extcap_control_in_h = INVALID_HANDLE_VALUE;
@@ -1127,7 +1128,7 @@ capture_opts_del_iface(capture_options *capture_opts, guint if_index)
         g_hash_table_unref(interface_opts->extcap_args);
     if (interface_opts->extcap_pid != INVALID_EXTCAP_PID)
         g_spawn_close_pid(interface_opts->extcap_pid);
-    g_free(interface_opts->extcap_userdata);
+    g_free(interface_opts->extcap_pipedata);
     g_free(interface_opts->extcap_control_in);
     g_free(interface_opts->extcap_control_out);
 #ifdef HAVE_PCAP_REMOTE
@@ -1174,12 +1175,12 @@ collect_ifaces(capture_options *capture_opts)
             interface_opts.if_type = device->if_info.type;
             interface_opts.extcap = g_strdup(device->if_info.extcap);
             interface_opts.extcap_fifo = NULL;
-            interface_opts.extcap_userdata = NULL;
+            interface_opts.extcap_pipedata = NULL;
             interface_opts.extcap_args = device->external_cap_args_settings;
             interface_opts.extcap_pid = INVALID_EXTCAP_PID;
             if (interface_opts.extcap_args)
                 g_hash_table_ref(interface_opts.extcap_args);
-            interface_opts.extcap_userdata = NULL;
+            interface_opts.extcap_pipedata = NULL;
 #ifdef _WIN32
             interface_opts.extcap_pipe_h = INVALID_HANDLE_VALUE;
             interface_opts.extcap_control_in_h = INVALID_HANDLE_VALUE;
index 715a3bee90cf34855d1d8b1eb0907fd009a5c1a8..7c344e31a7e271d08982f54f8536b036cfa18c5e 100644 (file)
@@ -198,12 +198,6 @@ typedef struct link_row_tag {
     gint dlt;
 } link_row;
 
-#ifdef _WIN32
-#define INVALID_EXTCAP_PID INVALID_HANDLE_VALUE
-#else
-#define INVALID_EXTCAP_PID (GPid)-1
-#endif
-
 typedef struct interface_options_tag {
     gchar            *name;                 /* the name of the interface provided to winpcap/libpcap to specify the interface */
     gchar            *descr;
@@ -218,7 +212,7 @@ typedef struct interface_options_tag {
     gchar            *extcap_fifo;
     GHashTable       *extcap_args;
     GPid              extcap_pid;           /* pid of running process or INVALID_EXTCAP_PID */
-    gpointer          extcap_userdata;
+    gpointer          extcap_pipedata;
     guint             extcap_child_watch;
 #ifdef _WIN32
     HANDLE            extcap_pipe_h;
index 25932affd716792ee527a762ea6e43288d4cb016..d83fd9c27e70c73b63e07eabd7e9489007b83eed 100644 (file)
--- a/extcap.c
+++ b/extcap.c
@@ -49,7 +49,6 @@
 
 #include "extcap.h"
 #include "extcap_parser.h"
-#include "extcap_spawn.h"
 
 #ifdef _WIN32
 static HANDLE pipe_h = INVALID_HANDLE_VALUE;
@@ -319,7 +318,7 @@ static gboolean extcap_foreach(gint argc, gchar **args,
                     continue;
                 }
 
-                if (extcap_spawn_sync((gchar *) dirname, extcap_path->str, argc, args, &command_output))
+                if (ws_pipe_spawn_sync((gchar *) dirname, extcap_path->str, argc, args, &command_output))
                 {
                     cb_info.output = command_output;
                     cb_info.extcap = extcap_path->str;
@@ -957,7 +956,7 @@ extcap_has_toolbar(const char *ifname)
 void extcap_if_cleanup(capture_options *capture_opts, gchar **errormsg)
 {
     interface_options *interface_opts;
-    extcap_userdata *userdata;
+    ws_pipe_t *pipedata;
     guint icnt = 0;
     gboolean overwrite_exitcode;
     gchar *buffer;
@@ -1031,17 +1030,17 @@ void extcap_if_cleanup(capture_options *capture_opts, gchar **errormsg)
               "Extcap [%s] - Closing spawned PID: %d", interface_opts->name,
               interface_opts->extcap_pid);
 
-        userdata = (extcap_userdata *) interface_opts->extcap_userdata;
-        if (userdata)
+        pipedata = (ws_pipe_t *) interface_opts->extcap_pipedata;
+        if (pipedata)
         {
-            if (userdata->extcap_stderr_rd > 0 && ws_pipe_data_available(userdata->extcap_stderr_rd))
+            if (pipedata->stderr_fd > 0 && ws_pipe_data_available(pipedata->stderr_fd))
             {
                 buffer = (gchar *)g_malloc0(STDERR_BUFFER_SIZE + 1);
-                ws_read_string_from_pipe(ws_get_pipe_handle(userdata->extcap_stderr_rd), buffer, STDERR_BUFFER_SIZE + 1);
+                ws_read_string_from_pipe(ws_get_pipe_handle(pipedata->stderr_fd), buffer, STDERR_BUFFER_SIZE + 1);
                 if (strlen(buffer) > 0)
                 {
-                    userdata->extcap_stderr = g_strdup_printf("%s", buffer);
-                    userdata->exitcode = 1;
+                    pipedata->stderr_msg = g_strdup_printf("%s", buffer);
+                    pipedata->exitcode = 1;
                 }
                 g_free(buffer);
             }
@@ -1050,37 +1049,37 @@ void extcap_if_cleanup(capture_options *capture_opts, gchar **errormsg)
             /* Final child watch may not have been called */
             if (interface_opts->extcap_child_watch != 0)
             {
-                extcap_child_watch_cb(userdata->pid, 0, capture_opts);
+                extcap_child_watch_cb(pipedata->pid, 0, capture_opts);
                 /* it will have changed in extcap_child_watch_cb */
                 interface_opts = &g_array_index(capture_opts->ifaces, interface_options,
                                                icnt);
             }
 #endif
 
-            if (userdata->extcap_stderr != NULL)
+            if (pipedata->stderr_msg != NULL)
             {
                 overwrite_exitcode = TRUE;
             }
 
-            if (overwrite_exitcode || userdata->exitcode != 0)
+            if (overwrite_exitcode || pipedata->exitcode != 0)
             {
-                if (userdata->extcap_stderr != 0)
+                if (pipedata->stderr_msg != 0)
                 {
                     if (*errormsg == NULL)
                     {
-                        *errormsg = g_strdup_printf("Error by extcap pipe: %s", userdata->extcap_stderr);
+                        *errormsg = g_strdup_printf("Error by extcap pipe: %s", pipedata->stderr_msg);
                     }
                     else
                     {
-                        gchar *temp = g_strconcat(*errormsg, "\nError by extcap pipe: " , userdata->extcap_stderr, NULL);
+                        gchar *temp = g_strconcat(*errormsg, "\nError by extcap pipe: " , pipedata->stderr_msg, NULL);
                         g_free(*errormsg);
                         *errormsg = temp;
                     }
-                    g_free(userdata->extcap_stderr);
+                    g_free(pipedata->stderr_msg);
                 }
 
-                userdata->extcap_stderr = NULL;
-                userdata->exitcode = 0;
+                pipedata->stderr_msg = NULL;
+                pipedata->exitcode = 0;
             }
         }
 
@@ -1098,8 +1097,8 @@ void extcap_if_cleanup(capture_options *capture_opts, gchar **errormsg)
             g_spawn_close_pid(interface_opts->extcap_pid);
             interface_opts->extcap_pid = INVALID_EXTCAP_PID;
 
-            g_free(interface_opts->extcap_userdata);
-            interface_opts->extcap_userdata = NULL;
+            g_free(interface_opts->extcap_pipedata);
+            interface_opts->extcap_pipedata = NULL;
         }
     }
 }
@@ -1128,7 +1127,7 @@ void extcap_child_watch_cb(GPid pid, gint status, gpointer user_data)
 {
     guint i;
     interface_options *interface_opts;
-    extcap_userdata *userdata = NULL;
+    ws_pipe_t *pipedata = NULL;
     capture_options *capture_opts = (capture_options *)(user_data);
 
     if (capture_opts == NULL || capture_opts->ifaces == NULL || capture_opts->ifaces->len == 0)
@@ -1145,32 +1144,32 @@ void extcap_child_watch_cb(GPid pid, gint status, gpointer user_data)
         interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i);
         if (interface_opts->extcap_pid == pid)
         {
-            userdata = (extcap_userdata *)interface_opts->extcap_userdata;
-            if (userdata != NULL)
+            pipedata = (ws_pipe_t *)interface_opts->extcap_pipedata;
+            if (pipedata != NULL)
             {
                 interface_opts->extcap_pid = INVALID_EXTCAP_PID;
-                userdata->exitcode = 0;
+                pipedata->exitcode = 0;
 #ifndef _WIN32
                 if (WIFEXITED(status))
                 {
                     if (WEXITSTATUS(status) != 0)
                     {
-                        userdata->exitcode = WEXITSTATUS(status);
+                        pipedata->exitcode = WEXITSTATUS(status);
                     }
                 }
                 else
                 {
-                    userdata->exitcode = G_SPAWN_ERROR_FAILED;
+                    pipedata->exitcode = G_SPAWN_ERROR_FAILED;
                 }
 #else
                 if (status != 0)
                 {
-                    userdata->exitcode = status;
+                    pipedata->exitcode = status;
                 }
 #endif
-                if (status == 0 && userdata->extcap_stderr != NULL)
+                if (status == 0 && pipedata->stderr_msg != NULL)
                 {
-                    userdata->exitcode = 1;
+                    pipedata->exitcode = 1;
                 }
             }
             g_source_remove(interface_opts->extcap_child_watch);
@@ -1288,7 +1287,7 @@ extcap_init_interfaces(capture_options *capture_opts)
 {
     guint i;
     interface_options *interface_opts;
-    extcap_userdata *userdata;
+    ws_pipe_t *pipedata;
 
     for (i = 0; i < capture_opts->ifaces->len; i++)
     {
@@ -1331,16 +1330,16 @@ extcap_init_interfaces(capture_options *capture_opts)
         /* Create extcap call */
         args = extcap_prepare_arguments(interface_opts);
 
-        userdata = g_new0(extcap_userdata, 1);
+        pipedata = g_new0(ws_pipe_t, 1);
 
-        pid = extcap_spawn_async(userdata, args);
+        pid = ws_pipe_spawn_async(pipedata, args);
 
         g_ptr_array_foreach(args, (GFunc)g_free, NULL);
         g_ptr_array_free(args, TRUE);
 
         if (pid == INVALID_EXTCAP_PID)
         {
-            g_free(userdata);
+            g_free(pipedata);
             continue;
         }
 
@@ -1356,8 +1355,6 @@ extcap_init_interfaces(capture_options *capture_opts)
          * connect to named pipe (including user interaction).
          * Wait on multiple object in case of extcap termination
          * without opening pipe.
-         *
-         * Minimum supported version of Windows: XP / Server 2003.
          */
         if (pid != INVALID_EXTCAP_PID)
         {
@@ -1372,11 +1369,11 @@ extcap_init_interfaces(capture_options *capture_opts)
                 num_pipe_handles += 2;
              }
 
-            extcap_wait_for_pipe(pipe_handles, num_pipe_handles, pid);
+            ws_pipe_wait_for_pipe(pipe_handles, num_pipe_handles, pid);
         }
 #endif
 
-        interface_opts->extcap_userdata = (gpointer) userdata;
+        interface_opts->extcap_pipedata = (gpointer) pipedata;
     }
 
     return TRUE;
diff --git a/extcap_spawn.c b/extcap_spawn.c
deleted file mode 100644 (file)
index 816e0e3..0000000
+++ /dev/null
@@ -1,381 +0,0 @@
-/* extcap_spawn.c
- *
- * Routines to spawn extcap external capture programs
- * Copyright 2016, Roland Knall <rknall@gmail.com>
- *
- * Wireshark - Network traffic analyzer
- * By Gerald Combs <gerald@wireshark.org>
- * Copyright 1998 Gerald Combs
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <glib.h>
-#include <string.h>
-
-#include <wsutil/file_util.h>
-#include <wsutil/filesystem.h>
-#include <wsutil/ws_pipe.h>
-#ifdef _WIN32
-#include <wsutil/win32-utils.h>
-#endif
-
-#include <log.h>
-
-#include "extcap.h"
-#include "extcap_spawn.h"
-
-gboolean extcap_spawn_sync(gchar *dirname, gchar *command, gint argc, gchar **args, gchar **command_output)
-{
-    gboolean status = FALSE;
-    gboolean result = FALSE;
-    gchar **argv = NULL;
-    gint cnt = 0;
-    gchar *local_output = NULL;
-#ifdef _WIN32
-
-#define BUFFER_SIZE 16384
-
-    GString *winargs = g_string_sized_new(200);
-    gchar *quoted_arg;
-    gunichar2 *wcommandline;
-
-    STARTUPINFO info;
-    PROCESS_INFORMATION processInfo;
-
-    SECURITY_ATTRIBUTES sa;
-    HANDLE child_stdout_rd = NULL;
-    HANDLE child_stdout_wr = NULL;
-    HANDLE child_stderr_rd = NULL;
-    HANDLE child_stderr_wr = NULL;
-
-    const gchar *oldpath = g_getenv("PATH");
-    gchar *newpath = NULL;
-#else
-    gint exit_status = 0;
-#endif
-
-    argv = (gchar **) g_malloc0(sizeof(gchar *) * (argc + 2));
-
-#ifdef _WIN32
-    newpath = g_strdup_printf("%s;%s", g_strescape(get_progfile_dir(), NULL), oldpath);
-    g_setenv("PATH", newpath, TRUE);
-
-    argv[0] = g_strescape(command, NULL);
-#else
-    argv[0] = g_strdup(command);
-#endif
-
-    for (cnt = 0; cnt < argc; cnt++)
-        argv[cnt + 1] = args[cnt];
-    argv[argc + 1] = NULL;
-
-#ifdef _WIN32
-
-    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
-    sa.bInheritHandle = TRUE;
-    sa.lpSecurityDescriptor = NULL;
-
-    if (!CreatePipe(&child_stdout_rd, &child_stdout_wr, &sa, 0))
-    {
-        g_free(argv[0]);
-        g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdout handle");
-        return FALSE;
-    }
-
-    if (!CreatePipe(&child_stderr_rd, &child_stderr_wr, &sa, 0))
-    {
-        CloseHandle(child_stdout_rd);
-        CloseHandle(child_stdout_wr);
-        g_free(argv[0]);
-        g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stderr handle");
-        return FALSE;
-    }
-
-    /* convert args array into a single string */
-    /* XXX - could change sync_pipe_add_arg() instead */
-    /* there is a drawback here: the length is internally limited to 1024 bytes */
-    for (cnt = 0; argv[cnt] != 0; cnt++) {
-        if (cnt != 0) g_string_append_c(winargs, ' ');    /* don't prepend a space before the path!!! */
-        quoted_arg = protect_arg(argv[cnt]);
-        g_string_append(winargs, quoted_arg);
-        g_free(quoted_arg);
-    }
-
-    wcommandline = g_utf8_to_utf16(winargs->str, (glong)winargs->len, NULL, NULL, NULL);
-
-    memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
-    memset(&info, 0, sizeof(STARTUPINFO));
-
-    info.cb = sizeof(STARTUPINFO);
-    info.hStdError = child_stderr_wr;
-    info.hStdOutput = child_stdout_wr;
-    info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
-    info.wShowWindow = SW_HIDE;
-
-    if (CreateProcess(NULL, wcommandline, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &info, &processInfo))
-    {
-        gchar* buffer;
-
-        WaitForSingleObject(processInfo.hProcess, INFINITE);
-        buffer = (gchar*)g_malloc(BUFFER_SIZE);
-        status = ws_read_string_from_pipe(child_stdout_rd, buffer, BUFFER_SIZE);
-        if (status)
-        {
-            local_output = g_strdup_printf("%s", buffer);
-        }
-        g_free(buffer);
-
-        CloseHandle(child_stdout_rd);
-        CloseHandle(child_stdout_wr);
-        CloseHandle(child_stderr_rd);
-        CloseHandle(child_stderr_wr);
-
-        CloseHandle(processInfo.hProcess);
-        CloseHandle(processInfo.hThread);
-    }
-    else
-        status = FALSE;
-
-    g_setenv("PATH", oldpath, TRUE);
-#else
-
-    status = g_spawn_sync(dirname, argv, NULL,
-                          (GSpawnFlags) 0, NULL, NULL, &local_output, NULL, &exit_status, NULL);
-
-    if (status && exit_status != 0)
-        status = FALSE;
-#endif
-
-    if (status)
-    {
-        if (command_output != NULL && local_output != NULL)
-            *command_output = g_strdup(local_output);
-
-        result = TRUE;
-    }
-
-    g_free(local_output);
-    g_free(argv[0]);
-    g_free(argv);
-
-    return result;
-}
-
-GPid extcap_spawn_async(extcap_userdata *userdata, GPtrArray *args)
-{
-    GPid pid = INVALID_EXTCAP_PID;
-
-#ifdef _WIN32
-    gint cnt = 0;
-    gchar **tmp = NULL;
-
-    GString *winargs = g_string_sized_new(200);
-    gchar *quoted_arg;
-    gunichar2 *wcommandline;
-
-    STARTUPINFO info;
-    PROCESS_INFORMATION processInfo;
-
-    SECURITY_ATTRIBUTES sa;
-    HANDLE child_stdout_rd = NULL;
-    HANDLE child_stdout_wr = NULL;
-    HANDLE child_stderr_rd = NULL;
-    HANDLE child_stderr_wr = NULL;
-
-    const gchar *oldpath = g_getenv("PATH");
-    gchar *newpath = NULL;
-
-    newpath = g_strdup_printf("%s;%s", g_strescape(get_progfile_dir(), NULL), oldpath);
-    g_setenv("PATH", newpath, TRUE);
-
-    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
-    sa.bInheritHandle = TRUE;
-    sa.lpSecurityDescriptor = NULL;
-
-    if (!CreatePipe(&child_stdout_rd, &child_stdout_wr, &sa, 0))
-    {
-        g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdout handle");
-        return FALSE;
-    }
-
-    if (!CreatePipe(&child_stderr_rd, &child_stderr_wr, &sa, 0))
-    {
-        CloseHandle(child_stdout_rd);
-        CloseHandle(child_stdout_wr);
-        g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stderr handle");
-        return FALSE;
-    }
-
-    /* convert args array into a single string */
-    /* XXX - could change sync_pipe_add_arg() instead */
-    /* there is a drawback here: the length is internally limited to 1024 bytes */
-    for (tmp = (gchar **)args->pdata, cnt = 0; *tmp && **tmp; ++cnt, ++tmp) {
-        if (cnt != 0) g_string_append_c(winargs, ' ');    /* don't prepend a space before the path!!! */
-        quoted_arg = protect_arg(*tmp);
-        g_string_append(winargs, quoted_arg);
-        g_free(quoted_arg);
-    }
-
-    wcommandline = g_utf8_to_utf16(winargs->str, (glong)winargs->len, NULL, NULL, NULL);
-
-    memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
-    memset(&info, 0, sizeof(STARTUPINFO));
-
-    info.cb = sizeof(STARTUPINFO);
-    info.hStdError = child_stderr_wr;
-    info.hStdOutput = child_stdout_wr;
-    info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
-    info.wShowWindow = SW_HIDE;
-
-    if (CreateProcess(NULL, wcommandline, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &info, &processInfo))
-    {
-        userdata->extcap_stderr_rd = _open_osfhandle((intptr_t)(child_stderr_rd), _O_BINARY);
-        userdata->extcap_stdout_rd = _open_osfhandle((intptr_t)(child_stdout_rd), _O_BINARY);
-        userdata->threadId = processInfo.hThread;
-        pid = processInfo.hProcess;
-    }
-
-    g_setenv("PATH", oldpath, TRUE);
-#else
-    g_spawn_async_with_pipes(NULL, (gchar **)args->pdata, NULL,
-                             (GSpawnFlags) G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL,
-                             &pid, NULL, &userdata->extcap_stdout_rd, &userdata->extcap_stderr_rd, NULL);
-#endif
-
-    userdata->pid = pid;
-
-    return pid;
-}
-
-#ifdef _WIN32
-
-typedef struct
-{
-    HANDLE pipeHandle;
-    OVERLAPPED ol;
-    BOOL pendingIO;
-} PIPEINTS;
-
-gboolean
-extcap_wait_for_pipe(HANDLE * pipe_handles, int num_pipe_handles, HANDLE pid)
-{
-    PIPEINTS pipeinsts[3];
-    DWORD dw, cbRet;
-    HANDLE handles[4];
-    int error_code;
-    int num_waiting_to_connect = 0;
-    int num_handles = num_pipe_handles + 1; // PID handle is also added to list of handles.
-
-    if (num_pipe_handles == 0 || num_pipe_handles > 3)
-    {
-        g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Invalid number of pipes given as argument.");
-        return FALSE;
-    }
-
-    for (int i = 0; i < num_pipe_handles; ++i)
-    {
-        pipeinsts[i].pipeHandle = pipe_handles[i];
-        pipeinsts[i].ol.Pointer = 0;
-        pipeinsts[i].ol.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-        pipeinsts[i].pendingIO = FALSE;
-        handles[i] = pipeinsts[i].ol.hEvent;
-        BOOL connected = ConnectNamedPipe(pipeinsts[i].pipeHandle, &pipeinsts[i].ol);
-        if (connected)
-        {
-            error_code = GetLastError();
-            g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "ConnectNamedPipe failed with %d \n.", error_code);
-            return FALSE;
-        }
-
-        switch (GetLastError())
-        {
-        case ERROR_IO_PENDING:
-            num_waiting_to_connect++;
-            pipeinsts[i].pendingIO = TRUE;
-            break;
-
-        case ERROR_PIPE_CONNECTED:
-            if (SetEvent(pipeinsts[i].ol.hEvent))
-            {
-                break;
-            } // Fallthrough if this fails.
-
-        default:
-            error_code = GetLastError();
-            g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "ConnectNamedPipe failed with %d \n.", error_code);
-            return FALSE;
-        }
-    }
-
-    // Store pid of extcap process so it can be monitored in case it fails before the pipes has connceted.
-    handles[num_pipe_handles] = pid;
-
-    while(num_waiting_to_connect > 0)
-    {
-        dw = WaitForMultipleObjects(num_handles, handles, FALSE, 30000);
-        int idx = dw - WAIT_OBJECT_0;
-        if (dw == WAIT_TIMEOUT)
-        {
-            g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap didn't connect to pipe within 30 seconds.");
-            return FALSE;
-        }
-        // If index points to our handles array
-        else if (idx >= 0 && idx < num_handles)
-        {
-            if (idx < num_pipe_handles)  // Index of pipe handle
-            {
-                if (pipeinsts[idx].pendingIO)
-                {
-                    BOOL success = GetOverlappedResult(
-                        pipeinsts[idx].pipeHandle, // handle to pipe
-                        &pipeinsts[idx].ol,        // OVERLAPPED structure
-                        &cbRet,                    // bytes transferred
-                        FALSE);                    // do not wait
-
-                    if (!success)
-                    {
-                        g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Error %d \n.", GetLastError());
-                        return FALSE;
-                    }
-                    else
-                    {
-                        pipeinsts[idx].pendingIO = FALSE;
-                        CloseHandle(pipeinsts[idx].ol.hEvent);
-                        num_waiting_to_connect--;
-                    }
-                }
-            }
-            else // Index of PID
-            {
-                // Fail since index of 'pid' indicates that the pid of the extcap process has terminated.
-                g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap terminated without connecting to pipe.");
-                return FALSE;
-            }
-        }
-        else
-        {
-            g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "WaitForMultipleObjects returned 0x%08X. Error %d", dw, GetLastError());
-            return FALSE;
-        }
-    }
-
-    return TRUE;
-}
-#endif
-
-/*
- * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
- *
- * Local variables:
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- *
- * vi: set shiftwidth=4 tabstop=8 expandtab:
- * :indentSize=4:tabSize=8:noTabs=true:
- */
diff --git a/extcap_spawn.h b/extcap_spawn.h
deleted file mode 100644 (file)
index 0557a6f..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* extcap_spawn.h
- * Helper routines for executing extcap utilities
- *
- * Copyright 2016, Roland Knall <rknall@gmail.com>
- *
- * Wireshark - Network traffic analyzer
- * By Gerald Combs <gerald@wireshark.org>
- * Copyright 1998 Gerald Combs
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#ifndef __EXTCAP_SPAWN_H__
-#define __EXTCAP_SPAWN_H__
-
-#include <config.h>
-
-#include <glib.h>
-
-#include <extcap.h>
-
-typedef struct _extcap_userdata {
-    GPid pid;
-    gchar * extcap_stderr;
-    gint exitcode;
-    gint extcap_stderr_rd;
-    gint extcap_stdout_rd;
-#ifdef _WIN32
-    HANDLE threadId;
-#endif
-} extcap_userdata;
-
-gboolean extcap_spawn_sync ( gchar * dirname, gchar * command, gint argc, gchar ** argv, gchar ** command_output );
-
-GPid extcap_spawn_async ( extcap_userdata * userdata, GPtrArray * args );
-
-#ifdef _WIN32
-gboolean extcap_wait_for_pipe(HANDLE * pipe_handles, int num_pipe_handles, HANDLE pid);
-#endif
-
-#endif
-
-/*
- * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
- *
- * Local variables:
- * c-basic-offset: 4
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- *
- * vi: set shiftwidth=4 tabstop=8 expandtab:
- * :indentSize=4:tabSize=8:noTabs=true:
- */
index 2c0f28b89e8841d655e1e9e38e88ab7d769288c3..3649276864cbee7e05be2684baf5aa33851268ba 100644 (file)
@@ -18,6 +18,8 @@
 #ifdef _WIN32
 #include <windows.h>
 #include <io.h>
+#include <fcntl.h> /* for _O_BINARY */
+#include <wsutil/win32-utils.h>
 #else
 #include <unistd.h>
 #ifdef HAVE_SYS_SELECT_H
 #include <glib.h>
 #include <log.h>
 
+#include <wsutil/filesystem.h>
 #include "wsutil/ws_pipe.h"
 
+gboolean ws_pipe_spawn_sync(gchar *dirname, gchar *command, gint argc, gchar **args, gchar **command_output)
+{
+    gboolean status = FALSE;
+    gboolean result = FALSE;
+    gchar **argv = NULL;
+    gint cnt = 0;
+    gchar *local_output = NULL;
+#ifdef _WIN32
+
+#define BUFFER_SIZE 16384
+
+    GString *winargs = g_string_sized_new(200);
+    gchar *quoted_arg;
+    gunichar2 *wcommandline;
+
+    STARTUPINFO info;
+    PROCESS_INFORMATION processInfo;
+
+    SECURITY_ATTRIBUTES sa;
+    HANDLE child_stdout_rd = NULL;
+    HANDLE child_stdout_wr = NULL;
+    HANDLE child_stderr_rd = NULL;
+    HANDLE child_stderr_wr = NULL;
+
+    const gchar *oldpath = g_getenv("PATH");
+    gchar *newpath = NULL;
+#else
+    gint exit_status = 0;
+#endif
+
+    argv = (gchar **) g_malloc0(sizeof(gchar *) * (argc + 2));
+
+#ifdef _WIN32
+    newpath = g_strdup_printf("%s;%s", g_strescape(get_progfile_dir(), NULL), oldpath);
+    g_setenv("PATH", newpath, TRUE);
+
+    argv[0] = g_strescape(command, NULL);
+#else
+    argv[0] = g_strdup(command);
+#endif
+
+    for (cnt = 0; cnt < argc; cnt++)
+        argv[cnt + 1] = args[cnt];
+    argv[argc + 1] = NULL;
+
+#ifdef _WIN32
+
+    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+    sa.bInheritHandle = TRUE;
+    sa.lpSecurityDescriptor = NULL;
+
+    if (!CreatePipe(&child_stdout_rd, &child_stdout_wr, &sa, 0))
+    {
+        g_free(argv[0]);
+        g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdout handle");
+        return FALSE;
+    }
+
+    if (!CreatePipe(&child_stderr_rd, &child_stderr_wr, &sa, 0))
+    {
+        CloseHandle(child_stdout_rd);
+        CloseHandle(child_stdout_wr);
+        g_free(argv[0]);
+        g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stderr handle");
+        return FALSE;
+    }
+
+    /* convert args array into a single string */
+    /* XXX - could change sync_pipe_add_arg() instead */
+    /* there is a drawback here: the length is internally limited to 1024 bytes */
+    for (cnt = 0; argv[cnt] != 0; cnt++) {
+        if (cnt != 0) g_string_append_c(winargs, ' ');    /* don't prepend a space before the path!!! */
+        quoted_arg = protect_arg(argv[cnt]);
+        g_string_append(winargs, quoted_arg);
+        g_free(quoted_arg);
+    }
+
+    wcommandline = g_utf8_to_utf16(winargs->str, (glong)winargs->len, NULL, NULL, NULL);
+
+    memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
+    memset(&info, 0, sizeof(STARTUPINFO));
+
+    info.cb = sizeof(STARTUPINFO);
+    info.hStdError = child_stderr_wr;
+    info.hStdOutput = child_stdout_wr;
+    info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+    info.wShowWindow = SW_HIDE;
+
+    if (CreateProcess(NULL, wcommandline, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &info, &processInfo))
+    {
+        gchar* buffer;
+
+        WaitForSingleObject(processInfo.hProcess, INFINITE);
+        buffer = (gchar*)g_malloc(BUFFER_SIZE);
+        status = ws_read_string_from_pipe(child_stdout_rd, buffer, BUFFER_SIZE);
+        if (status)
+        {
+            local_output = g_strdup_printf("%s", buffer);
+        }
+        g_free(buffer);
+
+        CloseHandle(child_stdout_rd);
+        CloseHandle(child_stdout_wr);
+        CloseHandle(child_stderr_rd);
+        CloseHandle(child_stderr_wr);
+
+        CloseHandle(processInfo.hProcess);
+        CloseHandle(processInfo.hThread);
+    }
+    else
+        status = FALSE;
+
+    g_setenv("PATH", oldpath, TRUE);
+#else
+
+    status = g_spawn_sync(dirname, argv, NULL,
+                          (GSpawnFlags) 0, NULL, NULL, &local_output, NULL, &exit_status, NULL);
+
+    if (status && exit_status != 0)
+        status = FALSE;
+#endif
+
+    if (status)
+    {
+        if (command_output != NULL && local_output != NULL)
+            *command_output = g_strdup(local_output);
+
+        result = TRUE;
+    }
+
+    g_free(local_output);
+    g_free(argv[0]);
+    g_free(argv);
+
+    return result;
+}
+
+GPid ws_pipe_spawn_async(ws_pipe_t *ws_pipe, GPtrArray *args)
+{
+    GPid pid = INVALID_EXTCAP_PID;
+
+#ifdef _WIN32
+    gint cnt = 0;
+    gchar **tmp = NULL;
+
+    GString *winargs = g_string_sized_new(200);
+    gchar *quoted_arg;
+    gunichar2 *wcommandline;
+
+    STARTUPINFO info;
+    PROCESS_INFORMATION processInfo;
+
+    SECURITY_ATTRIBUTES sa;
+    HANDLE child_stdin_rd = NULL;
+    HANDLE child_stdin_wr = NULL;
+    HANDLE child_stdout_rd = NULL;
+    HANDLE child_stdout_wr = NULL;
+    HANDLE child_stderr_rd = NULL;
+    HANDLE child_stderr_wr = NULL;
+
+    const gchar *oldpath = g_getenv("PATH");
+    gchar *newpath = NULL;
+
+    newpath = g_strdup_printf("%s;%s", g_strescape(get_progfile_dir(), NULL), oldpath);
+    g_setenv("PATH", newpath, TRUE);
+
+    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+    sa.bInheritHandle = TRUE;
+    sa.lpSecurityDescriptor = NULL;
+
+    if (!CreatePipe(&child_stdin_rd, &child_stdin_wr, &sa, 0))
+    {
+        g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdin handle");
+        return FALSE;
+    }
+
+    if (!CreatePipe(&child_stdout_rd, &child_stdout_wr, &sa, 0))
+    {
+        g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdout handle");
+        return FALSE;
+    }
+
+    if (!CreatePipe(&child_stderr_rd, &child_stderr_wr, &sa, 0))
+    {
+        CloseHandle(child_stdout_rd);
+        CloseHandle(child_stdout_wr);
+        g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stderr handle");
+        return FALSE;
+    }
+
+    /* convert args array into a single string */
+    /* XXX - could change sync_pipe_add_arg() instead */
+    /* there is a drawback here: the length is internally limited to 1024 bytes */
+    for (tmp = (gchar **)args->pdata, cnt = 0; *tmp && **tmp; ++cnt, ++tmp) {
+        if (cnt != 0) g_string_append_c(winargs, ' ');    /* don't prepend a space before the path!!! */
+        quoted_arg = protect_arg(*tmp);
+        g_string_append(winargs, quoted_arg);
+        g_free(quoted_arg);
+    }
+
+    wcommandline = g_utf8_to_utf16(winargs->str, (glong)winargs->len, NULL, NULL, NULL);
+
+    memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
+    memset(&info, 0, sizeof(STARTUPINFO));
+
+    info.cb = sizeof(STARTUPINFO);
+    info.hStdInput = child_stdin_rd;
+    info.hStdError = child_stderr_wr;
+    info.hStdOutput = child_stdout_wr;
+    info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+    info.wShowWindow = SW_HIDE;
+
+    if (CreateProcess(NULL, wcommandline, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &info, &processInfo))
+    {
+        ws_pipe->stdin_fd = _open_osfhandle((intptr_t)(child_stdin_wr), _O_BINARY);
+        ws_pipe->stdout_fd = _open_osfhandle((intptr_t)(child_stdout_rd), _O_BINARY);
+        ws_pipe->stderr_fd = _open_osfhandle((intptr_t)(child_stderr_rd), _O_BINARY);
+        ws_pipe->threadId = processInfo.hThread;
+        pid = processInfo.hProcess;
+    }
+
+    g_setenv("PATH", oldpath, TRUE);
+#else
+    g_spawn_async_with_pipes(NULL, (gchar **)args->pdata, NULL,
+                             (GSpawnFlags) G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL,
+                             &pid, &ws_pipe->stdin_fd, &ws_pipe->stdout_fd, &ws_pipe->stderr_fd, NULL);
+#endif
+
+    ws_pipe->pid = pid;
+
+    return pid;
+}
+
+#ifdef _WIN32
+
+typedef struct
+{
+    HANDLE pipeHandle;
+    OVERLAPPED ol;
+    BOOL pendingIO;
+} PIPEINTS;
+
+gboolean
+ws_pipe_wait_for_pipe(HANDLE * pipe_handles, int num_pipe_handles, HANDLE pid)
+{
+    PIPEINTS pipeinsts[3];
+    DWORD dw, cbRet;
+    HANDLE handles[4];
+    int error_code;
+    int num_waiting_to_connect = 0;
+    int num_handles = num_pipe_handles + 1; // PID handle is also added to list of handles.
+
+    if (num_pipe_handles == 0 || num_pipe_handles > 3)
+    {
+        g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Invalid number of pipes given as argument.");
+        return FALSE;
+    }
+
+    for (int i = 0; i < num_pipe_handles; ++i)
+    {
+        pipeinsts[i].pipeHandle = pipe_handles[i];
+        pipeinsts[i].ol.Pointer = 0;
+        pipeinsts[i].ol.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+        pipeinsts[i].pendingIO = FALSE;
+        handles[i] = pipeinsts[i].ol.hEvent;
+        BOOL connected = ConnectNamedPipe(pipeinsts[i].pipeHandle, &pipeinsts[i].ol);
+        if (connected)
+        {
+            error_code = GetLastError();
+            g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "ConnectNamedPipe failed with %d \n.", error_code);
+            return FALSE;
+        }
+
+        switch (GetLastError())
+        {
+        case ERROR_IO_PENDING:
+            num_waiting_to_connect++;
+            pipeinsts[i].pendingIO = TRUE;
+            break;
+
+        case ERROR_PIPE_CONNECTED:
+            if (SetEvent(pipeinsts[i].ol.hEvent))
+            {
+                break;
+            } // Fallthrough if this fails.
+
+        default:
+            error_code = GetLastError();
+            g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "ConnectNamedPipe failed with %d \n.", error_code);
+            return FALSE;
+        }
+    }
+
+    // Store pid of extcap process so it can be monitored in case it fails before the pipes has connceted.
+    handles[num_pipe_handles] = pid;
+
+    while(num_waiting_to_connect > 0)
+    {
+        dw = WaitForMultipleObjects(num_handles, handles, FALSE, 30000);
+        int idx = dw - WAIT_OBJECT_0;
+        if (dw == WAIT_TIMEOUT)
+        {
+            g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap didn't connect to pipe within 30 seconds.");
+            return FALSE;
+        }
+        // If index points to our handles array
+        else if (idx >= 0 && idx < num_handles)
+        {
+            if (idx < num_pipe_handles)  // Index of pipe handle
+            {
+                if (pipeinsts[idx].pendingIO)
+                {
+                    BOOL success = GetOverlappedResult(
+                        pipeinsts[idx].pipeHandle, // handle to pipe
+                        &pipeinsts[idx].ol,        // OVERLAPPED structure
+                        &cbRet,                    // bytes transferred
+                        FALSE);                    // do not wait
+
+                    if (!success)
+                    {
+                        g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Error %d \n.", GetLastError());
+                        return FALSE;
+                    }
+                    else
+                    {
+                        pipeinsts[idx].pendingIO = FALSE;
+                        CloseHandle(pipeinsts[idx].ol.hEvent);
+                        num_waiting_to_connect--;
+                    }
+                }
+            }
+            else // Index of PID
+            {
+                // Fail since index of 'pid' indicates that the pid of the extcap process has terminated.
+                g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap terminated without connecting to pipe.");
+                return FALSE;
+            }
+        }
+        else
+        {
+            g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "WaitForMultipleObjects returned 0x%08X. Error %d", dw, GetLastError());
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+#endif
+
 gboolean
 ws_pipe_data_available(int pipe_fd)
 {
index 8a4870f2cc474cd9d5d299fcf5f55a156a3008ea..e69873c44962d068d6977b78b02f428a440c5d12 100644 (file)
 
 #include <glib.h>
 
+#ifdef _WIN32
+#define INVALID_EXTCAP_PID INVALID_HANDLE_VALUE
+#else
+#define INVALID_EXTCAP_PID (GPid)-1
+#endif
+
 #ifdef _WIN32
 #include <windows.h>
 #include <io.h>
 #define ws_get_pipe_handle(pipe_fd)    (pipe_fd)
 #endif
 
+typedef struct _ws_pipe_t {
+    GPid pid;
+    gchar *stderr_msg;
+    gint exitcode;
+    gint stdin_fd;
+    gint stdout_fd;
+    gint stderr_fd;
+#ifdef _WIN32
+    HANDLE threadId;
+#endif
+} ws_pipe_t;
+
+WS_DLL_PUBLIC gboolean ws_pipe_spawn_sync ( gchar * dirname, gchar * command, gint argc, gchar ** argv, gchar ** command_output );
+
+WS_DLL_PUBLIC GPid ws_pipe_spawn_async (ws_pipe_t * ws_pipe, GPtrArray * args );
+
+#ifdef _WIN32
+WS_DLL_PUBLIC gboolean ws_pipe_wait_for_pipe(HANDLE * pipe_handles, int num_pipe_handles, HANDLE pid);
+#endif
+
 WS_DLL_PUBLIC gboolean ws_pipe_data_available(int pipe_fd);
 
 WS_DLL_PUBLIC gboolean ws_read_string_from_pipe(ws_pipe_handle read_pipe,