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