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/>. */
23 #include <sys/syscall.h>
26 #include <sys/resource.h>
27 #include <not-cancel.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;
48 for (cnt
= 0; cnt
< fa
->__used
; ++cnt
) {
49 struct __spawn_action
*action
= &fa
->__actions
[cnt
];
51 switch (action
->tag
) {
53 if (close_not_cancel(action
->action
.close_action
.fd
) != 0) {
55 getrlimit64(RLIMIT_NOFILE
, &fdlimit
);
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. */
68 int new_fd
= open_not_cancel(action
->action
.open_action
.path
,
69 action
->action
.open_action
.oflag
71 action
->action
.open_action
.mode
);
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
)
82 if (close_not_cancel(new_fd
) != 0)
88 if (dup2(action
->action
.dup2_action
.fd
,
89 action
->action
.dup2_action
.newfd
)
90 != action
->action
.dup2_action
.newfd
)
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. */
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;
122 if (is_vfork_safe(flags
) && !fa
)
125 #ifdef __ARCH_USE_MMU__
142 if (flags
& POSIX_SPAWN_SETSIGMASK
) {
143 if (sigprocmask(SIG_SETMASK
, &attrp
->__ss
, NULL
) != 0)
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
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)
166 if (flags
& POSIX_SPAWN_SETSCHEDULER
) {
167 if (sched_setscheduler(0, attrp
->__policy
, &attrp
->__sp
) == -1)
169 } else if (flags
& POSIX_SPAWN_SETSCHEDPARAM
) {
170 if (sched_setparam(0, &attrp
->__sp
) == -1)
174 if (flags
& POSIX_SPAWN_SETPGROUP
) {
175 if (setpgid(0, attrp
->__pgrp
) != 0)
179 if (flags
& POSIX_SPAWN_RESETIDS
) {
180 if (seteuid(getuid()) || setegid(getgid()))
184 if (fa
&& execute_file_actions(fa
))
187 if (!path
|| strchr(file
, '/')) {
188 execve(file
, argv
, envp
);
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. */
206 char *p
= (char *)path
;
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. */
217 startp
= (char *) memcpy(name
- (p
- path
), path
, p
- path
);
219 execve(startp
, argv
, envp
);
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. */
231 /* Some other error means we found an executable file,
232 but something went wrong executing it; return the
233 error to our caller. */
237 } while (*p
++ != '\0');
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
[],
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
[],
261 const char *path
= getenv("PATH");
264 path
= ":/bin:/usr/bin";
266 return __spawni(pid
, file
, fa
, attrp
, argv
, envp
, path
);