summaryrefslogtreecommitdiff
path: root/lib/spawni.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spawni.c')
-rw-r--r--lib/spawni.c349
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