1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov * Copyright (c) 1998 - 2001, 2004 Kungliga Tekniska Högskolan
3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray * All rights reserved.
5b528cefcSMark Murray *
6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray * modification, are permitted provided that the following conditions
8b528cefcSMark Murray * are met:
9b528cefcSMark Murray *
10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray *
13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray * documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray *
17b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray * may be used to endorse or promote products derived from this software
19b528cefcSMark Murray * without specific prior written permission.
20b528cefcSMark Murray *
21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray * SUCH DAMAGE.
32b528cefcSMark Murray */
33b528cefcSMark Murray
34b528cefcSMark Murray #include <config.h>
35b528cefcSMark Murray
36b528cefcSMark Murray #include <stdarg.h>
37b528cefcSMark Murray #include <stdlib.h>
38b528cefcSMark Murray #ifdef HAVE_SYS_TYPES_H
39b528cefcSMark Murray #include <sys/types.h>
40b528cefcSMark Murray #endif
41b528cefcSMark Murray #ifdef HAVE_SYS_WAIT_H
42b528cefcSMark Murray #include <sys/wait.h>
43b528cefcSMark Murray #endif
44b528cefcSMark Murray #ifdef HAVE_UNISTD_H
45b528cefcSMark Murray #include <unistd.h>
46b528cefcSMark Murray #endif
47b528cefcSMark Murray #include <errno.h>
48b528cefcSMark Murray
49c19800e8SDoug Rabson #include "roken.h"
50b528cefcSMark Murray
51b528cefcSMark Murray #define EX_NOEXEC 126
52b528cefcSMark Murray #define EX_NOTFOUND 127
53b528cefcSMark Murray
54b528cefcSMark Murray /* return values:
55*ae771770SStanislav Sedov SE_E_UNSPECIFIED on `unspecified' system errors
56*ae771770SStanislav Sedov SE_E_FORKFAILED on fork failures
57*ae771770SStanislav Sedov SE_E_WAITPIDFAILED on waitpid errors
58*ae771770SStanislav Sedov SE_E_EXECTIMEOUT exec timeout
59b528cefcSMark Murray 0- is return value from subprocess
60*ae771770SStanislav Sedov SE_E_NOEXEC if the program couldn't be executed
61*ae771770SStanislav Sedov SE_E_NOTFOUND if the program couldn't be found
62b528cefcSMark Murray 128- is 128 + signal that killed subprocess
63c19800e8SDoug Rabson
64c19800e8SDoug Rabson possible values `func' can return:
65c19800e8SDoug Rabson ((time_t)-2) exit loop w/o killing child and return
66c19800e8SDoug Rabson `exec timeout'/-4 from simple_exec
67c19800e8SDoug Rabson ((time_t)-1) kill child with SIGTERM and wait for child to exit
68c19800e8SDoug Rabson 0 don't timeout again
69c19800e8SDoug Rabson n seconds to next timeout
70b528cefcSMark Murray */
71b528cefcSMark Murray
72c19800e8SDoug Rabson static int sig_alarm;
73c19800e8SDoug Rabson
74c19800e8SDoug Rabson static RETSIGTYPE
sigtimeout(int sig)75c19800e8SDoug Rabson sigtimeout(int sig)
76b528cefcSMark Murray {
77c19800e8SDoug Rabson sig_alarm = 1;
78c19800e8SDoug Rabson SIGRETURN(0);
79c19800e8SDoug Rabson }
80c19800e8SDoug Rabson
81*ae771770SStanislav Sedov ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
wait_for_process_timed(pid_t pid,time_t (* func)(void *),void * ptr,time_t timeout)82c19800e8SDoug Rabson wait_for_process_timed(pid_t pid, time_t (*func)(void *),
83c19800e8SDoug Rabson void *ptr, time_t timeout)
84c19800e8SDoug Rabson {
85c19800e8SDoug Rabson RETSIGTYPE (*old_func)(int sig) = NULL;
86c19800e8SDoug Rabson unsigned int oldtime = 0;
87c19800e8SDoug Rabson int ret;
88c19800e8SDoug Rabson
89c19800e8SDoug Rabson sig_alarm = 0;
90c19800e8SDoug Rabson
91c19800e8SDoug Rabson if (func) {
92c19800e8SDoug Rabson old_func = signal(SIGALRM, sigtimeout);
93c19800e8SDoug Rabson oldtime = alarm(timeout);
94c19800e8SDoug Rabson }
95c19800e8SDoug Rabson
96b528cefcSMark Murray while(1) {
97b528cefcSMark Murray int status;
98b528cefcSMark Murray
99c19800e8SDoug Rabson while(waitpid(pid, &status, 0) < 0) {
100c19800e8SDoug Rabson if (errno != EINTR) {
101*ae771770SStanislav Sedov ret = SE_E_WAITPIDFAILED;
102c19800e8SDoug Rabson goto out;
103c19800e8SDoug Rabson }
104c19800e8SDoug Rabson if (func == NULL)
105c19800e8SDoug Rabson continue;
106c19800e8SDoug Rabson if (sig_alarm == 0)
107c19800e8SDoug Rabson continue;
108c19800e8SDoug Rabson timeout = (*func)(ptr);
109c19800e8SDoug Rabson if (timeout == (time_t)-1) {
110c19800e8SDoug Rabson kill(pid, SIGTERM);
111c19800e8SDoug Rabson continue;
112c19800e8SDoug Rabson } else if (timeout == (time_t)-2) {
113*ae771770SStanislav Sedov ret = SE_E_EXECTIMEOUT;
114c19800e8SDoug Rabson goto out;
115c19800e8SDoug Rabson }
116c19800e8SDoug Rabson alarm(timeout);
117c19800e8SDoug Rabson }
118b528cefcSMark Murray if(WIFSTOPPED(status))
119b528cefcSMark Murray continue;
120c19800e8SDoug Rabson if(WIFEXITED(status)) {
121c19800e8SDoug Rabson ret = WEXITSTATUS(status);
122c19800e8SDoug Rabson break;
123b528cefcSMark Murray }
124c19800e8SDoug Rabson if(WIFSIGNALED(status)) {
125c19800e8SDoug Rabson ret = WTERMSIG(status) + 128;
126c19800e8SDoug Rabson break;
127c19800e8SDoug Rabson }
128c19800e8SDoug Rabson }
129c19800e8SDoug Rabson out:
130c19800e8SDoug Rabson if (func) {
131c19800e8SDoug Rabson signal(SIGALRM, old_func);
132c19800e8SDoug Rabson alarm(oldtime);
133c19800e8SDoug Rabson }
134c19800e8SDoug Rabson return ret;
135b528cefcSMark Murray }
136b528cefcSMark Murray
137*ae771770SStanislav Sedov ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
wait_for_process(pid_t pid)138c19800e8SDoug Rabson wait_for_process(pid_t pid)
139c19800e8SDoug Rabson {
140c19800e8SDoug Rabson return wait_for_process_timed(pid, NULL, NULL, 0);
141c19800e8SDoug Rabson }
142c19800e8SDoug Rabson
143*ae771770SStanislav Sedov ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
pipe_execv(FILE ** stdin_fd,FILE ** stdout_fd,FILE ** stderr_fd,const char * file,...)1444137ff4cSJacques Vidrine pipe_execv(FILE **stdin_fd, FILE **stdout_fd, FILE **stderr_fd,
1454137ff4cSJacques Vidrine const char *file, ...)
1464137ff4cSJacques Vidrine {
1474137ff4cSJacques Vidrine int in_fd[2], out_fd[2], err_fd[2];
1484137ff4cSJacques Vidrine pid_t pid;
1494137ff4cSJacques Vidrine va_list ap;
1504137ff4cSJacques Vidrine char **argv;
1514137ff4cSJacques Vidrine
1524137ff4cSJacques Vidrine if(stdin_fd != NULL)
1534137ff4cSJacques Vidrine pipe(in_fd);
1544137ff4cSJacques Vidrine if(stdout_fd != NULL)
1554137ff4cSJacques Vidrine pipe(out_fd);
1564137ff4cSJacques Vidrine if(stderr_fd != NULL)
1574137ff4cSJacques Vidrine pipe(err_fd);
1584137ff4cSJacques Vidrine pid = fork();
1594137ff4cSJacques Vidrine switch(pid) {
1604137ff4cSJacques Vidrine case 0:
1614137ff4cSJacques Vidrine va_start(ap, file);
1624137ff4cSJacques Vidrine argv = vstrcollect(&ap);
1634137ff4cSJacques Vidrine va_end(ap);
1644137ff4cSJacques Vidrine if(argv == NULL)
1654137ff4cSJacques Vidrine exit(-1);
1664137ff4cSJacques Vidrine
1674137ff4cSJacques Vidrine /* close pipes we're not interested in */
1684137ff4cSJacques Vidrine if(stdin_fd != NULL)
1694137ff4cSJacques Vidrine close(in_fd[1]);
1704137ff4cSJacques Vidrine if(stdout_fd != NULL)
1714137ff4cSJacques Vidrine close(out_fd[0]);
1724137ff4cSJacques Vidrine if(stderr_fd != NULL)
1734137ff4cSJacques Vidrine close(err_fd[0]);
1744137ff4cSJacques Vidrine
1754137ff4cSJacques Vidrine /* pipe everything caller doesn't care about to /dev/null */
1764137ff4cSJacques Vidrine if(stdin_fd == NULL)
1774137ff4cSJacques Vidrine in_fd[0] = open(_PATH_DEVNULL, O_RDONLY);
1784137ff4cSJacques Vidrine if(stdout_fd == NULL)
1794137ff4cSJacques Vidrine out_fd[1] = open(_PATH_DEVNULL, O_WRONLY);
1804137ff4cSJacques Vidrine if(stderr_fd == NULL)
1814137ff4cSJacques Vidrine err_fd[1] = open(_PATH_DEVNULL, O_WRONLY);
1824137ff4cSJacques Vidrine
1834137ff4cSJacques Vidrine /* move to proper descriptors */
1844137ff4cSJacques Vidrine if(in_fd[0] != STDIN_FILENO) {
1854137ff4cSJacques Vidrine dup2(in_fd[0], STDIN_FILENO);
1864137ff4cSJacques Vidrine close(in_fd[0]);
1874137ff4cSJacques Vidrine }
1884137ff4cSJacques Vidrine if(out_fd[1] != STDOUT_FILENO) {
1894137ff4cSJacques Vidrine dup2(out_fd[1], STDOUT_FILENO);
1904137ff4cSJacques Vidrine close(out_fd[1]);
1914137ff4cSJacques Vidrine }
1924137ff4cSJacques Vidrine if(err_fd[1] != STDERR_FILENO) {
1934137ff4cSJacques Vidrine dup2(err_fd[1], STDERR_FILENO);
1944137ff4cSJacques Vidrine close(err_fd[1]);
1954137ff4cSJacques Vidrine }
1964137ff4cSJacques Vidrine
197c19800e8SDoug Rabson closefrom(3);
198c19800e8SDoug Rabson
1994137ff4cSJacques Vidrine execv(file, argv);
2004137ff4cSJacques Vidrine exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
2014137ff4cSJacques Vidrine case -1:
2024137ff4cSJacques Vidrine if(stdin_fd != NULL) {
2034137ff4cSJacques Vidrine close(in_fd[0]);
2044137ff4cSJacques Vidrine close(in_fd[1]);
2054137ff4cSJacques Vidrine }
2064137ff4cSJacques Vidrine if(stdout_fd != NULL) {
2074137ff4cSJacques Vidrine close(out_fd[0]);
2084137ff4cSJacques Vidrine close(out_fd[1]);
2094137ff4cSJacques Vidrine }
2104137ff4cSJacques Vidrine if(stderr_fd != NULL) {
2114137ff4cSJacques Vidrine close(err_fd[0]);
2124137ff4cSJacques Vidrine close(err_fd[1]);
2134137ff4cSJacques Vidrine }
214*ae771770SStanislav Sedov return SE_E_FORKFAILED;
2154137ff4cSJacques Vidrine default:
2164137ff4cSJacques Vidrine if(stdin_fd != NULL) {
2174137ff4cSJacques Vidrine close(in_fd[0]);
2184137ff4cSJacques Vidrine *stdin_fd = fdopen(in_fd[1], "w");
2194137ff4cSJacques Vidrine }
2204137ff4cSJacques Vidrine if(stdout_fd != NULL) {
2214137ff4cSJacques Vidrine close(out_fd[1]);
2224137ff4cSJacques Vidrine *stdout_fd = fdopen(out_fd[0], "r");
2234137ff4cSJacques Vidrine }
2244137ff4cSJacques Vidrine if(stderr_fd != NULL) {
2254137ff4cSJacques Vidrine close(err_fd[1]);
2264137ff4cSJacques Vidrine *stderr_fd = fdopen(err_fd[0], "r");
2274137ff4cSJacques Vidrine }
2284137ff4cSJacques Vidrine }
2294137ff4cSJacques Vidrine return pid;
2304137ff4cSJacques Vidrine }
2314137ff4cSJacques Vidrine
232*ae771770SStanislav Sedov ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
simple_execvp_timed(const char * file,char * const args[],time_t (* func)(void *),void * ptr,time_t timeout)233c19800e8SDoug Rabson simple_execvp_timed(const char *file, char *const args[],
234c19800e8SDoug Rabson time_t (*func)(void *), void *ptr, time_t timeout)
235b528cefcSMark Murray {
236b528cefcSMark Murray pid_t pid = fork();
237b528cefcSMark Murray switch(pid){
238b528cefcSMark Murray case -1:
239*ae771770SStanislav Sedov return SE_E_FORKFAILED;
240b528cefcSMark Murray case 0:
241b528cefcSMark Murray execvp(file, args);
242b528cefcSMark Murray exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
243b528cefcSMark Murray default:
244c19800e8SDoug Rabson return wait_for_process_timed(pid, func, ptr, timeout);
245b528cefcSMark Murray }
246b528cefcSMark Murray }
247b528cefcSMark Murray
248*ae771770SStanislav Sedov ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
simple_execvp(const char * file,char * const args[])249c19800e8SDoug Rabson simple_execvp(const char *file, char *const args[])
250c19800e8SDoug Rabson {
251c19800e8SDoug Rabson return simple_execvp_timed(file, args, NULL, NULL, 0);
252c19800e8SDoug Rabson }
253c19800e8SDoug Rabson
254b528cefcSMark Murray /* gee, I'd like a execvpe */
255*ae771770SStanislav Sedov ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
simple_execve_timed(const char * file,char * const args[],char * const envp[],time_t (* func)(void *),void * ptr,time_t timeout)256c19800e8SDoug Rabson simple_execve_timed(const char *file, char *const args[], char *const envp[],
257c19800e8SDoug Rabson time_t (*func)(void *), void *ptr, time_t timeout)
258b528cefcSMark Murray {
259b528cefcSMark Murray pid_t pid = fork();
260b528cefcSMark Murray switch(pid){
261b528cefcSMark Murray case -1:
262*ae771770SStanislav Sedov return SE_E_FORKFAILED;
263b528cefcSMark Murray case 0:
264b528cefcSMark Murray execve(file, args, envp);
265b528cefcSMark Murray exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
266b528cefcSMark Murray default:
267c19800e8SDoug Rabson return wait_for_process_timed(pid, func, ptr, timeout);
268b528cefcSMark Murray }
269b528cefcSMark Murray }
270b528cefcSMark Murray
271*ae771770SStanislav Sedov ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
simple_execve(const char * file,char * const args[],char * const envp[])272c19800e8SDoug Rabson simple_execve(const char *file, char *const args[], char *const envp[])
273c19800e8SDoug Rabson {
274c19800e8SDoug Rabson return simple_execve_timed(file, args, envp, NULL, NULL, 0);
275c19800e8SDoug Rabson }
276c19800e8SDoug Rabson
277*ae771770SStanislav Sedov ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
simple_execlp(const char * file,...)278b528cefcSMark Murray simple_execlp(const char *file, ...)
279b528cefcSMark Murray {
280b528cefcSMark Murray va_list ap;
281b528cefcSMark Murray char **argv;
282b528cefcSMark Murray int ret;
283b528cefcSMark Murray
284b528cefcSMark Murray va_start(ap, file);
28513e3f4d6SMark Murray argv = vstrcollect(&ap);
286b528cefcSMark Murray va_end(ap);
287b528cefcSMark Murray if(argv == NULL)
288*ae771770SStanislav Sedov return SE_E_UNSPECIFIED;
289b528cefcSMark Murray ret = simple_execvp(file, argv);
290b528cefcSMark Murray free(argv);
291b528cefcSMark Murray return ret;
292b528cefcSMark Murray }
293b528cefcSMark Murray
294*ae771770SStanislav Sedov ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
simple_execle(const char * file,...)295b528cefcSMark Murray simple_execle(const char *file, ... /* ,char *const envp[] */)
296b528cefcSMark Murray {
297b528cefcSMark Murray va_list ap;
298b528cefcSMark Murray char **argv;
299b528cefcSMark Murray char *const* envp;
300b528cefcSMark Murray int ret;
301b528cefcSMark Murray
302b528cefcSMark Murray va_start(ap, file);
30313e3f4d6SMark Murray argv = vstrcollect(&ap);
304b528cefcSMark Murray envp = va_arg(ap, char **);
305b528cefcSMark Murray va_end(ap);
306b528cefcSMark Murray if(argv == NULL)
307*ae771770SStanislav Sedov return SE_E_UNSPECIFIED;
308b528cefcSMark Murray ret = simple_execve(file, argv, envp);
309b528cefcSMark Murray free(argv);
310b528cefcSMark Murray return ret;
311b528cefcSMark Murray }
312