1 /* Copyright (C) 2000, 2011 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
25 #include <sys/resource.h>
26 #include <not-cancel.h>
29 #include "spawn_int.h"
31 /* The Unix standard contains a long explanation of the way to signal
32 an error after the fork() was successful. Since no new wait status
33 was wanted there is no way to signal an error using one of the
34 available methods. The committee chose to signal an error by a
35 normal program exit with the exit code 127. */
36 #define SPAWN_ERROR 127
38 /* Execute file actions.
39 * Returns true on error.
41 inline static bool execute_file_actions(const posix_spawn_file_actions_t *fa)
43 struct rlimit64 fdlimit;
44 bool have_fdlimit = false;
47 for (cnt = 0; cnt < fa->__used; ++cnt) {
48 struct __spawn_action *action = &fa->__actions[cnt];
50 switch (action->tag) {
52 if (close_not_cancel(action->action.close_action.fd) != 0) {
54 getrlimit64(RLIMIT_NOFILE, &fdlimit);
58 /* Only signal errors for file descriptors out of range. */
59 if (0 > action->action.close_action.fd
60 || action->action.close_action.fd >= fdlimit.rlim_cur)
61 /* Signal the error. */
67 int new_fd = open_not_cancel(action->action.open_action.path,
68 action->action.open_action.oflag
70 action->action.open_action.mode);
75 /* Make sure the desired file descriptor is used. */
76 if (new_fd != action->action.open_action.fd) {
77 if (dup2(new_fd, action->action.open_action.fd)
78 != action->action.open_action.fd)
81 if (close_not_cancel(new_fd) != 0)
87 if (dup2(action->action.dup2_action.fd,
88 action->action.dup2_action.newfd)
89 != action->action.dup2_action.newfd)
98 #define DANGEROUS (POSIX_SPAWN_SETSIGMASK \
99 | POSIX_SPAWN_SETSIGDEF \
100 | POSIX_SPAWN_SETSCHEDPARAM \
101 | POSIX_SPAWN_SETSCHEDULER \
102 | POSIX_SPAWN_SETPGROUP \
103 | POSIX_SPAWN_RESETIDS)
104 inline static bool is_vfork_safe(short int flags)
106 return ((flags & POSIX_SPAWN_USEVFORK) || !(flags & DANGEROUS));
110 /* Spawn a new process executing PATH with the attributes describes in *ATTRP.
111 Before running the process perform the actions described in FILE-ACTIONS. */
113 __spawni(pid_t *pid, const char *file,
114 const posix_spawn_file_actions_t *fa,
115 const posix_spawnattr_t *attrp, char *const argv[],
116 char *const envp[], const char *path)
118 short int flags = attrp ? attrp->__flags : 0;
121 if (is_vfork_safe(flags) && !fa)
124 #ifdef __ARCH_USE_MMU__
141 if (flags & POSIX_SPAWN_SETSIGMASK) {
142 if (sigprocmask(SIG_SETMASK, &attrp->__ss, NULL) != 0)
146 if (flags & POSIX_SPAWN_SETSIGDEF) {
147 /* We have to iterate over all signals. This could possibly be
148 done better but it requires system specific solutions since
149 the sigset_t data type can be very different on different
154 memset(&sa, 0, sizeof(sa));
155 sa.sa_handler = SIG_DFL;
157 for (sig = 1; sig <= _NSIG; ++sig) {
158 if (sigismember(&attrp->__sd, sig)) {
159 if (sigaction(sig, &sa, NULL) != 0)
165 if (flags & POSIX_SPAWN_SETSCHEDULER) {
166 if (sched_setscheduler(0, attrp->__policy, &attrp->__sp) == -1)
168 } else if (flags & POSIX_SPAWN_SETSCHEDPARAM) {
169 if (sched_setparam(0, &attrp->__sp) == -1)
173 if (flags & POSIX_SPAWN_SETPGROUP) {
174 if (setpgid(0, attrp->__pgrp) != 0)
178 if (flags & POSIX_SPAWN_RESETIDS) {
179 if (seteuid(getuid()) || setegid(getgid()))
183 if (fa && execute_file_actions(fa))
186 if (!path || strchr(file, '/')) {
187 execve(file, argv, envp);
194 size_t filelen = strlen(file) + 1;
195 size_t pathlen = strlen(path) + 1;
196 name = alloca(pathlen + filelen);
198 /* Copy the file name at the top. */
199 name = (char *) memcpy(name + pathlen, file, filelen);
201 /* And add the slash. */
208 p = strchrnul(path, ':');
210 /* Two adjacent colons, or a colon at the beginning or the end
211 of `PATH' means to search the current directory. */
215 startp = (char *) memcpy(name - (p - path), path, p - path);
217 execve(startp, argv, envp);
224 /* Those errors indicate the file is missing or not
225 executable by us, in which case we want to just try
226 the next path directory. */
229 /* Some other error means we found an executable file,
230 but something went wrong executing it; return the
231 error to our caller. */
236 } while (*p++ != '\0');
242 /* Spawn a new process executing PATH with the attributes describes in *ATTRP.
243 Before running the process perform the actions described in FILE-ACTIONS. */
244 int posix_spawn (pid_t *pid, const char *path,
245 const posix_spawn_file_actions_t *fa,
246 const posix_spawnattr_t *attrp, char *const argv[],
249 return __spawni(pid, path, fa, attrp, argv, envp, NULL);
252 /* Spawn a new process executing FILE with the attributes describes in *ATTRP.
253 Before running the process perform the actions described in FILE-ACTIONS. */
255 posix_spawnp(pid_t *pid, const char *file,
256 const posix_spawn_file_actions_t *fa,
257 const posix_spawnattr_t *attrp, char *const argv[],
260 const char *path = getenv("PATH");
263 path = ":/bin:/usr/bin";
265 return __spawni(pid, file, fa, attrp, argv, envp, path);