s6

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

s6-svc.c (3947B)


      1 /* ISC license. */
      2 
      3 #include <skalibs/nonposix.h>
      4 
      5 #include <string.h>
      6 #include <unistd.h>
      7 #include <errno.h>
      8 #include <signal.h>
      9 
     10 #include <skalibs/types.h>
     11 #include <skalibs/sgetopt.h>
     12 #include <skalibs/strerr.h>
     13 #include <skalibs/nsig.h>
     14 #include <skalibs/sig.h>
     15 #include <skalibs/djbunix.h>
     16 #include <skalibs/exec.h>
     17 
     18 #include <s6/config.h>
     19 #include <s6/supervise.h>
     20 
     21 #define USAGE "s6-svc [ -wu | -wU | -wd | -wD | -wr | -wR ] [ -T timeout ] [ -s signal | -abqhkti12pcy ] [ -roduDUxOQ ] servicedir"
     22 #define dieusage() strerr_dieusage(100, USAGE)
     23 
     24 #define DATASIZE 63
     25 
     26 int main (int argc, char const *const *argv)
     27 {
     28   static char const cmdsig[NSIG] =
     29   {
     30     [SIGALRM] = 'a',
     31     [SIGABRT] = 'b',
     32     [SIGQUIT] = 'q',
     33     [SIGHUP] = 'h',
     34     [SIGKILL] = 'k',
     35     [SIGTERM] = 't',
     36     [SIGINT] = 'i',
     37     [SIGUSR1] = '1',
     38     [SIGUSR2] = '2',
     39     [SIGSTOP] = 'p',
     40     [SIGCONT] = 'c',
     41     [SIGWINCH] = 'y'
     42   } ;
     43   size_t len ;
     44   unsigned int datalen = 1 ;
     45   unsigned int timeout = 0 ;
     46   char data[DATASIZE+1] = "-" ;
     47   char updown[3] = "-\0" ;
     48   PROG = "s6-svc" ;
     49   {
     50     subgetopt l = SUBGETOPT_ZERO ;
     51     for (;;)
     52     {
     53       int opt = subgetopt_r(argc, argv, "s:abqhkti12pcyroduDUxOQT:w:", &l) ;
     54       if (opt == -1) break ;
     55       switch (opt)
     56       {
     57         case 's' :
     58         {
     59           int sig ;
     60           if (!sig0_scan(l.arg, &sig)) strerr_dief2x(100, "invalid signal: ", l.arg) ;
     61           if (!cmdsig[sig]) strerr_dief2x(100, l.arg, " is not in the list of user-available signals") ;
     62           opt = cmdsig[sig] ;
     63         }
     64         case 'a' :
     65         case 'b' :
     66         case 'q' :
     67         case 'h' :
     68         case 'k' :
     69         case 't' :
     70         case 'i' :
     71         case '1' :
     72         case '2' :
     73         case 'p' :
     74         case 'c' :
     75         case 'y' :
     76         case 'r' :
     77         case 'o' :
     78         case 'd' :
     79         case 'u' :
     80         case 'D' :
     81         case 'U' :
     82         case 'x' :
     83         case 'O' :
     84         case 'Q' :
     85         {
     86           if (datalen >= DATASIZE) strerr_dief1x(100, "too many commands") ;
     87           data[datalen++] = opt ;
     88           break ;
     89         }
     90         case 'T' : if (!uint0_scan(l.arg, &timeout)) dieusage() ; break ;
     91         case 'w' :
     92         {
     93           if (!memchr("dDuUrR", l.arg[0], 6)) dieusage() ;
     94           updown[1] = l.arg[0] ;
     95           break ;
     96         }
     97         default : dieusage() ;
     98       }
     99     }
    100     argc -= l.ind ; argv += l.ind ;
    101   }
    102   if (!argc) dieusage() ;
    103   if (argc > 1) strerr_warnw1x("ignoring extra arguments") ;
    104   len = strlen(argv[0]) ;
    105   if (!len) strerr_dief1x(100, "invalid service path") ;
    106 
    107   if (updown[1] == 'U' || updown[1] == 'R')
    108   {
    109     char fn[len + 17] ;
    110     memcpy(fn, argv[0], len) ;
    111     memcpy(fn + len, "/notification-fd", 17) ;
    112     if (access(fn, F_OK) < 0)
    113     {
    114       if (errno != ENOENT) strerr_diefu2sys(111, "access ", fn) ;
    115       updown[1] = updown[1] == 'U' ? 'u' : 'r' ;
    116       strerr_warnw2x(fn, " not present - ignoring request for readiness notification") ;
    117     }
    118   }
    119 
    120   if (updown[1])
    121   {
    122     char const *newargv[11] ;
    123     unsigned int m = 0 ;
    124     char fmt[UINT_FMT] ;
    125     newargv[m++] = datalen > 1 ? S6_BINPREFIX "s6-svlisten1" : S6_BINPREFIX "s6-svwait" ;
    126     newargv[m++] = updown ;
    127     if (timeout)
    128     {
    129       fmt[uint_fmt(fmt, timeout)] = 0 ;
    130       newargv[m++] = "-t" ;
    131       newargv[m++] = fmt ;
    132     }
    133     newargv[m++] = "--" ;
    134     newargv[m++] = argv[0] ;
    135     if (datalen > 1)
    136     {
    137       newargv[m++] = S6_BINPREFIX "s6-svc" ;
    138       newargv[m++] = data ;
    139       newargv[m++] = "--" ;
    140       newargv[m++] = argv[0] ;
    141     }
    142     newargv[m++] = 0 ;
    143     xexec(newargv) ;
    144   }
    145   else switch (s6_svc_writectl(argv[0], S6_SUPERVISE_CTLDIR, data + 1, datalen - 1))
    146   {
    147     case -1 : strerr_diefu2sys(111, "control ", argv[0]) ;
    148     case -2 : strerr_dief3sys(100, "something is wrong with the ", argv[0], "/" S6_SUPERVISE_CTLDIR " directory") ;
    149     case 0 : strerr_diefu3x(100, "control ", argv[0], ": supervisor not listening") ;
    150   }
    151   return 0 ;
    152 }