runit

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

runsv.c (15915B)


      1 #include <sys/types.h>
      2 #include <sys/stat.h>
      3 #include <unistd.h>
      4 #include <stdio.h>
      5 #include <signal.h>
      6 #include <poll.h>
      7 #include "iopause.h"
      8 #include "strerr.h"
      9 #include "error.h"
     10 #include "taia.h"
     11 #include "sig.h"
     12 #include "env.h"
     13 #include "coe.h"
     14 #include "ndelay.h"
     15 #include "fifo.h"
     16 #include "open.h"
     17 #include "lock.h"
     18 #include "wait.h"
     19 #include <sys/wait.h>
     20 #include "fd.h"
     21 #include "buffer.h"
     22 #include "fmt.h"
     23 #include "byte.h"
     24 
     25 #define USAGE " dir"
     26 
     27 static char *progname;
     28 static int selfpipe[2];
     29 
     30 /* state */
     31 #define S_DOWN 0
     32 #define S_RUN 1
     33 #define S_FINISH 2
     34 /* ctrl */
     35 #define C_NOOP 0
     36 #define C_TERM 1
     37 #define C_PAUSE 2
     38 /* want */
     39 #define W_UP 0
     40 #define W_DOWN 1
     41 #define W_EXIT 2
     42 
     43 struct svdir {
     44   int pid;
     45   int state;
     46   int ctrl;
     47   int want;
     48   struct taia start;
     49   int wstat;
     50   int fdlock;
     51   int fdcontrol;
     52   int fdcontrolwrite;
     53   int islog;
     54 };
     55 static struct svdir svd[2];
     56 
     57 static int sigterm =0;
     58 static int haslog =0;
     59 static int pidchanged =1;
     60 static int logpipe[2];
     61 static char *dir;
     62 
     63 static void usage () { strerr_die4x(1, "usage: ", progname, USAGE, "\n"); }
     64 
     65 static void fatal(char *m)
     66 {
     67   strerr_die5sys(111, "runsv ", dir, ": fatal: ", m, ": ");
     68 }
     69 static void fatal2(char *m1, char *m2)
     70 {
     71   strerr_die6sys(111, "runsv ", dir, ": fatal: ", m1, m2, ": ");
     72 }
     73 static void fatalx(char *m1, char *m2)
     74 {
     75   strerr_die5x(111, "runsv ", dir, ": fatal: ", m1, m2);
     76 }
     77 static void warn(char *m)
     78 {
     79   strerr_warn5("runsv ", dir, ": warning: ", m, ": ", &strerr_sys);
     80 }
     81 static void warn2(char *m1, char *m2)
     82 {
     83   strerr_warn6("runsv ", dir, ": warning: ", m1, m2, ": ", &strerr_sys);
     84 }
     85 static void warnx(char *m1, char *m2, char *m3)
     86 {
     87   strerr_warn6("runsv ", dir, ": warning: ", m1, m2, m3, 0);
     88 }
     89 
     90 static void stopservice(struct svdir *);
     91 
     92 static void s_child() { write(selfpipe[1], "", 1); }
     93 static void s_term()
     94 {
     95   sigterm =1;
     96   write(selfpipe[1], "", 1); /* XXX */
     97 }
     98 
     99 static void update_status(struct svdir *s)
    100 {
    101   unsigned long l;
    102   int fd;
    103   char status[20];
    104   char bspace[64];
    105   buffer b;
    106   char spid[FMT_ULONG];
    107   char *fstatus ="supervise/status";
    108   char *fstatusnew ="supervise/status.new";
    109   char *fstat ="supervise/stat";
    110   char *fstatnew ="supervise/stat.new";
    111   char *fpid ="supervise/pid";
    112   char *fpidnew ="supervise/pid.new";
    113 
    114   if (s->islog) {
    115     fstatus ="log/supervise/status";
    116     fstatusnew ="log/supervise/status.new";
    117     fstat ="log/supervise/stat";
    118     fstatnew ="log/supervise/stat.new";
    119     fpid ="log/supervise/pid";
    120     fpidnew ="log/supervise/pid.new";
    121   }
    122 
    123   /* pid */
    124   if (pidchanged) {
    125     if ((fd =open_trunc(fpidnew)) == -1) {
    126       warn2("unable to open ", fpidnew);
    127       return;
    128     }
    129     buffer_init(&b, buffer_unixwrite, fd, bspace, sizeof bspace);
    130     spid[fmt_ulong(spid, (unsigned long)s->pid)] =0;
    131     if (s->pid) {
    132       buffer_puts(&b, spid);
    133       buffer_puts(&b, "\n");
    134       buffer_flush(&b);
    135     }
    136     close(fd);
    137     if (rename(fpidnew, fpid) == -1) {
    138       warn2("unable to rename pid.new to ", fpid);
    139       return;
    140     }
    141     pidchanged =0;
    142   }
    143 
    144   /* stat */
    145   if ((fd =open_trunc(fstatnew)) == -1) {
    146     warn2("unable to open ", fstatnew);
    147     return;
    148   }
    149   buffer_init(&b, buffer_unixwrite, fd, bspace, sizeof bspace);
    150   switch (s->state) {
    151   case S_DOWN:
    152     buffer_puts(&b, "down");
    153     break;
    154   case S_RUN:
    155     buffer_puts(&b, "run");
    156     break;
    157   case S_FINISH:
    158     buffer_puts(&b, "finish");
    159     break;
    160   }
    161   if (s->ctrl & C_PAUSE) buffer_puts(&b, ", paused");
    162   if (s->ctrl & C_TERM) buffer_puts(&b, ", got TERM");
    163   if (s->state != S_DOWN)
    164     switch(s->want) {
    165     case W_DOWN:
    166       buffer_puts(&b, ", want down");
    167       break;
    168     case W_EXIT:
    169       buffer_puts(&b, ", want exit");
    170       break;
    171     }
    172   buffer_puts(&b, "\n");
    173   buffer_flush(&b);
    174   close(fd);
    175   if (rename(fstatnew, fstat) == -1)
    176     warn2("unable to rename stat.new to ", fstat);
    177 
    178   /* supervise compatibility */
    179   taia_pack(status, &s->start);
    180   l =(unsigned long)s->pid;
    181   status[12] =l; l >>=8;
    182   status[13] =l; l >>=8;
    183   status[14] =l; l >>=8;
    184   status[15] =l;
    185   if (s->ctrl & C_PAUSE)
    186     status[16] =1;
    187   else
    188     status[16] =0;
    189   if (s->want == W_UP)
    190     status[17] ='u';
    191   else
    192     status[17] ='d';
    193   if (s->ctrl & C_TERM)
    194     status[18] =1;
    195   else
    196     status[18] =0;
    197   status[19] =s->state;
    198   if ((fd =open_trunc(fstatusnew)) == -1) {
    199     warn2("unable to open ", fstatusnew);
    200     return;
    201   }
    202   if ((l =write(fd, status, sizeof status)) == -1) {
    203     warn2("unable to write ", fstatusnew);
    204     close(fd);
    205     unlink(fstatusnew);
    206     return;
    207   }
    208   close(fd);
    209   if (l < sizeof status) {
    210     warnx("unable to write ", fstatusnew, ": partial write.");
    211     return;
    212   }
    213   if (rename(fstatusnew, fstatus) == -1)
    214     warn2("unable to rename status.new to ", fstatus);
    215 }
    216 static unsigned int custom(struct svdir *s, char c)
    217 {
    218   int pid;
    219   int w;
    220   char a[10];
    221   struct stat st;
    222   char *prog[2];
    223 
    224   if (s->islog) return(0);
    225   byte_copy(a, 10, "control/?");
    226   a[8] =c;
    227   if (stat(a, &st) == 0) {
    228     if (st.st_mode & S_IXUSR) {
    229       if ((pid =fork()) == -1) {
    230         warn2("unable to fork for ", a);
    231         return(0);
    232       }
    233       if (! pid) {
    234         if (haslog && fd_copy(1, logpipe[1]) == -1)
    235           warn2("unable to setup stdout for ", a);
    236         prog[0] =a;
    237         prog[1] =0;
    238         execve(a, prog, environ);
    239         fatal("unable to run control/?");
    240       }
    241       while (wait_pid(&w, pid) == -1) {
    242         if (errno == error_intr) continue;
    243         warn2("unable to wait for child ", a);
    244         return(0);
    245       }
    246       return(! wait_exitcode(w));
    247     }
    248   }
    249   else {
    250     if (errno == error_noent) return(0);
    251     warn2("unable to stat ", a);
    252   }
    253   return(0);
    254 }
    255 static void stopservice(struct svdir *s)
    256 {
    257   if (s->pid && ! custom(s, 't')) {
    258     kill(s->pid, SIGTERM);
    259     s->ctrl |=C_TERM;
    260     update_status(s);
    261   }
    262   if (s->want == W_DOWN) {
    263     kill(s->pid, SIGCONT);
    264     custom(s, 'd'); return;
    265   }
    266   if (s->want == W_EXIT) {
    267     kill(s->pid, SIGCONT);
    268     custom(s, 'x');
    269   }
    270 }
    271 
    272 static void startservice(struct svdir *s)
    273 {
    274   int p;
    275   char *run[4];
    276   char code[FMT_ULONG];
    277   char stat[FMT_ULONG];
    278 
    279   if (s->state == S_FINISH) {
    280     run[0] ="./finish";
    281     code[fmt_ulong(code, wait_exitcode(s->wstat))] =0;
    282     run[1] =wait_crashed(s->wstat) ? "-1" : code;
    283     stat[fmt_ulong(stat, s->wstat & 0xff)] =0;
    284     run[2] =stat;
    285     run[3] =0;
    286   }
    287   else {
    288     run[0] ="./run";
    289     custom(s, 'u');
    290     run[1] =0;
    291   }
    292 
    293   if (s->pid != 0) stopservice(s); /* should never happen */
    294   while ((p =fork()) == -1) {
    295     warn("unable to fork, sleeping");
    296     sleep(5);
    297   }
    298   if (p == 0) {
    299     /* child */
    300     if (haslog) {
    301       if (s->islog) {
    302         if (fd_copy(0, logpipe[0]) == -1)
    303           fatal("unable to setup filedescriptor for ./log/run");
    304         close(logpipe[1]);
    305         if (chdir("./log") == -1)
    306           fatal("unable to change directory to ./log");        
    307       }
    308       else {
    309         if (fd_copy(1, logpipe[1]) == -1)
    310           fatal("unable to setup filedescriptor for ./run");
    311         close(logpipe[0]);
    312       }
    313     }
    314     sig_uncatch(sig_child);
    315     sig_unblock(sig_child);
    316     sig_uncatch(sig_term);
    317     sig_unblock(sig_term);
    318     execve(*run, run, environ);
    319     if (s->islog)
    320       fatal2("unable to start log/", *run);
    321     else
    322       fatal2("unable to start ", *run);
    323   }
    324   if (s->state != S_FINISH) {
    325     taia_now(&s->start);
    326     s->state =S_RUN;
    327   }
    328   s->pid =p;
    329   pidchanged =1;
    330   s->ctrl =C_NOOP;
    331   update_status(s);
    332 }
    333 static int ctrl(struct svdir *s, char c)
    334 {
    335   switch(c) {
    336   case 'd': /* down */
    337     s->want =W_DOWN;
    338     update_status(s);
    339     if (s->state == S_RUN) stopservice(s);
    340     break;
    341   case 'u': /* up */
    342     s->want =W_UP;
    343     update_status(s);
    344     if (s->state == S_DOWN) startservice(s);
    345     break;
    346   case 'x': /* exit */
    347     if (s->islog) break;
    348     s->want =W_EXIT;
    349     update_status(s);
    350     if (s->state == S_RUN) stopservice(s);
    351     break;
    352   case 't': /* sig term */
    353     if (s->state == S_RUN) stopservice(s);
    354     break;
    355   case 'k': /* sig kill */
    356     if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGKILL);
    357     s->state =S_DOWN;
    358     break;
    359   case 'p': /* sig pause */
    360     if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGSTOP);
    361     s->ctrl |=C_PAUSE;
    362     update_status(s);
    363     break;
    364   case 'c': /* sig cont */
    365     if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGCONT);
    366     if (s->ctrl & C_PAUSE) s->ctrl &=~C_PAUSE;
    367     update_status(s);
    368     break;
    369   case 'o': /* once */
    370     s->want =W_DOWN;
    371     update_status(s);
    372     if (s->state == S_DOWN) startservice(s);
    373     break;
    374   case 'a': /* sig alarm */
    375     if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGALRM);
    376     break;
    377   case 'h': /* sig hup */
    378     if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGHUP);
    379     break;
    380   case 'i': /* sig int */
    381     if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGINT);
    382     break;
    383   case 'q': /* sig quit */
    384     if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGQUIT);
    385     break;
    386   case '1': /* sig usr1 */
    387     if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGUSR1);
    388     break;
    389   case '2': /* sig usr2 */
    390     if ((s->state == S_RUN) && ! custom(s, c)) kill(s->pid, SIGUSR2);
    391     break;
    392   }
    393   return(1);
    394 }
    395 
    396 int main(int argc, char **argv) {
    397   struct stat s;
    398   int fd;
    399   int r;
    400   char buf[256];
    401 
    402   progname =argv[0];
    403   if (! argv[1] || argv[2]) usage();
    404   dir =argv[1];
    405 
    406   if (pipe(selfpipe) == -1) fatal("unable to create selfpipe");
    407   coe(selfpipe[0]);
    408   coe(selfpipe[1]);
    409   ndelay_on(selfpipe[0]);
    410   ndelay_on(selfpipe[1]);
    411   
    412   sig_block(sig_child);
    413   sig_catch(sig_child, s_child);
    414   sig_block(sig_term);
    415   sig_catch(sig_term, s_term);
    416 
    417   if (chdir(dir) == -1) fatal("unable to change to directory");
    418   svd[0].pid =0;
    419   svd[0].state =S_DOWN;
    420   svd[0].ctrl =C_NOOP;
    421   svd[0].want =W_UP;
    422   svd[0].islog =0;
    423   svd[1].pid =0;
    424   taia_now(&svd[0].start);
    425   if (stat("down", &s) != -1) svd[0].want =W_DOWN;
    426 
    427   if (stat("log", &s) == -1) {
    428     if (errno != error_noent)
    429       warn("unable to stat() ./log: ");
    430   }
    431   else {
    432     if (! S_ISDIR(s.st_mode))
    433       warnx("./log", 0, ": not a directory.");
    434     else {
    435       haslog =1;
    436       svd[1].state =S_DOWN;
    437       svd[1].ctrl =C_NOOP;
    438       svd[1].want =W_UP;
    439       svd[1].islog =1;
    440       taia_now(&svd[1].start);
    441       if (stat("log/down", &s) != -1)
    442         svd[1].want =W_DOWN;
    443       if (pipe(logpipe) == -1)
    444         fatal("unable to create log pipe");
    445       coe(logpipe[0]);
    446       coe(logpipe[1]);
    447     }
    448   }
    449 
    450   if (mkdir("supervise", 0700) == -1) {
    451     if ((r =readlink("supervise", buf, 256)) != -1) {
    452       if (r == 256)
    453         fatalx("unable to readlink ./supervise: ", "name too long");
    454       buf[r] =0;
    455       mkdir(buf, 0700);
    456     }
    457     else {
    458       if ((errno != ENOENT) && (errno != EINVAL))
    459         fatal("unable to readlink ./supervise");
    460     }
    461   }
    462   if ((svd[0].fdlock =open_append("supervise/lock")) == -1)
    463     fatal("unable to open supervise/lock");
    464   if (lock_exnb(svd[0].fdlock) == -1) fatal("unable to lock supervise/lock");
    465   coe(svd[0].fdlock);
    466   if (haslog) {
    467     if (mkdir("log/supervise", 0700) == -1) {
    468       if ((r =readlink("log/supervise", buf, 256)) != -1) {
    469         if (r == 256)
    470           fatalx("unable to readlink ./log/supervise: ", "name too long");
    471         buf[r] =0;
    472         if ((fd =open_read(".")) == -1)
    473           fatal("unable to open current directory");
    474         if (chdir("./log") == -1)
    475           fatal("unable to change directory to ./log"); 
    476         mkdir(buf, 0700);
    477         if (fchdir(fd) == -1)
    478           fatal("unable to change back to service directory");
    479         close(fd);
    480       }
    481       else {
    482         if ((errno != ENOENT) && (errno != EINVAL))
    483           fatal("unable to readlink ./log/supervise");
    484       }
    485     }
    486     if ((svd[1].fdlock =open_append("log/supervise/lock")) == -1)
    487       fatal("unable to open log/supervise/lock");
    488     if (lock_ex(svd[1].fdlock) == -1)
    489       fatal("unable to lock log/supervise/lock");
    490     coe(svd[1].fdlock);
    491   }
    492 
    493   mkfifo("supervise/control", 0600);
    494   if (stat("supervise/control", &s) == -1)
    495     fatal("unable to stat supervise/control");
    496   if (!S_ISFIFO(s.st_mode))
    497     fatalx("supervise/control exists but is not a fifo", "");
    498   if ((svd[0].fdcontrol =open_read("supervise/control")) == -1)
    499     fatal("unable to open supervise/control");
    500   coe(svd[0].fdcontrol);
    501   if ((svd[0].fdcontrolwrite =open_write("supervise/control")) == -1)
    502     fatal("unable to open supervise/control");
    503   coe(svd[0].fdcontrolwrite);
    504   update_status(&svd[0]);
    505   if (haslog) {
    506     mkfifo("log/supervise/control", 0600);
    507     if (stat("supervise/control", &s) == -1)
    508       fatal("unable to stat log/supervise/control");
    509     if (!S_ISFIFO(s.st_mode))
    510       fatalx("log/supervise/control exists but is not a fifo", "");
    511     if ((svd[1].fdcontrol =open_read("log/supervise/control")) == -1)
    512       fatal("unable to open log/supervise/control");
    513     coe(svd[1].fdcontrol);
    514     if ((svd[1].fdcontrolwrite =open_write("log/supervise/control")) == -1)
    515       fatal("unable to open log/supervise/control");
    516     coe(svd[1].fdcontrolwrite);
    517     update_status(&svd[1]);
    518   }
    519   mkfifo("supervise/ok",0600);
    520   if ((fd =open_read("supervise/ok")) == -1)
    521     fatal("unable to read supervise/ok");
    522   coe(fd);
    523   if (haslog) {
    524     mkfifo("log/supervise/ok",0600);
    525     if ((fd =open_read("log/supervise/ok")) == -1)
    526       fatal("unable to read log/supervise/ok");
    527     coe(fd);
    528   }
    529   for (;;) {
    530     struct pollfd x[3];
    531     struct taia deadline;
    532     struct taia now;
    533     char ch;
    534 
    535     if (haslog)
    536       if (! svd[1].pid && (svd[1].want == W_UP)) startservice(&svd[1]);
    537     if (! svd[0].pid)
    538       if ((svd[0].want == W_UP) || (svd[0].state == S_FINISH))
    539         startservice(&svd[0]);
    540 
    541     x[0].fd =selfpipe[0];
    542     x[0].events =POLLIN;
    543     x[1].fd =svd[0].fdcontrol;
    544     x[1].events =POLLIN;
    545     if (haslog) {
    546       x[2].fd =svd[1].fdcontrol;
    547       x[2].events =POLLIN;
    548     }
    549     taia_now(&now);
    550     taia_uint(&deadline, 3600);
    551     taia_add(&deadline, &now, &deadline);
    552 
    553     sig_unblock(sig_term);
    554     sig_unblock(sig_child);
    555     iopause(x, 2 +haslog, &deadline, &now);
    556     sig_block(sig_term);
    557     sig_block(sig_child);
    558 
    559     while (read(selfpipe[0], &ch, 1) == 1)
    560       ;
    561     for (;;) {
    562       int child;
    563       int wstat;
    564       
    565       child =waitpid( -1, &wstat, WNOHANG );
    566       if (!child) break;
    567       if ((child == -1) && (errno != error_intr)) break;
    568       if (child == svd[0].pid) {
    569         svd[0].pid =0;
    570         pidchanged =1;
    571         svd[0].wstat =wstat;
    572         svd[0].ctrl &=~C_TERM;
    573         if (svd[0].state != S_FINISH)
    574           if ((fd =open_read("finish")) != -1) {
    575             close(fd);
    576             svd[0].state =S_FINISH;
    577             update_status(&svd[0]);
    578             continue;
    579           }
    580         svd[0].state =S_DOWN;
    581         taia_uint(&deadline, 1);
    582         taia_add(&deadline, &svd[0].start, &deadline);
    583         taia_now(&svd[0].start);
    584         update_status(&svd[0]);
    585         if (taia_less(&svd[0].start, &deadline)) sleep(1);
    586       }
    587       if (haslog) {
    588         if (child == svd[1].pid) {
    589           svd[1].pid =0;
    590           pidchanged =1;
    591           svd[1].state =S_DOWN;
    592           svd[1].ctrl &=~C_TERM;
    593           taia_uint(&deadline, 1);
    594           taia_add(&deadline, &svd[1].start, &deadline);
    595           taia_now(&svd[1].start);
    596           update_status(&svd[1]);
    597           if (taia_less(&svd[1].start, &deadline)) sleep(1);
    598         }
    599       }
    600     }
    601     if (read(svd[0].fdcontrol, &ch, 1) == 1) ctrl(&svd[0], ch);
    602     if (haslog)
    603       if (read(svd[1].fdcontrol, &ch, 1) == 1) ctrl(&svd[1], ch);
    604 
    605     if (sigterm) { ctrl(&svd[0], 'x'); sigterm =0; }
    606 
    607     if ((svd[0].want == W_EXIT) && (svd[0].state == S_DOWN)) {
    608       if (svd[1].pid == 0) _exit(0);
    609       if (svd[1].want != W_EXIT) {
    610         svd[1].want =W_EXIT;
    611         /* stopservice(&svd[1]); */
    612         update_status(&svd[1]);
    613         if (close(logpipe[1]) == -1) warn("unable to close logpipe[1]");
    614         if (close(logpipe[0]) == -1) warn("unable to close logpipe[0]");
    615       }
    616     }
    617   }
    618 }