remove obstack support
[uclibc-ng.git] / librt / spawn.c
blob25e3994e12c77fbeb4ca96fe85dfeea4bb3f7e2a
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/>. */
18 #include <errno.h>
19 #include <alloca.h>
20 #include <unistd.h>
21 #include <signal.h>
22 #include <stdbool.h>
23 #include <sys/syscall.h>
24 #include <fcntl.h>
26 #include <sys/resource.h>
27 #include <not-cancel.h>
29 #include <spawn.h>
30 #include "spawn_int.h"
32 /* The Unix standard contains a long explanation of the way to signal
33 an error after the fork() was successful. Since no new wait status
34 was wanted there is no way to signal an error using one of the
35 available methods. The committee chose to signal an error by a
36 normal program exit with the exit code 127. */
37 #define SPAWN_ERROR 127
39 /* Execute file actions.
40 * Returns true on error.
42 inline static bool execute_file_actions(const posix_spawn_file_actions_t *fa)
44 struct rlimit64 fdlimit;
45 bool have_fdlimit = false;
46 int cnt;
48 for (cnt = 0; cnt < fa->__used; ++cnt) {
49 struct __spawn_action *action = &fa->__actions[cnt];
51 switch (action->tag) {
52 case spawn_do_close:
53 if (close_not_cancel(action->action.close_action.fd) != 0) {
54 if (!have_fdlimit) {
55 getrlimit64(RLIMIT_NOFILE, &fdlimit);
56 have_fdlimit = true;
59 /* Only signal errors for file descriptors out of range. */
60 if (0 > action->action.close_action.fd
61 || action->action.close_action.fd >= fdlimit.rlim_cur)
62 /* Signal the error. */
63 return true;
65 break;
67 case spawn_do_open:;
68 int new_fd = open_not_cancel(action->action.open_action.path,
69 action->action.open_action.oflag
70 | O_LARGEFILE,
71 action->action.open_action.mode);
73 if (new_fd == -1)
74 return true;
76 /* Make sure the desired file descriptor is used. */
77 if (new_fd != action->action.open_action.fd) {
78 if (dup2(new_fd, action->action.open_action.fd)
79 != action->action.open_action.fd)
80 return true;
82 if (close_not_cancel(new_fd) != 0)
83 return true;
85 break;
87 case spawn_do_dup2:
88 if (dup2(action->action.dup2_action.fd,
89 action->action.dup2_action.newfd)
90 != action->action.dup2_action.newfd)
91 return true;
92 break;
96 return false;
99 #define DANGEROUS (POSIX_SPAWN_SETSIGMASK \
100 | POSIX_SPAWN_SETSIGDEF \
101 | POSIX_SPAWN_SETSCHEDPARAM \
102 | POSIX_SPAWN_SETSCHEDULER \
103 | POSIX_SPAWN_SETPGROUP \
104 | POSIX_SPAWN_RESETIDS)
105 inline static bool is_vfork_safe(short int flags)
107 return ((flags & POSIX_SPAWN_USEVFORK) || !(flags & DANGEROUS));
111 /* Spawn a new process executing PATH with the attributes describes in *ATTRP.
112 Before running the process perform the actions described in FILE-ACTIONS. */
113 static int
114 __spawni(pid_t *pid, const char *file,
115 const posix_spawn_file_actions_t *fa,
116 const posix_spawnattr_t *attrp, char *const argv[],
117 char *const envp[], const char *path)
119 short int flags = attrp ? attrp->__flags : 0;
121 pid_t new_pid;
122 if (is_vfork_safe(flags) && !fa)
123 new_pid = vfork();
124 else {
125 #ifdef __ARCH_USE_MMU__
126 new_pid = fork();
127 #else
128 return ENOSYS;
129 #endif
132 if (new_pid) {
133 if (new_pid < 0)
134 return errno;
136 if (pid)
137 *pid = new_pid;
139 return 0;
142 if (flags & POSIX_SPAWN_SETSIGMASK) {
143 if (sigprocmask(SIG_SETMASK, &attrp->__ss, NULL) != 0)
144 goto error;
147 if (flags & POSIX_SPAWN_SETSIGDEF) {
148 /* We have to iterate over all signals. This could possibly be
149 done better but it requires system specific solutions since
150 the sigset_t data type can be very different on different
151 architectures. */
152 struct sigaction sa;
153 int sig;
155 memset(&sa, 0, sizeof(sa));
156 sa.sa_handler = SIG_DFL;
158 for (sig = 1; sig <= _NSIG; ++sig) {
159 if (sigismember(&attrp->__sd, sig)) {
160 if (sigaction(sig, &sa, NULL) != 0)
161 goto error;
166 if (flags & POSIX_SPAWN_SETSCHEDULER) {
167 if (sched_setscheduler(0, attrp->__policy, &attrp->__sp) == -1)
168 goto error;
169 } else if (flags & POSIX_SPAWN_SETSCHEDPARAM) {
170 if (sched_setparam(0, &attrp->__sp) == -1)
171 goto error;
174 if (flags & POSIX_SPAWN_SETPGROUP) {
175 if (setpgid(0, attrp->__pgrp) != 0)
176 goto error;
179 if (flags & POSIX_SPAWN_RESETIDS) {
180 if (seteuid(getuid()) || setegid(getgid()))
181 goto error;
184 if (fa && execute_file_actions(fa))
185 goto error;
187 if (!path || strchr(file, '/')) {
188 execve(file, argv, envp);
189 goto error;
193 char *name;
195 size_t filelen = strlen(file) + 1;
196 size_t pathlen = strlen(path) + 1;
197 name = alloca(pathlen + filelen);
199 /* Copy the file name at the top. */
200 name = (char *) memcpy(name + pathlen, file, filelen);
202 /* And add the slash. */
203 *--name = '/';
206 char *p = (char *)path;
207 do {
208 char *startp;
209 path = p;
210 p = strchrnul(path, ':');
212 /* Two adjacent colons, or a colon at the beginning or the end
213 of `PATH' means to search the current directory. */
214 if (p == path)
215 startp = name + 1;
216 else
217 startp = (char *) memcpy(name - (p - path), path, p - path);
219 execve(startp, argv, envp);
221 switch (errno) {
222 case EACCES:
223 case ENOENT:
224 case ESTALE:
225 case ENOTDIR:
226 /* Those errors indicate the file is missing or not
227 executable by us, in which case we want to just try
228 the next path directory. */
229 break;
230 default:
231 /* Some other error means we found an executable file,
232 but something went wrong executing it; return the
233 error to our caller. */
234 goto error;
237 } while (*p++ != '\0');
239 error:
240 _exit(SPAWN_ERROR);
243 /* Spawn a new process executing PATH with the attributes describes in *ATTRP.
244 Before running the process perform the actions described in FILE-ACTIONS. */
245 int posix_spawn (pid_t *pid, const char *path,
246 const posix_spawn_file_actions_t *fa,
247 const posix_spawnattr_t *attrp, char *const argv[],
248 char *const envp[])
250 return __spawni(pid, path, fa, attrp, argv, envp, NULL);
253 /* Spawn a new process executing FILE with the attributes describes in *ATTRP.
254 Before running the process perform the actions described in FILE-ACTIONS. */
256 posix_spawnp(pid_t *pid, const char *file,
257 const posix_spawn_file_actions_t *fa,
258 const posix_spawnattr_t *attrp, char *const argv[],
259 char *const envp[])
261 const char *path = getenv("PATH");
263 if (!path)
264 path = ":/bin:/usr/bin";
266 return __spawni(pid, file, fa, attrp, argv, envp, path);