1 /* $NetBSD: simple_exec.c,v 1.1.1.1 2011/04/13 18:15:43 elric Exp $ */
4 * Copyright (c) 1998 - 2001, 2004 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 #ifdef HAVE_SYS_TYPES_H
41 #include <sys/types.h>
43 #ifdef HAVE_SYS_WAIT_H
51 #include <krb5/roken.h>
54 #define EX_NOTFOUND 127
57 SE_E_UNSPECIFIED on `unspecified' system errors
58 SE_E_FORKFAILED on fork failures
59 SE_E_WAITPIDFAILED on waitpid errors
60 SE_E_EXECTIMEOUT exec timeout
61 0- is return value from subprocess
62 SE_E_NOEXEC if the program couldn't be executed
63 SE_E_NOTFOUND if the program couldn't be found
64 128- is 128 + signal that killed subprocess
66 possible values `func' can return:
67 ((time_t)-2) exit loop w/o killing child and return
68 `exec timeout'/-4 from simple_exec
69 ((time_t)-1) kill child with SIGTERM and wait for child to exit
71 n seconds to next timeout
83 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
84 wait_for_process_timed(pid_t pid
, time_t (*func
)(void *),
85 void *ptr
, time_t timeout
)
87 RETSIGTYPE (*old_func
)(int sig
) = NULL
;
88 unsigned int oldtime
= 0;
94 old_func
= signal(SIGALRM
, sigtimeout
);
95 oldtime
= alarm(timeout
);
101 while(waitpid(pid
, &status
, 0) < 0) {
102 if (errno
!= EINTR
) {
103 ret
= SE_E_WAITPIDFAILED
;
110 timeout
= (*func
)(ptr
);
111 if (timeout
== (time_t)-1) {
114 } else if (timeout
== (time_t)-2) {
115 ret
= SE_E_EXECTIMEOUT
;
120 if(WIFSTOPPED(status
))
122 if(WIFEXITED(status
)) {
123 ret
= WEXITSTATUS(status
);
126 if(WIFSIGNALED(status
)) {
127 ret
= WTERMSIG(status
) + 128;
133 signal(SIGALRM
, old_func
);
139 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
140 wait_for_process(pid_t pid
)
142 return wait_for_process_timed(pid
, NULL
, NULL
, 0);
145 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
146 pipe_execv(FILE **stdin_fd
, FILE **stdout_fd
, FILE **stderr_fd
,
147 const char *file
, ...)
149 int in_fd
[2], out_fd
[2], err_fd
[2];
156 if(stdout_fd
!= NULL
)
158 if(stderr_fd
!= NULL
)
164 argv
= vstrcollect(&ap
);
169 /* close pipes we're not interested in */
172 if(stdout_fd
!= NULL
)
174 if(stderr_fd
!= NULL
)
177 /* pipe everything caller doesn't care about to /dev/null */
179 in_fd
[0] = open(_PATH_DEVNULL
, O_RDONLY
);
180 if(stdout_fd
== NULL
)
181 out_fd
[1] = open(_PATH_DEVNULL
, O_WRONLY
);
182 if(stderr_fd
== NULL
)
183 err_fd
[1] = open(_PATH_DEVNULL
, O_WRONLY
);
185 /* move to proper descriptors */
186 if(in_fd
[0] != STDIN_FILENO
) {
187 dup2(in_fd
[0], STDIN_FILENO
);
190 if(out_fd
[1] != STDOUT_FILENO
) {
191 dup2(out_fd
[1], STDOUT_FILENO
);
194 if(err_fd
[1] != STDERR_FILENO
) {
195 dup2(err_fd
[1], STDERR_FILENO
);
202 exit((errno
== ENOENT
) ? EX_NOTFOUND
: EX_NOEXEC
);
204 if(stdin_fd
!= NULL
) {
208 if(stdout_fd
!= NULL
) {
212 if(stderr_fd
!= NULL
) {
216 return SE_E_FORKFAILED
;
218 if(stdin_fd
!= NULL
) {
220 *stdin_fd
= fdopen(in_fd
[1], "w");
222 if(stdout_fd
!= NULL
) {
224 *stdout_fd
= fdopen(out_fd
[0], "r");
226 if(stderr_fd
!= NULL
) {
228 *stderr_fd
= fdopen(err_fd
[0], "r");
234 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
235 simple_execvp_timed(const char *file
, char *const args
[],
236 time_t (*func
)(void *), void *ptr
, time_t timeout
)
241 return SE_E_FORKFAILED
;
244 exit((errno
== ENOENT
) ? EX_NOTFOUND
: EX_NOEXEC
);
246 return wait_for_process_timed(pid
, func
, ptr
, timeout
);
250 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
251 simple_execvp(const char *file
, char *const args
[])
253 return simple_execvp_timed(file
, args
, NULL
, NULL
, 0);
256 /* gee, I'd like a execvpe */
257 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
258 simple_execve_timed(const char *file
, char *const args
[], char *const envp
[],
259 time_t (*func
)(void *), void *ptr
, time_t timeout
)
264 return SE_E_FORKFAILED
;
266 execve(file
, args
, envp
);
267 exit((errno
== ENOENT
) ? EX_NOTFOUND
: EX_NOEXEC
);
269 return wait_for_process_timed(pid
, func
, ptr
, timeout
);
273 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
274 simple_execve(const char *file
, char *const args
[], char *const envp
[])
276 return simple_execve_timed(file
, args
, envp
, NULL
, NULL
, 0);
279 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
280 simple_execlp(const char *file
, ...)
287 argv
= vstrcollect(&ap
);
290 return SE_E_UNSPECIFIED
;
291 ret
= simple_execvp(file
, argv
);
296 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
297 simple_execle(const char *file
, ... /* ,char *const envp[] */)
305 argv
= vstrcollect(&ap
);
306 envp
= va_arg(ap
, char **);
309 return SE_E_UNSPECIFIED
;
310 ret
= simple_execve(file
, argv
, envp
);