Add a note about casting the results of g_new() and g_new0().
[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 (gint                 *exit_status,
445                    gboolean              do_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                    GError              **error)     
454 {
455   const int mode = (exit_status == NULL) ? P_NOWAIT : P_WAIT;
456   char **new_argv;
457   int rc = -1;
458   int saved_errno;
459   GError *conv_error = NULL;
460   gint conv_error_index;
461
462   new_argv = (flags & G_SPAWN_FILE_AND_ARGV_ZERO) ? protected_argv + 1 : protected_argv;
463   if (G_WIN32_HAVE_WIDECHAR_API ())
464     {
465       wchar_t *wargv0, **wargv, **wenvp;
466       
467       wargv0 = g_utf8_to_utf16 (argv[0], -1, NULL, NULL, &conv_error);
468       if (wargv0 == NULL)
469         {
470           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
471                        _("Invalid program name: %s"),
472                        conv_error->message);
473           g_error_free (conv_error);
474           
475           return FALSE;
476         }
477       
478       if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error))
479         {
480           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
481                        _("Invalid string in argument vector at %d: %s"),
482                        conv_error_index, conv_error->message);
483           g_error_free (conv_error);
484           g_free (wargv0);
485           
486           return FALSE;
487         }
488       
489       if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error))
490         {
491           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
492                        _("Invalid string in environment: %s"),
493                        conv_error->message);
494           g_error_free (conv_error);
495           g_free (wargv0);
496           g_strfreev ((gchar **) wargv);
497           
498           return FALSE;
499         }
500       
501       if (child_setup)
502         (* child_setup) (user_data);
503       
504       if (flags & G_SPAWN_SEARCH_PATH)
505         if (wenvp != NULL)
506           rc = _wspawnvpe (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp);
507         else
508           rc = _wspawnvp (mode, wargv0, (const wchar_t **) wargv);
509       else
510         if (wenvp != NULL)
511           rc = _wspawnve (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp);
512         else
513           rc = _wspawnv (mode, wargv0, (const wchar_t **) wargv);
514       
515       g_free (wargv0);
516       g_strfreev ((gchar **) wargv);
517       g_strfreev ((gchar **) wenvp);
518     }
519   else
520     {
521       char *cpargv0, **cpargv, **cpenvp;
522       
523       cpargv0 = g_locale_from_utf8 (argv[0], -1, NULL, NULL, &conv_error);
524       if (cpargv0 == NULL)
525         {
526           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
527                        _("Invalid program name: %s"),
528                        conv_error->message);
529           g_error_free (conv_error);
530
531           return FALSE;
532         }
533
534       if  (!utf8_charv_to_cp_charv (new_argv, &cpargv, &conv_error_index, &conv_error))
535         {
536           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
537                        _("Invalid string in argument vector at %d: %s"),
538                        conv_error_index, conv_error->message);
539           g_error_free (conv_error);
540           g_free (cpargv0);
541
542           return FALSE;
543         }
544
545       if (!utf8_charv_to_cp_charv (envp, &cpenvp, NULL, &conv_error))
546         {
547           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
548                        _("Invalid string in environment: %s"),
549                        conv_error->message);
550           g_error_free (conv_error);
551           g_free (cpargv0);
552           g_strfreev (cpargv);
553
554           return FALSE;
555         }
556
557       if (child_setup)
558         (* child_setup) (user_data);
559
560       if (flags & G_SPAWN_SEARCH_PATH)
561         if (cpenvp != NULL)
562           rc = spawnvpe (mode, cpargv0, (const char **) cpargv, (const char **) cpenvp);
563         else
564           rc = spawnvp (mode, cpargv0, (const char **) cpargv);
565       else
566         if (envp != NULL)
567           rc = spawnve (mode, cpargv0, (const char **) cpargv, (const char **) cpenvp);
568         else
569           rc = spawnv (mode, cpargv0, (const char **) cpargv);
570
571       g_free (cpargv0);
572       g_strfreev (cpargv);
573       g_strfreev (cpenvp);
574     }
575
576   saved_errno = errno;
577
578   if (rc == -1 && saved_errno != 0)
579     {
580       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
581                    _("Failed to execute child process (%s)"),
582                    g_strerror (saved_errno));
583       return FALSE;
584     }
585
586   if (exit_status == NULL)
587     {
588       if (child_handle && do_return_handle)
589         *child_handle = (GPid) rc;
590       else
591         {
592           CloseHandle ((HANDLE) rc);
593           if (child_handle)
594             *child_handle = 0;
595         }
596     }
597   else
598     *exit_status = rc;
599
600   return TRUE;
601 }
602
603 static gboolean
604 do_spawn_with_pipes (gint                 *exit_status,
605                      gboolean              do_return_handle,
606                      const gchar          *working_directory,
607                      gchar               **argv,
608                      char                **envp,
609                      GSpawnFlags           flags,
610                      GSpawnChildSetupFunc  child_setup,
611                      gpointer              user_data,
612                      GPid                 *child_handle,
613                      gint                 *standard_input,
614                      gint                 *standard_output,
615                      gint                 *standard_error,
616                      gint                 *err_report,
617                      GError              **error)     
618 {
619   char **protected_argv;
620   char args[ARG_COUNT][10];
621   char **new_argv;
622   int i;
623   int rc = -1;
624   int saved_errno;
625   int argc;
626   int stdin_pipe[2] = { -1, -1 };
627   int stdout_pipe[2] = { -1, -1 };
628   int stderr_pipe[2] = { -1, -1 };
629   int child_err_report_pipe[2] = { -1, -1 };
630   int helper_report[2];
631   static gboolean warned_about_child_setup = FALSE;
632   GError *conv_error = NULL;
633   gint conv_error_index;
634   gchar *helper_process;
635   CONSOLE_CURSOR_INFO cursor_info;
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 (exit_status, do_return_handle, flags,
657                            argv, envp, protected_argv,
658                            child_setup, user_data, child_handle,
659                            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   if (GetConsoleCursorInfo (GetStdHandle (STD_OUTPUT_HANDLE), &cursor_info))
678     helper_process = HELPER_PROCESS "-console.exe";
679   else
680     helper_process = HELPER_PROCESS ".exe";
681   new_argv[0] = helper_process;
682   _g_sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_pipe[1]);
683   new_argv[ARG_CHILD_ERR_REPORT] = args[ARG_CHILD_ERR_REPORT];
684   
685   if (flags & G_SPAWN_FILE_AND_ARGV_ZERO)
686     {
687       /* Overload ARG_CHILD_ERR_REPORT to also encode the
688        * G_SPAWN_FILE_AND_ARGV_ZERO functionality.
689        */
690       strcat (args[ARG_CHILD_ERR_REPORT], "#");
691     }
692   
693   if (standard_input)
694     {
695       _g_sprintf (args[ARG_STDIN], "%d", stdin_pipe[0]);
696       new_argv[ARG_STDIN] = args[ARG_STDIN];
697     }
698   else if (flags & G_SPAWN_CHILD_INHERITS_STDIN)
699     {
700       /* Let stdin be alone */
701       new_argv[ARG_STDIN] = "-";
702     }
703   else
704     {
705       /* Keep process from blocking on a read of stdin */
706       new_argv[ARG_STDIN] = "z";
707     }
708   
709   if (standard_output)
710     {
711       _g_sprintf (args[ARG_STDOUT], "%d", stdout_pipe[1]);
712       new_argv[ARG_STDOUT] = args[ARG_STDOUT];
713     }
714   else if (flags & G_SPAWN_STDOUT_TO_DEV_NULL)
715     {
716       new_argv[ARG_STDOUT] = "z";
717     }
718   else
719     {
720       new_argv[ARG_STDOUT] = "-";
721     }
722   
723   if (standard_error)
724     {
725       _g_sprintf (args[ARG_STDERR], "%d", stderr_pipe[1]);
726       new_argv[ARG_STDERR] = args[ARG_STDERR];
727     }
728   else if (flags & G_SPAWN_STDERR_TO_DEV_NULL)
729     {
730       new_argv[ARG_STDERR] = "z";
731     }
732   else
733     {
734       new_argv[ARG_STDERR] = "-";
735     }
736   
737   if (working_directory && *working_directory)
738     new_argv[ARG_WORKING_DIRECTORY] = protect_argv_string (working_directory);
739   else
740     new_argv[ARG_WORKING_DIRECTORY] = g_strdup ("-");
741   
742   if (!(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN))
743     new_argv[ARG_CLOSE_DESCRIPTORS] = "y";
744   else
745     new_argv[ARG_CLOSE_DESCRIPTORS] = "-";
746
747   if (flags & G_SPAWN_SEARCH_PATH)
748     new_argv[ARG_USE_PATH] = "y";
749   else
750     new_argv[ARG_USE_PATH] = "-";
751
752   if (exit_status == NULL)
753     new_argv[ARG_WAIT] = "-";
754   else
755     new_argv[ARG_WAIT] = "w";
756
757   for (i = 0; i <= argc; i++)
758     new_argv[ARG_PROGRAM + i] = protected_argv[i];
759
760   if (debug)
761     {
762       g_print ("calling %s with argv:\n", helper_process);
763       for (i = 0; i < argc + 1 + ARG_COUNT; i++)
764         g_print ("argv[%d]: %s\n", i, (new_argv[i] ? new_argv[i] : "NULL"));
765     }
766
767   if (G_WIN32_HAVE_WIDECHAR_API ())
768     {
769       wchar_t *whelper = g_utf8_to_utf16 (helper_process, -1, NULL, NULL, NULL);
770       wchar_t **wargv, **wenvp;
771
772       if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error))
773         {
774           if (conv_error_index == ARG_WORKING_DIRECTORY)
775             g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
776                          _("Invalid working directory: %s"),
777                          conv_error->message);
778           else
779             g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
780                          _("Invalid string in argument vector at %d: %s"),
781                          conv_error_index - ARG_PROGRAM, conv_error->message);
782           g_error_free (conv_error);
783           g_strfreev (protected_argv);
784           g_free (new_argv[ARG_WORKING_DIRECTORY]);
785           g_free (new_argv);
786           g_free (whelper);
787           
788           return FALSE;
789         }
790       
791       if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error))
792         {
793           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
794                        _("Invalid string in environment: %s"),
795                        conv_error->message);
796           g_error_free (conv_error);
797           g_strfreev (protected_argv);
798           g_free (new_argv[ARG_WORKING_DIRECTORY]);
799           g_free (new_argv);
800           g_free (whelper);
801           g_strfreev ((gchar **) wargv);
802           
803           return FALSE;
804         }
805
806       if (child_setup)
807         (* child_setup) (user_data);
808
809       if (wenvp != NULL)
810         /* Let's hope envp hasn't mucked with PATH so that
811          * gspawn-win32-helper.exe isn't found.
812          */
813         rc = _wspawnvpe (P_NOWAIT, whelper, (const wchar_t **) wargv, (const wchar_t **) wenvp);
814       else
815         rc = _wspawnvp (P_NOWAIT, whelper, (const wchar_t **) wargv);
816
817       saved_errno = errno;
818
819       g_free (whelper);
820       g_strfreev ((gchar **) wargv);
821       g_strfreev ((gchar **) wenvp);
822     }
823   else
824     {
825       char **cpargv, **cpenvp;
826
827       if (!utf8_charv_to_cp_charv (new_argv, &cpargv, &conv_error_index, &conv_error))
828         {
829           if (conv_error_index == ARG_WORKING_DIRECTORY)
830             g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
831                          _("Invalid working directory: %s"),
832                          conv_error->message);
833           else
834             g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
835                          _("Invalid string in argument vector at %d: %s"),
836                          conv_error_index - ARG_PROGRAM, conv_error->message);
837           g_error_free (conv_error);
838           g_strfreev (protected_argv);
839           g_free (new_argv[ARG_WORKING_DIRECTORY]);
840           g_free (new_argv);
841           
842           return FALSE;
843         }
844         
845       if (!utf8_charv_to_cp_charv (envp, &cpenvp, NULL, &conv_error))
846         {
847           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
848                        _("Invalid string in environment: %s"),
849                        conv_error->message);
850           g_error_free (conv_error);
851           g_strfreev (protected_argv);
852           g_free (new_argv[ARG_WORKING_DIRECTORY]);
853           g_free (new_argv);
854           g_strfreev (cpargv);
855           
856           return FALSE;
857         }
858
859       if (child_setup)
860         (* child_setup) (user_data);
861
862       if (cpenvp != NULL)
863         rc = spawnvpe (P_NOWAIT, helper_process, (const char **) cpargv, (const char **) cpenvp);
864       else
865         rc = spawnvp (P_NOWAIT, helper_process, (const char **) cpargv);
866
867       saved_errno = errno;
868
869       g_strfreev (cpargv);
870       g_strfreev (cpenvp);
871     }
872
873   /* Close the other process's ends of the pipes in this process,
874    * otherwise the reader will never get EOF.
875    */
876   close_and_invalidate (&child_err_report_pipe[1]);
877   close_and_invalidate (&stdin_pipe[0]);
878   close_and_invalidate (&stdout_pipe[1]);
879   close_and_invalidate (&stderr_pipe[1]);
880
881   g_strfreev (protected_argv);
882
883   g_free (new_argv[ARG_WORKING_DIRECTORY]);
884   g_free (new_argv);
885
886   /* Check if gspawn-win32-helper couldn't be run */
887   if (rc == -1 && saved_errno != 0)
888     {
889       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
890                    _("Failed to execute helper program (%s)"),
891                    g_strerror (saved_errno));
892       goto cleanup_and_fail;
893     }
894
895   if (exit_status != NULL)
896     {
897       /* Synchronous case. Pass helper's report pipe back to caller,
898        * which takes care of reading it after the grandchild has
899        * finished.
900        */
901       g_assert (err_report != NULL);
902       *err_report = child_err_report_pipe[0];
903     }
904   else
905     {
906       /* Asynchronous case. We read the helper's report right away. */
907       if (!read_helper_report (child_err_report_pipe[0], helper_report, error))
908         goto cleanup_and_fail;
909         
910       close (child_err_report_pipe[0]);
911
912       switch (helper_report[0])
913         {
914         case CHILD_NO_ERROR:
915           if (child_handle && do_return_handle)
916             {
917               /* rc is our HANDLE for gspawn-win32-helper. It has
918                * told us the HANDLE of its child. Duplicate that into
919                * a HANDLE valid in this process.
920                */
921               if (!DuplicateHandle ((HANDLE) rc, (HANDLE) helper_report[1],
922                                     GetCurrentProcess (), (LPHANDLE) child_handle,
923                                     0, TRUE, DUPLICATE_SAME_ACCESS))
924                 *child_handle = 0;
925             }
926           else if (child_handle)
927             *child_handle = 0;
928           break;
929           
930         default:
931           set_child_error (helper_report, working_directory, error);
932           goto cleanup_and_fail;
933         }
934     }
935
936   /* Success against all odds! return the information */
937       
938   if (standard_input)
939     *standard_input = stdin_pipe[1];
940   if (standard_output)
941     *standard_output = stdout_pipe[0];
942   if (standard_error)
943     *standard_error = stderr_pipe[0];
944   if (rc != -1)
945     CloseHandle ((HANDLE) rc);
946   
947   return TRUE;
948
949  cleanup_and_fail:
950   if (rc != -1)
951     CloseHandle ((HANDLE) rc);
952   if (child_err_report_pipe[0] != -1)
953     close (child_err_report_pipe[0]);
954   if (child_err_report_pipe[1] != -1)
955     close (child_err_report_pipe[1]);
956   if (stdin_pipe[0] != -1)
957     close (stdin_pipe[0]);
958   if (stdin_pipe[1] != -1)
959     close (stdin_pipe[1]);
960   if (stdout_pipe[0] != -1)
961     close (stdout_pipe[0]);
962   if (stdout_pipe[1] != -1)
963     close (stdout_pipe[1]);
964   if (stderr_pipe[0] != -1)
965     close (stderr_pipe[0]);
966   if (stderr_pipe[1] != -1)
967     close (stderr_pipe[1]);
968
969   return FALSE;
970 }
971
972 gboolean
973 g_spawn_sync_utf8 (const gchar          *working_directory,
974                    gchar               **argv,
975                    gchar               **envp,
976                    GSpawnFlags           flags,
977                    GSpawnChildSetupFunc  child_setup,
978                    gpointer              user_data,
979                    gchar               **standard_output,
980                    gchar               **standard_error,
981                    gint                 *exit_status,
982                    GError              **error)     
983 {
984   gint outpipe = -1;
985   gint errpipe = -1;
986   gint reportpipe = -1;
987   GIOChannel *outchannel = NULL;
988   GIOChannel *errchannel = NULL;
989   GPollFD outfd, errfd;
990   GPollFD fds[2];
991   gint nfds;
992   gint outindex = -1;
993   gint errindex = -1;
994   gint ret;
995   GString *outstr = NULL;
996   GString *errstr = NULL;
997   gboolean failed;
998   gint status;
999   
1000   g_return_val_if_fail (argv != NULL, FALSE);
1001   g_return_val_if_fail (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), FALSE);
1002   g_return_val_if_fail (standard_output == NULL ||
1003                         !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
1004   g_return_val_if_fail (standard_error == NULL ||
1005                         !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
1006   
1007   /* Just to ensure segfaults if callers try to use
1008    * these when an error is reported.
1009    */
1010   if (standard_output)
1011     *standard_output = NULL;
1012
1013   if (standard_error)
1014     *standard_error = NULL;
1015   
1016   if (!do_spawn_with_pipes (&status,
1017                             FALSE,
1018                             working_directory,
1019                             argv,
1020                             envp,
1021                             flags,
1022                             child_setup,
1023                             user_data,
1024                             NULL,
1025                             NULL,
1026                             standard_output ? &outpipe : NULL,
1027                             standard_error ? &errpipe : NULL,
1028                             &reportpipe,
1029                             error))
1030     return FALSE;
1031
1032   /* Read data from child. */
1033   
1034   failed = FALSE;
1035
1036   if (outpipe >= 0)
1037     {
1038       outstr = g_string_new (NULL);
1039       outchannel = g_io_channel_win32_new_fd (outpipe);
1040       g_io_channel_set_encoding (outchannel, NULL, NULL);
1041       g_io_channel_set_buffered (outchannel, FALSE);
1042       g_io_channel_win32_make_pollfd (outchannel,
1043                                       G_IO_IN | G_IO_ERR | G_IO_HUP,
1044                                       &outfd);
1045       if (debug)
1046         g_print ("outfd=%x\n", outfd.fd);
1047     }
1048       
1049   if (errpipe >= 0)
1050     {
1051       errstr = g_string_new (NULL);
1052       errchannel = g_io_channel_win32_new_fd (errpipe);
1053       g_io_channel_set_encoding (errchannel, NULL, NULL);
1054       g_io_channel_set_buffered (errchannel, FALSE);
1055       g_io_channel_win32_make_pollfd (errchannel,
1056                                       G_IO_IN | G_IO_ERR | G_IO_HUP,
1057                                       &errfd);
1058       if (debug)
1059         g_print ("errfd=%x\n", errfd.fd);
1060     }
1061
1062   /* Read data until we get EOF on all pipes. */
1063   while (!failed && (outpipe >= 0 || errpipe >= 0))
1064     {
1065       nfds = 0;
1066       if (outpipe >= 0)
1067         {
1068           fds[nfds] = outfd;
1069           outindex = nfds;
1070           nfds++;
1071         }
1072       if (errpipe >= 0)
1073         {
1074           fds[nfds] = errfd;
1075           errindex = nfds;
1076           nfds++;
1077         }
1078
1079       if (debug)
1080         g_print ("g_spawn_sync: calling g_io_channel_win32_poll, nfds=%d\n",
1081                  nfds);
1082
1083       ret = g_io_channel_win32_poll (fds, nfds, -1);
1084
1085       if (ret < 0)
1086         {
1087           failed = TRUE;
1088
1089           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ,
1090                        _("Unexpected error in g_io_channel_win32_poll() reading data from a child process"));
1091           
1092           break;
1093         }
1094
1095       if (outpipe >= 0 && (fds[outindex].revents & G_IO_IN))
1096         {
1097           switch (read_data (outstr, outchannel, error))
1098             {
1099             case READ_FAILED:
1100               if (debug)
1101                 g_print ("g_spawn_sync: outchannel: READ_FAILED\n");
1102               failed = TRUE;
1103               break;
1104             case READ_EOF:
1105               if (debug)
1106                 g_print ("g_spawn_sync: outchannel: READ_EOF\n");
1107               g_io_channel_unref (outchannel);
1108               outchannel = NULL;
1109               close_and_invalidate (&outpipe);
1110               break;
1111             default:
1112               if (debug)
1113                 g_print ("g_spawn_sync: outchannel: OK\n");
1114               break;
1115             }
1116
1117           if (failed)
1118             break;
1119         }
1120
1121       if (errpipe >= 0 && (fds[errindex].revents & G_IO_IN))
1122         {
1123           switch (read_data (errstr, errchannel, error))
1124             {
1125             case READ_FAILED:
1126               if (debug)
1127                 g_print ("g_spawn_sync: errchannel: READ_FAILED\n");
1128               failed = TRUE;
1129               break;
1130             case READ_EOF:
1131               if (debug)
1132                 g_print ("g_spawn_sync: errchannel: READ_EOF\n");
1133               g_io_channel_unref (errchannel);
1134               errchannel = NULL;
1135               close_and_invalidate (&errpipe);
1136               break;
1137             default:
1138               if (debug)
1139                 g_print ("g_spawn_sync: errchannel: OK\n");
1140               break;
1141             }
1142
1143           if (failed)
1144             break;
1145         }
1146     }
1147
1148   if (reportpipe == -1)
1149     {
1150       /* No helper process, exit status of actual spawned process
1151        * already available.
1152        */
1153       if (exit_status)
1154         *exit_status = status;
1155     }
1156   else
1157     {
1158       /* Helper process was involved. Read its report now after the
1159        * grandchild has finished.
1160        */
1161       gint helper_report[2];
1162
1163       if (!read_helper_report (reportpipe, helper_report, error))
1164         failed = TRUE;
1165       else
1166         {
1167           switch (helper_report[0])
1168             {
1169             case CHILD_NO_ERROR:
1170               if (exit_status)
1171                 *exit_status = helper_report[1];
1172               break;
1173             default:
1174               set_child_error (helper_report, working_directory, error);
1175               failed = TRUE;
1176               break;
1177             }
1178         }
1179       close_and_invalidate (&reportpipe);
1180     }
1181
1182
1183   /* These should only be open still if we had an error.  */
1184   
1185   if (outchannel != NULL)
1186     g_io_channel_unref (outchannel);
1187   if (errchannel != NULL)
1188     g_io_channel_unref (errchannel);
1189   if (outpipe >= 0)
1190     close_and_invalidate (&outpipe);
1191   if (errpipe >= 0)
1192     close_and_invalidate (&errpipe);
1193   
1194   if (failed)
1195     {
1196       if (outstr)
1197         g_string_free (outstr, TRUE);
1198       if (errstr)
1199         g_string_free (errstr, TRUE);
1200
1201       return FALSE;
1202     }
1203   else
1204     {
1205       if (standard_output)        
1206         *standard_output = g_string_free (outstr, FALSE);
1207
1208       if (standard_error)
1209         *standard_error = g_string_free (errstr, FALSE);
1210
1211       return TRUE;
1212     }
1213 }
1214
1215 gboolean
1216 g_spawn_async_with_pipes_utf8 (const gchar          *working_directory,
1217                                gchar               **argv,
1218                                gchar               **envp,
1219                                GSpawnFlags           flags,
1220                                GSpawnChildSetupFunc  child_setup,
1221                                gpointer              user_data,
1222                                GPid                 *child_handle,
1223                                gint                 *standard_input,
1224                                gint                 *standard_output,
1225                                gint                 *standard_error,
1226                                GError              **error)
1227 {
1228   g_return_val_if_fail (argv != NULL, FALSE);
1229   g_return_val_if_fail (standard_output == NULL ||
1230                         !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
1231   g_return_val_if_fail (standard_error == NULL ||
1232                         !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
1233   /* can't inherit stdin if we have an input pipe. */
1234   g_return_val_if_fail (standard_input == NULL ||
1235                         !(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE);
1236   
1237   return do_spawn_with_pipes (NULL,
1238                               (flags & G_SPAWN_DO_NOT_REAP_CHILD),
1239                               working_directory,
1240                               argv,
1241                               envp,
1242                               flags,
1243                               child_setup,
1244                               user_data,
1245                               child_handle,
1246                               standard_input,
1247                               standard_output,
1248                               standard_error,
1249                               NULL,
1250                               error);
1251 }
1252
1253 gboolean
1254 g_spawn_command_line_sync_utf8 (const gchar  *command_line,
1255                                 gchar       **standard_output,
1256                                 gchar       **standard_error,
1257                                 gint         *exit_status,
1258                                 GError      **error)
1259 {
1260   gboolean retval;
1261   gchar **argv = 0;
1262
1263   g_return_val_if_fail (command_line != NULL, FALSE);
1264   
1265   if (!g_shell_parse_argv (command_line,
1266                            NULL, &argv,
1267                            error))
1268     return FALSE;
1269   
1270   retval = g_spawn_sync_utf8 (NULL,
1271                               argv,
1272                               NULL,
1273                               G_SPAWN_SEARCH_PATH,
1274                               NULL,
1275                               NULL,
1276                               standard_output,
1277                               standard_error,
1278                               exit_status,
1279                               error);
1280   g_strfreev (argv);
1281
1282   return retval;
1283 }
1284
1285 gboolean
1286 g_spawn_command_line_async_utf8 (const gchar *command_line,
1287                                  GError     **error)
1288 {
1289   gboolean retval;
1290   gchar **argv = 0;
1291
1292   g_return_val_if_fail (command_line != NULL, FALSE);
1293
1294   if (!g_shell_parse_argv (command_line,
1295                            NULL, &argv,
1296                            error))
1297     return FALSE;
1298   
1299   retval = g_spawn_async_utf8 (NULL,
1300                                argv,
1301                                NULL,
1302                                G_SPAWN_SEARCH_PATH,
1303                                NULL,
1304                                NULL,
1305                                NULL,
1306                                error);
1307   g_strfreev (argv);
1308
1309   return retval;
1310 }
1311
1312 void
1313 g_spawn_close_pid (GPid pid)
1314 {
1315     CloseHandle (pid);
1316 }
1317
1318 /* Binary compatibility versions that take system codepage pathnames,
1319  * argument vectors and environments. These get used only by code
1320  * built against 2.8.1 or earlier. Code built against 2.8.2 or later
1321  * will use the _utf8 versions above (see the #defines in gspawn.h).
1322  */
1323
1324 #undef g_spawn_async
1325 #undef g_spawn_async_with_pipes
1326 #undef g_spawn_sync
1327 #undef g_spawn_command_line_sync
1328 #undef g_spawn_command_line_async
1329
1330 static gboolean
1331 setup_utf8_copies (const gchar *working_directory,
1332                    gchar      **utf8_working_directory,
1333                    gchar      **argv,
1334                    gchar     ***utf8_argv,
1335                    gchar      **envp,
1336                    gchar     ***utf8_envp,
1337                    GError     **error)
1338 {
1339   gint i, argc, envc;
1340
1341   if (working_directory == NULL)
1342     *utf8_working_directory = NULL;
1343   else
1344     {
1345       GError *conv_error = NULL;
1346       
1347       *utf8_working_directory = g_locale_to_utf8 (working_directory, -1, NULL, NULL, &conv_error);
1348       if (*utf8_working_directory == NULL)
1349         {
1350           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
1351                        _("Invalid working directory: %s"),
1352                        conv_error->message);
1353           g_error_free (conv_error);
1354           return FALSE;
1355         }
1356     }
1357
1358   argc = 0;
1359   while (argv[argc])
1360     ++argc;
1361   *utf8_argv = g_new (gchar *, argc + 1);
1362   for (i = 0; i < argc; i++)
1363     {
1364       GError *conv_error = NULL;
1365
1366       (*utf8_argv)[i] = g_locale_to_utf8 (argv[i], -1, NULL, NULL, &conv_error);
1367       if ((*utf8_argv)[i] == NULL)
1368         {
1369           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
1370                        _("Invalid string in argument vector at %d: %s"),
1371                        i, conv_error->message);
1372           g_error_free (conv_error);
1373           
1374           g_strfreev (*utf8_argv);
1375           *utf8_argv = NULL;
1376
1377           g_free (*utf8_working_directory);
1378           *utf8_working_directory = NULL;
1379
1380           return FALSE;
1381         }
1382     }
1383   (*utf8_argv)[argc] = NULL;
1384
1385   if (envp == NULL)
1386     {
1387       *utf8_envp = NULL;
1388     }
1389   else
1390     {
1391       envc = 0;
1392       while (envp[envc])
1393         ++envc;
1394       *utf8_envp = g_new (gchar *, envc + 1);
1395       for (i = 0; i < envc; i++)
1396         {
1397           GError *conv_error = NULL;
1398
1399           (*utf8_envp)[i] = g_locale_to_utf8 (envp[i], -1, NULL, NULL, &conv_error);
1400           if ((*utf8_envp)[i] == NULL)
1401             {   
1402               g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
1403                            _("Invalid string in environment: %s"),
1404                            conv_error->message);
1405               g_error_free (conv_error);
1406
1407               g_strfreev (*utf8_envp);
1408               *utf8_envp = NULL;
1409
1410               g_strfreev (*utf8_argv);
1411               *utf8_argv = NULL;
1412
1413               g_free (*utf8_working_directory);
1414               *utf8_working_directory = NULL;
1415
1416               return FALSE;
1417             }
1418         }
1419       (*utf8_envp)[envc] = NULL;
1420     }
1421   return TRUE;
1422 }
1423
1424 static void
1425 free_utf8_copies (gchar  *utf8_working_directory,
1426                   gchar **utf8_argv,
1427                   gchar **utf8_envp)
1428 {
1429   g_free (utf8_working_directory);
1430   g_strfreev (utf8_argv);
1431   g_strfreev (utf8_envp);
1432 }
1433
1434 gboolean
1435 g_spawn_async_with_pipes (const gchar          *working_directory,
1436                           gchar               **argv,
1437                           gchar               **envp,
1438                           GSpawnFlags           flags,
1439                           GSpawnChildSetupFunc  child_setup,
1440                           gpointer              user_data,
1441                           GPid                 *child_handle,
1442                           gint                 *standard_input,
1443                           gint                 *standard_output,
1444                           gint                 *standard_error,
1445                           GError              **error)
1446 {
1447   gchar *utf8_working_directory;
1448   gchar **utf8_argv;
1449   gchar **utf8_envp;
1450   gboolean retval;
1451
1452   if (!setup_utf8_copies (working_directory, &utf8_working_directory,
1453                           argv, &utf8_argv,
1454                           envp, &utf8_envp,
1455                           error))
1456     return FALSE;
1457
1458   retval = g_spawn_async_with_pipes_utf8 (utf8_working_directory,
1459                                           utf8_argv, utf8_envp,
1460                                           flags, child_setup, user_data,
1461                                           child_handle,
1462                                           standard_input, standard_output, standard_error,
1463                                           error);
1464
1465   free_utf8_copies (utf8_working_directory, utf8_argv, utf8_envp);
1466
1467   return retval;
1468 }
1469
1470 gboolean
1471 g_spawn_async (const gchar          *working_directory,
1472                gchar               **argv,
1473                gchar               **envp,
1474                GSpawnFlags           flags,
1475                GSpawnChildSetupFunc  child_setup,
1476                gpointer              user_data,
1477                GPid                 *child_handle,
1478                GError              **error)
1479 {
1480   return g_spawn_async_with_pipes (working_directory,
1481                                    argv, envp,
1482                                    flags,
1483                                    child_setup,
1484                                    user_data,
1485                                    child_handle,
1486                                    NULL, NULL, NULL,
1487                                    error);
1488 }
1489
1490 gboolean
1491 g_spawn_sync (const gchar          *working_directory,
1492               gchar               **argv,
1493               gchar               **envp,
1494               GSpawnFlags           flags,
1495               GSpawnChildSetupFunc  child_setup,
1496               gpointer              user_data,
1497               gchar               **standard_output,
1498               gchar               **standard_error,
1499               gint                 *exit_status,
1500               GError              **error)     
1501 {
1502   gchar *utf8_working_directory;
1503   gchar **utf8_argv;
1504   gchar **utf8_envp;
1505   gboolean retval;
1506
1507   if (!setup_utf8_copies (working_directory, &utf8_working_directory,
1508                           argv, &utf8_argv,
1509                           envp, &utf8_envp,
1510                           error))
1511     return FALSE;
1512
1513   retval = g_spawn_sync_utf8 (utf8_working_directory,
1514                               utf8_argv, utf8_envp,
1515                               flags, child_setup, user_data,
1516                               standard_output, standard_error, exit_status,
1517                               error);
1518
1519   free_utf8_copies (utf8_working_directory, utf8_argv, utf8_envp);
1520
1521   return retval;
1522 }
1523
1524 gboolean
1525 g_spawn_command_line_sync (const gchar  *command_line,
1526                            gchar       **standard_output,
1527                            gchar       **standard_error,
1528                            gint         *exit_status,
1529                            GError      **error)
1530 {
1531   gboolean retval;
1532   gchar **argv = 0;
1533
1534   g_return_val_if_fail (command_line != NULL, FALSE);
1535   
1536   if (!g_shell_parse_argv (command_line,
1537                            NULL, &argv,
1538                            error))
1539     return FALSE;
1540   
1541   retval = g_spawn_sync (NULL,
1542                          argv,
1543                          NULL,
1544                          G_SPAWN_SEARCH_PATH,
1545                          NULL,
1546                          NULL,
1547                          standard_output,
1548                          standard_error,
1549                          exit_status,
1550                          error);
1551   g_strfreev (argv);
1552
1553   return retval;
1554 }
1555
1556 gboolean
1557 g_spawn_command_line_async (const gchar *command_line,
1558                             GError     **error)
1559 {
1560   gboolean retval;
1561   gchar **argv = 0;
1562
1563   g_return_val_if_fail (command_line != NULL, FALSE);
1564
1565   if (!g_shell_parse_argv (command_line,
1566                            NULL, &argv,
1567                            error))
1568     return FALSE;
1569   
1570   retval = g_spawn_async (NULL,
1571                           argv,
1572                           NULL,
1573                           G_SPAWN_SEARCH_PATH,
1574                           NULL,
1575                           NULL,
1576                           NULL,
1577                           error);
1578   g_strfreev (argv);
1579
1580   return retval;
1581 }
1582
1583 #endif /* !GSPAWN_HELPER */
1584
1585 #define __G_SPAWN_C__
1586 #include "galiasdef.c"