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"
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 **);
71
#ifdef G_SPAWN_WIN32_DEBUG
73
#define SETUP_DEBUG() /* empty */
75
static int debug = -1;
76
#define SETUP_DEBUG() \
81
if (getenv ("G_SPAWN_WIN32_DEBUG") != NULL) \
98
ARG_CHILD_ERR_REPORT = 1,
102
ARG_WORKING_DIRECTORY,
103
ARG_CLOSE_DESCRIPTORS,
107
ARG_COUNT = ARG_PROGRAM
111
protect_argv_string (const gchar *string)
113
const gchar *p = string;
116
gboolean need_dblquotes = FALSE;
119
if (*p == ' ' || *p == '\t')
120
need_dblquotes = TRUE;
126
while (*pp && *pp == '\\')
135
q = retval = g_malloc (len + need_dblquotes*2 + 1);
148
while (*pp && *pp == '\\')
165
protect_argv (gchar **argv,
173
*new_argv = g_new (gchar *, argc+1);
175
/* Quote each argv element if necessary, so that it will get
176
* reconstructed correctly in the C runtime startup code. Note that
177
* the unquoting algorithm in the C runtime is really weird, and
178
* rather different than what Unix shells do. See stdargv.c in the C
179
* runtime sources (in the Platform SDK, in src/crt).
181
* Note that an new_argv[0] constructed by this function should
182
* *not* be passed as the filename argument to a spawn* or exec*
183
* family function. That argument should be the real file name
184
* without any quoting.
186
for (i = 0; i < argc; i++)
187
(*new_argv)[i] = protect_argv_string (argv[i]);
189
(*new_argv)[argc] = NULL;
194
#ifndef GSPAWN_HELPER
196
#define HELPER_PROCESS "gspawn-win32-helper"
199
g_spawn_error_quark (void)
201
return g_quark_from_static_string ("g-exec-error-quark");
205
g_spawn_async_utf8 (const gchar *working_directory,
209
GSpawnChildSetupFunc child_setup,
214
g_return_val_if_fail (argv != NULL, FALSE);
216
return g_spawn_async_with_pipes_utf8 (working_directory,
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)
231
close_and_invalidate (gint *fd)
242
READ_FAILED = 0, /* FALSE */
248
read_data (GString *str,
249
GIOChannel *iochannel,
258
giostatus = g_io_channel_read_chars (iochannel, buf, sizeof (buf), &bytes, NULL);
264
g_string_append_len (str, buf, bytes);
267
else if (giostatus == G_IO_STATUS_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"));
281
make_pipe (gint p[2],
286
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
287
_("Failed to create pipe for communicating with child process (%s)"),
295
/* The helper process writes a status report back to us, through a
296
* pipe, consisting of two ints.
299
read_helper_report (int fd,
305
while (bytes < sizeof(gint)*2)
310
g_print ("%s:read_helper_report: read %d...\n",
312
sizeof(gint)*2 - bytes);
314
chunk = read (fd, ((gchar*)report) + bytes,
315
sizeof(gint)*2 - bytes);
318
g_print ("...got %d bytes\n", chunk);
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)"),
336
if (bytes < sizeof(gint)*2)
343
set_child_error (gint report[2],
344
const gchar *working_directory,
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)"),
353
g_strerror (report[1]));
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]));
361
g_assert_not_reached ();
366
utf8_charv_to_wcharv (char **utf8_charv,
371
wchar_t **retval = NULL;
374
if (utf8_charv != NULL)
378
while (utf8_charv[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)
390
g_free (retval[--i]);
403
utf8_charv_to_cp_charv (char **utf8_charv,
408
char **retval = NULL;
411
if (utf8_charv != NULL)
415
while (utf8_charv[n])
417
retval = g_new (char *, n + 1);
419
for (i = 0; i < n; i++)
421
retval[i] = g_locale_from_utf8 (utf8_charv[i], -1, NULL, NULL, error);
422
if (retval[i] == NULL)
427
g_free (retval[--i]);
440
do_spawn_directly (gint *exit_status,
441
gboolean do_return_handle,
445
char **protected_argv,
446
GSpawnChildSetupFunc child_setup,
451
const int mode = (exit_status == NULL) ? P_NOWAIT : P_WAIT;
455
GError *conv_error = NULL;
456
gint conv_error_index;
458
new_argv = (flags & G_SPAWN_FILE_AND_ARGV_ZERO) ? protected_argv + 1 : protected_argv;
459
if (G_WIN32_HAVE_WIDECHAR_API ())
461
wchar_t *wargv0, **wargv, **wenvp;
463
wargv0 = g_utf8_to_utf16 (argv[0], -1, NULL, NULL, &conv_error);
466
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
467
_("Invalid program name: %s"),
468
conv_error->message);
469
g_error_free (conv_error);
474
if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error))
476
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
477
_("Invalid string in argument vector at %d: %s"),
478
conv_error_index, conv_error->message);
479
g_error_free (conv_error);
485
if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error))
487
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
488
_("Invalid string in environment: %s"),
489
conv_error->message);
490
g_error_free (conv_error);
492
g_strfreev ((gchar **) wargv);
498
(* child_setup) (user_data);
500
if (flags & G_SPAWN_SEARCH_PATH)
502
rc = _wspawnvpe (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp);
504
rc = _wspawnvp (mode, wargv0, (const wchar_t **) wargv);
507
rc = _wspawnve (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp);
509
rc = _wspawnv (mode, wargv0, (const wchar_t **) wargv);
512
g_strfreev ((gchar **) wargv);
513
g_strfreev ((gchar **) wenvp);
517
char *cpargv0, **cpargv, **cpenvp;
519
cpargv0 = g_locale_from_utf8 (argv[0], -1, NULL, NULL, &conv_error);
522
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
523
_("Invalid program name: %s"),
524
conv_error->message);
525
g_error_free (conv_error);
530
if (!utf8_charv_to_cp_charv (new_argv, &cpargv, &conv_error_index, &conv_error))
532
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
533
_("Invalid string in argument vector at %d: %s"),
534
conv_error_index, conv_error->message);
535
g_error_free (conv_error);
541
if (!utf8_charv_to_cp_charv (envp, &cpenvp, NULL, &conv_error))
543
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
544
_("Invalid string in environment: %s"),
545
conv_error->message);
546
g_error_free (conv_error);
554
(* child_setup) (user_data);
556
if (flags & G_SPAWN_SEARCH_PATH)
558
rc = spawnvpe (mode, cpargv0, (const char **) cpargv, (const char **) cpenvp);
560
rc = spawnvp (mode, cpargv0, (const char **) cpargv);
563
rc = spawnve (mode, cpargv0, (const char **) cpargv, (const char **) cpenvp);
565
rc = spawnv (mode, cpargv0, (const char **) cpargv);
574
if (rc == -1 && saved_errno != 0)
576
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
577
_("Failed to execute child process (%s)"),
578
g_strerror (saved_errno));
582
if (exit_status == NULL)
584
if (child_handle && do_return_handle)
585
*child_handle = (GPid) rc;
588
CloseHandle ((HANDLE) rc);
600
do_spawn_with_pipes (gint *exit_status,
601
gboolean do_return_handle,
602
const gchar *working_directory,
606
GSpawnChildSetupFunc child_setup,
609
gint *standard_input,
610
gint *standard_output,
611
gint *standard_error,
615
char **protected_argv;
616
char args[ARG_COUNT][10];
622
int stdin_pipe[2] = { -1, -1 };
623
int stdout_pipe[2] = { -1, -1 };
624
int stderr_pipe[2] = { -1, -1 };
625
int child_err_report_pipe[2] = { -1, -1 };
626
int helper_report[2];
627
static gboolean warned_about_child_setup = FALSE;
628
GError *conv_error = NULL;
629
gint conv_error_index;
630
gchar *helper_process;
631
CONSOLE_CURSOR_INFO cursor_info;
635
if (child_setup && !warned_about_child_setup)
637
warned_about_child_setup = TRUE;
638
g_warning ("passing a child setup function to the g_spawn functions is pointless and dangerous on Win32");
641
argc = protect_argv (argv, &protected_argv);
643
if (!standard_input && !standard_output && !standard_error &&
644
(flags & G_SPAWN_CHILD_INHERITS_STDIN) &&
645
!(flags & G_SPAWN_STDOUT_TO_DEV_NULL) &&
646
!(flags & G_SPAWN_STDERR_TO_DEV_NULL) &&
647
(working_directory == NULL || !*working_directory) &&
648
(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN))
650
/* We can do without the helper process */
652
do_spawn_directly (exit_status, do_return_handle, flags,
653
argv, envp, protected_argv,
654
child_setup, user_data, child_handle,
656
g_strfreev (protected_argv);
660
if (standard_input && !make_pipe (stdin_pipe, error))
661
goto cleanup_and_fail;
663
if (standard_output && !make_pipe (stdout_pipe, error))
664
goto cleanup_and_fail;
666
if (standard_error && !make_pipe (stderr_pipe, error))
667
goto cleanup_and_fail;
669
if (!make_pipe (child_err_report_pipe, error))
670
goto cleanup_and_fail;
672
new_argv = g_new (char *, argc + 1 + ARG_COUNT);
673
if (GetConsoleCursorInfo (GetStdHandle (STD_OUTPUT_HANDLE), &cursor_info))
674
helper_process = HELPER_PROCESS "-console.exe";
676
helper_process = HELPER_PROCESS ".exe";
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] = "-";
748
if (exit_status == NULL)
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 %s with argv:\n", helper_process);
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;
891
if (exit_status != NULL)
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 && do_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)
927
set_child_error (helper_report, working_directory, error);
928
goto cleanup_and_fail;
932
/* Success against all odds! return the information */
935
*standard_input = stdin_pipe[1];
937
*standard_output = stdout_pipe[0];
939
*standard_error = stderr_pipe[0];
941
CloseHandle ((HANDLE) rc);
947
CloseHandle ((HANDLE) rc);
948
if (child_err_report_pipe[0] != -1)
949
close (child_err_report_pipe[0]);
950
if (child_err_report_pipe[1] != -1)
951
close (child_err_report_pipe[1]);
952
if (stdin_pipe[0] != -1)
953
close (stdin_pipe[0]);
954
if (stdin_pipe[1] != -1)
955
close (stdin_pipe[1]);
956
if (stdout_pipe[0] != -1)
957
close (stdout_pipe[0]);
958
if (stdout_pipe[1] != -1)
959
close (stdout_pipe[1]);
960
if (stderr_pipe[0] != -1)
961
close (stderr_pipe[0]);
962
if (stderr_pipe[1] != -1)
963
close (stderr_pipe[1]);
969
g_spawn_sync_utf8 (const gchar *working_directory,
973
GSpawnChildSetupFunc child_setup,
975
gchar **standard_output,
976
gchar **standard_error,
982
gint reportpipe = -1;
983
GIOChannel *outchannel = NULL;
984
GIOChannel *errchannel = NULL;
985
GPollFD outfd, errfd;
991
GString *outstr = NULL;
992
GString *errstr = NULL;
996
g_return_val_if_fail (argv != NULL, FALSE);
997
g_return_val_if_fail (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), FALSE);
998
g_return_val_if_fail (standard_output == NULL ||
999
!(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
1000
g_return_val_if_fail (standard_error == NULL ||
1001
!(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
1003
/* Just to ensure segfaults if callers try to use
1004
* these when an error is reported.
1006
if (standard_output)
1007
*standard_output = NULL;
1010
*standard_error = NULL;
1012
if (!do_spawn_with_pipes (&status,
1022
standard_output ? &outpipe : NULL,
1023
standard_error ? &errpipe : NULL,
1028
/* Read data from child. */
1034
outstr = g_string_new (NULL);
1035
outchannel = g_io_channel_win32_new_fd (outpipe);
1036
g_io_channel_set_encoding (outchannel, NULL, NULL);
1037
g_io_channel_set_buffered (outchannel, FALSE);
1038
g_io_channel_win32_make_pollfd (outchannel,
1039
G_IO_IN | G_IO_ERR | G_IO_HUP,
1042
g_print ("outfd=%x\n", outfd.fd);
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_set_buffered (errchannel, FALSE);
1051
g_io_channel_win32_make_pollfd (errchannel,
1052
G_IO_IN | G_IO_ERR | G_IO_HUP,
1055
g_print ("errfd=%x\n", errfd.fd);
1058
/* Read data until we get EOF on all pipes. */
1059
while (!failed && (outpipe >= 0 || errpipe >= 0))
1076
g_print ("g_spawn_sync: calling g_io_channel_win32_poll, nfds=%d\n",
1079
ret = g_io_channel_win32_poll (fds, nfds, -1);
1085
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ,
1086
_("Unexpected error in g_io_channel_win32_poll() reading data from a child process"));
1091
if (outpipe >= 0 && (fds[outindex].revents & G_IO_IN))
1093
switch (read_data (outstr, outchannel, error))
1097
g_print ("g_spawn_sync: outchannel: READ_FAILED\n");
1102
g_print ("g_spawn_sync: outchannel: READ_EOF\n");
1103
g_io_channel_unref (outchannel);
1105
close_and_invalidate (&outpipe);
1109
g_print ("g_spawn_sync: outchannel: OK\n");
1117
if (errpipe >= 0 && (fds[errindex].revents & G_IO_IN))
1119
switch (read_data (errstr, errchannel, error))
1123
g_print ("g_spawn_sync: errchannel: READ_FAILED\n");
1128
g_print ("g_spawn_sync: errchannel: READ_EOF\n");
1129
g_io_channel_unref (errchannel);
1131
close_and_invalidate (&errpipe);
1135
g_print ("g_spawn_sync: errchannel: OK\n");
1144
if (reportpipe == -1)
1146
/* No helper process, exit status of actual spawned process
1147
* already available.
1150
*exit_status = status;
1154
/* Helper process was involved. Read its report now after the
1155
* grandchild has finished.
1157
gint helper_report[2];
1159
if (!read_helper_report (reportpipe, helper_report, error))
1163
switch (helper_report[0])
1165
case CHILD_NO_ERROR:
1167
*exit_status = helper_report[1];
1170
set_child_error (helper_report, working_directory, error);
1175
close_and_invalidate (&reportpipe);
1179
/* These should only be open still if we had an error. */
1181
if (outchannel != NULL)
1182
g_io_channel_unref (outchannel);
1183
if (errchannel != NULL)
1184
g_io_channel_unref (errchannel);
1186
close_and_invalidate (&outpipe);
1188
close_and_invalidate (&errpipe);
1193
g_string_free (outstr, TRUE);
1195
g_string_free (errstr, TRUE);
1201
if (standard_output)
1202
*standard_output = g_string_free (outstr, FALSE);
1205
*standard_error = g_string_free (errstr, FALSE);
1212
g_spawn_async_with_pipes_utf8 (const gchar *working_directory,
1216
GSpawnChildSetupFunc child_setup,
1219
gint *standard_input,
1220
gint *standard_output,
1221
gint *standard_error,
1224
g_return_val_if_fail (argv != NULL, FALSE);
1225
g_return_val_if_fail (standard_output == NULL ||
1226
!(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
1227
g_return_val_if_fail (standard_error == NULL ||
1228
!(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
1229
/* can't inherit stdin if we have an input pipe. */
1230
g_return_val_if_fail (standard_input == NULL ||
1231
!(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE);
1233
return do_spawn_with_pipes (NULL,
1234
(flags & G_SPAWN_DO_NOT_REAP_CHILD),
1250
g_spawn_command_line_sync_utf8 (const gchar *command_line,
1251
gchar **standard_output,
1252
gchar **standard_error,
1259
g_return_val_if_fail (command_line != NULL, FALSE);
1261
if (!g_shell_parse_argv (command_line,
1266
retval = g_spawn_sync_utf8 (NULL,
1269
G_SPAWN_SEARCH_PATH,
1282
g_spawn_command_line_async_utf8 (const gchar *command_line,
1288
g_return_val_if_fail (command_line != NULL, FALSE);
1290
if (!g_shell_parse_argv (command_line,
1295
retval = g_spawn_async_utf8 (NULL,
1298
G_SPAWN_SEARCH_PATH,
1309
g_spawn_close_pid (GPid pid)
1314
/* Binary compatibility versions that take system codepage pathnames,
1315
* argument vectors and environments. These get used only by code
1316
* built against 2.8.1 or earlier. Code built against 2.8.2 or later
1317
* will use the _utf8 versions above (see the #defines in gspawn.h).
1320
#undef g_spawn_async
1321
#undef g_spawn_async_with_pipes
1323
#undef g_spawn_command_line_sync
1324
#undef g_spawn_command_line_async
1327
setup_utf8_copies (const gchar *working_directory,
1328
gchar **utf8_working_directory,
1337
if (working_directory == NULL)
1338
*utf8_working_directory = NULL;
1341
GError *conv_error = NULL;
1343
*utf8_working_directory = g_locale_to_utf8 (working_directory, -1, NULL, NULL, &conv_error);
1344
if (*utf8_working_directory == NULL)
1346
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
1347
_("Invalid working directory: %s"),
1348
conv_error->message);
1349
g_error_free (conv_error);
1357
*utf8_argv = g_new (gchar *, argc + 1);
1358
for (i = 0; i < argc; i++)
1360
GError *conv_error = NULL;
1362
(*utf8_argv)[i] = g_locale_to_utf8 (argv[i], -1, NULL, NULL, &conv_error);
1363
if ((*utf8_argv)[i] == NULL)
1365
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
1366
_("Invalid string in argument vector at %d: %s"),
1367
i, conv_error->message);
1368
g_error_free (conv_error);
1370
g_strfreev (*utf8_argv);
1373
g_free (*utf8_working_directory);
1374
*utf8_working_directory = NULL;
1379
(*utf8_argv)[argc] = NULL;
1390
*utf8_envp = g_new (gchar *, envc + 1);
1391
for (i = 0; i < envc; i++)
1393
GError *conv_error = NULL;
1395
(*utf8_envp)[i] = g_locale_to_utf8 (envp[i], -1, NULL, NULL, &conv_error);
1396
if ((*utf8_envp)[i] == NULL)
1398
g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
1399
_("Invalid string in environment: %s"),
1400
conv_error->message);
1401
g_error_free (conv_error);
1403
g_strfreev (*utf8_envp);
1406
g_strfreev (*utf8_argv);
1409
g_free (*utf8_working_directory);
1410
*utf8_working_directory = NULL;
1415
(*utf8_envp)[envc] = NULL;
1421
free_utf8_copies (gchar *utf8_working_directory,
1425
g_free (utf8_working_directory);
1426
g_strfreev (utf8_argv);
1427
g_strfreev (utf8_envp);
1431
g_spawn_async_with_pipes (const gchar *working_directory,
1435
GSpawnChildSetupFunc child_setup,
1438
gint *standard_input,
1439
gint *standard_output,
1440
gint *standard_error,
1443
gchar *utf8_working_directory;
1448
if (!setup_utf8_copies (working_directory, &utf8_working_directory,
1454
retval = g_spawn_async_with_pipes_utf8 (utf8_working_directory,
1455
utf8_argv, utf8_envp,
1456
flags, child_setup, user_data,
1458
standard_input, standard_output, standard_error,
1461
free_utf8_copies (utf8_working_directory, utf8_argv, utf8_envp);
1467
g_spawn_async (const gchar *working_directory,
1471
GSpawnChildSetupFunc child_setup,
1476
return g_spawn_async_with_pipes (working_directory,
1487
g_spawn_sync (const gchar *working_directory,
1491
GSpawnChildSetupFunc child_setup,
1493
gchar **standard_output,
1494
gchar **standard_error,
1498
gchar *utf8_working_directory;
1503
if (!setup_utf8_copies (working_directory, &utf8_working_directory,
1509
retval = g_spawn_sync_utf8 (utf8_working_directory,
1510
utf8_argv, utf8_envp,
1511
flags, child_setup, user_data,
1512
standard_output, standard_error, exit_status,
1515
free_utf8_copies (utf8_working_directory, utf8_argv, utf8_envp);
1521
g_spawn_command_line_sync (const gchar *command_line,
1522
gchar **standard_output,
1523
gchar **standard_error,
1530
g_return_val_if_fail (command_line != NULL, FALSE);
1532
if (!g_shell_parse_argv (command_line,
1537
retval = g_spawn_sync (NULL,
1540
G_SPAWN_SEARCH_PATH,
1553
g_spawn_command_line_async (const gchar *command_line,
1559
g_return_val_if_fail (command_line != NULL, FALSE);
1561
if (!g_shell_parse_argv (command_line,
1566
retval = g_spawn_async (NULL,
1569
G_SPAWN_SEARCH_PATH,
1579
#endif /* !GSPAWN_HELPER */
1581
#define __G_SPAWN_C__
1582
#include "galiasdef.c"