1 /* Guts of POSIX spawn interface. Generic POSIX.1 version.
2 Copyright (C) 2000-2006, 2008-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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 <spawn.h>
22 #include "spawn_int.h"
23
24 #include <alloca.h>
25 #include <errno.h>
26
27 #include <fcntl.h>
28 #ifndef O_LARGEFILE
29 # define O_LARGEFILE 0
30 #endif
31
32 #if _LIBC || HAVE_PATHS_H
33 # include <paths.h>
34 #else
35 # define _PATH_BSHELL BOURNE_SHELL
36 #endif
37
38 #include <signal.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42
43 #if _LIBC
44 # include <not-cancel.h>
45 #else
46 # define close_not_cancel close
47 # define open_not_cancel open
48 #endif
49
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
62
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
79
80
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
87
88
89 #if defined _WIN32 && ! defined __CYGWIN__
90 /* Native Windows API. */
91
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
97
98 /* Get declarations of the native Windows API functions. */
99 # define WIN32_LEAN_AND_MEAN
100 # include <windows.h>
101
102 # include <stdio.h>
103
104 # include "filename.h"
105 # include "concat-filename.h"
106 # include "findprog.h"
107 # include "malloca.h"
108 # include "windows-spawn.h"
109
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
117
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.
120 */
121 static int
122 grow_inheritable_handles (struct inheritable_handles *inh_handles, int newfd)
123 {
124 if (inh_handles->allocated <= newfd)
125 {
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)
133 {
134 errno = ENOMEM;
135 return -1;
136 }
137 inh_handles->allocated = new_allocated;
138 inh_handles->ih = new_ih;
139 }
140
141 struct IHANDLE *ih = inh_handles->ih;
142
143 for (; inh_handles->count <= newfd; inh_handles->count++)
144 ih[inh_handles->count].handle = INVALID_HANDLE_VALUE;
145
146 return 0;
147 }
148
149 # if SPAWN_INTERNAL_OPTIMIZE_DUPLICATEHANDLE
150
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.
155 */
156 static int
157 do_delayed_dup2 (int newfd, struct inheritable_handles *inh_handles,
158 HANDLE curr_process)
159 {
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))
170 {
171 errno = EBADF; /* arbitrary */
172 return -1;
173 }
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;
178 }
179
180 /* Performs the remaining delayed dup2 (oldfd, newfd).
181 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
182 */
183 static int
184 do_remaining_delayed_dup2 (struct inheritable_handles *inh_handles,
185 HANDLE curr_process)
186 {
187 size_t handles_count = inh_handles->count;
188 int newfd;
189
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;
196 }
197
198 # endif
199
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)
204 {
205 struct IHANDLE *ih = inh_handles->ih;
206 size_t handles_count = inh_handles->count;
207 unsigned int fd;
208
209 for (fd = 0; fd < handles_count; fd++)
210 {
211 HANDLE handle = ih[fd].handle;
212
213 if (handle != INVALID_HANDLE_VALUE
214 && (ih[fd].flags & KEEP_OPEN_IN_CHILD) == 0)
215 {
216 if (!(ih[fd].flags & KEEP_OPEN_IN_PARENT))
217 CloseHandle (handle);
218 ih[fd].handle = INVALID_HANDLE_VALUE;
219 }
220 }
221
222 while (handles_count > 3
223 && ih[handles_count - 1].handle == INVALID_HANDLE_VALUE)
224 handles_count--;
225
226 inh_handles->count = handles_count;
227 }
228
229 /* Closes all handles in inh_handles. */
230 static void
231 close_inheritable_handles (struct inheritable_handles *inh_handles)
232 {
233 struct IHANDLE *ih = inh_handles->ih;
234 size_t handles_count = inh_handles->count;
235 unsigned int fd;
236
237 for (fd = 0; fd < handles_count; fd++)
238 {
239 HANDLE handle = ih[fd].handle;
240
241 if (handle != INVALID_HANDLE_VALUE
242 && !(ih[fd].flags & DELAYED_DUP2_NEWFD)
243 && !(ih[fd].flags & KEEP_OPEN_IN_PARENT))
244 CloseHandle (handle);
245 }
246 }
247
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)
252 {
253 const char *cp = p;
254 for (; n > 0; cp++, n--)
255 if (*cp != 0)
256 return 0;
257 return 1;
258 }
259
260 /* Tests whether *S contains no signals. */
261 static bool
262 sigisempty (const sigset_t *s)
263 {
264 return memiszero (s, sizeof (sigset_t));
265 }
266
267 /* Executes a 'close' action.
268 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
269 */
270 static int
271 do_close (struct inheritable_handles *inh_handles, int fd, bool ignore_EBADF)
272 {
273 if (!(fd >= 0 && fd < inh_handles->count
274 && inh_handles->ih[fd].handle != INVALID_HANDLE_VALUE))
275 {
276 if (ignore_EBADF)
277 return 0;
278 else
279 {
280 errno = EBADF;
281 return -1;
282 }
283 }
284
285 # if SPAWN_INTERNAL_OPTIMIZE_DUPLICATEHANDLE
286 if ((inh_handles->ih[fd].flags & DELAYED_DUP2_NEWFD) != 0)
287 {
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;
296 }
297 else if ((inh_handles->ih[fd].flags & DELAYED_DUP2_OLDFD) != 0)
298 {
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;
308 }
309 else
310 # endif
311 {
312 if (!(inh_handles->ih[fd].flags & KEEP_OPEN_IN_PARENT)
313 && !CloseHandle (inh_handles->ih[fd].handle))
314 {
315 inh_handles->ih[fd].handle = INVALID_HANDLE_VALUE;
316 errno = EIO;
317 return -1;
318 }
319 }
320 inh_handles->ih[fd].handle = INVALID_HANDLE_VALUE;
321
322 return 0;
323 }
324
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)
329 {
330 /* To ease portability. Like in open.c. */
331 if (strcmp (name, "/dev/null") == 0)
332 name = "NUL";
333
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]))
338 {
339 name += 2;
340 while (ISSLASH (name[1]))
341 name++;
342 }
343
344 size_t len = strlen (name);
345 size_t drive_prefix_len = (HAS_DEVICE (name) ? 2 : 0);
346
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;
351
352 rlen = len;
353 while (rlen > drive_prefix_len && ISSLASH (name[rlen-1]))
354 {
355 check_dir = true;
356 if (rlen == drive_prefix_len + 1)
357 break;
358 rlen--;
359 }
360
361 /* Handle '' and 'C:'. */
362 if (!check_dir && rlen == drive_prefix_len)
363 {
364 errno = ENOENT;
365 return INVALID_HANDLE_VALUE;
366 }
367
368 /* Handle '\\'. */
369 if (rlen == 1 && ISSLASH (name[0]) && len >= 2)
370 {
371 errno = ENOENT;
372 return INVALID_HANDLE_VALUE;
373 }
374
375 const char *rname;
376 char *malloca_rname;
377 if (rlen == len)
378 {
379 rname = name;
380 malloca_rname = NULL;
381 }
382 else
383 {
384 malloca_rname = malloca (rlen + 1);
385 if (malloca_rname == NULL)
386 {
387 errno = ENOMEM;
388 return INVALID_HANDLE_VALUE;
389 }
390 memcpy (malloca_rname, name, rlen);
391 malloca_rname[rlen] = '\0';
392 rname = malloca_rname;
393 }
394
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 ())
432 {
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;
444
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;
450
451 case ERROR_OUTOFMEMORY:
452 errno = ENOMEM;
453 break;
454
455 case ERROR_WRITE_PROTECT:
456 errno = EROFS;
457 break;
458
459 case ERROR_WRITE_FAULT:
460 case ERROR_READ_FAULT:
461 case ERROR_GEN_FAILURE:
462 errno = EIO;
463 break;
464
465 case ERROR_BUFFER_OVERFLOW:
466 case ERROR_FILENAME_EXCED_RANGE:
467 errno = ENAMETOOLONG;
468 break;
469
470 case ERROR_DELETE_PENDING: /* XXX map to EACCES or EPERM? */
471 errno = EPERM;
472 break;
473
474 default:
475 errno = EINVAL;
476 break;
477 }
478
479 if (malloca_rname != NULL)
480 {
481 int saved_errno = errno;
482 freea (malloca_rname);
483 errno = saved_errno;
484 }
485 return handle;
486 }
487
488 /* Executes an 'open' action.
489 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
490 */
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)
495 {
496 if (!(newfd >= 0 && newfd < _getmaxstdio ()))
497 {
498 errno = EBADF;
499 return -1;
500 }
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)
506 {
507 errno = EINVAL;
508 return -1;
509 }
510 char *filename_to_free = NULL;
511 if (directory != NULL && IS_RELATIVE_FILE_NAME (filename))
512 {
513 char *real_filename = concatenated_filename (directory, filename, NULL);
514 if (real_filename == NULL)
515 {
516 errno = ENOMEM;
517 return -1;
518 }
519 filename = real_filename;
520 filename_to_free = real_filename;
521 }
522 HANDLE handle = open_handle (filename, flags, mode);
523 if (handle == INVALID_HANDLE_VALUE)
524 {
525 free (filename_to_free);
526 return -1;
527 }
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;
533 }
534
535 /* Executes a 'dup2' action.
536 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
537 */
538 static int
539 do_dup2 (struct inheritable_handles *inh_handles, int oldfd, int newfd,
540 HANDLE curr_process)
541 {
542 if (!(oldfd >= 0 && oldfd < inh_handles->count
543 && inh_handles->ih[oldfd].handle != INVALID_HANDLE_VALUE))
544 {
545 errno = EBADF;
546 return -1;
547 }
548 if (!(newfd >= 0 && newfd < _getmaxstdio ()))
549 {
550 errno = EBADF;
551 return -1;
552 }
553 if (newfd != oldfd)
554 {
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)
568 {
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))
579 {
580 errno = EBADF; /* arbitrary */
581 return -1;
582 }
583 inh_handles->ih[newfd].flags =
584 (unsigned char) inh_handles->ih[oldfd].flags | KEEP_OPEN_IN_CHILD;
585 }
586 else
587 {
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;
594 }
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))
599 {
600 errno = EBADF; /* arbitrary */
601 return -1;
602 }
603 inh_handles->ih[newfd].flags =
604 (unsigned char) inh_handles->ih[oldfd].flags | KEEP_OPEN_IN_CHILD;
605 # endif
606 }
607 return 0;
608 }
609
610 int
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)
615 {
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;
626
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);
647
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++;
653
654 /* Compose the command. */
655 char *command = compose_command (argv);
656 if (command == NULL)
657 {
658 free (argv_mem_to_free);
659 return ENOMEM;
660 }
661
662 /* Copy *ENVP into a contiguous block of memory. */
663 char *envblock;
664 if (envp == NULL)
665 envblock = NULL;
666 else
667 {
668 envblock = compose_envblock (envp);
669 if (envblock == NULL)
670 {
671 free (command);
672 free (argv_mem_to_free);
673 return ENOMEM;
674 }
675 }
676
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;
685
686 /* Directory in which to execute the new process. */
687 const char *directory = NULL;
688
689 /* Execute the file_actions, modifying the inh_handles instead of the
690 file descriptors of the current process. */
691 if (file_actions != NULL)
692 {
693 HANDLE curr_process = GetCurrentProcess ();
694 int cnt;
695
696 for (cnt = 0; cnt < file_actions->_used; ++cnt)
697 {
698 struct __spawn_action *action = &file_actions->_actions[cnt];
699
700 switch (action->tag)
701 {
702 case spawn_do_close:
703 {
704 int fd = action->action.close_action.fd;
705 if (do_close (&inh_handles, fd, false) < 0)
706 goto failed_2;
707 }
708 break;
709
710 case spawn_do_open:
711 {
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;
720 }
721 break;
722
723 case spawn_do_dup2:
724 {
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;
729 }
730 break;
731
732 case spawn_do_chdir:
733 {
734 char *newdir = action->action.chdir_action.path;
735 if (directory != NULL && IS_RELATIVE_FILE_NAME (newdir))
736 {
737 newdir = concatenated_filename (directory, newdir, NULL);
738 if (newdir == NULL)
739 {
740 errno = ENOMEM;
741 goto failed_2;
742 }
743 }
744 directory = newdir;
745 }
746 break;
747
748 case spawn_do_fchdir:
749 /* Not supported in this implementation. */
750 errno = EINVAL;
751 goto failed_2;
752 }
753 }
754
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
760 }
761
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);
765
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;
777
778 /* Perform the PATH search now, considering the final DIRECTORY. */
779 char *resolved_prog_filename_to_free = NULL;
780 {
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;
789 }
790
791 PROCESS_INFORMATION pinfo;
792 if (!CreateProcess (prog_filename, command, NULL, NULL, TRUE,
793 process_creation_flags, envblock, directory, &sinfo,
794 &pinfo))
795 {
796 DWORD error = GetLastError ();
797
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);
805
806 return convert_CreateProcess_error (error);
807 }
808
809 if (pinfo.hThread)
810 CloseHandle (pinfo.hThread);
811
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);
819
820 if (pid != NULL)
821 *pid = (intptr_t) pinfo.hProcess;
822 return 0;
823
824 failed_3:
825 {
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;
834 }
835
836 failed_2:
837 {
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;
845 }
846
847 failed_1:
848 free (envblock);
849 free (command);
850 free (argv_mem_to_free);
851 return errno;
852 }
853
854 #else
855
856
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
863
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. */
866 int
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)
871 {
872 pid_t new_pid;
873 char *path, *p, *name;
874 size_t len;
875 size_t pathlen;
876
877 /* Do this once. */
878 short int flags = attrp == NULL ? 0 : attrp->_flags;
879
880 /* Avoid gcc warning
881 "variable 'flags' might be clobbered by 'longjmp' or 'vfork'" */
882 (void) &flags;
883
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 ();
899
900 if (new_pid != 0)
901 {
902 if (new_pid < 0)
903 return errno;
904
905 /* The call was successful. Store the PID if necessary. */
906 if (pid != NULL)
907 *pid = new_pid;
908
909 return 0;
910 }
911
912 /* Set signal mask. */
913 if ((flags & POSIX_SPAWN_SETSIGMASK) != 0
914 && sigprocmask (SIG_SETMASK, &attrp->_ss, NULL) != 0)
915 _exit (SPAWN_ERROR);
916
917 /* Set signal default action. */
918 if ((flags & POSIX_SPAWN_SETSIGDEF) != 0)
919 {
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;
926
927 memset (&sa, '\0', sizeof (sa));
928 sa.sa_handler = SIG_DFL;
929
930 for (sig = 1; sig <= NSIG; ++sig)
931 if (sigismember (&attrp->_sd, sig) != 0
932 && sigaction (sig, &sa, NULL) != 0)
933 _exit (SPAWN_ERROR);
934
935 }
936
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)
941 {
942 if (sched_setparam (0, &attrp->_sp) == -1)
943 _exit (SPAWN_ERROR);
944 }
945 else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
946 {
947 if (sched_setscheduler (0, attrp->_policy,
948 (flags & POSIX_SPAWN_SETSCHEDPARAM) != 0
949 ? &attrp->_sp : NULL) == -1)
950 _exit (SPAWN_ERROR);
951 }
952 #endif
953
954 /* Set the process group ID. */
955 if ((flags & POSIX_SPAWN_SETPGROUP) != 0
956 && setpgid (0, attrp->_pgrp) != 0)
957 _exit (SPAWN_ERROR);
958
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);
964
965 /* Execute the file actions. */
966 if (file_actions != NULL)
967 {
968 int cnt;
969
970 for (cnt = 0; cnt < file_actions->_used; ++cnt)
971 {
972 struct __spawn_action *action = &file_actions->_actions[cnt];
973
974 switch (action->tag)
975 {
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;
981
982 case spawn_do_open:
983 {
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);
988
989 if (new_fd == -1)
990 /* The 'open' call failed. */
991 _exit (SPAWN_ERROR);
992
993 /* Make sure the desired file descriptor is used. */
994 if (new_fd != action->action.open_action.fd)
995 {
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);
1000
1001 if (close_not_cancel (new_fd) != 0)
1002 /* The 'close' call failed. */
1003 _exit (SPAWN_ERROR);
1004 }
1005 }
1006 break;
1007
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;
1015
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;
1021
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;
1027 }
1028 }
1029 }
1030
1031 if (! use_path || strchr (file, '/') != NULL)
1032 {
1033 /* The FILE parameter is actually a path. */
1034 execve (file, (char * const *) argv, (char * const *) envp);
1035
1036 /* Oh, oh. 'execve' returns. This is bad. */
1037 _exit (SPAWN_ERROR);
1038 }
1039
1040 /* We have to search for FILE on the path. */
1041 path = getenv ("PATH");
1042 if (path == NULL)
1043 {
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
1056 }
1057
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 = '/';
1065
1066 p = path;
1067 do
1068 {
1069 char *startp;
1070
1071 path = p;
1072 p = strchrnul (path, ':');
1073
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);
1080
1081 /* Try to execute this name. If it works, execv will not return. */
1082 execve (startp, (char * const *) argv, (char * const *) envp);
1083
1084 switch (errno)
1085 {
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;
1094
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);
1100 }
1101 }
1102 while (*p++ != '\0');
1103
1104 /* Return with an error. */
1105 _exit (SPAWN_ERROR);
1106 }
1107
1108 #endif