windows-spawn: Export another auxiliary function.
[gnulib.git] / lib / windows-spawn.c
blobb0a6dda9c0b526e61623883033b98350715da762
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"
43 /* Don't assume that UNICODE is not defined. */
44 #undef STARTUPINFO
45 #define STARTUPINFO STARTUPINFOA
46 #undef CreateProcess
47 #define CreateProcess CreateProcessA
49 #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*?"
50 #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 /* Returns the length of a quoted argument string. */
53 static size_t
54 quoted_arg_length (const char *string)
56 bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
57 size_t length;
58 unsigned int backslashes;
59 const char *s;
61 length = 0;
62 backslashes = 0;
63 if (quote_around)
64 length++;
65 for (s = string; *s != '\0'; s++)
67 char c = *s;
68 if (c == '"')
69 length += backslashes + 1;
70 length++;
71 if (c == '\\')
72 backslashes++;
73 else
74 backslashes = 0;
76 if (quote_around)
77 length += backslashes + 1;
79 return length;
82 /* Produces a quoted argument string.
83 Stores exactly quoted_arg_length (STRING) + 1 bytes, including the final
84 NUL byte, at MEM.
85 Returns a pointer past the stored quoted argument string. */
86 static char *
87 quoted_arg_string (const char *string, char *mem)
89 bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
90 char *p;
91 unsigned int backslashes;
92 const char *s;
94 p = mem;
95 backslashes = 0;
96 if (quote_around)
97 *p++ = '"';
98 for (s = string; *s != '\0'; s++)
100 char c = *s;
101 if (c == '"')
103 unsigned int j;
104 for (j = backslashes + 1; j > 0; j--)
105 *p++ = '\\';
107 *p++ = c;
108 if (c == '\\')
109 backslashes++;
110 else
111 backslashes = 0;
113 if (quote_around)
115 unsigned int j;
116 for (j = backslashes; j > 0; j--)
117 *p++ = '\\';
118 *p++ = '"';
120 *p++ = '\0';
122 return p;
125 const char **
126 prepare_spawn (const char * const *argv, char **mem_to_free)
128 size_t argc;
129 const char **new_argv;
130 size_t i;
132 /* Count number of arguments. */
133 for (argc = 0; argv[argc] != NULL; argc++)
136 /* Allocate new argument vector. */
137 new_argv = (const char **) malloc ((1 + argc + 1) * sizeof (const char *));
139 /* Add an element upfront that can be used when argv[0] turns out to be a
140 script, not a program.
141 On Unix, this would be "/bin/sh". On native Windows, "sh" is actually
142 "sh.exe". We have to omit the directory part and rely on the search in
143 PATH, because the mingw "mount points" are not visible inside Windows
144 CreateProcess(). */
145 new_argv[0] = "sh.exe";
147 /* Put quoted arguments into the new argument vector. */
148 size_t needed_size = 0;
149 for (i = 0; i < argc; i++)
151 const char *string = argv[i];
152 size_t length;
154 if (string[0] == '\0')
155 length = strlen ("\"\"");
156 else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
157 length = quoted_arg_length (string);
158 else
159 length = strlen (string);
160 needed_size += length + 1;
163 char *mem;
164 if (needed_size == 0)
165 mem = NULL;
166 else
168 mem = (char *) malloc (needed_size);
169 if (mem == NULL)
171 /* Memory allocation failure. */
172 free (new_argv);
173 errno = ENOMEM;
174 return NULL;
177 *mem_to_free = mem;
179 for (i = 0; i < argc; i++)
181 const char *string = argv[i];
183 new_argv[1 + i] = mem;
184 if (string[0] == '\0')
186 size_t length = strlen ("\"\"");
187 memcpy (mem, "\"\"", length + 1);
188 mem += length + 1;
190 else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
192 mem = quoted_arg_string (string, mem);
194 else
196 size_t length = strlen (string);
197 memcpy (mem, string, length + 1);
198 mem += length + 1;
201 new_argv[1 + argc] = NULL;
203 return new_argv;
206 char *
207 compose_command (const char * const *argv)
209 /* Just concatenate the argv[] strings, separated by spaces. */
210 char *command;
212 /* Determine the size of the needed block of memory. */
213 size_t total_size = 0;
214 const char * const *ap;
215 const char *p;
216 for (ap = argv; (p = *ap) != NULL; ap++)
217 total_size += strlen (p) + 1;
218 size_t command_size = (total_size > 0 ? total_size : 1);
220 /* Allocate the block of memory. */
221 command = (char *) malloc (command_size);
222 if (command == NULL)
224 errno = ENOMEM;
225 return NULL;
228 /* Fill it. */
229 if (total_size > 0)
231 char *cp = command;
232 for (ap = argv; (p = *ap) != NULL; ap++)
234 size_t size = strlen (p) + 1;
235 memcpy (cp, p, size - 1);
236 cp += size;
237 cp[-1] = ' ';
239 cp[-1] = '\0';
241 else
242 *command = '\0';
244 return command;
247 char *
248 compose_envblock (const char * const *envp)
250 /* This is a bit hairy, because we don't have a lock that would prevent other
251 threads from making modifications in ENVP. So, just make sure we don't
252 crash; but if other threads are making modifications, part of the result
253 may be wrong. */
254 retry:
256 /* Guess the size of the needed block of memory.
257 The guess will be exact if other threads don't make modifications. */
258 size_t total_size = 0;
259 const char * const *ep;
260 const char *p;
261 for (ep = envp; (p = *ep) != NULL; ep++)
262 total_size += strlen (p) + 1;
263 size_t envblock_size = total_size;
265 /* Allocate the block of memory. */
266 char *envblock = (char *) malloc (envblock_size + 1);
267 if (envblock == NULL)
269 errno = ENOMEM;
270 return NULL;
272 size_t envblock_used = 0;
273 for (ep = envp; (p = *ep) != NULL; ep++)
275 size_t size = strlen (p) + 1;
276 if (envblock_used + size > envblock_size)
278 /* Other threads did modifications. Need more memory. */
279 envblock_size += envblock_size / 2;
280 if (envblock_used + size > envblock_size)
281 envblock_size = envblock_used + size;
283 char *new_envblock = (char *) realloc (envblock, envblock_size + 1);
284 if (new_envblock == NULL)
286 free (envblock);
287 errno = ENOMEM;
288 return NULL;
290 envblock = new_envblock;
292 memcpy (envblock + envblock_used, p, size);
293 envblock_used += size;
294 if (envblock[envblock_used - 1] != '\0')
296 /* Other threads did modifications. Restart. */
297 free (envblock);
298 goto retry;
301 envblock[envblock_used] = '\0';
302 return envblock;
306 intptr_t
307 spawnpvech (int mode,
308 const char *progname, const char * const *argv,
309 const char * const *envp,
310 const char *currdir,
311 HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle)
313 /* Validate the arguments. */
314 if (!(mode == P_WAIT
315 || mode == P_NOWAIT
316 || mode == P_DETACH
317 || mode == P_OVERLAY)
318 || progname == NULL || argv == NULL)
320 errno = EINVAL;
321 return -1;
324 /* Implement the 'p' letter: search for PROGNAME in getenv ("PATH"). */
325 const char *resolved_progname =
326 find_in_given_path (progname, getenv ("PATH"), NULL, false);
327 if (resolved_progname == NULL)
328 return -1;
330 /* Compose the command. */
331 char *command = compose_command (argv);
332 if (command == NULL)
333 goto out_of_memory_1;
335 /* Copy *ENVP into a contiguous block of memory. */
336 char *envblock;
337 if (envp == NULL)
338 envblock = NULL;
339 else
341 envblock = compose_envblock (envp);
342 if (envblock == NULL)
343 goto out_of_memory_2;
346 /* CreateProcess
347 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa> */
348 /* Regarding handle inheritance, see
349 <https://docs.microsoft.com/en-us/windows/win32/sysinfo/handle-inheritance> */
350 /* <https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags> */
351 DWORD process_creation_flags = (mode == P_DETACH ? DETACHED_PROCESS : 0);
352 /* STARTUPINFO
353 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa> */
354 STARTUPINFO sinfo;
355 sinfo.cb = sizeof (STARTUPINFO);
356 sinfo.lpReserved = NULL;
357 sinfo.lpDesktop = NULL;
358 sinfo.lpTitle = NULL;
359 sinfo.dwFlags = STARTF_USESTDHANDLES;
360 sinfo.hStdInput = stdin_handle;
361 sinfo.hStdOutput = stdout_handle;
362 sinfo.hStdError = stderr_handle;
364 char *hblock = NULL;
365 #if 0
366 sinfo.cbReserved2 = 0;
367 sinfo.lpReserved2 = NULL;
368 #else
369 /* On newer versions of Windows, more file descriptors / handles than the
370 first three can be passed.
371 The format is as follows: Let N be an exclusive upper bound for the file
372 descriptors to be passed. Two arrays are constructed in memory:
373 - flags[0..N-1], of element type 'unsigned char',
374 - handles[0..N-1], of element type 'HANDLE' or 'intptr_t'.
375 For used entries, handles[i] is the handle, and flags[i] is a set of flags,
376 a combination of:
377 1 for open file descriptors,
378 64 for handles of type FILE_TYPE_CHAR,
379 8 for handles of type FILE_TYPE_PIPE.
380 For unused entries - this includes the first three, since they are already
381 passed above -, handles[i] is INVALID_HANDLE_VALUE and flags[i] is zero.
382 lpReserved2 now is a pointer to the concatenation (without padding) of:
383 - an 'unsigned int' whose value is N,
384 - the contents of the flags[0..N-1] array,
385 - the contents of the handles[0..N-1] array.
386 cbReserved2 is the size (in bytes) of the object at lpReserved2. */
388 /* _getmaxstdio
389 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/getmaxstdio>
390 Default value is 512. */
391 unsigned int fdmax;
392 for (fdmax = _getmaxstdio (); fdmax > 0; fdmax--)
394 unsigned int fd = fdmax - 1;
395 /* _get_osfhandle
396 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle> */
397 HANDLE handle = (HANDLE) _get_osfhandle (fd);
398 if (handle != INVALID_HANDLE_VALUE)
400 DWORD hflags;
401 /* GetHandleInformation
402 <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation> */
403 if (GetHandleInformation (handle, &hflags))
405 if ((hflags & HANDLE_FLAG_INHERIT) != 0)
406 /* fd denotes an inheritable descriptor. */
407 break;
411 if (fdmax > 0)
413 sinfo.cbReserved2 =
414 sizeof (unsigned int)
415 + fdmax * sizeof (unsigned char)
416 + fdmax * sizeof (HANDLE);
417 /* Add some padding, so that we can work with a properly HANDLE array. */
418 hblock = (char *) malloc (sinfo.cbReserved2 + (sizeof (HANDLE) - 1));
419 if (hblock == NULL)
420 goto out_of_memory_3;
421 * (unsigned int *) hblock = fdmax;
422 unsigned char *flags = (unsigned char *) (hblock + sizeof (unsigned int));
423 char *handles = (char *) (flags + fdmax);
424 HANDLE *handles_aligned =
425 (HANDLE *) (((uintptr_t) handles + (sizeof (HANDLE) - 1))
426 & - (uintptr_t) sizeof (HANDLE));
428 unsigned int fd;
429 for (fd = 0; fd < fdmax; fd++)
431 flags[fd] = 0;
432 handles_aligned[fd] = INVALID_HANDLE_VALUE;
433 /* The first three are already passed above. */
434 if (fd >= 3)
436 /* _get_osfhandle
437 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle> */
438 HANDLE handle = (HANDLE) _get_osfhandle (fd);
439 if (handle != INVALID_HANDLE_VALUE)
441 DWORD hflags;
442 /* GetHandleInformation
443 <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation> */
444 if (GetHandleInformation (handle, &hflags))
446 if ((hflags & HANDLE_FLAG_INHERIT) != 0)
448 /* fd denotes an inheritable descriptor. */
449 /* On Microsoft Windows, it would be sufficient to
450 set flags[fd] = 1. But on ReactOS or Wine,
451 adding the bit that indicates the handle type
452 may be necessary. So, just do it everywhere. */
453 switch (GetFileType (handle))
455 case FILE_TYPE_CHAR:
456 flags[fd] = 64 | 1;
457 break;
458 case FILE_TYPE_PIPE:
459 flags[fd] = 8 | 1;
460 break;
461 default:
462 flags[fd] = 1;
463 break;
465 handles_aligned[fd] = handle;
472 if (handles != (char *) handles_aligned)
473 memmove (handles, (char *) handles_aligned, fdmax * sizeof (HANDLE));
474 sinfo.lpReserved2 = (BYTE *) hblock;
476 else
478 sinfo.cbReserved2 = 0;
479 sinfo.lpReserved2 = NULL;
482 #endif
484 PROCESS_INFORMATION pinfo;
485 if (!CreateProcess (resolved_progname, command, NULL, NULL, TRUE,
486 process_creation_flags, envblock, currdir, &sinfo,
487 &pinfo))
489 DWORD error = GetLastError ();
491 if (hblock != NULL)
492 free (hblock);
493 if (envblock != NULL)
494 free (envblock);
495 free (command);
496 if (resolved_progname != progname)
497 free ((char *) resolved_progname);
499 /* Some of these errors probably cannot happen. But who knows... */
500 switch (error)
502 case ERROR_FILE_NOT_FOUND:
503 case ERROR_PATH_NOT_FOUND:
504 case ERROR_BAD_PATHNAME:
505 case ERROR_BAD_NET_NAME:
506 case ERROR_INVALID_NAME:
507 case ERROR_DIRECTORY:
508 errno = ENOENT;
509 break;
511 case ERROR_ACCESS_DENIED:
512 case ERROR_SHARING_VIOLATION:
513 errno = EACCES;
514 break;
516 case ERROR_OUTOFMEMORY:
517 errno = ENOMEM;
518 break;
520 case ERROR_BUFFER_OVERFLOW:
521 case ERROR_FILENAME_EXCED_RANGE:
522 errno = ENAMETOOLONG;
523 break;
525 case ERROR_BAD_FORMAT:
526 case ERROR_BAD_EXE_FORMAT:
527 errno = ENOEXEC;
528 break;
530 default:
531 errno = EINVAL;
532 break;
535 return -1;
538 if (pinfo.hThread)
539 CloseHandle (pinfo.hThread);
540 if (hblock != NULL)
541 free (hblock);
542 if (envblock != NULL)
543 free (envblock);
544 free (command);
545 if (resolved_progname != progname)
546 free ((char *) resolved_progname);
548 switch (mode)
550 case P_WAIT:
552 /* Wait until it terminates. Then get its exit status code. */
553 switch (WaitForSingleObject (pinfo.hProcess, INFINITE))
555 case WAIT_OBJECT_0:
556 break;
557 case WAIT_FAILED:
558 errno = ECHILD;
559 return -1;
560 default:
561 abort ();
564 DWORD exit_code;
565 if (!GetExitCodeProcess (pinfo.hProcess, &exit_code))
567 errno = ECHILD;
568 return -1;
570 CloseHandle (pinfo.hProcess);
571 return exit_code;
574 case P_NOWAIT:
575 /* Return pinfo.hProcess, not pinfo.dwProcessId. */
576 return (intptr_t) pinfo.hProcess;
578 case P_DETACH:
579 case P_OVERLAY:
580 CloseHandle (pinfo.hProcess);
581 return 0;
583 default:
584 /* Already checked above. */
585 abort ();
588 /*NOTREACHED*/
589 #if 0
590 out_of_memory_4:
591 if (hblock != NULL)
592 free (hblock);
593 #endif
594 out_of_memory_3:
595 if (envblock != NULL)
596 free (envblock);
597 out_of_memory_2:
598 free (command);
599 out_of_memory_1:
600 if (resolved_progname != progname)
601 free ((char *) resolved_progname);
602 errno = ENOMEM;
603 return -1;