s6

Mirror/fork of https://skarnet.org/software/s6/
git clone https://ccx.te2000.cz/git/s6
Log | Files | Refs | README | LICENSE

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, &notif)) 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 }