1 /* $NetBSD: work_fork.c,v 1.8 2016/01/08 21:35:39 christos Exp $ */ 2 3 /* 4 * work_fork.c - fork implementation for blocking worker child. 5 */ 6 #include <config.h> 7 #include "ntp_workimpl.h" 8 9 #ifdef WORK_FORK 10 #include <stdio.h> 11 #include <ctype.h> 12 #include <signal.h> 13 #include <sys/wait.h> 14 15 #include "iosignal.h" 16 #include "ntp_stdlib.h" 17 #include "ntp_malloc.h" 18 #include "ntp_syslog.h" 19 #include "ntpd.h" 20 #include "ntp_io.h" 21 #include "ntp_assert.h" 22 #include "ntp_unixtime.h" 23 #include "ntp_worker.h" 24 25 /* === variables === */ 26 int worker_process; 27 addremove_io_fd_func addremove_io_fd; 28 static volatile int worker_sighup_received; 29 30 /* === function prototypes === */ 31 static void fork_blocking_child(blocking_child *); 32 static RETSIGTYPE worker_sighup(int); 33 static void send_worker_home_atexit(void); 34 static void cleanup_after_child(blocking_child *); 35 36 /* === functions === */ 37 /* 38 * exit_worker() 39 * 40 * On some systems _exit() is preferred to exit() for forked children. 41 * For example, http://netbsd.gw.com/cgi-bin/man-cgi?fork++NetBSD-5.0 42 * recommends _exit() to avoid double-flushing C runtime stream buffers 43 * and also to avoid calling the parent's atexit() routines in the 44 * child. On those systems WORKER_CHILD_EXIT is _exit. Since _exit 45 * bypasses CRT cleanup, fflush() files we know might have output 46 * buffered. 47 */ 48 void 49 exit_worker( 50 int exitcode 51 ) 52 { 53 if (syslog_file != NULL) 54 fflush(syslog_file); 55 fflush(stdout); 56 fflush(stderr); 57 WORKER_CHILD_EXIT (exitcode); /* space before ( required */ 58 } 59 60 61 static RETSIGTYPE 62 worker_sighup( 63 int sig 64 ) 65 { 66 if (SIGHUP == sig) 67 worker_sighup_received = 1; 68 } 69 70 71 int 72 worker_sleep( 73 blocking_child * c, 74 time_t seconds 75 ) 76 { 77 u_int sleep_remain; 78 79 sleep_remain = (u_int)seconds; 80 do { 81 if (!worker_sighup_received) 82 sleep_remain = sleep(sleep_remain); 83 if (worker_sighup_received) { 84 TRACE(1, ("worker SIGHUP with %us left to sleep", 85 sleep_remain)); 86 worker_sighup_received = 0; 87 return -1; 88 } 89 } while (sleep_remain); 90 91 return 0; 92 } 93 94 95 void 96 interrupt_worker_sleep(void) 97 { 98 u_int idx; 99 blocking_child * c; 100 int rc; 101 102 for (idx = 0; idx < blocking_children_alloc; idx++) { 103 c = blocking_children[idx]; 104 105 if (NULL == c || c->reusable == TRUE) 106 continue; 107 108 rc = kill(c->pid, SIGHUP); 109 if (rc < 0) 110 msyslog(LOG_ERR, 111 "Unable to signal HUP to wake child pid %d: %m", 112 c->pid); 113 } 114 } 115 116 117 /* 118 * harvest_child_status() runs in the parent. 119 */ 120 static void 121 harvest_child_status( 122 blocking_child * c 123 ) 124 { 125 if (c->pid) 126 { 127 /* Wait on the child so it can finish terminating */ 128 if (waitpid(c->pid, NULL, 0) == c->pid) 129 TRACE(4, ("harvested child %d\n", c->pid)); 130 else if (errno != ECHILD) { 131 /* 132 * SIG_IGN on SIGCHLD on some os's means do not wait 133 * but reap automaticallyi 134 */ 135 msyslog(LOG_ERR, "error waiting on child %d: %m", c->pid); 136 } 137 c->pid = 0; 138 } 139 } 140 141 /* 142 * req_child_exit() runs in the parent. 143 */ 144 int 145 req_child_exit( 146 blocking_child * c 147 ) 148 { 149 if (-1 != c->req_write_pipe) { 150 close(c->req_write_pipe); 151 c->req_write_pipe = -1; 152 return 0; 153 } 154 /* Closing the pipe forces the child to exit */ 155 harvest_child_status(c); 156 return -1; 157 } 158 159 160 /* 161 * cleanup_after_child() runs in parent. 162 */ 163 static void 164 cleanup_after_child( 165 blocking_child * c 166 ) 167 { 168 harvest_child_status(c); 169 if (-1 != c->resp_read_pipe) { 170 (*addremove_io_fd)(c->resp_read_pipe, c->ispipe, TRUE); 171 close(c->resp_read_pipe); 172 c->resp_read_pipe = -1; 173 } 174 c->resp_read_ctx = NULL; 175 DEBUG_INSIST(-1 == c->req_read_pipe); 176 DEBUG_INSIST(-1 == c->resp_write_pipe); 177 c->reusable = TRUE; 178 } 179 180 181 static void 182 send_worker_home_atexit(void) 183 { 184 u_int idx; 185 blocking_child * c; 186 187 if (worker_process) 188 return; 189 190 for (idx = 0; idx < blocking_children_alloc; idx++) { 191 c = blocking_children[idx]; 192 if (NULL == c) 193 continue; 194 req_child_exit(c); 195 } 196 } 197 198 199 int 200 send_blocking_req_internal( 201 blocking_child * c, 202 blocking_pipe_header * hdr, 203 void * data 204 ) 205 { 206 int octets; 207 int rc; 208 209 DEBUG_REQUIRE(hdr != NULL); 210 DEBUG_REQUIRE(data != NULL); 211 DEBUG_REQUIRE(BLOCKING_REQ_MAGIC == hdr->magic_sig); 212 213 if (-1 == c->req_write_pipe) { 214 fork_blocking_child(c); 215 DEBUG_INSIST(-1 != c->req_write_pipe); 216 } 217 218 octets = sizeof(*hdr); 219 rc = write(c->req_write_pipe, hdr, octets); 220 221 if (rc == octets) { 222 octets = hdr->octets - sizeof(*hdr); 223 rc = write(c->req_write_pipe, data, octets); 224 225 if (rc == octets) 226 return 0; 227 } 228 229 if (rc < 0) 230 msyslog(LOG_ERR, 231 "send_blocking_req_internal: pipe write: %m"); 232 else 233 msyslog(LOG_ERR, 234 "send_blocking_req_internal: short write %d of %d", 235 rc, octets); 236 237 /* Fatal error. Clean up the child process. */ 238 req_child_exit(c); 239 exit(1); /* otherwise would be return -1 */ 240 } 241 242 243 blocking_pipe_header * 244 receive_blocking_req_internal( 245 blocking_child * c 246 ) 247 { 248 blocking_pipe_header hdr; 249 blocking_pipe_header * req; 250 int rc; 251 long octets; 252 253 DEBUG_REQUIRE(-1 != c->req_read_pipe); 254 255 req = NULL; 256 257 do { 258 rc = read(c->req_read_pipe, &hdr, sizeof(hdr)); 259 } while (rc < 0 && EINTR == errno); 260 261 if (rc < 0) { 262 msyslog(LOG_ERR, 263 "receive_blocking_req_internal: pipe read %m"); 264 } else if (0 == rc) { 265 TRACE(4, ("parent closed request pipe, child %d terminating\n", 266 c->pid)); 267 } else if (rc != sizeof(hdr)) { 268 msyslog(LOG_ERR, 269 "receive_blocking_req_internal: short header read %d of %lu", 270 rc, (u_long)sizeof(hdr)); 271 } else { 272 INSIST(sizeof(hdr) < hdr.octets && hdr.octets < 4 * 1024); 273 req = emalloc(hdr.octets); 274 memcpy(req, &hdr, sizeof(*req)); 275 octets = hdr.octets - sizeof(hdr); 276 rc = read(c->req_read_pipe, (char *)req + sizeof(*req), 277 octets); 278 279 if (rc < 0) 280 msyslog(LOG_ERR, 281 "receive_blocking_req_internal: pipe data read %m"); 282 else if (rc != octets) 283 msyslog(LOG_ERR, 284 "receive_blocking_req_internal: short read %d of %ld", 285 rc, octets); 286 else if (BLOCKING_REQ_MAGIC != req->magic_sig) 287 msyslog(LOG_ERR, 288 "receive_blocking_req_internal: packet header mismatch (0x%x)", 289 req->magic_sig); 290 else 291 return req; 292 } 293 294 if (req != NULL) 295 free(req); 296 297 return NULL; 298 } 299 300 301 int 302 send_blocking_resp_internal( 303 blocking_child * c, 304 blocking_pipe_header * resp 305 ) 306 { 307 long octets; 308 int rc; 309 310 DEBUG_REQUIRE(-1 != c->resp_write_pipe); 311 312 octets = resp->octets; 313 rc = write(c->resp_write_pipe, resp, octets); 314 free(resp); 315 316 if (octets == rc) 317 return 0; 318 319 if (rc < 0) 320 TRACE(1, ("send_blocking_resp_internal: pipe write %m\n")); 321 else 322 TRACE(1, ("send_blocking_resp_internal: short write %d of %ld\n", 323 rc, octets)); 324 325 return -1; 326 } 327 328 329 blocking_pipe_header * 330 receive_blocking_resp_internal( 331 blocking_child * c 332 ) 333 { 334 blocking_pipe_header hdr; 335 blocking_pipe_header * resp; 336 int rc; 337 long octets; 338 339 DEBUG_REQUIRE(c->resp_read_pipe != -1); 340 341 resp = NULL; 342 rc = read(c->resp_read_pipe, &hdr, sizeof(hdr)); 343 344 if (rc < 0) { 345 TRACE(1, ("receive_blocking_resp_internal: pipe read %m\n")); 346 } else if (0 == rc) { 347 /* this is the normal child exited indication */ 348 } else if (rc != sizeof(hdr)) { 349 TRACE(1, ("receive_blocking_resp_internal: short header read %d of %lu\n", 350 rc, (u_long)sizeof(hdr))); 351 } else if (BLOCKING_RESP_MAGIC != hdr.magic_sig) { 352 TRACE(1, ("receive_blocking_resp_internal: header mismatch (0x%x)\n", 353 hdr.magic_sig)); 354 } else { 355 INSIST(sizeof(hdr) < hdr.octets && 356 hdr.octets < 16 * 1024); 357 resp = emalloc(hdr.octets); 358 memcpy(resp, &hdr, sizeof(*resp)); 359 octets = hdr.octets - sizeof(hdr); 360 rc = read(c->resp_read_pipe, 361 (char *)resp + sizeof(*resp), 362 octets); 363 364 if (rc < 0) 365 TRACE(1, ("receive_blocking_resp_internal: pipe data read %m\n")); 366 else if (rc < octets) 367 TRACE(1, ("receive_blocking_resp_internal: short read %d of %ld\n", 368 rc, octets)); 369 else 370 return resp; 371 } 372 373 cleanup_after_child(c); 374 375 if (resp != NULL) 376 free(resp); 377 378 return NULL; 379 } 380 381 382 #if defined(HAVE_DROPROOT) && defined(WORK_FORK) 383 void 384 fork_deferred_worker(void) 385 { 386 u_int idx; 387 blocking_child * c; 388 389 REQUIRE(droproot && root_dropped); 390 391 for (idx = 0; idx < blocking_children_alloc; idx++) { 392 c = blocking_children[idx]; 393 if (NULL == c) 394 continue; 395 if (-1 != c->req_write_pipe && 0 == c->pid) 396 fork_blocking_child(c); 397 } 398 } 399 #endif 400 401 402 static void 403 fork_blocking_child( 404 blocking_child * c 405 ) 406 { 407 static int atexit_installed; 408 static int blocking_pipes[4] = { -1, -1, -1, -1 }; 409 int rc; 410 int was_pipe; 411 int is_pipe; 412 int saved_errno = 0; 413 int childpid; 414 int keep_fd; 415 int fd; 416 417 /* 418 * parent and child communicate via a pair of pipes. 419 * 420 * 0 child read request 421 * 1 parent write request 422 * 2 parent read response 423 * 3 child write response 424 */ 425 if (-1 == c->req_write_pipe) { 426 rc = pipe_socketpair(&blocking_pipes[0], &was_pipe); 427 if (0 != rc) { 428 saved_errno = errno; 429 } else { 430 rc = pipe_socketpair(&blocking_pipes[2], &is_pipe); 431 if (0 != rc) { 432 saved_errno = errno; 433 close(blocking_pipes[0]); 434 close(blocking_pipes[1]); 435 } else { 436 INSIST(was_pipe == is_pipe); 437 } 438 } 439 if (0 != rc) { 440 errno = saved_errno; 441 msyslog(LOG_ERR, "unable to create worker pipes: %m"); 442 exit(1); 443 } 444 445 /* 446 * Move the descriptors the parent will keep open out of the 447 * low descriptors preferred by C runtime buffered FILE *. 448 */ 449 c->req_write_pipe = move_fd(blocking_pipes[1]); 450 c->resp_read_pipe = move_fd(blocking_pipes[2]); 451 /* 452 * wake any worker child on orderly shutdown of the 453 * daemon so that it can notice the broken pipes and 454 * go away promptly. 455 */ 456 if (!atexit_installed) { 457 atexit(&send_worker_home_atexit); 458 atexit_installed = TRUE; 459 } 460 } 461 462 #ifdef HAVE_DROPROOT 463 /* defer the fork until after root is dropped */ 464 if (droproot && !root_dropped) 465 return; 466 #endif 467 if (syslog_file != NULL) 468 fflush(syslog_file); 469 fflush(stdout); 470 fflush(stderr); 471 472 signal_no_reset(SIGCHLD, SIG_IGN); 473 474 childpid = fork(); 475 if (-1 == childpid) { 476 msyslog(LOG_ERR, "unable to fork worker: %m"); 477 exit(1); 478 } 479 480 if (childpid) { 481 /* this is the parent */ 482 TRACE(1, ("forked worker child (pid %d)\n", childpid)); 483 c->pid = childpid; 484 c->ispipe = is_pipe; 485 486 /* close the child's pipe descriptors. */ 487 close(blocking_pipes[0]); 488 close(blocking_pipes[3]); 489 490 memset(blocking_pipes, -1, sizeof(blocking_pipes)); 491 492 /* wire into I/O loop */ 493 (*addremove_io_fd)(c->resp_read_pipe, is_pipe, FALSE); 494 495 return; /* parent returns */ 496 } 497 498 /* 499 * The parent gets the child pid as the return value of fork(). 500 * The child must work for it. 501 */ 502 c->pid = getpid(); 503 worker_process = TRUE; 504 505 /* 506 * In the child, close all files except stdin, stdout, stderr, 507 * and the two child ends of the pipes. 508 */ 509 DEBUG_INSIST(-1 == c->req_read_pipe); 510 DEBUG_INSIST(-1 == c->resp_write_pipe); 511 c->req_read_pipe = blocking_pipes[0]; 512 c->resp_write_pipe = blocking_pipes[3]; 513 514 kill_asyncio(0); 515 closelog(); 516 if (syslog_file != NULL) { 517 fclose(syslog_file); 518 syslog_file = NULL; 519 syslogit = TRUE; 520 } 521 keep_fd = max(c->req_read_pipe, c->resp_write_pipe); 522 for (fd = 3; fd < keep_fd; fd++) 523 if (fd != c->req_read_pipe && 524 fd != c->resp_write_pipe) 525 close(fd); 526 close_all_beyond(keep_fd); 527 /* 528 * We get signals from refclock serial I/O on NetBSD in the 529 * worker if we do not reset SIGIO's handler to the default. 530 * It is not conditionalized for NetBSD alone because on 531 * systems where it is not needed, it is harmless, and that 532 * allows us to handle unknown others with NetBSD behavior. 533 * [Bug 1386] 534 */ 535 #if defined(USE_SIGIO) 536 signal_no_reset(SIGIO, SIG_DFL); 537 #elif defined(USE_SIGPOLL) 538 signal_no_reset(SIGPOLL, SIG_DFL); 539 #endif 540 signal_no_reset(SIGHUP, worker_sighup); 541 init_logging("ntp_intres", 0, FALSE); 542 setup_logfile(NULL); 543 544 /* 545 * And now back to the portable code 546 */ 547 exit_worker(blocking_child_common(c)); 548 } 549 550 551 #else /* !WORK_FORK follows */ 552 char work_fork_nonempty_compilation_unit; 553 #endif 554