OSDN Git Service

Do define some IPv6 related symbols even with IPv6 disabled
[uclinux-h8/uclibc-ng.git] / librt / spawn.c
1 /* Copyright (C) 2000, 2011 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
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.
8
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.
13
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/>.  */
17
18 #include <errno.h>
19 #include <alloca.h>
20 #include <unistd.h>
21 #include <signal.h>
22 #include <stdbool.h>
23 #include <fcntl.h>
24
25 #include <sys/resource.h>
26 #include <not-cancel.h>
27
28 #include <spawn.h>
29 #include "spawn_int.h"
30
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
37
38 /* Execute file actions.
39  * Returns true on error.
40  */
41 inline static bool execute_file_actions(const posix_spawn_file_actions_t *fa)
42 {
43         struct rlimit64 fdlimit;
44         bool have_fdlimit = false;
45         int cnt;
46
47         for (cnt = 0; cnt < fa->__used; ++cnt) {
48                 struct __spawn_action *action = &fa->__actions[cnt];
49
50                 switch (action->tag) {
51                 case spawn_do_close:
52                         if (close_not_cancel(action->action.close_action.fd) != 0) {
53                                 if (!have_fdlimit) {
54                                         getrlimit64(RLIMIT_NOFILE, &fdlimit);
55                                         have_fdlimit = true;
56                                 }
57
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.  */
62                                         return true;
63                         }
64                         break;
65
66                 case spawn_do_open:;
67                         int new_fd = open_not_cancel(action->action.open_action.path,
68                                                      action->action.open_action.oflag
69                                                      | O_LARGEFILE,
70                                                      action->action.open_action.mode);
71
72                         if (new_fd == -1)
73                                 return true;
74
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)
79                                         return true;
80
81                                 if (close_not_cancel(new_fd) != 0)
82                                         return true;
83                         }
84                         break;
85
86                 case spawn_do_dup2:
87                         if (dup2(action->action.dup2_action.fd,
88                                    action->action.dup2_action.newfd)
89                             != action->action.dup2_action.newfd)
90                                 return true;
91                         break;
92                 }
93         }
94
95         return false;
96 }
97
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)
105 {
106         return ((flags & POSIX_SPAWN_USEVFORK) || !(flags & DANGEROUS));
107 }
108
109
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. */
112 static int
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)
117 {
118         short int flags = attrp ? attrp->__flags : 0;
119
120         pid_t new_pid;
121         if (is_vfork_safe(flags) && !fa)
122                 new_pid = vfork();
123         else {
124 #ifdef __ARCH_USE_MMU__
125                 new_pid = fork();
126 #else
127                 return ENOSYS;
128 #endif
129         }
130
131         if (new_pid) {
132                 if (new_pid < 0)
133                         return errno;
134
135                 if (pid)
136                         *pid = new_pid;
137
138                 return 0;
139         }
140
141         if (flags & POSIX_SPAWN_SETSIGMASK) {
142                 if (sigprocmask(SIG_SETMASK, &attrp->__ss, NULL) != 0)
143                         goto error;
144         }
145
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
150                    architectures.  */
151                 struct sigaction sa;
152                 int sig;
153
154                 memset(&sa, 0, sizeof(sa));
155                 sa.sa_handler = SIG_DFL;
156
157                 for (sig = 1; sig <= _NSIG; ++sig) {
158                         if (sigismember(&attrp->__sd, sig)) {
159                                 if (sigaction(sig, &sa, NULL) != 0)
160                                         goto error;
161                         }
162                 }
163         }
164
165         if (flags & POSIX_SPAWN_SETSCHEDULER) {
166                 if (sched_setscheduler(0, attrp->__policy, &attrp->__sp) == -1)
167                         goto error;
168         } else if (flags & POSIX_SPAWN_SETSCHEDPARAM) {
169                 if (sched_setparam(0, &attrp->__sp) == -1)
170                         goto error;
171         }
172
173         if (flags & POSIX_SPAWN_SETPGROUP) {
174                 if (setpgid(0, attrp->__pgrp) != 0)
175                         goto error;
176         }
177
178         if (flags & POSIX_SPAWN_RESETIDS) {
179                 if (seteuid(getuid()) || setegid(getgid()))
180                         goto error;
181         }
182
183         if (fa && execute_file_actions(fa))
184                 goto error;
185
186         if (!path || strchr(file, '/')) {
187                 execve(file, argv, envp);
188                 goto error;
189         }
190
191
192         char *name;
193         {
194                 size_t filelen = strlen(file) + 1;
195                 size_t pathlen = strlen(path) + 1;
196                 name = alloca(pathlen + filelen);
197
198                 /* Copy the file name at the top. */
199                 name = (char *) memcpy(name + pathlen, file, filelen);
200
201                 /* And add the slash.  */
202                 *--name = '/';
203         }
204
205         char *p;
206         do {
207                 char *startp;
208                 p = strchrnul(path, ':');
209
210                 /* Two adjacent colons, or a colon at the beginning or the end
211                    of `PATH' means to search the current directory.  */
212                 if (p == path)
213                         startp = name + 1;
214                 else
215                         startp = (char *) memcpy(name - (p - path), path, p - path);
216
217                 execve(startp, argv, envp);
218
219                 switch (errno) {
220                 case EACCES:
221                 case ENOENT:
222                 case ESTALE:
223                 case ENOTDIR:
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. */
227                         break;
228                 default:
229                         /* Some other error means we found an executable file,
230                            but something went wrong executing it; return the
231                            error to our caller. */
232                         goto error;
233                 }
234
235                 path = p;
236         } while (*p++ != '\0');
237
238 error:
239         _exit(SPAWN_ERROR);
240 }
241
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[],
247                char *const envp[])
248 {
249         return __spawni(pid, path, fa, attrp, argv, envp, NULL);
250 }
251
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. */
254 int
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[],
258              char *const envp[])
259 {
260         const char *path = getenv("PATH");
261
262         if (!path)
263                 path = ":/bin:/usr/bin";
264
265         return __spawni(pid, file, fa, attrp, argv, envp, path);
266 }