1 /* $NetBSD: work_fork.c,v 1.6 2015/07/17 15:17:07 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 msyslog(LOG_ERR, "error waiting on child %d: %m", c->pid); 131 c->pid = 0; 132 } 133 } 134 135 /* 136 * req_child_exit() runs in the parent. 137 */ 138 int 139 req_child_exit( 140 blocking_child * c 141 ) 142 { 143 if (-1 != c->req_write_pipe) { 144 close(c->req_write_pipe); 145 c->req_write_pipe = -1; 146 return 0; 147 } 148 /* Closing the pipe forces the child to exit */ 149 harvest_child_status(c); 150 return -1; 151 } 152 153 154 /* 155 * cleanup_after_child() runs in parent. 156 */ 157 static void 158 cleanup_after_child( 159 blocking_child * c 160 ) 161 { 162 harvest_child_status(c); 163 if (-1 != c->resp_read_pipe) { 164 (*addremove_io_fd)(c->resp_read_pipe, c->ispipe, TRUE); 165 close(c->resp_read_pipe); 166 c->resp_read_pipe = -1; 167 } 168 c->resp_read_ctx = NULL; 169 DEBUG_INSIST(-1 == c->req_read_pipe); 170 DEBUG_INSIST(-1 == c->resp_write_pipe); 171 c->reusable = TRUE; 172 } 173 174 175 static void 176 send_worker_home_atexit(void) 177 { 178 u_int idx; 179 blocking_child * c; 180 181 if (worker_process) 182 return; 183 184 for (idx = 0; idx < blocking_children_alloc; idx++) { 185 c = blocking_children[idx]; 186 if (NULL == c) 187 continue; 188 req_child_exit(c); 189 } 190 } 191 192 193 int 194 send_blocking_req_internal( 195 blocking_child * c, 196 blocking_pipe_header * hdr, 197 void * data 198 ) 199 { 200 int octets; 201 int rc; 202 203 DEBUG_REQUIRE(hdr != NULL); 204 DEBUG_REQUIRE(data != NULL); 205 DEBUG_REQUIRE(BLOCKING_REQ_MAGIC == hdr->magic_sig); 206 207 if (-1 == c->req_write_pipe) { 208 fork_blocking_child(c); 209 DEBUG_INSIST(-1 != c->req_write_pipe); 210 } 211 212 octets = sizeof(*hdr); 213 rc = write(c->req_write_pipe, hdr, octets); 214 215 if (rc == octets) { 216 octets = hdr->octets - sizeof(*hdr); 217 rc = write(c->req_write_pipe, data, octets); 218 219 if (rc == octets) 220 return 0; 221 } 222 223 if (rc < 0) 224 msyslog(LOG_ERR, 225 "send_blocking_req_internal: pipe write: %m"); 226 else 227 msyslog(LOG_ERR, 228 "send_blocking_req_internal: short write %d of %d", 229 rc, octets); 230 231 /* Fatal error. Clean up the child process. */ 232 req_child_exit(c); 233 exit(1); /* otherwise would be return -1 */ 234 } 235 236 237 blocking_pipe_header * 238 receive_blocking_req_internal( 239 blocking_child * c 240 ) 241 { 242 blocking_pipe_header hdr; 243 blocking_pipe_header * req; 244 int rc; 245 long octets; 246 247 DEBUG_REQUIRE(-1 != c->req_read_pipe); 248 249 req = NULL; 250 251 do { 252 rc = read(c->req_read_pipe, &hdr, sizeof(hdr)); 253 } while (rc < 0 && EINTR == errno); 254 255 if (rc < 0) { 256 msyslog(LOG_ERR, 257 "receive_blocking_req_internal: pipe read %m"); 258 } else if (0 == rc) { 259 TRACE(4, ("parent closed request pipe, child %d terminating\n", 260 c->pid)); 261 } else if (rc != sizeof(hdr)) { 262 msyslog(LOG_ERR, 263 "receive_blocking_req_internal: short header read %d of %lu", 264 rc, (u_long)sizeof(hdr)); 265 } else { 266 INSIST(sizeof(hdr) < hdr.octets && hdr.octets < 4 * 1024); 267 req = emalloc(hdr.octets); 268 memcpy(req, &hdr, sizeof(*req)); 269 octets = hdr.octets - sizeof(hdr); 270 rc = read(c->req_read_pipe, (char *)req + sizeof(*req), 271 octets); 272 273 if (rc < 0) 274 msyslog(LOG_ERR, 275 "receive_blocking_req_internal: pipe data read %m"); 276 else if (rc != octets) 277 msyslog(LOG_ERR, 278 "receive_blocking_req_internal: short read %d of %ld", 279 rc, octets); 280 else if (BLOCKING_REQ_MAGIC != req->magic_sig) 281 msyslog(LOG_ERR, 282 "receive_blocking_req_internal: packet header mismatch (0x%x)", 283 req->magic_sig); 284 else 285 return req; 286 } 287 288 if (req != NULL) 289 free(req); 290 291 return NULL; 292 } 293 294 295 int 296 send_blocking_resp_internal( 297 blocking_child * c, 298 blocking_pipe_header * resp 299 ) 300 { 301 long octets; 302 int rc; 303 304 DEBUG_REQUIRE(-1 != c->resp_write_pipe); 305 306 octets = resp->octets; 307 rc = write(c->resp_write_pipe, resp, octets); 308 free(resp); 309 310 if (octets == rc) 311 return 0; 312 313 if (rc < 0) 314 TRACE(1, ("send_blocking_resp_internal: pipe write %m\n")); 315 else 316 TRACE(1, ("send_blocking_resp_internal: short write %d of %ld\n", 317 rc, octets)); 318 319 return -1; 320 } 321 322 323 blocking_pipe_header * 324 receive_blocking_resp_internal( 325 blocking_child * c 326 ) 327 { 328 blocking_pipe_header hdr; 329 blocking_pipe_header * resp; 330 int rc; 331 long octets; 332 333 DEBUG_REQUIRE(c->resp_read_pipe != -1); 334 335 resp = NULL; 336 rc = read(c->resp_read_pipe, &hdr, sizeof(hdr)); 337 338 if (rc < 0) { 339 TRACE(1, ("receive_blocking_resp_internal: pipe read %m\n")); 340 } else if (0 == rc) { 341 /* this is the normal child exited indication */ 342 } else if (rc != sizeof(hdr)) { 343 TRACE(1, ("receive_blocking_resp_internal: short header read %d of %lu\n", 344 rc, (u_long)sizeof(hdr))); 345 } else if (BLOCKING_RESP_MAGIC != hdr.magic_sig) { 346 TRACE(1, ("receive_blocking_resp_internal: header mismatch (0x%x)\n", 347 hdr.magic_sig)); 348 } else { 349 INSIST(sizeof(hdr) < hdr.octets && 350 hdr.octets < 16 * 1024); 351 resp = emalloc(hdr.octets); 352 memcpy(resp, &hdr, sizeof(*resp)); 353 octets = hdr.octets - sizeof(hdr); 354 rc = read(c->resp_read_pipe, 355 (char *)resp + sizeof(*resp), 356 octets); 357 358 if (rc < 0) 359 TRACE(1, ("receive_blocking_resp_internal: pipe data read %m\n")); 360 else if (rc < octets) 361 TRACE(1, ("receive_blocking_resp_internal: short read %d of %ld\n", 362 rc, octets)); 363 else 364 return resp; 365 } 366 367 cleanup_after_child(c); 368 369 if (resp != NULL) 370 free(resp); 371 372 return NULL; 373 } 374 375 376 #if defined(HAVE_DROPROOT) && defined(WORK_FORK) 377 void 378 fork_deferred_worker(void) 379 { 380 u_int idx; 381 blocking_child * c; 382 383 REQUIRE(droproot && root_dropped); 384 385 for (idx = 0; idx < blocking_children_alloc; idx++) { 386 c = blocking_children[idx]; 387 if (NULL == c) 388 continue; 389 if (-1 != c->req_write_pipe && 0 == c->pid) 390 fork_blocking_child(c); 391 } 392 } 393 #endif 394 395 396 static void 397 fork_blocking_child( 398 blocking_child * c 399 ) 400 { 401 static int atexit_installed; 402 static int blocking_pipes[4] = { -1, -1, -1, -1 }; 403 int rc; 404 int was_pipe; 405 int is_pipe; 406 int saved_errno = 0; 407 int childpid; 408 int keep_fd; 409 int fd; 410 411 /* 412 * parent and child communicate via a pair of pipes. 413 * 414 * 0 child read request 415 * 1 parent write request 416 * 2 parent read response 417 * 3 child write response 418 */ 419 if (-1 == c->req_write_pipe) { 420 rc = pipe_socketpair(&blocking_pipes[0], &was_pipe); 421 if (0 != rc) { 422 saved_errno = errno; 423 } else { 424 rc = pipe_socketpair(&blocking_pipes[2], &is_pipe); 425 if (0 != rc) { 426 saved_errno = errno; 427 close(blocking_pipes[0]); 428 close(blocking_pipes[1]); 429 } else { 430 INSIST(was_pipe == is_pipe); 431 } 432 } 433 if (0 != rc) { 434 errno = saved_errno; 435 msyslog(LOG_ERR, "unable to create worker pipes: %m"); 436 exit(1); 437 } 438 439 /* 440 * Move the descriptors the parent will keep open out of the 441 * low descriptors preferred by C runtime buffered FILE *. 442 */ 443 c->req_write_pipe = move_fd(blocking_pipes[1]); 444 c->resp_read_pipe = move_fd(blocking_pipes[2]); 445 /* 446 * wake any worker child on orderly shutdown of the 447 * daemon so that it can notice the broken pipes and 448 * go away promptly. 449 */ 450 if (!atexit_installed) { 451 atexit(&send_worker_home_atexit); 452 atexit_installed = TRUE; 453 } 454 } 455 456 #ifdef HAVE_DROPROOT 457 /* defer the fork until after root is dropped */ 458 if (droproot && !root_dropped) 459 return; 460 #endif 461 if (syslog_file != NULL) 462 fflush(syslog_file); 463 fflush(stdout); 464 fflush(stderr); 465 466 signal_no_reset(SIGCHLD, SIG_IGN); 467 468 childpid = fork(); 469 if (-1 == childpid) { 470 msyslog(LOG_ERR, "unable to fork worker: %m"); 471 exit(1); 472 } 473 474 if (childpid) { 475 /* this is the parent */ 476 TRACE(1, ("forked worker child (pid %d)\n", childpid)); 477 c->pid = childpid; 478 c->ispipe = is_pipe; 479 480 /* close the child's pipe descriptors. */ 481 close(blocking_pipes[0]); 482 close(blocking_pipes[3]); 483 484 memset(blocking_pipes, -1, sizeof(blocking_pipes)); 485 486 /* wire into I/O loop */ 487 (*addremove_io_fd)(c->resp_read_pipe, is_pipe, FALSE); 488 489 return; /* parent returns */ 490 } 491 492 /* 493 * The parent gets the child pid as the return value of fork(). 494 * The child must work for it. 495 */ 496 c->pid = getpid(); 497 worker_process = TRUE; 498 499 /* 500 * In the child, close all files except stdin, stdout, stderr, 501 * and the two child ends of the pipes. 502 */ 503 DEBUG_INSIST(-1 == c->req_read_pipe); 504 DEBUG_INSIST(-1 == c->resp_write_pipe); 505 c->req_read_pipe = blocking_pipes[0]; 506 c->resp_write_pipe = blocking_pipes[3]; 507 508 kill_asyncio(0); 509 closelog(); 510 if (syslog_file != NULL) { 511 fclose(syslog_file); 512 syslog_file = NULL; 513 syslogit = TRUE; 514 } 515 keep_fd = max(c->req_read_pipe, c->resp_write_pipe); 516 for (fd = 3; fd < keep_fd; fd++) 517 if (fd != c->req_read_pipe && 518 fd != c->resp_write_pipe) 519 close(fd); 520 close_all_beyond(keep_fd); 521 /* 522 * We get signals from refclock serial I/O on NetBSD in the 523 * worker if we do not reset SIGIO's handler to the default. 524 * It is not conditionalized for NetBSD alone because on 525 * systems where it is not needed, it is harmless, and that 526 * allows us to handle unknown others with NetBSD behavior. 527 * [Bug 1386] 528 */ 529 #if defined(USE_SIGIO) 530 signal_no_reset(SIGIO, SIG_DFL); 531 #elif defined(USE_SIGPOLL) 532 signal_no_reset(SIGPOLL, SIG_DFL); 533 #endif 534 signal_no_reset(SIGHUP, worker_sighup); 535 init_logging("ntp_intres", 0, FALSE); 536 setup_logfile(NULL); 537 538 /* 539 * And now back to the portable code 540 */ 541 exit_worker(blocking_child_common(c)); 542 } 543 544 545 #else /* !WORK_FORK follows */ 546 char work_fork_nonempty_compilation_unit; 547 #endif 548