execute, spawn-pipe: Make multithread-safe on native Windows.
[gnulib.git] / lib / windows-spawn.c
blob2a59ff29f590eea0a49d2d47f3bc07e48de28fd6
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/>. */
18 #include <config.h>
20 /* Specification. */
21 #include "windows-spawn.h"
23 /* Get declarations of the native Windows API functions. */
24 #define WIN32_LEAN_AND_MEAN
25 #include <windows.h>
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
33 /* Get _get_osfhandle(). */
34 #if GNULIB_MSVC_NOTHROW
35 # include "msvc-nothrow.h"
36 #else
37 # include <io.h>
38 #endif
39 #include <process.h>
41 #include "findprog.h"
42 #include "xalloc.h"
44 /* Don't assume that UNICODE is not defined. */
45 #undef STARTUPINFO
46 #define STARTUPINFO STARTUPINFOA
47 #undef CreateProcess
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"
52 char **
53 prepare_spawn (char **argv)
55 size_t argc;
56 char **new_argv;
57 size_t i;
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
71 CreateProcess(). */
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);
84 size_t length;
85 unsigned int backslashes;
86 const char *s;
87 char *quoted_string;
88 char *p;
90 length = 0;
91 backslashes = 0;
92 if (quote_around)
93 length++;
94 for (s = string; *s != '\0'; s++)
96 char c = *s;
97 if (c == '"')
98 length += backslashes + 1;
99 length++;
100 if (c == '\\')
101 backslashes++;
102 else
103 backslashes = 0;
105 if (quote_around)
106 length += backslashes + 1;
108 quoted_string = (char *) xmalloc (length + 1);
110 p = quoted_string;
111 backslashes = 0;
112 if (quote_around)
113 *p++ = '"';
114 for (s = string; *s != '\0'; s++)
116 char c = *s;
117 if (c == '"')
119 unsigned int j;
120 for (j = backslashes + 1; j > 0; j--)
121 *p++ = '\\';
123 *p++ = c;
124 if (c == '\\')
125 backslashes++;
126 else
127 backslashes = 0;
129 if (quote_around)
131 unsigned int j;
132 for (j = backslashes; j > 0; j--)
133 *p++ = '\\';
134 *p++ = '"';
136 *p = '\0';
138 new_argv[i] = quoted_string;
140 else
141 new_argv[i] = (char *) string;
143 new_argv[argc] = NULL;
145 return new_argv;
148 intptr_t
149 spawnpvech (int mode,
150 const char *progname, const char * const *argv,
151 const char * const *envp,
152 const char *currdir,
153 HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle)
155 /* Validate the arguments. */
156 if (!(mode == P_WAIT
157 || mode == P_NOWAIT
158 || mode == P_DETACH
159 || mode == P_OVERLAY)
160 || progname == NULL || argv == NULL)
162 errno = EINVAL;
163 return -1;
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)
170 return -1;
172 /* Compose the command.
173 Just concatenate the argv[] strings, separated by spaces. */
174 char *command;
176 /* Determine the size of the needed block of memory. */
177 size_t total_size = 0;
178 const char * const *ap;
179 const char *p;
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);
184 if (command == NULL)
185 goto out_of_memory_1;
186 if (total_size > 0)
188 char *cp = command;
189 for (ap = argv; (p = *ap) != NULL; ap++)
191 size_t size = strlen (p) + 1;
192 memcpy (cp, p, size - 1);
193 cp += size;
194 cp[-1] = ' ';
196 cp[-1] = '\0';
198 else
199 *command = '\0';
202 /* Copy *ENVP into a contiguous block of memory. */
203 char *envblock;
204 if (envp == NULL)
205 envblock = NULL;
206 else
207 retry:
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;
213 const char *p;
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. */
241 free (envblock);
242 goto retry;
245 envblock[envblock_used] = '\0';
248 /* CreateProcess
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);
254 /* STARTUPINFO
255 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa> */
256 STARTUPINFO sinfo;
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;
266 char *hblock = NULL;
267 #if 0
268 sinfo.cbReserved2 = 0;
269 sinfo.lpReserved2 = NULL;
270 #else
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,
278 a combination of:
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. */
290 /* _getmaxstdio
291 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/getmaxstdio>
292 Default value is 512. */
293 unsigned int fdmax;
294 for (fdmax = _getmaxstdio (); fdmax > 0; fdmax--)
296 unsigned int fd = fdmax - 1;
297 /* _get_osfhandle
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)
302 DWORD hflags;
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. */
309 break;
313 if (fdmax > 0)
315 sinfo.cbReserved2 =
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));
321 if (hblock == NULL)
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));
330 unsigned int fd;
331 for (fd = 0; fd < fdmax; fd++)
333 flags[fd] = 0;
334 handles_aligned[fd] = INVALID_HANDLE_VALUE;
335 /* The first three are already passed above. */
336 if (fd >= 3)
338 /* _get_osfhandle
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)
343 DWORD hflags;
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))
357 case FILE_TYPE_CHAR:
358 flags[fd] = 64 | 1;
359 break;
360 case FILE_TYPE_PIPE:
361 flags[fd] = 8 | 1;
362 break;
363 default:
364 flags[fd] = 1;
365 break;
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;
378 else
380 sinfo.cbReserved2 = 0;
381 sinfo.lpReserved2 = NULL;
384 #endif
386 PROCESS_INFORMATION pinfo;
387 if (!CreateProcess (resolved_progname, command, NULL, NULL, TRUE,
388 flags, envblock, currdir, &sinfo, &pinfo))
390 DWORD error = GetLastError ();
392 if (hblock != NULL)
393 free (hblock);
394 if (envblock != NULL)
395 free (envblock);
396 free (command);
397 if (resolved_progname != progname)
398 free ((char *) resolved_progname);
400 /* Some of these errors probably cannot happen. But who knows... */
401 switch (error)
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:
409 errno = ENOENT;
410 break;
412 case ERROR_ACCESS_DENIED:
413 case ERROR_SHARING_VIOLATION:
414 errno = EACCES;
415 break;
417 case ERROR_OUTOFMEMORY:
418 errno = ENOMEM;
419 break;
421 case ERROR_BUFFER_OVERFLOW:
422 case ERROR_FILENAME_EXCED_RANGE:
423 errno = ENAMETOOLONG;
424 break;
426 default:
427 errno = EINVAL;
428 break;
431 return -1;
434 if (pinfo.hThread)
435 CloseHandle (pinfo.hThread);
436 if (hblock != NULL)
437 free (hblock);
438 if (envblock != NULL)
439 free (envblock);
440 free (command);
441 if (resolved_progname != progname)
442 free ((char *) resolved_progname);
444 switch (mode)
446 case P_WAIT:
448 /* Wait until it terminates. Then get its exit status code. */
449 switch (WaitForSingleObject (pinfo.hProcess, INFINITE))
451 case WAIT_OBJECT_0:
452 break;
453 case WAIT_FAILED:
454 errno = ECHILD;
455 return -1;
456 default:
457 abort ();
460 DWORD exit_code;
461 if (!GetExitCodeProcess (pinfo.hProcess, &exit_code))
463 errno = ECHILD;
464 return -1;
466 CloseHandle (pinfo.hProcess);
467 return exit_code;
470 case P_NOWAIT:
471 /* Return pinfo.hProcess, not pinfo.dwProcessId. */
472 return (intptr_t) pinfo.hProcess;
474 case P_DETACH:
475 case P_OVERLAY:
476 CloseHandle (pinfo.hProcess);
477 return 0;
479 default:
480 /* Already checked above. */
481 abort ();
484 /*NOTREACHED*/
485 #if 0
486 out_of_memory_4:
487 if (hblock != NULL)
488 free (hblock);
489 #endif
490 out_of_memory_3:
491 if (envblock != NULL)
492 free (envblock);
493 out_of_memory_2:
494 free (command);
495 out_of_memory_1:
496 if (resolved_progname != progname)
497 free ((char *) resolved_progname);
498 errno = ENOMEM;
499 return -1;