diff options
Diffstat (limited to 'lib/spawni.c')
-rw-r--r-- | lib/spawni.c | 349 |
1 files changed, 0 insertions, 349 deletions
diff --git a/lib/spawni.c b/lib/spawni.c deleted file mode 100644 index 182d13ff24c..00000000000 --- a/lib/spawni.c +++ /dev/null @@ -1,349 +0,0 @@ -/* Guts of POSIX spawn interface. Generic POSIX.1 version. - Copyright (C) 2000-2006, 2008-2020 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. */ - -#include <config.h> - -/* Specification. */ -#include <spawn.h> -#include "spawn_int.h" - -#include <alloca.h> -#include <errno.h> - -#include <fcntl.h> -#ifndef O_LARGEFILE -# define O_LARGEFILE 0 -#endif - -#if _LIBC || HAVE_PATHS_H -# include <paths.h> -#else -# define _PATH_BSHELL BOURNE_SHELL -#endif - -#include <signal.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#if _LIBC -# include <not-cancel.h> -#else -# define close_not_cancel close -# define open_not_cancel open -#endif - -#if _LIBC -# include <local-setxid.h> -#else -# if !HAVE_SETEUID -# define seteuid(id) setresuid (-1, id, -1) -# endif -# if !HAVE_SETEGID -# define setegid(id) setresgid (-1, id, -1) -# endif -# define local_seteuid(id) seteuid (id) -# define local_setegid(id) setegid (id) -#endif - -#if _LIBC -# define alloca __alloca -# define execve __execve -# define dup2 __dup2 -# define fork __fork -# define getgid __getgid -# define getuid __getuid -# define sched_setparam __sched_setparam -# define sched_setscheduler __sched_setscheduler -# define setpgid __setpgid -# define sigaction __sigaction -# define sigismember __sigismember -# define sigprocmask __sigprocmask -# define strchrnul __strchrnul -# define vfork __vfork -#endif - - -/* The Unix standard contains a long explanation of the way to signal - an error after the fork() was successful. Since no new wait status - was wanted there is no way to signal an error using one of the - available methods. The committee chose to signal an error by a - normal program exit with the exit code 127. */ -#define SPAWN_ERROR 127 - - -#if defined _WIN32 && ! defined __CYGWIN__ - -/* Native Windows API. */ -int -__spawni (pid_t *pid, const char *file, - const posix_spawn_file_actions_t *file_actions, - const posix_spawnattr_t *attrp, const char *const argv[], - const char *const envp[], int use_path) -{ - /* Not yet implemented. */ - return ENOSYS; -} - -#else - - -/* Spawn a new process executing PATH with the attributes describes in *ATTRP. - Before running the process perform the actions described in FILE-ACTIONS. */ -int -__spawni (pid_t *pid, const char *file, - const posix_spawn_file_actions_t *file_actions, - const posix_spawnattr_t *attrp, const char *const argv[], - const char *const envp[], int use_path) -{ - pid_t new_pid; - char *path, *p, *name; - size_t len; - size_t pathlen; - - /* Do this once. */ - short int flags = attrp == NULL ? 0 : attrp->_flags; - - /* Avoid gcc warning - "variable 'flags' might be clobbered by 'longjmp' or 'vfork'" */ - (void) &flags; - - /* Generate the new process. */ -#if HAVE_VFORK - if ((flags & POSIX_SPAWN_USEVFORK) != 0 - /* If no major work is done, allow using vfork. Note that we - might perform the path searching. But this would be done by - a call to execvp(), too, and such a call must be OK according - to POSIX. */ - || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF - | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER - | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0 - && file_actions == NULL)) - new_pid = vfork (); - else -#endif - new_pid = fork (); - - if (new_pid != 0) - { - if (new_pid < 0) - return errno; - - /* The call was successful. Store the PID if necessary. */ - if (pid != NULL) - *pid = new_pid; - - return 0; - } - - /* Set signal mask. */ - if ((flags & POSIX_SPAWN_SETSIGMASK) != 0 - && sigprocmask (SIG_SETMASK, &attrp->_ss, NULL) != 0) - _exit (SPAWN_ERROR); - - /* Set signal default action. */ - if ((flags & POSIX_SPAWN_SETSIGDEF) != 0) - { - /* We have to iterate over all signals. This could possibly be - done better but it requires system specific solutions since - the sigset_t data type can be very different on different - architectures. */ - int sig; - struct sigaction sa; - - memset (&sa, '\0', sizeof (sa)); - sa.sa_handler = SIG_DFL; - - for (sig = 1; sig <= NSIG; ++sig) - if (sigismember (&attrp->_sd, sig) != 0 - && sigaction (sig, &sa, NULL) != 0) - _exit (SPAWN_ERROR); - - } - -#if (_LIBC ? defined _POSIX_PRIORITY_SCHEDULING : HAVE_SCHED_SETPARAM && HAVE_SCHED_SETSCHEDULER) - /* Set the scheduling algorithm and parameters. */ - if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER)) - == POSIX_SPAWN_SETSCHEDPARAM) - { - if (sched_setparam (0, &attrp->_sp) == -1) - _exit (SPAWN_ERROR); - } - else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0) - { - if (sched_setscheduler (0, attrp->_policy, - (flags & POSIX_SPAWN_SETSCHEDPARAM) != 0 - ? &attrp->_sp : NULL) == -1) - _exit (SPAWN_ERROR); - } -#endif - - /* Set the process group ID. */ - if ((flags & POSIX_SPAWN_SETPGROUP) != 0 - && setpgid (0, attrp->_pgrp) != 0) - _exit (SPAWN_ERROR); - - /* Set the effective user and group IDs. */ - if ((flags & POSIX_SPAWN_RESETIDS) != 0 - && (local_seteuid (getuid ()) != 0 - || local_setegid (getgid ()) != 0)) - _exit (SPAWN_ERROR); - - /* Execute the file actions. */ - if (file_actions != NULL) - { - int cnt; - - for (cnt = 0; cnt < file_actions->_used; ++cnt) - { - struct __spawn_action *action = &file_actions->_actions[cnt]; - - switch (action->tag) - { - case spawn_do_close: - if (close_not_cancel (action->action.close_action.fd) != 0) - /* Signal the error. */ - _exit (SPAWN_ERROR); - break; - - case spawn_do_open: - { - int new_fd = open_not_cancel (action->action.open_action.path, - action->action.open_action.oflag - | O_LARGEFILE, - action->action.open_action.mode); - - if (new_fd == -1) - /* The 'open' call failed. */ - _exit (SPAWN_ERROR); - - /* Make sure the desired file descriptor is used. */ - if (new_fd != action->action.open_action.fd) - { - if (dup2 (new_fd, action->action.open_action.fd) - != action->action.open_action.fd) - /* The 'dup2' call failed. */ - _exit (SPAWN_ERROR); - - if (close_not_cancel (new_fd) != 0) - /* The 'close' call failed. */ - _exit (SPAWN_ERROR); - } - } - break; - - case spawn_do_dup2: - if (dup2 (action->action.dup2_action.fd, - action->action.dup2_action.newfd) - != action->action.dup2_action.newfd) - /* The 'dup2' call failed. */ - _exit (SPAWN_ERROR); - break; - - case spawn_do_chdir: - if (chdir (action->action.chdir_action.path) < 0) - /* The 'chdir' call failed. */ - _exit (SPAWN_ERROR); - break; - - case spawn_do_fchdir: - if (fchdir (action->action.fchdir_action.fd) < 0) - /* The 'fchdir' call failed. */ - _exit (SPAWN_ERROR); - break; - } - } - } - - if (! use_path || strchr (file, '/') != NULL) - { - /* The FILE parameter is actually a path. */ - execve (file, (char * const *) argv, (char * const *) envp); - - /* Oh, oh. 'execve' returns. This is bad. */ - _exit (SPAWN_ERROR); - } - - /* We have to search for FILE on the path. */ - path = getenv ("PATH"); - if (path == NULL) - { -#if HAVE_CONFSTR - /* There is no 'PATH' in the environment. - The default search path is the current directory - followed by the path 'confstr' returns for '_CS_PATH'. */ - len = confstr (_CS_PATH, (char *) NULL, 0); - path = (char *) alloca (1 + len); - path[0] = ':'; - (void) confstr (_CS_PATH, path + 1, len); -#else - /* Pretend that the PATH contains only the current directory. */ - path = ""; -#endif - } - - len = strlen (file) + 1; - pathlen = strlen (path); - name = alloca (pathlen + len + 1); - /* Copy the file name at the top. */ - name = (char *) memcpy (name + pathlen + 1, file, len); - /* And add the slash. */ - *--name = '/'; - - p = path; - do - { - char *startp; - - path = p; - p = strchrnul (path, ':'); - - if (p == path) - /* Two adjacent colons, or a colon at the beginning or the end - of 'PATH' means to search the current directory. */ - startp = name + 1; - else - startp = (char *) memcpy (name - (p - path), path, p - path); - - /* Try to execute this name. If it works, execv will not return. */ - execve (startp, (char * const *) argv, (char * const *) envp); - - switch (errno) - { - case EACCES: - case ENOENT: - case ESTALE: - case ENOTDIR: - /* Those errors indicate the file is missing or not executable - by us, in which case we want to just try the next path - directory. */ - break; - - default: - /* Some other error means we found an executable file, but - something went wrong executing it; return the error to our - caller. */ - _exit (SPAWN_ERROR); - } - } - while (*p++ != '\0'); - - /* Return with an error. */ - _exit (SPAWN_ERROR); -} - -#endif |