Add g_key_file_load_from_dirs for looking through a search path for a
[platform/upstream/glib.git] / glib / gspawn-win32.c
1 /* gspawn-win32.c - Process launching on Win32
2  *
3  *  Copyright 2000 Red Hat, Inc.
4  *  Copyright 2003 Tor Lillqvist
5  *
6  * GLib is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * GLib is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with GLib; see the file COPYING.LIB.  If not, write
18  * to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /*
23  * Implementation details on Win32.
24  *
25  * - There is no way to set the no-inherit flag for
26  *   a "file descriptor" in the MS C runtime. The flag is there,
27  *   and the dospawn() function uses it, but unfortunately
28  *   this flag can only be set when opening the file.
29  * - As there is no fork(), we cannot reliably change directory
30  *   before starting the child process. (There might be several threads
31  *   running, and the current directory is common for all threads.)
32  *
33  * Thus, we must in most cases use a helper program to handle closing
34  * of (inherited) file descriptors and changing of directory. The
35  * helper process is also needed if the standard input, standard
36  * output, or standard error of the process to be run are supposed to
37  * be redirected somewhere.
38  *
39  * The structure of the source code in this file is a mess, I know.
40  */
41
42 /* Define this to get some logging all the time */
43 /* #define G_SPAWN_WIN32_DEBUG */
44
45 #include "config.h"
46
47 #include "glib.h"
48 #include "gprintfint.h"
49 #include "glibintl.h"
50 #include "galias.h"
51
52 #include <string.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55
56 #include <windows.h>
57 #include <errno.h>
58 #include <fcntl.h>
59 #include <io.h>
60 #include <process.h>
61 #include <direct.h>
62
63 #ifdef __MINGW32__
64 /* Mingw doesn't have prototypes for these */
65 int _wspawnvpe (int, const wchar_t *, const wchar_t **, const wchar_t **);
66 int _wspawnvp (int, const wchar_t *, const wchar_t **);
67 int _wspawnve (int, const wchar_t *, const wchar_t **, const wchar_t **);
68 int _wspawnv (int, const wchar_t *, const wchar_t **);
69 #endif
70
71 #ifdef G_SPAWN_WIN32_DEBUG
72   static int debug = 1;
73   #define SETUP_DEBUG() /* empty */
74 #else
75   static int debug = -1;
76   #define SETUP_DEBUG()                                 \
77     G_STMT_START                                        \
78       {                                                 \
79         if (debug == -1)                                \
80           {                                             \
81             if (getenv ("G_SPAWN_WIN32_DEBUG") != NULL) \
82               debug = 1;                                \
83             else                                        \
84               debug = 0;                                \
85           }                                             \
86       }                                                 \
87     G_STMT_END
88 #endif
89
90 enum
91 {
92   CHILD_NO_ERROR,
93   CHILD_CHDIR_FAILED,
94   CHILD_SPAWN_FAILED,
95 };
96
97 enum {
98   ARG_CHILD_ERR_REPORT = 1,
99   ARG_STDIN,
100   ARG_STDOUT,
101   ARG_STDERR,
102   ARG_WORKING_DIRECTORY,
103   ARG_CLOSE_DESCRIPTORS,
104   ARG_USE_PATH,
105   ARG_WAIT,
106   ARG_PROGRAM,
107   ARG_COUNT = ARG_PROGRAM
108 };
109
110 #ifndef GSPAWN_HELPER
111
112 #define HELPER_PROCESS "gspawn-win32-helper"
113
114 static gchar *
115 protect_argv_string (const gchar *string)
116 {
117   const gchar *p = string;
118   gchar *retval, *q;
119   gint len = 0;
120   gboolean need_dblquotes = FALSE;
121   while (*p)
122     {
123       if (*p == ' ' || *p == '\t')
124         need_dblquotes = TRUE;
125       else if (*p == '"')
126         len++;
127       else if (*p == '\\')
128         {
129           const gchar *pp = p;
130           while (*pp && *pp == '\\')
131             pp++;
132           if (*pp == '"')
133             len++;
134         }
135       len++;
136       p++;
137     }
138   
139   q = retval = g_malloc (len + need_dblquotes*2 + 1);
140   p = string;
141
142   if (need_dblquotes)
143     *q++ = '"';
144   
145   while (*p)
146     {
147       if (*p == '"')
148         *q++ = '\\';
149       else if (*p == '\\')
150         {
151           const gchar *pp = p;
152           while (*pp && *pp == '\\')
153             pp++;
154           if (*pp == '"')
155             *q++ = '\\';
156         }
157       *q++ = *p;
158       p++;
159     }
160   
161   if (need_dblquotes)
162     *q++ = '"';
163   *q++ = '\0';
164
165   return retval;
166 }
167
168 static gint
169 protect_argv (gchar  **argv,
170               gchar ***new_argv)
171 {
172   gint i;
173   gint argc = 0;
174   
175   while (argv[argc])
176     ++argc;
177   *new_argv = g_new (gchar *, argc+1);
178
179   /* Quote each argv element if necessary, so that it will get
180    * reconstructed correctly in the C runtime startup code.  Note that
181    * the unquoting algorithm in the C runtime is really weird, and
182    * rather different than what Unix shells do. See stdargv.c in the C
183    * runtime sources (in the Platform SDK, in src/crt).
184    *
185    * Note that an new_argv[0] constructed by this function should
186    * *not* be passed as the filename argument to a spawn* or exec*
187    * family function. That argument should be the real file name
188    * without any quoting.
189    */
190   for (i = 0; i < argc; i++)
191     (*new_argv)[i] = protect_argv_string (argv[i]);
192
193   (*new_argv)[argc] = NULL;
194
195   return argc;
196 }
197
198 GQuark
199 g_spawn_error_quark (void)
200 {
201   return g_quark_from_static_string ("g-exec-error-quark");
202 }
203
204 gboolean
205 g_spawn_async_utf8 (const gchar          *working_directory,
206                     gchar               **argv,
207                     gchar               **envp,
208                     GSpawnFlags           flags,
209                     GSpawnChildSetupFunc  child_setup,
210                     gpointer              user_data,
211                     GPid                 *child_handle,
212                     GError              **error)
213 {
214   g_return_val_if_fail (argv != NULL, FALSE);
215   
216   return g_spawn_async_with_pipes_utf8 (working_directory,
217                                         argv, envp,
218                                         flags,
219                                         child_setup,
220                                         user_data,
221                                         child_handle,
222                                         NULL, NULL, NULL,
223                                         error);
224 }
225
226 /* Avoids a danger in threaded situations (calling close()
227  * on a file descriptor twice, and another thread has
228  * re-opened it since the first close)
229  */
230 static void
231 close_and_invalidate (gint *fd)
232 {
233   if (*fd < 0)
234     return;
235
236   close (*fd);
237   *fd = -1;
238 }
239
240 typedef enum
241 {
242   READ_FAILED = 0, /* FALSE */
243   READ_OK,
244   READ_EOF
245 } ReadResult;
246
247 static ReadResult
248 read_data (GString     *str,
249            GIOChannel  *iochannel,
250            GError     **error)
251 {
252   GIOStatus giostatus;
253   gssize bytes;
254   gchar buf[4096];
255
256  again:
257   
258   giostatus = g_io_channel_read_chars (iochannel, buf, sizeof (buf), &bytes, NULL);
259
260   if (bytes == 0)
261     return READ_EOF;
262   else if (bytes > 0)
263     {
264       g_string_append_len (str, buf, bytes);
265       return READ_OK;
266     }
267   else if (giostatus == G_IO_STATUS_AGAIN)
268     goto again;
269   else if (giostatus == G_IO_STATUS_ERROR)
270     {
271       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ,
272                    _("Failed to read data from child process"));
273       
274       return READ_FAILED;
275     }
276   else
277     return READ_OK;
278 }
279
280 static gboolean
281 make_pipe (gint     p[2],
282            GError **error)
283 {
284   if (pipe (p) < 0)
285     {
286       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
287                    _("Failed to create pipe for communicating with child process (%s)"),
288                    g_strerror (errno));
289       return FALSE;
290     }
291   else
292     return TRUE;
293 }
294
295 /* The helper process writes a status report back to us, through a
296  * pipe, consisting of two ints.
297  */
298 static gboolean
299 read_helper_report (int      fd,
300                     gint     report[2],
301                     GError **error)
302 {
303   gint bytes = 0;
304   
305   while (bytes < sizeof(gint)*2)
306     {
307       gint chunk;
308
309       if (debug)
310         g_print ("%s:read_helper_report: read %d...\n",
311                  __FILE__,
312                  sizeof(gint)*2 - bytes);
313
314       chunk = read (fd, ((gchar*)report) + bytes,
315                     sizeof(gint)*2 - bytes);
316
317       if (debug)
318         g_print ("...got %d bytes\n", chunk);
319           
320       if (chunk < 0)
321         {
322           /* Some weird shit happened, bail out */
323               
324           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
325                        _("Failed to read from child pipe (%s)"),
326                        g_strerror (errno));
327
328           return FALSE;
329         }
330       else if (chunk == 0)
331         break; /* EOF */
332       else
333         bytes += chunk;
334     }
335
336   if (bytes < sizeof(gint)*2)
337     return FALSE;
338
339   return TRUE;
340 }
341
342 static void
343 set_child_error (gint         report[2],
344                  const gchar *working_directory,
345                  GError     **error)
346 {
347   switch (report[0])
348     {
349     case CHILD_CHDIR_FAILED:
350       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
351                    _("Failed to change to directory '%s' (%s)"),
352                    working_directory,
353                    g_strerror (report[1]));
354       break;
355     case CHILD_SPAWN_FAILED:
356       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
357                    _("Failed to execute child process (%s)"),
358                    g_strerror (report[1]));
359       break;
360     default:
361       g_assert_not_reached ();
362     }
363 }
364
365 static gboolean
366 utf8_charv_to_wcharv (char     **utf8_charv,
367                       wchar_t ***wcharv,
368                       int       *error_index,
369                       GError   **error)
370 {
371   wchar_t **retval = NULL;
372
373   *wcharv = NULL;
374   if (utf8_charv != NULL)
375     {
376       int n = 0, i;
377
378       while (utf8_charv[n])
379         n++;
380       retval = g_new (wchar_t *, n + 1);
381
382       for (i = 0; i < n; i++)
383         {
384           retval[i] = g_utf8_to_utf16 (utf8_charv[i], -1, NULL, NULL, error);
385           if (retval[i] == NULL)
386             {
387               if (error_index)
388                 *error_index = i;
389               while (i)
390                 g_free (retval[--i]);
391               g_free (retval);
392               return FALSE;
393             }
394         }
395             
396       retval[n] = NULL;
397     }
398   *wcharv = retval;
399   return TRUE;
400 }
401
402 static gboolean
403 do_spawn_directly (gint                 *exit_status,
404                    gboolean              do_return_handle,
405                    GSpawnFlags           flags,
406                    gchar               **argv,
407                    char                **envp,
408                    char                **protected_argv,
409                    GSpawnChildSetupFunc  child_setup,
410                    gpointer              user_data,
411                    GPid                 *child_handle,
412                    GError              **error)     
413 {
414   const int mode = (exit_status == NULL) ? P_NOWAIT : P_WAIT;
415   char **new_argv;
416   int rc = -1;
417   int saved_errno;
418   GError *conv_error = NULL;
419   gint conv_error_index;
420   wchar_t *wargv0, **wargv, **wenvp;
421
422   new_argv = (flags & G_SPAWN_FILE_AND_ARGV_ZERO) ? protected_argv + 1 : protected_argv;
423       
424   wargv0 = g_utf8_to_utf16 (argv[0], -1, NULL, NULL, &conv_error);
425   if (wargv0 == NULL)
426     {
427       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
428                    _("Invalid program name: %s"),
429                    conv_error->message);
430       g_error_free (conv_error);
431       
432       return FALSE;
433     }
434   
435   if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error))
436     {
437       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
438                    _("Invalid string in argument vector at %d: %s"),
439                    conv_error_index, conv_error->message);
440       g_error_free (conv_error);
441       g_free (wargv0);
442
443       return FALSE;
444     }
445
446   if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error))
447     {
448       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
449                    _("Invalid string in environment: %s"),
450                    conv_error->message);
451       g_error_free (conv_error);
452       g_free (wargv0);
453       g_strfreev ((gchar **) wargv);
454
455       return FALSE;
456     }
457
458   if (child_setup)
459     (* child_setup) (user_data);
460
461   if (flags & G_SPAWN_SEARCH_PATH)
462     if (wenvp != NULL)
463       rc = _wspawnvpe (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp);
464     else
465       rc = _wspawnvp (mode, wargv0, (const wchar_t **) wargv);
466   else
467     if (wenvp != NULL)
468       rc = _wspawnve (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp);
469     else
470       rc = _wspawnv (mode, wargv0, (const wchar_t **) wargv);
471
472   g_free (wargv0);
473   g_strfreev ((gchar **) wargv);
474   g_strfreev ((gchar **) wenvp);
475
476   saved_errno = errno;
477
478   if (rc == -1 && saved_errno != 0)
479     {
480       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
481                    _("Failed to execute child process (%s)"),
482                    g_strerror (saved_errno));
483       return FALSE;
484     }
485
486   if (exit_status == NULL)
487     {
488       if (child_handle && do_return_handle)
489         *child_handle = (GPid) rc;
490       else
491         {
492           CloseHandle ((HANDLE) rc);
493           if (child_handle)
494             *child_handle = 0;
495         }
496     }
497   else
498     *exit_status = rc;
499
500   return TRUE;
501 }
502
503 static gboolean
504 do_spawn_with_pipes (gint                 *exit_status,
505                      gboolean              do_return_handle,
506                      const gchar          *working_directory,
507                      gchar               **argv,
508                      char                **envp,
509                      GSpawnFlags           flags,
510                      GSpawnChildSetupFunc  child_setup,
511                      gpointer              user_data,
512                      GPid                 *child_handle,
513                      gint                 *standard_input,
514                      gint                 *standard_output,
515                      gint                 *standard_error,
516                      gint                 *err_report,
517                      GError              **error)     
518 {
519   char **protected_argv;
520   char args[ARG_COUNT][10];
521   char **new_argv;
522   int i;
523   int rc = -1;
524   int saved_errno;
525   int argc;
526   int stdin_pipe[2] = { -1, -1 };
527   int stdout_pipe[2] = { -1, -1 };
528   int stderr_pipe[2] = { -1, -1 };
529   int child_err_report_pipe[2] = { -1, -1 };
530   int helper_report[2];
531   static gboolean warned_about_child_setup = FALSE;
532   GError *conv_error = NULL;
533   gint conv_error_index;
534   gchar *helper_process;
535   CONSOLE_CURSOR_INFO cursor_info;
536   wchar_t *whelper, **wargv, **wenvp;
537   
538   SETUP_DEBUG();
539
540   if (child_setup && !warned_about_child_setup)
541     {
542       warned_about_child_setup = TRUE;
543       g_warning ("passing a child setup function to the g_spawn functions is pointless and dangerous on Win32");
544     }
545
546   argc = protect_argv (argv, &protected_argv);
547
548   if (!standard_input && !standard_output && !standard_error &&
549       (flags & G_SPAWN_CHILD_INHERITS_STDIN) &&
550       !(flags & G_SPAWN_STDOUT_TO_DEV_NULL) &&
551       !(flags & G_SPAWN_STDERR_TO_DEV_NULL) &&
552       (working_directory == NULL || !*working_directory) &&
553       (flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN))
554     {
555       /* We can do without the helper process */
556       gboolean retval =
557         do_spawn_directly (exit_status, do_return_handle, flags,
558                            argv, envp, protected_argv,
559                            child_setup, user_data, child_handle,
560                            error);
561       g_strfreev (protected_argv);
562       return retval;
563     }
564
565   if (standard_input && !make_pipe (stdin_pipe, error))
566     goto cleanup_and_fail;
567   
568   if (standard_output && !make_pipe (stdout_pipe, error))
569     goto cleanup_and_fail;
570   
571   if (standard_error && !make_pipe (stderr_pipe, error))
572     goto cleanup_and_fail;
573   
574   if (!make_pipe (child_err_report_pipe, error))
575     goto cleanup_and_fail;
576   
577   new_argv = g_new (char *, argc + 1 + ARG_COUNT);
578   if (GetConsoleCursorInfo (GetStdHandle (STD_OUTPUT_HANDLE), &cursor_info))
579     helper_process = HELPER_PROCESS "-console.exe";
580   else
581     helper_process = HELPER_PROCESS ".exe";
582   new_argv[0] = helper_process;
583   _g_sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_pipe[1]);
584   new_argv[ARG_CHILD_ERR_REPORT] = args[ARG_CHILD_ERR_REPORT];
585   
586   if (flags & G_SPAWN_FILE_AND_ARGV_ZERO)
587     {
588       /* Overload ARG_CHILD_ERR_REPORT to also encode the
589        * G_SPAWN_FILE_AND_ARGV_ZERO functionality.
590        */
591       strcat (args[ARG_CHILD_ERR_REPORT], "#");
592     }
593   
594   if (standard_input)
595     {
596       _g_sprintf (args[ARG_STDIN], "%d", stdin_pipe[0]);
597       new_argv[ARG_STDIN] = args[ARG_STDIN];
598     }
599   else if (flags & G_SPAWN_CHILD_INHERITS_STDIN)
600     {
601       /* Let stdin be alone */
602       new_argv[ARG_STDIN] = "-";
603     }
604   else
605     {
606       /* Keep process from blocking on a read of stdin */
607       new_argv[ARG_STDIN] = "z";
608     }
609   
610   if (standard_output)
611     {
612       _g_sprintf (args[ARG_STDOUT], "%d", stdout_pipe[1]);
613       new_argv[ARG_STDOUT] = args[ARG_STDOUT];
614     }
615   else if (flags & G_SPAWN_STDOUT_TO_DEV_NULL)
616     {
617       new_argv[ARG_STDOUT] = "z";
618     }
619   else
620     {
621       new_argv[ARG_STDOUT] = "-";
622     }
623   
624   if (standard_error)
625     {
626       _g_sprintf (args[ARG_STDERR], "%d", stderr_pipe[1]);
627       new_argv[ARG_STDERR] = args[ARG_STDERR];
628     }
629   else if (flags & G_SPAWN_STDERR_TO_DEV_NULL)
630     {
631       new_argv[ARG_STDERR] = "z";
632     }
633   else
634     {
635       new_argv[ARG_STDERR] = "-";
636     }
637   
638   if (working_directory && *working_directory)
639     new_argv[ARG_WORKING_DIRECTORY] = protect_argv_string (working_directory);
640   else
641     new_argv[ARG_WORKING_DIRECTORY] = g_strdup ("-");
642   
643   if (!(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN))
644     new_argv[ARG_CLOSE_DESCRIPTORS] = "y";
645   else
646     new_argv[ARG_CLOSE_DESCRIPTORS] = "-";
647
648   if (flags & G_SPAWN_SEARCH_PATH)
649     new_argv[ARG_USE_PATH] = "y";
650   else
651     new_argv[ARG_USE_PATH] = "-";
652
653   if (exit_status == NULL)
654     new_argv[ARG_WAIT] = "-";
655   else
656     new_argv[ARG_WAIT] = "w";
657
658   for (i = 0; i <= argc; i++)
659     new_argv[ARG_PROGRAM + i] = protected_argv[i];
660
661   if (debug)
662     {
663       g_print ("calling %s with argv:\n", helper_process);
664       for (i = 0; i < argc + 1 + ARG_COUNT; i++)
665         g_print ("argv[%d]: %s\n", i, (new_argv[i] ? new_argv[i] : "NULL"));
666     }
667
668   whelper = g_utf8_to_utf16 (helper_process, -1, NULL, NULL, NULL);
669
670   if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error))
671     {
672       if (conv_error_index == ARG_WORKING_DIRECTORY)
673         g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
674                      _("Invalid working directory: %s"),
675                      conv_error->message);
676       else
677         g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
678                      _("Invalid string in argument vector at %d: %s"),
679                      conv_error_index - ARG_PROGRAM, conv_error->message);
680       g_error_free (conv_error);
681       g_strfreev (protected_argv);
682       g_free (new_argv[ARG_WORKING_DIRECTORY]);
683       g_free (new_argv);
684       g_free (whelper);
685
686       return FALSE;
687     }
688
689   if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error))
690     {
691       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
692                    _("Invalid string in environment: %s"),
693                    conv_error->message);
694       g_error_free (conv_error);
695       g_strfreev (protected_argv);
696       g_free (new_argv[ARG_WORKING_DIRECTORY]);
697       g_free (new_argv);
698       g_free (whelper);
699       g_strfreev ((gchar **) wargv);
700  
701       return FALSE;
702     }
703
704   if (child_setup)
705     (* child_setup) (user_data);
706
707   if (wenvp != NULL)
708     /* Let's hope envp hasn't mucked with PATH so that
709      * gspawn-win32-helper.exe isn't found.
710      */
711     rc = _wspawnvpe (P_NOWAIT, whelper, (const wchar_t **) wargv, (const wchar_t **) wenvp);
712   else
713     rc = _wspawnvp (P_NOWAIT, whelper, (const wchar_t **) wargv);
714
715   saved_errno = errno;
716
717   g_free (whelper);
718   g_strfreev ((gchar **) wargv);
719   g_strfreev ((gchar **) wenvp);
720
721   /* Close the other process's ends of the pipes in this process,
722    * otherwise the reader will never get EOF.
723    */
724   close_and_invalidate (&child_err_report_pipe[1]);
725   close_and_invalidate (&stdin_pipe[0]);
726   close_and_invalidate (&stdout_pipe[1]);
727   close_and_invalidate (&stderr_pipe[1]);
728
729   g_strfreev (protected_argv);
730
731   g_free (new_argv[ARG_WORKING_DIRECTORY]);
732   g_free (new_argv);
733
734   /* Check if gspawn-win32-helper couldn't be run */
735   if (rc == -1 && saved_errno != 0)
736     {
737       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
738                    _("Failed to execute helper program (%s)"),
739                    g_strerror (saved_errno));
740       goto cleanup_and_fail;
741     }
742
743   if (exit_status != NULL)
744     {
745       /* Synchronous case. Pass helper's report pipe back to caller,
746        * which takes care of reading it after the grandchild has
747        * finished.
748        */
749       g_assert (err_report != NULL);
750       *err_report = child_err_report_pipe[0];
751     }
752   else
753     {
754       /* Asynchronous case. We read the helper's report right away. */
755       if (!read_helper_report (child_err_report_pipe[0], helper_report, error))
756         goto cleanup_and_fail;
757         
758       close (child_err_report_pipe[0]);
759
760       switch (helper_report[0])
761         {
762         case CHILD_NO_ERROR:
763           if (child_handle && do_return_handle)
764             {
765               /* rc is our HANDLE for gspawn-win32-helper. It has
766                * told us the HANDLE of its child. Duplicate that into
767                * a HANDLE valid in this process.
768                */
769               if (!DuplicateHandle ((HANDLE) rc, (HANDLE) helper_report[1],
770                                     GetCurrentProcess (), (LPHANDLE) child_handle,
771                                     0, TRUE, DUPLICATE_SAME_ACCESS))
772                 *child_handle = 0;
773             }
774           else if (child_handle)
775             *child_handle = 0;
776           break;
777           
778         default:
779           set_child_error (helper_report, working_directory, error);
780           goto cleanup_and_fail;
781         }
782     }
783
784   /* Success against all odds! return the information */
785       
786   if (standard_input)
787     *standard_input = stdin_pipe[1];
788   if (standard_output)
789     *standard_output = stdout_pipe[0];
790   if (standard_error)
791     *standard_error = stderr_pipe[0];
792   if (rc != -1)
793     CloseHandle ((HANDLE) rc);
794   
795   return TRUE;
796
797  cleanup_and_fail:
798   if (rc != -1)
799     CloseHandle ((HANDLE) rc);
800   if (child_err_report_pipe[0] != -1)
801     close (child_err_report_pipe[0]);
802   if (child_err_report_pipe[1] != -1)
803     close (child_err_report_pipe[1]);
804   if (stdin_pipe[0] != -1)
805     close (stdin_pipe[0]);
806   if (stdin_pipe[1] != -1)
807     close (stdin_pipe[1]);
808   if (stdout_pipe[0] != -1)
809     close (stdout_pipe[0]);
810   if (stdout_pipe[1] != -1)
811     close (stdout_pipe[1]);
812   if (stderr_pipe[0] != -1)
813     close (stderr_pipe[0]);
814   if (stderr_pipe[1] != -1)
815     close (stderr_pipe[1]);
816
817   return FALSE;
818 }
819
820 gboolean
821 g_spawn_sync_utf8 (const gchar          *working_directory,
822                    gchar               **argv,
823                    gchar               **envp,
824                    GSpawnFlags           flags,
825                    GSpawnChildSetupFunc  child_setup,
826                    gpointer              user_data,
827                    gchar               **standard_output,
828                    gchar               **standard_error,
829                    gint                 *exit_status,
830                    GError              **error)     
831 {
832   gint outpipe = -1;
833   gint errpipe = -1;
834   gint reportpipe = -1;
835   GIOChannel *outchannel = NULL;
836   GIOChannel *errchannel = NULL;
837   GPollFD outfd, errfd;
838   GPollFD fds[2];
839   gint nfds;
840   gint outindex = -1;
841   gint errindex = -1;
842   gint ret;
843   GString *outstr = NULL;
844   GString *errstr = NULL;
845   gboolean failed;
846   gint status;
847   
848   g_return_val_if_fail (argv != NULL, FALSE);
849   g_return_val_if_fail (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), FALSE);
850   g_return_val_if_fail (standard_output == NULL ||
851                         !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
852   g_return_val_if_fail (standard_error == NULL ||
853                         !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
854   
855   /* Just to ensure segfaults if callers try to use
856    * these when an error is reported.
857    */
858   if (standard_output)
859     *standard_output = NULL;
860
861   if (standard_error)
862     *standard_error = NULL;
863   
864   if (!do_spawn_with_pipes (&status,
865                             FALSE,
866                             working_directory,
867                             argv,
868                             envp,
869                             flags,
870                             child_setup,
871                             user_data,
872                             NULL,
873                             NULL,
874                             standard_output ? &outpipe : NULL,
875                             standard_error ? &errpipe : NULL,
876                             &reportpipe,
877                             error))
878     return FALSE;
879
880   /* Read data from child. */
881   
882   failed = FALSE;
883
884   if (outpipe >= 0)
885     {
886       outstr = g_string_new (NULL);
887       outchannel = g_io_channel_win32_new_fd (outpipe);
888       g_io_channel_set_encoding (outchannel, NULL, NULL);
889       g_io_channel_set_buffered (outchannel, FALSE);
890       g_io_channel_win32_make_pollfd (outchannel,
891                                       G_IO_IN | G_IO_ERR | G_IO_HUP,
892                                       &outfd);
893       if (debug)
894         g_print ("outfd=%x\n", outfd.fd);
895     }
896       
897   if (errpipe >= 0)
898     {
899       errstr = g_string_new (NULL);
900       errchannel = g_io_channel_win32_new_fd (errpipe);
901       g_io_channel_set_encoding (errchannel, NULL, NULL);
902       g_io_channel_set_buffered (errchannel, FALSE);
903       g_io_channel_win32_make_pollfd (errchannel,
904                                       G_IO_IN | G_IO_ERR | G_IO_HUP,
905                                       &errfd);
906       if (debug)
907         g_print ("errfd=%x\n", errfd.fd);
908     }
909
910   /* Read data until we get EOF on all pipes. */
911   while (!failed && (outpipe >= 0 || errpipe >= 0))
912     {
913       nfds = 0;
914       if (outpipe >= 0)
915         {
916           fds[nfds] = outfd;
917           outindex = nfds;
918           nfds++;
919         }
920       if (errpipe >= 0)
921         {
922           fds[nfds] = errfd;
923           errindex = nfds;
924           nfds++;
925         }
926
927       if (debug)
928         g_print ("g_spawn_sync: calling g_io_channel_win32_poll, nfds=%d\n",
929                  nfds);
930
931       ret = g_io_channel_win32_poll (fds, nfds, -1);
932
933       if (ret < 0)
934         {
935           failed = TRUE;
936
937           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ,
938                        _("Unexpected error in g_io_channel_win32_poll() reading data from a child process"));
939           
940           break;
941         }
942
943       if (outpipe >= 0 && (fds[outindex].revents & G_IO_IN))
944         {
945           switch (read_data (outstr, outchannel, error))
946             {
947             case READ_FAILED:
948               if (debug)
949                 g_print ("g_spawn_sync: outchannel: READ_FAILED\n");
950               failed = TRUE;
951               break;
952             case READ_EOF:
953               if (debug)
954                 g_print ("g_spawn_sync: outchannel: READ_EOF\n");
955               g_io_channel_unref (outchannel);
956               outchannel = NULL;
957               close_and_invalidate (&outpipe);
958               break;
959             default:
960               if (debug)
961                 g_print ("g_spawn_sync: outchannel: OK\n");
962               break;
963             }
964
965           if (failed)
966             break;
967         }
968
969       if (errpipe >= 0 && (fds[errindex].revents & G_IO_IN))
970         {
971           switch (read_data (errstr, errchannel, error))
972             {
973             case READ_FAILED:
974               if (debug)
975                 g_print ("g_spawn_sync: errchannel: READ_FAILED\n");
976               failed = TRUE;
977               break;
978             case READ_EOF:
979               if (debug)
980                 g_print ("g_spawn_sync: errchannel: READ_EOF\n");
981               g_io_channel_unref (errchannel);
982               errchannel = NULL;
983               close_and_invalidate (&errpipe);
984               break;
985             default:
986               if (debug)
987                 g_print ("g_spawn_sync: errchannel: OK\n");
988               break;
989             }
990
991           if (failed)
992             break;
993         }
994     }
995
996   if (reportpipe == -1)
997     {
998       /* No helper process, exit status of actual spawned process
999        * already available.
1000        */
1001       if (exit_status)
1002         *exit_status = status;
1003     }
1004   else
1005     {
1006       /* Helper process was involved. Read its report now after the
1007        * grandchild has finished.
1008        */
1009       gint helper_report[2];
1010
1011       if (!read_helper_report (reportpipe, helper_report, error))
1012         failed = TRUE;
1013       else
1014         {
1015           switch (helper_report[0])
1016             {
1017             case CHILD_NO_ERROR:
1018               if (exit_status)
1019                 *exit_status = helper_report[1];
1020               break;
1021             default:
1022               set_child_error (helper_report, working_directory, error);
1023               failed = TRUE;
1024               break;
1025             }
1026         }
1027       close_and_invalidate (&reportpipe);
1028     }
1029
1030
1031   /* These should only be open still if we had an error.  */
1032   
1033   if (outchannel != NULL)
1034     g_io_channel_unref (outchannel);
1035   if (errchannel != NULL)
1036     g_io_channel_unref (errchannel);
1037   if (outpipe >= 0)
1038     close_and_invalidate (&outpipe);
1039   if (errpipe >= 0)
1040     close_and_invalidate (&errpipe);
1041   
1042   if (failed)
1043     {
1044       if (outstr)
1045         g_string_free (outstr, TRUE);
1046       if (errstr)
1047         g_string_free (errstr, TRUE);
1048
1049       return FALSE;
1050     }
1051   else
1052     {
1053       if (standard_output)        
1054         *standard_output = g_string_free (outstr, FALSE);
1055
1056       if (standard_error)
1057         *standard_error = g_string_free (errstr, FALSE);
1058
1059       return TRUE;
1060     }
1061 }
1062
1063 gboolean
1064 g_spawn_async_with_pipes_utf8 (const gchar          *working_directory,
1065                                gchar               **argv,
1066                                gchar               **envp,
1067                                GSpawnFlags           flags,
1068                                GSpawnChildSetupFunc  child_setup,
1069                                gpointer              user_data,
1070                                GPid                 *child_handle,
1071                                gint                 *standard_input,
1072                                gint                 *standard_output,
1073                                gint                 *standard_error,
1074                                GError              **error)
1075 {
1076   g_return_val_if_fail (argv != NULL, FALSE);
1077   g_return_val_if_fail (standard_output == NULL ||
1078                         !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
1079   g_return_val_if_fail (standard_error == NULL ||
1080                         !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
1081   /* can't inherit stdin if we have an input pipe. */
1082   g_return_val_if_fail (standard_input == NULL ||
1083                         !(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE);
1084   
1085   return do_spawn_with_pipes (NULL,
1086                               (flags & G_SPAWN_DO_NOT_REAP_CHILD),
1087                               working_directory,
1088                               argv,
1089                               envp,
1090                               flags,
1091                               child_setup,
1092                               user_data,
1093                               child_handle,
1094                               standard_input,
1095                               standard_output,
1096                               standard_error,
1097                               NULL,
1098                               error);
1099 }
1100
1101 gboolean
1102 g_spawn_command_line_sync_utf8 (const gchar  *command_line,
1103                                 gchar       **standard_output,
1104                                 gchar       **standard_error,
1105                                 gint         *exit_status,
1106                                 GError      **error)
1107 {
1108   gboolean retval;
1109   gchar **argv = 0;
1110
1111   g_return_val_if_fail (command_line != NULL, FALSE);
1112   
1113   if (!g_shell_parse_argv (command_line,
1114                            NULL, &argv,
1115                            error))
1116     return FALSE;
1117   
1118   retval = g_spawn_sync_utf8 (NULL,
1119                               argv,
1120                               NULL,
1121                               G_SPAWN_SEARCH_PATH,
1122                               NULL,
1123                               NULL,
1124                               standard_output,
1125                               standard_error,
1126                               exit_status,
1127                               error);
1128   g_strfreev (argv);
1129
1130   return retval;
1131 }
1132
1133 gboolean
1134 g_spawn_command_line_async_utf8 (const gchar *command_line,
1135                                  GError     **error)
1136 {
1137   gboolean retval;
1138   gchar **argv = 0;
1139
1140   g_return_val_if_fail (command_line != NULL, FALSE);
1141
1142   if (!g_shell_parse_argv (command_line,
1143                            NULL, &argv,
1144                            error))
1145     return FALSE;
1146   
1147   retval = g_spawn_async_utf8 (NULL,
1148                                argv,
1149                                NULL,
1150                                G_SPAWN_SEARCH_PATH,
1151                                NULL,
1152                                NULL,
1153                                NULL,
1154                                error);
1155   g_strfreev (argv);
1156
1157   return retval;
1158 }
1159
1160 void
1161 g_spawn_close_pid (GPid pid)
1162 {
1163     CloseHandle (pid);
1164 }
1165
1166 /* Binary compatibility versions that take system codepage pathnames,
1167  * argument vectors and environments. These get used only by code
1168  * built against 2.8.1 or earlier. Code built against 2.8.2 or later
1169  * will use the _utf8 versions above (see the #defines in gspawn.h).
1170  */
1171
1172 #undef g_spawn_async
1173 #undef g_spawn_async_with_pipes
1174 #undef g_spawn_sync
1175 #undef g_spawn_command_line_sync
1176 #undef g_spawn_command_line_async
1177
1178 static gboolean
1179 setup_utf8_copies (const gchar *working_directory,
1180                    gchar      **utf8_working_directory,
1181                    gchar      **argv,
1182                    gchar     ***utf8_argv,
1183                    gchar      **envp,
1184                    gchar     ***utf8_envp,
1185                    GError     **error)
1186 {
1187   gint i, argc, envc;
1188
1189   if (working_directory == NULL)
1190     *utf8_working_directory = NULL;
1191   else
1192     {
1193       GError *conv_error = NULL;
1194       
1195       *utf8_working_directory = g_locale_to_utf8 (working_directory, -1, NULL, NULL, &conv_error);
1196       if (*utf8_working_directory == NULL)
1197         {
1198           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
1199                        _("Invalid working directory: %s"),
1200                        conv_error->message);
1201           g_error_free (conv_error);
1202           return FALSE;
1203         }
1204     }
1205
1206   argc = 0;
1207   while (argv[argc])
1208     ++argc;
1209   *utf8_argv = g_new (gchar *, argc + 1);
1210   for (i = 0; i < argc; i++)
1211     {
1212       GError *conv_error = NULL;
1213
1214       (*utf8_argv)[i] = g_locale_to_utf8 (argv[i], -1, NULL, NULL, &conv_error);
1215       if ((*utf8_argv)[i] == NULL)
1216         {
1217           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
1218                        _("Invalid string in argument vector at %d: %s"),
1219                        i, conv_error->message);
1220           g_error_free (conv_error);
1221           
1222           g_strfreev (*utf8_argv);
1223           *utf8_argv = NULL;
1224
1225           g_free (*utf8_working_directory);
1226           *utf8_working_directory = NULL;
1227
1228           return FALSE;
1229         }
1230     }
1231   (*utf8_argv)[argc] = NULL;
1232
1233   if (envp == NULL)
1234     {
1235       *utf8_envp = NULL;
1236     }
1237   else
1238     {
1239       envc = 0;
1240       while (envp[envc])
1241         ++envc;
1242       *utf8_envp = g_new (gchar *, envc + 1);
1243       for (i = 0; i < envc; i++)
1244         {
1245           GError *conv_error = NULL;
1246
1247           (*utf8_envp)[i] = g_locale_to_utf8 (envp[i], -1, NULL, NULL, &conv_error);
1248           if ((*utf8_envp)[i] == NULL)
1249             {   
1250               g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
1251                            _("Invalid string in environment: %s"),
1252                            conv_error->message);
1253               g_error_free (conv_error);
1254
1255               g_strfreev (*utf8_envp);
1256               *utf8_envp = NULL;
1257
1258               g_strfreev (*utf8_argv);
1259               *utf8_argv = NULL;
1260
1261               g_free (*utf8_working_directory);
1262               *utf8_working_directory = NULL;
1263
1264               return FALSE;
1265             }
1266         }
1267       (*utf8_envp)[envc] = NULL;
1268     }
1269   return TRUE;
1270 }
1271
1272 static void
1273 free_utf8_copies (gchar  *utf8_working_directory,
1274                   gchar **utf8_argv,
1275                   gchar **utf8_envp)
1276 {
1277   g_free (utf8_working_directory);
1278   g_strfreev (utf8_argv);
1279   g_strfreev (utf8_envp);
1280 }
1281
1282 gboolean
1283 g_spawn_async_with_pipes (const gchar          *working_directory,
1284                           gchar               **argv,
1285                           gchar               **envp,
1286                           GSpawnFlags           flags,
1287                           GSpawnChildSetupFunc  child_setup,
1288                           gpointer              user_data,
1289                           GPid                 *child_handle,
1290                           gint                 *standard_input,
1291                           gint                 *standard_output,
1292                           gint                 *standard_error,
1293                           GError              **error)
1294 {
1295   gchar *utf8_working_directory;
1296   gchar **utf8_argv;
1297   gchar **utf8_envp;
1298   gboolean retval;
1299
1300   if (!setup_utf8_copies (working_directory, &utf8_working_directory,
1301                           argv, &utf8_argv,
1302                           envp, &utf8_envp,
1303                           error))
1304     return FALSE;
1305
1306   retval = g_spawn_async_with_pipes_utf8 (utf8_working_directory,
1307                                           utf8_argv, utf8_envp,
1308                                           flags, child_setup, user_data,
1309                                           child_handle,
1310                                           standard_input, standard_output, standard_error,
1311                                           error);
1312
1313   free_utf8_copies (utf8_working_directory, utf8_argv, utf8_envp);
1314
1315   return retval;
1316 }
1317
1318 gboolean
1319 g_spawn_async (const gchar          *working_directory,
1320                gchar               **argv,
1321                gchar               **envp,
1322                GSpawnFlags           flags,
1323                GSpawnChildSetupFunc  child_setup,
1324                gpointer              user_data,
1325                GPid                 *child_handle,
1326                GError              **error)
1327 {
1328   return g_spawn_async_with_pipes (working_directory,
1329                                    argv, envp,
1330                                    flags,
1331                                    child_setup,
1332                                    user_data,
1333                                    child_handle,
1334                                    NULL, NULL, NULL,
1335                                    error);
1336 }
1337
1338 gboolean
1339 g_spawn_sync (const gchar          *working_directory,
1340               gchar               **argv,
1341               gchar               **envp,
1342               GSpawnFlags           flags,
1343               GSpawnChildSetupFunc  child_setup,
1344               gpointer              user_data,
1345               gchar               **standard_output,
1346               gchar               **standard_error,
1347               gint                 *exit_status,
1348               GError              **error)     
1349 {
1350   gchar *utf8_working_directory;
1351   gchar **utf8_argv;
1352   gchar **utf8_envp;
1353   gboolean retval;
1354
1355   if (!setup_utf8_copies (working_directory, &utf8_working_directory,
1356                           argv, &utf8_argv,
1357                           envp, &utf8_envp,
1358                           error))
1359     return FALSE;
1360
1361   retval = g_spawn_sync_utf8 (utf8_working_directory,
1362                               utf8_argv, utf8_envp,
1363                               flags, child_setup, user_data,
1364                               standard_output, standard_error, exit_status,
1365                               error);
1366
1367   free_utf8_copies (utf8_working_directory, utf8_argv, utf8_envp);
1368
1369   return retval;
1370 }
1371
1372 gboolean
1373 g_spawn_command_line_sync (const gchar  *command_line,
1374                            gchar       **standard_output,
1375                            gchar       **standard_error,
1376                            gint         *exit_status,
1377                            GError      **error)
1378 {
1379   gboolean retval;
1380   gchar **argv = 0;
1381
1382   g_return_val_if_fail (command_line != NULL, FALSE);
1383   
1384   if (!g_shell_parse_argv (command_line,
1385                            NULL, &argv,
1386                            error))
1387     return FALSE;
1388   
1389   retval = g_spawn_sync (NULL,
1390                          argv,
1391                          NULL,
1392                          G_SPAWN_SEARCH_PATH,
1393                          NULL,
1394                          NULL,
1395                          standard_output,
1396                          standard_error,
1397                          exit_status,
1398                          error);
1399   g_strfreev (argv);
1400
1401   return retval;
1402 }
1403
1404 gboolean
1405 g_spawn_command_line_async (const gchar *command_line,
1406                             GError     **error)
1407 {
1408   gboolean retval;
1409   gchar **argv = 0;
1410
1411   g_return_val_if_fail (command_line != NULL, FALSE);
1412
1413   if (!g_shell_parse_argv (command_line,
1414                            NULL, &argv,
1415                            error))
1416     return FALSE;
1417   
1418   retval = g_spawn_async (NULL,
1419                           argv,
1420                           NULL,
1421                           G_SPAWN_SEARCH_PATH,
1422                           NULL,
1423                           NULL,
1424                           NULL,
1425                           error);
1426   g_strfreev (argv);
1427
1428   return retval;
1429 }
1430
1431 #endif /* !GSPAWN_HELPER */
1432
1433 #define __G_SPAWN_C__
1434 #include "galiasdef.c"