announce-gen: add comments
[gnulib.git] / lib / windows-spawn.c
blobdccd40e112f800b80ab31db2f2818acf159da42c
1 /* Auxiliary functions for the creation of subprocesses. Native Windows API.
2 Copyright (C) 2001, 2003-2025 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2003.
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
10 This file 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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser 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 <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
32 /* Get _get_osfhandle(). */
33 #if GNULIB_MSVC_NOTHROW
34 # include "msvc-nothrow.h"
35 #else
36 # include <io.h>
37 #endif
38 #include <process.h>
40 #include "findprog.h"
41 #include "windows-path.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, const char *new_PATH)
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 if (new_PATH != NULL)
262 total_size += strlen (new_PATH) + 1;
263 for (ep = envp; (p = *ep) != NULL; ep++)
264 if (!(new_PATH != NULL && strncmp (p, "PATH=", 5) == 0))
265 total_size += strlen (p) + 1;
266 size_t envblock_size = total_size;
268 /* Allocate the block of memory. */
269 char *envblock = (char *) malloc (envblock_size + 1);
270 if (envblock == NULL)
272 errno = ENOMEM;
273 return NULL;
275 size_t envblock_used = 0;
276 if (new_PATH != NULL)
278 size_t size = strlen (new_PATH) + 1;
279 memcpy (envblock + envblock_used, new_PATH, size);
280 envblock_used += size;
282 for (ep = envp; (p = *ep) != NULL; ep++)
283 if (!(new_PATH != NULL && strncmp (p, "PATH=", 5) == 0))
285 size_t size = strlen (p) + 1;
286 if (envblock_used + size > envblock_size)
288 /* Other threads did modifications. Need more memory. */
289 envblock_size += envblock_size / 2;
290 if (envblock_used + size > envblock_size)
291 envblock_size = envblock_used + size;
293 char *new_envblock =
294 (char *) realloc (envblock, envblock_size + 1);
295 if (new_envblock == NULL)
297 free (envblock);
298 errno = ENOMEM;
299 return NULL;
301 envblock = new_envblock;
303 memcpy (envblock + envblock_used, p, size);
304 envblock_used += size;
305 if (envblock[envblock_used - 1] != '\0')
307 /* Other threads did modifications. Restart. */
308 free (envblock);
309 goto retry;
312 envblock[envblock_used] = '\0';
313 return envblock;
318 init_inheritable_handles (struct inheritable_handles *inh_handles,
319 bool duplicate)
321 /* Determine the minimal count of handles we need to care about. */
322 size_t handles_count;
324 /* _getmaxstdio
325 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/getmaxstdio>
326 Default value is 512. */
327 unsigned int fdmax = _getmaxstdio ();
328 if (fdmax < 3)
329 fdmax = 3;
330 for (; fdmax > 3; fdmax--)
332 unsigned int fd = fdmax - 1;
333 /* _get_osfhandle
334 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle> */
335 HANDLE handle = (HANDLE) _get_osfhandle (fd);
336 if (handle != INVALID_HANDLE_VALUE)
338 if (duplicate)
339 /* We will add fd to the array, regardless of whether it is
340 inheritable or not. */
341 break;
342 else
344 DWORD hflags;
345 /* GetHandleInformation
346 <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation> */
347 if (GetHandleInformation (handle, &hflags))
349 if ((hflags & HANDLE_FLAG_INHERIT) != 0)
350 /* fd denotes an inheritable descriptor. */
351 break;
356 handles_count = fdmax;
358 /* Note: handles_count >= 3. */
360 /* Allocate the array. */
361 size_t handles_allocated = handles_count;
362 struct IHANDLE *ih =
363 (struct IHANDLE *) malloc (handles_allocated * sizeof (struct IHANDLE));
364 if (ih == NULL)
366 errno = ENOMEM;
367 return -1;
370 /* Fill in the array. */
372 HANDLE curr_process = (duplicate ? GetCurrentProcess () : INVALID_HANDLE_VALUE);
373 unsigned int fd;
374 for (fd = 0; fd < handles_count; fd++)
376 ih[fd].handle = INVALID_HANDLE_VALUE;
377 /* _get_osfhandle
378 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle> */
379 HANDLE handle = (HANDLE) _get_osfhandle (fd);
380 if (handle != INVALID_HANDLE_VALUE)
382 DWORD hflags;
383 /* GetHandleInformation
384 <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation> */
385 if (GetHandleInformation (handle, &hflags))
387 if (duplicate)
389 /* Add fd to the array, regardless of whether it is
390 inheritable or not. */
391 if ((hflags & HANDLE_FLAG_INHERIT) != 0)
393 /* Instead of duplicating it, just mark it as shared. */
394 ih[fd].handle = handle;
395 ih[fd].flags = KEEP_OPEN_IN_PARENT | KEEP_OPEN_IN_CHILD;
397 else
399 if (!DuplicateHandle (curr_process, handle,
400 curr_process, &ih[fd].handle,
401 0, TRUE, DUPLICATE_SAME_ACCESS))
403 unsigned int i;
404 for (i = 0; i < fd; i++)
405 if (ih[i].handle != INVALID_HANDLE_VALUE
406 && !(ih[i].flags & KEEP_OPEN_IN_PARENT))
407 CloseHandle (ih[i].handle);
408 free (ih);
409 errno = EBADF; /* arbitrary */
410 return -1;
412 ih[fd].flags = 0;
415 else
417 if ((hflags & HANDLE_FLAG_INHERIT) != 0)
419 /* fd denotes an inheritable descriptor. */
420 ih[fd].handle = handle;
421 ih[fd].flags = KEEP_OPEN_IN_CHILD;
429 /* Return the result. */
430 inh_handles->count = handles_count;
431 inh_handles->allocated = handles_allocated;
432 inh_handles->ih = ih;
433 return 0;
437 compose_handles_block (const struct inheritable_handles *inh_handles,
438 STARTUPINFO *sinfo)
440 /* STARTUPINFO
441 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa> */
442 sinfo->dwFlags = STARTF_USESTDHANDLES;
443 sinfo->hStdInput = inh_handles->ih[0].handle;
444 sinfo->hStdOutput = inh_handles->ih[1].handle;
445 sinfo->hStdError = inh_handles->ih[2].handle;
447 /* On newer versions of Windows, more file descriptors / handles than the
448 first three can be passed.
449 The format is as follows: Let N be an exclusive upper bound for the file
450 descriptors to be passed. Two arrays are constructed in memory:
451 - flags[0..N-1], of element type 'unsigned char',
452 - handles[0..N-1], of element type 'HANDLE' or 'intptr_t'.
453 For used entries, handles[i] is the handle, and flags[i] is a set of flags,
454 a combination of:
455 1 for open file descriptors,
456 64 for handles of type FILE_TYPE_CHAR,
457 8 for handles of type FILE_TYPE_PIPE,
458 32 for O_APPEND.
459 For unused entries - this may include any of the first three, since they
460 are already passed above -, handles[i] is INVALID_HANDLE_VALUE and flags[i]
461 is zero.
462 lpReserved2 now is a pointer to the concatenation (without padding) of:
463 - an 'unsigned int' whose value is N,
464 - the contents of the flags[0..N-1] array,
465 - the contents of the handles[0..N-1] array.
466 cbReserved2 is the size (in bytes) of the object at lpReserved2. */
468 size_t handles_count = inh_handles->count;
470 sinfo->cbReserved2 =
471 sizeof (unsigned int)
472 + handles_count * sizeof (unsigned char)
473 + handles_count * sizeof (HANDLE);
474 /* Add some padding, so that we can work with a properly aligned HANDLE
475 array. */
476 char *hblock = (char *) malloc (sinfo->cbReserved2 + (sizeof (HANDLE) - 1));
477 if (hblock == NULL)
479 errno = ENOMEM;
480 return -1;
482 unsigned char *flags = (unsigned char *) (hblock + sizeof (unsigned int));
483 char *handles = (char *) (flags + handles_count);
484 HANDLE *handles_aligned =
485 (HANDLE *) (((uintptr_t) handles + (sizeof (HANDLE) - 1))
486 & - (uintptr_t) sizeof (HANDLE));
488 * (unsigned int *) hblock = handles_count;
490 unsigned int fd;
491 for (fd = 0; fd < handles_count; fd++)
493 handles_aligned[fd] = INVALID_HANDLE_VALUE;
494 flags[fd] = 0;
496 HANDLE handle = inh_handles->ih[fd].handle;
497 if (handle != INVALID_HANDLE_VALUE
498 /* The first three are possibly already passed above.
499 But they need to passed here as well, if they have some flags. */
500 && (fd >= 3 || (unsigned char) inh_handles->ih[fd].flags != 0))
502 DWORD hflags;
503 /* GetHandleInformation
504 <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation> */
505 if (GetHandleInformation (handle, &hflags))
507 if ((hflags & HANDLE_FLAG_INHERIT) != 0)
509 /* fd denotes an inheritable descriptor. */
510 handles_aligned[fd] = handle;
511 /* On Microsoft Windows, it would be sufficient to set
512 flags[fd] = 1. But on ReactOS or Wine, adding the bit
513 that indicates the handle type may be necessary. So,
514 just do it everywhere. */
515 flags[fd] = 1 | (unsigned char) inh_handles->ih[fd].flags;
516 switch (GetFileType (handle))
518 case FILE_TYPE_CHAR:
519 flags[fd] |= 64;
520 break;
521 case FILE_TYPE_PIPE:
522 flags[fd] |= 8;
523 break;
524 default:
525 break;
528 else
529 /* We shouldn't have any non-inheritable handles in
530 inh_handles->handles. */
531 abort ();
536 if (handles != (char *) handles_aligned)
537 memmove (handles, (char *) handles_aligned, handles_count * sizeof (HANDLE));
539 sinfo->lpReserved2 = (BYTE *) hblock;
541 return 0;
544 void
545 free_inheritable_handles (struct inheritable_handles *inh_handles)
547 free (inh_handles->ih);
551 convert_CreateProcess_error (DWORD error)
553 /* Some of these errors probably cannot happen. But who knows... */
554 switch (error)
556 case ERROR_FILE_NOT_FOUND:
557 case ERROR_PATH_NOT_FOUND:
558 case ERROR_BAD_PATHNAME:
559 case ERROR_BAD_NET_NAME:
560 case ERROR_INVALID_NAME:
561 case ERROR_DIRECTORY:
562 return ENOENT;
564 case ERROR_ACCESS_DENIED:
565 case ERROR_SHARING_VIOLATION:
566 return EACCES;
568 case ERROR_OUTOFMEMORY:
569 return ENOMEM;
571 case ERROR_BUFFER_OVERFLOW:
572 case ERROR_FILENAME_EXCED_RANGE:
573 return ENAMETOOLONG;
575 case ERROR_BAD_FORMAT:
576 case ERROR_BAD_EXE_FORMAT:
577 return ENOEXEC;
579 default:
580 return EINVAL;
584 intptr_t
585 spawnpvech (int mode,
586 const char *progname, const char * const *argv,
587 const char * const *envp,
588 const char * const *dll_dirs,
589 const char *currdir,
590 HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle)
592 /* Validate the arguments. */
593 if (!(mode == P_WAIT
594 || mode == P_NOWAIT
595 || mode == P_DETACH
596 || mode == P_OVERLAY)
597 || progname == NULL || argv == NULL)
599 errno = EINVAL;
600 return -1;
603 /* Implement the 'p' letter: search for PROGNAME in getenv ("PATH"). */
604 const char *resolved_progname =
605 find_in_given_path (progname, getenv ("PATH"), NULL, false);
606 if (resolved_progname == NULL)
607 return -1;
609 /* Compose the command. */
610 char *command = compose_command (argv);
611 if (command == NULL)
612 goto out_of_memory_1;
614 /* Copy *ENVP into a contiguous block of memory. */
615 char *envblock;
616 if (envp == NULL && !(dll_dirs != NULL && dll_dirs[0] != NULL))
617 envblock = NULL;
618 else
620 if (envp == NULL)
621 /* Documentation:
622 <https://learn.microsoft.com/en-us/cpp/c-runtime-library/environ-wenviron> */
623 envp = (const char **) _environ;
624 char *new_PATH = NULL;
625 if (dll_dirs != NULL && dll_dirs[0] != NULL)
627 new_PATH = extended_PATH (dll_dirs);
628 if (new_PATH == NULL)
629 goto out_of_memory_2;
631 envblock = compose_envblock (envp, new_PATH);
632 free (new_PATH);
633 if (envblock == NULL)
634 goto out_of_memory_2;
637 /* Collect the inheritable handles. */
638 struct inheritable_handles inh_handles;
639 if (init_inheritable_handles (&inh_handles, false) < 0)
641 int saved_errno = errno;
642 if (envblock != NULL)
643 free (envblock);
644 free (command);
645 if (resolved_progname != progname)
646 free ((char *) resolved_progname);
647 errno = saved_errno;
648 return -1;
650 inh_handles.ih[0].handle = stdin_handle;
651 inh_handles.ih[0].flags = KEEP_OPEN_IN_CHILD;
652 inh_handles.ih[1].handle = stdout_handle;
653 inh_handles.ih[1].flags = KEEP_OPEN_IN_CHILD;
654 inh_handles.ih[2].handle = stderr_handle;
655 inh_handles.ih[2].flags = KEEP_OPEN_IN_CHILD;
657 /* CreateProcess
658 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa> */
659 /* <https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags> */
660 DWORD process_creation_flags = (mode == P_DETACH ? DETACHED_PROCESS : 0);
661 /* STARTUPINFO
662 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa> */
663 STARTUPINFO sinfo;
664 sinfo.cb = sizeof (STARTUPINFO);
665 sinfo.lpReserved = NULL;
666 sinfo.lpDesktop = NULL;
667 sinfo.lpTitle = NULL;
668 if (compose_handles_block (&inh_handles, &sinfo) < 0)
670 int saved_errno = errno;
671 free_inheritable_handles (&inh_handles);
672 if (envblock != NULL)
673 free (envblock);
674 free (command);
675 if (resolved_progname != progname)
676 free ((char *) resolved_progname);
677 errno = saved_errno;
678 return -1;
681 PROCESS_INFORMATION pinfo;
682 if (!CreateProcess (resolved_progname, command, NULL, NULL, TRUE,
683 process_creation_flags, envblock, currdir, &sinfo,
684 &pinfo))
686 DWORD error = GetLastError ();
688 free (sinfo.lpReserved2);
689 free_inheritable_handles (&inh_handles);
690 if (envblock != NULL)
691 free (envblock);
692 free (command);
693 if (resolved_progname != progname)
694 free ((char *) resolved_progname);
696 errno = convert_CreateProcess_error (error);
697 return -1;
700 if (pinfo.hThread)
701 CloseHandle (pinfo.hThread);
702 free (sinfo.lpReserved2);
703 free_inheritable_handles (&inh_handles);
704 if (envblock != NULL)
705 free (envblock);
706 free (command);
707 if (resolved_progname != progname)
708 free ((char *) resolved_progname);
710 switch (mode)
712 case P_WAIT:
714 /* Wait until it terminates. Then get its exit status code. */
715 switch (WaitForSingleObject (pinfo.hProcess, INFINITE))
717 case WAIT_OBJECT_0:
718 break;
719 case WAIT_FAILED:
720 errno = ECHILD;
721 return -1;
722 default:
723 abort ();
726 DWORD exit_code;
727 if (!GetExitCodeProcess (pinfo.hProcess, &exit_code))
729 errno = ECHILD;
730 return -1;
732 CloseHandle (pinfo.hProcess);
733 return exit_code;
736 case P_NOWAIT:
737 /* Return pinfo.hProcess, not pinfo.dwProcessId. */
738 return (intptr_t) pinfo.hProcess;
740 case P_DETACH:
741 case P_OVERLAY:
742 CloseHandle (pinfo.hProcess);
743 return 0;
745 default:
746 /* Already checked above. */
747 abort ();
750 /*NOTREACHED*/
751 out_of_memory_2:
752 free (command);
753 out_of_memory_1:
754 if (resolved_progname != progname)
755 free ((char *) resolved_progname);
756 errno = ENOMEM;
757 return -1;