X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgspawn-win32.c;h=2acbde33c7d73c38503c2ea2ee2f3d8594011928;hb=30ed5f53e205e6bfc35126a9d3c62dac8a9c5dad;hp=ff42dea439f4b3973fbe162a3cbede0615bd1a39;hpb=4362cb6f26e278e8f4bdd048ea86ea608c441f71;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gspawn-win32.c b/glib/gspawn-win32.c index ff42dea..2acbde3 100644 --- a/glib/gspawn-win32.c +++ b/glib/gspawn-win32.c @@ -30,7 +30,7 @@ * before starting the child process. (There might be several threads * running, and the current directory is common for all threads.) * - * Thus, we must in most cases use a helper program to handle closing + * Thus, we must in many cases use a helper program to handle closing * of (inherited) file descriptors and changing of directory. The * helper process is also needed if the standard input, standard * output, or standard error of the process to be run are supposed to @@ -42,11 +42,13 @@ /* Define this to get some logging all the time */ /* #define G_SPAWN_WIN32_DEBUG */ -#include +#include "config.h" #include "glib.h" +#include "glib-private.h" #include "gprintfint.h" -#include "galias.h" +#include "glibintl.h" +#include "gthread.h" #include #include @@ -58,17 +60,9 @@ #include #include #include +#include -#ifdef __MINGW32__ -/* Mingw doesn't have prototypes for these */ -int _wspawnvpe (int, const wchar_t *, const wchar_t **, const wchar_t **); -int _wspawnvp (int, const wchar_t *, const wchar_t **); -int _wspawnve (int, const wchar_t *, const wchar_t **, const wchar_t **); -int _wspawnv (int, const wchar_t *, const wchar_t **); -#endif - -#include "glibintl.h" - +#ifndef GSPAWN_HELPER #ifdef G_SPAWN_WIN32_DEBUG static int debug = 1; #define SETUP_DEBUG() /* empty */ @@ -87,6 +81,7 @@ int _wspawnv (int, const wchar_t *, const wchar_t **); } \ G_STMT_END #endif +#endif enum { @@ -97,6 +92,7 @@ enum enum { ARG_CHILD_ERR_REPORT = 1, + ARG_HELPER_SYNC, ARG_STDIN, ARG_STDOUT, ARG_STDERR, @@ -108,6 +104,27 @@ enum { ARG_COUNT = ARG_PROGRAM }; +static int +dup_noninherited (int fd, + int mode) +{ + HANDLE filehandle; + + DuplicateHandle (GetCurrentProcess (), (LPHANDLE) _get_osfhandle (fd), + GetCurrentProcess (), &filehandle, + 0, FALSE, DUPLICATE_SAME_ACCESS); + close (fd); + return _open_osfhandle ((gintptr) filehandle, mode | _O_NOINHERIT); +} + +#ifndef GSPAWN_HELPER + +#ifdef _WIN64 +#define HELPER_PROCESS "gspawn-win64-helper" +#else +#define HELPER_PROCESS "gspawn-win32-helper" +#endif + static gchar * protect_argv_string (const gchar *string) { @@ -192,18 +209,8 @@ protect_argv (gchar **argv, return argc; } -#ifndef GSPAWN_HELPER - -#define HELPER_PROCESS "gspawn-win32-helper" - -GQuark -g_spawn_error_quark (void) -{ - static GQuark quark = 0; - if (quark == 0) - quark = g_quark_from_static_string ("g-exec-error-quark"); - return quark; -} +G_DEFINE_QUARK (g-exec-error-quark, g_spawn_error) +G_DEFINE_QUARK (g-spawn-exit-error-quark, g_spawn_exit_error) gboolean g_spawn_async_utf8 (const gchar *working_directory, @@ -254,7 +261,7 @@ read_data (GString *str, GError **error) { GIOStatus giostatus; - gssize bytes; + gsize bytes; gchar buf[4096]; again: @@ -272,8 +279,8 @@ read_data (GString *str, goto again; else if (giostatus == G_IO_STATUS_ERROR) { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ, - _("Failed to read data from child process")); + g_set_error_literal (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ, + _("Failed to read data from child process")); return READ_FAILED; } @@ -285,11 +292,13 @@ static gboolean make_pipe (gint p[2], GError **error) { - if (pipe (p) < 0) + if (_pipe (p, 4096, _O_BINARY) < 0) { + int errsv = errno; + g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, _("Failed to create pipe for communicating with child process (%s)"), - g_strerror (errno)); + g_strerror (errsv)); return FALSE; } else @@ -301,50 +310,56 @@ make_pipe (gint p[2], */ static gboolean read_helper_report (int fd, - gint report[2], + gintptr report[2], GError **error) { gint bytes = 0; - while (bytes < sizeof(gint)*2) + while (bytes < sizeof(gintptr)*2) { gint chunk; if (debug) - g_print ("%s:read_helper_report: read %d...\n", + g_print ("%s:read_helper_report: read %" G_GSIZE_FORMAT "...\n", __FILE__, - sizeof(gint)*2 - bytes); + sizeof(gintptr)*2 - bytes); chunk = read (fd, ((gchar*)report) + bytes, - sizeof(gint)*2 - bytes); + sizeof(gintptr)*2 - bytes); if (debug) g_print ("...got %d bytes\n", chunk); if (chunk < 0) { + int errsv = errno; + /* Some weird shit happened, bail out */ - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, _("Failed to read from child pipe (%s)"), - g_strerror (errno)); + g_strerror (errsv)); return FALSE; } else if (chunk == 0) - break; /* EOF */ + { + g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, + _("Failed to read from child pipe (%s)"), + "EOF"); + break; /* EOF */ + } else bytes += chunk; } - if (bytes < sizeof(gint)*2) + if (bytes < sizeof(gintptr)*2) return FALSE; return TRUE; } static void -set_child_error (gint report[2], +set_child_error (gintptr report[2], const gchar *working_directory, GError **error) { @@ -404,175 +419,73 @@ utf8_charv_to_wcharv (char **utf8_charv, } static gboolean -utf8_charv_to_cp_charv (char **utf8_charv, - gchar ***cp_charv, - int *error_index, - GError **error) -{ - char **retval = NULL; - - *cp_charv = NULL; - if (utf8_charv != NULL) - { - int n = 0, i; - - while (utf8_charv[n]) - n++; - retval = g_new (char *, n + 1); - - for (i = 0; i < n; i++) - { - retval[i] = g_locale_from_utf8 (utf8_charv[i], -1, NULL, NULL, error); - if (retval[i] == NULL) - { - if (error_index) - *error_index = i; - while (i) - g_free (retval[--i]); - g_free (retval); - return FALSE; - } - } - retval[n] = NULL; - } - - *cp_charv = retval; - return TRUE; -} - -static gboolean -do_spawn_directly (gboolean dont_wait, - gboolean dont_return_handle, +do_spawn_directly (gint *exit_status, + gboolean do_return_handle, GSpawnFlags flags, gchar **argv, char **envp, char **protected_argv, - GSpawnChildSetupFunc child_setup, - gpointer user_data, GPid *child_handle, - gint *exit_status, GError **error) { - int mode = dont_wait ? P_NOWAIT : P_WAIT; + const int mode = (exit_status == NULL) ? P_NOWAIT : P_WAIT; char **new_argv; - int rc = -1; + gintptr rc = -1; int saved_errno; GError *conv_error = NULL; gint conv_error_index; + wchar_t *wargv0, **wargv, **wenvp; new_argv = (flags & G_SPAWN_FILE_AND_ARGV_ZERO) ? protected_argv + 1 : protected_argv; - if (G_WIN32_HAVE_WIDECHAR_API ()) - { - wchar_t *wargv0, **wargv, **wenvp; - - wargv0 = g_utf8_to_utf16 (argv[0], -1, NULL, NULL, &conv_error); - if (wargv0 == NULL) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid program name: %s"), - conv_error->message); - g_error_free (conv_error); - - return FALSE; - } - if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error)) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in argument vector at %d: %s"), - conv_error_index, conv_error->message); - g_error_free (conv_error); - g_free (wargv0); - - return FALSE; - } - - if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error)) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in environment: %s"), - conv_error->message); - g_error_free (conv_error); - g_free (wargv0); - g_strfreev ((gchar **) wargv); - - return FALSE; - } - - if (child_setup) - (* child_setup) (user_data); - - if (flags & G_SPAWN_SEARCH_PATH) - if (wenvp != NULL) - rc = _wspawnvpe (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp); - else - rc = _wspawnvp (mode, wargv0, (const wchar_t **) wargv); - else - if (wenvp != NULL) - rc = _wspawnve (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp); - else - rc = _wspawnv (mode, wargv0, (const wchar_t **) wargv); + wargv0 = g_utf8_to_utf16 (argv[0], -1, NULL, NULL, &conv_error); + if (wargv0 == NULL) + { + g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, + _("Invalid program name: %s"), + conv_error->message); + g_error_free (conv_error); - g_free (wargv0); - g_strfreev ((gchar **) wargv); - g_strfreev ((gchar **) wenvp); + return FALSE; } - else + + if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error)) { - char *cpargv0, **cpargv, **cpenvp; - - cpargv0 = g_locale_from_utf8 (argv[0], -1, NULL, NULL, &conv_error); - if (cpargv0 == NULL) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid program name: %s"), - conv_error->message); - g_error_free (conv_error); - - return FALSE; - } - - if (!utf8_charv_to_cp_charv (new_argv, &cpargv, &conv_error_index, &conv_error)) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in argument vector at %d: %s"), - conv_error_index, conv_error->message); - g_error_free (conv_error); - g_free (cpargv0); + g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, + _("Invalid string in argument vector at %d: %s"), + conv_error_index, conv_error->message); + g_error_free (conv_error); + g_free (wargv0); - return FALSE; - } + return FALSE; + } - if (!utf8_charv_to_cp_charv (envp, &cpenvp, NULL, &conv_error)) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in environment: %s"), - conv_error->message); - g_error_free (conv_error); - g_free (cpargv0); - g_strfreev (cpargv); + if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error)) + { + g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, + _("Invalid string in environment: %s"), + conv_error->message); + g_error_free (conv_error); + g_free (wargv0); + g_strfreev ((gchar **) wargv); - return FALSE; - } + return FALSE; + } - if (child_setup) - (* child_setup) (user_data); + if (flags & G_SPAWN_SEARCH_PATH) + if (wenvp != NULL) + rc = _wspawnvpe (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp); + else + rc = _wspawnvp (mode, wargv0, (const wchar_t **) wargv); + else + if (wenvp != NULL) + rc = _wspawnve (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp); + else + rc = _wspawnv (mode, wargv0, (const wchar_t **) wargv); - if (flags & G_SPAWN_SEARCH_PATH) - if (cpenvp != NULL) - rc = spawnvpe (mode, cpargv0, (const char **) cpargv, (const char **) cpenvp); - else - rc = spawnvp (mode, cpargv0, (const char **) cpargv); - else - if (envp != NULL) - rc = spawnve (mode, cpargv0, (const char **) cpargv, (const char **) cpenvp); - else - rc = spawnv (mode, cpargv0, (const char **) cpargv); - - g_free (cpargv0); - g_strfreev (cpargv); - g_strfreev (cpenvp); - } + g_free (wargv0); + g_strfreev ((gchar **) wargv); + g_strfreev ((gchar **) wenvp); saved_errno = errno; @@ -584,9 +497,9 @@ do_spawn_directly (gboolean dont_wait, return FALSE; } - if (dont_wait) + if (exit_status == NULL) { - if (child_handle && !dont_return_handle) + if (child_handle && do_return_handle) *child_handle = (GPid) rc; else { @@ -595,26 +508,24 @@ do_spawn_directly (gboolean dont_wait, *child_handle = 0; } } - else if (exit_status) + else *exit_status = rc; return TRUE; } static gboolean -do_spawn_with_pipes (gboolean dont_wait, - gboolean dont_return_handle, +do_spawn_with_pipes (gint *exit_status, + gboolean do_return_handle, const gchar *working_directory, gchar **argv, char **envp, GSpawnFlags flags, GSpawnChildSetupFunc child_setup, - gpointer user_data, GPid *child_handle, gint *standard_input, gint *standard_output, gint *standard_error, - gint *exit_status, gint *err_report, GError **error) { @@ -622,24 +533,27 @@ do_spawn_with_pipes (gboolean dont_wait, char args[ARG_COUNT][10]; char **new_argv; int i; - int rc = -1; + gintptr rc = -1; int saved_errno; int argc; int stdin_pipe[2] = { -1, -1 }; int stdout_pipe[2] = { -1, -1 }; int stderr_pipe[2] = { -1, -1 }; int child_err_report_pipe[2] = { -1, -1 }; - int helper_report[2]; + int helper_sync_pipe[2] = { -1, -1 }; + gintptr helper_report[2]; static gboolean warned_about_child_setup = FALSE; GError *conv_error = NULL; gint conv_error_index; - - SETUP_DEBUG(); + gchar *helper_process; + CONSOLE_CURSOR_INFO cursor_info; + wchar_t *whelper, **wargv, **wenvp; + gchar *glib_dll_directory; if (child_setup && !warned_about_child_setup) { warned_about_child_setup = TRUE; - g_warning ("passing a child setup function to the g_spawn functions is pointless and dangerous on Win32"); + g_warning ("passing a child setup function to the g_spawn functions is pointless on Windows and it is ignored"); } argc = protect_argv (argv, &protected_argv); @@ -653,10 +567,9 @@ do_spawn_with_pipes (gboolean dont_wait, { /* We can do without the helper process */ gboolean retval = - do_spawn_directly (dont_wait, dont_return_handle, flags, + do_spawn_directly (exit_status, do_return_handle, flags, argv, envp, protected_argv, - child_setup, user_data, child_handle, - exit_status, error); + child_handle, error); g_strfreev (protected_argv); return retval; } @@ -673,11 +586,36 @@ do_spawn_with_pipes (gboolean dont_wait, if (!make_pipe (child_err_report_pipe, error)) goto cleanup_and_fail; + if (!make_pipe (helper_sync_pipe, error)) + goto cleanup_and_fail; + new_argv = g_new (char *, argc + 1 + ARG_COUNT); - new_argv[0] = HELPER_PROCESS; + if (GetConsoleCursorInfo (GetStdHandle (STD_OUTPUT_HANDLE), &cursor_info)) + helper_process = HELPER_PROCESS "-console.exe"; + else + helper_process = HELPER_PROCESS ".exe"; + + glib_dll_directory = _glib_get_dll_directory (); + if (glib_dll_directory != NULL) + { + helper_process = g_build_filename (glib_dll_directory, helper_process, NULL); + g_free (glib_dll_directory); + } + else + helper_process = g_strdup (helper_process); + + new_argv[0] = protect_argv_string (helper_process); + _g_sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_pipe[1]); new_argv[ARG_CHILD_ERR_REPORT] = args[ARG_CHILD_ERR_REPORT]; + /* Make the read end of the child error report pipe + * noninherited. Otherwise it will needlessly be inherited by the + * helper process, and the started actual user process. As such that + * shouldn't harm, but it is unnecessary. + */ + child_err_report_pipe[0] = dup_noninherited (child_err_report_pipe[0], _O_RDONLY); + if (flags & G_SPAWN_FILE_AND_ARGV_ZERO) { /* Overload ARG_CHILD_ERR_REPORT to also encode the @@ -686,6 +624,17 @@ do_spawn_with_pipes (gboolean dont_wait, strcat (args[ARG_CHILD_ERR_REPORT], "#"); } + _g_sprintf (args[ARG_HELPER_SYNC], "%d", helper_sync_pipe[0]); + new_argv[ARG_HELPER_SYNC] = args[ARG_HELPER_SYNC]; + + /* Make the write end of the sync pipe noninherited. Otherwise the + * helper process will inherit it, and thus if this process happens + * to crash before writing the sync byte to the pipe, the helper + * process won't read but won't get any EOF either, as it has the + * write end open itself. + */ + helper_sync_pipe[1] = dup_noninherited (helper_sync_pipe[1], _O_WRONLY); + if (standard_input) { _g_sprintf (args[ARG_STDIN], "%d", stdin_pipe[0]); @@ -745,7 +694,7 @@ do_spawn_with_pipes (gboolean dont_wait, else new_argv[ARG_USE_PATH] = "-"; - if (dont_wait) + if (exit_status == NULL) new_argv[ARG_WAIT] = "-"; else new_argv[ARG_WAIT] = "w"; @@ -753,129 +702,77 @@ do_spawn_with_pipes (gboolean dont_wait, for (i = 0; i <= argc; i++) new_argv[ARG_PROGRAM + i] = protected_argv[i]; + SETUP_DEBUG(); + if (debug) { - g_print ("calling " HELPER_PROCESS " with argv:\n"); + g_print ("calling %s with argv:\n", helper_process); for (i = 0; i < argc + 1 + ARG_COUNT; i++) g_print ("argv[%d]: %s\n", i, (new_argv[i] ? new_argv[i] : "NULL")); } - if (G_WIN32_HAVE_WIDECHAR_API ()) + if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error)) { - wchar_t *whelper = g_utf8_to_utf16 (HELPER_PROCESS, -1, NULL, NULL, NULL); - wchar_t **wargv, **wenvp; - - if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error)) - { - if (conv_error_index == ARG_WORKING_DIRECTORY) - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR, - _("Invalid working directory: %s"), - conv_error->message); - else - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in argument vector at %d: %s"), - conv_error_index - ARG_PROGRAM, conv_error->message); - g_error_free (conv_error); - g_strfreev (protected_argv); - g_free (new_argv[ARG_WORKING_DIRECTORY]); - g_free (new_argv); - g_free (whelper); - - return FALSE; - } - - if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error)) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in environment: %s"), - conv_error->message); - g_error_free (conv_error); - g_strfreev (protected_argv); - g_free (new_argv[ARG_WORKING_DIRECTORY]); - g_free (new_argv); - g_free (whelper); - g_strfreev ((gchar **) wargv); - - return FALSE; - } - - if (child_setup) - (* child_setup) (user_data); - - if (wenvp != NULL) - /* Let's hope envp hasn't mucked with PATH so that - * gspawn-win32-helper.exe isn't found. - */ - rc = _wspawnvpe (P_NOWAIT, whelper, (const wchar_t **) wargv, (const wchar_t **) wenvp); + if (conv_error_index == ARG_WORKING_DIRECTORY) + g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR, + _("Invalid working directory: %s"), + conv_error->message); else - rc = _wspawnvp (P_NOWAIT, whelper, (const wchar_t **) wargv); + g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, + _("Invalid string in argument vector at %d: %s"), + conv_error_index - ARG_PROGRAM, conv_error->message); + g_error_free (conv_error); + g_strfreev (protected_argv); + g_free (new_argv[0]); + g_free (new_argv[ARG_WORKING_DIRECTORY]); + g_free (new_argv); + g_free (helper_process); - saved_errno = errno; + goto cleanup_and_fail; + } - g_free (whelper); + if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error)) + { + g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, + _("Invalid string in environment: %s"), + conv_error->message); + g_error_free (conv_error); + g_strfreev (protected_argv); + g_free (new_argv[0]); + g_free (new_argv[ARG_WORKING_DIRECTORY]); + g_free (new_argv); + g_free (helper_process); g_strfreev ((gchar **) wargv); - g_strfreev ((gchar **) wenvp); + + goto cleanup_and_fail; } - else - { - char **cpargv, **cpenvp; - if (!utf8_charv_to_cp_charv (new_argv, &cpargv, &conv_error_index, &conv_error)) - { - if (conv_error_index == ARG_WORKING_DIRECTORY) - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR, - _("Invalid working directory: %s"), - conv_error->message); - else - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in argument vector at %d: %s"), - conv_error_index - ARG_PROGRAM, conv_error->message); - g_error_free (conv_error); - g_strfreev (protected_argv); - g_free (new_argv[ARG_WORKING_DIRECTORY]); - g_free (new_argv); - - return FALSE; - } - - if (!utf8_charv_to_cp_charv (envp, &cpenvp, NULL, &conv_error)) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in environment: %s"), - conv_error->message); - g_error_free (conv_error); - g_strfreev (protected_argv); - g_free (new_argv[ARG_WORKING_DIRECTORY]); - g_free (new_argv); - g_strfreev (cpargv); - - return FALSE; - } - - if (child_setup) - (* child_setup) (user_data); + whelper = g_utf8_to_utf16 (helper_process, -1, NULL, NULL, NULL); + g_free (helper_process); - if (cpenvp != NULL) - rc = spawnvpe (P_NOWAIT, HELPER_PROCESS, (const char **) cpargv, (const char **) cpenvp); - else - rc = spawnvp (P_NOWAIT, HELPER_PROCESS, (const char **) cpargv); + if (wenvp != NULL) + rc = _wspawnvpe (P_NOWAIT, whelper, (const wchar_t **) wargv, (const wchar_t **) wenvp); + else + rc = _wspawnvp (P_NOWAIT, whelper, (const wchar_t **) wargv); - saved_errno = errno; + saved_errno = errno; - g_strfreev (cpargv); - g_strfreev (cpenvp); - } + g_free (whelper); + g_strfreev ((gchar **) wargv); + g_strfreev ((gchar **) wenvp); /* Close the other process's ends of the pipes in this process, * otherwise the reader will never get EOF. */ close_and_invalidate (&child_err_report_pipe[1]); + close_and_invalidate (&helper_sync_pipe[0]); close_and_invalidate (&stdin_pipe[0]); close_and_invalidate (&stdout_pipe[1]); close_and_invalidate (&stderr_pipe[1]); g_strfreev (protected_argv); + g_free (new_argv[0]); g_free (new_argv[ARG_WORKING_DIRECTORY]); g_free (new_argv); @@ -888,7 +785,7 @@ do_spawn_with_pipes (gboolean dont_wait, goto cleanup_and_fail; } - if (!dont_wait) + if (exit_status != NULL) { /* Synchronous case. Pass helper's report pipe back to caller, * which takes care of reading it after the grandchild has @@ -896,6 +793,8 @@ do_spawn_with_pipes (gboolean dont_wait, */ g_assert (err_report != NULL); *err_report = child_err_report_pipe[0]; + write (helper_sync_pipe[1], " ", 1); + close_and_invalidate (&helper_sync_pipe[1]); } else { @@ -903,12 +802,12 @@ do_spawn_with_pipes (gboolean dont_wait, if (!read_helper_report (child_err_report_pipe[0], helper_report, error)) goto cleanup_and_fail; - close (child_err_report_pipe[0]); + close_and_invalidate (&child_err_report_pipe[0]); switch (helper_report[0]) { case CHILD_NO_ERROR: - if (child_handle && dont_wait && !dont_return_handle) + if (child_handle && do_return_handle) { /* rc is our HANDLE for gspawn-win32-helper. It has * told us the HANDLE of its child. Duplicate that into @@ -917,15 +816,21 @@ do_spawn_with_pipes (gboolean dont_wait, if (!DuplicateHandle ((HANDLE) rc, (HANDLE) helper_report[1], GetCurrentProcess (), (LPHANDLE) child_handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) - *child_handle = 0; + { + char *emsg = g_win32_error_message (GetLastError ()); + g_print("%s\n", emsg); + *child_handle = 0; + } } else if (child_handle) *child_handle = 0; - if (exit_status) - *exit_status = helper_report[1]; + write (helper_sync_pipe[1], " ", 1); + close_and_invalidate (&helper_sync_pipe[1]); break; default: + write (helper_sync_pipe[1], " ", 1); + close_and_invalidate (&helper_sync_pipe[1]); set_child_error (helper_report, working_directory, error); goto cleanup_and_fail; } @@ -945,12 +850,17 @@ do_spawn_with_pipes (gboolean dont_wait, return TRUE; cleanup_and_fail: + if (rc != -1) CloseHandle ((HANDLE) rc); if (child_err_report_pipe[0] != -1) close (child_err_report_pipe[0]); if (child_err_report_pipe[1] != -1) close (child_err_report_pipe[1]); + if (helper_sync_pipe[0] != -1) + close (helper_sync_pipe[0]); + if (helper_sync_pipe[1] != -1) + close (helper_sync_pipe[1]); if (stdin_pipe[0] != -1) close (stdin_pipe[0]); if (stdin_pipe[1] != -1) @@ -1011,19 +921,17 @@ g_spawn_sync_utf8 (const gchar *working_directory, if (standard_error) *standard_error = NULL; - if (!do_spawn_with_pipes (FALSE, - TRUE, + if (!do_spawn_with_pipes (&status, + FALSE, working_directory, argv, envp, flags, child_setup, - user_data, NULL, NULL, standard_output ? &outpipe : NULL, standard_error ? &errpipe : NULL, - &status, &reportpipe, error)) return FALSE; @@ -1037,9 +945,12 @@ g_spawn_sync_utf8 (const gchar *working_directory, outstr = g_string_new (NULL); outchannel = g_io_channel_win32_new_fd (outpipe); g_io_channel_set_encoding (outchannel, NULL, NULL); + g_io_channel_set_buffered (outchannel, FALSE); g_io_channel_win32_make_pollfd (outchannel, G_IO_IN | G_IO_ERR | G_IO_HUP, &outfd); + if (debug) + g_print ("outfd=%p\n", (HANDLE) outfd.fd); } if (errpipe >= 0) @@ -1047,9 +958,12 @@ g_spawn_sync_utf8 (const gchar *working_directory, errstr = g_string_new (NULL); errchannel = g_io_channel_win32_new_fd (errpipe); g_io_channel_set_encoding (errchannel, NULL, NULL); + g_io_channel_set_buffered (errchannel, FALSE); g_io_channel_win32_make_pollfd (errchannel, G_IO_IN | G_IO_ERR | G_IO_HUP, &errfd); + if (debug) + g_print ("errfd=%p\n", (HANDLE) errfd.fd); } /* Read data until we get EOF on all pipes. */ @@ -1079,8 +993,8 @@ g_spawn_sync_utf8 (const gchar *working_directory, { failed = TRUE; - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ, - _("Unexpected error in g_io_channel_win32_poll() reading data from a child process")); + g_set_error_literal (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ, + _("Unexpected error in g_io_channel_win32_poll() reading data from a child process")); break; } @@ -1151,7 +1065,7 @@ g_spawn_sync_utf8 (const gchar *working_directory, /* Helper process was involved. Read its report now after the * grandchild has finished. */ - gint helper_report[2]; + gintptr helper_report[2]; if (!read_helper_report (reportpipe, helper_report, error)) failed = TRUE; @@ -1227,20 +1141,18 @@ g_spawn_async_with_pipes_utf8 (const gchar *working_directory, g_return_val_if_fail (standard_input == NULL || !(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE); - return do_spawn_with_pipes (TRUE, - !(flags & G_SPAWN_DO_NOT_REAP_CHILD), + return do_spawn_with_pipes (NULL, + (flags & G_SPAWN_DO_NOT_REAP_CHILD), working_directory, argv, envp, flags, child_setup, - user_data, child_handle, standard_input, standard_output, standard_error, NULL, - NULL, error); } @@ -1309,6 +1221,27 @@ g_spawn_close_pid (GPid pid) CloseHandle (pid); } +gboolean +g_spawn_check_exit_status (gint exit_status, + GError **error) +{ + gboolean ret = FALSE; + + if (exit_status != 0) + { + g_set_error (error, G_SPAWN_EXIT_ERROR, exit_status, + _("Child process exited with code %ld"), + (long) exit_status); + goto out; + } + + ret = TRUE; + out: + return ret; +} + +#if !defined (_WIN64) + /* Binary compatibility versions that take system codepage pathnames, * argument vectors and environments. These get used only by code * built against 2.8.1 or earlier. Code built against 2.8.2 or later @@ -1574,7 +1507,6 @@ g_spawn_command_line_async (const gchar *command_line, return retval; } -#endif /* !GSPAWN_HELPER */ +#endif /* !_WIN64 */ -#define __G_SPAWN_C__ -#include "galiasdef.c" +#endif /* !GSPAWN_HELPER */