1 /* $NetBSD: popen.c,v 1.19 2005/07/19 23:07:10 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1980, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93"; 36 #else 37 __RCSID("$NetBSD: popen.c,v 1.19 2005/07/19 23:07:10 christos Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include "rcv.h" 42 #include <sys/wait.h> 43 #include <fcntl.h> 44 #include <errno.h> 45 #include <stdarg.h> 46 #include "extern.h" 47 48 #define READ 0 49 #define WRITE 1 50 51 struct fp { 52 FILE *fp; 53 int pipe; 54 pid_t pid; 55 struct fp *link; 56 }; 57 static struct fp *fp_head; 58 59 struct child { 60 pid_t pid; 61 char done; 62 char free; 63 int status; 64 struct child *link; 65 }; 66 static struct child *child, *child_freelist = NULL; 67 68 static struct child *findchild(pid_t, int); 69 static void delchild(struct child *); 70 static pid_t file_pid(FILE *); 71 static pid_t start_commandv(const char *, sigset_t *, int, int, va_list); 72 73 FILE * 74 Fopen(const char *fn, const char *mode) 75 { 76 FILE *fp; 77 78 if ((fp = fopen(fn, mode)) != NULL) { 79 register_file(fp, 0, 0); 80 (void)fcntl(fileno(fp), F_SETFD, 1); 81 } 82 return fp; 83 } 84 85 FILE * 86 Fdopen(int fd, const char *mode) 87 { 88 FILE *fp; 89 90 if ((fp = fdopen(fd, mode)) != NULL) { 91 register_file(fp, 0, 0); 92 (void)fcntl(fileno(fp), F_SETFD, 1); 93 } 94 return fp; 95 } 96 97 int 98 Fclose(FILE *fp) 99 { 100 101 unregister_file(fp); 102 return fclose(fp); 103 } 104 105 FILE * 106 Popen(const char *cmd, const char *mode) 107 { 108 int p[2]; 109 int myside, hisside, fd0, fd1; 110 pid_t pid; 111 sigset_t nset; 112 FILE *fp; 113 114 if (pipe(p) < 0) 115 return NULL; 116 (void)fcntl(p[READ], F_SETFD, 1); 117 (void)fcntl(p[WRITE], F_SETFD, 1); 118 if (*mode == 'r') { 119 myside = p[READ]; 120 hisside = fd0 = fd1 = p[WRITE]; 121 } else { 122 myside = p[WRITE]; 123 hisside = fd0 = p[READ]; 124 fd1 = -1; 125 } 126 (void)sigemptyset(&nset); 127 pid = start_command(value("SHELL"), &nset, fd0, fd1, "-c", cmd, NULL); 128 if (pid < 0) { 129 (void)close(p[READ]); 130 (void)close(p[WRITE]); 131 return NULL; 132 } 133 (void)close(hisside); 134 if ((fp = fdopen(myside, mode)) != NULL) 135 register_file(fp, 1, pid); 136 return fp; 137 } 138 139 int 140 Pclose(FILE *ptr) 141 { 142 int i; 143 sigset_t nset, oset; 144 145 i = file_pid(ptr); 146 unregister_file(ptr); 147 (void)fclose(ptr); 148 (void)sigemptyset(&nset); 149 (void)sigaddset(&nset, SIGINT); 150 (void)sigaddset(&nset, SIGHUP); 151 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 152 i = wait_child(i); 153 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 154 return i; 155 } 156 157 void 158 close_all_files(void) 159 { 160 161 while (fp_head) 162 if (fp_head->pipe) 163 (void)Pclose(fp_head->fp); 164 else 165 (void)Fclose(fp_head->fp); 166 } 167 168 void 169 register_file(FILE *fp, int pipefd, pid_t pid) 170 { 171 struct fp *fpp; 172 173 if ((fpp = (struct fp *)malloc(sizeof(*fpp))) == NULL) 174 errx(1, "Out of memory"); 175 fpp->fp = fp; 176 fpp->pipe = pipefd; 177 fpp->pid = pid; 178 fpp->link = fp_head; 179 fp_head = fpp; 180 } 181 182 void 183 unregister_file(FILE *fp) 184 { 185 struct fp **pp, *p; 186 187 for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link) 188 if (p->fp == fp) { 189 *pp = p->link; 190 (void)free(p); 191 return; 192 } 193 errx(1, "Invalid file pointer"); 194 } 195 196 static pid_t 197 file_pid(FILE *fp) 198 { 199 struct fp *p; 200 201 for (p = fp_head; p; p = p->link) 202 if (p->fp == fp) 203 return p->pid; 204 errx(1, "Invalid file pointer"); 205 /*NOTREACHED*/ 206 } 207 208 /* 209 * Run a command without a shell, with optional arguments and splicing 210 * of stdin (-1 means none) and stdout. The command name can be a sequence 211 * of words. 212 * Signals must be handled by the caller. 213 * "nset" contains the signals to ignore in the new process. 214 * SIGINT is enabled unless it's in "nset". 215 */ 216 static pid_t 217 start_commandv(const char *cmd, sigset_t *nset, int infd, int outfd, 218 va_list args) 219 { 220 pid_t pid; 221 222 if ((pid = fork()) < 0) { 223 warn("fork"); 224 return -1; 225 } 226 if (pid == 0) { 227 char *argv[100]; 228 int i = getrawlist(cmd, argv, sizeof(argv)/ sizeof(*argv)); 229 230 while ((argv[i++] = va_arg(args, char *)) != NULL) 231 continue; 232 argv[i] = NULL; 233 prepare_child(nset, infd, outfd); 234 (void)execvp(argv[0], argv); 235 warn("%s", argv[0]); 236 _exit(1); 237 } 238 return pid; 239 } 240 241 int 242 run_command(const char *cmd, sigset_t *nset, int infd, int outfd, ...) 243 { 244 pid_t pid; 245 va_list args; 246 247 va_start(args, outfd); 248 pid = start_commandv(cmd, nset, infd, outfd, args); 249 va_end(args); 250 if (pid < 0) 251 return -1; 252 return wait_command(pid); 253 } 254 255 int 256 start_command(const char *cmd, sigset_t *nset, int infd, int outfd, ...) 257 { 258 va_list args; 259 int r; 260 261 va_start(args, outfd); 262 r = start_commandv(cmd, nset, infd, outfd, args); 263 va_end(args); 264 return r; 265 } 266 267 void 268 prepare_child(sigset_t *nset, int infd, int outfd) 269 { 270 int i; 271 sigset_t eset; 272 273 /* 274 * All file descriptors other than 0, 1, and 2 are supposed to be 275 * close-on-exec. 276 */ 277 if (infd > 0) { 278 (void)dup2(infd, 0); 279 } else if (infd != 0) { 280 /* we don't want the child stealing my stdin input */ 281 (void)close(0); 282 (void)open(_PATH_DEVNULL, O_RDONLY, 0); 283 } 284 if (outfd >= 0 && outfd != 1) 285 (void)dup2(outfd, 1); 286 if (nset == NULL) 287 return; 288 if (nset != NULL) { 289 for (i = 1; i < NSIG; i++) 290 if (sigismember(nset, i)) 291 (void)signal(i, SIG_IGN); 292 } 293 if (nset == NULL || !sigismember(nset, SIGINT)) 294 (void)signal(SIGINT, SIG_DFL); 295 (void)sigemptyset(&eset); 296 (void)sigprocmask(SIG_SETMASK, &eset, NULL); 297 } 298 299 int 300 wait_command(pid_t pid) 301 { 302 303 if (wait_child(pid) < 0) { 304 (void)puts("Fatal error in process."); 305 return -1; 306 } 307 return 0; 308 } 309 310 static struct child * 311 findchild(pid_t pid, int dont_alloc) 312 { 313 struct child **cpp; 314 315 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; 316 cpp = &(*cpp)->link) 317 ; 318 if (*cpp == NULL) { 319 if (dont_alloc) 320 return NULL; 321 if (child_freelist) { 322 *cpp = child_freelist; 323 child_freelist = (*cpp)->link; 324 } else { 325 *cpp = (struct child *)malloc(sizeof(struct child)); 326 if (*cpp == NULL) 327 errx(1, "Out of memory"); 328 } 329 (*cpp)->pid = pid; 330 (*cpp)->done = (*cpp)->free = 0; 331 (*cpp)->link = NULL; 332 } 333 return *cpp; 334 } 335 336 static void 337 delchild(struct child *cp) 338 { 339 struct child **cpp; 340 341 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) 342 ; 343 *cpp = cp->link; 344 cp->link = child_freelist; 345 child_freelist = cp; 346 } 347 348 void 349 /*ARGSUSED*/ 350 sigchild(int signo) 351 { 352 pid_t pid; 353 int status; 354 struct child *cp; 355 int save_errno = errno; 356 357 while ((pid = 358 waitpid((pid_t)-1, &status, WNOHANG)) > 0) { 359 cp = findchild(pid, 1); 360 if (!cp) 361 continue; 362 if (cp->free) 363 delchild(cp); 364 else { 365 cp->done = 1; 366 cp->status = status; 367 } 368 } 369 errno = save_errno; 370 } 371 372 int wait_status; 373 374 /* 375 * Wait for a specific child to die. 376 */ 377 int 378 wait_child(pid_t pid) 379 { 380 struct child *cp; 381 sigset_t nset, oset; 382 pid_t rv = 0; 383 384 (void)sigemptyset(&nset); 385 (void)sigaddset(&nset, SIGCHLD); 386 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 387 /* 388 * If we have not already waited on the pid (via sigchild) 389 * wait on it now. Otherwise, use the wait status stashed 390 * by sigchild. 391 */ 392 cp = findchild(pid, 1); 393 if (cp == NULL || !cp->done) 394 rv = waitpid(pid, &wait_status, 0); 395 else 396 wait_status = cp->status; 397 if (cp != NULL) 398 delchild(cp); 399 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 400 if (rv == -1 || (WIFEXITED(wait_status) && WEXITSTATUS(wait_status))) 401 return -1; 402 else 403 return 0; 404 } 405 406 /* 407 * Mark a child as don't care. 408 */ 409 void 410 free_child(pid_t pid) 411 { 412 struct child *cp; 413 sigset_t nset, oset; 414 415 (void)sigemptyset(&nset); 416 (void)sigaddset(&nset, SIGCHLD); 417 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 418 if ((cp = findchild(pid, 0)) != NULL) { 419 if (cp->done) 420 delchild(cp); 421 else 422 cp->free = 1; 423 } 424 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 425 } 426