s6-svscan.c (19257B)
1 /* ISC license. */ 2 3 #include <string.h> 4 #include <sys/stat.h> 5 #include <sys/wait.h> 6 #include <unistd.h> 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <signal.h> 10 11 #include <skalibs/posixplz.h> 12 #include <skalibs/uint32.h> 13 #include <skalibs/allreadwrite.h> 14 #include <skalibs/sgetopt.h> 15 #include <skalibs/types.h> 16 #include <skalibs/strerr.h> 17 #include <skalibs/tai.h> 18 #include <skalibs/iopause.h> 19 #include <skalibs/devino.h> 20 #include <skalibs/cspawn.h> 21 #include <skalibs/djbunix.h> 22 #include <skalibs/direntry.h> 23 #include <skalibs/sig.h> 24 #include <skalibs/selfpipe.h> 25 #include <skalibs/exec.h> 26 #include <skalibs/bitarray.h> 27 #include <skalibs/genset.h> 28 #include <skalibs/avltreen.h> 29 30 #include <s6/config.h> 31 #include <s6/supervise.h> 32 33 #include <skalibs/posixishard.h> 34 35 #define USAGE "s6-svscan [ -c services_max | -C services_max ] [ -L name_max ] [ -t timeout ] [ -d notif ] [ -X consoleholder ] [ dir ]" 36 #define dieusage() strerr_dieusage(100, USAGE) 37 38 #define CTL S6_SVSCAN_CTLDIR "/control" 39 #define LCK S6_SVSCAN_CTLDIR "/lock" 40 #define FINISH_PROG S6_SVSCAN_CTLDIR "/finish" 41 #define CRASH_PROG S6_SVSCAN_CTLDIR "/crash" 42 #define SIGNAL_PROG S6_SVSCAN_CTLDIR "/SIG" 43 #define SIGNAL_PROG_LEN (sizeof(SIGNAL_PROG) - 1) 44 #define SPECIAL_LOGGER_SERVICE "s6-svscan-log" 45 46 typedef struct service_s service, *service_ref ; 47 struct service_s 48 { 49 devino devino ; 50 pid_t pid ; 51 tain start ; 52 int p ; 53 uint32_t peer ; 54 } ; 55 56 struct flags_s 57 { 58 uint8_t cont : 1 ; 59 uint8_t waitall : 1 ; 60 } ; 61 62 static unsigned int consoleholder = 0 ; 63 static struct flags_s flags = { .cont = 1, .waitall = 0 } ; 64 65 static uint32_t namemax = 251 ; 66 static char *names ; 67 #define NAME(i) (names + (i) * (namemax + 5)) 68 69 static genset *services ; 70 #define SERVICE(i) genset_p(service, services, (i)) 71 static uint32_t max = 1000 ; 72 static uint32_t special ; 73 74 static avltreen *by_pid ; 75 static avltreen *by_devino ; 76 static char *active ; 77 78 static tain scan_deadline = TAIN_EPOCH ; 79 static tain start_deadline = TAIN_INFINITE ; 80 static tain scantto = TAIN_INFINITE_RELATIVE ; 81 82 83 /* Tree management */ 84 85 static void *bydevino_dtok (uint32_t d, void *aux) 86 { 87 genset *g = aux ; 88 return &genset_p(service, g, d)->devino ; 89 } 90 91 static int bydevino_cmp (void const *a, void const *b, void *aux) 92 { 93 (void)aux ; 94 return devino_cmp(a, b) ; 95 } 96 97 static void *bypid_dtok (uint32_t d, void *aux) 98 { 99 genset *g = aux ; 100 return &genset_p(service, g, d)->pid ; 101 } 102 103 static int bypid_cmp (void const *a, void const *b, void *aux) 104 { 105 (void)aux ; 106 pid_t const *aa = a ; 107 pid_t const *bb = b ; 108 return *aa < *bb ? -1 : *aa > *bb ; 109 } 110 111 112 /* On-exit utility */ 113 114 static void restore_console (void) 115 { 116 if (consoleholder) 117 { 118 fd_move(2, consoleholder) ; 119 if (fd_copy(1, 2) < 0) strerr_warnwu1sys("restore stdout") ; 120 } 121 } 122 123 static void panicnosp (char const *) gccattr_noreturn ; 124 static void panicnosp (char const *errmsg) 125 { 126 char const *eargv[2] = { CRASH_PROG, 0 } ; 127 strerr_warnwu1sys(errmsg) ; 128 strerr_warnw2x("executing into ", eargv[0]) ; 129 execv(eargv[0], (char *const *)eargv) ; 130 strerr_dieexec(errno == ENOENT ? 127 : 126, eargv[0]) ; 131 } 132 133 static void panic (char const *) gccattr_noreturn ; 134 static void panic (char const *errmsg) 135 { 136 int e = errno ; 137 selfpipe_finish() ; 138 restore_console() ; 139 errno = e ; 140 panicnosp(errmsg) ; 141 } 142 143 static int close_pipes_iter (void *data, void *aux) 144 { 145 service *sv = data ; 146 if (sv->p >= 0) close(sv->p) ; 147 (void)aux ; 148 return 1 ; 149 } 150 151 static inline void close_pipes (void) 152 { 153 genset_iter(services, &close_pipes_iter, 0) ; 154 if (special < max) 155 { 156 fd_close(1) ; 157 if (open2("/dev/null", O_WRONLY) < 0) 158 strerr_warnwu1sys("open /dev/null") ; 159 } 160 } 161 162 static inline void waitthem (void) 163 { 164 while (avltreen_len(by_pid)) 165 { 166 int wstat ; 167 pid_t pid = wait_nointr(&wstat) ; 168 if (pid < 0) 169 { 170 strerr_warnwu1sys("wait for all s6-supervise processes") ; 171 break ; 172 } 173 avltreen_delete(by_pid, &pid) ; 174 } 175 } 176 177 178 /* Misc utility */ 179 180 /* 181 what: 182 1 -> kill all services 183 2 -> kill inactive services 184 4 -> send a SIGTERM to loggers instead of SIGHUP 185 8 -> reap 186 16 -> delay killing until the next scan 187 */ 188 189 static inline int is_logger (uint32_t i) 190 { 191 return !!strchr(NAME(i), '/') ; 192 } 193 194 /* Triggered actions: config */ 195 196 static inline void chld (unsigned int *what) 197 { 198 *what |= 8 ; 199 } 200 201 static inline void alrm (unsigned int *what) 202 { 203 *what |= 16 ; 204 tain_copynow(&scan_deadline) ; 205 } 206 207 static inline void abrt (void) 208 { 209 flags.cont = 0 ; 210 flags.waitall = 0 ; 211 } 212 213 static void hup (unsigned int *what) 214 { 215 *what |= 18 ; 216 tain_copynow(&scan_deadline) ; 217 } 218 219 static void term (unsigned int *what) 220 { 221 flags.cont = 0 ; 222 flags.waitall = 1 ; 223 *what |= 3 ; 224 } 225 226 static void quit (unsigned int *what) 227 { 228 flags.cont = 0 ; 229 flags.waitall = 1 ; 230 *what |= 7 ; 231 } 232 233 static void handle_signals (unsigned int *what) 234 { 235 for (;;) 236 { 237 int sig = selfpipe_read() ; 238 switch (sig) 239 { 240 case -1 : panic("selfpipe_read") ; 241 case 0 : return ; 242 case SIGCHLD : chld(what) ; break ; 243 case SIGALRM : alrm(what) ; break ; 244 case SIGABRT : abrt() ; break ; 245 default : 246 { 247 int usebuiltin = 1 ; 248 char const *name = sig_name(sig) ; 249 size_t len = strlen(name) ; 250 char fn[SIGNAL_PROG_LEN + len + 1] ; 251 char const *const newargv[2] = { fn, 0 } ; 252 memcpy(fn, SIGNAL_PROG, SIGNAL_PROG_LEN) ; 253 memcpy(fn + SIGNAL_PROG_LEN, name, len + 1) ; 254 if (access(newargv[0], X_OK) == 0) /* avoids a spawn, don't care about the toctou */ 255 { 256 if (cspawn(newargv[0], newargv, (char const **)environ, CSPAWN_FLAGS_SELFPIPE_FINISH, 0, 0)) 257 usebuiltin = 0 ; 258 else if (errno != ENOENT) strerr_warnwu2sys("spawn ", newargv[0]) ; 259 } 260 if (usebuiltin) switch (sig) 261 { 262 case SIGHUP : hup(what) ; break ; 263 case SIGINT : 264 case SIGTERM : term(what) ; break ; 265 case SIGQUIT : quit(what) ; break ; 266 } 267 } 268 } 269 } 270 } 271 272 static void handle_control (int fd, unsigned int *what) 273 { 274 for (;;) 275 { 276 char c ; 277 ssize_t r = sanitize_read(fd_read(fd, &c, 1)) ; 278 if (r < 0) panic("read control pipe") ; 279 else if (!r) break ; 280 switch (c) 281 { 282 case 'z' : chld(what) ; break ; 283 case 'a' : alrm(what) ; break ; 284 case 'b' : abrt() ; break ; 285 case 'h' : hup(what) ; break ; 286 case 'i' : 287 case 't' : term(what) ; break ; 288 case 'q' : quit(what) ; break ; 289 case 'n' : *what |= 2 ; break ; 290 case 'N' : *what |= 6 ; break ; 291 default : 292 { 293 char s[2] = { c, 0 } ; 294 strerr_warnw2x("received unknown control command: ", s) ; 295 } 296 } 297 } 298 } 299 300 301 /* Triggered action: killer */ 302 303 static int killthem_iter (void *data, void *aux) 304 { 305 service *sv = data ; 306 unsigned int *what = aux ; 307 uint32_t i = sv - SERVICE(0) ; 308 if ((*what & 1 || !bitarray_peek(active, i)) && sv->pid) 309 kill(sv->pid, *what & (2 << (i == special || is_logger(i))) ? SIGTERM : SIGHUP) ; 310 return 1 ; 311 } 312 313 static inline void killthem (unsigned int *what) 314 { 315 if (*what & 16 || !(*what & 7)) return ; 316 genset_iter(services, &killthem_iter, what) ; 317 *what &= ~7 ; 318 } 319 320 321 /* Triggered action: reaper */ 322 323 /* 324 sv->p values: 325 0+ : this end of the pipe 326 -1 : not a logged service 327 -2 : inactive and peer dead, do not reactivate 328 -3 : reactivation wanted, trigger rescan on death 329 */ 330 331 static void remove_service (service *sv) 332 { 333 if (sv->peer < max) 334 { 335 service *peer = SERVICE(sv->peer) ; 336 if (peer->p >= 0) 337 { 338 close(peer->p) ; 339 peer->p = -2 ; 340 } 341 peer->peer = max ; 342 } 343 if (sv->p == -3) tain_earliest1(&scan_deadline, &sv->start) ; 344 else if (sv->p >= 0) close(sv->p) ; 345 avltreen_delete(by_devino, &sv->devino) ; 346 genset_delete(services, sv - SERVICE(0)) ; 347 } 348 349 static void reap (unsigned int *what) 350 { 351 if (!(*what & 8)) return ; 352 *what &= ~8 ; 353 for (;;) 354 { 355 uint32_t i ; 356 int wstat ; 357 pid_t pid = wait_nohang(&wstat) ; 358 if (pid < 0) 359 if (errno != ECHILD) panic("wait_nohang") ; 360 else break ; 361 else if (!pid) break ; 362 else if (avltreen_search(by_pid, &pid, &i)) 363 { 364 service *sv = SERVICE(i) ; 365 avltreen_delete(by_pid, &pid) ; 366 sv->pid = 0 ; 367 if (bitarray_peek(active, i)) tain_earliest1(&start_deadline, &sv->start) ; 368 else remove_service(sv) ; 369 } 370 } 371 } 372 373 374 /* 375 On-timeout action: scanner. 376 (This can be triggered, but the trigger just sets the timeout to 0.) 377 It's on-timeout because it can fail and get rescheduled for later. 378 */ 379 380 static int check (char const *name, uint32_t prod, char *act) 381 { 382 struct stat st ; 383 devino di ; 384 uint32_t i ; 385 service *sv ; 386 if (stat(name, &st) == -1) 387 { 388 if (prod < max && errno == ENOENT) 389 { 390 if (SERVICE(prod)->peer < max) 391 strerr_warnw3x("logger for service ", NAME(prod), " has been moved") ; 392 return max ; 393 } 394 strerr_warnwu2sys("stat ", name) ; 395 return -4 ; 396 } 397 if (!S_ISDIR(st.st_mode)) return max ; 398 di.dev = st.st_dev ; 399 di.ino = st.st_ino ; 400 if (avltreen_search(by_devino, &di, &i)) 401 { 402 sv = SERVICE(i) ; 403 if (sv->peer < max) 404 { 405 if (prod < max && prod != sv->peer) 406 { 407 strerr_warnw3x("old service ", name, " still exists, waiting") ; 408 return -10 ; 409 } 410 if (sv->p == -1) 411 { 412 sv->p = -2 ; 413 return i ; 414 } 415 } 416 } 417 else 418 { 419 i = genset_new(services) ; 420 if (i >= max) 421 { 422 strerr_warnwu3x("start supervisor for ", name, ": too many services") ; 423 return -60 ; 424 } 425 sv = SERVICE(i) ; 426 sv->devino = di ; 427 sv->pid = 0 ; 428 tain_copynow(&sv->start) ; 429 tain_copynow(&start_deadline) ; /* XXX: may cause a superfluous start if logger fails, oh well */ 430 if (prod >= max) 431 { 432 sv->peer = max ; 433 sv->p = -1 ; 434 if (special >= max && !strcmp(name, SPECIAL_LOGGER_SERVICE)) special = i ; 435 } 436 else 437 { 438 int p[2] ; 439 if (pipecoe(p) == -1) 440 { 441 strerr_warnwu2sys("create pipe for ", name) ; 442 genset_delete(services, i) ; 443 return -3 ; 444 } 445 sv->peer = prod ; 446 sv->p = p[0] ; 447 SERVICE(prod)->peer = i ; 448 SERVICE(prod)->p = p[1] ; 449 } 450 avltreen_insert(by_devino, i) ; 451 } 452 strcpy(NAME(i), name) ; 453 bitarray_set(act, i) ; 454 return i ; 455 } 456 457 static void set_scan_timeout (unsigned int n) 458 { 459 tain a ; 460 tain_addsec_g(&a, n) ; 461 tain_earliest1(&scan_deadline, &a) ; 462 } 463 464 static int remove_deadinactive_iter (void *data, void *aux) 465 { 466 service *sv = data ; 467 uint32_t *n = aux ; 468 if (!bitarray_peek(active, sv - SERVICE(0))) 469 { 470 if (!sv->pid) remove_service(sv) ; 471 if (!--n) return 0 ; 472 } 473 return 1 ; 474 } 475 476 static void scan (unsigned int *what) 477 { 478 DIR *dir = opendir(".") ; 479 char tmpactive[bitarray_div8(max)] ; 480 tain_add_g(&scan_deadline, &scantto) ; 481 memset(tmpactive, 0, bitarray_div8(max)) ; 482 if (!dir) 483 { 484 strerr_warnwu1sys("opendir .") ; 485 set_scan_timeout(5) ; 486 return ; 487 } 488 for (;;) 489 { 490 int i ; 491 size_t len ; 492 direntry *d ; 493 errno = 0 ; 494 d = readdir(dir) ; 495 if (!d) break ; 496 if (d->d_name[0] == '.') continue ; 497 len = strlen(d->d_name) ; 498 if (len > namemax) 499 { 500 strerr_warnw2x("name too long - not spawning service: ", d->d_name) ; 501 continue ; 502 } 503 i = check(d->d_name, max, tmpactive) ; 504 if (i < 0) 505 { 506 dir_close(dir) ; 507 set_scan_timeout(-i) ; 508 return ; 509 } 510 if (i < max) 511 { 512 char logname[len + 5] ; 513 memcpy(logname, d->d_name, len) ; 514 memcpy(logname + len, "/log", 5) ; 515 if (check(logname, i, tmpactive) < 0) 516 { 517 genset_delete(services, i) ; 518 dir_close(dir) ; 519 set_scan_timeout(-i) ; 520 return ; 521 } 522 } 523 } 524 dir_close(dir) ; 525 if (errno) 526 { 527 strerr_warnwu1sys("readdir .") ; 528 set_scan_timeout(5) ; 529 return ; 530 } 531 memcpy(active, tmpactive, bitarray_div8(max)) ; 532 533 { 534 uint32_t n = genset_n(services) - avltreen_len(by_devino) ; 535 if (n) genset_iter(services, &remove_deadinactive_iter, &n) ; 536 } 537 *what &= ~16 ; 538 } 539 540 541 /* 542 On-timeout action: starter. 543 This cannot be user-triggered. It runs when a service needs to (re)start. 544 */ 545 546 static int start_iter (void *data, void *aux) 547 { 548 service *sv = data ; 549 uint32_t i = sv - SERVICE(0) ; 550 char const *const cargv[3] = { "s6-supervise", NAME(i), 0 } ; 551 cspawn_fileaction fa[2] = 552 { 553 [0] = { .type = CSPAWN_FA_MOVE }, 554 [1] = { .type = CSPAWN_FA_MOVE } 555 } ; 556 size_t j = 0 ; 557 558 if (!bitarray_peek(active, i) 559 || sv->pid 560 || tain_future(&sv->start)) return 1 ; 561 if (sv->peer < max) 562 { 563 fa[j].x.fd2[0] = !is_logger(i) ; 564 fa[j].x.fd2[1] = sv->p ; 565 j++ ; 566 } 567 if (consoleholder && i == special) 568 { 569 fa[j].x.fd2[0] = 2 ; 570 fa[j].x.fd2[1] = consoleholder ; 571 j++ ; 572 } 573 574 sv->pid = cspawn(S6_BINPREFIX "s6-supervise", cargv, (char const *const *)environ, CSPAWN_FLAGS_SELFPIPE_FINISH, fa, j) ; 575 if (!sv->pid) 576 { 577 strerr_warnwu2sys("spawn s6-supervise for ", NAME(i)) ; 578 tain_addsec_g(&start_deadline, 10) ; 579 return 0 ; 580 } 581 avltreen_insert(by_pid, i) ; 582 tain_addsec_g(&sv->start, 1) ; 583 (void)aux ; 584 return 1 ; 585 } 586 587 static inline void start (void) 588 { 589 start_deadline = tain_infinite ; 590 genset_iter(services, &start_iter, 0) ; 591 } 592 593 594 /* Main. */ 595 596 static inline int control_init (void) 597 { 598 mode_t m = umask(0) ; 599 int fdctl, fdlck, r ; 600 if (mkdir(S6_SVSCAN_CTLDIR, 0700) < 0) 601 { 602 struct stat st ; 603 if (errno != EEXIST) 604 strerr_diefu1sys(111, "mkdir " S6_SVSCAN_CTLDIR) ; 605 if (stat(S6_SVSCAN_CTLDIR, &st) < 0) 606 strerr_diefu1sys(111, "stat " S6_SVSCAN_CTLDIR) ; 607 if (!S_ISDIR(st.st_mode)) 608 strerr_dief1x(100, S6_SVSCAN_CTLDIR " exists and is not a directory") ; 609 } 610 611 fdlck = open3(LCK, O_WRONLY | O_NONBLOCK | O_CREAT | O_CLOEXEC, 0600) ; 612 if (fdlck < 0) strerr_diefu1sys(111, "open " LCK) ; 613 r = fd_lock(fdlck, 1, 1) ; 614 if (r < 0) strerr_diefu1sys(111, "lock " LCK) ; 615 if (!r) strerr_dief1x(100, "another instance of s6-svscan is already running on the same directory") ; 616 /* fdlck leaks but it's coe */ 617 618 if (mkfifo(CTL, 0600) < 0) 619 { 620 struct stat st ; 621 if (errno != EEXIST) 622 strerr_diefu1sys(111, "mkfifo " CTL) ; 623 if (stat(CTL, &st) < 0) 624 strerr_diefu1sys(111, "stat " CTL) ; 625 if (!S_ISFIFO(st.st_mode)) 626 strerr_dief1x(100, CTL " is not a FIFO") ; 627 } 628 fdctl = openc_read(CTL) ; 629 if (fdctl < 0) 630 strerr_diefu1sys(111, "open " CTL " for reading") ; 631 r = openc_write(CTL) ; 632 if (r < 0) 633 strerr_diefu1sys(111, "open " CTL " for writing") ; 634 /* r leaks but it's coe */ 635 636 umask(m) ; 637 return fdctl ; 638 } 639 640 int main (int argc, char const *const *argv) 641 { 642 iopause_fd x[2] = { { .fd = -1, .events = IOPAUSE_READ }, { .fd = -1, .events = IOPAUSE_READ } } ; 643 PROG = "s6-svscan" ; 644 645 { 646 subgetopt l = SUBGETOPT_ZERO ; 647 unsigned int notif = 0 ; 648 unsigned int t = 0 ; 649 for (;;) 650 { 651 int opt = subgetopt_r(argc, argv, "c:C:L:t:d:X:", &l) ; 652 if (opt == -1) break ; 653 switch (opt) 654 { 655 case 'c' : if (!uint320_scan(l.arg, &max)) dieusage() ; max <<= 1 ; break ; 656 case 'C' : if (!uint320_scan(l.arg, &max)) dieusage() ; break ; 657 case 'L' : if (!uint320_scan(l.arg, &namemax)) dieusage() ; break ; 658 case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; 659 case 'd' : if (!uint0_scan(l.arg, ¬if)) dieusage() ; break ; 660 case 'X' : if (!uint0_scan(l.arg, &consoleholder)) dieusage() ; break ; 661 default : dieusage() ; 662 } 663 } 664 argc -= l.ind ; argv += l.ind ; 665 if (t) tain_from_millisecs(&scantto, t) ; 666 if (max < 4) max = 4 ; 667 if (max > 160000) max = 160000 ; 668 special = max ; 669 if (namemax < 11) namemax = 11 ; 670 if (namemax > 1019) namemax = 1019 ; 671 672 if (notif) 673 { 674 if (notif < 3) strerr_dief1x(100, "notification fd must be 3 or more") ; 675 if (fcntl(notif, F_GETFD) == -1) strerr_dief1sys(100, "invalid notification fd") ; 676 } 677 if (consoleholder) 678 { 679 if (consoleholder < 3) strerr_dief1x(100, "console holder fd must be 3 or more") ; 680 if (fcntl(consoleholder, F_GETFD) < 0) strerr_dief1sys(100, "invalid console holder fd") ; 681 if (coe(consoleholder) == -1) strerr_diefu1sys(111, "coe console holder") ; 682 } 683 if (!fd_sanitize()) strerr_diefu1x(100, "sanitize standard fds") ; 684 685 if (argc && (chdir(argv[0]) == -1)) strerr_diefu1sys(111, "chdir") ; 686 x[1].fd = control_init() ; 687 x[0].fd = selfpipe_init() ; 688 if (x[0].fd < 0) strerr_diefu1sys(111, "selfpipe_init") ; 689 690 if (!sig_altignore(SIGPIPE)) strerr_diefu1sys(111, "ignore SIGPIPE") ; 691 { 692 sigset_t set ; 693 sigemptyset(&set) ; 694 sigaddset(&set, SIGCHLD) ; 695 sigaddset(&set, SIGALRM) ; 696 sigaddset(&set, SIGABRT) ; 697 sigaddset(&set, SIGHUP) ; 698 sigaddset(&set, SIGINT) ; 699 sigaddset(&set, SIGTERM) ; 700 sigaddset(&set, SIGQUIT) ; 701 sigaddset(&set, SIGUSR1) ; 702 sigaddset(&set, SIGUSR2) ; 703 #ifdef SIGPWR 704 sigaddset(&set, SIGPWR) ; 705 #endif 706 #ifdef SIGWINCH 707 sigaddset(&set, SIGWINCH) ; 708 #endif 709 if (!selfpipe_trapset(&set)) strerr_diefu1sys(111, "trap signals") ; 710 } 711 if (notif) 712 { 713 write(notif, "\n", 1) ; 714 close(notif) ; 715 } 716 } 717 718 { 719 unsigned int what = 0 ; 720 service services_storage[max] ; 721 uint32_t services_freelist[max] ; 722 avlnode bydevino_storage[max] ; 723 uint32_t bydevino_freelist[max] ; 724 avlnode bypid_storage[max] ; 725 uint32_t bypid_freelist[max] ; 726 genset services_info ; 727 avltreen bydevino_info ; 728 avltreen bypid_info ; 729 char name_storage[max * (namemax + 5)] ; 730 char active_storage[bitarray_div8(max)] ; 731 732 GENSET_init(&services_info, service, services_storage, services_freelist, max) ; 733 avltreen_init(&bydevino_info, bydevino_storage, bydevino_freelist, max, &bydevino_dtok, &bydevino_cmp, &services_info) ; 734 avltreen_init(&bypid_info, bypid_storage, bypid_freelist, max, &bypid_dtok, &bypid_cmp, &services_info) ; 735 services = &services_info ; 736 by_devino = &bydevino_info ; 737 by_pid = &bypid_info ; 738 names = name_storage ; 739 active = active_storage ; 740 741 tain_now_set_stopwatch_g() ; 742 743 /* From now on, we must not die. 744 Temporize on recoverable errors, and panic on serious ones. */ 745 746 while (flags.cont) 747 { 748 int r ; 749 tain deadline = scan_deadline ; 750 tain_earliest1(&deadline, &start_deadline) ; 751 r = iopause_g(x, 2, &deadline) ; 752 if (r < 0) panic("iopause") ; 753 else if (!r) 754 { 755 if (!tain_future(&scan_deadline)) scan(&what) ; 756 if (!tain_future(&start_deadline)) start() ; 757 } 758 else 759 { 760 if ((x[0].revents | x[1].revents) & IOPAUSE_EXCEPT) 761 { 762 errno = EIO ; 763 panic("check internal pipes") ; 764 } 765 if (x[0].revents & IOPAUSE_READ) handle_signals(&what) ; 766 if (x[1].revents & IOPAUSE_READ) handle_control(x[1].fd, &what) ; 767 } 768 killthem(&what) ; 769 reap(&what) ; 770 } 771 772 /* Finish phase. */ 773 774 close_pipes() ; 775 restore_console() ; 776 if (flags.waitall) waitthem() ; 777 selfpipe_finish() ; 778 } 779 { 780 char const *eargv[2] = { FINISH_PROG, 0 } ; 781 execv(eargv[0], (char **)eargv) ; 782 if (errno != ENOENT) panicnosp("exec finish script " FINISH_PROG) ; 783 } 784 return 0 ; 785 }