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 }