runit

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

runit.c (8653B)


      1 #include <sys/types.h>
      2 #include <sys/reboot.h>
      3 #include <sys/ioctl.h>
      4 #include <sys/stat.h>
      5 #include <signal.h>
      6 #include <unistd.h>
      7 #include <fcntl.h>
      8 #include <poll.h>
      9 #include "runit.h"
     10 #include "sig.h"
     11 #include "strerr.h"
     12 #include "error.h"
     13 #include "coe.h"
     14 #include "ndelay.h"
     15 #include "wait.h"
     16 #include <sys/wait.h>
     17 #include "open.h"
     18 
     19 /* #define DEBUG */
     20 
     21 #define INFO "- runit: "
     22 #define WARNING "- runit: warning: "
     23 #define FATAL "- runit: fatal: "
     24 
     25 static const char * const stage[3] ={
     26   "/etc/runit/1",
     27   "/etc/runit/2",
     28   "/etc/runit/3" };
     29 
     30 static int selfpipe[2];
     31 static int sigc =0;
     32 static int sigi =0;
     33 
     34 static void sig_cont_handler( int s )
     35 {
     36   sigc++;
     37   write(selfpipe[1], "", 1);
     38 }
     39 static void sig_int_handler( int s )
     40 {
     41   sigi++;
     42   write(selfpipe[1], "", 1);
     43 }
     44 static void sig_child_handler( int s ) { write(selfpipe[1], "", 1); }
     45 
     46 int main (int argc, const char * const *argv, char * const *envp)
     47 {
     48   const char * prog[2];
     49   int pid, pid2;
     50   int wstat;
     51   int st;
     52   struct pollfd x;
     53   char ch;
     54   int ttyfd;
     55   struct stat s;
     56 
     57   if (getpid() != 1) strerr_die2x(111, FATAL, "must be run as process no 1.");
     58   setsid();
     59 
     60   sig_block(sig_alarm);
     61   sig_block(sig_child);
     62   sig_catch(sig_child, sig_child_handler);
     63   sig_block(sig_cont);
     64   sig_catch(sig_cont, sig_cont_handler);
     65   sig_block(sig_hangup);
     66   sig_block(sig_int);
     67   sig_catch(sig_int, sig_int_handler);
     68   sig_block(sig_pipe);
     69   sig_block(sig_term);
     70 
     71   /* console */
     72   if ((ttyfd =open_write("/dev/console")) != -1) {
     73     dup2(ttyfd, 0); dup2(ttyfd, 1); dup2(ttyfd, 2);
     74     if (ttyfd > 2) close(ttyfd);
     75   }
     76 
     77   /* create selfpipe */
     78   while (pipe(selfpipe) == -1) {
     79     strerr_warn2(FATAL, "unable to create selfpipe, pausing: ", &strerr_sys);
     80     sleep(5);
     81   }
     82   coe(selfpipe[0]);
     83   coe(selfpipe[1]);
     84   ndelay_on(selfpipe[0]);
     85   ndelay_on(selfpipe[1]);
     86 
     87 #ifdef RB_DISABLE_CAD
     88   /* activate ctrlaltdel handling, glibc, dietlibc */
     89   if (RB_DISABLE_CAD == 0) reboot(0);
     90 #endif
     91 
     92   strerr_warn3(INFO, VERSION, ": booting.", 0);
     93 
     94   /* runit */
     95   for (st =0; st < 3; st++) {
     96     /* if (st == 2) logwtmp("~", "reboot", ""); */
     97     while ((pid =fork()) == -1) {
     98       strerr_warn4(FATAL, "unable to fork for \"", stage[st], "\" pausing: ",
     99                    &strerr_sys);
    100       sleep(5);
    101     }
    102     if (!pid) {
    103       /* child */
    104       prog[0] =stage[st];
    105       prog[1] =0;
    106 
    107       /* stage 1 gets full control of console */
    108       if (st == 0) {
    109         if ((ttyfd =open("/dev/console", O_RDWR)) != -1) {
    110 #ifdef TIOCSCTTY 
    111           ioctl(ttyfd, TIOCSCTTY, (char *)0);
    112 #endif
    113           dup2(ttyfd, 0);
    114           if (ttyfd > 2) close(ttyfd);
    115         }
    116         else
    117           strerr_warn2(WARNING, "unable to open /dev/console: ", &strerr_sys);
    118       }
    119       else
    120         setsid();
    121 
    122       sig_unblock(sig_alarm);
    123       sig_unblock(sig_child);
    124       sig_uncatch(sig_child);
    125       sig_unblock(sig_cont);
    126       sig_ignore(sig_cont);
    127       sig_unblock(sig_hangup);
    128       sig_unblock(sig_int);
    129       sig_uncatch(sig_int);
    130       sig_unblock(sig_pipe);
    131       sig_unblock(sig_term);
    132             
    133       strerr_warn3(INFO, "enter stage: ", stage[st], 0);
    134       execve(*prog, (char const *const *)prog, envp);
    135       strerr_die4sys(0, FATAL, "unable to start child: ", stage[st], ": ");
    136     }
    137 
    138     x.fd =selfpipe[0];
    139     x.events =POLLIN;
    140     for (;;) {
    141       int child;
    142 
    143       sig_unblock(sig_child);
    144       sig_unblock(sig_cont);
    145       sig_unblock(sig_int);
    146       poll(&x, 1, 14000);
    147       sig_block(sig_cont);
    148       sig_block(sig_child);
    149       sig_block(sig_int);
    150       
    151       while (read(selfpipe[0], &ch, 1) == 1) {}
    152       while ((child =waitpid( -1, &wstat, WNOHANG )) > 0)
    153         if (child == pid) break;
    154       if (child == -1) {
    155         strerr_warn2(WARNING, "waitpid, pausing: ", &strerr_sys);
    156         sleep(5);
    157       }
    158 
    159       /* reget stderr */
    160       if ((ttyfd =open_write("/dev/console")) != -1) {
    161         dup2(ttyfd, 2);
    162         if (ttyfd > 2) close(ttyfd);
    163       }
    164 
    165       if (child == pid) {
    166         if (wait_exitcode(wstat) != 0) {
    167           if (wait_crashed(wstat))
    168             strerr_warn3(WARNING, "child crashed: ", stage[st], 0);
    169           else
    170             strerr_warn3(WARNING, "child failed: ", stage[st], 0);
    171           if (st == 0)
    172             /* this is stage 1 */
    173             if (wait_crashed(wstat) || (wait_exitcode(wstat) == 100)) {
    174               strerr_warn3(INFO, "leave stage: ", stage[st], 0);
    175               strerr_warn2(WARNING, "skipping stage 2...", 0);
    176               st++;
    177               break;
    178             }
    179           if (st == 1)
    180             /* this is stage 2 */
    181             if (wait_crashed(wstat) || (wait_exitcode(wstat) == 111)) {
    182               strerr_warn2(WARNING, "killing all processes in stage 2...", 0);
    183               kill(-pid, 9);
    184               sleep(5);
    185               strerr_warn2(WARNING, "restarting.", 0);
    186               st--;
    187               break;
    188             }
    189         }
    190         strerr_warn3(INFO, "leave stage: ", stage[st], 0);
    191         break;
    192       }
    193       if (child != 0) {
    194         /* collect terminated children */
    195         write(selfpipe[1], "", 1);
    196         continue;
    197       }
    198 
    199       /* sig? */
    200       if (!sigc  && !sigi) {
    201 #ifdef DEBUG
    202         strerr_warn2(WARNING, "poll: ", &strerr_sys);
    203 #endif
    204         continue;
    205       }
    206       if (st != 1) {
    207         strerr_warn2(WARNING, "signals only work in stage 2.", 0);
    208         sigc =sigi =0;
    209         continue;
    210       }
    211       if (sigi && (stat(CTRLALTDEL, &s) != -1) && (s.st_mode & S_IXUSR)) {
    212         strerr_warn2(INFO, "ctrl-alt-del request...", 0);
    213         prog[0] =CTRLALTDEL; prog[1] =0;
    214         while ((pid2 =fork()) == -1) {
    215           strerr_warn4(FATAL, "unable to fork for \"", CTRLALTDEL,
    216                        "\" pausing: ", &strerr_sys);
    217           sleep(5);
    218         }
    219         if (!pid2) {
    220           /* child */
    221           strerr_warn3(INFO, "enter stage: ", prog[0], 0);
    222           execve(*prog, (char const *const *) prog, envp);
    223           strerr_die4sys(0, FATAL, "unable to start child: ", prog[0], ": ");
    224         }
    225         if (wait_pid(&wstat, pid2) == -1)
    226           strerr_warn2(FATAL, "wait_pid: ", &strerr_sys);
    227         if (wait_crashed(wstat))
    228           strerr_warn3(WARNING, "child crashed: ", CTRLALTDEL, 0);
    229         strerr_warn3(INFO, "leave stage: ", prog[0], 0);
    230         sigi =0;
    231         sigc++;
    232       }
    233       if (sigc && (stat(STOPIT, &s) != -1) && (s.st_mode & S_IXUSR)) {
    234         int i;
    235         /* unlink(STOPIT); */
    236         chmod(STOPIT, 0);
    237 
    238         /* kill stage 2 */
    239 #ifdef DEBUG
    240         strerr_warn2(WARNING, "sending sigterm...", 0);
    241 #endif
    242         kill(pid, sig_term);
    243         i =0;
    244         while (i < 5) {
    245           if ((child =waitpid( -1, &wstat, WNOHANG )) == pid) {
    246 #ifdef DEBUG
    247             strerr_warn2(WARNING, "stage 2 terminated.", 0);
    248 #endif
    249             pid =0;
    250             break;
    251           }
    252           if (child) continue;
    253           if (child == -1) 
    254             strerr_warn2(WARNING, "waitpid: ", &strerr_sys);
    255 #ifdef DEBUG
    256           strerr_warn2(WARNING, "waiting...", 0);
    257 #endif
    258           sleep(1);
    259           i++;
    260         }
    261         if (pid) {
    262           /* still there */
    263           strerr_warn2(WARNING,
    264                        "stage 2 not terminated, sending sigkill...", 0);
    265           kill(pid, 9);
    266           if (wait_pid(&wstat, pid) == -1)
    267             strerr_warn2(WARNING, "wait_pid: ", &strerr_sys);
    268         }
    269         sigc =0;
    270         strerr_warn3(INFO, "leave stage: ", stage[st], 0);
    271 
    272         /* enter stage 3 */
    273         break;
    274       }
    275       sigc =sigi =0;
    276 #ifdef DEBUG
    277       strerr_warn2(WARNING, "no request.", 0);
    278 #endif
    279     }
    280   }
    281 
    282   /* reget stderr */
    283   if ((ttyfd =open_write("/dev/console")) != -1) {
    284     dup2(ttyfd, 2);
    285     if (ttyfd > 2) close(ttyfd);
    286   }
    287 
    288 #ifdef RB_AUTOBOOT
    289   /* fallthrough stage 3 */
    290   strerr_warn2(INFO, "sending KILL signal to all processes...", 0);
    291   kill(-1, SIGKILL);
    292 
    293   pid =fork();
    294   switch (pid) {
    295   case  0:
    296   case -1:
    297   if ((stat(REBOOT, &s) != -1) && (s.st_mode & S_IXUSR)) {
    298     strerr_warn2(INFO, "system reboot.", 0);
    299     sync();
    300     reboot(RB_AUTOBOOT);
    301   }
    302   else {
    303 #ifdef RB_POWER_OFF
    304     strerr_warn2(INFO, "power off...", 0);
    305     sync();
    306     reboot(RB_POWER_OFF);
    307     sleep(2);
    308 #endif
    309 #ifdef RB_HALT_SYSTEM
    310     strerr_warn2(INFO, "system halt.", 0);
    311     sync();
    312     reboot(RB_HALT_SYSTEM);
    313 #else
    314 #ifdef RB_HALT
    315     strerr_warn2(INFO, "system halt.", 0);
    316     sync();
    317     reboot(RB_HALT);
    318 #else
    319     strerr_warn2(INFO, "system reboot.", 0);
    320     sync();
    321     reboot(RB_AUTOBOOT);
    322 #endif
    323 #endif
    324   }
    325   if (pid == 0) _exit(0);
    326   break;
    327   default:
    328   sig_unblock(sig_child);
    329   while (wait_pid(0, pid) == -1);
    330   }
    331 #endif
    332 
    333   for (;;) sig_pause();
    334   /* not reached */
    335   strerr_die2x(0, INFO, "exit.");
    336   return(0);
    337 }