openat: don’t close (-1)
[gnulib.git] / lib / spawni.c
blob211394bb9f9b44be304bf261b098b1d68c42f900
1 /* Guts of POSIX spawn interface. Generic POSIX.1 version.
2 Copyright (C) 2000-2006, 2008-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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 <spawn.h>
22 #include "spawn_int.h"
24 #include <alloca.h>
25 #include <errno.h>
27 #include <fcntl.h>
28 #ifndef O_LARGEFILE
29 # define O_LARGEFILE 0
30 #endif
32 #if _LIBC || HAVE_PATHS_H
33 # include <paths.h>
34 #else
35 # define _PATH_BSHELL BOURNE_SHELL
36 #endif
38 #include <signal.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
43 #if _LIBC
44 # include <not-cancel.h>
45 #else
46 # define close_not_cancel close
47 # define open_not_cancel open
48 #endif
50 #if _LIBC
51 # include <local-setxid.h>
52 #else
53 # if !HAVE_SETEUID
54 # define seteuid(id) setresuid (-1, id, -1)
55 # endif
56 # if !HAVE_SETEGID
57 # define setegid(id) setresgid (-1, id, -1)
58 # endif
59 # define local_seteuid(id) seteuid (id)
60 # define local_setegid(id) setegid (id)
61 #endif
63 #if _LIBC
64 # define alloca __alloca
65 # define execve __execve
66 # define dup2 __dup2
67 # define fork __fork
68 # define getgid __getgid
69 # define getuid __getuid
70 # define sched_setparam __sched_setparam
71 # define sched_setscheduler __sched_setscheduler
72 # define setpgid __setpgid
73 # define sigaction __sigaction
74 # define sigismember __sigismember
75 # define sigprocmask __sigprocmask
76 # define strchrnul __strchrnul
77 # define vfork __vfork
78 #endif
81 /* The Unix standard contains a long explanation of the way to signal
82 an error after the fork() was successful. Since no new wait status
83 was wanted there is no way to signal an error using one of the
84 available methods. The committee chose to signal an error by a
85 normal program exit with the exit code 127. */
86 #define SPAWN_ERROR 127
89 #if defined _WIN32 && ! defined __CYGWIN__
90 /* Native Windows API. */
92 /* Define to 1 to enable DuplicateHandle optimization.
93 Define to 0 to disable this optimization. */
94 # ifndef SPAWN_INTERNAL_OPTIMIZE_DUPLICATEHANDLE
95 # define SPAWN_INTERNAL_OPTIMIZE_DUPLICATEHANDLE 1
96 # endif
98 /* Get declarations of the native Windows API functions. */
99 # define WIN32_LEAN_AND_MEAN
100 # include <windows.h>
102 # include <stdio.h>
104 # include "filename.h"
105 # include "concat-filename.h"
106 # include "findprog.h"
107 # include "malloca.h"
108 # include "windows-spawn.h"
110 /* Don't assume that UNICODE is not defined. */
111 # undef CreateFile
112 # define CreateFile CreateFileA
113 # undef STARTUPINFO
114 # define STARTUPINFO STARTUPINFOA
115 # undef CreateProcess
116 # define CreateProcess CreateProcessA
118 /* Grows inh_handles->count so that it becomes > newfd.
119 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
121 static int
122 grow_inheritable_handles (struct inheritable_handles *inh_handles, int newfd)
124 if (inh_handles->allocated <= newfd)
126 size_t new_allocated = 2 * inh_handles->allocated + 1;
127 if (new_allocated <= newfd)
128 new_allocated = newfd + 1;
129 struct IHANDLE *new_ih =
130 (struct IHANDLE *)
131 realloc (inh_handles->ih, new_allocated * sizeof (struct IHANDLE));
132 if (new_ih == NULL)
134 errno = ENOMEM;
135 return -1;
137 inh_handles->allocated = new_allocated;
138 inh_handles->ih = new_ih;
141 struct IHANDLE *ih = inh_handles->ih;
143 for (; inh_handles->count <= newfd; inh_handles->count++)
144 ih[inh_handles->count].handle = INVALID_HANDLE_VALUE;
146 return 0;
149 # if SPAWN_INTERNAL_OPTIMIZE_DUPLICATEHANDLE
151 /* Assuming inh_handles->ih[newfd].handle != INVALID_HANDLE_VALUE
152 and (inh_handles->ih[newfd].flags & DELAYED_DUP2_NEWFD) != 0,
153 actually performs the delayed dup2 (oldfd, newfd).
154 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
156 static int
157 do_delayed_dup2 (int newfd, struct inheritable_handles *inh_handles,
158 HANDLE curr_process)
160 int oldfd = inh_handles->ih[newfd].linked_fd;
161 /* Check invariants. */
162 if (!((inh_handles->ih[oldfd].flags & DELAYED_DUP2_OLDFD) != 0
163 && newfd == inh_handles->ih[oldfd].linked_fd
164 && inh_handles->ih[newfd].handle == inh_handles->ih[oldfd].handle))
165 abort ();
166 /* Duplicate the handle now. */
167 if (!DuplicateHandle (curr_process, inh_handles->ih[oldfd].handle,
168 curr_process, &inh_handles->ih[newfd].handle,
169 0, TRUE, DUPLICATE_SAME_ACCESS))
171 errno = EBADF; /* arbitrary */
172 return -1;
174 inh_handles->ih[oldfd].flags &= ~DELAYED_DUP2_OLDFD;
175 inh_handles->ih[newfd].flags =
176 (unsigned char) inh_handles->ih[oldfd].flags | KEEP_OPEN_IN_CHILD;
177 return 0;
180 /* Performs the remaining delayed dup2 (oldfd, newfd).
181 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
183 static int
184 do_remaining_delayed_dup2 (struct inheritable_handles *inh_handles,
185 HANDLE curr_process)
187 size_t handles_count = inh_handles->count;
188 int newfd;
190 for (newfd = 0; newfd < handles_count; newfd++)
191 if (inh_handles->ih[newfd].handle != INVALID_HANDLE_VALUE
192 && (inh_handles->ih[newfd].flags & DELAYED_DUP2_NEWFD) != 0)
193 if (do_delayed_dup2 (newfd, inh_handles, curr_process) < 0)
194 return -1;
195 return 0;
198 # endif
200 /* Closes the handles in inh_handles that are not meant to be preserved in the
201 child process, and reduces inh_handles->count to the minimum needed. */
202 static void
203 shrink_inheritable_handles (struct inheritable_handles *inh_handles)
205 struct IHANDLE *ih = inh_handles->ih;
206 size_t handles_count = inh_handles->count;
207 unsigned int fd;
209 for (fd = 0; fd < handles_count; fd++)
211 HANDLE handle = ih[fd].handle;
213 if (handle != INVALID_HANDLE_VALUE
214 && (ih[fd].flags & KEEP_OPEN_IN_CHILD) == 0)
216 if (!(ih[fd].flags & KEEP_OPEN_IN_PARENT))
217 CloseHandle (handle);
218 ih[fd].handle = INVALID_HANDLE_VALUE;
222 while (handles_count > 3
223 && ih[handles_count - 1].handle == INVALID_HANDLE_VALUE)
224 handles_count--;
226 inh_handles->count = handles_count;
229 /* Closes all handles in inh_handles. */
230 static void
231 close_inheritable_handles (struct inheritable_handles *inh_handles)
233 struct IHANDLE *ih = inh_handles->ih;
234 size_t handles_count = inh_handles->count;
235 unsigned int fd;
237 for (fd = 0; fd < handles_count; fd++)
239 HANDLE handle = ih[fd].handle;
241 if (handle != INVALID_HANDLE_VALUE
242 && !(ih[fd].flags & DELAYED_DUP2_NEWFD)
243 && !(ih[fd].flags & KEEP_OPEN_IN_PARENT))
244 CloseHandle (handle);
248 /* Tests whether a memory region, starting at P and N bytes long, contains only
249 zeroes. */
250 static bool
251 memiszero (const void *p, size_t n)
253 const char *cp = p;
254 for (; n > 0; cp++, n--)
255 if (*cp != 0)
256 return 0;
257 return 1;
260 /* Tests whether *S contains no signals. */
261 static bool
262 sigisempty (const sigset_t *s)
264 return memiszero (s, sizeof (sigset_t));
267 /* Executes a 'close' action.
268 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
270 static int
271 do_close (struct inheritable_handles *inh_handles, int fd, bool ignore_EBADF)
273 if (!(fd >= 0 && fd < inh_handles->count
274 && inh_handles->ih[fd].handle != INVALID_HANDLE_VALUE))
276 if (ignore_EBADF)
277 return 0;
278 else
280 errno = EBADF;
281 return -1;
285 # if SPAWN_INTERNAL_OPTIMIZE_DUPLICATEHANDLE
286 if ((inh_handles->ih[fd].flags & DELAYED_DUP2_NEWFD) != 0)
288 int dup2_oldfd = inh_handles->ih[fd].linked_fd;
289 /* Check invariants. */
290 if (!((inh_handles->ih[dup2_oldfd].flags & DELAYED_DUP2_OLDFD) != 0
291 && fd == inh_handles->ih[dup2_oldfd].linked_fd
292 && inh_handles->ih[fd].handle == inh_handles->ih[dup2_oldfd].handle))
293 abort ();
294 /* Annihilate a delayed dup2 (..., fd) call. */
295 inh_handles->ih[dup2_oldfd].flags &= ~DELAYED_DUP2_OLDFD;
297 else if ((inh_handles->ih[fd].flags & DELAYED_DUP2_OLDFD) != 0)
299 int dup2_newfd = inh_handles->ih[fd].linked_fd;
300 /* Check invariants. */
301 if (!((inh_handles->ih[dup2_newfd].flags & DELAYED_DUP2_NEWFD) != 0
302 && fd == inh_handles->ih[dup2_newfd].linked_fd
303 && inh_handles->ih[fd].handle == inh_handles->ih[dup2_newfd].handle))
304 abort ();
305 /* Optimize a delayed dup2 (fd, ...) call. */
306 inh_handles->ih[dup2_newfd].flags =
307 (inh_handles->ih[fd].flags & ~DELAYED_DUP2_OLDFD) | KEEP_OPEN_IN_CHILD;
309 else
310 # endif
312 if (!(inh_handles->ih[fd].flags & KEEP_OPEN_IN_PARENT)
313 && !CloseHandle (inh_handles->ih[fd].handle))
315 inh_handles->ih[fd].handle = INVALID_HANDLE_VALUE;
316 errno = EIO;
317 return -1;
320 inh_handles->ih[fd].handle = INVALID_HANDLE_VALUE;
322 return 0;
325 /* Opens an inheritable HANDLE to a file.
326 Upon failure, returns INVALID_HANDLE_VALUE with errno set. */
327 static HANDLE
328 open_handle (const char *name, int flags, mode_t mode)
330 /* To ease portability. Like in open.c. */
331 if (strcmp (name, "/dev/null") == 0)
332 name = "NUL";
334 /* POSIX <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>
335 specifies: "More than two leading <slash> characters shall be treated as
336 a single <slash> character." */
337 if (ISSLASH (name[0]) && ISSLASH (name[1]) && ISSLASH (name[2]))
339 name += 2;
340 while (ISSLASH (name[1]))
341 name++;
344 size_t len = strlen (name);
345 size_t drive_prefix_len = (HAS_DEVICE (name) ? 2 : 0);
347 /* Remove trailing slashes (except the very first one, at position
348 drive_prefix_len), but remember their presence. */
349 size_t rlen;
350 bool check_dir = false;
352 rlen = len;
353 while (rlen > drive_prefix_len && ISSLASH (name[rlen-1]))
355 check_dir = true;
356 if (rlen == drive_prefix_len + 1)
357 break;
358 rlen--;
361 /* Handle '' and 'C:'. */
362 if (!check_dir && rlen == drive_prefix_len)
364 errno = ENOENT;
365 return INVALID_HANDLE_VALUE;
368 /* Handle '\\'. */
369 if (rlen == 1 && ISSLASH (name[0]) && len >= 2)
371 errno = ENOENT;
372 return INVALID_HANDLE_VALUE;
375 const char *rname;
376 char *malloca_rname;
377 if (rlen == len)
379 rname = name;
380 malloca_rname = NULL;
382 else
384 malloca_rname = malloca (rlen + 1);
385 if (malloca_rname == NULL)
387 errno = ENOMEM;
388 return INVALID_HANDLE_VALUE;
390 memcpy (malloca_rname, name, rlen);
391 malloca_rname[rlen] = '\0';
392 rname = malloca_rname;
395 /* For the meaning of the flags, see
396 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/open-wopen> */
397 /* Open a handle to the file.
398 CreateFile
399 <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea>
400 <https://docs.microsoft.com/en-us/windows/desktop/FileIO/creating-and-opening-files> */
401 SECURITY_ATTRIBUTES sec_attr;
402 sec_attr.nLength = sizeof (SECURITY_ATTRIBUTES);
403 sec_attr.lpSecurityDescriptor = NULL;
404 sec_attr.bInheritHandle = TRUE;
405 HANDLE handle =
406 CreateFile (rname,
407 ((flags & (O_WRONLY | O_RDWR)) != 0
408 ? GENERIC_READ | GENERIC_WRITE
409 : GENERIC_READ),
410 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
411 &sec_attr,
412 ((flags & O_CREAT) != 0
413 ? ((flags & O_EXCL) != 0
414 ? CREATE_NEW
415 : ((flags & O_TRUNC) != 0 ? CREATE_ALWAYS : OPEN_ALWAYS))
416 : ((flags & O_TRUNC) != 0
417 ? TRUNCATE_EXISTING
418 : OPEN_EXISTING)),
419 /* FILE_FLAG_BACKUP_SEMANTICS is useful for opening directories,
420 which is out-of-scope here. */
421 /* FILE_FLAG_POSIX_SEMANTICS (treat file names that differ only
422 in case as different) makes sense only when applied to *all*
423 filesystem operations. */
424 /* FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS */
425 FILE_ATTRIBUTE_NORMAL
426 | ((flags & O_TEMPORARY) != 0 ? FILE_FLAG_DELETE_ON_CLOSE : 0)
427 | ((flags & O_SEQUENTIAL ) != 0 ? FILE_FLAG_SEQUENTIAL_SCAN : 0)
428 | ((flags & O_RANDOM) != 0 ? FILE_FLAG_RANDOM_ACCESS : 0),
429 NULL);
430 if (handle == INVALID_HANDLE_VALUE)
431 switch (GetLastError ())
433 /* Some of these errors probably cannot happen with the specific flags
434 that we pass to CreateFile. But who knows... */
435 case ERROR_FILE_NOT_FOUND: /* The last component of rname does not exist. */
436 case ERROR_PATH_NOT_FOUND: /* Some directory component in rname does not exist. */
437 case ERROR_BAD_PATHNAME: /* rname is such as '\\server'. */
438 case ERROR_BAD_NETPATH: /* rname is such as '\\nonexistentserver\share'. */
439 case ERROR_BAD_NET_NAME: /* rname is such as '\\server\nonexistentshare'. */
440 case ERROR_INVALID_NAME: /* rname contains wildcards, misplaced colon, etc. */
441 case ERROR_DIRECTORY:
442 errno = ENOENT;
443 break;
445 case ERROR_ACCESS_DENIED: /* rname is such as 'C:\System Volume Information\foo'. */
446 case ERROR_SHARING_VIOLATION: /* rname is such as 'C:\pagefile.sys'. */
447 /* XXX map to EACCES or EPERM? */
448 errno = EACCES;
449 break;
451 case ERROR_OUTOFMEMORY:
452 errno = ENOMEM;
453 break;
455 case ERROR_WRITE_PROTECT:
456 errno = EROFS;
457 break;
459 case ERROR_WRITE_FAULT:
460 case ERROR_READ_FAULT:
461 case ERROR_GEN_FAILURE:
462 errno = EIO;
463 break;
465 case ERROR_BUFFER_OVERFLOW:
466 case ERROR_FILENAME_EXCED_RANGE:
467 errno = ENAMETOOLONG;
468 break;
470 case ERROR_DELETE_PENDING: /* XXX map to EACCES or EPERM? */
471 errno = EPERM;
472 break;
474 default:
475 errno = EINVAL;
476 break;
479 if (malloca_rname != NULL)
481 int saved_errno = errno;
482 freea (malloca_rname);
483 errno = saved_errno;
485 return handle;
488 /* Executes an 'open' action.
489 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
491 static int
492 do_open (struct inheritable_handles *inh_handles, int newfd,
493 const char *filename, const char *directory,
494 int flags, mode_t mode)
496 if (!(newfd >= 0 && newfd < _getmaxstdio ()))
498 errno = EBADF;
499 return -1;
501 if (grow_inheritable_handles (inh_handles, newfd) < 0)
502 return -1;
503 if (do_close (inh_handles, newfd, true) < 0)
504 return -1;
505 if (filename == NULL)
507 errno = EINVAL;
508 return -1;
510 char *filename_to_free = NULL;
511 if (directory != NULL && IS_RELATIVE_FILE_NAME (filename))
513 char *real_filename = concatenated_filename (directory, filename, NULL);
514 if (real_filename == NULL)
516 errno = ENOMEM;
517 return -1;
519 filename = real_filename;
520 filename_to_free = real_filename;
522 HANDLE handle = open_handle (filename, flags, mode);
523 if (handle == INVALID_HANDLE_VALUE)
525 free (filename_to_free);
526 return -1;
528 free (filename_to_free);
529 inh_handles->ih[newfd].handle = handle;
530 inh_handles->ih[newfd].flags =
531 ((flags & O_APPEND) != 0 ? 32 : 0) | KEEP_OPEN_IN_CHILD;
532 return 0;
535 /* Executes a 'dup2' action.
536 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
538 static int
539 do_dup2 (struct inheritable_handles *inh_handles, int oldfd, int newfd,
540 HANDLE curr_process)
542 if (!(oldfd >= 0 && oldfd < inh_handles->count
543 && inh_handles->ih[oldfd].handle != INVALID_HANDLE_VALUE))
545 errno = EBADF;
546 return -1;
548 if (!(newfd >= 0 && newfd < _getmaxstdio ()))
550 errno = EBADF;
551 return -1;
553 if (newfd != oldfd)
555 if (grow_inheritable_handles (inh_handles, newfd) < 0)
556 return -1;
557 if (do_close (inh_handles, newfd, true) < 0)
558 return -1;
559 /* We may need to duplicate the handle, so that a forthcoming do_close
560 action on oldfd has no effect on newfd. */
561 # if SPAWN_INTERNAL_OPTIMIZE_DUPLICATEHANDLE
562 /* But try to not do it now; delay it if possible. In many cases, the
563 DuplicateHandle call can be optimized away. */
564 if ((inh_handles->ih[oldfd].flags & DELAYED_DUP2_NEWFD) != 0)
565 if (do_delayed_dup2 (oldfd, inh_handles, curr_process) < 0)
566 return -1;
567 if ((inh_handles->ih[oldfd].flags & DELAYED_DUP2_OLDFD) != 0)
569 /* Check invariants. */
570 int dup2_newfd = inh_handles->ih[oldfd].linked_fd;
571 if (!((inh_handles->ih[dup2_newfd].flags & DELAYED_DUP2_NEWFD) != 0
572 && oldfd == inh_handles->ih[dup2_newfd].linked_fd
573 && inh_handles->ih[oldfd].handle == inh_handles->ih[dup2_newfd].handle))
574 abort ();
575 /* We can't delay two or more dup2 calls from the same oldfd. */
576 if (!DuplicateHandle (curr_process, inh_handles->ih[oldfd].handle,
577 curr_process, &inh_handles->ih[newfd].handle,
578 0, TRUE, DUPLICATE_SAME_ACCESS))
580 errno = EBADF; /* arbitrary */
581 return -1;
583 inh_handles->ih[newfd].flags =
584 (unsigned char) inh_handles->ih[oldfd].flags | KEEP_OPEN_IN_CHILD;
586 else
588 /* Delay the dup2 (oldfd, newfd) action. */
589 inh_handles->ih[oldfd].flags |= DELAYED_DUP2_OLDFD;
590 inh_handles->ih[oldfd].linked_fd = newfd;
591 inh_handles->ih[newfd].handle = inh_handles->ih[oldfd].handle;
592 inh_handles->ih[newfd].flags = DELAYED_DUP2_NEWFD;
593 inh_handles->ih[newfd].linked_fd = oldfd;
595 # else
596 if (!DuplicateHandle (curr_process, inh_handles->ih[oldfd].handle,
597 curr_process, &inh_handles->ih[newfd].handle,
598 0, TRUE, DUPLICATE_SAME_ACCESS))
600 errno = EBADF; /* arbitrary */
601 return -1;
603 inh_handles->ih[newfd].flags =
604 (unsigned char) inh_handles->ih[oldfd].flags | KEEP_OPEN_IN_CHILD;
605 # endif
607 return 0;
611 __spawni (pid_t *pid, const char *prog_filename,
612 const posix_spawn_file_actions_t *file_actions,
613 const posix_spawnattr_t *attrp, const char *const prog_argv[],
614 const char *const envp[], int use_path)
616 /* Validate the arguments. */
617 if (prog_filename == NULL
618 || (attrp != NULL
619 && ((attrp->_flags & ~POSIX_SPAWN_SETPGROUP) != 0
620 || attrp->_pgrp != 0
621 || ! sigisempty (&attrp->_sd)
622 || ! sigisempty (&attrp->_ss)
623 || attrp->_sp.sched_priority != 0
624 || attrp->_policy != 0)))
625 return EINVAL;
627 /* Process group handling:
628 Native Windows does not have the concept of process group, but it has the
629 concept of a console attached to a process.
630 So, we interpret the three cases as follows:
631 - Flag POSIX_SPAWN_SETPGROUP not set: Means, the child process is in the
632 same process group as the parent process. We interpret this as a
633 request to reuse the same console.
634 - Flag POSIX_SPAWN_SETPGROUP set with attrp->_pgrp == 0: Means the child
635 process starts a process group of its own. See
636 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_getpgroup.html>
637 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgrp.html>
638 We interpret this as a request to detach from the current console.
639 - Flag POSIX_SPAWN_SETPGROUP set with attrp->_pgrp != 0: Means the child
640 process joins another, existing process group. See
641 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_getpgroup.html>
642 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html>
643 We don't support this case; it produces error EINVAL above. */
644 /* <https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags> */
645 DWORD process_creation_flags =
646 (attrp != NULL && (attrp->_flags & POSIX_SPAWN_SETPGROUP) != 0 ? DETACHED_PROCESS : 0);
648 char *argv_mem_to_free;
649 const char **argv = prepare_spawn (prog_argv, &argv_mem_to_free);
650 if (argv == NULL)
651 return errno; /* errno is set here */
652 argv++;
654 /* Compose the command. */
655 char *command = compose_command (argv);
656 if (command == NULL)
658 free (argv_mem_to_free);
659 return ENOMEM;
662 /* Copy *ENVP into a contiguous block of memory. */
663 char *envblock;
664 if (envp == NULL)
665 envblock = NULL;
666 else
668 envblock = compose_envblock (envp, NULL);
669 if (envblock == NULL)
671 free (command);
672 free (argv_mem_to_free);
673 return ENOMEM;
677 /* Set up the array of handles to inherit.
678 Duplicate each handle, so that a spawn_do_close action (below) has no
679 effect on the file descriptors of the current process. Alternatively,
680 we could store, for each handle, a bit that tells whether it is shared
681 with the current process. But this is simpler. */
682 struct inheritable_handles inh_handles;
683 if (init_inheritable_handles (&inh_handles, true) < 0)
684 goto failed_1;
686 /* Directory in which to execute the new process. */
687 const char *directory = NULL;
689 /* Execute the file_actions, modifying the inh_handles instead of the
690 file descriptors of the current process. */
691 if (file_actions != NULL)
693 HANDLE curr_process = GetCurrentProcess ();
694 int cnt;
696 for (cnt = 0; cnt < file_actions->_used; ++cnt)
698 struct __spawn_action *action = &file_actions->_actions[cnt];
700 switch (action->tag)
702 case spawn_do_close:
704 int fd = action->action.close_action.fd;
705 if (do_close (&inh_handles, fd, false) < 0)
706 goto failed_2;
708 break;
710 case spawn_do_open:
712 int newfd = action->action.open_action.fd;
713 const char *filename = action->action.open_action.path;
714 int flags = action->action.open_action.oflag;
715 mode_t mode = action->action.open_action.mode;
716 if (do_open (&inh_handles, newfd, filename, directory,
717 flags, mode)
718 < 0)
719 goto failed_2;
721 break;
723 case spawn_do_dup2:
725 int oldfd = action->action.dup2_action.fd;
726 int newfd = action->action.dup2_action.newfd;
727 if (do_dup2 (&inh_handles, oldfd, newfd, curr_process) < 0)
728 goto failed_2;
730 break;
732 case spawn_do_chdir:
734 char *newdir = action->action.chdir_action.path;
735 if (directory != NULL && IS_RELATIVE_FILE_NAME (newdir))
737 newdir = concatenated_filename (directory, newdir, NULL);
738 if (newdir == NULL)
740 errno = ENOMEM;
741 goto failed_2;
744 directory = newdir;
746 break;
748 case spawn_do_fchdir:
749 /* Not supported in this implementation. */
750 errno = EINVAL;
751 goto failed_2;
755 # if SPAWN_INTERNAL_OPTIMIZE_DUPLICATEHANDLE
756 /* Do the remaining delayed dup2 invocations. */
757 if (do_remaining_delayed_dup2 (&inh_handles, curr_process) < 0)
758 goto failed_2;
759 # endif
762 /* Close the handles in inh_handles that are not meant to be preserved in the
763 child process, and reduce inh_handles.count to the minimum needed. */
764 shrink_inheritable_handles (&inh_handles);
766 /* CreateProcess
767 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa> */
768 /* STARTUPINFO
769 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa> */
770 STARTUPINFO sinfo;
771 sinfo.cb = sizeof (STARTUPINFO);
772 sinfo.lpReserved = NULL;
773 sinfo.lpDesktop = NULL;
774 sinfo.lpTitle = NULL;
775 if (compose_handles_block (&inh_handles, &sinfo) < 0)
776 goto failed_2;
778 /* Perform the PATH search now, considering the final DIRECTORY. */
779 char *resolved_prog_filename_to_free = NULL;
781 const char *resolved_prog_filename =
782 find_in_given_path (prog_filename, use_path ? getenv ("PATH") : "",
783 directory, false);
784 if (resolved_prog_filename == NULL)
785 goto failed_3;
786 if (resolved_prog_filename != prog_filename)
787 resolved_prog_filename_to_free = (char *) resolved_prog_filename;
788 prog_filename = resolved_prog_filename;
791 PROCESS_INFORMATION pinfo;
792 if (!CreateProcess (prog_filename, command, NULL, NULL, TRUE,
793 process_creation_flags, envblock, directory, &sinfo,
794 &pinfo))
796 DWORD error = GetLastError ();
798 free (resolved_prog_filename_to_free);
799 free (sinfo.lpReserved2);
800 close_inheritable_handles (&inh_handles);
801 free_inheritable_handles (&inh_handles);
802 free (envblock);
803 free (command);
804 free (argv_mem_to_free);
806 return convert_CreateProcess_error (error);
809 if (pinfo.hThread)
810 CloseHandle (pinfo.hThread);
812 free (resolved_prog_filename_to_free);
813 free (sinfo.lpReserved2);
814 close_inheritable_handles (&inh_handles);
815 free_inheritable_handles (&inh_handles);
816 free (envblock);
817 free (command);
818 free (argv_mem_to_free);
820 if (pid != NULL)
821 *pid = (intptr_t) pinfo.hProcess;
822 return 0;
824 failed_3:
826 int saved_errno = errno;
827 free (sinfo.lpReserved2);
828 close_inheritable_handles (&inh_handles);
829 free_inheritable_handles (&inh_handles);
830 free (envblock);
831 free (command);
832 free (argv_mem_to_free);
833 return saved_errno;
836 failed_2:
838 int saved_errno = errno;
839 close_inheritable_handles (&inh_handles);
840 free_inheritable_handles (&inh_handles);
841 free (envblock);
842 free (command);
843 free (argv_mem_to_free);
844 return saved_errno;
847 failed_1:
848 free (envblock);
849 free (command);
850 free (argv_mem_to_free);
851 return errno;
854 #else
857 /* The warning "warning: 'vfork' is deprecated: Use posix_spawn or fork" seen
858 on macOS 12 is pointless, as we use vfork only when it is safe or when the
859 user has explicitly requested it. Silence this warning. */
860 #if _GL_GNUC_PREREQ (4, 2)
861 # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
862 #endif
864 /* Spawn a new process executing PATH with the attributes describes in *ATTRP.
865 Before running the process perform the actions described in FILE-ACTIONS. */
867 __spawni (pid_t *pid, const char *file,
868 const posix_spawn_file_actions_t *file_actions,
869 const posix_spawnattr_t *attrp, const char *const argv[],
870 const char *const envp[], int use_path)
872 pid_t new_pid;
873 char *path, *p, *name;
874 size_t len;
875 size_t pathlen;
877 /* Do this once. */
878 short int flags = attrp == NULL ? 0 : attrp->_flags;
880 /* Avoid gcc warning
881 "variable 'flags' might be clobbered by 'longjmp' or 'vfork'" */
882 (void) &flags;
884 /* Generate the new process. */
885 #if HAVE_VFORK
886 if ((flags & POSIX_SPAWN_USEVFORK) != 0
887 /* If no major work is done, allow using vfork. Note that we
888 might perform the path searching. But this would be done by
889 a call to execvp(), too, and such a call must be OK according
890 to POSIX. */
891 || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF
892 | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER
893 | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0
894 && file_actions == NULL))
895 new_pid = vfork ();
896 else
897 #endif
898 new_pid = fork ();
900 if (new_pid != 0)
902 if (new_pid < 0)
903 return errno;
905 /* The call was successful. Store the PID if necessary. */
906 if (pid != NULL)
907 *pid = new_pid;
909 return 0;
912 /* Set signal mask. */
913 if ((flags & POSIX_SPAWN_SETSIGMASK) != 0
914 && sigprocmask (SIG_SETMASK, &attrp->_ss, NULL) != 0)
915 _exit (SPAWN_ERROR);
917 /* Set signal default action. */
918 if ((flags & POSIX_SPAWN_SETSIGDEF) != 0)
920 /* We have to iterate over all signals. This could possibly be
921 done better but it requires system specific solutions since
922 the sigset_t data type can be very different on different
923 architectures. */
924 int sig;
925 struct sigaction sa;
927 memset (&sa, '\0', sizeof (sa));
928 sa.sa_handler = SIG_DFL;
930 for (sig = 1; sig <= NSIG; ++sig)
931 if (sigismember (&attrp->_sd, sig) != 0
932 && sigaction (sig, &sa, NULL) != 0)
933 _exit (SPAWN_ERROR);
937 #if (_LIBC ? defined _POSIX_PRIORITY_SCHEDULING : HAVE_SCHED_SETPARAM && HAVE_SCHED_SETSCHEDULER)
938 /* Set the scheduling algorithm and parameters. */
939 if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
940 == POSIX_SPAWN_SETSCHEDPARAM)
942 if (sched_setparam (0, &attrp->_sp) == -1)
943 _exit (SPAWN_ERROR);
945 else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
947 if (sched_setscheduler (0, attrp->_policy,
948 (flags & POSIX_SPAWN_SETSCHEDPARAM) != 0
949 ? &attrp->_sp : NULL) == -1)
950 _exit (SPAWN_ERROR);
952 #endif
954 /* Set the process group ID. */
955 if ((flags & POSIX_SPAWN_SETPGROUP) != 0
956 && setpgid (0, attrp->_pgrp) != 0)
957 _exit (SPAWN_ERROR);
959 /* Set the effective user and group IDs. */
960 if ((flags & POSIX_SPAWN_RESETIDS) != 0
961 && (local_seteuid (getuid ()) != 0
962 || local_setegid (getgid ()) != 0))
963 _exit (SPAWN_ERROR);
965 /* Execute the file actions. */
966 if (file_actions != NULL)
968 int cnt;
970 for (cnt = 0; cnt < file_actions->_used; ++cnt)
972 struct __spawn_action *action = &file_actions->_actions[cnt];
974 switch (action->tag)
976 case spawn_do_close:
977 if (close_not_cancel (action->action.close_action.fd) != 0)
978 /* Signal the error. */
979 _exit (SPAWN_ERROR);
980 break;
982 case spawn_do_open:
984 int new_fd = open_not_cancel (action->action.open_action.path,
985 action->action.open_action.oflag
986 | O_LARGEFILE,
987 action->action.open_action.mode);
989 if (new_fd == -1)
990 /* The 'open' call failed. */
991 _exit (SPAWN_ERROR);
993 /* Make sure the desired file descriptor is used. */
994 if (new_fd != action->action.open_action.fd)
996 if (dup2 (new_fd, action->action.open_action.fd)
997 != action->action.open_action.fd)
998 /* The 'dup2' call failed. */
999 _exit (SPAWN_ERROR);
1001 if (close_not_cancel (new_fd) != 0)
1002 /* The 'close' call failed. */
1003 _exit (SPAWN_ERROR);
1006 break;
1008 case spawn_do_dup2:
1009 if (dup2 (action->action.dup2_action.fd,
1010 action->action.dup2_action.newfd)
1011 != action->action.dup2_action.newfd)
1012 /* The 'dup2' call failed. */
1013 _exit (SPAWN_ERROR);
1014 break;
1016 case spawn_do_chdir:
1017 if (chdir (action->action.chdir_action.path) < 0)
1018 /* The 'chdir' call failed. */
1019 _exit (SPAWN_ERROR);
1020 break;
1022 case spawn_do_fchdir:
1023 if (fchdir (action->action.fchdir_action.fd) < 0)
1024 /* The 'fchdir' call failed. */
1025 _exit (SPAWN_ERROR);
1026 break;
1031 if (! use_path || strchr (file, '/') != NULL)
1033 /* The FILE parameter is actually a path. */
1034 execve (file, (char * const *) argv, (char * const *) envp);
1036 /* Oh, oh. 'execve' returns. This is bad. */
1037 _exit (SPAWN_ERROR);
1040 /* We have to search for FILE on the path. */
1041 path = getenv ("PATH");
1042 if (path == NULL)
1044 #if HAVE_CONFSTR
1045 /* There is no 'PATH' in the environment.
1046 The default search path is the current directory
1047 followed by the path 'confstr' returns for '_CS_PATH'. */
1048 len = confstr (_CS_PATH, (char *) NULL, 0);
1049 path = (char *) alloca (1 + len);
1050 path[0] = ':';
1051 (void) confstr (_CS_PATH, path + 1, len);
1052 #else
1053 /* Pretend that the PATH contains only the current directory. */
1054 path = "";
1055 #endif
1058 len = strlen (file) + 1;
1059 pathlen = strlen (path);
1060 name = alloca (pathlen + len + 1);
1061 /* Copy the file name at the top. */
1062 name = (char *) memcpy (name + pathlen + 1, file, len);
1063 /* And add the slash. */
1064 *--name = '/';
1066 p = path;
1069 char *startp;
1071 path = p;
1072 p = strchrnul (path, ':');
1074 if (p == path)
1075 /* Two adjacent colons, or a colon at the beginning or the end
1076 of 'PATH' means to search the current directory. */
1077 startp = name + 1;
1078 else
1079 startp = (char *) memcpy (name - (p - path), path, p - path);
1081 /* Try to execute this name. If it works, execv will not return. */
1082 execve (startp, (char * const *) argv, (char * const *) envp);
1084 switch (errno)
1086 case EACCES:
1087 case ENOENT:
1088 case ESTALE:
1089 case ENOTDIR:
1090 /* Those errors indicate the file is missing or not executable
1091 by us, in which case we want to just try the next path
1092 directory. */
1093 break;
1095 default:
1096 /* Some other error means we found an executable file, but
1097 something went wrong executing it; return the error to our
1098 caller. */
1099 _exit (SPAWN_ERROR);
1102 while (*p++ != '\0');
1104 /* Return with an error. */
1105 _exit (SPAWN_ERROR);
1108 #endif