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/>. */
22 #include "spawn_int.h"
29 # define O_LARGEFILE 0
32 #if _LIBC || HAVE_PATHS_H
35 # define _PATH_BSHELL BOURNE_SHELL
44 # include <not-cancel.h>
46 # define close_not_cancel close
47 # define open_not_cancel open
51 # include <local-setxid.h>
54 # define seteuid(id) setresuid (-1, id, -1)
57 # define setegid(id) setresgid (-1, id, -1)
59 # define local_seteuid(id) seteuid (id)
60 # define local_setegid(id) setegid (id)
64 # define alloca __alloca
65 # define execve __execve
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
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
98 /* Get declarations of the native Windows API functions. */
99 # define WIN32_LEAN_AND_MEAN
100 # include <windows.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. */
112 # define CreateFile CreateFileA
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.
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
=
131 realloc (inh_handles
->ih
, new_allocated
* sizeof (struct IHANDLE
));
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
;
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.
157 do_delayed_dup2 (int newfd
, struct inheritable_handles
*inh_handles
,
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
))
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 */
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
;
180 /* Performs the remaining delayed dup2 (oldfd, newfd).
181 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
184 do_remaining_delayed_dup2 (struct inheritable_handles
*inh_handles
,
187 size_t handles_count
= inh_handles
->count
;
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)
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. */
203 shrink_inheritable_handles (struct inheritable_handles
*inh_handles
)
205 struct IHANDLE
*ih
= inh_handles
->ih
;
206 size_t handles_count
= inh_handles
->count
;
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
)
226 inh_handles
->count
= handles_count
;
229 /* Closes all handles in inh_handles. */
231 close_inheritable_handles (struct inheritable_handles
*inh_handles
)
233 struct IHANDLE
*ih
= inh_handles
->ih
;
234 size_t handles_count
= inh_handles
->count
;
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
251 memiszero (const void *p
, size_t n
)
254 for (; n
> 0; cp
++, n
--)
260 /* Tests whether *S contains no signals. */
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.
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
))
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
))
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
))
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
;
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
;
320 inh_handles
->ih
[fd
].handle
= INVALID_HANDLE_VALUE
;
325 /* Opens an inheritable HANDLE to a file.
326 Upon failure, returns INVALID_HANDLE_VALUE with errno set. */
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)
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]))
340 while (ISSLASH (name
[1]))
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. */
350 bool check_dir
= false;
353 while (rlen
> drive_prefix_len
&& ISSLASH (name
[rlen
-1]))
356 if (rlen
== drive_prefix_len
+ 1)
361 /* Handle '' and 'C:'. */
362 if (!check_dir
&& rlen
== drive_prefix_len
)
365 return INVALID_HANDLE_VALUE
;
369 if (rlen
== 1 && ISSLASH (name
[0]) && len
>= 2)
372 return INVALID_HANDLE_VALUE
;
380 malloca_rname
= NULL
;
384 malloca_rname
= malloca (rlen
+ 1);
385 if (malloca_rname
== NULL
)
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.
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
;
407 ((flags
& (O_WRONLY
| O_RDWR
)) != 0
408 ? GENERIC_READ
| GENERIC_WRITE
410 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
412 ((flags
& O_CREAT
) != 0
413 ? ((flags
& O_EXCL
) != 0
415 : ((flags
& O_TRUNC
) != 0 ? CREATE_ALWAYS
: OPEN_ALWAYS
))
416 : ((flags
& O_TRUNC
) != 0
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),
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
:
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? */
451 case ERROR_OUTOFMEMORY
:
455 case ERROR_WRITE_PROTECT
:
459 case ERROR_WRITE_FAULT
:
460 case ERROR_READ_FAULT
:
461 case ERROR_GEN_FAILURE
:
465 case ERROR_BUFFER_OVERFLOW
:
466 case ERROR_FILENAME_EXCED_RANGE
:
467 errno
= ENAMETOOLONG
;
470 case ERROR_DELETE_PENDING
: /* XXX map to EACCES or EPERM? */
479 if (malloca_rname
!= NULL
)
481 int saved_errno
= errno
;
482 freea (malloca_rname
);
488 /* Executes an 'open' action.
489 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
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 ()))
501 if (grow_inheritable_handles (inh_handles
, newfd
) < 0)
503 if (do_close (inh_handles
, newfd
, true) < 0)
505 if (filename
== NULL
)
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
)
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
);
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
;
535 /* Executes a 'dup2' action.
536 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
539 do_dup2 (struct inheritable_handles
*inh_handles
, int oldfd
, int newfd
,
542 if (!(oldfd
>= 0 && oldfd
< inh_handles
->count
543 && inh_handles
->ih
[oldfd
].handle
!= INVALID_HANDLE_VALUE
))
548 if (!(newfd
>= 0 && newfd
< _getmaxstdio ()))
555 if (grow_inheritable_handles (inh_handles
, newfd
) < 0)
557 if (do_close (inh_handles
, newfd
, true) < 0)
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)
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
))
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 */
583 inh_handles
->ih
[newfd
].flags
=
584 (unsigned char) inh_handles
->ih
[oldfd
].flags
| KEEP_OPEN_IN_CHILD
;
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
;
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 */
603 inh_handles
->ih
[newfd
].flags
=
604 (unsigned char) inh_handles
->ih
[oldfd
].flags
| KEEP_OPEN_IN_CHILD
;
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
619 && ((attrp
->_flags
& ~POSIX_SPAWN_SETPGROUP
) != 0
621 || ! sigisempty (&attrp
->_sd
)
622 || ! sigisempty (&attrp
->_ss
)
623 || attrp
->_sp
.sched_priority
!= 0
624 || attrp
->_policy
!= 0)))
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
);
651 return errno
; /* errno is set here */
654 /* Compose the command. */
655 char *command
= compose_command (argv
);
658 free (argv_mem_to_free
);
662 /* Copy *ENVP into a contiguous block of memory. */
668 envblock
= compose_envblock (envp
, NULL
);
669 if (envblock
== NULL
)
672 free (argv_mem_to_free
);
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)
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 ();
696 for (cnt
= 0; cnt
< file_actions
->_used
; ++cnt
)
698 struct __spawn_action
*action
= &file_actions
->_actions
[cnt
];
704 int fd
= action
->action
.close_action
.fd
;
705 if (do_close (&inh_handles
, fd
, false) < 0)
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
,
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)
734 char *newdir
= action
->action
.chdir_action
.path
;
735 if (directory
!= NULL
&& IS_RELATIVE_FILE_NAME (newdir
))
737 newdir
= concatenated_filename (directory
, newdir
, NULL
);
748 case spawn_do_fchdir
:
749 /* Not supported in this implementation. */
755 # if SPAWN_INTERNAL_OPTIMIZE_DUPLICATEHANDLE
756 /* Do the remaining delayed dup2 invocations. */
757 if (do_remaining_delayed_dup2 (&inh_handles
, curr_process
) < 0)
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
);
767 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa> */
769 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa> */
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)
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") : "",
784 if (resolved_prog_filename
== NULL
)
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
,
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
);
804 free (argv_mem_to_free
);
806 return convert_CreateProcess_error (error
);
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
);
818 free (argv_mem_to_free
);
821 *pid
= (intptr_t) pinfo
.hProcess
;
826 int saved_errno
= errno
;
827 free (sinfo
.lpReserved2
);
828 close_inheritable_handles (&inh_handles
);
829 free_inheritable_handles (&inh_handles
);
832 free (argv_mem_to_free
);
838 int saved_errno
= errno
;
839 close_inheritable_handles (&inh_handles
);
840 free_inheritable_handles (&inh_handles
);
843 free (argv_mem_to_free
);
850 free (argv_mem_to_free
);
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"
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
)
873 char *path
, *p
, *name
;
878 short int flags
= attrp
== NULL
? 0 : attrp
->_flags
;
881 "variable 'flags' might be clobbered by 'longjmp' or 'vfork'" */
884 /* Generate the new process. */
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
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
))
905 /* The call was successful. Store the PID if necessary. */
912 /* Set signal mask. */
913 if ((flags
& POSIX_SPAWN_SETSIGMASK
) != 0
914 && sigprocmask (SIG_SETMASK
, &attrp
->_ss
, NULL
) != 0)
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
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)
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)
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)
954 /* Set the process group ID. */
955 if ((flags
& POSIX_SPAWN_SETPGROUP
) != 0
956 && setpgid (0, attrp
->_pgrp
) != 0)
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))
965 /* Execute the file actions. */
966 if (file_actions
!= NULL
)
970 for (cnt
= 0; cnt
< file_actions
->_used
; ++cnt
)
972 struct __spawn_action
*action
= &file_actions
->_actions
[cnt
];
977 if (close_not_cancel (action
->action
.close_action
.fd
) != 0)
978 /* Signal the error. */
984 int new_fd
= open_not_cancel (action
->action
.open_action
.path
,
985 action
->action
.open_action
.oflag
987 action
->action
.open_action
.mode
);
990 /* The 'open' call failed. */
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. */
1001 if (close_not_cancel (new_fd
) != 0)
1002 /* The 'close' call failed. */
1003 _exit (SPAWN_ERROR
);
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
);
1016 case spawn_do_chdir
:
1017 if (chdir (action
->action
.chdir_action
.path
) < 0)
1018 /* The 'chdir' call failed. */
1019 _exit (SPAWN_ERROR
);
1022 case spawn_do_fchdir
:
1023 if (fchdir (action
->action
.fchdir_action
.fd
) < 0)
1024 /* The 'fchdir' call failed. */
1025 _exit (SPAWN_ERROR
);
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");
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
);
1051 (void) confstr (_CS_PATH
, path
+ 1, len
);
1053 /* Pretend that the PATH contains only the current directory. */
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. */
1072 p
= strchrnul (path
, ':');
1075 /* Two adjacent colons, or a colon at the beginning or the end
1076 of 'PATH' means to search the current directory. */
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
);
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
1096 /* Some other error means we found an executable file, but
1097 something went wrong executing it; return the error to our
1099 _exit (SPAWN_ERROR
);
1102 while (*p
++ != '\0');
1104 /* Return with an error. */
1105 _exit (SPAWN_ERROR
);