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