1 /* Auxiliary functions for the creation of subprocesses. Native Windows API.
2 Copyright (C) 2001, 2003-2020 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2003.
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/>. */
21 #include "windows-spawn.h"
23 /* Get declarations of the native Windows API functions. */
24 #define WIN32_LEAN_AND_MEAN
33 /* Get _get_osfhandle(). */
34 #if GNULIB_MSVC_NOTHROW
35 # include "msvc-nothrow.h"
44 /* Don't assume that UNICODE is not defined. */
46 #define STARTUPINFO STARTUPINFOA
48 #define CreateProcess CreateProcessA
50 #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037*?"
51 #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
53 prepare_spawn (char **argv
)
59 /* Count number of arguments. */
60 for (argc
= 0; argv
[argc
] != NULL
; argc
++)
63 /* Allocate new argument vector. */
64 new_argv
= XNMALLOC (1 + argc
+ 1, char *);
66 /* Add an element upfront that can be used when argv[0] turns out to be a
67 script, not a program.
68 On Unix, this would be "/bin/sh". On native Windows, "sh" is actually
69 "sh.exe". We have to omit the directory part and rely on the search in
70 PATH, because the mingw "mount points" are not visible inside Windows
72 *new_argv
++ = "sh.exe";
74 /* Put quoted arguments into the new argument vector. */
75 for (i
= 0; i
< argc
; i
++)
77 const char *string
= argv
[i
];
79 if (string
[0] == '\0')
80 new_argv
[i
] = xstrdup ("\"\"");
81 else if (strpbrk (string
, SHELL_SPECIAL_CHARS
) != NULL
)
83 bool quote_around
= (strpbrk (string
, SHELL_SPACE_CHARS
) != NULL
);
85 unsigned int backslashes
;
94 for (s
= string
; *s
!= '\0'; s
++)
98 length
+= backslashes
+ 1;
106 length
+= backslashes
+ 1;
108 quoted_string
= (char *) xmalloc (length
+ 1);
114 for (s
= string
; *s
!= '\0'; s
++)
120 for (j
= backslashes
+ 1; j
> 0; j
--)
132 for (j
= backslashes
; j
> 0; j
--)
138 new_argv
[i
] = quoted_string
;
141 new_argv
[i
] = (char *) string
;
143 new_argv
[argc
] = NULL
;
149 spawnpvech (int mode
,
150 const char *progname
, const char * const *argv
,
151 const char * const *envp
,
153 HANDLE stdin_handle
, HANDLE stdout_handle
, HANDLE stderr_handle
)
155 /* Validate the arguments. */
159 || mode
== P_OVERLAY
)
160 || progname
== NULL
|| argv
== NULL
)
166 /* Implement the 'p' letter: search for PROGNAME in getenv ("PATH"). */
167 const char *resolved_progname
=
168 find_in_given_path (progname
, getenv ("PATH"), false);
169 if (resolved_progname
== NULL
)
172 /* Compose the command.
173 Just concatenate the argv[] strings, separated by spaces. */
176 /* Determine the size of the needed block of memory. */
177 size_t total_size
= 0;
178 const char * const *ap
;
180 for (ap
= argv
; (p
= *ap
) != NULL
; ap
++)
181 total_size
+= strlen (p
) + 1;
182 size_t command_size
= (total_size
> 0 ? total_size
: 1);
183 command
= (char *) malloc (command_size
);
185 goto out_of_memory_1
;
189 for (ap
= argv
; (p
= *ap
) != NULL
; ap
++)
191 size_t size
= strlen (p
) + 1;
192 memcpy (cp
, p
, size
- 1);
202 /* Copy *ENVP into a contiguous block of memory. */
209 /* Guess the size of the needed block of memory.
210 The guess will be exact if other threads don't make modifications. */
211 size_t total_size
= 0;
212 const char * const *ep
;
214 for (ep
= envp
; (p
= *ep
) != NULL
; ep
++)
215 total_size
+= strlen (p
) + 1;
216 size_t envblock_size
= total_size
;
217 envblock
= (char *) malloc (envblock_size
+ 1);
218 if (envblock
== NULL
)
219 goto out_of_memory_2
;
220 size_t envblock_used
= 0;
221 for (ep
= envp
; (p
= *ep
) != NULL
; ep
++)
223 size_t size
= strlen (p
) + 1;
224 if (envblock_used
+ size
> envblock_size
)
226 /* Other threads did modifications. Need more memory. */
227 envblock_size
+= envblock_size
/ 2;
228 if (envblock_used
+ size
> envblock_size
)
229 envblock_size
= envblock_used
+ size
;
231 char *new_envblock
= (char *) realloc (envblock
, envblock_size
+ 1);
232 if (new_envblock
== NULL
)
233 goto out_of_memory_3
;
234 envblock
= new_envblock
;
236 memcpy (envblock
+ envblock_used
, p
, size
);
237 envblock_used
+= size
;
238 if (envblock
[envblock_used
- 1] != '\0')
240 /* Other threads did modifications. Restart. */
245 envblock
[envblock_used
] = '\0';
249 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa> */
250 /* Regarding handle inheritance, see
251 <https://docs.microsoft.com/en-us/windows/win32/sysinfo/handle-inheritance> */
252 /* <https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags> */
253 DWORD flags
= (mode
== P_DETACH
? DETACHED_PROCESS
: 0);
255 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa> */
257 sinfo
.cb
= sizeof (STARTUPINFO
);
258 sinfo
.lpReserved
= NULL
;
259 sinfo
.lpDesktop
= NULL
;
260 sinfo
.lpTitle
= NULL
;
261 sinfo
.dwFlags
= STARTF_USESTDHANDLES
;
262 sinfo
.hStdInput
= stdin_handle
;
263 sinfo
.hStdOutput
= stdout_handle
;
264 sinfo
.hStdError
= stderr_handle
;
268 sinfo
.cbReserved2
= 0;
269 sinfo
.lpReserved2
= NULL
;
271 /* On newer versions of Windows, more file descriptors / handles than the
272 first three can be passed.
273 The format is as follows: Let N be an exclusive upper bound for the file
274 descriptors to be passed. Two arrays are constructed in memory:
275 - flags[0..N-1], of element type 'unsigned char',
276 - handles[0..N-1], of element type 'HANDLE' or 'intptr_t'.
277 For used entries, handles[i] is the handle, and flags[i] is a set of flags,
279 1 for open file descriptors,
280 64 for handles of type FILE_TYPE_CHAR,
281 8 for handles of type FILE_TYPE_PIPE.
282 For unused entries - this includes the first three, since they are already
283 passed above -, handles[i] is INVALID_HANDLE_VALUE and flags[i] is zero.
284 lpReserved2 now is a pointer to the concatenation (without padding) of:
285 - an 'unsigned int' whose value is N,
286 - the contents of the flags[0..N-1] array,
287 - the contents of the handles[0..N-1] array.
288 cbReserved2 is the size (in bytes) of the object at lpReserved2. */
291 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/getmaxstdio>
292 Default value is 512. */
294 for (fdmax
= _getmaxstdio (); fdmax
> 0; fdmax
--)
296 unsigned int fd
= fdmax
- 1;
298 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle> */
299 HANDLE handle
= (HANDLE
) _get_osfhandle (fd
);
300 if (handle
!= INVALID_HANDLE_VALUE
)
303 /* GetHandleInformation
304 <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation> */
305 if (GetHandleInformation (handle
, &hflags
))
307 if ((hflags
& HANDLE_FLAG_INHERIT
) != 0)
308 /* fd denotes an inheritable descriptor. */
316 sizeof (unsigned int)
317 + fdmax
* sizeof (unsigned char)
318 + fdmax
* sizeof (HANDLE
);
319 /* Add some padding, so that we can work with a properly HANDLE array. */
320 hblock
= (char *) malloc (sinfo
.cbReserved2
+ (sizeof (HANDLE
) - 1));
322 goto out_of_memory_3
;
323 * (unsigned int *) hblock
= fdmax
;
324 unsigned char *flags
= (unsigned char *) (hblock
+ sizeof (unsigned int));
325 char *handles
= (char *) (flags
+ fdmax
);
326 HANDLE
*handles_aligned
=
327 (HANDLE
*) (((uintptr_t) handles
+ (sizeof (HANDLE
) - 1))
328 & - (uintptr_t) sizeof (HANDLE
));
331 for (fd
= 0; fd
< fdmax
; fd
++)
334 handles_aligned
[fd
] = INVALID_HANDLE_VALUE
;
335 /* The first three are already passed above. */
339 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle> */
340 HANDLE handle
= (HANDLE
) _get_osfhandle (fd
);
341 if (handle
!= INVALID_HANDLE_VALUE
)
344 /* GetHandleInformation
345 <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation> */
346 if (GetHandleInformation (handle
, &hflags
))
348 if ((hflags
& HANDLE_FLAG_INHERIT
) != 0)
350 /* fd denotes an inheritable descriptor. */
351 /* On Microsoft Windows, it would be sufficient to
352 set flags[fd] = 1. But on ReactOS or Wine,
353 adding the bit that indicates the handle type
354 may be necessary. So, just do it everywhere. */
355 switch (GetFileType (handle
))
367 handles_aligned
[fd
] = handle
;
374 if (handles
!= (char *) handles_aligned
)
375 memmove (handles
, (char *) handles_aligned
, fdmax
* sizeof (HANDLE
));
376 sinfo
.lpReserved2
= (BYTE
*) hblock
;
380 sinfo
.cbReserved2
= 0;
381 sinfo
.lpReserved2
= NULL
;
386 PROCESS_INFORMATION pinfo
;
387 if (!CreateProcess (resolved_progname
, command
, NULL
, NULL
, TRUE
,
388 flags
, envblock
, currdir
, &sinfo
, &pinfo
))
390 DWORD error
= GetLastError ();
394 if (envblock
!= NULL
)
397 if (resolved_progname
!= progname
)
398 free ((char *) resolved_progname
);
400 /* Some of these errors probably cannot happen. But who knows... */
403 case ERROR_FILE_NOT_FOUND
:
404 case ERROR_PATH_NOT_FOUND
:
405 case ERROR_BAD_PATHNAME
:
406 case ERROR_BAD_NET_NAME
:
407 case ERROR_INVALID_NAME
:
408 case ERROR_DIRECTORY
:
412 case ERROR_ACCESS_DENIED
:
413 case ERROR_SHARING_VIOLATION
:
417 case ERROR_OUTOFMEMORY
:
421 case ERROR_BUFFER_OVERFLOW
:
422 case ERROR_FILENAME_EXCED_RANGE
:
423 errno
= ENAMETOOLONG
;
435 CloseHandle (pinfo
.hThread
);
438 if (envblock
!= NULL
)
441 if (resolved_progname
!= progname
)
442 free ((char *) resolved_progname
);
448 /* Wait until it terminates. Then get its exit status code. */
449 switch (WaitForSingleObject (pinfo
.hProcess
, INFINITE
))
461 if (!GetExitCodeProcess (pinfo
.hProcess
, &exit_code
))
466 CloseHandle (pinfo
.hProcess
);
471 /* Return pinfo.hProcess, not pinfo.dwProcessId. */
472 return (intptr_t) pinfo
.hProcess
;
476 CloseHandle (pinfo
.hProcess
);
480 /* Already checked above. */
491 if (envblock
!= NULL
)
496 if (resolved_progname
!= progname
)
497 free ((char *) resolved_progname
);