1 /* Auxiliary functions for the creation of subprocesses. Native Windows API.
2 Copyright (C) 2001, 2003-2023 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2003.
4
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.
9
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.
14
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/>. */
17
18 #include <config.h>
19
20 /* Specification. */
21 #include "windows-spawn.h"
22
23 /* Get declarations of the native Windows API functions. */
24 #define WIN32_LEAN_AND_MEAN
25 #include <windows.h>
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31
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>
39
40 #include "findprog.h"
41
42 /* Don't assume that UNICODE is not defined. */
43 #undef STARTUPINFO
44 #define STARTUPINFO STARTUPINFOA
45 #undef CreateProcess
46 #define CreateProcess CreateProcessA
47
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"
50
51 /* Returns the length of a quoted argument string. */
52 static size_t
53 quoted_arg_length (const char *string)
54 {
55 bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
56 size_t length;
57 unsigned int backslashes;
58 const char *s;
59
60 length = 0;
61 backslashes = 0;
62 if (quote_around)
63 length++;
64 for (s = string; *s != '\0'; s++)
65 {
66 char c = *s;
67 if (c == '"')
68 length += backslashes + 1;
69 length++;
70 if (c == '\\')
71 backslashes++;
72 else
73 backslashes = 0;
74 }
75 if (quote_around)
76 length += backslashes + 1;
77
78 return length;
79 }
80
81 /* Produces a quoted argument string.
82 Stores exactly quoted_arg_length (STRING) + 1 bytes, including the final
83 NUL byte, at MEM.
84 Returns a pointer past the stored quoted argument string. */
85 static char *
86 quoted_arg_string (const char *string, char *mem)
87 {
88 bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
89 char *p;
90 unsigned int backslashes;
91 const char *s;
92
93 p = mem;
94 backslashes = 0;
95 if (quote_around)
96 *p++ = '"';
97 for (s = string; *s != '\0'; s++)
98 {
99 char c = *s;
100 if (c == '"')
101 {
102 unsigned int j;
103 for (j = backslashes + 1; j > 0; j--)
104 *p++ = '\\';
105 }
106 *p++ = c;
107 if (c == '\\')
108 backslashes++;
109 else
110 backslashes = 0;
111 }
112 if (quote_around)
113 {
114 unsigned int j;
115 for (j = backslashes; j > 0; j--)
116 *p++ = '\\';
117 *p++ = '"';
118 }
119 *p++ = '\0';
120
121 return p;
122 }
123
124 const char **
125 prepare_spawn (const char * const *argv, char **mem_to_free)
126 {
127 size_t argc;
128 const char **new_argv;
129 size_t i;
130
131 /* Count number of arguments. */
132 for (argc = 0; argv[argc] != NULL; argc++)
133 ;
134
135 /* Allocate new argument vector. */
136 new_argv = (const char **) malloc ((1 + argc + 1) * sizeof (const char *));
137
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
143 CreateProcess(). */
144 new_argv[0] = "sh.exe";
145
146 /* Put quoted arguments into the new argument vector. */
147 size_t needed_size = 0;
148 for (i = 0; i < argc; i++)
149 {
150 const char *string = argv[i];
151 size_t length;
152
153 if (string[0] == '\0')
154 length = strlen ("\"\"");
155 else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
156 length = quoted_arg_length (string);
157 else
158 length = strlen (string);
159 needed_size += length + 1;
160 }
161
162 char *mem;
163 if (needed_size == 0)
164 mem = NULL;
165 else
166 {
167 mem = (char *) malloc (needed_size);
168 if (mem == NULL)
169 {
170 /* Memory allocation failure. */
171 free (new_argv);
172 errno = ENOMEM;
173 return NULL;
174 }
175 }
176 *mem_to_free = mem;
177
178 for (i = 0; i < argc; i++)
179 {
180 const char *string = argv[i];
181
182 new_argv[1 + i] = mem;
183 if (string[0] == '\0')
184 {
185 size_t length = strlen ("\"\"");
186 memcpy (mem, "\"\"", length + 1);
187 mem += length + 1;
188 }
189 else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
190 {
191 mem = quoted_arg_string (string, mem);
192 }
193 else
194 {
195 size_t length = strlen (string);
196 memcpy (mem, string, length + 1);
197 mem += length + 1;
198 }
199 }
200 new_argv[1 + argc] = NULL;
201
202 return new_argv;
203 }
204
205 char *
206 compose_command (const char * const *argv)
207 {
208 /* Just concatenate the argv[] strings, separated by spaces. */
209 char *command;
210
211 /* Determine the size of the needed block of memory. */
212 size_t total_size = 0;
213 const char * const *ap;
214 const char *p;
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);
218
219 /* Allocate the block of memory. */
220 command = (char *) malloc (command_size);
221 if (command == NULL)
222 {
223 errno = ENOMEM;
224 return NULL;
225 }
226
227 /* Fill it. */
228 if (total_size > 0)
229 {
230 char *cp = command;
231 for (ap = argv; (p = *ap) != NULL; ap++)
232 {
233 size_t size = strlen (p) + 1;
234 memcpy (cp, p, size - 1);
235 cp += size;
236 cp[-1] = ' ';
237 }
238 cp[-1] = '\0';
239 }
240 else
241 *command = '\0';
242
243 return command;
244 }
245
246 char *
247 compose_envblock (const char * const *envp)
248 {
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
252 may be wrong. */
253 retry:
254 {
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;
259 const char *p;
260 for (ep = envp; (p = *ep) != NULL; ep++)
261 total_size += strlen (p) + 1;
262 size_t envblock_size = total_size;
263
264 /* Allocate the block of memory. */
265 char *envblock = (char *) malloc (envblock_size + 1);
266 if (envblock == NULL)
267 {
268 errno = ENOMEM;
269 return NULL;
270 }
271 size_t envblock_used = 0;
272 for (ep = envp; (p = *ep) != NULL; ep++)
273 {
274 size_t size = strlen (p) + 1;
275 if (envblock_used + size > envblock_size)
276 {
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;
281
282 char *new_envblock = (char *) realloc (envblock, envblock_size + 1);
283 if (new_envblock == NULL)
284 {
285 free (envblock);
286 errno = ENOMEM;
287 return NULL;
288 }
289 envblock = new_envblock;
290 }
291 memcpy (envblock + envblock_used, p, size);
292 envblock_used += size;
293 if (envblock[envblock_used - 1] != '\0')
294 {
295 /* Other threads did modifications. Restart. */
296 free (envblock);
297 goto retry;
298 }
299 }
300 envblock[envblock_used] = '\0';
301 return envblock;
302 }
303 }
304
305 int
306 init_inheritable_handles (struct inheritable_handles *inh_handles,
307 bool duplicate)
308 {
309 /* Determine the minimal count of handles we need to care about. */
310 size_t handles_count;
311 {
312 /* _getmaxstdio
313 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/getmaxstdio>
314 Default value is 512. */
315 unsigned int fdmax = _getmaxstdio ();
316 if (fdmax < 3)
317 fdmax = 3;
318 for (; fdmax > 3; fdmax--)
319 {
320 unsigned int fd = fdmax - 1;
321 /* _get_osfhandle
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)
325 {
326 if (duplicate)
327 /* We will add fd to the array, regardless of whether it is
328 inheritable or not. */
329 break;
330 else
331 {
332 DWORD hflags;
333 /* GetHandleInformation
334 <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation> */
335 if (GetHandleInformation (handle, &hflags))
336 {
337 if ((hflags & HANDLE_FLAG_INHERIT) != 0)
338 /* fd denotes an inheritable descriptor. */
339 break;
340 }
341 }
342 }
343 }
344 handles_count = fdmax;
345 }
346 /* Note: handles_count >= 3. */
347
348 /* Allocate the array. */
349 size_t handles_allocated = handles_count;
350 struct IHANDLE *ih =
351 (struct IHANDLE *) malloc (handles_allocated * sizeof (struct IHANDLE));
352 if (ih == NULL)
353 {
354 errno = ENOMEM;
355 return -1;
356 }
357
358 /* Fill in the array. */
359 {
360 HANDLE curr_process = (duplicate ? GetCurrentProcess () : INVALID_HANDLE_VALUE);
361 unsigned int fd;
362 for (fd = 0; fd < handles_count; fd++)
363 {
364 ih[fd].handle = INVALID_HANDLE_VALUE;
365 /* _get_osfhandle
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)
369 {
370 DWORD hflags;
371 /* GetHandleInformation
372 <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation> */
373 if (GetHandleInformation (handle, &hflags))
374 {
375 if (duplicate)
376 {
377 /* Add fd to the array, regardless of whether it is
378 inheritable or not. */
379 if ((hflags & HANDLE_FLAG_INHERIT) != 0)
380 {
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;
384 }
385 else
386 {
387 if (!DuplicateHandle (curr_process, handle,
388 curr_process, &ih[fd].handle,
389 0, TRUE, DUPLICATE_SAME_ACCESS))
390 {
391 unsigned int i;
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);
396 free (ih);
397 errno = EBADF; /* arbitrary */
398 return -1;
399 }
400 ih[fd].flags = 0;
401 }
402 }
403 else
404 {
405 if ((hflags & HANDLE_FLAG_INHERIT) != 0)
406 {
407 /* fd denotes an inheritable descriptor. */
408 ih[fd].handle = handle;
409 ih[fd].flags = KEEP_OPEN_IN_CHILD;
410 }
411 }
412 }
413 }
414 }
415 }
416
417 /* Return the result. */
418 inh_handles->count = handles_count;
419 inh_handles->allocated = handles_allocated;
420 inh_handles->ih = ih;
421 return 0;
422 }
423
424 int
425 compose_handles_block (const struct inheritable_handles *inh_handles,
426 STARTUPINFO *sinfo)
427 {
428 /* STARTUPINFO
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;
434
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,
442 a combination of:
443 1 for open file descriptors,
444 64 for handles of type FILE_TYPE_CHAR,
445 8 for handles of type FILE_TYPE_PIPE,
446 32 for O_APPEND.
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]
449 is zero.
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. */
455
456 size_t handles_count = inh_handles->count;
457
458 sinfo->cbReserved2 =
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
463 array. */
464 char *hblock = (char *) malloc (sinfo->cbReserved2 + (sizeof (HANDLE) - 1));
465 if (hblock == NULL)
466 {
467 errno = ENOMEM;
468 return -1;
469 }
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));
475
476 * (unsigned int *) hblock = handles_count;
477 {
478 unsigned int fd;
479 for (fd = 0; fd < handles_count; fd++)
480 {
481 handles_aligned[fd] = INVALID_HANDLE_VALUE;
482 flags[fd] = 0;
483
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))
489 {
490 DWORD hflags;
491 /* GetHandleInformation
492 <https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-gethandleinformation> */
493 if (GetHandleInformation (handle, &hflags))
494 {
495 if ((hflags & HANDLE_FLAG_INHERIT) != 0)
496 {
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))
505 {
506 case FILE_TYPE_CHAR:
507 flags[fd] |= 64;
508 break;
509 case FILE_TYPE_PIPE:
510 flags[fd] |= 8;
511 break;
512 default:
513 break;
514 }
515 }
516 else
517 /* We shouldn't have any non-inheritable handles in
518 inh_handles->handles. */
519 abort ();
520 }
521 }
522 }
523 }
524 if (handles != (char *) handles_aligned)
525 memmove (handles, (char *) handles_aligned, handles_count * sizeof (HANDLE));
526
527 sinfo->lpReserved2 = (BYTE *) hblock;
528
529 return 0;
530 }
531
532 void
533 free_inheritable_handles (struct inheritable_handles *inh_handles)
534 {
535 free (inh_handles->ih);
536 }
537
538 int
539 convert_CreateProcess_error (DWORD error)
540 {
541 /* Some of these errors probably cannot happen. But who knows... */
542 switch (error)
543 {
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:
550 return ENOENT;
551 break;
552
553 case ERROR_ACCESS_DENIED:
554 case ERROR_SHARING_VIOLATION:
555 return EACCES;
556 break;
557
558 case ERROR_OUTOFMEMORY:
559 return ENOMEM;
560 break;
561
562 case ERROR_BUFFER_OVERFLOW:
563 case ERROR_FILENAME_EXCED_RANGE:
564 return ENAMETOOLONG;
565 break;
566
567 case ERROR_BAD_FORMAT:
568 case ERROR_BAD_EXE_FORMAT:
569 return ENOEXEC;
570 break;
571
572 default:
573 return EINVAL;
574 break;
575 }
576 }
577
578 intptr_t
579 spawnpvech (int mode,
580 const char *progname, const char * const *argv,
581 const char * const *envp,
582 const char *currdir,
583 HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle)
584 {
585 /* Validate the arguments. */
586 if (!(mode == P_WAIT
587 || mode == P_NOWAIT
588 || mode == P_DETACH
589 || mode == P_OVERLAY)
590 || progname == NULL || argv == NULL)
591 {
592 errno = EINVAL;
593 return -1;
594 }
595
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)
600 return -1;
601
602 /* Compose the command. */
603 char *command = compose_command (argv);
604 if (command == NULL)
605 goto out_of_memory_1;
606
607 /* Copy *ENVP into a contiguous block of memory. */
608 char *envblock;
609 if (envp == NULL)
610 envblock = NULL;
611 else
612 {
613 envblock = compose_envblock (envp);
614 if (envblock == NULL)
615 goto out_of_memory_2;
616 }
617
618 /* Collect the inheritable handles. */
619 struct inheritable_handles inh_handles;
620 if (init_inheritable_handles (&inh_handles, false) < 0)
621 {
622 int saved_errno = errno;
623 if (envblock != NULL)
624 free (envblock);
625 free (command);
626 if (resolved_progname != progname)
627 free ((char *) resolved_progname);
628 errno = saved_errno;
629 return -1;
630 }
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;
637
638 /* CreateProcess
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);
642 /* STARTUPINFO
643 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa> */
644 STARTUPINFO sinfo;
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)
650 {
651 int saved_errno = errno;
652 free_inheritable_handles (&inh_handles);
653 if (envblock != NULL)
654 free (envblock);
655 free (command);
656 if (resolved_progname != progname)
657 free ((char *) resolved_progname);
658 errno = saved_errno;
659 return -1;
660 }
661
662 PROCESS_INFORMATION pinfo;
663 if (!CreateProcess (resolved_progname, command, NULL, NULL, TRUE,
664 process_creation_flags, envblock, currdir, &sinfo,
665 &pinfo))
666 {
667 DWORD error = GetLastError ();
668
669 free (sinfo.lpReserved2);
670 free_inheritable_handles (&inh_handles);
671 if (envblock != NULL)
672 free (envblock);
673 free (command);
674 if (resolved_progname != progname)
675 free ((char *) resolved_progname);
676
677 errno = convert_CreateProcess_error (error);
678 return -1;
679 }
680
681 if (pinfo.hThread)
682 CloseHandle (pinfo.hThread);
683 free (sinfo.lpReserved2);
684 free_inheritable_handles (&inh_handles);
685 if (envblock != NULL)
686 free (envblock);
687 free (command);
688 if (resolved_progname != progname)
689 free ((char *) resolved_progname);
690
691 switch (mode)
692 {
693 case P_WAIT:
694 {
695 /* Wait until it terminates. Then get its exit status code. */
696 switch (WaitForSingleObject (pinfo.hProcess, INFINITE))
697 {
698 case WAIT_OBJECT_0:
699 break;
700 case WAIT_FAILED:
701 errno = ECHILD;
702 return -1;
703 default:
704 abort ();
705 }
706
707 DWORD exit_code;
708 if (!GetExitCodeProcess (pinfo.hProcess, &exit_code))
709 {
710 errno = ECHILD;
711 return -1;
712 }
713 CloseHandle (pinfo.hProcess);
714 return exit_code;
715 }
716
717 case P_NOWAIT:
718 /* Return pinfo.hProcess, not pinfo.dwProcessId. */
719 return (intptr_t) pinfo.hProcess;
720
721 case P_DETACH:
722 case P_OVERLAY:
723 CloseHandle (pinfo.hProcess);
724 return 0;
725
726 default:
727 /* Already checked above. */
728 abort ();
729 }
730
731 /*NOTREACHED*/
732 out_of_memory_2:
733 free (command);
734 out_of_memory_1:
735 if (resolved_progname != progname)
736 free ((char *) resolved_progname);
737 errno = ENOMEM;
738 return -1;
739 }