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 */
48 #include "gprintfint.h"
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 **);
72 #ifdef G_SPAWN_WIN32_DEBUG
74 #define SETUP_DEBUG() /* empty */
76 static int debug = -1;
77 #define SETUP_DEBUG() \
82 if (getenv ("G_SPAWN_WIN32_DEBUG") != NULL) \
99 ARG_CHILD_ERR_REPORT = 1,
103 ARG_WORKING_DIRECTORY,
104 ARG_CLOSE_DESCRIPTORS,
108 ARG_COUNT = ARG_PROGRAM
112 protect_argv_string (const gchar *string)
114 const gchar *p = string;
117 gboolean need_dblquotes = FALSE;
120 if (*p == ' ' || *p == '\t')
121 need_dblquotes = TRUE;
127 while (*pp && *pp == '\\')
136 q = retval = g_malloc (len + need_dblquotes*2 + 1);
149 while (*pp && *pp == '\\')
166 protect_argv (gchar **argv,
174 *new_argv = g_new (gchar *, argc+1);
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).
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.
187 for (i = 0; i < argc; i++)
188 (*new_argv)[i] = protect_argv_string (argv[i]);
190 (*new_argv)[argc] = NULL;
195 #ifndef GSPAWN_HELPER
197 #define HELPER_PROCESS "gspawn-win32-helper"
200 g_spawn_error_quark (void)
202 static GQuark quark = 0;
204 quark = g_quark_from_static_string ("g-exec-error-quark");
209 g_spawn_async_utf8 (const gchar *working_directory,
213 GSpawnChildSetupFunc child_setup,
218 g_return_val_if_fail (argv != NULL, FALSE);
220 return g_spawn_async_with_pipes_utf8 (working_directory,
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)
235 close_and_invalidate (gint *fd)
246 READ_FAILED = 0, /* FALSE */
252 read_data (GString *str,
253 GIOChannel *iochannel,
262 giostatus = g_io_channel_read_chars (iochannel, buf, sizeof (buf), &bytes, NULL);
268 g_string_append_len (str, buf, bytes);
271 else if (giostatus == G_IO_STATUS_AGAIN)
273 else if (giostatus == G_IO_STATUS_ERROR)
275 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ,
276 _("Failed to read data from child process"));
285 make_pipe (gint p[2],
290 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
291 _("Failed to create pipe for communicating with child process (%s)"),
299 /* The helper process writes a status report back to us, through a
300 * pipe, consisting of two ints.
303 read_helper_report (int fd,
309 while (bytes < sizeof(gint)*2)
314 g_print ("%s:read_helper_report: read %d...\n",
316 sizeof(gint)*2 - bytes);
318 chunk = read (fd, ((gchar*)report) + bytes,
319 sizeof(gint)*2 - bytes);
322 g_print ("...got %d bytes\n", chunk);
326 /* Some weird shit happened, bail out */
328 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
329 _("Failed to read from child pipe (%s)"),
340 if (bytes < sizeof(gint)*2)
347 set_child_error (gint report[2],
348 const gchar *working_directory,
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)"),
357 g_strerror (report[1]));
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]));
365 g_assert_not_reached ();
370 utf8_charv_to_wcharv (char **utf8_charv,
375 wchar_t **retval = NULL;
378 if (utf8_charv != NULL)
382 while (utf8_charv[n])
384 retval = g_new (wchar_t *, n + 1);
386 for (i = 0; i < n; i++)
388 retval[i] = g_utf8_to_utf16 (utf8_charv[i], -1, NULL, NULL, error);
389 if (retval[i] == NULL)
394 g_free (retval[--i]);
407 utf8_charv_to_cp_charv (char **utf8_charv,
412 char **retval = NULL;
415 if (utf8_charv != NULL)
419 while (utf8_charv[n])
421 retval = g_new (char *, n + 1);
423 for (i = 0; i < n; i++)
425 retval[i] = g_locale_from_utf8 (utf8_charv[i], -1, NULL, NULL, error);
426 if (retval[i] == NULL)
431 g_free (retval[--i]);
444 do_spawn_directly (gboolean dont_wait,
445 gboolean dont_return_handle,
449 char **protected_argv,
450 GSpawnChildSetupFunc child_setup,
456 int mode = dont_wait ? P_NOWAIT : P_WAIT;
460 GError *conv_error = NULL;
461 gint conv_error_index;
463 new_argv = (flags & G_SPAWN_FILE_AND_ARGV_ZERO) ? protected_argv + 1 : protected_argv;
464 if (G_WIN32_HAVE_WIDECHAR_API ())
466 wchar_t *wargv0, **wargv, **wenvp;
468 wargv0 = g_utf8_to_utf16 (argv[0], -1, NULL, NULL, &conv_error);
471 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
472 _("Invalid program name: %s"),
473 conv_error->message);
474 g_error_free (conv_error);
479 if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error))
481 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
482 _("Invalid string in argument vector at %d: %s"),
483 conv_error_index, conv_error->message);
484 g_error_free (conv_error);
490 if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error))
492 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
493 _("Invalid string in environment: %s"),
494 conv_error->message);
495 g_error_free (conv_error);
497 g_strfreev ((gchar **) wargv);
503 (* child_setup) (user_data);
505 if (flags & G_SPAWN_SEARCH_PATH)
507 rc = _wspawnvpe (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp);
509 rc = _wspawnvp (mode, wargv0, (const wchar_t **) wargv);
512 rc = _wspawnve (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp);
514 rc = _wspawnv (mode, wargv0, (const wchar_t **) wargv);
517 g_strfreev ((gchar **) wargv);
518 g_strfreev ((gchar **) wenvp);
522 char *cpargv0, **cpargv, **cpenvp;
524 cpargv0 = g_locale_from_utf8 (argv[0], -1, NULL, NULL, &conv_error);
527 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
528 _("Invalid program name: %s"),
529 conv_error->message);
530 g_error_free (conv_error);
535 if (!utf8_charv_to_cp_charv (new_argv, &cpargv, &conv_error_index, &conv_error))
537 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
538 _("Invalid string in argument vector at %d: %s"),
539 conv_error_index, conv_error->message);
540 g_error_free (conv_error);
546 if (!utf8_charv_to_cp_charv (envp, &cpenvp, NULL, &conv_error))
548 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
549 _("Invalid string in environment: %s"),
550 conv_error->message);
551 g_error_free (conv_error);
559 (* child_setup) (user_data);
561 if (flags & G_SPAWN_SEARCH_PATH)
563 rc = spawnvpe (mode, cpargv0, (const char **) cpargv, (const char **) cpenvp);
565 rc = spawnvp (mode, cpargv0, (const char **) cpargv);
568 rc = spawnve (mode, cpargv0, (const char **) cpargv, (const char **) cpenvp);
570 rc = spawnv (mode, cpargv0, (const char **) cpargv);
579 if (rc == -1 && saved_errno != 0)
581 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
582 _("Failed to execute child process (%s)"),
583 g_strerror (saved_errno));
589 if (child_handle && !dont_return_handle)
590 *child_handle = (GPid) rc;
593 CloseHandle ((HANDLE) rc);
598 else if (exit_status)
605 do_spawn_with_pipes (gboolean dont_wait,
606 gboolean dont_return_handle,
607 const gchar *working_directory,
611 GSpawnChildSetupFunc child_setup,
614 gint *standard_input,
615 gint *standard_output,
616 gint *standard_error,
621 char **protected_argv;
622 char args[ARG_COUNT][10];
628 int stdin_pipe[2] = { -1, -1 };
629 int stdout_pipe[2] = { -1, -1 };
630 int stderr_pipe[2] = { -1, -1 };
631 int child_err_report_pipe[2] = { -1, -1 };
632 int helper_report[2];
633 static gboolean warned_about_child_setup = FALSE;
634 GError *conv_error = NULL;
635 gint conv_error_index;
639 if (child_setup && !warned_about_child_setup)
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");
645 argc = protect_argv (argv, &protected_argv);
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))
654 /* We can do without the helper process */
656 do_spawn_directly (dont_wait, dont_return_handle, flags,
657 argv, envp, protected_argv,
658 child_setup, user_data, child_handle,
660 g_strfreev (protected_argv);
664 if (standard_input && !make_pipe (stdin_pipe, error))
665 goto cleanup_and_fail;
667 if (standard_output && !make_pipe (stdout_pipe, error))
668 goto cleanup_and_fail;
670 if (standard_error && !make_pipe (stderr_pipe, error))
671 goto cleanup_and_fail;
673 if (!make_pipe (child_err_report_pipe, error))
674 goto cleanup_and_fail;
676 new_argv = g_new (char *, argc + 1 + ARG_COUNT);
677 new_argv[0] = HELPER_PROCESS;
678 _g_sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_pipe[1]);
679 new_argv[ARG_CHILD_ERR_REPORT] = args[ARG_CHILD_ERR_REPORT];
681 if (flags & G_SPAWN_FILE_AND_ARGV_ZERO)
683 /* Overload ARG_CHILD_ERR_REPORT to also encode the
684 * G_SPAWN_FILE_AND_ARGV_ZERO functionality.
686 strcat (args[ARG_CHILD_ERR_REPORT], "#");
691 _g_sprintf (args[ARG_STDIN], "%d", stdin_pipe[0]);
692 new_argv[ARG_STDIN] = args[ARG_STDIN];
694 else if (flags & G_SPAWN_CHILD_INHERITS_STDIN)
696 /* Let stdin be alone */
697 new_argv[ARG_STDIN] = "-";
701 /* Keep process from blocking on a read of stdin */
702 new_argv[ARG_STDIN] = "z";
707 _g_sprintf (args[ARG_STDOUT], "%d", stdout_pipe[1]);
708 new_argv[ARG_STDOUT] = args[ARG_STDOUT];
710 else if (flags & G_SPAWN_STDOUT_TO_DEV_NULL)
712 new_argv[ARG_STDOUT] = "z";
716 new_argv[ARG_STDOUT] = "-";
721 _g_sprintf (args[ARG_STDERR], "%d", stderr_pipe[1]);
722 new_argv[ARG_STDERR] = args[ARG_STDERR];
724 else if (flags & G_SPAWN_STDERR_TO_DEV_NULL)
726 new_argv[ARG_STDERR] = "z";
730 new_argv[ARG_STDERR] = "-";
733 if (working_directory && *working_directory)
734 new_argv[ARG_WORKING_DIRECTORY] = protect_argv_string (working_directory);
736 new_argv[ARG_WORKING_DIRECTORY] = g_strdup ("-");
738 if (!(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN))
739 new_argv[ARG_CLOSE_DESCRIPTORS] = "y";
741 new_argv[ARG_CLOSE_DESCRIPTORS] = "-";
743 if (flags & G_SPAWN_SEARCH_PATH)
744 new_argv[ARG_USE_PATH] = "y";
746 new_argv[ARG_USE_PATH] = "-";
749 new_argv[ARG_WAIT] = "-";
751 new_argv[ARG_WAIT] = "w";
753 for (i = 0; i <= argc; i++)
754 new_argv[ARG_PROGRAM + i] = protected_argv[i];
758 g_print ("calling " HELPER_PROCESS " with argv:\n");
759 for (i = 0; i < argc + 1 + ARG_COUNT; i++)
760 g_print ("argv[%d]: %s\n", i, (new_argv[i] ? new_argv[i] : "NULL"));
763 if (G_WIN32_HAVE_WIDECHAR_API ())
765 wchar_t *whelper = g_utf8_to_utf16 (HELPER_PROCESS, -1, NULL, NULL, NULL);
766 wchar_t **wargv, **wenvp;
768 if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error))
770 if (conv_error_index == ARG_WORKING_DIRECTORY)
771 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
772 _("Invalid working directory: %s"),
773 conv_error->message);
775 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
776 _("Invalid string in argument vector at %d: %s"),
777 conv_error_index - ARG_PROGRAM, conv_error->message);
778 g_error_free (conv_error);
779 g_strfreev (protected_argv);
780 g_free (new_argv[ARG_WORKING_DIRECTORY]);
787 if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error))
789 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
790 _("Invalid string in environment: %s"),
791 conv_error->message);
792 g_error_free (conv_error);
793 g_strfreev (protected_argv);
794 g_free (new_argv[ARG_WORKING_DIRECTORY]);
797 g_strfreev ((gchar **) wargv);
803 (* child_setup) (user_data);
806 /* Let's hope envp hasn't mucked with PATH so that
807 * gspawn-win32-helper.exe isn't found.
809 rc = _wspawnvpe (P_NOWAIT, whelper, (const wchar_t **) wargv, (const wchar_t **) wenvp);
811 rc = _wspawnvp (P_NOWAIT, whelper, (const wchar_t **) wargv);
816 g_strfreev ((gchar **) wargv);
817 g_strfreev ((gchar **) wenvp);
821 char **cpargv, **cpenvp;
823 if (!utf8_charv_to_cp_charv (new_argv, &cpargv, &conv_error_index, &conv_error))
825 if (conv_error_index == ARG_WORKING_DIRECTORY)
826 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
827 _("Invalid working directory: %s"),
828 conv_error->message);
830 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
831 _("Invalid string in argument vector at %d: %s"),
832 conv_error_index - ARG_PROGRAM, conv_error->message);
833 g_error_free (conv_error);
834 g_strfreev (protected_argv);
835 g_free (new_argv[ARG_WORKING_DIRECTORY]);
841 if (!utf8_charv_to_cp_charv (envp, &cpenvp, NULL, &conv_error))
843 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
844 _("Invalid string in environment: %s"),
845 conv_error->message);
846 g_error_free (conv_error);
847 g_strfreev (protected_argv);
848 g_free (new_argv[ARG_WORKING_DIRECTORY]);
856 (* child_setup) (user_data);
859 rc = spawnvpe (P_NOWAIT, HELPER_PROCESS, (const char **) cpargv, (const char **) cpenvp);
861 rc = spawnvp (P_NOWAIT, HELPER_PROCESS, (const char **) cpargv);
869 /* Close the other process's ends of the pipes in this process,
870 * otherwise the reader will never get EOF.
872 close_and_invalidate (&child_err_report_pipe[1]);
873 close_and_invalidate (&stdin_pipe[0]);
874 close_and_invalidate (&stdout_pipe[1]);
875 close_and_invalidate (&stderr_pipe[1]);
877 g_strfreev (protected_argv);
879 g_free (new_argv[ARG_WORKING_DIRECTORY]);
882 /* Check if gspawn-win32-helper couldn't be run */
883 if (rc == -1 && saved_errno != 0)
885 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
886 _("Failed to execute helper program (%s)"),
887 g_strerror (saved_errno));
888 goto cleanup_and_fail;
893 /* Synchronous case. Pass helper's report pipe back to caller,
894 * which takes care of reading it after the grandchild has
897 g_assert (err_report != NULL);
898 *err_report = child_err_report_pipe[0];
902 /* Asynchronous case. We read the helper's report right away. */
903 if (!read_helper_report (child_err_report_pipe[0], helper_report, error))
904 goto cleanup_and_fail;
906 close (child_err_report_pipe[0]);
908 switch (helper_report[0])
911 if (child_handle && dont_wait && !dont_return_handle)
913 /* rc is our HANDLE for gspawn-win32-helper. It has
914 * told us the HANDLE of its child. Duplicate that into
915 * a HANDLE valid in this process.
917 if (!DuplicateHandle ((HANDLE) rc, (HANDLE) helper_report[1],
918 GetCurrentProcess (), (LPHANDLE) child_handle,
919 0, TRUE, DUPLICATE_SAME_ACCESS))
922 else if (child_handle)
925 *exit_status = helper_report[1];
929 set_child_error (helper_report, working_directory, error);
930 goto cleanup_and_fail;
934 /* Success against all odds! return the information */
937 *standard_input = stdin_pipe[1];
939 *standard_output = stdout_pipe[0];
941 *standard_error = stderr_pipe[0];
943 CloseHandle ((HANDLE) rc);
949 CloseHandle ((HANDLE) rc);
950 if (child_err_report_pipe[0] != -1)
951 close (child_err_report_pipe[0]);
952 if (child_err_report_pipe[1] != -1)
953 close (child_err_report_pipe[1]);
954 if (stdin_pipe[0] != -1)
955 close (stdin_pipe[0]);
956 if (stdin_pipe[1] != -1)
957 close (stdin_pipe[1]);
958 if (stdout_pipe[0] != -1)
959 close (stdout_pipe[0]);
960 if (stdout_pipe[1] != -1)
961 close (stdout_pipe[1]);
962 if (stderr_pipe[0] != -1)
963 close (stderr_pipe[0]);
964 if (stderr_pipe[1] != -1)
965 close (stderr_pipe[1]);
971 g_spawn_sync_utf8 (const gchar *working_directory,
975 GSpawnChildSetupFunc child_setup,
977 gchar **standard_output,
978 gchar **standard_error,
984 gint reportpipe = -1;
985 GIOChannel *outchannel = NULL;
986 GIOChannel *errchannel = NULL;
987 GPollFD outfd, errfd;
993 GString *outstr = NULL;
994 GString *errstr = NULL;
998 g_return_val_if_fail (argv != NULL, FALSE);
999 g_return_val_if_fail (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), FALSE);
1000 g_return_val_if_fail (standard_output == NULL ||
1001 !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
1002 g_return_val_if_fail (standard_error == NULL ||
1003 !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
1005 /* Just to ensure segfaults if callers try to use
1006 * these when an error is reported.
1008 if (standard_output)
1009 *standard_output = NULL;
1012 *standard_error = NULL;
1014 if (!do_spawn_with_pipes (FALSE,
1024 standard_output ? &outpipe : NULL,
1025 standard_error ? &errpipe : NULL,
1031 /* Read data from child. */
1037 outstr = g_string_new (NULL);
1038 outchannel = g_io_channel_win32_new_fd (outpipe);
1039 g_io_channel_set_encoding (outchannel, NULL, NULL);
1040 g_io_channel_win32_make_pollfd (outchannel,
1041 G_IO_IN | G_IO_ERR | G_IO_HUP,
1047 errstr = g_string_new (NULL);
1048 errchannel = g_io_channel_win32_new_fd (errpipe);
1049 g_io_channel_set_encoding (errchannel, NULL, NULL);
1050 g_io_channel_win32_make_pollfd (errchannel,
1051 G_IO_IN | G_IO_ERR | G_IO_HUP,
1055 /* Read data until we get EOF on all pipes. */
1056 while (!failed && (outpipe >= 0 || errpipe >= 0))
1073 g_print ("g_spawn_sync: calling g_io_channel_win32_poll, nfds=%d\n",
1076 ret = g_io_channel_win32_poll (fds, nfds, -1);
1082 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ,
1083 _("Unexpected error in g_io_channel_win32_poll() reading data from a child process"));
1088 if (outpipe >= 0 && (fds[outindex].revents & G_IO_IN))
1090 switch (read_data (outstr, outchannel, error))
1094 g_print ("g_spawn_sync: outchannel: READ_FAILED\n");
1099 g_print ("g_spawn_sync: outchannel: READ_EOF\n");
1100 g_io_channel_unref (outchannel);
1102 close_and_invalidate (&outpipe);
1106 g_print ("g_spawn_sync: outchannel: OK\n");
1114 if (errpipe >= 0 && (fds[errindex].revents & G_IO_IN))
1116 switch (read_data (errstr, errchannel, error))
1120 g_print ("g_spawn_sync: errchannel: READ_FAILED\n");
1125 g_print ("g_spawn_sync: errchannel: READ_EOF\n");
1126 g_io_channel_unref (errchannel);
1128 close_and_invalidate (&errpipe);
1132 g_print ("g_spawn_sync: errchannel: OK\n");
1141 if (reportpipe == -1)
1143 /* No helper process, exit status of actual spawned process
1144 * already available.
1147 *exit_status = status;
1151 /* Helper process was involved. Read its report now after the
1152 * grandchild has finished.
1154 gint helper_report[2];
1156 if (!read_helper_report (reportpipe, helper_report, error))
1160 switch (helper_report[0])
1162 case CHILD_NO_ERROR:
1164 *exit_status = helper_report[1];
1167 set_child_error (helper_report, working_directory, error);
1172 close_and_invalidate (&reportpipe);
1176 /* These should only be open still if we had an error. */
1178 if (outchannel != NULL)
1179 g_io_channel_unref (outchannel);
1180 if (errchannel != NULL)
1181 g_io_channel_unref (errchannel);
1183 close_and_invalidate (&outpipe);
1185 close_and_invalidate (&errpipe);
1190 g_string_free (outstr, TRUE);
1192 g_string_free (errstr, TRUE);
1198 if (standard_output)
1199 *standard_output = g_string_free (outstr, FALSE);
1202 *standard_error = g_string_free (errstr, FALSE);
1209 g_spawn_async_with_pipes_utf8 (const gchar *working_directory,
1213 GSpawnChildSetupFunc child_setup,
1216 gint *standard_input,
1217 gint *standard_output,
1218 gint *standard_error,
1221 g_return_val_if_fail (argv != NULL, FALSE);
1222 g_return_val_if_fail (standard_output == NULL ||
1223 !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
1224 g_return_val_if_fail (standard_error == NULL ||
1225 !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
1226 /* can't inherit stdin if we have an input pipe. */
1227 g_return_val_if_fail (standard_input == NULL ||
1228 !(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE);
1230 return do_spawn_with_pipes (TRUE,
1231 !(flags & G_SPAWN_DO_NOT_REAP_CHILD),
1248 g_spawn_command_line_sync_utf8 (const gchar *command_line,
1249 gchar **standard_output,
1250 gchar **standard_error,
1257 g_return_val_if_fail (command_line != NULL, FALSE);
1259 if (!g_shell_parse_argv (command_line,
1264 retval = g_spawn_sync_utf8 (NULL,
1267 G_SPAWN_SEARCH_PATH,
1280 g_spawn_command_line_async_utf8 (const gchar *command_line,
1286 g_return_val_if_fail (command_line != NULL, FALSE);
1288 if (!g_shell_parse_argv (command_line,
1293 retval = g_spawn_async_utf8 (NULL,
1296 G_SPAWN_SEARCH_PATH,
1307 g_spawn_close_pid (GPid pid)
1312 /* Binary compatibility versions that take system codepage pathnames,
1313 * argument vectors and environments. These get used only by code
1314 * built against 2.8.1 or earlier. Code built against 2.8.2 or later
1315 * will use the _utf8 versions above (see the #defines in gspawn.h).
1318 #undef g_spawn_async
1319 #undef g_spawn_async_with_pipes
1321 #undef g_spawn_command_line_sync
1322 #undef g_spawn_command_line_async
1325 setup_utf8_copies (const gchar *working_directory,
1326 gchar **utf8_working_directory,
1335 if (working_directory == NULL)
1336 *utf8_working_directory = NULL;
1339 GError *conv_error = NULL;
1341 *utf8_working_directory = g_locale_to_utf8 (working_directory, -1, NULL, NULL, &conv_error);
1342 if (*utf8_working_directory == NULL)
1344 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
1345 _("Invalid working directory: %s"),
1346 conv_error->message);
1347 g_error_free (conv_error);
1355 *utf8_argv = g_new (gchar *, argc + 1);
1356 for (i = 0; i < argc; i++)
1358 GError *conv_error = NULL;
1360 (*utf8_argv)[i] = g_locale_to_utf8 (argv[i], -1, NULL, NULL, &conv_error);
1361 if ((*utf8_argv)[i] == NULL)
1363 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
1364 _("Invalid string in argument vector at %d: %s"),
1365 i, conv_error->message);
1366 g_error_free (conv_error);
1368 g_strfreev (*utf8_argv);
1371 g_free (*utf8_working_directory);
1372 *utf8_working_directory = NULL;
1377 (*utf8_argv)[argc] = NULL;
1388 *utf8_envp = g_new (gchar *, envc + 1);
1389 for (i = 0; i < envc; i++)
1391 GError *conv_error = NULL;
1393 (*utf8_envp)[i] = g_locale_to_utf8 (envp[i], -1, NULL, NULL, &conv_error);
1394 if ((*utf8_envp)[i] == NULL)
1396 g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
1397 _("Invalid string in environment: %s"),
1398 conv_error->message);
1399 g_error_free (conv_error);
1401 g_strfreev (*utf8_envp);
1404 g_strfreev (*utf8_argv);
1407 g_free (*utf8_working_directory);
1408 *utf8_working_directory = NULL;
1413 (*utf8_envp)[envc] = NULL;
1419 free_utf8_copies (gchar *utf8_working_directory,
1423 g_free (utf8_working_directory);
1424 g_strfreev (utf8_argv);
1425 g_strfreev (utf8_envp);
1429 g_spawn_async_with_pipes (const gchar *working_directory,
1433 GSpawnChildSetupFunc child_setup,
1436 gint *standard_input,
1437 gint *standard_output,
1438 gint *standard_error,
1441 gchar *utf8_working_directory;
1446 if (!setup_utf8_copies (working_directory, &utf8_working_directory,
1452 retval = g_spawn_async_with_pipes_utf8 (utf8_working_directory,
1453 utf8_argv, utf8_envp,
1454 flags, child_setup, user_data,
1456 standard_input, standard_output, standard_error,
1459 free_utf8_copies (utf8_working_directory, utf8_argv, utf8_envp);
1465 g_spawn_async (const gchar *working_directory,
1469 GSpawnChildSetupFunc child_setup,
1474 return g_spawn_async_with_pipes (working_directory,
1485 g_spawn_sync (const gchar *working_directory,
1489 GSpawnChildSetupFunc child_setup,
1491 gchar **standard_output,
1492 gchar **standard_error,
1496 gchar *utf8_working_directory;
1501 if (!setup_utf8_copies (working_directory, &utf8_working_directory,
1507 retval = g_spawn_sync_utf8 (utf8_working_directory,
1508 utf8_argv, utf8_envp,
1509 flags, child_setup, user_data,
1510 standard_output, standard_error, exit_status,
1513 free_utf8_copies (utf8_working_directory, utf8_argv, utf8_envp);
1519 g_spawn_command_line_sync (const gchar *command_line,
1520 gchar **standard_output,
1521 gchar **standard_error,
1528 g_return_val_if_fail (command_line != NULL, FALSE);
1530 if (!g_shell_parse_argv (command_line,
1535 retval = g_spawn_sync (NULL,
1538 G_SPAWN_SEARCH_PATH,
1551 g_spawn_command_line_async (const gchar *command_line,
1557 g_return_val_if_fail (command_line != NULL, FALSE);
1559 if (!g_shell_parse_argv (command_line,
1564 retval = g_spawn_async (NULL,
1567 G_SPAWN_SEARCH_PATH,
1577 #endif /* !GSPAWN_HELPER */
1579 #define __G_SPAWN_C__
1580 #include "galiasdef.c"