root/source4/heimdal/lib/roken/simple_exec.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sigtimeout
  2. wait_for_process_timed
  3. wait_for_process
  4. pipe_execv
  5. simple_execvp_timed
  6. simple_execvp
  7. simple_execve_timed
  8. simple_execve
  9. simple_execlp
  10. simple_execle
  11. simple_execl

   1 /*
   2  * Copyright (c) 1998 - 2001, 2004 Kungliga Tekniska Högskolan
   3  * (Royal Institute of Technology, Stockholm, Sweden).
   4  * All rights reserved.
   5  *
   6  * Redistribution and use in source and binary forms, with or without
   7  * modification, are permitted provided that the following conditions
   8  * are met:
   9  *
  10  * 1. Redistributions of source code must retain the above copyright
  11  *    notice, this list of conditions and the following disclaimer.
  12  *
  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.
  16  *
  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.
  20  *
  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
  31  * SUCH DAMAGE.
  32  */
  33 
  34 #ifdef HAVE_CONFIG_H
  35 #include <config.h>
  36 RCSID("$Id$");
  37 #endif
  38 
  39 #include <stdarg.h>
  40 #include <stdlib.h>
  41 #ifdef HAVE_SYS_TYPES_H
  42 #include <sys/types.h>
  43 #endif
  44 #ifdef HAVE_SYS_WAIT_H
  45 #include <sys/wait.h>
  46 #endif
  47 #ifdef HAVE_UNISTD_H
  48 #include <unistd.h>
  49 #endif
  50 #include <errno.h>
  51 
  52 #include "roken.h"
  53 
  54 #if !HAVE_DECL_ENVIRON
  55 extern char **environ;
  56 #endif
  57 
  58 #define EX_NOEXEC       126
  59 #define EX_NOTFOUND     127
  60 
  61 /* return values:
  62    -1   on `unspecified' system errors
  63    -2   on fork failures
  64    -3   on waitpid errors
  65    -4   exec timeout
  66    0-   is return value from subprocess
  67    126  if the program couldn't be executed
  68    127  if the program couldn't be found
  69    128- is 128 + signal that killed subprocess
  70 
  71    possible values `func' can return:
  72    ((time_t)-2)         exit loop w/o killing child and return
  73                         `exec timeout'/-4 from simple_exec
  74    ((time_t)-1)         kill child with SIGTERM and wait for child to exit
  75    0                    don't timeout again
  76    n                    seconds to next timeout
  77    */
  78 
  79 static int sig_alarm;
  80 
  81 static RETSIGTYPE
  82 sigtimeout(int sig)
     /* [<][>][^][v][top][bottom][index][help] */
  83 {
  84     sig_alarm = 1;
  85     SIGRETURN(0);
  86 }
  87 
  88 int ROKEN_LIB_FUNCTION
  89 wait_for_process_timed(pid_t pid, time_t (*func)(void *),
     /* [<][>][^][v][top][bottom][index][help] */
  90                        void *ptr, time_t timeout)
  91 {
  92     RETSIGTYPE (*old_func)(int sig) = NULL;
  93     unsigned int oldtime = 0;
  94     int ret;
  95 
  96     sig_alarm = 0;
  97 
  98     if (func) {
  99         old_func = signal(SIGALRM, sigtimeout);
 100         oldtime = alarm(timeout);
 101     }
 102 
 103     while(1) {
 104         int status;
 105 
 106         while(waitpid(pid, &status, 0) < 0) {
 107             if (errno != EINTR) {
 108                 ret = -3;
 109                 goto out;
 110             }
 111             if (func == NULL)
 112                 continue;
 113             if (sig_alarm == 0)
 114                 continue;
 115             timeout = (*func)(ptr);
 116             if (timeout == (time_t)-1) {
 117                 kill(pid, SIGTERM);
 118                 continue;
 119             } else if (timeout == (time_t)-2) {
 120                 ret = -4;
 121                 goto out;
 122             }
 123             alarm(timeout);
 124         }
 125         if(WIFSTOPPED(status))
 126             continue;
 127         if(WIFEXITED(status)) {
 128             ret = WEXITSTATUS(status);
 129             break;
 130         }
 131         if(WIFSIGNALED(status)) {
 132             ret = WTERMSIG(status) + 128;
 133             break;
 134         }
 135     }
 136  out:
 137     if (func) {
 138         signal(SIGALRM, old_func);
 139         alarm(oldtime);
 140     }
 141     return ret;
 142 }
 143 
 144 int ROKEN_LIB_FUNCTION
 145 wait_for_process(pid_t pid)
     /* [<][>][^][v][top][bottom][index][help] */
 146 {
 147     return wait_for_process_timed(pid, NULL, NULL, 0);
 148 }
 149 
 150 int ROKEN_LIB_FUNCTION
 151 pipe_execv(FILE **stdin_fd, FILE **stdout_fd, FILE **stderr_fd,
     /* [<][>][^][v][top][bottom][index][help] */
 152            const char *file, ...)
 153 {
 154     int in_fd[2], out_fd[2], err_fd[2];
 155     pid_t pid;
 156     va_list ap;
 157     char **argv;
 158 
 159     if(stdin_fd != NULL)
 160         pipe(in_fd);
 161     if(stdout_fd != NULL)
 162         pipe(out_fd);
 163     if(stderr_fd != NULL)
 164         pipe(err_fd);
 165     pid = fork();
 166     switch(pid) {
 167     case 0:
 168         va_start(ap, file);
 169         argv = vstrcollect(&ap);
 170         va_end(ap);
 171         if(argv == NULL)
 172             exit(-1);
 173 
 174         /* close pipes we're not interested in */
 175         if(stdin_fd != NULL)
 176             close(in_fd[1]);
 177         if(stdout_fd != NULL)
 178             close(out_fd[0]);
 179         if(stderr_fd != NULL)
 180             close(err_fd[0]);
 181 
 182         /* pipe everything caller doesn't care about to /dev/null */
 183         if(stdin_fd == NULL)
 184             in_fd[0] = open(_PATH_DEVNULL, O_RDONLY);
 185         if(stdout_fd == NULL)
 186             out_fd[1] = open(_PATH_DEVNULL, O_WRONLY);
 187         if(stderr_fd == NULL)
 188             err_fd[1] = open(_PATH_DEVNULL, O_WRONLY);
 189 
 190         /* move to proper descriptors */
 191         if(in_fd[0] != STDIN_FILENO) {
 192             dup2(in_fd[0], STDIN_FILENO);
 193             close(in_fd[0]);
 194         }
 195         if(out_fd[1] != STDOUT_FILENO) {
 196             dup2(out_fd[1], STDOUT_FILENO);
 197             close(out_fd[1]);
 198         }
 199         if(err_fd[1] != STDERR_FILENO) {
 200             dup2(err_fd[1], STDERR_FILENO);
 201             close(err_fd[1]);
 202         }
 203 
 204         closefrom(3);
 205 
 206         execv(file, argv);
 207         exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
 208     case -1:
 209         if(stdin_fd != NULL) {
 210             close(in_fd[0]);
 211             close(in_fd[1]);
 212         }
 213         if(stdout_fd != NULL) {
 214             close(out_fd[0]);
 215             close(out_fd[1]);
 216         }
 217         if(stderr_fd != NULL) {
 218             close(err_fd[0]);
 219             close(err_fd[1]);
 220         }
 221         return -2;
 222     default:
 223         if(stdin_fd != NULL) {
 224             close(in_fd[0]);
 225             *stdin_fd = fdopen(in_fd[1], "w");
 226         }
 227         if(stdout_fd != NULL) {
 228             close(out_fd[1]);
 229             *stdout_fd = fdopen(out_fd[0], "r");
 230         }
 231         if(stderr_fd != NULL) {
 232             close(err_fd[1]);
 233             *stderr_fd = fdopen(err_fd[0], "r");
 234         }
 235     }
 236     return pid;
 237 }
 238 
 239 int ROKEN_LIB_FUNCTION
 240 simple_execvp_timed(const char *file, char *const args[],
     /* [<][>][^][v][top][bottom][index][help] */
 241                     time_t (*func)(void *), void *ptr, time_t timeout)
 242 {
 243     pid_t pid = fork();
 244     switch(pid){
 245     case -1:
 246         return -2;
 247     case 0:
 248         execvp(file, args);
 249         exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
 250     default:
 251         return wait_for_process_timed(pid, func, ptr, timeout);
 252     }
 253 }
 254 
 255 int ROKEN_LIB_FUNCTION
 256 simple_execvp(const char *file, char *const args[])
     /* [<][>][^][v][top][bottom][index][help] */
 257 {
 258     return simple_execvp_timed(file, args, NULL, NULL, 0);
 259 }
 260 
 261 /* gee, I'd like a execvpe */
 262 int ROKEN_LIB_FUNCTION
 263 simple_execve_timed(const char *file, char *const args[], char *const envp[],
     /* [<][>][^][v][top][bottom][index][help] */
 264                     time_t (*func)(void *), void *ptr, time_t timeout)
 265 {
 266     pid_t pid = fork();
 267     switch(pid){
 268     case -1:
 269         return -2;
 270     case 0:
 271         execve(file, args, envp);
 272         exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC);
 273     default:
 274         return wait_for_process_timed(pid, func, ptr, timeout);
 275     }
 276 }
 277 
 278 int ROKEN_LIB_FUNCTION
 279 simple_execve(const char *file, char *const args[], char *const envp[])
     /* [<][>][^][v][top][bottom][index][help] */
 280 {
 281     return simple_execve_timed(file, args, envp, NULL, NULL, 0);
 282 }
 283 
 284 int ROKEN_LIB_FUNCTION
 285 simple_execlp(const char *file, ...)
     /* [<][>][^][v][top][bottom][index][help] */
 286 {
 287     va_list ap;
 288     char **argv;
 289     int ret;
 290 
 291     va_start(ap, file);
 292     argv = vstrcollect(&ap);
 293     va_end(ap);
 294     if(argv == NULL)
 295         return -1;
 296     ret = simple_execvp(file, argv);
 297     free(argv);
 298     return ret;
 299 }
 300 
 301 int ROKEN_LIB_FUNCTION
 302 simple_execle(const char *file, ... /* ,char *const envp[] */)
     /* [<][>][^][v][top][bottom][index][help] */
 303 {
 304     va_list ap;
 305     char **argv;
 306     char *const* envp;
 307     int ret;
 308 
 309     va_start(ap, file);
 310     argv = vstrcollect(&ap);
 311     envp = va_arg(ap, char **);
 312     va_end(ap);
 313     if(argv == NULL)
 314         return -1;
 315     ret = simple_execve(file, argv, envp);
 316     free(argv);
 317     return ret;
 318 }
 319 
 320 int ROKEN_LIB_FUNCTION
 321 simple_execl(const char *file, ...)
     /* [<][>][^][v][top][bottom][index][help] */
 322 {
 323     va_list ap;
 324     char **argv;
 325     int ret;
 326 
 327     va_start(ap, file);
 328     argv = vstrcollect(&ap);
 329     va_end(ap);
 330     if(argv == NULL)
 331         return -1;
 332     ret = simple_execve(file, argv, environ);
 333     free(argv);
 334     return ret;
 335 }

/* [<][>][^][v][top][bottom][index][help] */