intial implementation of new API functions. Not sure if it behaves as
[platform/upstream/glib.git] / glib / gspawn-win32.c
1 /* gspawn-win32.c - Process launching on Win32
2  *
3  *  Copyright 2000 Red Hat, Inc.
4  *
5  * GLib is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * GLib is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with GLib; see the file COPYING.LIB.  If not, write
17  * to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Implementation details on Win32.
23  *
24  * - There is no way to set the no-inherit flag for
25  *   a "file descriptor" in the MS C runtime. The flag is there,
26  *   and the dospawn() function uses it, but unfortunately
27  *   this flag can only be set when opening the file.
28  * - As there is no fork(), we cannot reliably change directory
29  *   before starting the child process. (There might be several threads
30  *   running, and the current directory is common for all threads.)
31  *
32  * Thus, we must in most cases use a helper program to handle closing
33  * of (inherited) file descriptors and changing of directory. In fact,
34  * we do it all the time.
35  *
36  * This source file contains the source for that helper program.
37  * To compile it, #define GSPAWN_HELPER.
38  */
39
40 /* Define this to get some logging all the time */
41 /* #define G_SPAWN_WIN32_DEBUG */
42
43 #include "glib.h"
44
45 #include <string.h>
46 #include <stdlib.h>
47 #include <stdio.h>
48
49 #include <windows.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <io.h>
53 #include <process.h>
54 #include <direct.h>
55
56 #include "glibintl.h"
57
58 #ifdef G_SPAWN_WIN32_DEBUG
59   static int debug = 1;
60   #define SETUP_DEBUG() /* empty */
61
62 #else
63   static int debug = -1;
64   #define SETUP_DEBUG()                                 \
65     G_STMT_START                                        \
66       {                                                 \
67         if (debug == -1)                                \
68           {                                             \
69             if (getenv ("G_SPAWN_WIN32_DEBUG") != NULL) \
70               debug = 1;                                \
71             else                                        \
72               debug = 0;                                \
73           }                                             \
74       }                                                 \
75     G_STMT_END
76 #endif
77
78 enum
79 {
80   CHILD_NO_ERROR,
81   CHILD_CHDIR_FAILED,
82   CHILD_SPAWN_FAILED,
83 };
84
85 enum {
86   ARG_CHILD_ERR_REPORT = 1,
87   ARG_STDIN,
88   ARG_STDOUT,
89   ARG_STDERR,
90   ARG_WORKING_DIRECTORY,
91   ARG_CLOSE_DESCRIPTORS,
92   ARG_USE_PATH,
93   ARG_WAIT,
94   ARG_PROGRAM,
95   ARG_COUNT = ARG_PROGRAM
96 };
97
98 #ifndef GSPAWN_HELPER
99
100 static gboolean make_pipe            (gint                  p[2],
101                                       GError              **error);
102 static gboolean fork_exec_with_pipes (gboolean              dont_wait,
103                                       const gchar          *working_directory,
104                                       gchar               **argv,
105                                       gchar               **envp,
106                                       gboolean              close_descriptors,
107                                       gboolean              search_path,
108                                       gboolean              stdout_to_null,
109                                       gboolean              stderr_to_null,
110                                       gboolean              child_inherits_stdin,
111                                       GSpawnChildSetupFunc  child_setup,
112                                       gpointer              user_data,
113                                       gint                 *standard_input,
114                                       gint                 *standard_output,
115                                       gint                 *standard_error,
116                                       gint                 *exit_status,
117                                       GError              **error);
118
119 GQuark
120 g_spawn_error_quark (void)
121 {
122   static GQuark quark = 0;
123   if (quark == 0)
124     quark = g_quark_from_static_string ("g-exec-error-quark");
125   return quark;
126 }
127
128 /**
129  * g_spawn_async:
130  * @working_directory: child's current working directory, or NULL to inherit parent's
131  * @argv: child's argument vector
132  * @envp: child's environment, or NULL to inherit parent's
133  * @flags: flags from #GSpawnFlags
134  * @child_setup: function to run in the child just before exec()
135  * @user_data: user data for @child_setup
136  * @child_pid: return location for child process ID, or NULL
137  * @error: return location for error
138  * 
139  * See g_spawn_async_with_pipes() for a full description; this function
140  * simply calls the g_spawn_async_with_pipes() without any pipes.
141  * 
142  * Return value: TRUE on success, FALSE if error is set
143  **/
144 gboolean
145 g_spawn_async (const gchar          *working_directory,
146                gchar               **argv,
147                gchar               **envp,
148                GSpawnFlags           flags,
149                GSpawnChildSetupFunc  child_setup,
150                gpointer              user_data,
151                gint                 *child_pid,
152                GError              **error)
153 {
154   g_return_val_if_fail (argv != NULL, FALSE);
155   
156   return g_spawn_async_with_pipes (working_directory,
157                                    argv, envp,
158                                    flags,
159                                    child_setup,
160                                    user_data,
161                                    child_pid,
162                                    NULL, NULL, NULL,
163                                    error);
164 }
165
166 /* Avoids a danger in threaded situations (calling close()
167  * on a file descriptor twice, and another thread has
168  * re-opened it since the first close)
169  */
170 static gint
171 close_and_invalidate (gint *fd)
172 {
173   gint ret;
174
175   ret = close (*fd);
176   *fd = -1;
177
178   return ret;
179 }
180
181 typedef enum
182 {
183   READ_FAILED = 0, /* FALSE */
184   READ_OK,
185   READ_EOF
186 } ReadResult;
187
188 static ReadResult
189 read_data (GString     *str,
190            GIOChannel  *iochannel,
191            GError     **error)
192 {
193   GIOError gioerror;
194   gint bytes;
195   gchar buf[4096];
196
197  again:
198   
199   gioerror = g_io_channel_read (iochannel, buf, sizeof (buf), &bytes);
200
201   if (bytes == 0)
202     return READ_EOF;
203   else if (bytes > 0)
204     {
205       g_string_append_len (str, buf, bytes);
206       return READ_OK;
207     }
208   else if (gioerror == G_IO_ERROR_AGAIN)
209     goto again;
210   else if (gioerror != G_IO_ERROR_NONE)
211     {
212       g_set_error (error,
213                    G_SPAWN_ERROR,
214                    G_SPAWN_ERROR_READ,
215                    _("Failed to read data from child process"));
216       
217       return READ_FAILED;
218     }
219   else
220     return READ_OK;
221 }
222
223 /**
224  * g_spawn_sync:
225  * @working_directory: child's current working directory, or NULL to inherit parent's
226  * @argv: child's argument vector
227  * @envp: child's environment, or NULL to inherit parent's
228  * @flags: flags from #GSpawnFlags
229  * @child_setup: function to run in the child just before exec()
230  * @user_data: user data for @child_setup
231  * @standard_output: return location for child output 
232  * @standard_error: return location for child error messages
233  * @exit_status: child exit status, as returned by waitpid()
234  * @error: return location for error
235  *
236  * Executes a child synchronously (waits for the child to exit before returning).
237  * All output from the child is stored in @standard_output and @standard_error,
238  * if those parameters are non-NULL. If @exit_status is non-NULL, the exit status
239  * of the child is stored there as it would be by waitpid(); standard UNIX
240  * macros such as WIFEXITED() and WEXITSTATUS() must be used to evaluate the
241  * exit status. If an error occurs, no data is returned in @standard_output,
242  * @standard_error, or @exit_status.
243  * 
244  * This function calls g_spawn_async_with_pipes() internally; see that function
245  * for full details on the other parameters.
246  * 
247  * Return value: TRUE on success, FALSE if an error was set.
248  **/
249 gboolean
250 g_spawn_sync (const gchar          *working_directory,
251               gchar               **argv,
252               gchar               **envp,
253               GSpawnFlags           flags,
254               GSpawnChildSetupFunc  child_setup,
255               gpointer              user_data,
256               gchar               **standard_output,
257               gchar               **standard_error,
258               gint                 *exit_status,
259               GError              **error)     
260 {
261   gint outpipe = -1;
262   gint errpipe = -1;
263   GIOChannel *outchannel = NULL;
264   GIOChannel *errchannel = NULL;
265   GPollFD outfd, errfd;
266   GPollFD fds[2];
267   gint nfds;
268   gint outindex = -1;
269   gint errindex = -1;
270   gint ret;
271   GString *outstr = NULL;
272   GString *errstr = NULL;
273   gboolean failed;
274   gint status;
275   
276   g_return_val_if_fail (argv != NULL, FALSE);
277   g_return_val_if_fail (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), FALSE);
278   g_return_val_if_fail (standard_output == NULL ||
279                         !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
280   g_return_val_if_fail (standard_error == NULL ||
281                         !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
282   
283   /* Just to ensure segfaults if callers try to use
284    * these when an error is reported.
285    */
286   if (standard_output)
287     *standard_output = NULL;
288
289   if (standard_error)
290     *standard_error = NULL;
291   
292   if (!fork_exec_with_pipes (FALSE,
293                              working_directory,
294                              argv,
295                              envp,
296                              !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
297                              (flags & G_SPAWN_SEARCH_PATH) != 0,
298                              (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
299                              (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
300                              (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
301                              child_setup,
302                              user_data,
303                              NULL,
304                              standard_output ? &outpipe : NULL,
305                              standard_error ? &errpipe : NULL,
306                              &status,
307                              error))
308     return FALSE;
309
310   /* Read data from child. */
311   
312   failed = FALSE;
313
314   if (outpipe >= 0)
315     {
316       outstr = g_string_new ("");
317       outchannel = g_io_channel_win32_new_fd (outpipe);
318       g_io_channel_win32_make_pollfd (outchannel,
319                                       G_IO_IN | G_IO_ERR | G_IO_HUP,
320                                       &outfd);
321     }
322       
323   if (errpipe >= 0)
324     {
325       errstr = g_string_new ("");
326       errchannel = g_io_channel_win32_new_fd (errpipe);
327       g_io_channel_win32_make_pollfd (errchannel,
328                                       G_IO_IN | G_IO_ERR | G_IO_HUP,
329                                       &errfd);
330     }
331
332   /* Read data until we get EOF on both pipes. */
333   while (!failed &&
334          (outpipe >= 0 ||
335           errpipe >= 0))
336     {
337       nfds = 0;
338       if (outpipe >= 0)
339         {
340           fds[nfds] = outfd;
341           outindex = nfds;
342           nfds++;
343         }
344       if (errpipe >= 0)
345         {
346           fds[nfds] = errfd;
347           errindex = nfds;
348           nfds++;
349         }
350
351       if (debug)
352         g_print ("%s:g_spawn_sync: calling g_io_channel_win32_poll, nfds=%d\n",
353                  __FILE__, nfds);
354
355       ret = g_io_channel_win32_poll (fds, nfds, -1);
356
357       if (ret < 0)
358         {
359           failed = TRUE;
360
361           g_set_error (error,
362                        G_SPAWN_ERROR,
363                        G_SPAWN_ERROR_READ,
364                        _("Unexpected error in g_io_channel_win32_poll() reading data from a child process"));
365               
366           break;
367         }
368
369       if (outpipe >= 0 && (fds[outindex].revents & G_IO_IN))
370         {
371           switch (read_data (outstr, outchannel, error))
372             {
373             case READ_FAILED:
374               if (debug)
375                 g_print ("g_spawn_sync: outchannel: READ_FAILED\n");
376               failed = TRUE;
377               break;
378             case READ_EOF:
379               if (debug)
380                 g_print ("g_spawn_sync: outchannel: READ_EOF\n");
381               g_io_channel_unref (outchannel);
382               outchannel = NULL;
383               close_and_invalidate (&outpipe);
384               break;
385             default:
386               if (debug)
387                 g_print ("g_spawn_sync: outchannel: OK\n");
388               break;
389             }
390
391           if (failed)
392             break;
393         }
394
395       if (errpipe >= 0 && (fds[errindex].revents & G_IO_IN))
396         {
397           switch (read_data (errstr, errchannel, error))
398             {
399             case READ_FAILED:
400               if (debug)
401                 g_print ("g_spawn_sync: errchannel: READ_FAILED\n");
402               failed = TRUE;
403               break;
404             case READ_EOF:
405               if (debug)
406                 g_print ("g_spawn_sync: errchannel: READ_EOF\n");
407               g_io_channel_unref (errchannel);
408               errchannel = NULL;
409               close_and_invalidate (&errpipe);
410               break;
411             default:
412               if (debug)
413                 g_print ("g_spawn_sync: errchannel: OK\n");
414               break;
415             }
416
417           if (failed)
418             break;
419         }
420     }
421
422   /* These should only be open still if we had an error.  */
423   
424   if (outchannel != NULL)
425     g_io_channel_unref (outchannel);
426   if (errchannel != NULL)
427     g_io_channel_unref (errchannel);
428   if (outpipe >= 0)
429     close_and_invalidate (&outpipe);
430   if (errpipe >= 0)
431     close_and_invalidate (&errpipe);
432   
433   if (failed)
434     {
435       if (outstr)
436         g_string_free (outstr, TRUE);
437       if (errstr)
438         g_string_free (errstr, TRUE);
439
440       return FALSE;
441     }
442   else
443     {
444       if (exit_status)
445         *exit_status = status;
446       
447       if (standard_output)        
448         *standard_output = g_string_free (outstr, FALSE);
449
450       if (standard_error)
451         *standard_error = g_string_free (errstr, FALSE);
452
453       return TRUE;
454     }
455 }
456
457 /**
458  * g_spawn_async_with_pipes:
459  * @working_directory: child's current working directory, or NULL to inherit parent's
460  * @argv: child's argument vector
461  * @envp: child's environment, or NULL to inherit parent's
462  * @flags: flags from #GSpawnFlags
463  * @child_setup: function to run in the child just before exec()
464  * @user_data: user data for @child_setup
465  * @child_pid: return location for child process ID, or NULL
466  * @standard_input: return location for file descriptor to write to child's stdin, or NULL
467  * @standard_output: return location for file descriptor to read child's stdout, or NULL
468  * @standard_error: return location for file descriptor to read child's stderr, or NULL
469  * @error: return location for error
470  *
471  * Executes a child program asynchronously (your program will not
472  * block waiting for the child to exit). The child program is
473  * specified by the only argument that must be provided, @argv. @argv
474  * should be a NULL-terminated array of strings, to be passed as the
475  * argument vector for the child. The first string in @argv is of
476  * course the name of the program to execute. By default, the name of
477  * the program must be a full path; the PATH shell variable will only
478  * be searched if you pass the %G_SPAWN_SEARCH_PATH flag.
479  *
480  * @envp is a NULL-terminated array of strings, where each string
481  * has the form <literal>KEY=VALUE</literal>. This will become
482  * the child's environment. If @envp is NULL, the child inherits its
483  * parent's environment.
484  *
485  * @flags should be the bitwise OR of any flags you want to affect the
486  * function's behavior. The %G_SPAWN_DO_NOT_REAP_CHILD means that the
487  * child will not be automatically reaped; you must call waitpid() or
488  * handle SIGCHLD yourself, or the child will become a zombie.
489  * %G_SPAWN_LEAVE_DESCRIPTORS_OPEN means that the parent's open file
490  * descriptors will be inherited by the child; otherwise all
491  * descriptors except stdin/stdout/stderr will be closed before
492  * calling exec() in the child. %G_SPAWN_SEARCH_PATH means that
493  * <literal>argv[0]</literal> need not be an absolute path, it
494  * will be looked for in the user's PATH. %G_SPAWN_STDOUT_TO_DEV_NULL
495  * means that the child's standad output will be discarded, instead
496  * of going to the same location as the parent's standard output.
497  * %G_SPAWN_STDERR_TO_DEV_NULL means that the child's standard error
498  * will be discarded. %G_SPAWN_CHILD_INHERITS_STDIN means that
499  * the child will inherit the parent's standard input (by default,
500  * the child's standard input is attached to /dev/null).
501  *
502  * @child_setup and @user_data are a function and user data to be
503  * called in the child after GLib has performed all the setup it plans
504  * to perform (including creating pipes, closing file descriptors,
505  * etc.) but before calling exec(). That is, @child_setup is called
506  * just before calling exec() in the child. Obviously actions taken in
507  * this function will only affect the child, not the parent. 
508  *
509  * If non-NULL, @child_pid will be filled with the child's process
510  * ID. You can use the process ID to send signals to the child, or
511  * to waitpid() if you specified the %G_SPAWN_DO_NOT_REAP_CHILD flag.
512  *
513  * If non-NULL, the @standard_input, @standard_output, @standard_error
514  * locations will be filled with file descriptors for writing to the child's
515  * standard input or reading from its standard output or standard error.
516  * The caller of g_spawn_async_with_pipes() must close these file descriptors
517  * when they are no longer in use. If these parameters are NULL, the
518  * corresponding pipe won't be created.
519  *
520  * @error can be NULL to ignore errors, or non-NULL to report errors.
521  * If an error is set, the function returns FALSE. Errors
522  * are reported even if they occur in the child (for example if the
523  * executable in <literal>argv[0]</literal> is not found). Typically
524  * the <literal>message</literal> field of returned errors should be displayed
525  * to users. Possible errors are those from the #G_SPAWN_ERROR domain.
526  *
527  * If an error occurs, @child_pid, @standard_input, @standard_output,
528  * and @standard_error will not be filled with valid values.
529  * 
530  * Return value: TRUE on success, FALSE if an error was set
531  **/
532 gboolean
533 g_spawn_async_with_pipes (const gchar          *working_directory,
534                           gchar               **argv,
535                           gchar               **envp,
536                           GSpawnFlags           flags,
537                           GSpawnChildSetupFunc  child_setup,
538                           gpointer              user_data,
539                           gint                 *child_pid,
540                           gint                 *standard_input,
541                           gint                 *standard_output,
542                           gint                 *standard_error,
543                           GError              **error)
544 {
545   g_return_val_if_fail (argv != NULL, FALSE);
546   g_return_val_if_fail (standard_output == NULL ||
547                         !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
548   g_return_val_if_fail (standard_error == NULL ||
549                         !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
550   /* can't inherit stdin if we have an input pipe. */
551   g_return_val_if_fail (standard_input == NULL ||
552                         !(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE);
553   
554   return fork_exec_with_pipes (!(flags & G_SPAWN_DO_NOT_REAP_CHILD),
555                                working_directory,
556                                argv,
557                                envp,
558                                !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
559                                (flags & G_SPAWN_SEARCH_PATH) != 0,
560                                (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
561                                (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
562                                (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
563                                child_setup,
564                                user_data,
565                                standard_input,
566                                standard_output,
567                                standard_error,
568                                NULL,
569                                error);
570 }
571
572 /**
573  * g_spawn_command_line_sync:
574  * @command_line: a command line 
575  * @standard_output: return location for child output
576  * @standard_error: return location for child errors
577  * @exit_status: return location for child exit status
578  * @error: return location for errors
579  *
580  * A simple version of g_spawn_sync() with little-used parameters
581  * removed, taking a command line instead of an argument vector.  See
582  * g_spawn_sync() for full details. @command_line will be parsed by
583  * g_shell_parse_argv(). Unlike g_spawn_sync(), the %G_SPAWN_SEARCH_PATH flag
584  * is enabled. Note that %G_SPAWN_SEARCH_PATH can have security
585  * implications, so consider using g_spawn_sync() directly if
586  * appropriate. Possible errors are those from g_spawn_sync() and those
587  * from g_shell_parse_argv().
588  * 
589  * Return value: TRUE on success, FALSE if an error was set
590  **/
591 gboolean
592 g_spawn_command_line_sync (const gchar  *command_line,
593                            gchar       **standard_output,
594                            gchar       **standard_error,
595                            gint         *exit_status,
596                            GError      **error)
597 {
598   gboolean retval;
599   gchar **argv = 0;
600
601   g_return_val_if_fail (command_line != NULL, FALSE);
602   
603   if (!g_shell_parse_argv (command_line,
604                            NULL, &argv,
605                            error))
606     return FALSE;
607   
608   retval = g_spawn_sync (NULL,
609                          argv,
610                          NULL,
611                          G_SPAWN_SEARCH_PATH,
612                          NULL,
613                          NULL,
614                          standard_output,
615                          standard_error,
616                          exit_status,
617                          error);
618   g_strfreev (argv);
619
620   return retval;
621 }
622
623 /**
624  * g_spawn_command_line_async:
625  * @command_line: a command line
626  * @error: return location for errors
627  * 
628  * A simple version of g_spawn_async() that parses a command line with
629  * g_shell_parse_argv() and passes it to g_spawn_async(). Runs a
630  * command line in the background. Unlike g_spawn_async(), the
631  * %G_SPAWN_SEARCH_PATH flag is enabled, other flags are not. Note
632  * that %G_SPAWN_SEARCH_PATH can have security implications, so
633  * consider using g_spawn_async() directly if appropriate. Possible
634  * errors are those from g_shell_parse_argv() and g_spawn_async().
635  * 
636  * Return value: TRUE on success, FALSE if error is set.
637  **/
638 gboolean
639 g_spawn_command_line_async (const gchar *command_line,
640                             GError     **error)
641 {
642   gboolean retval;
643   gchar **argv = 0;
644
645   g_return_val_if_fail (command_line != NULL, FALSE);
646
647   if (!g_shell_parse_argv (command_line,
648                            NULL, &argv,
649                            error))
650     return FALSE;
651   
652   retval = g_spawn_async (NULL,
653                           argv,
654                           NULL,
655                           G_SPAWN_SEARCH_PATH,
656                           NULL,
657                           NULL,
658                           NULL,
659                           error);
660   g_strfreev (argv);
661
662   return retval;
663 }
664
665 static gint
666 do_exec (gboolean              dont_wait,
667          gint                  child_err_report_fd,
668          gint                  stdin_fd,
669          gint                  stdout_fd,
670          gint                  stderr_fd,
671          const gchar          *working_directory,
672          gchar               **argv,
673          gchar               **envp,
674          gboolean              close_descriptors,
675          gboolean              search_path,
676          gboolean              stdout_to_null,
677          gboolean              stderr_to_null,
678          gboolean              child_inherits_stdin,
679          GSpawnChildSetupFunc  child_setup,
680          gpointer              user_data)
681 {
682   gchar **new_argv;
683   gchar args[ARG_COUNT][10];
684   gint i;
685   int argc = 0;
686
687   SETUP_DEBUG();
688
689   while (argv[argc])
690     ++argc;
691
692   new_argv = g_new (gchar *, argc + 1 + ARG_COUNT);
693
694   new_argv[0] = "gspawn-win32-helper";
695   sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_fd);
696   new_argv[ARG_CHILD_ERR_REPORT] = args[ARG_CHILD_ERR_REPORT];
697
698   if (stdin_fd >= 0)
699     {
700       sprintf (args[ARG_STDIN], "%d", stdin_fd);
701       new_argv[ARG_STDIN] = args[ARG_STDIN];
702     }
703   else if (child_inherits_stdin)
704     {
705       /* Let stdin be alone */
706       new_argv[ARG_STDIN] = "-";
707     }
708   else
709     {
710       /* Keep process from blocking on a read of stdin */
711       new_argv[ARG_STDIN] = "z";
712     }
713
714   if (stdout_fd >= 0)
715     {
716       sprintf (args[ARG_STDOUT], "%d", stdout_fd);
717       new_argv[ARG_STDOUT] = args[ARG_STDOUT];
718     }
719   else if (stdout_to_null)
720     {
721       new_argv[ARG_STDOUT] = "z";
722     }
723   else
724     {
725       new_argv[ARG_STDOUT] = "-";
726     }
727
728   if (stderr_fd >= 0)
729     {
730       sprintf (args[ARG_STDERR], "%d", stderr_fd);
731       new_argv[ARG_STDERR] = args[ARG_STDERR];
732     }
733   else if (stderr_to_null)
734     {
735       new_argv[ARG_STDERR] = "z";
736     }
737   else
738     {
739       new_argv[ARG_STDERR] = "-";
740     }
741
742   if (working_directory && *working_directory)
743     new_argv[ARG_WORKING_DIRECTORY] = working_directory;
744   else
745     new_argv[ARG_WORKING_DIRECTORY] = "-";
746
747   if (close_descriptors)
748     new_argv[ARG_CLOSE_DESCRIPTORS] = "y";
749   else
750     new_argv[ARG_CLOSE_DESCRIPTORS] = "-";
751
752   if (search_path)
753     new_argv[ARG_USE_PATH] = "y";
754   else
755     new_argv[ARG_USE_PATH] = "-";
756
757   if (dont_wait)
758     new_argv[ARG_WAIT] = "-";
759   else
760     new_argv[ARG_WAIT] = "w";
761
762   for (i = 0; i <= argc; i++)
763     new_argv[ARG_PROGRAM + i] = argv[i];
764
765   /* Call user function just before we execute the helper program,
766    * which executes the program. Dunno what's the usefulness of this.
767    * A child setup function used on Unix probably isn't of much use
768    * as such on Win32, anyhow.
769    */
770   if (child_setup)
771     {
772       (* child_setup) (user_data);
773     }
774
775   if (debug)
776     {
777       g_print ("calling gspawn-win32-helper with argv:\n");
778       for (i = 0; i < argc + 1 + ARG_COUNT; i++)
779         g_print ("argv[%d]: %s\n", i, (new_argv[i] ? new_argv[i] : "NULL"));
780     }
781   
782   if (envp != NULL)
783     /* Let's hope envp hasn't mucked with PATH so that
784      * gspawn-win32-helper.exe isn't found.
785      */
786     spawnvpe (P_NOWAIT, "gspawn-win32-helper", new_argv, envp);
787   else
788     spawnvp (P_NOWAIT, "gspawn-win32-helper", new_argv);
789
790   /* FIXME: What if gspawn-win32-helper.exe isn't found? */
791
792   /* Close the child_err_report_fd and the other process's ends of the
793    * pipes in this process, otherwise the reader will never get
794    * EOF.
795    */
796   close (child_err_report_fd);
797   if (stdin_fd >= 0)
798     close (stdin_fd);
799   if (stdout_fd >= 0)
800     close (stdout_fd);
801   if (stderr_fd >= 0)
802     close (stderr_fd);
803
804   g_free (new_argv);
805
806   return 0;
807 }
808
809 static gboolean
810 read_ints (int      fd,
811            gint*    buf,
812            gint     n_ints_in_buf,
813            gint    *n_ints_read,
814            GError **error)
815 {
816   gint bytes = 0;
817   
818   while (bytes < sizeof(gint)*n_ints_in_buf)
819     {
820       gint chunk;
821
822       if (debug)
823         g_print ("%s:read_ints: trying to read %d bytes from pipe...\n",
824                  __FILE__,
825                  sizeof(gint)*n_ints_in_buf - bytes);
826
827       chunk = read (fd, ((gchar*)buf) + bytes,
828                     sizeof(gint)*n_ints_in_buf - bytes);
829
830       if (debug)
831         g_print ("... got %d bytes\n", chunk);
832           
833       if (chunk < 0)
834         {
835           /* Some weird shit happened, bail out */
836               
837           g_set_error (error,
838                        G_SPAWN_ERROR,
839                        G_SPAWN_ERROR_FAILED,
840                        _("Failed to read from child pipe (%s)"),
841                        g_strerror (errno));
842
843           return FALSE;
844         }
845       else if (chunk == 0)
846         break; /* EOF */
847       else
848         bytes += chunk;
849     }
850
851   *n_ints_read = bytes/sizeof(gint);
852
853   return TRUE;
854 }
855
856 static gboolean
857 fork_exec_with_pipes (gboolean              dont_wait,
858                       const gchar          *working_directory,
859                       gchar               **argv,
860                       gchar               **envp,
861                       gboolean              close_descriptors,
862                       gboolean              search_path,
863                       gboolean              stdout_to_null,
864                       gboolean              stderr_to_null,
865                       gboolean              child_inherits_stdin,
866                       GSpawnChildSetupFunc  child_setup,
867                       gpointer              user_data,
868                       gint                 *standard_input,
869                       gint                 *standard_output,
870                       gint                 *standard_error,
871                       gint                 *exit_status,
872                       GError              **error)     
873 {
874   gint stdin_pipe[2] = { -1, -1 };
875   gint stdout_pipe[2] = { -1, -1 };
876   gint stderr_pipe[2] = { -1, -1 };
877   gint child_err_report_pipe[2] = { -1, -1 };
878   gint status;
879   gint bytes;
880   gint buf[2];
881   gint n_ints = 0;
882   
883   if (!make_pipe (child_err_report_pipe, error))
884     return FALSE;
885
886   if (standard_input && !make_pipe (stdin_pipe, error))
887     goto cleanup_and_fail;
888   
889   if (standard_output && !make_pipe (stdout_pipe, error))
890     goto cleanup_and_fail;
891
892   if (standard_error && !make_pipe (stderr_pipe, error))
893     goto cleanup_and_fail;
894
895   status = do_exec (dont_wait,
896                     child_err_report_pipe[1],
897                     stdin_pipe[0],
898                     stdout_pipe[1],
899                     stderr_pipe[1],
900                     working_directory,
901                     argv,
902                     envp,
903                     close_descriptors,
904                     search_path,
905                     stdout_to_null,
906                     stderr_to_null,
907                     child_inherits_stdin,
908                     child_setup,
909                     user_data);
910       
911   if (!read_ints (child_err_report_pipe[0],
912                   buf, 2, &n_ints,
913                   error))
914     goto cleanup_and_fail;
915         
916   if (n_ints == 2)
917     {
918       /* Error from the child. */
919       
920       switch (buf[0])
921         {
922         case CHILD_NO_ERROR:
923           break;
924           
925         case CHILD_CHDIR_FAILED:
926           g_set_error (error,
927                        G_SPAWN_ERROR,
928                        G_SPAWN_ERROR_CHDIR,
929                        _("Failed to change to directory '%s' (%s)"),
930                        working_directory,
931                        g_strerror (buf[1]));
932           goto cleanup_and_fail;
933           
934         case CHILD_SPAWN_FAILED:
935           g_set_error (error,
936                        G_SPAWN_ERROR,
937                        G_SPAWN_ERROR_FAILED,
938                        _("Failed to execute child process (%s)"),
939                        g_strerror (buf[1]));
940           goto cleanup_and_fail;
941         }
942     }
943
944   /* Success against all odds! return the information */
945       
946   if (standard_input)
947     *standard_input = stdin_pipe[1];
948   if (standard_output)
949     *standard_output = stdout_pipe[0];
950   if (standard_error)
951     *standard_error = stderr_pipe[0];
952   if (exit_status)
953     *exit_status = status;
954   
955   return TRUE;
956
957  cleanup_and_fail:
958   close_and_invalidate (&child_err_report_pipe[0]);
959   close_and_invalidate (&child_err_report_pipe[1]);
960   close_and_invalidate (&stdin_pipe[0]);
961   close_and_invalidate (&stdin_pipe[1]);
962   close_and_invalidate (&stdout_pipe[0]);
963   close_and_invalidate (&stdout_pipe[1]);
964   close_and_invalidate (&stderr_pipe[0]);
965   close_and_invalidate (&stderr_pipe[1]);
966
967   return FALSE;
968 }
969
970 static gboolean
971 make_pipe (gint     p[2],
972            GError **error)
973 {
974   if (pipe (p) < 0)
975     {
976       g_set_error (error,
977                    G_SPAWN_ERROR,
978                    G_SPAWN_ERROR_FAILED,
979                    _("Failed to create pipe for communicating with child process (%s)"),
980                    g_strerror (errno));
981       return FALSE;
982     }
983   else
984     return TRUE;
985 }
986
987 #endif /* !GSPAWN_HELPER */