1 /* Guts of POSIX spawn interface. Generic POSIX.1 version.
2 Copyright (C) 2000-2006, 2008-2021 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 /* Get declarations of the native Windows API functions. */
93 # define WIN32_LEAN_AND_MEAN
94 # include <windows.h>
95
96 # include <stdbool.h>
97 # include <stdio.h>
98
99 # include "filename.h"
100 # include "concat-filename.h"
101 # include "findprog.h"
102 # include "malloca.h"
103 # include "windows-spawn.h"
104
105 /* Don't assume that UNICODE is not defined. */
106 # undef CreateFile
107 # define CreateFile CreateFileA
108 # undef STARTUPINFO
109 # define STARTUPINFO STARTUPINFOA
110 # undef CreateProcess
111 # define CreateProcess CreateProcessA
112
113 /* Grows inh_handles->count so that it becomes > newfd.
114 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
115 */
116 static int
117 grow_inheritable_handles (struct inheritable_handles *inh_handles, int newfd)
118 {
119 if (inh_handles->allocated <= newfd)
120 {
121 size_t new_allocated = 2 * inh_handles->allocated + 1;
122 if (new_allocated <= newfd)
123 new_allocated = newfd + 1;
124 HANDLE *new_handles_array =
125 (HANDLE *)
126 realloc (inh_handles->handles, new_allocated * sizeof (HANDLE));
127 if (new_handles_array == NULL)
128 {
129 errno = ENOMEM;
130 return -1;
131 }
132 unsigned char *new_flags_array =
133 (unsigned char *)
134 realloc (inh_handles->flags, new_allocated * sizeof (unsigned char));
135 if (new_flags_array == NULL)
136 {
137 free (new_handles_array);
138 errno = ENOMEM;
139 return -1;
140 }
141 inh_handles->allocated = new_allocated;
142 inh_handles->handles = new_handles_array;
143 inh_handles->flags = new_flags_array;
144 }
145
146 HANDLE *handles = inh_handles->handles;
147
148 for (; inh_handles->count <= newfd; inh_handles->count++)
149 handles[inh_handles->count] = INVALID_HANDLE_VALUE;
150
151 return 0;
152 }
153
154 /* Reduces inh_handles->count to the minimum needed. */
155 static void
156 shrink_inheritable_handles (struct inheritable_handles *inh_handles)
157 {
158 HANDLE *handles = inh_handles->handles;
159
160 while (inh_handles->count > 3
161 && handles[inh_handles->count - 1] == INVALID_HANDLE_VALUE)
162 inh_handles->count--;
163 }
164
165 /* Closes all handles in inh_handles. */
166 static void
167 close_inheritable_handles (struct inheritable_handles *inh_handles)
168 {
169 HANDLE *handles = inh_handles->handles;
170 size_t handles_count = inh_handles->count;
171 unsigned int fd;
172
173 for (fd = 0; fd < handles_count; fd++)
174 {
175 HANDLE handle = handles[fd];
176
177 if (handle != INVALID_HANDLE_VALUE)
178 CloseHandle (handle);
179 }
180 }
181
182 /* Tests whether a memory region, starting at P and N bytes long, contains only
183 zeroes. */
184 static bool
185 memiszero (const void *p, size_t n)
186 {
187 const char *cp = p;
188 for (; n > 0; cp++, n--)
189 if (*cp != 0)
190 return 0;
191 return 1;
192 }
193
194 /* Tests whether *S contains no signals. */
195 static bool
196 sigisempty (const sigset_t *s)
197 {
198 return memiszero (s, sizeof (sigset_t));
199 }
200
201 /* Opens a HANDLE to a file.
202 Upon failure, returns INVALID_HANDLE_VALUE with errno set. */
203 static HANDLE
204 open_handle (const char *name, int flags, mode_t mode)
205 {
206 /* To ease portability. Like in open.c. */
207 if (strcmp (name, "/dev/null") == 0)
208 name = "NUL";
209
210 /* POSIX <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>
211 specifies: "More than two leading <slash> characters shall be treated as
212 a single <slash> character." */
213 if (ISSLASH (name[0]) && ISSLASH (name[1]) && ISSLASH (name[2]))
214 {
215 name += 2;
216 while (ISSLASH (name[1]))
217 name++;
218 }
219
220 size_t len = strlen (name);
221 size_t drive_prefix_len = (HAS_DEVICE (name) ? 2 : 0);
222
223 /* Remove trailing slashes (except the very first one, at position
224 drive_prefix_len), but remember their presence. */
225 size_t rlen;
226 bool check_dir = false;
227
228 rlen = len;
229 while (rlen > drive_prefix_len && ISSLASH (name[rlen-1]))
230 {
231 check_dir = true;
232 if (rlen == drive_prefix_len + 1)
233 break;
234 rlen--;
235 }
236
237 /* Handle '' and 'C:'. */
238 if (!check_dir && rlen == drive_prefix_len)
239 {
240 errno = ENOENT;
241 return INVALID_HANDLE_VALUE;
242 }
243
244 /* Handle '\\'. */
245 if (rlen == 1 && ISSLASH (name[0]) && len >= 2)
246 {
247 errno = ENOENT;
248 return INVALID_HANDLE_VALUE;
249 }
250
251 const char *rname;
252 char *malloca_rname;
253 if (rlen == len)
254 {
255 rname = name;
256 malloca_rname = NULL;
257 }
258 else
259 {
260 malloca_rname = malloca (rlen + 1);
261 if (malloca_rname == NULL)
262 {
263 errno = ENOMEM;
264 return INVALID_HANDLE_VALUE;
265 }
266 memcpy (malloca_rname, name, rlen);
267 malloca_rname[rlen] = '\0';
268 rname = malloca_rname;
269 }
270
271 /* For the meaning of the flags, see
272 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/open-wopen> */
273 /* Open a handle to the file.
274 CreateFile
275 <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea>
276 <https://docs.microsoft.com/en-us/windows/desktop/FileIO/creating-and-opening-files> */
277 HANDLE handle =
278 CreateFile (rname,
279 ((flags & (O_WRONLY | O_RDWR)) != 0
280 ? GENERIC_READ | GENERIC_WRITE
281 : GENERIC_READ),
282 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
283 NULL,
284 ((flags & O_CREAT) != 0
285 ? ((flags & O_EXCL) != 0
286 ? CREATE_NEW
287 : ((flags & O_TRUNC) != 0 ? CREATE_ALWAYS : OPEN_ALWAYS))
288 : ((flags & O_TRUNC) != 0
289 ? TRUNCATE_EXISTING
290 : OPEN_EXISTING)),
291 /* FILE_FLAG_BACKUP_SEMANTICS is useful for opening directories,
292 which is out-of-scope here. */
293 /* FILE_FLAG_POSIX_SEMANTICS (treat file names that differ only
294 in case as different) makes sense only when applied to *all*
295 filesystem operations. */
296 /* FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS */
297 FILE_ATTRIBUTE_NORMAL
298 | ((flags & O_TEMPORARY) != 0 ? FILE_FLAG_DELETE_ON_CLOSE : 0)
299 | ((flags & O_SEQUENTIAL ) != 0 ? FILE_FLAG_SEQUENTIAL_SCAN : 0)
300 | ((flags & O_RANDOM) != 0 ? FILE_FLAG_RANDOM_ACCESS : 0),
301 NULL);
302 if (handle == INVALID_HANDLE_VALUE)
303 switch (GetLastError ())
304 {
305 /* Some of these errors probably cannot happen with the specific flags
306 that we pass to CreateFile. But who knows... */
307 case ERROR_FILE_NOT_FOUND: /* The last component of rname does not exist. */
308 case ERROR_PATH_NOT_FOUND: /* Some directory component in rname does not exist. */
309 case ERROR_BAD_PATHNAME: /* rname is such as '\\server'. */
310 case ERROR_BAD_NETPATH: /* rname is such as '\\nonexistentserver\share'. */
311 case ERROR_BAD_NET_NAME: /* rname is such as '\\server\nonexistentshare'. */
312 case ERROR_INVALID_NAME: /* rname contains wildcards, misplaced colon, etc. */
313 case ERROR_DIRECTORY:
314 errno = ENOENT;
315 break;
316
317 case ERROR_ACCESS_DENIED: /* rname is such as 'C:\System Volume Information\foo'. */
318 case ERROR_SHARING_VIOLATION: /* rname is such as 'C:\pagefile.sys'. */
319 /* XXX map to EACCES or EPERM? */
320 errno = EACCES;
321 break;
322
323 case ERROR_OUTOFMEMORY:
324 errno = ENOMEM;
325 break;
326
327 case ERROR_WRITE_PROTECT:
328 errno = EROFS;
329 break;
330
331 case ERROR_WRITE_FAULT:
332 case ERROR_READ_FAULT:
333 case ERROR_GEN_FAILURE:
334 errno = EIO;
335 break;
336
337 case ERROR_BUFFER_OVERFLOW:
338 case ERROR_FILENAME_EXCED_RANGE:
339 errno = ENAMETOOLONG;
340 break;
341
342 case ERROR_DELETE_PENDING: /* XXX map to EACCES or EPERM? */
343 errno = EPERM;
344 break;
345
346 default:
347 errno = EINVAL;
348 break;
349 }
350
351 if (malloca_rname != NULL)
352 {
353 int saved_errno = errno;
354 freea (malloca_rname);
355 errno = saved_errno;
356 }
357 return handle;
358 }
359
360 /* Executes an 'open' action.
361 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
362 */
363 static int
364 do_open (struct inheritable_handles *inh_handles, int newfd,
365 const char *filename, const char *directory,
366 int flags, mode_t mode, HANDLE curr_process)
367 {
368 if (!(newfd >= 0 && newfd < _getmaxstdio ()))
369 {
370 errno = EBADF;
371 return -1;
372 }
373 if (grow_inheritable_handles (inh_handles, newfd) < 0)
374 return -1;
375 if (inh_handles->handles[newfd] != INVALID_HANDLE_VALUE
376 && !CloseHandle (inh_handles->handles[newfd]))
377 {
378 errno = EIO;
379 return -1;
380 }
381 if (filename == NULL)
382 {
383 errno = EINVAL;
384 return -1;
385 }
386 char *filename_to_free = NULL;
387 if (directory != NULL && IS_RELATIVE_FILE_NAME (filename))
388 {
389 char *real_filename = concatenated_filename (directory, filename, NULL);
390 if (real_filename == NULL)
391 {
392 errno = ENOMEM;
393 return -1;
394 }
395 filename = real_filename;
396 filename_to_free = real_filename;
397 }
398 HANDLE handle = open_handle (filename, flags, mode);
399 if (handle == INVALID_HANDLE_VALUE)
400 {
401 free (filename_to_free);
402 return -1;
403 }
404 free (filename_to_free);
405 /* Duplicate the handle, so that it becomes inheritable. */
406 if (!DuplicateHandle (curr_process, handle,
407 curr_process, &inh_handles->handles[newfd],
408 0, TRUE,
409 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
410 {
411 errno = EBADF; /* arbitrary */
412 return -1;
413 }
414 inh_handles->flags[newfd] = ((flags & O_APPEND) != 0 ? 32 : 0);
415 return 0;
416 }
417
418 /* Executes a 'dup2' action.
419 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
420 */
421 static int
422 do_dup2 (struct inheritable_handles *inh_handles, int oldfd, int newfd,
423 HANDLE curr_process)
424 {
425 if (!(oldfd >= 0 && oldfd < inh_handles->count
426 && inh_handles->handles[oldfd] != INVALID_HANDLE_VALUE))
427 {
428 errno = EBADF;
429 return -1;
430 }
431 if (!(newfd >= 0 && newfd < _getmaxstdio ()))
432 {
433 errno = EBADF;
434 return -1;
435 }
436 if (newfd != oldfd)
437 {
438 if (grow_inheritable_handles (inh_handles, newfd) < 0)
439 return -1;
440 if (inh_handles->handles[newfd] != INVALID_HANDLE_VALUE
441 && !CloseHandle (inh_handles->handles[newfd]))
442 {
443 errno = EIO;
444 return -1;
445 }
446 /* Duplicate the handle, so that it a forthcoming do_close action on oldfd
447 has no effect on newfd. */
448 if (!DuplicateHandle (curr_process, inh_handles->handles[oldfd],
449 curr_process, &inh_handles->handles[newfd],
450 0, TRUE, DUPLICATE_SAME_ACCESS))
451 {
452 errno = EBADF; /* arbitrary */
453 return -1;
454 }
455 inh_handles->flags[newfd] = 0;
456 }
457 return 0;
458 }
459
460 /* Executes a 'close' action.
461 Returns 0 upon success. In case of failure, -1 is returned, with errno set.
462 */
463 static int
464 do_close (struct inheritable_handles *inh_handles, int fd)
465 {
466 if (!(fd >= 0 && fd < inh_handles->count
467 && inh_handles->handles[fd] != INVALID_HANDLE_VALUE))
468 {
469 errno = EBADF;
470 return -1;
471 }
472 if (!CloseHandle (inh_handles->handles[fd]))
473 {
474 errno = EIO;
475 return -1;
476 }
477 inh_handles->handles[fd] = INVALID_HANDLE_VALUE;
478 return 0;
479 }
480
481 int
482 __spawni (pid_t *pid, const char *prog_filename,
483 const posix_spawn_file_actions_t *file_actions,
484 const posix_spawnattr_t *attrp, const char *const prog_argv[],
485 const char *const envp[], int use_path)
486 {
487 /* Validate the arguments. */
488 if (prog_filename == NULL
489 || (attrp != NULL
490 && ((attrp->_flags & ~POSIX_SPAWN_SETPGROUP) != 0
491 || attrp->_pgrp != 0
492 || ! sigisempty (&attrp->_sd)
493 || ! sigisempty (&attrp->_ss)
494 || attrp->_sp.sched_priority != 0
495 || attrp->_policy != 0)))
496 return EINVAL;
497
498 /* Process group handling:
499 Native Windows does not have the concept of process group, but it has the
500 concept of a console attached to a process.
501 So, we interpret the three cases as follows:
502 - Flag POSIX_SPAWN_SETPGROUP not set: Means, the child process is in the
503 same process group as the parent process. We interpret this as a
504 request to reuse the same console.
505 - Flag POSIX_SPAWN_SETPGROUP set with attrp->_pgrp == 0: Means the child
506 process starts a process group of its own. See
507 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_getpgroup.html>
508 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgrp.html>
509 We interpret this as a request to detach from the current console.
510 - Flag POSIX_SPAWN_SETPGROUP set with attrp->_pgrp != 0: Means the child
511 process joins another, existing process group. See
512 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawnattr_getpgroup.html>
513 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html>
514 We don't support this case; it produces error EINVAL above. */
515 /* <https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags> */
516 DWORD process_creation_flags =
517 (attrp != NULL && (attrp->_flags & POSIX_SPAWN_SETPGROUP) != 0 ? DETACHED_PROCESS : 0);
518
519 char *argv_mem_to_free;
520 const char **argv = prepare_spawn (prog_argv, &argv_mem_to_free);
521 if (argv == NULL)
522 return errno; /* errno is set here */
523 argv++;
524
525 /* Compose the command. */
526 char *command = compose_command (argv);
527 if (command == NULL)
528 {
529 free (argv_mem_to_free);
530 return ENOMEM;
531 }
532
533 /* Copy *ENVP into a contiguous block of memory. */
534 char *envblock;
535 if (envp == NULL)
536 envblock = NULL;
537 else
538 {
539 envblock = compose_envblock (envp);
540 if (envblock == NULL)
541 {
542 free (command);
543 free (argv_mem_to_free);
544 return ENOMEM;
545 }
546 }
547
548 /* Set up the array of handles to inherit.
549 Duplicate each handle, so that a spawn_do_close action (below) has no
550 effect on the file descriptors of the current process. Alternatively,
551 we could store, for each handle, a bit that tells whether it is shared
552 with the current process. But this is simpler. */
553 struct inheritable_handles inh_handles;
554 if (init_inheritable_handles (&inh_handles, true) < 0)
555 goto failed_1;
556
557 /* Directory in which to execute the new process. */
558 const char *directory = NULL;
559
560 /* Execute the file_actions, modifying the inh_handles instead of the
561 file descriptors of the current process. */
562 if (file_actions != NULL)
563 {
564 HANDLE curr_process = GetCurrentProcess ();
565 int cnt;
566
567 for (cnt = 0; cnt < file_actions->_used; ++cnt)
568 {
569 struct __spawn_action *action = &file_actions->_actions[cnt];
570
571 switch (action->tag)
572 {
573 case spawn_do_close:
574 {
575 int fd = action->action.close_action.fd;
576 if (do_close (&inh_handles, fd) < 0)
577 goto failed_2;
578 }
579 break;
580
581 case spawn_do_open:
582 {
583 int newfd = action->action.open_action.fd;
584 const char *filename = action->action.open_action.path;
585 int flags = action->action.open_action.oflag;
586 mode_t mode = action->action.open_action.mode;
587 if (do_open (&inh_handles, newfd, filename, directory,
588 flags, mode, curr_process)
589 < 0)
590 goto failed_2;
591 }
592 break;
593
594 case spawn_do_dup2:
595 {
596 int oldfd = action->action.dup2_action.fd;
597 int newfd = action->action.dup2_action.newfd;
598 if (do_dup2 (&inh_handles, oldfd, newfd, curr_process) < 0)
599 goto failed_2;
600 }
601 break;
602
603 case spawn_do_chdir:
604 {
605 char *newdir = action->action.chdir_action.path;
606 if (directory != NULL && IS_RELATIVE_FILE_NAME (newdir))
607 {
608 newdir = concatenated_filename (directory, newdir, NULL);
609 if (newdir == NULL)
610 {
611 errno = ENOMEM;
612 goto failed_2;
613 }
614 }
615 directory = newdir;
616 }
617 break;
618
619 case spawn_do_fchdir:
620 /* Not supported in this implementation. */
621 errno = EINVAL;
622 goto failed_2;
623 }
624 }
625 }
626
627 /* Reduce inh_handles.count to the minimum needed. */
628 shrink_inheritable_handles (&inh_handles);
629
630 /* CreateProcess
631 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa> */
632 /* STARTUPINFO
633 <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa> */
634 STARTUPINFO sinfo;
635 sinfo.cb = sizeof (STARTUPINFO);
636 sinfo.lpReserved = NULL;
637 sinfo.lpDesktop = NULL;
638 sinfo.lpTitle = NULL;
639 if (compose_handles_block (&inh_handles, &sinfo) < 0)
640 goto failed_2;
641
642 /* Perform the PATH search now, considering the final DIRECTORY. */
643 char *resolved_prog_filename_to_free = NULL;
644 {
645 const char *resolved_prog_filename =
646 find_in_given_path (prog_filename, use_path ? getenv ("PATH") : "",
647 directory, false);
648 if (resolved_prog_filename == NULL)
649 goto failed_3;
650 if (resolved_prog_filename != prog_filename)
651 resolved_prog_filename_to_free = (char *) resolved_prog_filename;
652 prog_filename = resolved_prog_filename;
653 }
654
655 PROCESS_INFORMATION pinfo;
656 if (!CreateProcess (prog_filename, command, NULL, NULL, TRUE,
657 process_creation_flags, envblock, directory, &sinfo,
658 &pinfo))
659 {
660 DWORD error = GetLastError ();
661
662 free (resolved_prog_filename_to_free);
663 free (sinfo.lpReserved2);
664 close_inheritable_handles (&inh_handles);
665 free_inheritable_handles (&inh_handles);
666 free (envblock);
667 free (command);
668 free (argv_mem_to_free);
669
670 return convert_CreateProcess_error (error);
671 }
672
673 if (pinfo.hThread)
674 CloseHandle (pinfo.hThread);
675
676 free (resolved_prog_filename_to_free);
677 free (sinfo.lpReserved2);
678 close_inheritable_handles (&inh_handles);
679 free_inheritable_handles (&inh_handles);
680 free (envblock);
681 free (command);
682 free (argv_mem_to_free);
683
684 if (pid != NULL)
685 *pid = (intptr_t) pinfo.hProcess;
686 return 0;
687
688 failed_3:
689 {
690 int saved_errno = errno;
691 free (sinfo.lpReserved2);
692 close_inheritable_handles (&inh_handles);
693 free_inheritable_handles (&inh_handles);
694 free (envblock);
695 free (command);
696 free (argv_mem_to_free);
697 return saved_errno;
698 }
699
700 failed_2:
701 {
702 int saved_errno = errno;
703 close_inheritable_handles (&inh_handles);
704 free_inheritable_handles (&inh_handles);
705 free (envblock);
706 free (command);
707 free (argv_mem_to_free);
708 return saved_errno;
709 }
710
711 failed_1:
712 free (envblock);
713 free (command);
714 free (argv_mem_to_free);
715 return errno;
716 }
717
718 #else
719
720
721 /* Spawn a new process executing PATH with the attributes describes in *ATTRP.
722 Before running the process perform the actions described in FILE-ACTIONS. */
723 int
724 __spawni (pid_t *pid, const char *file,
725 const posix_spawn_file_actions_t *file_actions,
726 const posix_spawnattr_t *attrp, const char *const argv[],
727 const char *const envp[], int use_path)
728 {
729 pid_t new_pid;
730 char *path, *p, *name;
731 size_t len;
732 size_t pathlen;
733
734 /* Do this once. */
735 short int flags = attrp == NULL ? 0 : attrp->_flags;
736
737 /* Avoid gcc warning
738 "variable 'flags' might be clobbered by 'longjmp' or 'vfork'" */
739 (void) &flags;
740
741 /* Generate the new process. */
742 #if HAVE_VFORK
743 if ((flags & POSIX_SPAWN_USEVFORK) != 0
744 /* If no major work is done, allow using vfork. Note that we
745 might perform the path searching. But this would be done by
746 a call to execvp(), too, and such a call must be OK according
747 to POSIX. */
748 || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF
749 | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER
750 | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0
751 && file_actions == NULL))
752 new_pid = vfork ();
753 else
754 #endif
755 new_pid = fork ();
756
757 if (new_pid != 0)
758 {
759 if (new_pid < 0)
760 return errno;
761
762 /* The call was successful. Store the PID if necessary. */
763 if (pid != NULL)
764 *pid = new_pid;
765
766 return 0;
767 }
768
769 /* Set signal mask. */
770 if ((flags & POSIX_SPAWN_SETSIGMASK) != 0
771 && sigprocmask (SIG_SETMASK, &attrp->_ss, NULL) != 0)
772 _exit (SPAWN_ERROR);
773
774 /* Set signal default action. */
775 if ((flags & POSIX_SPAWN_SETSIGDEF) != 0)
776 {
777 /* We have to iterate over all signals. This could possibly be
778 done better but it requires system specific solutions since
779 the sigset_t data type can be very different on different
780 architectures. */
781 int sig;
782 struct sigaction sa;
783
784 memset (&sa, '\0', sizeof (sa));
785 sa.sa_handler = SIG_DFL;
786
787 for (sig = 1; sig <= NSIG; ++sig)
788 if (sigismember (&attrp->_sd, sig) != 0
789 && sigaction (sig, &sa, NULL) != 0)
790 _exit (SPAWN_ERROR);
791
792 }
793
794 #if (_LIBC ? defined _POSIX_PRIORITY_SCHEDULING : HAVE_SCHED_SETPARAM && HAVE_SCHED_SETSCHEDULER)
795 /* Set the scheduling algorithm and parameters. */
796 if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
797 == POSIX_SPAWN_SETSCHEDPARAM)
798 {
799 if (sched_setparam (0, &attrp->_sp) == -1)
800 _exit (SPAWN_ERROR);
801 }
802 else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
803 {
804 if (sched_setscheduler (0, attrp->_policy,
805 (flags & POSIX_SPAWN_SETSCHEDPARAM) != 0
806 ? &attrp->_sp : NULL) == -1)
807 _exit (SPAWN_ERROR);
808 }
809 #endif
810
811 /* Set the process group ID. */
812 if ((flags & POSIX_SPAWN_SETPGROUP) != 0
813 && setpgid (0, attrp->_pgrp) != 0)
814 _exit (SPAWN_ERROR);
815
816 /* Set the effective user and group IDs. */
817 if ((flags & POSIX_SPAWN_RESETIDS) != 0
818 && (local_seteuid (getuid ()) != 0
819 || local_setegid (getgid ()) != 0))
820 _exit (SPAWN_ERROR);
821
822 /* Execute the file actions. */
823 if (file_actions != NULL)
824 {
825 int cnt;
826
827 for (cnt = 0; cnt < file_actions->_used; ++cnt)
828 {
829 struct __spawn_action *action = &file_actions->_actions[cnt];
830
831 switch (action->tag)
832 {
833 case spawn_do_close:
834 if (close_not_cancel (action->action.close_action.fd) != 0)
835 /* Signal the error. */
836 _exit (SPAWN_ERROR);
837 break;
838
839 case spawn_do_open:
840 {
841 int new_fd = open_not_cancel (action->action.open_action.path,
842 action->action.open_action.oflag
843 | O_LARGEFILE,
844 action->action.open_action.mode);
845
846 if (new_fd == -1)
847 /* The 'open' call failed. */
848 _exit (SPAWN_ERROR);
849
850 /* Make sure the desired file descriptor is used. */
851 if (new_fd != action->action.open_action.fd)
852 {
853 if (dup2 (new_fd, action->action.open_action.fd)
854 != action->action.open_action.fd)
855 /* The 'dup2' call failed. */
856 _exit (SPAWN_ERROR);
857
858 if (close_not_cancel (new_fd) != 0)
859 /* The 'close' call failed. */
860 _exit (SPAWN_ERROR);
861 }
862 }
863 break;
864
865 case spawn_do_dup2:
866 if (dup2 (action->action.dup2_action.fd,
867 action->action.dup2_action.newfd)
868 != action->action.dup2_action.newfd)
869 /* The 'dup2' call failed. */
870 _exit (SPAWN_ERROR);
871 break;
872
873 case spawn_do_chdir:
874 if (chdir (action->action.chdir_action.path) < 0)
875 /* The 'chdir' call failed. */
876 _exit (SPAWN_ERROR);
877 break;
878
879 case spawn_do_fchdir:
880 if (fchdir (action->action.fchdir_action.fd) < 0)
881 /* The 'fchdir' call failed. */
882 _exit (SPAWN_ERROR);
883 break;
884 }
885 }
886 }
887
888 if (! use_path || strchr (file, '/') != NULL)
889 {
890 /* The FILE parameter is actually a path. */
891 execve (file, (char * const *) argv, (char * const *) envp);
892
893 /* Oh, oh. 'execve' returns. This is bad. */
894 _exit (SPAWN_ERROR);
895 }
896
897 /* We have to search for FILE on the path. */
898 path = getenv ("PATH");
899 if (path == NULL)
900 {
901 #if HAVE_CONFSTR
902 /* There is no 'PATH' in the environment.
903 The default search path is the current directory
904 followed by the path 'confstr' returns for '_CS_PATH'. */
905 len = confstr (_CS_PATH, (char *) NULL, 0);
906 path = (char *) alloca (1 + len);
907 path[0] = ':';
908 (void) confstr (_CS_PATH, path + 1, len);
909 #else
910 /* Pretend that the PATH contains only the current directory. */
911 path = "";
912 #endif
913 }
914
915 len = strlen (file) + 1;
916 pathlen = strlen (path);
917 name = alloca (pathlen + len + 1);
918 /* Copy the file name at the top. */
919 name = (char *) memcpy (name + pathlen + 1, file, len);
920 /* And add the slash. */
921 *--name = '/';
922
923 p = path;
924 do
925 {
926 char *startp;
927
928 path = p;
929 p = strchrnul (path, ':');
930
931 if (p == path)
932 /* Two adjacent colons, or a colon at the beginning or the end
933 of 'PATH' means to search the current directory. */
934 startp = name + 1;
935 else
936 startp = (char *) memcpy (name - (p - path), path, p - path);
937
938 /* Try to execute this name. If it works, execv will not return. */
939 execve (startp, (char * const *) argv, (char * const *) envp);
940
941 switch (errno)
942 {
943 case EACCES:
944 case ENOENT:
945 case ESTALE:
946 case ENOTDIR:
947 /* Those errors indicate the file is missing or not executable
948 by us, in which case we want to just try the next path
949 directory. */
950 break;
951
952 default:
953 /* Some other error means we found an executable file, but
954 something went wrong executing it; return the error to our
955 caller. */
956 _exit (SPAWN_ERROR);
957 }
958 }
959 while (*p++ != '\0');
960
961 /* Return with an error. */
962 _exit (SPAWN_ERROR);
963 }
964
965 #endif