1 /* $OpenBSD: child.c,v 1.13 2003/06/03 02:56:14 millert Exp $ */ 2 3 /* 4 * Copyright (c) 1983 Regents of the University of California. 5 * 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 "defs.h" 33 34 #ifndef lint 35 #if 0 36 static char RCSid[] __attribute__((__unused__)) = 37 "$From: child.c,v 1.3 1999/11/01 00:20:55 christos Exp $"; 38 #else 39 static char RCSid[] __attribute__((__unused__)) = 40 "$OpenBSD: child.c,v 1.13 2003/06/03 02:56:14 millert Exp $"; 41 #endif 42 43 static char sccsid[] __attribute__((__unused__)) = 44 "@(#)docmd.c 5.1 (Berkeley) 6/6/85"; 45 46 static char copyright[] __attribute__((__unused__)) = 47 "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 48 All rights reserved.\n"; 49 #endif /* not lint */ 50 51 /* 52 * Functions for rdist related to children 53 */ 54 55 #include <sys/types.h> 56 #include <sys/wait.h> 57 #if defined(NEED_SYS_SELECT_H) 58 #include <sys/select.h> 59 #endif /* NEED_SYS_SELECT_H */ 60 61 typedef enum _PROCSTATE { 62 PSrunning, 63 PSdead 64 } PROCSTATE; 65 66 /* 67 * Structure for child rdist processes mainted by the parent 68 */ 69 struct _child { 70 char *c_name; /* Name of child */ 71 int c_readfd; /* Read file descriptor */ 72 pid_t c_pid; /* Process ID */ 73 PROCSTATE c_state; /* Running? */ 74 struct _child *c_next; /* Next entry */ 75 }; 76 typedef struct _child CHILD; 77 78 static CHILD *childlist = NULL; /* List of children */ 79 int activechildren = 0; /* Number of active children */ 80 extern int maxchildren; /* Max active children */ 81 static int needscan = FALSE; /* Need to scan children */ 82 83 static void removechild(CHILD *); 84 static CHILD *copychild(CHILD *); 85 static void addchild(CHILD *); 86 static void readchild(CHILD *); 87 static pid_t waitproc(int *, int); 88 static void reap(int); 89 static void childscan(void); 90 91 /* 92 * Remove a child that has died (exited) 93 * from the list of active children 94 */ 95 static void 96 removechild(CHILD *child) 97 { 98 CHILD *pc, *prevpc; 99 100 debugmsg(DM_CALL, "removechild(%s, %d, %d) start", 101 child->c_name, child->c_pid, child->c_readfd); 102 103 /* 104 * Find the child in the list 105 */ 106 for (pc = childlist, prevpc = NULL; pc != NULL; 107 prevpc = pc, pc = pc->c_next) 108 if (pc == child) 109 break; 110 111 if (pc == NULL) 112 error("RemoveChild called with bad child %s %d %d", 113 child->c_name, child->c_pid, child->c_readfd); 114 else { 115 /* 116 * Remove the child 117 */ 118 #if defined(POSIX_SIGNALS) 119 sigset_t set; 120 121 sigemptyset(&set); 122 sigaddset(&set, SIGCHLD); 123 sigprocmask(SIG_BLOCK, &set, NULL); 124 #else /* !POSIX_SIGNALS */ 125 int oldmask; 126 127 oldmask = sigblock(sigmask(SIGCHLD)); 128 #endif /* POSIX_SIGNALS */ 129 130 if (prevpc != NULL) 131 prevpc->c_next = pc->c_next; 132 else 133 childlist = pc->c_next; 134 135 #if defined(POSIX_SIGNALS) 136 sigprocmask(SIG_UNBLOCK, &set, NULL); 137 #else 138 sigsetmask(oldmask); 139 #endif /* POSIX_SIGNALS */ 140 141 (void) free(child->c_name); 142 --activechildren; 143 (void) close(child->c_readfd); 144 (void) free(pc); 145 } 146 147 debugmsg(DM_CALL, "removechild() end"); 148 } 149 150 /* 151 * Create a totally new copy of a child. 152 */ 153 static CHILD * 154 copychild(CHILD *child) 155 { 156 CHILD *newc; 157 158 newc = (CHILD *) xmalloc(sizeof(CHILD)); 159 160 newc->c_name = xstrdup(child->c_name); 161 newc->c_readfd = child->c_readfd; 162 newc->c_pid = child->c_pid; 163 newc->c_state = child->c_state; 164 newc->c_next = NULL; 165 166 return(newc); 167 } 168 169 /* 170 * Add a child to the list of children. 171 */ 172 static void 173 addchild(CHILD *child) 174 { 175 CHILD *pc; 176 177 debugmsg(DM_CALL, "addchild() start\n"); 178 179 pc = copychild(child); 180 pc->c_next = childlist; 181 childlist = pc; 182 183 ++activechildren; 184 185 debugmsg(DM_MISC, 186 "addchild() created '%s' pid %d fd %d (active=%d)\n", 187 child->c_name, child->c_pid, child->c_readfd, activechildren); 188 } 189 190 /* 191 * Read input from a child process. 192 */ 193 static void 194 readchild(CHILD *child) 195 { 196 char rbuf[BUFSIZ]; 197 int amt; 198 199 debugmsg(DM_CALL, "[readchild(%s, %d, %d) start]", 200 child->c_name, child->c_pid, child->c_readfd); 201 202 /* 203 * Check that this is a valid child. 204 */ 205 if (child->c_name == NULL || child->c_readfd <= 0) { 206 debugmsg(DM_MISC, "[readchild(%s, %d, %d) bad child]", 207 child->c_name, child->c_pid, child->c_readfd); 208 return; 209 } 210 211 /* 212 * Read from child and display the result. 213 */ 214 while ((amt = read(child->c_readfd, rbuf, sizeof(rbuf))) > 0) { 215 /* XXX remove these debug calls */ 216 debugmsg(DM_MISC, "[readchild(%s, %d, %d) got %d bytes]", 217 child->c_name, child->c_pid, child->c_readfd, amt); 218 219 (void) xwrite(fileno(stdout), rbuf, amt); 220 221 debugmsg(DM_MISC, "[readchild(%s, %d, %d) write done]", 222 child->c_name, child->c_pid, child->c_readfd); 223 } 224 225 debugmsg(DM_MISC, "readchild(%s, %d, %d) done: amt = %d errno = %d\n", 226 child->c_name, child->c_pid, child->c_readfd, amt, errno); 227 228 /* 229 * See if we've reached EOF 230 */ 231 if (amt == 0) 232 debugmsg(DM_MISC, "readchild(%s, %d, %d) at EOF\n", 233 child->c_name, child->c_pid, child->c_readfd); 234 } 235 236 /* 237 * Wait for processes to exit. If "block" is true, then we block 238 * until a process exits. Otherwise, we return right away. If 239 * a process does exit, then the pointer "statval" is set to the 240 * exit status of the exiting process, if statval is not NULL. 241 */ 242 static pid_t 243 waitproc(int *statval, int block) 244 { 245 WAIT_ARG_TYPE status; 246 pid_t pid; 247 int exitval; 248 249 debugmsg(DM_CALL, "waitproc() %s, active children = %d...\n", 250 (block) ? "blocking" : "nonblocking", activechildren); 251 252 #if WAIT_TYPE == WAIT_WAITPID 253 pid = waitpid(-1, &status, (block) ? 0 : WNOHANG); 254 #else 255 #if WAIT_TYPE == WAIT_WAIT3 256 pid = wait3(&status, (block) ? 0 : WNOHANG, NULL); 257 #endif /* WAIT_WAIT3 */ 258 #endif /* WAIT_WAITPID */ 259 260 #if defined(WEXITSTATUS) 261 exitval = WEXITSTATUS(status); 262 #else 263 exitval = status.w_retcode; 264 #endif /* defined(WEXITSTATUS) */ 265 266 if (pid > 0 && exitval != 0) { 267 nerrs++; 268 debugmsg(DM_MISC, 269 "Child process %d exited with status %d.\n", 270 pid, exitval); 271 } 272 273 if (statval) 274 *statval = exitval; 275 276 debugmsg(DM_CALL, "waitproc() done (activechildren = %d)\n", 277 activechildren); 278 279 return(pid); 280 } 281 282 /* 283 * Check to see if any children have exited, and if so, read any unread 284 * input and then remove the child from the list of children. 285 */ 286 static void 287 reap(int dummy) 288 { 289 CHILD *pc; 290 int save_errno = errno; 291 int status = 0; 292 pid_t pid; 293 294 debugmsg(DM_CALL, "reap() called\n"); 295 296 /* 297 * Reap every child that has exited. Break out of the 298 * loop as soon as we run out of children that have 299 * exited so far. 300 */ 301 for ( ; ; ) { 302 /* 303 * Do a non-blocking check for exiting processes 304 */ 305 pid = waitproc(&status, FALSE); 306 debugmsg(DM_MISC, 307 "reap() pid = %d status = %d activechildren=%d\n", 308 pid, status, activechildren); 309 310 /* 311 * See if a child really exited 312 */ 313 if (pid == 0) 314 break; 315 if (pid < 0) { 316 if (errno != ECHILD) 317 error("Wait failed: %s", SYSERR); 318 break; 319 } 320 321 /* 322 * Find the process (pid) and mark it as dead. 323 */ 324 for (pc = childlist; pc; pc = pc->c_next) 325 if (pc->c_pid == pid) { 326 needscan = TRUE; 327 pc->c_state = PSdead; 328 } 329 330 } 331 332 /* 333 * Reset signals 334 */ 335 (void) signal(SIGCHLD, reap); 336 337 debugmsg(DM_CALL, "reap() done\n"); 338 errno = save_errno; 339 } 340 341 /* 342 * Scan the children list to find the child that just exited, 343 * read any unread input, then remove it from the list of active children. 344 */ 345 static void 346 childscan(void) 347 { 348 CHILD *pc, *nextpc; 349 350 debugmsg(DM_CALL, "childscan() start"); 351 352 for (pc = childlist; pc; pc = nextpc) { 353 nextpc = pc->c_next; 354 if (pc->c_state == PSdead) { 355 readchild(pc); 356 removechild(pc); 357 } 358 } 359 360 needscan = FALSE; 361 debugmsg(DM_CALL, "childscan() end"); 362 } 363 364 /* 365 #if defined HAVE_SELECT 366 * 367 * Wait for children to send output for us to read. 368 * 369 #else !HAVE_SELECT 370 * 371 * Wait up for children to exit. 372 * 373 #endif 374 */ 375 void 376 waitup(void) 377 { 378 #if defined(HAVE_SELECT) 379 int count; 380 CHILD *pc; 381 fd_set *rchildfdsp = NULL; 382 int rchildfdsn = 0; 383 size_t bytes; 384 385 debugmsg(DM_CALL, "waitup() start\n"); 386 387 if (needscan) 388 childscan(); 389 390 if (activechildren <= 0) 391 return; 392 393 /* 394 * Settup which children we want to select() on. 395 */ 396 for (pc = childlist; pc; pc = pc->c_next) 397 if (pc->c_readfd > rchildfdsn) 398 rchildfdsn = pc->c_readfd; 399 bytes = howmany(rchildfdsn+1, NFDBITS) * sizeof(fd_mask); 400 if ((rchildfdsp = (fd_set *)malloc(bytes)) == NULL) 401 return; 402 403 memset(rchildfdsp, 0, bytes); 404 for (pc = childlist; pc; pc = pc->c_next) 405 if (pc->c_readfd > 0) { 406 debugmsg(DM_MISC, "waitup() select on %d (%s)\n", 407 pc->c_readfd, pc->c_name); 408 FD_SET(pc->c_readfd, rchildfdsp); 409 } 410 411 /* 412 * Actually call select() 413 */ 414 /* XXX remove debugmsg() calls */ 415 debugmsg(DM_MISC, "waitup() Call select(), activechildren=%d\n", 416 activechildren); 417 418 count = select(rchildfdsn+1, (SELECT_FD_TYPE *) rchildfdsp, 419 NULL, NULL, NULL); 420 421 debugmsg(DM_MISC, "waitup() select returned %d activechildren = %d\n", 422 count, activechildren); 423 424 /* 425 * select() will return count < 0 and errno == EINTR when 426 * there are no active children left. 427 */ 428 if (count < 0) { 429 if (errno != EINTR) 430 error("Select failed reading children input: %s", 431 SYSERR); 432 free(rchildfdsp); 433 return; 434 } 435 436 /* 437 * This should never happen. 438 */ 439 if (count == 0) { 440 error("Select returned an unexpected count of 0."); 441 free(rchildfdsp); 442 return; 443 } 444 445 /* 446 * Go through the list of children and read from each child 447 * which select() detected as ready for reading. 448 */ 449 for (pc = childlist; pc && count > 0; pc = pc->c_next) { 450 /* 451 * Make sure child still exists 452 */ 453 if (pc->c_name && kill(pc->c_pid, 0) < 0 && 454 errno == ESRCH) { 455 debugmsg(DM_MISC, 456 "waitup() proc %d (%s) died unexpectedly!", 457 pc->c_pid, pc->c_name); 458 pc->c_state = PSdead; 459 needscan = TRUE; 460 } 461 462 if (pc->c_name == NULL || 463 !FD_ISSET(pc->c_readfd, rchildfdsp)) 464 continue; 465 466 readchild(pc); 467 --count; 468 } 469 free(rchildfdsp); 470 471 #else /* !defined(HAVE_SELECT) */ 472 473 /* 474 * The non-select() version of waitproc() 475 */ 476 debugmsg(DM_CALL, "waitup() start\n"); 477 478 if (waitproc(NULL, TRUE) > 0) 479 --activechildren; 480 481 #endif /* defined(HAVE_SELECT) */ 482 debugmsg(DM_CALL, "waitup() end\n"); 483 } 484 485 /* 486 * Spawn (create) a new child process for "cmd". 487 */ 488 int 489 spawn(struct cmd *cmd, struct cmd *cmdlist) 490 { 491 pid_t pid; 492 int fildes[2]; 493 char *childname = cmd->c_name; 494 495 if (pipe(fildes) < 0) { 496 error("Cannot create pipe for %s: %s", childname, SYSERR); 497 return(-1); 498 } 499 500 pid = fork(); 501 if (pid == (pid_t)-1) { 502 error("Cannot spawn child for %s: fork failed: %s", 503 childname, SYSERR); 504 return(-1); 505 } else if (pid > 0) { 506 /* 507 * Parent 508 */ 509 static CHILD newchild; 510 511 #if defined(FORK_MISSES) 512 /* 513 * XXX Some OS's have a bug where fork does not 514 * always return properly to the parent 515 * when a number of forks are done very quicky. 516 */ 517 sleep(2); 518 #endif /* FORK_MISSES */ 519 520 /* Receive notification when the child exits */ 521 (void) signal(SIGCHLD, reap); 522 523 /* Settup the new child */ 524 newchild.c_next = NULL; 525 newchild.c_name = childname; 526 newchild.c_readfd = fildes[PIPE_READ]; 527 newchild.c_pid = pid; 528 newchild.c_state = PSrunning; 529 530 /* We're not going to write to the child */ 531 (void) close(fildes[PIPE_WRITE]); 532 533 /* Set non-blocking I/O */ 534 if (setnonblocking(newchild.c_readfd, TRUE) < 0) { 535 error("Set nonblocking I/O failed: %s", SYSERR); 536 return(-1); 537 } 538 539 /* Add new child to child list */ 540 addchild(&newchild); 541 542 /* Mark all other entries for this host as assigned */ 543 markassigned(cmd, cmdlist); 544 545 debugmsg(DM_CALL, 546 "spawn() Forked child %d for host %s active = %d\n", 547 pid, childname, activechildren); 548 return(pid); 549 } else { 550 /* 551 * Child 552 */ 553 554 /* We're not going to read from our parent */ 555 (void) close(fildes[PIPE_READ]); 556 557 /* Make stdout and stderr go to PIPE_WRITE (our parent) */ 558 if (dup2(fildes[PIPE_WRITE], (int)fileno(stdout)) < 0) { 559 error("Cannot duplicate stdout file descriptor: %s", 560 SYSERR); 561 return(-1); 562 } 563 if (dup2(fildes[PIPE_WRITE], (int)fileno(stderr)) < 0) { 564 error("Cannot duplicate stderr file descriptor: %s", 565 SYSERR); 566 return(-1); 567 } 568 569 return(0); 570 } 571 } 572 573 574 /* 575 * Enable or disable non-blocking I/O mode. 576 * 577 * Code is from INN by Rich Salz. 578 */ 579 #if NBIO_TYPE == NBIO_IOCTL 580 #include <sys/ioctl.h> 581 582 int 583 setnonblocking(int fd, int flag) 584 { 585 int state; 586 587 state = flag ? 1 : 0; 588 return(ioctl(fd, FIONBIO, (char *)&state)); 589 } 590 591 #endif /* NBIO_IOCTL */ 592 593 594 #if NBIO_TYPE == NBIO_FCNTL 595 int 596 setnonblocking(int fd, int flag) 597 { 598 int mode; 599 600 if ((mode = fcntl(fd, F_GETFL, 0)) < 0) 601 return(-1); 602 if (flag) 603 mode |= FNDELAY; 604 else 605 mode &= ~FNDELAY; 606 return(fcntl(fd, F_SETFL, mode)); 607 } 608 #endif /* NBIO_FCNTL */ 609