2 * Copyright (c) 1998 - 2001, 2004 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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
38 #ifdef HAVE_SYS_TYPES_H
39 #include <sys/types.h>
41 #ifdef HAVE_SYS_WAIT_H
52 #define EX_NOTFOUND 127
55 SE_E_UNSPECIFIED on `unspecified' system errors
56 SE_E_FORKFAILED on fork failures
57 SE_E_WAITPIDFAILED on waitpid errors
58 SE_E_EXECTIMEOUT exec timeout
59 0- is return value from subprocess
60 SE_E_NOEXEC if the program couldn't be executed
61 SE_E_NOTFOUND if the program couldn't be found
62 128- is 128 + signal that killed subprocess
64 possible values `func' can return:
65 ((time_t)-2) exit loop w/o killing child and return
66 `exec timeout'/-4 from simple_exec
67 ((time_t)-1) kill child with SIGTERM and wait for child to exit
69 n seconds to next timeout
81 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
82 wait_for_process_timed(pid_t pid
, time_t (*func
)(void *),
83 void *ptr
, time_t timeout
)
85 RETSIGTYPE (*old_func
)(int sig
) = NULL
;
86 unsigned int oldtime
= 0;
92 old_func
= signal(SIGALRM
, sigtimeout
);
93 oldtime
= alarm(timeout
);
99 while(waitpid(pid
, &status
, 0) < 0) {
100 if (errno
!= EINTR
) {
101 ret
= SE_E_WAITPIDFAILED
;
108 timeout
= (*func
)(ptr
);
109 if (timeout
== (time_t)-1) {
112 } else if (timeout
== (time_t)-2) {
113 ret
= SE_E_EXECTIMEOUT
;
118 if(WIFSTOPPED(status
))
120 if(WIFEXITED(status
)) {
121 ret
= WEXITSTATUS(status
);
124 if(WIFSIGNALED(status
)) {
125 ret
= WTERMSIG(status
) + 128;
131 signal(SIGALRM
, old_func
);
137 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
138 wait_for_process(pid_t pid
)
140 return wait_for_process_timed(pid
, NULL
, NULL
, 0);
143 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
144 pipe_execv(FILE **stdin_fd
, FILE **stdout_fd
, FILE **stderr_fd
,
145 const char *file
, ...)
147 int in_fd
[2], out_fd
[2], err_fd
[2];
154 if(stdout_fd
!= NULL
)
156 if(stderr_fd
!= NULL
)
162 argv
= vstrcollect(&ap
);
167 /* close pipes we're not interested in */
170 if(stdout_fd
!= NULL
)
172 if(stderr_fd
!= NULL
)
175 /* pipe everything caller doesn't care about to /dev/null */
177 in_fd
[0] = open(_PATH_DEVNULL
, O_RDONLY
);
178 if(stdout_fd
== NULL
)
179 out_fd
[1] = open(_PATH_DEVNULL
, O_WRONLY
);
180 if(stderr_fd
== NULL
)
181 err_fd
[1] = open(_PATH_DEVNULL
, O_WRONLY
);
183 /* move to proper descriptors */
184 if(in_fd
[0] != STDIN_FILENO
) {
185 dup2(in_fd
[0], STDIN_FILENO
);
188 if(out_fd
[1] != STDOUT_FILENO
) {
189 dup2(out_fd
[1], STDOUT_FILENO
);
192 if(err_fd
[1] != STDERR_FILENO
) {
193 dup2(err_fd
[1], STDERR_FILENO
);
200 exit((errno
== ENOENT
) ? EX_NOTFOUND
: EX_NOEXEC
);
202 if(stdin_fd
!= NULL
) {
206 if(stdout_fd
!= NULL
) {
210 if(stderr_fd
!= NULL
) {
214 return SE_E_FORKFAILED
;
216 if(stdin_fd
!= NULL
) {
218 *stdin_fd
= fdopen(in_fd
[1], "w");
220 if(stdout_fd
!= NULL
) {
222 *stdout_fd
= fdopen(out_fd
[0], "r");
224 if(stderr_fd
!= NULL
) {
226 *stderr_fd
= fdopen(err_fd
[0], "r");
232 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
233 simple_execvp_timed(const char *file
, char *const args
[],
234 time_t (*func
)(void *), void *ptr
, time_t timeout
)
239 return SE_E_FORKFAILED
;
242 exit((errno
== ENOENT
) ? EX_NOTFOUND
: EX_NOEXEC
);
244 return wait_for_process_timed(pid
, func
, ptr
, timeout
);
248 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
249 simple_execvp(const char *file
, char *const args
[])
251 return simple_execvp_timed(file
, args
, NULL
, NULL
, 0);
254 /* gee, I'd like a execvpe */
255 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
256 simple_execve_timed(const char *file
, char *const args
[], char *const envp
[],
257 time_t (*func
)(void *), void *ptr
, time_t timeout
)
262 return SE_E_FORKFAILED
;
264 execve(file
, args
, envp
);
265 exit((errno
== ENOENT
) ? EX_NOTFOUND
: EX_NOEXEC
);
267 return wait_for_process_timed(pid
, func
, ptr
, timeout
);
271 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
272 simple_execve(const char *file
, char *const args
[], char *const envp
[])
274 return simple_execve_timed(file
, args
, envp
, NULL
, NULL
, 0);
277 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
278 simple_execlp(const char *file
, ...)
285 argv
= vstrcollect(&ap
);
288 return SE_E_UNSPECIFIED
;
289 ret
= simple_execvp(file
, argv
);
294 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
295 simple_execle(const char *file
, ... /* ,char *const envp[] */)
303 argv
= vstrcollect(&ap
);
304 envp
= va_arg(ap
, char **);
307 return SE_E_UNSPECIFIED
;
308 ret
= simple_execve(file
, argv
, envp
);