s6

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

s6-instance-maker.c (6145B)


      1 /* ISC license. */
      2 
      3 #include <errno.h>
      4 #include <string.h>
      5 #include <sys/stat.h>
      6 #include <sys/uio.h>
      7 
      8 #include <skalibs/uint64.h>
      9 #include <skalibs/types.h>
     10 #include <skalibs/buffer.h>
     11 #include <skalibs/strerr.h>
     12 #include <skalibs/sgetopt.h>
     13 #include <skalibs/stralloc.h>
     14 #include <skalibs/djbunix.h>
     15 #include <skalibs/skamisc.h>
     16 
     17 #include <execline/config.h>
     18 
     19 #include <s6/config.h>
     20 #include <s6/auto.h>
     21 
     22 #define USAGE "s6-instance-maker [ -c max ] [ -u user ] [ -l loguser ] [ -L logdir ] [ -t stamptype ] [ -n nfiles ] [ -s filesize ] [ -S maxsize ] [ -P prefix ] [ -r service[/logger[/pipeline]] ] template dir"
     23 #define dieusage() strerr_dieusage(100, USAGE)
     24 
     25 typedef struct svinfo_s svinfo, *svinfo_ref ;
     26 struct svinfo_s
     27 {
     28   char const *user ;
     29   unsigned int maxinstances ;
     30 } ;
     31 
     32 static stralloc sa = STRALLOC_ZERO ;
     33 
     34 static int write_run (buffer *b, void *data)
     35 {
     36   svinfo *t = data ;
     37   size_t l ;
     38   char fmt[UINT_FMT] ;
     39   l = uint_fmt(fmt, t->maxinstances) ;
     40   if (buffer_puts(b, "#!" EXECLINE_SHEBANGPREFIX "execlineb -P\n\n"
     41     EXECLINE_EXTBINPREFIX "fdmove -c 2 1\n") < 0) return 0 ;
     42   if (t->user[0])
     43   {
     44     if (!string_quote(&sa, t->user, strlen(t->user))) return 0 ;
     45     if (buffer_puts(b, S6_EXTBINPREFIX "s6-setuidgid ") < 0
     46      || buffer_put(b, sa.s, sa.len) < 0
     47      || buffer_put(b, "\n", 1) < 0) goto err ;
     48     sa.len = 0 ;
     49   }
     50   if (buffer_puts(b, S6_EXTBINPREFIX "s6-svscan -d3 -c") < 0
     51    || buffer_put(b, fmt, l) < 0
     52    || buffer_putsflush(b, " -- instance\n") < 0) return 0 ;
     53   return 1 ;
     54 
     55 err:
     56   sa.len = 0 ;
     57   return 0 ;
     58 }
     59 
     60 static void write_service (char const *dir, char const *template, char const *user, unsigned int maxinstances, char const *logger)
     61 {
     62   svinfo data = { .user = user, .maxinstances = maxinstances } ;
     63   size_t dirlen = strlen(dir) ;
     64   char fn[dirlen + 11] ;
     65   memcpy(fn, dir, dirlen) ;
     66   s6_auto_write_service(dir, 3, &write_run, &data, logger) ;
     67   if (!logger)
     68   {
     69     mode_t m = umask(0) ;
     70     memcpy(fn + dirlen, "/instance", 10) ;
     71     if (mkdir(fn, 0755) == -1) strerr_diefu2sys(111, "mkdir ", fn) ;
     72     memcpy(fn + dirlen + 9, "s", 2) ;
     73     if (mkdir(fn, 0755) == -1) strerr_diefu2sys(111, "mkdir ", fn) ;
     74     umask(m) ;
     75   }
     76   memcpy(fn + dirlen, "/template", 10) ;
     77   if (!hiercopy_tmp(template, fn, &sa))
     78     strerr_diefu4sys(111, "copy file hierarchy from ", template, " to ", fn) ;
     79 }
     80 
     81 int main (int argc, char const *const *argv)
     82 {
     83   char const *user = "" ;
     84   char const *loguser = 0 ;
     85   char const *logdir = 0 ;
     86   unsigned int maxinstances = 500 ;
     87   unsigned int stamptype = 1 ;
     88   unsigned int nfiles = 10 ;
     89   uint64_t filesize = 1000000 ;
     90   uint64_t maxsize = 0 ;
     91   char const *prefix = 0 ;
     92   char *rcinfo[3] = { 0, 0, 0 } ;
     93   size_t dirlen ;
     94   PROG = "s6-instance-maker" ;
     95   {
     96     subgetopt l = SUBGETOPT_ZERO ;
     97     for (;;)
     98     {
     99       int opt = subgetopt_r(argc, argv, "u:l:L:c:t:n:s:S:P:r:", &l) ;
    100       if (opt == -1) break ;
    101       switch (opt)
    102       {
    103         case 'u' : user = l.arg ; break ;
    104         case 'l' : loguser = l.arg ; break ;
    105         case 'L' : logdir = l.arg ; break ;
    106         case 'c' : if (!uint0_scan(l.arg, &maxinstances)) dieusage() ; break ;
    107         case 't' : if (!uint0_scan(l.arg, &stamptype)) dieusage() ; break ;
    108         case 'n' : if (!uint0_scan(l.arg, &nfiles)) dieusage() ; break ;
    109         case 's' : if (!uint640_scan(l.arg, &filesize)) dieusage() ; break ;
    110         case 'S' : if (!uint640_scan(l.arg, &maxsize)) dieusage() ; break ;
    111         case 'P' : prefix = l.arg ; break ;
    112 	case 'r' : rcinfo[0] = (char *)l.arg ; break ;
    113         default : dieusage() ;
    114       }
    115     }
    116     argc -= l.ind ; argv += l.ind ;
    117   }
    118 
    119   if (argc < 2) dieusage() ;
    120   if (logdir && logdir[0] != '/')
    121     strerr_dief1x(100, "logdir must be absolute") ;
    122   if (stamptype > 3) strerr_dief1x(100, "stamptype must be 0, 1, 2 or 3") ;
    123   if (strchr(user, ' ') || strchr(user, '\t') || strchr(user, '\n'))
    124     strerr_dief1x(100, "invalid user") ;
    125   if (maxinstances < 1) maxinstances = 1 ;
    126   if (maxinstances > 90000) maxinstances = 90000 ;
    127   if (rcinfo[0])
    128   {
    129     if (strchr(rcinfo[0], '\n'))
    130       strerr_dief2x(100, "newlines", " are forbidden in s6-rc names") ;
    131     if (rcinfo[0][0] == '/')
    132       strerr_dief2x(100, "service", " name cannot be empty") ;
    133     rcinfo[1] = strchr(rcinfo[0], '/') ;
    134     if (rcinfo[1])
    135     {
    136       *rcinfo[1]++ = 0 ;
    137       if (!rcinfo[1][0]) strerr_dief1x(100, "argument to -r must be: service or service/logger or service/logger/pipeline") ;
    138       if (rcinfo[1][0] == '/')
    139         strerr_dief2x(100, "logger", " name cannot be empty") ;
    140       if (!logdir) strerr_dief1x(100, "logger specifiec (-r) but logdir not specified (-L)") ;
    141       rcinfo[2] = strchr(rcinfo[1], '/') ;
    142       if (rcinfo[2])
    143       {
    144         *rcinfo[2]++ = 0 ;
    145         if (!rcinfo[2][0]) strerr_dief2x(100, "pipeline", " name cannot be empty") ;
    146         if (strchr(rcinfo[2], '/')) strerr_dief2x(100, "slashes", " are forbidden in s6-rc names") ;
    147       }
    148     }
    149     else if (logdir)
    150       strerr_dief1x(100, "logdir specified (-L) but logger name not specified (-r)") ;
    151   }
    152 
    153   dirlen = strlen(argv[1]) ;
    154   if (rcinfo[0])
    155   {
    156     mode_t m = umask(0) ;
    157     size_t svclen = strlen(rcinfo[0]) ;
    158     size_t loglen = rcinfo[1] ? strlen(rcinfo[1]) : 0 ;
    159     char dir[dirlen + 2 + (svclen > loglen ? svclen : loglen)] ;
    160     memcpy(dir, argv[1], dirlen) ;
    161     dir[dirlen] = '/' ;
    162     if (mkdir(argv[1], 0755) < 0 && errno != EEXIST)
    163       strerr_diefu2sys(111, "mkdir ", argv[1]) ;
    164     umask(m) ;
    165     memcpy(dir + dirlen + 1, rcinfo[0], svclen + 1) ;
    166     write_service(dir, argv[0], user, maxinstances, rcinfo[1] ? rcinfo[1] : "") ;
    167     if (rcinfo[1])
    168     {
    169       memcpy(dir + dirlen + 1, rcinfo[1], loglen + 1) ;
    170       s6_auto_write_logger_tmp(dir, loguser, logdir, stamptype, nfiles, filesize, maxsize, prefix, rcinfo[0], rcinfo[2], &sa) ;
    171     }
    172   }
    173   else
    174   {
    175     write_service(argv[1], argv[0], user, maxinstances, 0) ;
    176     if (logdir)
    177     {
    178       char dir[dirlen + 5] ;
    179       memcpy(dir, argv[1], dirlen) ;
    180       memcpy(dir + dirlen, "/log", 5) ;
    181       s6_auto_write_logger_tmp(dir, loguser, logdir, stamptype, nfiles, filesize, maxsize, prefix, 0, 0, &sa) ;
    182     }
    183   }
    184   return 0 ;
    185 }