1 /* Auxiliary functions for the creation of subprocesses. Native Windows API.
2 Copyright (C) 2001, 2003-2024 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/>. */
21 #include "windows-spawn.h"
23 /* Get declarations of the native Windows API functions. */
24 #define WIN32_LEAN_AND_MEAN
32 /* Get _get_osfhandle(). */
33 #if GNULIB_MSVC_NOTHROW
34 # include "msvc-nothrow.h"
42 /* Don't assume that UNICODE is not defined. */
44 #define STARTUPINFO STARTUPINFOA
46 #define CreateProcess CreateProcessA
48 #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*?"
49 #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"
51 /* Returns the length of a quoted argument string. */
53 quoted_arg_length (const char *string
)
55 bool quote_around
= (strpbrk (string
, SHELL_SPACE_CHARS
) != NULL
);
57 unsigned int backslashes
;
64 for (s
= string
; *s
!= '\0'; s
++)
68 length
+= backslashes
+ 1;
76 length
+= backslashes
+ 1;
81 /* Produces a quoted argument string.
82 Stores exactly quoted_arg_length (STRING) + 1 bytes, including the final
84 Returns a pointer past the stored quoted argument string. */
86 quoted_arg_string (const char *string
, char *mem
)
88 bool quote_around
= (strpbrk (string
, SHELL_SPACE_CHARS
) != NULL
);
90 unsigned int backslashes
;
97 for (s
= string
; *s
!= '\0'; s
++)
103 for (j
= backslashes
+ 1; j
> 0; j
--)
115 for (j
= backslashes
; j
> 0; j
--)
125 prepare_spawn (const char * const *argv
, char **mem_to_free
)
128 const char **new_argv
;
131 /* Count number of arguments. */
132 for (argc
= 0; argv
[argc
] != NULL
; argc
++)
135 /* Allocate new argument vector. */
136 new_argv
= (const char **) malloc ((1 + argc
+ 1) * sizeof (const char *));
138 /* Add an element upfront that can be used when argv[0] turns out to be a
139 script, not a program.
140 On Unix, this would be "/bin/sh". On native Windows, "sh" is actually
141 "sh.exe". We have to omit the directory part and rely on the search in
142 PATH, because the mingw "mount points" are not visible inside Windows
144 new_argv
[0] = "sh.exe";
146 /* Put quoted arguments into the new argument vector. */
147 size_t needed_size
= 0;
148 for (i
= 0; i
< argc
; i
++)
150 const char *string
= argv
[i
];
153 if (string
[0] == '\0')
154 length
= strlen ("\"\"");
155 else if (strpbrk (string
, SHELL_SPECIAL_CHARS
) != NULL
)
156 length
= quoted_arg_length (string
);
158 length
= strlen (string
);
159 needed_size
+= length
+ 1;
163 if (needed_size
== 0)
167 mem
= (char *) malloc (needed_size
);
170 /* Memory allocation failure. */
178 for (i
= 0; i
< argc
; i
++)
180 const char *string
= argv
[i
];
182 new_argv
[1 + i
] = mem
;
183 if (string
[0] == '\0')
185 size_t length
= strlen ("\"\"");
186 memcpy (mem
, "\"\"", length
+ 1);
189 else if (strpbrk (string
, SHELL_SPECIAL_CHARS
) != NULL
)
191 mem
= quoted_arg_string (string
, mem
);
195 size_t length
= strlen (string
);
196 memcpy (mem
, string
, length
+ 1);
200 new_argv
[1 + argc
] = NULL
;
206 compose_command (const char * const *argv
)
208 /* Just concatenate the argv[] strings, separated by spaces. */
211 /* Determine the size of the needed block of memory. */
212 size_t total_size
= 0;
213 const char * const *ap
;
215 for (ap
= argv
; (p
= *ap
) != NULL
; ap
++)
216 total_size
+= strlen (p
) + 1;
217 size_t command_size
= (total_size
> 0 ? total_size
: 1);
219 /* Allocate the block of memory. */
220 command
= (char *) malloc (command_size
);
231 for (ap
= argv
; (p
= *ap
) != NULL
; ap
++)
233 size_t size
= strlen (p
) + 1;
234 memcpy (cp
, p
, size
- 1);
247 compose_envblock (const char * const *envp
)
249 /* This is a bit hairy, because we don't have a lock that would prevent other
250 threads from making modifications in ENVP. So, just make sure we don't
251 crash; but if other threads are making modifications, part of the result
255 /* Guess the size of the needed block of memory.
256 The guess will be exact if other threads don't make modifications. */
257 size_t total_size
= 0;
258 const char * const *ep
;
260 for (ep
= envp
; (p
= *ep
) != NULL
; ep
++)
261 total_size
+= strlen (p
) + 1;
262 size_t envblock_size
= total_size
;
264 /* Allocate the block of memory. */
265 char *envblock
= (char *) malloc (envblock_size
+ 1);
266 if (envblock
== NULL
)
271 size_t envblock_used
= 0;
272 for (ep
= envp
; (p
= *ep
) != NULL
; ep
++)
274 size_t size
= strlen (p
) + 1;
275 if (envblock_used
+ size
> envblock_size
)
277 /* Other threads did modifications. Need more memory. */
278 envblock_size
+= envblock_size
/ 2;
279 if (envblock_used
+ size
> envblock_size
)
280 envblock_size
= envblock_used
+ size
;
282 char *new_envblock
= (char *) realloc (envblock
, envblock_size
+ 1);
283 if (new_envblock
== NULL
)
289 envblock
= new_envblock
;
291 memcpy (envblock
+ envblock_used
, p
, size
);
292 envblock_used
+= size
;
293 if (envblock
[envblock_used
- 1] != '\0')
295 /* Other threads did modifications. Restart. */
300 envblock
[envblock_used
] = '\0';
306 init_inheritable_handles (struct inheritable_handles
*inh_handles
,
309 /* Determine the minimal count of handles we need to care about. */
310 size_t handles_count
;
313 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/getmaxstdio>
314 Default value is 512. */
315 unsigned int fdmax
= _getmaxstdio ();
318 for (; fdmax
> 3; fdmax
--)
320 unsigned int fd
= fdmax
- 1;
322 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle> */
323 HANDLE handle
= (HANDLE
) _get_osfhandle (fd
);
324 if (handle
!= INVALID_HANDLE_VALUE
)
327 /* We will add fd to the array, regardless of whether it is
328 inheritable or not. */
333 /* GetHandleInformation
334 <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation> */
335 if (GetHandleInformation (handle
, &hflags
))
337 if ((hflags
& HANDLE_FLAG_INHERIT
) != 0)
338 /* fd denotes an inheritable descriptor. */
344 handles_count
= fdmax
;
346 /* Note: handles_count >= 3. */
348 /* Allocate the array. */
349 size_t handles_allocated
= handles_count
;
351 (struct IHANDLE
*) malloc (handles_allocated
* sizeof (struct IHANDLE
));
358 /* Fill in the array. */
360 HANDLE curr_process
= (duplicate
? GetCurrentProcess () : INVALID_HANDLE_VALUE
);
362 for (fd
= 0; fd
< handles_count
; fd
++)
364 ih
[fd
].handle
= INVALID_HANDLE_VALUE
;
366 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle> */
367 HANDLE handle
= (HANDLE
) _get_osfhandle (fd
);
368 if (handle
!= INVALID_HANDLE_VALUE
)
371 /* GetHandleInformation
372 <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation> */
373 if (GetHandleInformation (handle
, &hflags
))
377 /* Add fd to the array, regardless of whether it is
378 inheritable or not. */
379 if ((hflags
& HANDLE_FLAG_INHERIT
) != 0)
381 /* Instead of duplicating it, just mark it as shared. */
382 ih
[fd
].handle
= handle
;
383 ih
[fd
].flags
= KEEP_OPEN_IN_PARENT
| KEEP_OPEN_IN_CHILD
;
387 if (!DuplicateHandle (curr_process
, handle
,
388 curr_process
, &ih
[fd
].handle
,
389 0, TRUE
, DUPLICATE_SAME_ACCESS
))
392 for (i
= 0; i
< fd
; i
++)
393 if (ih
[i
].handle
!= INVALID_HANDLE_VALUE
394 && !(ih
[i
].flags
& KEEP_OPEN_IN_PARENT
))
395 CloseHandle (ih
[i
].handle
);
397 errno
= EBADF
; /* arbitrary */
405 if ((hflags
& HANDLE_FLAG_INHERIT
) != 0)
407 /* fd denotes an inheritable descriptor. */
408 ih
[fd
].handle
= handle
;
409 ih
[fd
].flags
= KEEP_OPEN_IN_CHILD
;
417 /* Return the result. */
418 inh_handles
->count
= handles_count
;
419 inh_handles
->allocated
= handles_allocated
;
420 inh_handles
->ih
= ih
;
425 compose_handles_block (const struct inheritable_handles
*inh_handles
,
429 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa> */
430 sinfo
->dwFlags
= STARTF_USESTDHANDLES
;
431 sinfo
->hStdInput
= inh_handles
->ih
[0].handle
;
432 sinfo
->hStdOutput
= inh_handles
->ih
[1].handle
;
433 sinfo
->hStdError
= inh_handles
->ih
[2].handle
;
435 /* On newer versions of Windows, more file descriptors / handles than the
436 first three can be passed.
437 The format is as follows: Let N be an exclusive upper bound for the file
438 descriptors to be passed. Two arrays are constructed in memory:
439 - flags[0..N-1], of element type 'unsigned char',
440 - handles[0..N-1], of element type 'HANDLE' or 'intptr_t'.
441 For used entries, handles[i] is the handle, and flags[i] is a set of flags,
443 1 for open file descriptors,
444 64 for handles of type FILE_TYPE_CHAR,
445 8 for handles of type FILE_TYPE_PIPE,
447 For unused entries - this may include any of the first three, since they
448 are already passed above -, handles[i] is INVALID_HANDLE_VALUE and flags[i]
450 lpReserved2 now is a pointer to the concatenation (without padding) of:
451 - an 'unsigned int' whose value is N,
452 - the contents of the flags[0..N-1] array,
453 - the contents of the handles[0..N-1] array.
454 cbReserved2 is the size (in bytes) of the object at lpReserved2. */
456 size_t handles_count
= inh_handles
->count
;
459 sizeof (unsigned int)
460 + handles_count
* sizeof (unsigned char)
461 + handles_count
* sizeof (HANDLE
);
462 /* Add some padding, so that we can work with a properly aligned HANDLE
464 char *hblock
= (char *) malloc (sinfo
->cbReserved2
+ (sizeof (HANDLE
) - 1));
470 unsigned char *flags
= (unsigned char *) (hblock
+ sizeof (unsigned int));
471 char *handles
= (char *) (flags
+ handles_count
);
472 HANDLE
*handles_aligned
=
473 (HANDLE
*) (((uintptr_t) handles
+ (sizeof (HANDLE
) - 1))
474 & - (uintptr_t) sizeof (HANDLE
));
476 * (unsigned int *) hblock
= handles_count
;
479 for (fd
= 0; fd
< handles_count
; fd
++)
481 handles_aligned
[fd
] = INVALID_HANDLE_VALUE
;
484 HANDLE handle
= inh_handles
->ih
[fd
].handle
;
485 if (handle
!= INVALID_HANDLE_VALUE
486 /* The first three are possibly already passed above.
487 But they need to passed here as well, if they have some flags. */
488 && (fd
>= 3 || (unsigned char) inh_handles
->ih
[fd
].flags
!= 0))
491 /* GetHandleInformation
492 <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation> */
493 if (GetHandleInformation (handle
, &hflags
))
495 if ((hflags
& HANDLE_FLAG_INHERIT
) != 0)
497 /* fd denotes an inheritable descriptor. */
498 handles_aligned
[fd
] = handle
;
499 /* On Microsoft Windows, it would be sufficient to set
500 flags[fd] = 1. But on ReactOS or Wine, adding the bit
501 that indicates the handle type may be necessary. So,
502 just do it everywhere. */
503 flags
[fd
] = 1 | (unsigned char) inh_handles
->ih
[fd
].flags
;
504 switch (GetFileType (handle
))
517 /* We shouldn't have any non-inheritable handles in
518 inh_handles->handles. */
524 if (handles
!= (char *) handles_aligned
)
525 memmove (handles
, (char *) handles_aligned
, handles_count
* sizeof (HANDLE
));
527 sinfo
->lpReserved2
= (BYTE
*) hblock
;
533 free_inheritable_handles (struct inheritable_handles
*inh_handles
)
535 free (inh_handles
->ih
);
539 convert_CreateProcess_error (DWORD error
)
541 /* Some of these errors probably cannot happen. But who knows... */
544 case ERROR_FILE_NOT_FOUND
:
545 case ERROR_PATH_NOT_FOUND
:
546 case ERROR_BAD_PATHNAME
:
547 case ERROR_BAD_NET_NAME
:
548 case ERROR_INVALID_NAME
:
549 case ERROR_DIRECTORY
:
553 case ERROR_ACCESS_DENIED
:
554 case ERROR_SHARING_VIOLATION
:
558 case ERROR_OUTOFMEMORY
:
562 case ERROR_BUFFER_OVERFLOW
:
563 case ERROR_FILENAME_EXCED_RANGE
:
567 case ERROR_BAD_FORMAT
:
568 case ERROR_BAD_EXE_FORMAT
:
579 spawnpvech (int mode
,
580 const char *progname
, const char * const *argv
,
581 const char * const *envp
,
583 HANDLE stdin_handle
, HANDLE stdout_handle
, HANDLE stderr_handle
)
585 /* Validate the arguments. */
589 || mode
== P_OVERLAY
)
590 || progname
== NULL
|| argv
== NULL
)
596 /* Implement the 'p' letter: search for PROGNAME in getenv ("PATH"). */
597 const char *resolved_progname
=
598 find_in_given_path (progname
, getenv ("PATH"), NULL
, false);
599 if (resolved_progname
== NULL
)
602 /* Compose the command. */
603 char *command
= compose_command (argv
);
605 goto out_of_memory_1
;
607 /* Copy *ENVP into a contiguous block of memory. */
613 envblock
= compose_envblock (envp
);
614 if (envblock
== NULL
)
615 goto out_of_memory_2
;
618 /* Collect the inheritable handles. */
619 struct inheritable_handles inh_handles
;
620 if (init_inheritable_handles (&inh_handles
, false) < 0)
622 int saved_errno
= errno
;
623 if (envblock
!= NULL
)
626 if (resolved_progname
!= progname
)
627 free ((char *) resolved_progname
);
631 inh_handles
.ih
[0].handle
= stdin_handle
;
632 inh_handles
.ih
[0].flags
= KEEP_OPEN_IN_CHILD
;
633 inh_handles
.ih
[1].handle
= stdout_handle
;
634 inh_handles
.ih
[1].flags
= KEEP_OPEN_IN_CHILD
;
635 inh_handles
.ih
[2].handle
= stderr_handle
;
636 inh_handles
.ih
[2].flags
= KEEP_OPEN_IN_CHILD
;
639 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa> */
640 /* <https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags> */
641 DWORD process_creation_flags
= (mode
== P_DETACH
? DETACHED_PROCESS
: 0);
643 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa> */
645 sinfo
.cb
= sizeof (STARTUPINFO
);
646 sinfo
.lpReserved
= NULL
;
647 sinfo
.lpDesktop
= NULL
;
648 sinfo
.lpTitle
= NULL
;
649 if (compose_handles_block (&inh_handles
, &sinfo
) < 0)
651 int saved_errno
= errno
;
652 free_inheritable_handles (&inh_handles
);
653 if (envblock
!= NULL
)
656 if (resolved_progname
!= progname
)
657 free ((char *) resolved_progname
);
662 PROCESS_INFORMATION pinfo
;
663 if (!CreateProcess (resolved_progname
, command
, NULL
, NULL
, TRUE
,
664 process_creation_flags
, envblock
, currdir
, &sinfo
,
667 DWORD error
= GetLastError ();
669 free (sinfo
.lpReserved2
);
670 free_inheritable_handles (&inh_handles
);
671 if (envblock
!= NULL
)
674 if (resolved_progname
!= progname
)
675 free ((char *) resolved_progname
);
677 errno
= convert_CreateProcess_error (error
);
682 CloseHandle (pinfo
.hThread
);
683 free (sinfo
.lpReserved2
);
684 free_inheritable_handles (&inh_handles
);
685 if (envblock
!= NULL
)
688 if (resolved_progname
!= progname
)
689 free ((char *) resolved_progname
);
695 /* Wait until it terminates. Then get its exit status code. */
696 switch (WaitForSingleObject (pinfo
.hProcess
, INFINITE
))
708 if (!GetExitCodeProcess (pinfo
.hProcess
, &exit_code
))
713 CloseHandle (pinfo
.hProcess
);
718 /* Return pinfo.hProcess, not pinfo.dwProcessId. */
719 return (intptr_t) pinfo
.hProcess
;
723 CloseHandle (pinfo
.hProcess
);
727 /* Already checked above. */
735 if (resolved_progname
!= progname
)
736 free ((char *) resolved_progname
);