-/* gspawn.c - Process launching
+/* gspawn-win32.c - Process launching on Win32
*
* Copyright 2000 Red Hat, Inc.
*
* Thus, we must in most cases use a helper program to handle closing
* of (inherited) file descriptors and changing of directory. In fact,
* we do it all the time.
- *
- * This source file contains the source for that helper program.
- * To compile it, #define GSPAWN_HELPER.
*/
/* Define this to get some logging all the time */
/* #define G_SPAWN_WIN32_DEBUG */
+#include <config.h>
+
+#include "config.h"
+
#include "glib.h"
+#include "gprintfint.h"
#include <string.h>
#include <stdlib.h>
+#include <stdio.h>
#include <windows.h>
#include <errno.h>
#include <fcntl.h>
#include <io.h>
#include <process.h>
+#include <direct.h>
-#ifdef _
-#warning "FIXME remove gettext hack"
-#endif
-
-#define _(x) x
+#include "glibintl.h"
#ifdef G_SPAWN_WIN32_DEBUG
static int debug = 1;
G_STMT_START \
{ \
if (debug == -1) \
- if (getenv ("G_SPAWN_WIN32_DEBUG") != NULL) \
- debug = 1; \
- else \
- debug = 0; \
+ { \
+ if (getenv ("G_SPAWN_WIN32_DEBUG") != NULL) \
+ debug = 1; \
+ else \
+ debug = 0; \
+ } \
} \
G_STMT_END
#endif
static gboolean make_pipe (gint p[2],
GError **error);
-static gboolean fork_exec_with_pipes (gboolean dont_wait,
+static gboolean do_spawn_with_pipes (gboolean dont_wait,
+ gboolean dont_return_handle,
const gchar *working_directory,
gchar **argv,
gchar **envp,
gboolean child_inherits_stdin,
GSpawnChildSetupFunc child_setup,
gpointer user_data,
+ gint *child_pid,
gint *standard_input,
gint *standard_output,
gint *standard_error,
return quark;
}
-/**
- * g_spawn_async:
- * @working_directory: child's current working directory, or NULL to inherit parent's
- * @argv: child's argument vector
- * @envp: child's environment, or NULL to inherit parent's
- * @flags: flags from #GSpawnFlags
- * @child_setup: function to run in the child just before exec()
- * @user_data: user data for @child_setup
- * @child_pid: return location for child process ID, or NULL
- * @error: return location for error
- *
- * See g_spawn_async_with_pipes() for a full description; this function
- * simply calls the g_spawn_async_with_pipes() without any pipes.
- *
- * Return value: TRUE on success, FALSE if error is set
- **/
gboolean
g_spawn_async (const gchar *working_directory,
gchar **argv,
{
gint ret;
- ret = close (*fd);
- *fd = -1;
+ if (*fd < 0)
+ return -1;
+ else
+ {
+ ret = close (*fd);
+ *fd = -1;
+ }
return ret;
}
GIOChannel *iochannel,
GError **error)
{
- GIOError gioerror;
- gint bytes;
+ GIOStatus giostatus;
+ gssize bytes;
gchar buf[4096];
again:
- gioerror = g_io_channel_read (iochannel, buf, sizeof (buf), &bytes);
+ giostatus = g_io_channel_read_chars (iochannel, buf, sizeof (buf), &bytes, NULL);
if (bytes == 0)
return READ_EOF;
g_string_append_len (str, buf, bytes);
return READ_OK;
}
- else if (gioerror == G_IO_ERROR_AGAIN)
+ else if (giostatus == G_IO_STATUS_AGAIN)
goto again;
- else if (gioerror != G_IO_ERROR_NONE)
+ else if (giostatus == G_IO_STATUS_ERROR)
{
g_set_error (error,
G_SPAWN_ERROR,
return READ_OK;
}
-/**
- * g_spawn_sync:
- * @working_directory: child's current working directory, or NULL to inherit parent's
- * @argv: child's argument vector
- * @envp: child's environment, or NULL to inherit parent's
- * @flags: flags from #GSpawnFlags
- * @child_setup: function to run in the child just before exec()
- * @user_data: user data for @child_setup
- * @standard_output: return location for child output
- * @standard_error: return location for child error messages
- * @exit_status: child exit status, as returned by waitpid()
- * @error: return location for error
- *
- * Executes a child synchronously (waits for the child to exit before returning).
- * All output from the child is stored in @standard_output and @standard_error,
- * if those parameters are non-NULL. If @exit_status is non-NULL, the exit status
- * of the child is stored there as it would be by waitpid(); standard UNIX
- * macros such as WIFEXITED() and WEXITSTATUS() must be used to evaluate the
- * exit status. If an error occurs, no data is returned in @standard_output,
- * @standard_error, or @exit_status.
- *
- * This function calls g_spawn_async_with_pipes() internally; see that function
- * for full details on the other parameters.
- *
- * Return value: TRUE on success, FALSE if an error was set.
- **/
gboolean
g_spawn_sync (const gchar *working_directory,
gchar **argv,
{
gint outpipe = -1;
gint errpipe = -1;
+ gint pid;
GIOChannel *outchannel = NULL;
GIOChannel *errchannel = NULL;
GPollFD outfd, errfd;
if (standard_error)
*standard_error = NULL;
- if (!fork_exec_with_pipes (FALSE,
- working_directory,
- argv,
- envp,
- !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
- (flags & G_SPAWN_SEARCH_PATH) != 0,
- (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
- (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
- (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
- child_setup,
- user_data,
- NULL,
- standard_output ? &outpipe : NULL,
- standard_error ? &errpipe : NULL,
- &status,
- error))
+ if (!do_spawn_with_pipes (FALSE,
+ TRUE,
+ working_directory,
+ argv,
+ envp,
+ !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
+ (flags & G_SPAWN_SEARCH_PATH) != 0,
+ (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
+ (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
+ (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
+ child_setup,
+ user_data,
+ &pid,
+ NULL,
+ standard_output ? &outpipe : NULL,
+ standard_error ? &errpipe : NULL,
+ &status,
+ error))
return FALSE;
/* Read data from child. */
{
outstr = g_string_new ("");
outchannel = g_io_channel_win32_new_fd (outpipe);
+ g_io_channel_set_encoding (outchannel, NULL, NULL);
g_io_channel_win32_make_pollfd (outchannel,
G_IO_IN | G_IO_ERR | G_IO_HUP,
&outfd);
{
errstr = g_string_new ("");
errchannel = g_io_channel_win32_new_fd (errpipe);
+ g_io_channel_set_encoding (errchannel, NULL, NULL);
g_io_channel_win32_make_pollfd (errchannel,
G_IO_IN | G_IO_ERR | G_IO_HUP,
&errfd);
}
}
-/**
- * g_spawn_async_with_pipes:
- * @working_directory: child's current working directory, or NULL to inherit parent's
- * @argv: child's argument vector
- * @envp: child's environment, or NULL to inherit parent's
- * @flags: flags from #GSpawnFlags
- * @child_setup: function to run in the child just before exec()
- * @user_data: user data for @child_setup
- * @child_pid: return location for child process ID, or NULL
- * @standard_input: return location for file descriptor to write to child's stdin, or NULL
- * @standard_output: return location for file descriptor to read child's stdout, or NULL
- * @standard_error: return location for file descriptor to read child's stderr, or NULL
- * @error: return location for error
- *
- * Executes a child program asynchronously (your program will not
- * block waiting for the child to exit). The child program is
- * specified by the only argument that must be provided, @argv. @argv
- * should be a NULL-terminated array of strings, to be passed as the
- * argument vector for the child. The first string in @argv is of
- * course the name of the program to execute. By default, the name of
- * the program must be a full path; the PATH shell variable will only
- * be searched if you pass the %G_SPAWN_SEARCH_PATH flag.
- *
- * @envp is a NULL-terminated array of strings, where each string
- * has the form <literal>KEY=VALUE</literal>. This will become
- * the child's environment. If @envp is NULL, the child inherits its
- * parent's environment.
- *
- * @flags should be the bitwise OR of any flags you want to affect the
- * function's behavior. The %G_SPAWN_DO_NOT_REAP_CHILD means that the
- * child will not be automatically reaped; you must call waitpid() or
- * handle SIGCHLD yourself, or the child will become a zombie.
- * %G_SPAWN_LEAVE_DESCRIPTORS_OPEN means that the parent's open file
- * descriptors will be inherited by the child; otherwise all
- * descriptors except stdin/stdout/stderr will be closed before
- * calling exec() in the child. %G_SPAWN_SEARCH_PATH means that
- * <literal>argv[0]</literal> need not be an absolute path, it
- * will be looked for in the user's PATH. %G_SPAWN_STDOUT_TO_DEV_NULL
- * means that the child's standad output will be discarded, instead
- * of going to the same location as the parent's standard output.
- * %G_SPAWN_STDERR_TO_DEV_NULL means that the child's standard error
- * will be discarded. %G_SPAWN_CHILD_INHERITS_STDIN means that
- * the child will inherit the parent's standard input (by default,
- * the child's standard input is attached to /dev/null).
- *
- * @child_setup and @user_data are a function and user data to be
- * called in the child after GLib has performed all the setup it plans
- * to perform (including creating pipes, closing file descriptors,
- * etc.) but before calling exec(). That is, @child_setup is called
- * just before calling exec() in the child. Obviously actions taken in
- * this function will only affect the child, not the parent.
- *
- * If non-NULL, @child_pid will be filled with the child's process
- * ID. You can use the process ID to send signals to the child, or
- * to waitpid() if you specified the %G_SPAWN_DO_NOT_REAP_CHILD flag.
- *
- * If non-NULL, the @standard_input, @standard_output, @standard_error
- * locations will be filled with file descriptors for writing to the child's
- * standard input or reading from its standard output or standard error.
- * The caller of g_spawn_async_with_pipes() must close these file descriptors
- * when they are no longer in use. If these parameters are NULL, the
- * corresponding pipe won't be created.
- *
- * @error can be NULL to ignore errors, or non-NULL to report errors.
- * If an error is set, the function returns FALSE. Errors
- * are reported even if they occur in the child (for example if the
- * executable in <literal>argv[0]</literal> is not found). Typically
- * the <literal>message</literal> field of returned errors should be displayed
- * to users. Possible errors are those from the #G_SPAWN_ERROR domain.
- *
- * If an error occurs, @child_pid, @standard_input, @standard_output,
- * and @standard_error will not be filled with valid values.
- *
- * Return value: TRUE on success, FALSE if an error was set
- **/
gboolean
g_spawn_async_with_pipes (const gchar *working_directory,
gchar **argv,
g_return_val_if_fail (standard_input == NULL ||
!(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE);
- return fork_exec_with_pipes (!(flags & G_SPAWN_DO_NOT_REAP_CHILD),
- working_directory,
- argv,
- envp,
- !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
- (flags & G_SPAWN_SEARCH_PATH) != 0,
- (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
- (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
- (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
- child_setup,
- user_data,
- standard_input,
- standard_output,
- standard_error,
- NULL,
- error);
+ return do_spawn_with_pipes (TRUE,
+ !(flags & G_SPAWN_DO_NOT_REAP_CHILD),
+ working_directory,
+ argv,
+ envp,
+ !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
+ (flags & G_SPAWN_SEARCH_PATH) != 0,
+ (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
+ (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
+ (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
+ child_setup,
+ user_data,
+ child_pid,
+ standard_input,
+ standard_output,
+ standard_error,
+ NULL,
+ error);
}
-/**
- * g_spawn_command_line_sync:
- * @command_line: a command line
- * @standard_output: return location for child output
- * @standard_error: return location for child errors
- * @exit_status: return location for child exit status
- * @error: return location for errors
- *
- * A simple version of g_spawn_sync() with little-used parameters
- * removed, taking a command line instead of an argument vector. See
- * g_spawn_sync() for full details. @command_line will be parsed by
- * g_shell_parse_argv(). Unlike g_spawn_sync(), the %G_SPAWN_SEARCH_PATH flag
- * is enabled. Note that %G_SPAWN_SEARCH_PATH can have security
- * implications, so consider using g_spawn_sync() directly if
- * appropriate. Possible errors are those from g_spawn_sync() and those
- * from g_shell_parse_argv().
- *
- * Return value: TRUE on success, FALSE if an error was set
- **/
gboolean
g_spawn_command_line_sync (const gchar *command_line,
gchar **standard_output,
return retval;
}
-/**
- * g_spawn_command_line_async:
- * @command_line: a command line
- * @error: return location for errors
- *
- * A simple version of g_spawn_async() that parses a command line with
- * g_shell_parse_argv() and passes it to g_spawn_async(). Runs a
- * command line in the background. Unlike g_spawn_async(), the
- * %G_SPAWN_SEARCH_PATH flag is enabled, other flags are not. Note
- * that %G_SPAWN_SEARCH_PATH can have security implications, so
- * consider using g_spawn_async() directly if appropriate. Possible
- * errors are those from g_shell_parse_argv() and g_spawn_async().
- *
- * Return value: TRUE on success, FALSE if error is set.
- **/
gboolean
g_spawn_command_line_async (const gchar *command_line,
GError **error)
}
static gint
-do_exec (gboolean dont_wait,
- gint child_err_report_fd,
- gint stdin_fd,
- gint stdout_fd,
- gint stderr_fd,
- const gchar *working_directory,
- gchar **argv,
- gchar **envp,
- gboolean close_descriptors,
- gboolean search_path,
- gboolean stdout_to_null,
- gboolean stderr_to_null,
- gboolean child_inherits_stdin,
- GSpawnChildSetupFunc child_setup,
- gpointer user_data)
+do_spawn (gboolean dont_wait,
+ gint child_err_report_fd,
+ gint stdin_fd,
+ gint stdout_fd,
+ gint stderr_fd,
+ const gchar *working_directory,
+ gchar **argv,
+ gchar **envp,
+ gboolean close_descriptors,
+ gboolean search_path,
+ gboolean stdout_to_null,
+ gboolean stderr_to_null,
+ gboolean child_inherits_stdin,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data)
{
gchar **new_argv;
gchar args[ARG_COUNT][10];
gint i;
+ int rc;
int argc = 0;
SETUP_DEBUG();
new_argv = g_new (gchar *, argc + 1 + ARG_COUNT);
new_argv[0] = "gspawn-win32-helper";
- sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_fd);
+ _g_sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_fd);
new_argv[ARG_CHILD_ERR_REPORT] = args[ARG_CHILD_ERR_REPORT];
if (stdin_fd >= 0)
{
- sprintf (args[ARG_STDIN], "%d", stdin_fd);
+ _g_sprintf (args[ARG_STDIN], "%d", stdin_fd);
new_argv[ARG_STDIN] = args[ARG_STDIN];
}
else if (child_inherits_stdin)
if (stdout_fd >= 0)
{
- sprintf (args[ARG_STDOUT], "%d", stdout_fd);
+ _g_sprintf (args[ARG_STDOUT], "%d", stdout_fd);
new_argv[ARG_STDOUT] = args[ARG_STDOUT];
}
else if (stdout_to_null)
if (stderr_fd >= 0)
{
- sprintf (args[ARG_STDERR], "%d", stderr_fd);
+ _g_sprintf (args[ARG_STDERR], "%d", stderr_fd);
new_argv[ARG_STDERR] = args[ARG_STDERR];
}
else if (stderr_to_null)
}
if (working_directory && *working_directory)
- new_argv[ARG_WORKING_DIRECTORY] = working_directory;
+ new_argv[ARG_WORKING_DIRECTORY] = g_strdup (working_directory);
else
new_argv[ARG_WORKING_DIRECTORY] = "-";
/* Call user function just before we execute the helper program,
* which executes the program. Dunno what's the usefulness of this.
* A child setup function used on Unix probably isn't of much use
- * as such on Win32, anyhow.
+ * as such on Win32, anyhow
*/
if (child_setup)
{
/* Let's hope envp hasn't mucked with PATH so that
* gspawn-win32-helper.exe isn't found.
*/
- spawnvpe (P_NOWAIT, "gspawn-win32-helper", new_argv, envp);
+ rc = spawnvpe (P_NOWAIT, "gspawn-win32-helper", new_argv, envp);
else
- spawnvp (P_NOWAIT, "gspawn-win32-helper", new_argv);
-
- /* FIXME: What if gspawn-win32-helper.exe isn't found? */
+ rc = spawnvp (P_NOWAIT, "gspawn-win32-helper", new_argv);
/* Close the child_err_report_fd and the other process's ends of the
* pipes in this process, otherwise the reader will never get
if (stderr_fd >= 0)
close (stderr_fd);
+ g_free (new_argv[ARG_WORKING_DIRECTORY]);
g_free (new_argv);
- return 0;
+ return rc;
}
static gboolean
}
static gboolean
-fork_exec_with_pipes (gboolean dont_wait,
- const gchar *working_directory,
- gchar **argv,
- gchar **envp,
- gboolean close_descriptors,
- gboolean search_path,
- gboolean stdout_to_null,
- gboolean stderr_to_null,
- gboolean child_inherits_stdin,
- GSpawnChildSetupFunc child_setup,
- gpointer user_data,
- gint *standard_input,
- gint *standard_output,
- gint *standard_error,
- gint *exit_status,
- GError **error)
+do_spawn_with_pipes (gboolean dont_wait,
+ gboolean dont_return_handle,
+ const gchar *working_directory,
+ gchar **argv,
+ gchar **envp,
+ gboolean close_descriptors,
+ gboolean search_path,
+ gboolean stdout_to_null,
+ gboolean stderr_to_null,
+ gboolean child_inherits_stdin,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data,
+ gint *child_pid,
+ gint *standard_input,
+ gint *standard_output,
+ gint *standard_error,
+ gint *exit_status,
+ GError **error)
{
gint stdin_pipe[2] = { -1, -1 };
gint stdout_pipe[2] = { -1, -1 };
gint stderr_pipe[2] = { -1, -1 };
gint child_err_report_pipe[2] = { -1, -1 };
- gint status;
- gint bytes;
+ gint helper = -1;
gint buf[2];
gint n_ints = 0;
if (standard_error && !make_pipe (stderr_pipe, error))
goto cleanup_and_fail;
- status = do_exec (dont_wait,
- child_err_report_pipe[1],
- stdin_pipe[0],
- stdout_pipe[1],
- stderr_pipe[1],
- working_directory,
- argv,
- envp,
- close_descriptors,
- search_path,
- stdout_to_null,
- stderr_to_null,
- child_inherits_stdin,
- child_setup,
- user_data);
+ helper = do_spawn (dont_wait,
+ child_err_report_pipe[1],
+ stdin_pipe[0],
+ stdout_pipe[1],
+ stderr_pipe[1],
+ working_directory,
+ argv,
+ envp,
+ close_descriptors,
+ search_path,
+ stdout_to_null,
+ stderr_to_null,
+ child_inherits_stdin,
+ child_setup,
+ user_data);
+ /* do_spawn() returns -1 if gspawn-win32-helper couldn't be run */
+ if (helper == -1)
+ {
+ g_set_error (error,
+ G_SPAWN_ERROR,
+ G_SPAWN_ERROR_FAILED,
+ _("Failed to execute helper program"));
+ goto cleanup_and_fail;
+ }
+
if (!read_ints (child_err_report_pipe[0],
buf, 2, &n_ints,
- error))
+ error) ||
+ n_ints != 2)
goto cleanup_and_fail;
- if (n_ints == 2)
+ /* Error code from gspawn-win32-helper. */
+ switch (buf[0])
{
- /* Error from the child. */
-
- switch (buf[0])
+ case CHILD_NO_ERROR:
+ if (child_pid && dont_wait && !dont_return_handle)
{
- case CHILD_NO_ERROR:
- break;
-
- case CHILD_CHDIR_FAILED:
- g_set_error (error,
- G_SPAWN_ERROR,
- G_SPAWN_ERROR_CHDIR,
- _("Failed to change to directory '%s' (%s)"),
- working_directory,
- g_strerror (buf[1]));
- goto cleanup_and_fail;
-
- case CHILD_SPAWN_FAILED:
- g_set_error (error,
- G_SPAWN_ERROR,
- G_SPAWN_ERROR_FAILED,
- _("Failed to execute child process (%s)"),
- g_strerror (buf[1]));
- goto cleanup_and_fail;
+ /* helper is our HANDLE for gspawn-win32-helper. It has
+ * told us the HANDLE of its child. Duplicate that into
+ * a HANDLE valid in this process.
+ */
+ if (!DuplicateHandle ((HANDLE) helper, (HANDLE) buf[1],
+ GetCurrentProcess (), (LPHANDLE) child_pid,
+ 0, TRUE, DUPLICATE_SAME_ACCESS))
+ *child_pid = 0;
}
+ else if (child_pid)
+ *child_pid = 0;
+ break;
+
+ case CHILD_CHDIR_FAILED:
+ g_set_error (error,
+ G_SPAWN_ERROR,
+ G_SPAWN_ERROR_CHDIR,
+ _("Failed to change to directory '%s' (%s)"),
+ working_directory,
+ g_strerror (buf[1]));
+ goto cleanup_and_fail;
+
+ case CHILD_SPAWN_FAILED:
+ g_set_error (error,
+ G_SPAWN_ERROR,
+ G_SPAWN_ERROR_FAILED,
+ _("Failed to execute child process (%s)"),
+ g_strerror (buf[1]));
+ goto cleanup_and_fail;
}
/* Success against all odds! return the information */
if (standard_error)
*standard_error = stderr_pipe[0];
if (exit_status)
- *exit_status = status;
+ *exit_status = buf[1];
+ CloseHandle ((HANDLE) helper);
return TRUE;
cleanup_and_fail:
+ if (helper != -1)
+ CloseHandle ((HANDLE) helper);
close_and_invalidate (&child_err_report_pipe[0]);
close_and_invalidate (&child_err_report_pipe[1]);
close_and_invalidate (&stdin_pipe[0]);
return TRUE;
}
-#else /* GSPAWN_HELPER */
-
-static void
-write_err_and_exit (gint fd,
- gint msg)
-{
- gint en = errno;
-
- write (fd, &msg, sizeof(msg));
- write (fd, &en, sizeof(en));
-
- _exit (1);
-}
-
-static void
-write_no_error (gint fd)
-{
- gint msg = CHILD_NO_ERROR;
- gint en = 0;
-
- write (fd, &msg, sizeof(msg));
- write (fd, &en, sizeof(en));
-}
-
-#ifdef __GNUC__
-# ifndef _stdcall
-# define _stdcall __attribute__((stdcall))
-# endif
-#endif
-
-/* We build gspawn-win32-helper.exe as a Windows GUI application
- * to avoid any temporarily flashing console windows in case
- * the gspawn function is invoked by a GUI program. Thus, no main()
- * but a WinMain(). We do, however, still use argc and argv tucked
- * away in the global __argc and __argv by the C runtime startup code.
- */
-
-int _stdcall
-WinMain (struct HINSTANCE__ *hInstance,
- struct HINSTANCE__ *hPrevInstance,
- char *lpszCmdLine,
- int nCmdShow)
-{
- int child_err_report_fd;
- int i;
- int fd;
- int mode;
- GString *debugstring;
-
- SETUP_DEBUG();
-
- if (debug)
- {
- debugstring = g_string_new ("");
-
- g_string_append (debugstring,
- g_strdup_printf ("g-spawn-win32-helper: "
- "argc = %d, argv: ",
- __argc));
- for (i = 0; i < __argc; i++)
- {
- if (i > 0)
- g_string_append (debugstring, " ");
- g_string_append (debugstring, __argv[i]);
- }
-
- MessageBox (NULL, debugstring->str, "gspawn-win32-helper", 0);
- }
-
- g_assert (__argc >= ARG_COUNT);
-
- /* argv[ARG_CHILD_ERR_REPORT] is the file descriptor onto which
- * write error messages.
- */
- child_err_report_fd = atoi (__argv[ARG_CHILD_ERR_REPORT]);
-
- /* argv[ARG_STDIN..ARG_STDERR] are the file descriptors that should
- * be dup2'd to stdin, stdout and stderr, '-' if the corresponding
- * std* should be let alone, and 'z' if it should be connected to
- * the bit bucket NUL:.
- */
- if (__argv[ARG_STDIN][0] == '-')
- ; /* Nothing */
- else if (__argv[ARG_STDIN][0] == 'z')
- {
- fd = open ("NUL:", O_RDONLY);
- if (fd != 0)
- {
- dup2 (fd, 0);
- close (fd);
- }
- }
- else
- {
- fd = atoi (__argv[ARG_STDIN]);
- if (fd != 0)
- {
- dup2 (fd, 0);
- close (fd);
- }
- }
-
- if (__argv[ARG_STDOUT][0] == '-')
- ; /* Nothing */
- else if (__argv[ARG_STDOUT][0] == 'z')
- {
- fd = open ("NUL:", O_WRONLY);
- if (fd != 1)
- {
- dup2 (fd, 1);
- close (fd);
- }
- }
- else
- {
- fd = atoi (__argv[ARG_STDOUT]);
- if (fd != 1)
- {
- dup2 (fd, 1);
- close (fd);
- }
- }
-
- if (__argv[ARG_STDERR][0] == '-')
- ; /* Nothing */
- else if (__argv[ARG_STDERR][0] == 'z')
- {
- fd = open ("NUL:", O_WRONLY);
- if (fd != 2)
- {
- dup2 (fd, 2);
- close (fd);
- }
- }
- else
- {
- fd = atoi (__argv[ARG_STDERR]);
- if (fd != 2)
- {
- dup2 (fd, 2);
- close (fd);
- }
- }
-
- /* __argv[ARG_WORKING_DIRECTORY] is the directory in which to run the
- * process. If "-", don't change directory.
- */
- if (__argv[ARG_WORKING_DIRECTORY][0] == '-' &&
- __argv[ARG_WORKING_DIRECTORY][1] == 0)
- ; /* Nothing */
- else if (chdir (__argv[ARG_WORKING_DIRECTORY]) < 0)
- write_err_and_exit (child_err_report_fd,
- CHILD_CHDIR_FAILED);
-
- /* __argv[ARG_CLOSE_DESCRIPTORS] is "y" if file descriptors from 3
- * upwards should be closed
- */
-
- if (__argv[ARG_CLOSE_DESCRIPTORS][0] == 'y')
- for (i = 3; i < 1000; i++) /* FIXME real limit? */
- if (i != child_err_report_fd)
- close (i);
-
- /* __argv[ARG_WAIT] is "w" to wait for the program to exit */
-
- if (__argv[ARG_WAIT][0] == 'w')
- mode = P_WAIT;
- else
- mode = P_NOWAIT;
-
- /* __argv[ARG_USE_PATH] is "y" to use PATH, otherwise not */
-
- /* __argv[ARG_PROGRAM] is program file to run,
- * __argv[ARG_PROGRAM+1]... is its __argv.
- */
-
- if (debug)
- {
- debugstring = g_string_new ("");
- g_string_append (debugstring,
- g_strdup_printf ("calling %s on program %s, __argv: ",
- (__argv[ARG_USE_PATH][0] == 'y' ?
- "spawnvp" : "spawnv"),
- __argv[ARG_PROGRAM]));
- i = ARG_PROGRAM+1;
- while (__argv[i])
- g_string_append (debugstring, __argv[i++]);
- MessageBox (NULL, debugstring->str, "gspawn-win32-helper", 0);
- }
-
- if (__argv[ARG_USE_PATH][0] == 'y')
- {
- if (spawnvp (mode, __argv[ARG_PROGRAM], __argv+ARG_PROGRAM) < 0)
- write_err_and_exit (child_err_report_fd, CHILD_SPAWN_FAILED);
- }
- else
- {
- if (spawnv (mode, __argv[ARG_PROGRAM], __argv+ARG_PROGRAM) < 0)
- write_err_and_exit (child_err_report_fd, CHILD_SPAWN_FAILED);
- }
-
- return 0;
-}
-
-#endif /* GSPAWN_HELPER */
+#endif /* !GSPAWN_HELPER */