155682Smarkm/* 2178825Sdfr * Copyright (c) 1998 - 2001, 2004 Kungliga Tekniska H�gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#ifdef HAVE_CONFIG_H 3555682Smarkm#include <config.h> 36178825SdfrRCSID("$Id: simple_exec.c 21005 2007-06-08 01:54:35Z lha $"); 3755682Smarkm#endif 3855682Smarkm 3955682Smarkm#include <stdarg.h> 4055682Smarkm#include <stdlib.h> 4155682Smarkm#ifdef HAVE_SYS_TYPES_H 4255682Smarkm#include <sys/types.h> 4355682Smarkm#endif 4455682Smarkm#ifdef HAVE_SYS_WAIT_H 4555682Smarkm#include <sys/wait.h> 4655682Smarkm#endif 4755682Smarkm#ifdef HAVE_UNISTD_H 4855682Smarkm#include <unistd.h> 4955682Smarkm#endif 5055682Smarkm#include <errno.h> 5155682Smarkm 52178825Sdfr#include "roken.h" 5355682Smarkm 5455682Smarkm#define EX_NOEXEC 126 5555682Smarkm#define EX_NOTFOUND 127 5655682Smarkm 5755682Smarkm/* return values: 5855682Smarkm -1 on `unspecified' system errors 5955682Smarkm -2 on fork failures 6055682Smarkm -3 on waitpid errors 61178825Sdfr -4 exec timeout 6255682Smarkm 0- is return value from subprocess 6355682Smarkm 126 if the program couldn't be executed 6455682Smarkm 127 if the program couldn't be found 6555682Smarkm 128- is 128 + signal that killed subprocess 66178825Sdfr 67178825Sdfr possible values `func' can return: 68178825Sdfr ((time_t)-2) exit loop w/o killing child and return 69178825Sdfr `exec timeout'/-4 from simple_exec 70178825Sdfr ((time_t)-1) kill child with SIGTERM and wait for child to exit 71178825Sdfr 0 don't timeout again 72178825Sdfr n seconds to next timeout 7355682Smarkm */ 7455682Smarkm 75178825Sdfrstatic int sig_alarm; 76178825Sdfr 77178825Sdfrstatic RETSIGTYPE 78178825Sdfrsigtimeout(int sig) 7955682Smarkm{ 80178825Sdfr sig_alarm = 1; 81178825Sdfr SIGRETURN(0); 82178825Sdfr} 83178825Sdfr 84178825Sdfrint ROKEN_LIB_FUNCTION 85178825Sdfrwait_for_process_timed(pid_t pid, time_t (*func)(void *), 86178825Sdfr void *ptr, time_t timeout) 87178825Sdfr{ 88178825Sdfr RETSIGTYPE (*old_func)(int sig) = NULL; 89178825Sdfr unsigned int oldtime = 0; 90178825Sdfr int ret; 91178825Sdfr 92178825Sdfr sig_alarm = 0; 93178825Sdfr 94178825Sdfr if (func) { 95178825Sdfr old_func = signal(SIGALRM, sigtimeout); 96178825Sdfr oldtime = alarm(timeout); 97178825Sdfr } 98178825Sdfr 9955682Smarkm while(1) { 10055682Smarkm int status; 10155682Smarkm 102178825Sdfr while(waitpid(pid, &status, 0) < 0) { 103178825Sdfr if (errno != EINTR) { 104178825Sdfr ret = -3; 105178825Sdfr goto out; 106178825Sdfr } 107178825Sdfr if (func == NULL) 108178825Sdfr continue; 109178825Sdfr if (sig_alarm == 0) 110178825Sdfr continue; 111178825Sdfr timeout = (*func)(ptr); 112178825Sdfr if (timeout == (time_t)-1) { 113178825Sdfr kill(pid, SIGTERM); 114178825Sdfr continue; 115178825Sdfr } else if (timeout == (time_t)-2) { 116178825Sdfr ret = -4; 117178825Sdfr goto out; 118178825Sdfr } 119178825Sdfr alarm(timeout); 120178825Sdfr } 12155682Smarkm if(WIFSTOPPED(status)) 12255682Smarkm continue; 123178825Sdfr if(WIFEXITED(status)) { 124178825Sdfr ret = WEXITSTATUS(status); 125178825Sdfr break; 126178825Sdfr } 127178825Sdfr if(WIFSIGNALED(status)) { 128178825Sdfr ret = WTERMSIG(status) + 128; 129178825Sdfr break; 130178825Sdfr } 13155682Smarkm } 132178825Sdfr out: 133178825Sdfr if (func) { 134178825Sdfr signal(SIGALRM, old_func); 135178825Sdfr alarm(oldtime); 136178825Sdfr } 137178825Sdfr return ret; 13855682Smarkm} 13955682Smarkm 140178825Sdfrint ROKEN_LIB_FUNCTION 141178825Sdfrwait_for_process(pid_t pid) 142178825Sdfr{ 143178825Sdfr return wait_for_process_timed(pid, NULL, NULL, 0); 144178825Sdfr} 145178825Sdfr 146178825Sdfrint ROKEN_LIB_FUNCTION 14790926Snectarpipe_execv(FILE **stdin_fd, FILE **stdout_fd, FILE **stderr_fd, 14890926Snectar const char *file, ...) 14990926Snectar{ 15090926Snectar int in_fd[2], out_fd[2], err_fd[2]; 15190926Snectar pid_t pid; 15290926Snectar va_list ap; 15390926Snectar char **argv; 15490926Snectar 15590926Snectar if(stdin_fd != NULL) 15690926Snectar pipe(in_fd); 15790926Snectar if(stdout_fd != NULL) 15890926Snectar pipe(out_fd); 15990926Snectar if(stderr_fd != NULL) 16090926Snectar pipe(err_fd); 16190926Snectar pid = fork(); 16290926Snectar switch(pid) { 16390926Snectar case 0: 16490926Snectar va_start(ap, file); 16590926Snectar argv = vstrcollect(&ap); 16690926Snectar va_end(ap); 16790926Snectar if(argv == NULL) 16890926Snectar exit(-1); 16990926Snectar 17090926Snectar /* close pipes we're not interested in */ 17190926Snectar if(stdin_fd != NULL) 17290926Snectar close(in_fd[1]); 17390926Snectar if(stdout_fd != NULL) 17490926Snectar close(out_fd[0]); 17590926Snectar if(stderr_fd != NULL) 17690926Snectar close(err_fd[0]); 17790926Snectar 17890926Snectar /* pipe everything caller doesn't care about to /dev/null */ 17990926Snectar if(stdin_fd == NULL) 18090926Snectar in_fd[0] = open(_PATH_DEVNULL, O_RDONLY); 18190926Snectar if(stdout_fd == NULL) 18290926Snectar out_fd[1] = open(_PATH_DEVNULL, O_WRONLY); 18390926Snectar if(stderr_fd == NULL) 18490926Snectar err_fd[1] = open(_PATH_DEVNULL, O_WRONLY); 18590926Snectar 18690926Snectar /* move to proper descriptors */ 18790926Snectar if(in_fd[0] != STDIN_FILENO) { 18890926Snectar dup2(in_fd[0], STDIN_FILENO); 18990926Snectar close(in_fd[0]); 19090926Snectar } 19190926Snectar if(out_fd[1] != STDOUT_FILENO) { 19290926Snectar dup2(out_fd[1], STDOUT_FILENO); 19390926Snectar close(out_fd[1]); 19490926Snectar } 19590926Snectar if(err_fd[1] != STDERR_FILENO) { 19690926Snectar dup2(err_fd[1], STDERR_FILENO); 19790926Snectar close(err_fd[1]); 19890926Snectar } 19990926Snectar 200178825Sdfr closefrom(3); 201178825Sdfr 20290926Snectar execv(file, argv); 20390926Snectar exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC); 20490926Snectar case -1: 20590926Snectar if(stdin_fd != NULL) { 20690926Snectar close(in_fd[0]); 20790926Snectar close(in_fd[1]); 20890926Snectar } 20990926Snectar if(stdout_fd != NULL) { 21090926Snectar close(out_fd[0]); 21190926Snectar close(out_fd[1]); 21290926Snectar } 21390926Snectar if(stderr_fd != NULL) { 21490926Snectar close(err_fd[0]); 21590926Snectar close(err_fd[1]); 21690926Snectar } 21790926Snectar return -2; 21890926Snectar default: 21990926Snectar if(stdin_fd != NULL) { 22090926Snectar close(in_fd[0]); 22190926Snectar *stdin_fd = fdopen(in_fd[1], "w"); 22290926Snectar } 22390926Snectar if(stdout_fd != NULL) { 22490926Snectar close(out_fd[1]); 22590926Snectar *stdout_fd = fdopen(out_fd[0], "r"); 22690926Snectar } 22790926Snectar if(stderr_fd != NULL) { 22890926Snectar close(err_fd[1]); 22990926Snectar *stderr_fd = fdopen(err_fd[0], "r"); 23090926Snectar } 23190926Snectar } 23290926Snectar return pid; 23390926Snectar} 23490926Snectar 235178825Sdfrint ROKEN_LIB_FUNCTION 236178825Sdfrsimple_execvp_timed(const char *file, char *const args[], 237178825Sdfr time_t (*func)(void *), void *ptr, time_t timeout) 23855682Smarkm{ 23955682Smarkm pid_t pid = fork(); 24055682Smarkm switch(pid){ 24155682Smarkm case -1: 24255682Smarkm return -2; 24355682Smarkm case 0: 24455682Smarkm execvp(file, args); 24555682Smarkm exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC); 24655682Smarkm default: 247178825Sdfr return wait_for_process_timed(pid, func, ptr, timeout); 24855682Smarkm } 24955682Smarkm} 25055682Smarkm 251178825Sdfrint ROKEN_LIB_FUNCTION 252178825Sdfrsimple_execvp(const char *file, char *const args[]) 253178825Sdfr{ 254178825Sdfr return simple_execvp_timed(file, args, NULL, NULL, 0); 255178825Sdfr} 256178825Sdfr 25755682Smarkm/* gee, I'd like a execvpe */ 258178825Sdfrint ROKEN_LIB_FUNCTION 259178825Sdfrsimple_execve_timed(const char *file, char *const args[], char *const envp[], 260178825Sdfr time_t (*func)(void *), void *ptr, time_t timeout) 26155682Smarkm{ 26255682Smarkm pid_t pid = fork(); 26355682Smarkm switch(pid){ 26455682Smarkm case -1: 26555682Smarkm return -2; 26655682Smarkm case 0: 26755682Smarkm execve(file, args, envp); 26855682Smarkm exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC); 26955682Smarkm default: 270178825Sdfr return wait_for_process_timed(pid, func, ptr, timeout); 27155682Smarkm } 27255682Smarkm} 27355682Smarkm 274178825Sdfrint ROKEN_LIB_FUNCTION 275178825Sdfrsimple_execve(const char *file, char *const args[], char *const envp[]) 276178825Sdfr{ 277178825Sdfr return simple_execve_timed(file, args, envp, NULL, NULL, 0); 278178825Sdfr} 279178825Sdfr 280178825Sdfrint ROKEN_LIB_FUNCTION 28155682Smarkmsimple_execlp(const char *file, ...) 28255682Smarkm{ 28355682Smarkm va_list ap; 28455682Smarkm char **argv; 28555682Smarkm int ret; 28655682Smarkm 28755682Smarkm va_start(ap, file); 28857416Smarkm argv = vstrcollect(&ap); 28955682Smarkm va_end(ap); 29055682Smarkm if(argv == NULL) 29155682Smarkm return -1; 29255682Smarkm ret = simple_execvp(file, argv); 29355682Smarkm free(argv); 29455682Smarkm return ret; 29555682Smarkm} 29655682Smarkm 297178825Sdfrint ROKEN_LIB_FUNCTION 29855682Smarkmsimple_execle(const char *file, ... /* ,char *const envp[] */) 29955682Smarkm{ 30055682Smarkm va_list ap; 30155682Smarkm char **argv; 30255682Smarkm char *const* envp; 30355682Smarkm int ret; 30455682Smarkm 30555682Smarkm va_start(ap, file); 30657416Smarkm argv = vstrcollect(&ap); 30755682Smarkm envp = va_arg(ap, char **); 30855682Smarkm va_end(ap); 30955682Smarkm if(argv == NULL) 31055682Smarkm return -1; 31155682Smarkm ret = simple_execve(file, argv, envp); 31255682Smarkm free(argv); 31355682Smarkm return ret; 31455682Smarkm} 31572445Sassar 316178825Sdfrint ROKEN_LIB_FUNCTION 31772445Sassarsimple_execl(const char *file, ...) 31872445Sassar{ 31972445Sassar va_list ap; 32072445Sassar char **argv; 32172445Sassar int ret; 32272445Sassar 32372445Sassar va_start(ap, file); 32472445Sassar argv = vstrcollect(&ap); 32572445Sassar va_end(ap); 32672445Sassar if(argv == NULL) 32772445Sassar return -1; 32872445Sassar ret = simple_execve(file, argv, environ); 32972445Sassar free(argv); 33072445Sassar return ret; 33172445Sassar} 332