s6-svlink.c (3594B)
1 /* ISC license. */ 2 3 #include <errno.h> 4 #include <stdint.h> 5 #include <string.h> 6 #include <sys/stat.h> 7 #include <libgen.h> 8 9 #include <skalibs/posixplz.h> 10 #include <skalibs/types.h> 11 #include <skalibs/sgetopt.h> 12 #include <skalibs/tai.h> 13 #include <skalibs/strerr.h> 14 #include <skalibs/stralloc.h> 15 #include <skalibs/djbunix.h> 16 17 #include <s6/supervise.h> 18 19 #define USAGE "s6-svlink [ -d | -D ] [ -f ] [ -P ] [ -t timeout ] scandir servicedir [ name ]" 20 #define dieusage() strerr_dieusage(100, USAGE) 21 22 static inline void checkscandir (char const *s) 23 { 24 int r ; 25 int fd ; 26 size_t len = strlen(s) ; 27 char fn[len + 6 + sizeof(S6_SVSCAN_CTLDIR)] ; 28 memcpy(fn, s, len) ; 29 memcpy(fn + len, "/" S6_SVSCAN_CTLDIR "/lock", 6 + sizeof(S6_SVSCAN_CTLDIR)) ; 30 fd = open_read(fn) ; 31 if (fd < 0) strerr_diefu2sys(111, "open ", fn) ; 32 r = fd_islocked(fd) ; 33 if (r < 0) strerr_diefu2sys(111, "check lock on ", fn) ; 34 if (!r) strerr_dief2x(1, "s6-svscan not running on ", s) ; 35 fd_close(fd) ; 36 } 37 38 static inline void checkservicedir (char const *s) 39 { 40 int r ; 41 struct stat st ; 42 size_t len = strlen(s) ; 43 char fn[len + 9] ; 44 memcpy(fn, s, len) ; 45 memcpy(fn + len, "/run", 5) ; 46 if (stat(fn, &st) == -1) strerr_diefu2sys(111, "stat ", fn) ; 47 if (!(st.st_mode & S_IXUSR)) strerr_dief2x(100, fn, " is not executable") ; 48 r = s6_svc_ok(s) ; 49 if (r < 0) strerr_diefu2sys(111, "check supervision status of ", s) ; 50 if (r) strerr_warnw2x("supervisor already running on ", s) ; 51 memcpy(fn + len + 1, "log", 4) ; 52 if (stat(fn, &st) == -1) 53 { 54 if (errno != ENOENT) strerr_diefu2sys(111, "stat ", fn) ; 55 } 56 else 57 { 58 if (!S_ISDIR(st.st_mode)) strerr_dief2x(100, fn, " is not a directory") ; 59 memcpy(fn + len + 4, "/run", 5) ; 60 if (stat(fn, &st) == -1) strerr_diefu2sys(111, "stat ", fn) ; 61 if (!(st.st_mode & S_IXUSR)) strerr_dief2x(100, fn, " is not executable") ; 62 fn[len + 4] = 0 ; 63 r = s6_svc_ok(fn) ; 64 if (r < 0) strerr_diefu2sys(111, "check supervision status of ", fn) ; 65 if (r) strerr_warnw2x("supervisor already running on ", fn) ; 66 } 67 } 68 69 int main (int argc, char const *const *argv) 70 { 71 tain tto = TAIN_INFINITE_RELATIVE ; 72 uint32_t options = 0 ; 73 char const *name ; 74 PROG = "s6-svlink" ; 75 { 76 unsigned int t = 0 ; 77 subgetopt l = SUBGETOPT_ZERO ; 78 for (;;) 79 { 80 int opt = subgetopt_r(argc, argv, "dDfPt:", &l) ; 81 if (opt == -1) break ; 82 switch (opt) 83 { 84 case 'd' : options |= 12 ; break ; 85 case 'D' : options |= 4 ; options &= ~8U ; break ; 86 case 'f' : options |= 1 ; break ; 87 case 'P' : options |= 2 ; break ; 88 case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; 89 default : dieusage() ; 90 } 91 } 92 argc -= l.ind ; argv += l.ind ; 93 if (t) tain_from_millisecs(&tto, t) ; 94 } 95 if (argc < 2) dieusage() ; 96 97 if (argv[2]) name = argv[2] ; 98 else 99 { 100 stralloc sa = STRALLOC_ZERO ; 101 if (!stralloc_cats(&sa, argv[1]) || !stralloc_0(&sa)) 102 strerr_diefu1sys(111, "stralloc_cats") ; 103 name = basename(sa.s) ; 104 } 105 if (!argv[0][0]) strerr_dief1x(100, "invalid scandir") ; 106 if (!argv[1][0]) strerr_dief1x(100, "invalid servicedir") ; 107 if (!name[0] || name[0] == '.' || name[0] == '/') 108 strerr_dief1x(100, "invalid name") ; 109 checkscandir(argv[0]) ; 110 checkservicedir(argv[1]) ; 111 112 tain_now_set_stopwatch_g() ; 113 tain_add_g(&tto, &tto) ; 114 115 if (s6_supervise_link_names_g(argv[0], argv + 1, &name, 1, options, &tto) == -1) 116 strerr_diefu6sys(errno == ETIMEDOUT ? 99 : 111, "link servicedir ", argv[1], " into scandir ", argv[0], " with name ", name) ; 117 return 0 ; 118 }