runsvdir.c (6782B)
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <unistd.h> 4 #include <signal.h> 5 #include <sys/types.h> 6 #include <dirent.h> 7 #include <poll.h> 8 #include <stdint.h> 9 #include "iopause.h" 10 #include "strerr.h" 11 #include "error.h" 12 #include "wait.h" 13 #include <sys/wait.h> 14 #include "env.h" 15 #include "open.h" 16 #include "pathexec.h" 17 #include "fd.h" 18 #include "str.h" 19 #include "coe.h" 20 #include "sig.h" 21 #include "ndelay.h" 22 #include "taia.h" 23 24 #define USAGE " [-P] dir" 25 26 #define MAXSERVICES 1000 27 28 static char *progname; 29 static char *svdir; 30 static unsigned long dev =0; 31 static unsigned long ino =0; 32 static struct { 33 unsigned long dev; 34 unsigned long ino; 35 int pid; 36 int isgone; 37 } sv[MAXSERVICES]; 38 static int svnum =0; 39 static int check =1; 40 static char *rplog =0; 41 static int rploglen; 42 static int logpipe[2]; 43 static struct pollfd io[1]; 44 static struct taia stamplog; 45 static int exitsoon =0; 46 static int pgrp =0; 47 48 static void usage ( void ) { strerr_die4x(1, "usage: ", progname, USAGE, "\n"); } 49 static void fatal(char *m1, char *m2) { 50 strerr_die6sys(100, "runsvdir ", svdir, ": fatal: ", m1, m2, ": "); 51 } 52 static void warn(char *m1, char *m2) { 53 strerr_warn6("runsvdir ", svdir, ": warning: ", m1, m2, ": ", &strerr_sys); 54 } 55 static void warn3x(char *m1, char *m2, char *m3) { 56 strerr_warn6("runsvdir ", svdir, ": warning: ", m1, m2, m3, 0); 57 } 58 static void s_term() { exitsoon =1; } 59 static void s_hangup() { exitsoon =2; } 60 61 static void runsv(int no, char *name) 62 { 63 int pid; 64 65 if ((pid =fork()) == -1) { 66 warn("unable to fork for ", name); 67 return; 68 } 69 if (pid == 0) { 70 /* child */ 71 const char *prog[3]; 72 73 prog[0] ="runsv"; 74 prog[1] =name; 75 prog[2] =0; 76 sig_uncatch(sig_hangup); 77 sig_uncatch(sig_term); 78 if (pgrp) setsid(); 79 pathexec_run(*prog, prog, (const char* const*)environ); 80 fatal("unable to start runsv ", name); 81 } 82 sv[no].pid =pid; 83 } 84 85 static void runsvdir( void ) 86 { 87 DIR *dir; 88 struct dirent *d; 89 int i; 90 struct stat s; 91 92 if (! (dir =opendir("."))) { 93 warn("unable to open directory ", svdir); 94 return; 95 } 96 for (i =0; i < svnum; i++) sv[i].isgone =1; 97 errno =0; 98 while ((d =readdir(dir))) { 99 if (d->d_name[0] == '.') continue; 100 if (stat(d->d_name, &s) == -1) { 101 warn("unable to stat ", d->d_name); 102 errno =0; 103 continue; 104 } 105 if (! S_ISDIR(s.st_mode)) continue; 106 for (i =0; i < svnum; i++) { 107 if ((sv[i].ino == s.st_ino) && (sv[i].dev == s.st_dev)) { 108 sv[i].isgone =0; 109 if (! sv[i].pid) runsv(i, d->d_name); 110 break; 111 } 112 } 113 if (i == svnum) { 114 /* new service */ 115 if (svnum >= MAXSERVICES) { 116 warn3x("unable to start runsv ", d->d_name, ": too many services."); 117 continue; 118 } 119 sv[i].ino =s.st_ino; 120 sv[i].dev =s.st_dev; 121 sv[i].pid =0; 122 sv[i].isgone =0; 123 svnum++; 124 runsv(i, d->d_name); 125 check =1; 126 } 127 } 128 if (errno) { 129 warn("unable to read directory ", svdir); 130 closedir(dir); 131 check =1; 132 return; 133 } 134 closedir(dir); 135 136 /* SIGTERM removed runsv's */ 137 for (i =0; i < svnum; i++) { 138 if (! sv[i].isgone) continue; 139 if (sv[i].pid) kill(sv[i].pid, SIGTERM); 140 sv[i] =sv[--svnum]; 141 check =1; 142 } 143 } 144 145 static int setup_log( void ) 146 { 147 if ((rploglen =str_len(rplog)) < 7) { 148 warn3x("log must have at least seven characters.", 0, 0); 149 return(0); 150 } 151 if (pipe(logpipe) == -1) { 152 warn3x("unable to create pipe for log.", 0, 0); 153 return(-1); 154 } 155 coe(logpipe[1]); 156 coe(logpipe[0]); 157 ndelay_on(logpipe[0]); 158 ndelay_on(logpipe[1]); 159 if (fd_copy(2, logpipe[1]) == -1) { 160 warn3x("unable to set filedescriptor for log.", 0, 0); 161 return(-1); 162 } 163 io[0].fd =logpipe[0]; 164 io[0].events = POLLIN; 165 taia_now(&stamplog); 166 return(1); 167 } 168 169 int main(int argc, char **argv) 170 { 171 struct stat s; 172 time_t mtime =0; 173 int wstat; 174 int curdir; 175 int pid; 176 struct taia deadline; 177 struct taia now; 178 struct taia stampcheck; 179 char ch; 180 int i; 181 182 progname =*argv++; 183 if (! argv || ! *argv) usage(); 184 if (**argv == '-') { 185 switch (*(*argv +1)) { 186 case 'P': 187 pgrp =1; 188 __attribute__((fallthrough)); 189 case '-': ++argv; 190 } 191 if (! argv || ! *argv) usage(); 192 } 193 194 sig_catch(sig_term, s_term); 195 sig_catch(sig_hangup, s_hangup); 196 svdir =*argv++; 197 if (argv && *argv) { 198 rplog =*argv; 199 if (setup_log() != 1) { 200 rplog =0; 201 warn3x("log service disabled.", 0, 0); 202 } 203 } 204 if ((curdir =open_read(".")) == -1) 205 fatal("unable to open current directory", 0); 206 coe(curdir); 207 208 taia_now(&stampcheck); 209 210 for (;;) { 211 /* collect children */ 212 for (;;) { 213 if ((pid =waitpid( -1, &wstat, WNOHANG )) <= 0) break; 214 for (i =0; i < svnum; i++) { 215 if (pid == sv[i].pid) { 216 /* runsv has gone */ 217 sv[i].pid =0; 218 check =1; 219 break; 220 } 221 } 222 } 223 224 taia_now(&now); 225 if (now.sec.x < (stampcheck.sec.x -3)) { 226 /* time warp */ 227 warn3x("time warp: resetting time stamp.", 0, 0); 228 taia_now(&stampcheck); 229 taia_now(&now); 230 if (rplog) taia_now(&stamplog); 231 } 232 if (taia_less(&now, &stampcheck) == 0) { 233 /* wait at least a second */ 234 taia_uint(&deadline, 1); 235 taia_add(&stampcheck, &now, &deadline); 236 237 if (stat(svdir, &s) != -1) { 238 if (check || \ 239 s.st_mtime != mtime || s.st_ino != ino || s.st_dev != dev) { 240 /* svdir modified */ 241 if (chdir(svdir) != -1) { 242 mtime =s.st_mtime; 243 dev =s.st_dev; 244 ino =s.st_ino; 245 check =0; 246 if (now.sec.x <= (4611686018427387914ULL +(uint64_t)mtime)) 247 sleep(1); 248 runsvdir(); 249 while (fchdir(curdir) == -1) { 250 warn("unable to change directory, pausing", 0); 251 sleep(5); 252 } 253 } 254 else 255 warn("unable to change directory to ", svdir); 256 } 257 } 258 else 259 warn("unable to stat ", svdir); 260 } 261 262 if (rplog) 263 if (taia_less(&now, &stamplog) == 0) { 264 write(logpipe[1], ".", 1); 265 taia_uint(&deadline, 900); 266 taia_add(&stamplog, &now, &deadline); 267 } 268 taia_uint(&deadline, check ? 1 : 5); 269 taia_add(&deadline, &now, &deadline); 270 271 sig_block(sig_child); 272 if (rplog) 273 iopause(io, 1, &deadline, &now); 274 else 275 iopause(0, 0, &deadline, &now); 276 sig_unblock(sig_child); 277 278 if (rplog && (io[0].revents | POLLIN)) 279 while (read(logpipe[0], &ch, 1) > 0) 280 if (ch) { 281 for (i =6; i < rploglen; i++) 282 rplog[i -1] =rplog[i]; 283 rplog[rploglen -1] =ch; 284 } 285 286 switch(exitsoon) { 287 case 1: 288 _exit(0); 289 case 2: 290 for (i =0; i < svnum; i++) if (sv[i].pid) kill(sv[i].pid, SIGTERM); 291 _exit(111); 292 } 293 } 294 }