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