1 /* 2 * Copyright (c) 1998 - 2001 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: simple_exec.c,v 1.10 2001/06/21 03:38:03 assar Exp $"); 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 #define EX_NOEXEC 126 55 #define EX_NOTFOUND 127 56 57 /* return values: 58 -1 on `unspecified' system errors 59 -2 on fork failures 60 -3 on waitpid errors 61 0- is return value from subprocess 62 126 if the program couldn't be executed 63 127 if the program couldn't be found 64 128- is 128 + signal that killed subprocess 65 */ 66 67 int 68 wait_for_process(pid_t pid) 69 { 70 while(1) { 71 int status; 72 73 while(waitpid(pid, &status, 0) < 0) 74 if (errno != EINTR) 75 return -3; 76 if(WIFSTOPPED(status)) 77 continue; 78 if(WIFEXITED(status)) 79 return WEXITSTATUS(status); 80 if(WIFSIGNALED(status)) 81 return WTERMSIG(status) + 128; 82 } 83 } 84 85 int 86 pipe_execv(FILE **stdin_fd, FILE **stdout_fd, FILE **stderr_fd, 87 const char *file, ...) 88 { 89 int in_fd[2], out_fd[2], err_fd[2]; 90 pid_t pid; 91 va_list ap; 92 char **argv; 93 94 if(stdin_fd != NULL) 95 pipe(in_fd); 96 if(stdout_fd != NULL) 97 pipe(out_fd); 98 if(stderr_fd != NULL) 99 pipe(err_fd); 100 pid = fork(); 101 switch(pid) { 102 case 0: 103 va_start(ap, file); 104 argv = vstrcollect(&ap); 105 va_end(ap); 106 if(argv == NULL) 107 exit(-1); 108 109 /* close pipes we're not interested in */ 110 if(stdin_fd != NULL) 111 close(in_fd[1]); 112 if(stdout_fd != NULL) 113 close(out_fd[0]); 114 if(stderr_fd != NULL) 115 close(err_fd[0]); 116 117 /* pipe everything caller doesn't care about to /dev/null */ 118 if(stdin_fd == NULL) 119 in_fd[0] = open(_PATH_DEVNULL, O_RDONLY); 120 if(stdout_fd == NULL) 121 out_fd[1] = open(_PATH_DEVNULL, O_WRONLY); 122 if(stderr_fd == NULL) 123 err_fd[1] = open(_PATH_DEVNULL, O_WRONLY); 124 125 /* move to proper descriptors */ 126 if(in_fd[0] != STDIN_FILENO) { 127 dup2(in_fd[0], STDIN_FILENO); 128 close(in_fd[0]); 129 } 130 if(out_fd[1] != STDOUT_FILENO) { 131 dup2(out_fd[1], STDOUT_FILENO); 132 close(out_fd[1]); 133 } 134 if(err_fd[1] != STDERR_FILENO) { 135 dup2(err_fd[1], STDERR_FILENO); 136 close(err_fd[1]); 137 } 138 139 execv(file, argv); 140 exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC); 141 case -1: 142 if(stdin_fd != NULL) { 143 close(in_fd[0]); 144 close(in_fd[1]); 145 } 146 if(stdout_fd != NULL) { 147 close(out_fd[0]); 148 close(out_fd[1]); 149 } 150 if(stderr_fd != NULL) { 151 close(err_fd[0]); 152 close(err_fd[1]); 153 } 154 return -2; 155 default: 156 if(stdin_fd != NULL) { 157 close(in_fd[0]); 158 *stdin_fd = fdopen(in_fd[1], "w"); 159 } 160 if(stdout_fd != NULL) { 161 close(out_fd[1]); 162 *stdout_fd = fdopen(out_fd[0], "r"); 163 } 164 if(stderr_fd != NULL) { 165 close(err_fd[1]); 166 *stderr_fd = fdopen(err_fd[0], "r"); 167 } 168 } 169 return pid; 170 } 171 172 int 173 simple_execvp(const char *file, char *const args[]) 174 { 175 pid_t pid = fork(); 176 switch(pid){ 177 case -1: 178 return -2; 179 case 0: 180 execvp(file, args); 181 exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC); 182 default: 183 return wait_for_process(pid); 184 } 185 } 186 187 /* gee, I'd like a execvpe */ 188 int 189 simple_execve(const char *file, char *const args[], char *const envp[]) 190 { 191 pid_t pid = fork(); 192 switch(pid){ 193 case -1: 194 return -2; 195 case 0: 196 execve(file, args, envp); 197 exit((errno == ENOENT) ? EX_NOTFOUND : EX_NOEXEC); 198 default: 199 return wait_for_process(pid); 200 } 201 } 202 203 int 204 simple_execlp(const char *file, ...) 205 { 206 va_list ap; 207 char **argv; 208 int ret; 209 210 va_start(ap, file); 211 argv = vstrcollect(&ap); 212 va_end(ap); 213 if(argv == NULL) 214 return -1; 215 ret = simple_execvp(file, argv); 216 free(argv); 217 return ret; 218 } 219 220 int 221 simple_execle(const char *file, ... /* ,char *const envp[] */) 222 { 223 va_list ap; 224 char **argv; 225 char *const* envp; 226 int ret; 227 228 va_start(ap, file); 229 argv = vstrcollect(&ap); 230 envp = va_arg(ap, char **); 231 va_end(ap); 232 if(argv == NULL) 233 return -1; 234 ret = simple_execve(file, argv, envp); 235 free(argv); 236 return ret; 237 } 238 239 int 240 simple_execl(const char *file, ...) 241 { 242 va_list ap; 243 char **argv; 244 int ret; 245 246 va_start(ap, file); 247 argv = vstrcollect(&ap); 248 va_end(ap); 249 if(argv == NULL) 250 return -1; 251 ret = simple_execve(file, argv, environ); 252 free(argv); 253 return ret; 254 } 255