/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- sigtimeout
- wait_for_process_timed
- wait_for_process
- pipe_execv
- simple_execvp_timed
- simple_execvp
- simple_execve_timed
- simple_execve
- simple_execlp
- simple_execle
- simple_execl
1 /*
2 * Copyright (c) 1998 - 2001, 2004 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 RCSID("$Id$");
37 #endif
38
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #ifdef HAVE_SYS_TYPES_H
42 #include <sys/types.h>
43 #endif
44 #ifdef HAVE_SYS_WAIT_H
45 #include <sys/wait.h>
46 #endif
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50 #include <errno.h>
51
52 #include "roken.h"
53
54 #if !HAVE_DECL_ENVIRON
55 extern char **environ;
56 #endif
57
58 #define EX_NOEXEC 126
59 #define EX_NOTFOUND 127
60
61 /* return values:
62 -1 on `unspecified' system errors
63 -2 on fork failures
64 -3 on waitpid errors
65 -4 exec timeout
66 0- is return value from subprocess
67 126 if the program couldn't be executed
68 127 if the program couldn't be found
69 128- is 128 + signal that killed subprocess
70
71 possible values `func' can return:
72 ((time_t)-2) exit loop w/o killing child and return
73 `exec timeout'/-4 from simple_exec
74 ((time_t)-1) kill child with SIGTERM and wait for child to exit
75 0 don't timeout again
76 n seconds to next timeout
77 */
78
79 static int sig_alarm;
80
81 static RETSIGTYPE
82 sigtimeout(int sig)
/* [<][>][^][v][top][bottom][index][help] */
83 {
84 sig_alarm = 1;
85 SIGRETURN(0);
86 }
87
88 int ROKEN_LIB_FUNCTION
89 wait_for_process_timed(pid_t pid, time_t (*func)(void *),
/* [<][>][^][v][top][bottom][index][help] */
90 void *ptr, time_t timeout)
91 {
92 RETSIGTYPE (*old_func)(int sig) = NULL;
93 unsigned int oldtime = 0;
94 int ret;
95
96 sig_alarm = 0;
97
98 if (func) {
99 old_func = signal(SIGALRM, sigtimeout);
100 oldtime = alarm(timeout);
101 }
102
103 while(1) {
104 int status;
105
106 while(waitpid(pid, &status, 0) < 0) {
107 if (errno != EINTR) {
108 ret = -3;
109 goto out;
110 }
111 if (func == NULL)
112 continue;
113 if (sig_alarm == 0)
114 continue;
115 timeout = (*func)(ptr);
116 if (timeout == (time_t)-1) {
117 kill(pid, SIGTERM);
118 continue;
119 } else if (timeout == (time_t)-2) {
120 ret = -4;
121 goto out;
122 }
123 alarm(timeout);
124 }
125 if(WIFSTOPPED(status))
126 continue;
127 if(WIFEXITED(status)) {
128 ret = WEXITSTATUS(status);
129 break;
130 }
131 if(WIFSIGNALED(status)) {
132 ret = WTERMSIG(status) + 128;
133 break;
134 }
135 }
136 out:
137 if (func) {
138 signal(SIGALRM, old_func);
139 alarm(oldtime);
140 }
141 return ret;
142 }
143
144 int ROKEN_LIB_FUNCTION
145 wait_for_process(pid_t pid)
/* [<][>][^][v][top][bottom][index][help] */
146 {
147 return wait_for_process_timed(pid, NULL, NULL, 0);
148 }
149
150 int ROKEN_LIB_FUNCTION
151 pipe_execv(FILE **stdin_fd, FILE **stdout_fd, FILE **stderr_fd,
/* [<][>][^][v][top][bottom][index][help] */
152 const char *file, ...)
153 {
154 int in_fd[2], out_fd[2], err_fd[2];
155 pid_t pid;
156 va_list ap;
157 char **argv;
158
159 if(stdin_fd != NULL)
160 pipe(in_fd);
161 if(stdout_fd != NULL)
162 pipe(out_fd);
163 if(stderr_fd != NULL)
164 pipe(err_fd);
165 pid = fork();
166 switch(pid) {
167 case 0:
168 va_start(ap, file);
169 argv = vstrcollect(&ap);
170 va_end(ap);
171 if(argv == NULL)
172 exit(-1);
173
174 /* close pipes we're not interested in */
175 if(stdin_fd != NULL)
176 close(in_fd[1]);
177 if(stdout_fd != NULL)
178 close(out_fd[0]);
179 if(stderr_fd != NULL)
180 close(err_fd[0]);
181
182 /* pipe everything caller doesn't care about to /dev/null */
183 if(stdin_fd == NULL)
184 in_fd[0] = open(_PATH_DEVNULL, O_RDONLY);
185 if(stdout_fd == NULL)
186 out_fd[1] = open(_PATH_DEVNULL, O_WRONLY);
187 if(stderr_fd == NULL)
188 err_fd[1] = open(_PATH_DEVNULL, O_WRONLY);
189
190 /* move to proper descriptors */
191 if(in_fd[0] != STDIN_FILENO) {
192 dup2(in_fd[0], STDIN_FILENO);
193 close(in_fd[0]);
194 }
195 if(out_fd[1] != STDOUT_FILENO) {
196 dup2(out_fd[1], STDOUT_FILENO);
197 close(out_fd[1]);
198 }
199 if(err_fd[1] != STDERR_FILENO) {
200 dup2(err_fd[1], STDERR_FILENO);
201 close(err_fd[1]);
202 }
203
204 closefrom(3);
205
206 execv(file, argv);
207 exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
208 case -1:
209 if(stdin_fd != NULL) {
210 close(in_fd[0]);
211 close(in_fd[1]);
212 }
213 if(stdout_fd != NULL) {
214 close(out_fd[0]);
215 close(out_fd[1]);
216 }
217 if(stderr_fd != NULL) {
218 close(err_fd[0]);
219 close(err_fd[1]);
220 }
221 return -2;
222 default:
223 if(stdin_fd != NULL) {
224 close(in_fd[0]);
225 *stdin_fd = fdopen(in_fd[1], "w");
226 }
227 if(stdout_fd != NULL) {
228 close(out_fd[1]);
229 *stdout_fd = fdopen(out_fd[0], "r");
230 }
231 if(stderr_fd != NULL) {
232 close(err_fd[1]);
233 *stderr_fd = fdopen(err_fd[0], "r");
234 }
235 }
236 return pid;
237 }
238
239 int ROKEN_LIB_FUNCTION
240 simple_execvp_timed(const char *file, char *const args[],
/* [<][>][^][v][top][bottom][index][help] */
241 time_t (*func)(void *), void *ptr, time_t timeout)
242 {
243 pid_t pid = fork();
244 switch(pid){
245 case -1:
246 return -2;
247 case 0:
248 execvp(file, args);
249 exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
250 default:
251 return wait_for_process_timed(pid, func, ptr, timeout);
252 }
253 }
254
255 int ROKEN_LIB_FUNCTION
256 simple_execvp(const char *file, char *const args[])
/* [<][>][^][v][top][bottom][index][help] */
257 {
258 return simple_execvp_timed(file, args, NULL, NULL, 0);
259 }
260
261 /* gee, I'd like a execvpe */
262 int ROKEN_LIB_FUNCTION
263 simple_execve_timed(const char *file, char *const args[], char *const envp[],
/* [<][>][^][v][top][bottom][index][help] */
264 time_t (*func)(void *), void *ptr, time_t timeout)
265 {
266 pid_t pid = fork();
267 switch(pid){
268 case -1:
269 return -2;
270 case 0:
271 execve(file, args, envp);
272 exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
273 default:
274 return wait_for_process_timed(pid, func, ptr, timeout);
275 }
276 }
277
278 int ROKEN_LIB_FUNCTION
279 simple_execve(const char *file, char *const args[], char *const envp[])
/* [<][>][^][v][top][bottom][index][help] */
280 {
281 return simple_execve_timed(file, args, envp, NULL, NULL, 0);
282 }
283
284 int ROKEN_LIB_FUNCTION
285 simple_execlp(const char *file, ...)
/* [<][>][^][v][top][bottom][index][help] */
286 {
287 va_list ap;
288 char **argv;
289 int ret;
290
291 va_start(ap, file);
292 argv = vstrcollect(&ap);
293 va_end(ap);
294 if(argv == NULL)
295 return -1;
296 ret = simple_execvp(file, argv);
297 free(argv);
298 return ret;
299 }
300
301 int ROKEN_LIB_FUNCTION
302 simple_execle(const char *file, ... /* ,char *const envp[] */)
/* [<][>][^][v][top][bottom][index][help] */
303 {
304 va_list ap;
305 char **argv;
306 char *const* envp;
307 int ret;
308
309 va_start(ap, file);
310 argv = vstrcollect(&ap);
311 envp = va_arg(ap, char **);
312 va_end(ap);
313 if(argv == NULL)
314 return -1;
315 ret = simple_execve(file, argv, envp);
316 free(argv);
317 return ret;
318 }
319
320 int ROKEN_LIB_FUNCTION
321 simple_execl(const char *file, ...)
/* [<][>][^][v][top][bottom][index][help] */
322 {
323 va_list ap;
324 char **argv;
325 int ret;
326
327 va_start(ap, file);
328 argv = vstrcollect(&ap);
329 va_end(ap);
330 if(argv == NULL)
331 return -1;
332 ret = simple_execve(file, argv, environ);
333 free(argv);
334 return ret;
335 }