Move docs inline, and improve wording. (#372598, Behdad Esfahbod)
[glib.git] / glib / gspawn-win32.c
blobf5bc820bb38104a5c987614afeafa52ff3753f19
1 /* gspawn-win32.c - Process launching on Win32
3 * Copyright 2000 Red Hat, Inc.
4 * Copyright 2003 Tor Lillqvist
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.
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.
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.
23 * Implementation details on Win32.
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.)
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.
39 * The structure of the source code in this file is a mess, I know.
42 /* Define this to get some logging all the time */
43 /* #define G_SPAWN_WIN32_DEBUG */
45 #include "config.h"
47 #include "glib.h"
48 #include "gprintfint.h"
49 #include "glibintl.h"
50 #include "galias.h"
52 #include <string.h>
53 #include <stdlib.h>
54 #include <stdio.h>
56 #include <windows.h>
57 #include <errno.h>
58 #include <fcntl.h>
59 #include <io.h>
60 #include <process.h>
61 #include <direct.h>
63 #ifdef __MINGW32__
64 /* Mingw doesn't have prototypes for these */
65 int _wspawnvpe (int, const wchar_t *, const wchar_t **, const wchar_t **);
66 int _wspawnvp (int, const wchar_t *, const wchar_t **);
67 int _wspawnve (int, const wchar_t *, const wchar_t **, const wchar_t **);
68 int _wspawnv (int, const wchar_t *, const wchar_t **);
69 #endif
71 #ifdef G_SPAWN_WIN32_DEBUG
72 static int debug = 1;
73 #define SETUP_DEBUG() /* empty */
74 #else
75 static int debug = -1;
76 #define SETUP_DEBUG() \
77 G_STMT_START \
78 { \
79 if (debug == -1) \
80 { \
81 if (getenv ("G_SPAWN_WIN32_DEBUG") != NULL) \
82 debug = 1; \
83 else \
84 debug = 0; \
85 } \
86 } \
87 G_STMT_END
88 #endif
90 enum
92 CHILD_NO_ERROR,
93 CHILD_CHDIR_FAILED,
94 CHILD_SPAWN_FAILED,
97 enum {
98 ARG_CHILD_ERR_REPORT = 1,
99 ARG_STDIN,
100 ARG_STDOUT,
101 ARG_STDERR,
102 ARG_WORKING_DIRECTORY,
103 ARG_CLOSE_DESCRIPTORS,
104 ARG_USE_PATH,
105 ARG_WAIT,
106 ARG_PROGRAM,
107 ARG_COUNT = ARG_PROGRAM
110 #ifndef GSPAWN_HELPER
112 #define HELPER_PROCESS "gspawn-win32-helper"
114 static gchar *
115 protect_argv_string (const gchar *string)
117 const gchar *p = string;
118 gchar *retval, *q;
119 gint len = 0;
120 gboolean need_dblquotes = FALSE;
121 while (*p)
123 if (*p == ' ' || *p == '\t')
124 need_dblquotes = TRUE;
125 else if (*p == '"')
126 len++;
127 else if (*p == '\\')
129 const gchar *pp = p;
130 while (*pp && *pp == '\\')
131 pp++;
132 if (*pp == '"')
133 len++;
135 len++;
136 p++;
139 q = retval = g_malloc (len + need_dblquotes*2 + 1);
140 p = string;
142 if (need_dblquotes)
143 *q++ = '"';
145 while (*p)
147 if (*p == '"')
148 *q++ = '\\';
149 else if (*p == '\\')
151 const gchar *pp = p;
152 while (*pp && *pp == '\\')
153 pp++;
154 if (*pp == '"')
155 *q++ = '\\';
157 *q++ = *p;
158 p++;
161 if (need_dblquotes)
162 *q++ = '"';
163 *q++ = '\0';
165 return retval;
168 static gint
169 protect_argv (gchar **argv,
170 gchar ***new_argv)
172 gint i;
173 gint argc = 0;
175 while (argv[argc])
176 ++argc;
177 *new_argv = g_new (gchar *, argc+1);
179 /* Quote each argv element if necessary, so that it will get
180 * reconstructed correctly in the C runtime startup code. Note that
181 * the unquoting algorithm in the C runtime is really weird, and
182 * rather different than what Unix shells do. See stdargv.c in the C
183 * runtime sources (in the Platform SDK, in src/crt).
185 * Note that an new_argv[0] constructed by this function should
186 * *not* be passed as the filename argument to a spawn* or exec*
187 * family function. That argument should be the real file name
188 * without any quoting.
190 for (i = 0; i < argc; i++)
191 (*new_argv)[i] = protect_argv_string (argv[i]);
193 (*new_argv)[argc] = NULL;
195 return argc;
198 GQuark
199 g_spawn_error_quark (void)
201 return g_quark_from_static_string ("g-exec-error-quark");
204 gboolean
205 g_spawn_async_utf8 (const gchar *working_directory,
206 gchar **argv,
207 gchar **envp,
208 GSpawnFlags flags,
209 GSpawnChildSetupFunc child_setup,
210 gpointer user_data,
211 GPid *child_handle,
212 GError **error)
214 g_return_val_if_fail (argv != NULL, FALSE);
216 return g_spawn_async_with_pipes_utf8 (working_directory,
217 argv, envp,
218 flags,
219 child_setup,
220 user_data,
221 child_handle,
222 NULL, NULL, NULL,
223 error);
226 /* Avoids a danger in threaded situations (calling close()
227 * on a file descriptor twice, and another thread has
228 * re-opened it since the first close)
230 static void
231 close_and_invalidate (gint *fd)
233 if (*fd < 0)
234 return;
236 close (*fd);
237 *fd = -1;
240 typedef enum
242 READ_FAILED = 0, /* FALSE */
243 READ_OK,
244 READ_EOF
245 } ReadResult;
247 static ReadResult
248 read_data (GString *str,
249 GIOChannel *iochannel,
250 GError **error)
252 GIOStatus giostatus;
253 gssize bytes;
254 gchar buf[4096];
256 again:
258 giostatus = g_io_channel_read_chars (iochannel, buf, sizeof (buf), &bytes, NULL);
260 if (bytes == 0)
261 return READ_EOF;
262 else if (bytes > 0)
264 g_string_append_len (str, buf, bytes);
265 return READ_OK;
267 else if (giostatus == G_IO_STATUS_AGAIN)
268 goto again;
269 else if (giostatus == G_IO_STATUS_ERROR)
271 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ,
272 _("Failed to read data from child process"));
274 return READ_FAILED;
276 else
277 return READ_OK;
280 static gboolean
281 make_pipe (gint p[2],
282 GError **error)
284 if (pipe (p) < 0)
286 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
287 _("Failed to create pipe for communicating with child process (%s)"),
288 g_strerror (errno));
289 return FALSE;
291 else
292 return TRUE;
295 /* The helper process writes a status report back to us, through a
296 * pipe, consisting of two ints.
298 static gboolean
299 read_helper_report (int fd,
300 gint report[2],
301 GError **error)
303 gint bytes = 0;
305 while (bytes < sizeof(gint)*2)
307 gint chunk;
309 if (debug)
310 g_print ("%s:read_helper_report: read %d...\n",
311 __FILE__,
312 sizeof(gint)*2 - bytes);
314 chunk = read (fd, ((gchar*)report) + bytes,
315 sizeof(gint)*2 - bytes);
317 if (debug)
318 g_print ("...got %d bytes\n", chunk);
320 if (chunk < 0)
322 /* Some weird shit happened, bail out */
324 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
325 _("Failed to read from child pipe (%s)"),
326 g_strerror (errno));
328 return FALSE;
330 else if (chunk == 0)
331 break; /* EOF */
332 else
333 bytes += chunk;
336 if (bytes < sizeof(gint)*2)
337 return FALSE;
339 return TRUE;
342 static void
343 set_child_error (gint report[2],
344 const gchar *working_directory,
345 GError **error)
347 switch (report[0])
349 case CHILD_CHDIR_FAILED:
350 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
351 _("Failed to change to directory '%s' (%s)"),
352 working_directory,
353 g_strerror (report[1]));
354 break;
355 case CHILD_SPAWN_FAILED:
356 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
357 _("Failed to execute child process (%s)"),
358 g_strerror (report[1]));
359 break;
360 default:
361 g_assert_not_reached ();
365 static gboolean
366 utf8_charv_to_wcharv (char **utf8_charv,
367 wchar_t ***wcharv,
368 int *error_index,
369 GError **error)
371 wchar_t **retval = NULL;
373 *wcharv = NULL;
374 if (utf8_charv != NULL)
376 int n = 0, i;
378 while (utf8_charv[n])
379 n++;
380 retval = g_new (wchar_t *, n + 1);
382 for (i = 0; i < n; i++)
384 retval[i] = g_utf8_to_utf16 (utf8_charv[i], -1, NULL, NULL, error);
385 if (retval[i] == NULL)
387 if (error_index)
388 *error_index = i;
389 while (i)
390 g_free (retval[--i]);
391 g_free (retval);
392 return FALSE;
396 retval[n] = NULL;
398 *wcharv = retval;
399 return TRUE;
402 static gboolean
403 do_spawn_directly (gint *exit_status,
404 gboolean do_return_handle,
405 GSpawnFlags flags,
406 gchar **argv,
407 char **envp,
408 char **protected_argv,
409 GSpawnChildSetupFunc child_setup,
410 gpointer user_data,
411 GPid *child_handle,
412 GError **error)
414 const int mode = (exit_status == NULL) ? P_NOWAIT : P_WAIT;
415 char **new_argv;
416 int rc = -1;
417 int saved_errno;
418 GError *conv_error = NULL;
419 gint conv_error_index;
420 wchar_t *wargv0, **wargv, **wenvp;
422 new_argv = (flags & G_SPAWN_FILE_AND_ARGV_ZERO) ? protected_argv + 1 : protected_argv;
424 wargv0 = g_utf8_to_utf16 (argv[0], -1, NULL, NULL, &conv_error);
425 if (wargv0 == NULL)
427 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
428 _("Invalid program name: %s"),
429 conv_error->message);
430 g_error_free (conv_error);
432 return FALSE;
435 if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error))
437 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
438 _("Invalid string in argument vector at %d: %s"),
439 conv_error_index, conv_error->message);
440 g_error_free (conv_error);
441 g_free (wargv0);
443 return FALSE;
446 if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error))
448 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
449 _("Invalid string in environment: %s"),
450 conv_error->message);
451 g_error_free (conv_error);
452 g_free (wargv0);
453 g_strfreev ((gchar **) wargv);
455 return FALSE;
458 if (child_setup)
459 (* child_setup) (user_data);
461 if (flags & G_SPAWN_SEARCH_PATH)
462 if (wenvp != NULL)
463 rc = _wspawnvpe (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp);
464 else
465 rc = _wspawnvp (mode, wargv0, (const wchar_t **) wargv);
466 else
467 if (wenvp != NULL)
468 rc = _wspawnve (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp);
469 else
470 rc = _wspawnv (mode, wargv0, (const wchar_t **) wargv);
472 g_free (wargv0);
473 g_strfreev ((gchar **) wargv);
474 g_strfreev ((gchar **) wenvp);
476 saved_errno = errno;
478 if (rc == -1 && saved_errno != 0)
480 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
481 _("Failed to execute child process (%s)"),
482 g_strerror (saved_errno));
483 return FALSE;
486 if (exit_status == NULL)
488 if (child_handle && do_return_handle)
489 *child_handle = (GPid) rc;
490 else
492 CloseHandle ((HANDLE) rc);
493 if (child_handle)
494 *child_handle = 0;
497 else
498 *exit_status = rc;
500 return TRUE;
503 static gboolean
504 do_spawn_with_pipes (gint *exit_status,
505 gboolean do_return_handle,
506 const gchar *working_directory,
507 gchar **argv,
508 char **envp,
509 GSpawnFlags flags,
510 GSpawnChildSetupFunc child_setup,
511 gpointer user_data,
512 GPid *child_handle,
513 gint *standard_input,
514 gint *standard_output,
515 gint *standard_error,
516 gint *err_report,
517 GError **error)
519 char **protected_argv;
520 char args[ARG_COUNT][10];
521 char **new_argv;
522 int i;
523 int rc = -1;
524 int saved_errno;
525 int argc;
526 int stdin_pipe[2] = { -1, -1 };
527 int stdout_pipe[2] = { -1, -1 };
528 int stderr_pipe[2] = { -1, -1 };
529 int child_err_report_pipe[2] = { -1, -1 };
530 int helper_report[2];
531 static gboolean warned_about_child_setup = FALSE;
532 GError *conv_error = NULL;
533 gint conv_error_index;
534 gchar *helper_process;
535 CONSOLE_CURSOR_INFO cursor_info;
536 wchar_t *whelper, **wargv, **wenvp;
538 SETUP_DEBUG();
540 if (child_setup && !warned_about_child_setup)
542 warned_about_child_setup = TRUE;
543 g_warning ("passing a child setup function to the g_spawn functions is pointless and dangerous on Win32");
546 argc = protect_argv (argv, &protected_argv);
548 if (!standard_input && !standard_output && !standard_error &&
549 (flags & G_SPAWN_CHILD_INHERITS_STDIN) &&
550 !(flags & G_SPAWN_STDOUT_TO_DEV_NULL) &&
551 !(flags & G_SPAWN_STDERR_TO_DEV_NULL) &&
552 (working_directory == NULL || !*working_directory) &&
553 (flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN))
555 /* We can do without the helper process */
556 gboolean retval =
557 do_spawn_directly (exit_status, do_return_handle, flags,
558 argv, envp, protected_argv,
559 child_setup, user_data, child_handle,
560 error);
561 g_strfreev (protected_argv);
562 return retval;
565 if (standard_input && !make_pipe (stdin_pipe, error))
566 goto cleanup_and_fail;
568 if (standard_output && !make_pipe (stdout_pipe, error))
569 goto cleanup_and_fail;
571 if (standard_error && !make_pipe (stderr_pipe, error))
572 goto cleanup_and_fail;
574 if (!make_pipe (child_err_report_pipe, error))
575 goto cleanup_and_fail;
577 new_argv = g_new (char *, argc + 1 + ARG_COUNT);
578 if (GetConsoleCursorInfo (GetStdHandle (STD_OUTPUT_HANDLE), &cursor_info))
579 helper_process = HELPER_PROCESS "-console.exe";
580 else
581 helper_process = HELPER_PROCESS ".exe";
582 new_argv[0] = helper_process;
583 _g_sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_pipe[1]);
584 new_argv[ARG_CHILD_ERR_REPORT] = args[ARG_CHILD_ERR_REPORT];
586 if (flags & G_SPAWN_FILE_AND_ARGV_ZERO)
588 /* Overload ARG_CHILD_ERR_REPORT to also encode the
589 * G_SPAWN_FILE_AND_ARGV_ZERO functionality.
591 strcat (args[ARG_CHILD_ERR_REPORT], "#");
594 if (standard_input)
596 _g_sprintf (args[ARG_STDIN], "%d", stdin_pipe[0]);
597 new_argv[ARG_STDIN] = args[ARG_STDIN];
599 else if (flags & G_SPAWN_CHILD_INHERITS_STDIN)
601 /* Let stdin be alone */
602 new_argv[ARG_STDIN] = "-";
604 else
606 /* Keep process from blocking on a read of stdin */
607 new_argv[ARG_STDIN] = "z";
610 if (standard_output)
612 _g_sprintf (args[ARG_STDOUT], "%d", stdout_pipe[1]);
613 new_argv[ARG_STDOUT] = args[ARG_STDOUT];
615 else if (flags & G_SPAWN_STDOUT_TO_DEV_NULL)
617 new_argv[ARG_STDOUT] = "z";
619 else
621 new_argv[ARG_STDOUT] = "-";
624 if (standard_error)
626 _g_sprintf (args[ARG_STDERR], "%d", stderr_pipe[1]);
627 new_argv[ARG_STDERR] = args[ARG_STDERR];
629 else if (flags & G_SPAWN_STDERR_TO_DEV_NULL)
631 new_argv[ARG_STDERR] = "z";
633 else
635 new_argv[ARG_STDERR] = "-";
638 if (working_directory && *working_directory)
639 new_argv[ARG_WORKING_DIRECTORY] = protect_argv_string (working_directory);
640 else
641 new_argv[ARG_WORKING_DIRECTORY] = g_strdup ("-");
643 if (!(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN))
644 new_argv[ARG_CLOSE_DESCRIPTORS] = "y";
645 else
646 new_argv[ARG_CLOSE_DESCRIPTORS] = "-";
648 if (flags & G_SPAWN_SEARCH_PATH)
649 new_argv[ARG_USE_PATH] = "y";
650 else
651 new_argv[ARG_USE_PATH] = "-";
653 if (exit_status == NULL)
654 new_argv[ARG_WAIT] = "-";
655 else
656 new_argv[ARG_WAIT] = "w";
658 for (i = 0; i <= argc; i++)
659 new_argv[ARG_PROGRAM + i] = protected_argv[i];
661 if (debug)
663 g_print ("calling %s with argv:\n", helper_process);
664 for (i = 0; i < argc + 1 + ARG_COUNT; i++)
665 g_print ("argv[%d]: %s\n", i, (new_argv[i] ? new_argv[i] : "NULL"));
668 whelper = g_utf8_to_utf16 (helper_process, -1, NULL, NULL, NULL);
670 if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error))
672 if (conv_error_index == ARG_WORKING_DIRECTORY)
673 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
674 _("Invalid working directory: %s"),
675 conv_error->message);
676 else
677 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
678 _("Invalid string in argument vector at %d: %s"),
679 conv_error_index - ARG_PROGRAM, conv_error->message);
680 g_error_free (conv_error);
681 g_strfreev (protected_argv);
682 g_free (new_argv[ARG_WORKING_DIRECTORY]);
683 g_free (new_argv);
684 g_free (whelper);
686 return FALSE;
689 if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error))
691 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
692 _("Invalid string in environment: %s"),
693 conv_error->message);
694 g_error_free (conv_error);
695 g_strfreev (protected_argv);
696 g_free (new_argv[ARG_WORKING_DIRECTORY]);
697 g_free (new_argv);
698 g_free (whelper);
699 g_strfreev ((gchar **) wargv);
701 return FALSE;
704 if (child_setup)
705 (* child_setup) (user_data);
707 if (wenvp != NULL)
708 /* Let's hope envp hasn't mucked with PATH so that
709 * gspawn-win32-helper.exe isn't found.
711 rc = _wspawnvpe (P_NOWAIT, whelper, (const wchar_t **) wargv, (const wchar_t **) wenvp);
712 else
713 rc = _wspawnvp (P_NOWAIT, whelper, (const wchar_t **) wargv);
715 saved_errno = errno;
717 g_free (whelper);
718 g_strfreev ((gchar **) wargv);
719 g_strfreev ((gchar **) wenvp);
721 /* Close the other process's ends of the pipes in this process,
722 * otherwise the reader will never get EOF.
724 close_and_invalidate (&child_err_report_pipe[1]);
725 close_and_invalidate (&stdin_pipe[0]);
726 close_and_invalidate (&stdout_pipe[1]);
727 close_and_invalidate (&stderr_pipe[1]);
729 g_strfreev (protected_argv);
731 g_free (new_argv[ARG_WORKING_DIRECTORY]);
732 g_free (new_argv);
734 /* Check if gspawn-win32-helper couldn't be run */
735 if (rc == -1 && saved_errno != 0)
737 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
738 _("Failed to execute helper program (%s)"),
739 g_strerror (saved_errno));
740 goto cleanup_and_fail;
743 if (exit_status != NULL)
745 /* Synchronous case. Pass helper's report pipe back to caller,
746 * which takes care of reading it after the grandchild has
747 * finished.
749 g_assert (err_report != NULL);
750 *err_report = child_err_report_pipe[0];
752 else
754 /* Asynchronous case. We read the helper's report right away. */
755 if (!read_helper_report (child_err_report_pipe[0], helper_report, error))
756 goto cleanup_and_fail;
758 close (child_err_report_pipe[0]);
760 switch (helper_report[0])
762 case CHILD_NO_ERROR:
763 if (child_handle && do_return_handle)
765 /* rc is our HANDLE for gspawn-win32-helper. It has
766 * told us the HANDLE of its child. Duplicate that into
767 * a HANDLE valid in this process.
769 if (!DuplicateHandle ((HANDLE) rc, (HANDLE) helper_report[1],
770 GetCurrentProcess (), (LPHANDLE) child_handle,
771 0, TRUE, DUPLICATE_SAME_ACCESS))
772 *child_handle = 0;
774 else if (child_handle)
775 *child_handle = 0;
776 break;
778 default:
779 set_child_error (helper_report, working_directory, error);
780 goto cleanup_and_fail;
784 /* Success against all odds! return the information */
786 if (standard_input)
787 *standard_input = stdin_pipe[1];
788 if (standard_output)
789 *standard_output = stdout_pipe[0];
790 if (standard_error)
791 *standard_error = stderr_pipe[0];
792 if (rc != -1)
793 CloseHandle ((HANDLE) rc);
795 return TRUE;
797 cleanup_and_fail:
798 if (rc != -1)
799 CloseHandle ((HANDLE) rc);
800 if (child_err_report_pipe[0] != -1)
801 close (child_err_report_pipe[0]);
802 if (child_err_report_pipe[1] != -1)
803 close (child_err_report_pipe[1]);
804 if (stdin_pipe[0] != -1)
805 close (stdin_pipe[0]);
806 if (stdin_pipe[1] != -1)
807 close (stdin_pipe[1]);
808 if (stdout_pipe[0] != -1)
809 close (stdout_pipe[0]);
810 if (stdout_pipe[1] != -1)
811 close (stdout_pipe[1]);
812 if (stderr_pipe[0] != -1)
813 close (stderr_pipe[0]);
814 if (stderr_pipe[1] != -1)
815 close (stderr_pipe[1]);
817 return FALSE;
820 gboolean
821 g_spawn_sync_utf8 (const gchar *working_directory,
822 gchar **argv,
823 gchar **envp,
824 GSpawnFlags flags,
825 GSpawnChildSetupFunc child_setup,
826 gpointer user_data,
827 gchar **standard_output,
828 gchar **standard_error,
829 gint *exit_status,
830 GError **error)
832 gint outpipe = -1;
833 gint errpipe = -1;
834 gint reportpipe = -1;
835 GIOChannel *outchannel = NULL;
836 GIOChannel *errchannel = NULL;
837 GPollFD outfd, errfd;
838 GPollFD fds[2];
839 gint nfds;
840 gint outindex = -1;
841 gint errindex = -1;
842 gint ret;
843 GString *outstr = NULL;
844 GString *errstr = NULL;
845 gboolean failed;
846 gint status;
848 g_return_val_if_fail (argv != NULL, FALSE);
849 g_return_val_if_fail (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), FALSE);
850 g_return_val_if_fail (standard_output == NULL ||
851 !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
852 g_return_val_if_fail (standard_error == NULL ||
853 !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
855 /* Just to ensure segfaults if callers try to use
856 * these when an error is reported.
858 if (standard_output)
859 *standard_output = NULL;
861 if (standard_error)
862 *standard_error = NULL;
864 if (!do_spawn_with_pipes (&status,
865 FALSE,
866 working_directory,
867 argv,
868 envp,
869 flags,
870 child_setup,
871 user_data,
872 NULL,
873 NULL,
874 standard_output ? &outpipe : NULL,
875 standard_error ? &errpipe : NULL,
876 &reportpipe,
877 error))
878 return FALSE;
880 /* Read data from child. */
882 failed = FALSE;
884 if (outpipe >= 0)
886 outstr = g_string_new (NULL);
887 outchannel = g_io_channel_win32_new_fd (outpipe);
888 g_io_channel_set_encoding (outchannel, NULL, NULL);
889 g_io_channel_set_buffered (outchannel, FALSE);
890 g_io_channel_win32_make_pollfd (outchannel,
891 G_IO_IN | G_IO_ERR | G_IO_HUP,
892 &outfd);
893 if (debug)
894 g_print ("outfd=%x\n", outfd.fd);
897 if (errpipe >= 0)
899 errstr = g_string_new (NULL);
900 errchannel = g_io_channel_win32_new_fd (errpipe);
901 g_io_channel_set_encoding (errchannel, NULL, NULL);
902 g_io_channel_set_buffered (errchannel, FALSE);
903 g_io_channel_win32_make_pollfd (errchannel,
904 G_IO_IN | G_IO_ERR | G_IO_HUP,
905 &errfd);
906 if (debug)
907 g_print ("errfd=%x\n", errfd.fd);
910 /* Read data until we get EOF on all pipes. */
911 while (!failed && (outpipe >= 0 || errpipe >= 0))
913 nfds = 0;
914 if (outpipe >= 0)
916 fds[nfds] = outfd;
917 outindex = nfds;
918 nfds++;
920 if (errpipe >= 0)
922 fds[nfds] = errfd;
923 errindex = nfds;
924 nfds++;
927 if (debug)
928 g_print ("g_spawn_sync: calling g_io_channel_win32_poll, nfds=%d\n",
929 nfds);
931 ret = g_io_channel_win32_poll (fds, nfds, -1);
933 if (ret < 0)
935 failed = TRUE;
937 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ,
938 _("Unexpected error in g_io_channel_win32_poll() reading data from a child process"));
940 break;
943 if (outpipe >= 0 && (fds[outindex].revents & G_IO_IN))
945 switch (read_data (outstr, outchannel, error))
947 case READ_FAILED:
948 if (debug)
949 g_print ("g_spawn_sync: outchannel: READ_FAILED\n");
950 failed = TRUE;
951 break;
952 case READ_EOF:
953 if (debug)
954 g_print ("g_spawn_sync: outchannel: READ_EOF\n");
955 g_io_channel_unref (outchannel);
956 outchannel = NULL;
957 close_and_invalidate (&outpipe);
958 break;
959 default:
960 if (debug)
961 g_print ("g_spawn_sync: outchannel: OK\n");
962 break;
965 if (failed)
966 break;
969 if (errpipe >= 0 && (fds[errindex].revents & G_IO_IN))
971 switch (read_data (errstr, errchannel, error))
973 case READ_FAILED:
974 if (debug)
975 g_print ("g_spawn_sync: errchannel: READ_FAILED\n");
976 failed = TRUE;
977 break;
978 case READ_EOF:
979 if (debug)
980 g_print ("g_spawn_sync: errchannel: READ_EOF\n");
981 g_io_channel_unref (errchannel);
982 errchannel = NULL;
983 close_and_invalidate (&errpipe);
984 break;
985 default:
986 if (debug)
987 g_print ("g_spawn_sync: errchannel: OK\n");
988 break;
991 if (failed)
992 break;
996 if (reportpipe == -1)
998 /* No helper process, exit status of actual spawned process
999 * already available.
1001 if (exit_status)
1002 *exit_status = status;
1004 else
1006 /* Helper process was involved. Read its report now after the
1007 * grandchild has finished.
1009 gint helper_report[2];
1011 if (!read_helper_report (reportpipe, helper_report, error))
1012 failed = TRUE;
1013 else
1015 switch (helper_report[0])
1017 case CHILD_NO_ERROR:
1018 if (exit_status)
1019 *exit_status = helper_report[1];
1020 break;
1021 default:
1022 set_child_error (helper_report, working_directory, error);
1023 failed = TRUE;
1024 break;
1027 close_and_invalidate (&reportpipe);
1031 /* These should only be open still if we had an error. */
1033 if (outchannel != NULL)
1034 g_io_channel_unref (outchannel);
1035 if (errchannel != NULL)
1036 g_io_channel_unref (errchannel);
1037 if (outpipe >= 0)
1038 close_and_invalidate (&outpipe);
1039 if (errpipe >= 0)
1040 close_and_invalidate (&errpipe);
1042 if (failed)
1044 if (outstr)
1045 g_string_free (outstr, TRUE);
1046 if (errstr)
1047 g_string_free (errstr, TRUE);
1049 return FALSE;
1051 else
1053 if (standard_output)
1054 *standard_output = g_string_free (outstr, FALSE);
1056 if (standard_error)
1057 *standard_error = g_string_free (errstr, FALSE);
1059 return TRUE;
1063 gboolean
1064 g_spawn_async_with_pipes_utf8 (const gchar *working_directory,
1065 gchar **argv,
1066 gchar **envp,
1067 GSpawnFlags flags,
1068 GSpawnChildSetupFunc child_setup,
1069 gpointer user_data,
1070 GPid *child_handle,
1071 gint *standard_input,
1072 gint *standard_output,
1073 gint *standard_error,
1074 GError **error)
1076 g_return_val_if_fail (argv != NULL, FALSE);
1077 g_return_val_if_fail (standard_output == NULL ||
1078 !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
1079 g_return_val_if_fail (standard_error == NULL ||
1080 !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
1081 /* can't inherit stdin if we have an input pipe. */
1082 g_return_val_if_fail (standard_input == NULL ||
1083 !(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE);
1085 return do_spawn_with_pipes (NULL,
1086 (flags & G_SPAWN_DO_NOT_REAP_CHILD),
1087 working_directory,
1088 argv,
1089 envp,
1090 flags,
1091 child_setup,
1092 user_data,
1093 child_handle,
1094 standard_input,
1095 standard_output,
1096 standard_error,
1097 NULL,
1098 error);
1101 gboolean
1102 g_spawn_command_line_sync_utf8 (const gchar *command_line,
1103 gchar **standard_output,
1104 gchar **standard_error,
1105 gint *exit_status,
1106 GError **error)
1108 gboolean retval;
1109 gchar **argv = 0;
1111 g_return_val_if_fail (command_line != NULL, FALSE);
1113 if (!g_shell_parse_argv (command_line,
1114 NULL, &argv,
1115 error))
1116 return FALSE;
1118 retval = g_spawn_sync_utf8 (NULL,
1119 argv,
1120 NULL,
1121 G_SPAWN_SEARCH_PATH,
1122 NULL,
1123 NULL,
1124 standard_output,
1125 standard_error,
1126 exit_status,
1127 error);
1128 g_strfreev (argv);
1130 return retval;
1133 gboolean
1134 g_spawn_command_line_async_utf8 (const gchar *command_line,
1135 GError **error)
1137 gboolean retval;
1138 gchar **argv = 0;
1140 g_return_val_if_fail (command_line != NULL, FALSE);
1142 if (!g_shell_parse_argv (command_line,
1143 NULL, &argv,
1144 error))
1145 return FALSE;
1147 retval = g_spawn_async_utf8 (NULL,
1148 argv,
1149 NULL,
1150 G_SPAWN_SEARCH_PATH,
1151 NULL,
1152 NULL,
1153 NULL,
1154 error);
1155 g_strfreev (argv);
1157 return retval;
1160 void
1161 g_spawn_close_pid (GPid pid)
1163 CloseHandle (pid);
1166 /* Binary compatibility versions that take system codepage pathnames,
1167 * argument vectors and environments. These get used only by code
1168 * built against 2.8.1 or earlier. Code built against 2.8.2 or later
1169 * will use the _utf8 versions above (see the #defines in gspawn.h).
1172 #undef g_spawn_async
1173 #undef g_spawn_async_with_pipes
1174 #undef g_spawn_sync
1175 #undef g_spawn_command_line_sync
1176 #undef g_spawn_command_line_async
1178 static gboolean
1179 setup_utf8_copies (const gchar *working_directory,
1180 gchar **utf8_working_directory,
1181 gchar **argv,
1182 gchar ***utf8_argv,
1183 gchar **envp,
1184 gchar ***utf8_envp,
1185 GError **error)
1187 gint i, argc, envc;
1189 if (working_directory == NULL)
1190 *utf8_working_directory = NULL;
1191 else
1193 GError *conv_error = NULL;
1195 *utf8_working_directory = g_locale_to_utf8 (working_directory, -1, NULL, NULL, &conv_error);
1196 if (*utf8_working_directory == NULL)
1198 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
1199 _("Invalid working directory: %s"),
1200 conv_error->message);
1201 g_error_free (conv_error);
1202 return FALSE;
1206 argc = 0;
1207 while (argv[argc])
1208 ++argc;
1209 *utf8_argv = g_new (gchar *, argc + 1);
1210 for (i = 0; i < argc; i++)
1212 GError *conv_error = NULL;
1214 (*utf8_argv)[i] = g_locale_to_utf8 (argv[i], -1, NULL, NULL, &conv_error);
1215 if ((*utf8_argv)[i] == NULL)
1217 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
1218 _("Invalid string in argument vector at %d: %s"),
1219 i, conv_error->message);
1220 g_error_free (conv_error);
1222 g_strfreev (*utf8_argv);
1223 *utf8_argv = NULL;
1225 g_free (*utf8_working_directory);
1226 *utf8_working_directory = NULL;
1228 return FALSE;
1231 (*utf8_argv)[argc] = NULL;
1233 if (envp == NULL)
1235 *utf8_envp = NULL;
1237 else
1239 envc = 0;
1240 while (envp[envc])
1241 ++envc;
1242 *utf8_envp = g_new (gchar *, envc + 1);
1243 for (i = 0; i < envc; i++)
1245 GError *conv_error = NULL;
1247 (*utf8_envp)[i] = g_locale_to_utf8 (envp[i], -1, NULL, NULL, &conv_error);
1248 if ((*utf8_envp)[i] == NULL)
1250 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
1251 _("Invalid string in environment: %s"),
1252 conv_error->message);
1253 g_error_free (conv_error);
1255 g_strfreev (*utf8_envp);
1256 *utf8_envp = NULL;
1258 g_strfreev (*utf8_argv);
1259 *utf8_argv = NULL;
1261 g_free (*utf8_working_directory);
1262 *utf8_working_directory = NULL;
1264 return FALSE;
1267 (*utf8_envp)[envc] = NULL;
1269 return TRUE;
1272 static void
1273 free_utf8_copies (gchar *utf8_working_directory,
1274 gchar **utf8_argv,
1275 gchar **utf8_envp)
1277 g_free (utf8_working_directory);
1278 g_strfreev (utf8_argv);
1279 g_strfreev (utf8_envp);
1282 gboolean
1283 g_spawn_async_with_pipes (const gchar *working_directory,
1284 gchar **argv,
1285 gchar **envp,
1286 GSpawnFlags flags,
1287 GSpawnChildSetupFunc child_setup,
1288 gpointer user_data,
1289 GPid *child_handle,
1290 gint *standard_input,
1291 gint *standard_output,
1292 gint *standard_error,
1293 GError **error)
1295 gchar *utf8_working_directory;
1296 gchar **utf8_argv;
1297 gchar **utf8_envp;
1298 gboolean retval;
1300 if (!setup_utf8_copies (working_directory, &utf8_working_directory,
1301 argv, &utf8_argv,
1302 envp, &utf8_envp,
1303 error))
1304 return FALSE;
1306 retval = g_spawn_async_with_pipes_utf8 (utf8_working_directory,
1307 utf8_argv, utf8_envp,
1308 flags, child_setup, user_data,
1309 child_handle,
1310 standard_input, standard_output, standard_error,
1311 error);
1313 free_utf8_copies (utf8_working_directory, utf8_argv, utf8_envp);
1315 return retval;
1318 gboolean
1319 g_spawn_async (const gchar *working_directory,
1320 gchar **argv,
1321 gchar **envp,
1322 GSpawnFlags flags,
1323 GSpawnChildSetupFunc child_setup,
1324 gpointer user_data,
1325 GPid *child_handle,
1326 GError **error)
1328 return g_spawn_async_with_pipes (working_directory,
1329 argv, envp,
1330 flags,
1331 child_setup,
1332 user_data,
1333 child_handle,
1334 NULL, NULL, NULL,
1335 error);
1338 gboolean
1339 g_spawn_sync (const gchar *working_directory,
1340 gchar **argv,
1341 gchar **envp,
1342 GSpawnFlags flags,
1343 GSpawnChildSetupFunc child_setup,
1344 gpointer user_data,
1345 gchar **standard_output,
1346 gchar **standard_error,
1347 gint *exit_status,
1348 GError **error)
1350 gchar *utf8_working_directory;
1351 gchar **utf8_argv;
1352 gchar **utf8_envp;
1353 gboolean retval;
1355 if (!setup_utf8_copies (working_directory, &utf8_working_directory,
1356 argv, &utf8_argv,
1357 envp, &utf8_envp,
1358 error))
1359 return FALSE;
1361 retval = g_spawn_sync_utf8 (utf8_working_directory,
1362 utf8_argv, utf8_envp,
1363 flags, child_setup, user_data,
1364 standard_output, standard_error, exit_status,
1365 error);
1367 free_utf8_copies (utf8_working_directory, utf8_argv, utf8_envp);
1369 return retval;
1372 gboolean
1373 g_spawn_command_line_sync (const gchar *command_line,
1374 gchar **standard_output,
1375 gchar **standard_error,
1376 gint *exit_status,
1377 GError **error)
1379 gboolean retval;
1380 gchar **argv = 0;
1382 g_return_val_if_fail (command_line != NULL, FALSE);
1384 if (!g_shell_parse_argv (command_line,
1385 NULL, &argv,
1386 error))
1387 return FALSE;
1389 retval = g_spawn_sync (NULL,
1390 argv,
1391 NULL,
1392 G_SPAWN_SEARCH_PATH,
1393 NULL,
1394 NULL,
1395 standard_output,
1396 standard_error,
1397 exit_status,
1398 error);
1399 g_strfreev (argv);
1401 return retval;
1404 gboolean
1405 g_spawn_command_line_async (const gchar *command_line,
1406 GError **error)
1408 gboolean retval;
1409 gchar **argv = 0;
1411 g_return_val_if_fail (command_line != NULL, FALSE);
1413 if (!g_shell_parse_argv (command_line,
1414 NULL, &argv,
1415 error))
1416 return FALSE;
1418 retval = g_spawn_async (NULL,
1419 argv,
1420 NULL,
1421 G_SPAWN_SEARCH_PATH,
1422 NULL,
1423 NULL,
1424 NULL,
1425 error);
1426 g_strfreev (argv);
1428 return retval;
1431 #endif /* !GSPAWN_HELPER */
1433 #define __G_SPAWN_C__
1434 #include "galiasdef.c"