From 0e44e47b2a3a151733a621d6418753ca56a2b8f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Thu, 12 Feb 2004 14:37:18 +0000 Subject: [PATCH] add timed simple_exec git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@13342 ec53bebd-3082-4978-b11e-865c3cabbd6b --- lib/roken/roken-common.h | 4 ++ lib/roken/simple_exec.c | 111 ++++++++++++++++++++++++++++++++------- 2 files changed, 97 insertions(+), 18 deletions(-) diff --git a/lib/roken/roken-common.h b/lib/roken/roken-common.h index f1e5ed862..0451f5bdb 100644 --- a/lib/roken/roken-common.h +++ b/lib/roken/roken-common.h @@ -261,11 +261,15 @@ SigAction signal(int iSig, SigAction pAction); /* BSD compatible */ int ROKEN_LIB_FUNCTION simple_execve(const char*, char*const[], char*const[]); int ROKEN_LIB_FUNCTION simple_execvp(const char*, char *const[]); +int ROKEN_LIB_FUNCTION simple_execvp_timed(const char *, char *const[], + time_t (*)(void *), void *, time_t); int ROKEN_LIB_FUNCTION simple_execlp(const char*, ...); int ROKEN_LIB_FUNCTION simple_execle(const char*, ...); int ROKEN_LIB_FUNCTION simple_execl(const char *file, ...); int ROKEN_LIB_FUNCTION wait_for_process(pid_t); +int ROKEN_LIB_FUNCTION wait_for_process_timed(pid_t, time_t (*)(void *), + void *, time_t); int ROKEN_LIB_FUNCTION pipe_execv(FILE**, FILE**, FILE**, const char*, ...); void ROKEN_LIB_FUNCTION print_version(const char *); diff --git a/lib/roken/simple_exec.c b/lib/roken/simple_exec.c index 6ec2e98d0..dbf5830ca 100644 --- a/lib/roken/simple_exec.c +++ b/lib/roken/simple_exec.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998 - 2001 Kungliga Tekniska Högskolan + * Copyright (c) 1998 - 2001, 2004 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -58,28 +58,89 @@ RCSID("$Id$"); -1 on `unspecified' system errors -2 on fork failures -3 on waitpid errors + -4 exec timeout 0- is return value from subprocess 126 if the program couldn't be executed 127 if the program couldn't be found 128- is 128 + signal that killed subprocess + + possible values `func' can return: + ((time_t)-2) exit loop w/o killing child and return + `exec timeout'/-4 from simple_exec + ((time_t)-1) kill child with SIGTERM and wait for child to exit + 0 don't timeout again + n seconds to next timeout */ +static int sig_alarm; + +static RETSIGTYPE +sigtimeout(int sig) +{ + sig_alarm = 1; + SIGRETURN(0); +} + +int +wait_for_process_timed(pid_t pid, time_t (*func)(void *), + void *ptr, time_t timeout) +{ + RETSIGTYPE (*old_func)(int sig) = NULL; + unsigned int oldtime = 0; + int ret; + + sig_alarm = 0; + + if (func) { + old_func = signal(SIGALRM, sigtimeout); + oldtime = alarm(timeout); + } + + while(1) { + int status; + + while(waitpid(pid, &status, 0) < 0) { + if (errno != EINTR) { + ret = -3; + goto out; + } + if (func == NULL) + continue; + if (sig_alarm == 0) + continue; + timeout = (*func)(ptr); + if (timeout == (time_t)-1) { + kill(pid, SIGTERM); + continue; + } else if (timeout == (time_t)-2) { + ret = -4; + goto out; + } + alarm(timeout); + } + if(WIFSTOPPED(status)) + continue; + if(WIFEXITED(status)) { + ret = WEXITSTATUS(status); + break; + } + if(WIFSIGNALED(status)) { + ret = WTERMSIG(status) + 128; + break; + } + } + out: + if (func) { + signal(SIGALRM, old_func); + alarm(oldtime); + } + return ret; +} + int wait_for_process(pid_t pid) { - while(1) { - int status; - - while(waitpid(pid, &status, 0) < 0) - if (errno != EINTR) - return -3; - if(WIFSTOPPED(status)) - continue; - if(WIFEXITED(status)) - return WEXITSTATUS(status); - if(WIFSIGNALED(status)) - return WTERMSIG(status) + 128; - } + return wait_for_process_timed(pid, NULL, NULL, 0); } int @@ -170,7 +231,8 @@ pipe_execv(FILE **stdin_fd, FILE **stdout_fd, FILE **stderr_fd, } int -simple_execvp(const char *file, char *const args[]) +simple_execvp_timed(const char *file, char *const args[], + time_t (*func)(void *), void *ptr, time_t timeout) { pid_t pid = fork(); switch(pid){ @@ -180,13 +242,20 @@ simple_execvp(const char *file, char *const args[]) execvp(file, args); exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC); default: - return wait_for_process(pid); + return wait_for_process_timed(pid, func, ptr, timeout); } } +int +simple_execvp(const char *file, char *const args[]) +{ + return simple_execvp_timed(file, args, NULL, NULL, 0); +} + /* gee, I'd like a execvpe */ int -simple_execve(const char *file, char *const args[], char *const envp[]) +simple_execve_timed(const char *file, char *const args[], char *const envp[], + time_t (*func)(void *), void *ptr, time_t timeout) { pid_t pid = fork(); switch(pid){ @@ -196,10 +265,16 @@ simple_execve(const char *file, char *const args[], char *const envp[]) execve(file, args, envp); exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC); default: - return wait_for_process(pid); + return wait_for_process_timed(pid, func, ptr, timeout); } } +int +simple_execve(const char *file, char *const args[], char *const envp[]) +{ + return simple_execve_timed(file, args, envp, NULL, NULL, 0); +} + int simple_execlp(const char *file, ...) {