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