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 }