1 /* Creation of autonomous subprocesses.
2 Copyright (C) 2001-2004, 2006-2020 Free Software Foundation, Inc.
3 Written by Bruno Haible <haible@clisp.cons.org>, 2001.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
31 #include <sys/types.h>
34 #include "canonicalize.h"
36 #include "fatal-signal.h"
39 #include "wait-process.h"
43 #define _(str) gettext (str)
46 /* Choice of implementation for native Windows.
47 - Define to 0 to use the posix_spawn facility (modules 'posix_spawn' and
48 'posix_spawnp'), that is based on the module 'windows-spawn'.
49 - Define to 1 to use the older code, that uses the module 'windows-spawn'
51 You can set this macro from a Makefile or at configure time, from the
53 #ifndef EXECUTE_IMPL_AVOID_POSIX_SPAWN
54 # define EXECUTE_IMPL_AVOID_POSIX_SPAWN 0
58 #if (defined _WIN32 && !defined __CYGWIN__) && EXECUTE_IMPL_AVOID_POSIX_SPAWN
60 /* Native Windows API. */
61 # if GNULIB_MSVC_NOTHROW
62 # include "msvc-nothrow.h"
67 # include "windows-spawn.h"
77 #if defined EINTR && (defined _WIN32 && !defined __CYGWIN__) && EXECUTE_IMPL_AVOID_POSIX_SPAWN
79 /* EINTR handling for close(), open().
80 These functions can return -1/EINTR even though we don't have any
81 signal handlers set up, namely when we get interrupted via SIGSTOP. */
84 nonintr_close (int fd
)
90 while (retval
< 0 && errno
== EINTR
);
94 #undef close /* avoid warning related to gnulib module unistd */
95 #define close nonintr_close
98 nonintr_open (const char *pathname
, int oflag
, mode_t mode
)
103 retval
= open (pathname
, oflag
, mode
);
104 while (retval
< 0 && errno
== EINTR
);
108 #undef open /* avoid warning on VMS */
109 #define open nonintr_open
115 execute (const char *progname
,
116 const char *prog_path
, const char * const *prog_argv
,
117 const char *directory
,
119 bool null_stdin
, bool null_stdout
, bool null_stderr
,
120 bool slave_process
, bool exit_on_error
,
124 char *prog_path_to_free
= NULL
;
126 if (directory
!= NULL
)
128 /* If a change of directory is requested, make sure PROG_PATH is absolute
129 before we do so. This is needed because
130 - posix_spawn and posix_spawnp are required to resolve a relative
131 PROG_PATH *after* changing the directory. See
132 <https://www.austingroupbugs.net/view.php?id=1208>:
133 "if this pathname does not start with a <slash> it shall be
134 interpreted relative to the working directory of the child
135 process _after_ all file_actions have been performed."
136 But this would be a surprising application behaviour, possibly
137 even security relevant.
138 - For the Windows CreateProcess() function, it is unspecified whether
139 a relative file name is interpreted to the parent's current
140 directory or to the specified directory. See
141 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa> */
142 if (! IS_ABSOLUTE_FILE_NAME (prog_path
))
144 const char *resolved_prog
=
145 find_in_given_path (prog_path
, getenv ("PATH"), NULL
, false);
146 if (resolved_prog
== NULL
)
147 goto fail_with_errno
;
148 if (resolved_prog
!= prog_path
)
149 prog_path_to_free
= (char *) resolved_prog
;
150 prog_path
= resolved_prog
;
152 if (! IS_ABSOLUTE_FILE_NAME (prog_path
))
154 char *absolute_prog
=
155 canonicalize_filename_mode (prog_path
,
156 CAN_MISSING
| CAN_NOLINKS
);
157 if (absolute_prog
== NULL
)
160 free (prog_path_to_free
);
161 goto fail_with_saved_errno
;
163 free (prog_path_to_free
);
164 prog_path_to_free
= absolute_prog
;
165 prog_path
= absolute_prog
;
167 if (! IS_ABSOLUTE_FILE_NAME (prog_path
))
173 #if (defined _WIN32 && !defined __CYGWIN__) && EXECUTE_IMPL_AVOID_POSIX_SPAWN
175 /* Native Windows API. */
177 char *argv_mem_to_free
;
179 const char **argv
= prepare_spawn (prog_argv
, &argv_mem_to_free
);
185 /* Create standard file handles of child process. */
189 || (nullinfd
= open ("NUL", O_RDONLY
, 0)) >= 0)
190 && (!(null_stdout
|| null_stderr
)
191 || (nulloutfd
= open ("NUL", O_RDWR
, 0)) >= 0))
192 /* Pass the environment explicitly. This is needed if the program has
193 modified the environment using putenv() or [un]setenv(). On Windows,
194 processes have two environments, one in the "environment block" of the
195 process and managed through SetEnvironmentVariable(), and one inside the
196 process, in the location retrieved by the 'environ' macro. If we were
197 to pass NULL, the child process would inherit a copy of the environment
198 block - ignoring the effects of putenv() and [un]setenv(). */
200 HANDLE stdin_handle
=
201 (HANDLE
) _get_osfhandle (null_stdin
? nullinfd
: STDIN_FILENO
);
202 HANDLE stdout_handle
=
203 (HANDLE
) _get_osfhandle (null_stdout
? nulloutfd
: STDOUT_FILENO
);
204 HANDLE stderr_handle
=
205 (HANDLE
) _get_osfhandle (null_stderr
? nulloutfd
: STDERR_FILENO
);
207 exitcode
= spawnpvech (P_WAIT
, prog_path
, argv
+ 1,
208 (const char * const *) environ
, directory
,
209 stdin_handle
, stdout_handle
, stderr_handle
);
210 # if 0 /* Executing arbitrary files as shell scripts is unsecure. */
211 if (exitcode
== -1 && errno
== ENOEXEC
)
213 /* prog is not a native executable. Try to execute it as a
214 shell script. Note that prepare_spawn() has already prepended
215 a hidden element "sh.exe" to argv. */
217 exitcode
= spawnpvech (P_WAIT
, argv
[0], argv
,
218 (const char * const *) environ
, directory
,
219 stdin_handle
, stdout_handle
, stderr_handle
);
230 free (argv_mem_to_free
);
231 free (prog_path_to_free
);
233 /* Treat failure and signalled child processes like wait_subprocess()
235 if (termsigp
!= NULL
)
239 goto fail_with_saved_errno
;
241 if (WIFSIGNALED (exitcode
))
243 if (termsigp
!= NULL
)
244 *termsigp
= WTERMSIG (exitcode
);
246 goto fail_with_saved_errno
;
254 /* Note about 127: Some errors during posix_spawnp() cause the function
255 posix_spawnp() to return an error code; some other errors cause the
256 subprocess to exit with return code 127. It is implementation
257 dependent which error is reported which way. We treat both cases as
259 sigset_t blocked_signals
;
260 posix_spawn_file_actions_t actions
;
261 bool actions_allocated
;
262 posix_spawnattr_t attrs
;
263 bool attrs_allocated
;
269 sigprocmask (SIG_SETMASK
, NULL
, &blocked_signals
);
270 block_fatal_signals ();
272 actions_allocated
= false;
273 attrs_allocated
= false;
274 if ((err
= posix_spawn_file_actions_init (&actions
)) != 0
275 || (actions_allocated
= true,
277 && (err
= posix_spawn_file_actions_addopen (&actions
,
279 "/dev/null", O_RDONLY
,
283 && (err
= posix_spawn_file_actions_addopen (&actions
,
289 && (err
= posix_spawn_file_actions_addopen (&actions
,
294 || (directory
!= NULL
295 && (err
= posix_spawn_file_actions_addchdir (&actions
,
297 # if !(defined _WIN32 && !defined __CYGWIN__)
299 && ((err
= posix_spawnattr_init (&attrs
)) != 0
300 || (attrs_allocated
= true,
301 (err
= posix_spawnattr_setsigmask (&attrs
,
304 || (err
= posix_spawnattr_setflags (&attrs
,
305 POSIX_SPAWN_SETSIGMASK
))
308 || (err
= (directory
!= NULL
309 ? posix_spawn (&child
, prog_path
, &actions
,
310 attrs_allocated
? &attrs
: NULL
,
311 (char * const *) prog_argv
, environ
)
312 : posix_spawnp (&child
, prog_path
, &actions
,
313 attrs_allocated
? &attrs
: NULL
,
314 (char * const *) prog_argv
, environ
)))
317 if (actions_allocated
)
318 posix_spawn_file_actions_destroy (&actions
);
320 posix_spawnattr_destroy (&attrs
);
322 unblock_fatal_signals ();
323 free (prog_path_to_free
);
324 if (termsigp
!= NULL
)
327 goto fail_with_saved_errno
;
329 posix_spawn_file_actions_destroy (&actions
);
331 posix_spawnattr_destroy (&attrs
);
334 register_slave_subprocess (child
);
335 unblock_fatal_signals ();
337 free (prog_path_to_free
);
339 return wait_subprocess (child
, progname
, ignore_sigpipe
, null_stderr
,
340 slave_process
, exit_on_error
, termsigp
);
346 fail_with_saved_errno
:
347 if (exit_on_error
|| !null_stderr
)
348 error (exit_on_error
? EXIT_FAILURE
: 0, saved_errno
,
349 _("%s subprocess failed"), progname
);