X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=runit%2Frunsvdir.c;h=8099ebf5c9090c5492aa287161f4528ca173a2e5;hb=176d49d4f7bd1c049211c704018b1ac9d432f52e;hp=8db0fc18915edd9ce2b5efbf1fba17c4b83cb0a9;hpb=b6adbf1be29841501cc49917249e85f273e1df7c;p=oweals%2Fbusybox.git diff --git a/runit/runsvdir.c b/runit/runsvdir.c index 8db0fc189..8099ebf5c 100644 --- a/runit/runsvdir.c +++ b/runit/runsvdir.c @@ -25,7 +25,7 @@ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* Busyboxed by Denis Vlasenko */ +/* Busyboxed by Denys Vlasenko */ /* TODO: depends on runit_lib.c - review and reduce/eliminate */ #include @@ -35,26 +35,47 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define MAXSERVICES 1000 -static char *svdir; -static unsigned long dev; -static unsigned long ino; -static struct service { - unsigned long dev; - unsigned long ino; - int pid; - int isgone; -} *sv; -static int svnum; -static int check = 1; -static char *rplog; -static int rploglen; -static int logpipe[2]; -static iopause_fd io[1]; -static struct taia stamplog; -static int exitsoon; -static int pgrp; +/* Should be not needed - all dirs are on same FS, right? */ +#define CHECK_DEVNO_TOO 0 + +struct service { +#if CHECK_DEVNO_TOO + dev_t dev; +#endif + ino_t ino; + pid_t pid; + smallint isgone; +}; + +struct globals { + struct service *sv; + char *svdir; + int svnum; +#if ENABLE_FEATURE_RUNSVDIR_LOG + char *rplog; + int rploglen; + struct fd_pair logpipe; + struct pollfd pfd[1]; + unsigned stamplog; +#endif + smallint need_rescan; /* = 1; */ + smallint set_pgrp; +}; +#define G (*(struct globals*)&bb_common_bufsiz1) +#define sv (G.sv ) +#define svdir (G.svdir ) +#define svnum (G.svnum ) +#define rplog (G.rplog ) +#define rploglen (G.rploglen ) +#define logpipe (G.logpipe ) +#define pfd (G.pfd ) +#define stamplog (G.stamplog ) +#define need_rescan (G.need_rescan ) +#define set_pgrp (G.set_pgrp ) +#define INIT_G() do { \ + need_rescan = 1; \ +} while (0) -#define usage() bb_show_usage() static void fatal2_cannot(const char *m1, const char *m2) { bb_perror_msg_and_die("%s: fatal: cannot %s%s", svdir, m1, m2); @@ -68,47 +89,43 @@ static void warn2_cannot(const char *m1, const char *m2) { warn3x("cannot ", m1, m2); } +#if ENABLE_FEATURE_RUNSVDIR_LOG static void warnx(const char *m1) { warn3x(m1, "", ""); } - -static void s_term(int sig_no) -{ - exitsoon = 1; -} -static void s_hangup(int sig_no) -{ - exitsoon = 2; -} +#endif static void runsv(int no, const char *name) { - int pid = fork(); + pid_t pid; + char *prog[3]; + + prog[0] = (char*)"runsv"; + prog[1] = (char*)name; + prog[2] = NULL; + + pid = vfork(); if (pid == -1) { - warn2_cannot("fork for ", name); + warn2_cannot("vfork", ""); return; } if (pid == 0) { /* child */ - char *prog[3]; - - prog[0] = (char*)"runsv"; - prog[1] = (char*)name; - prog[2] = NULL; - if (pgrp) + if (set_pgrp) setsid(); - signal(SIGHUP, SIG_DFL); - signal(SIGTERM, SIG_DFL); - BB_EXECVP(prog[0], prog); - //pathexec_run(*prog, prog, (char* const*)environ); + bb_signals(0 + + (1 << SIGHUP) + + (1 << SIGTERM) + , SIG_DFL); + execvp(prog[0], prog); fatal2_cannot("start runsv ", name); } sv[no].pid = pid; } -static void runsvdir(void) +static void do_rescan(void) { DIR *dir; direntry *d; @@ -122,17 +139,26 @@ static void runsvdir(void) } for (i = 0; i < svnum; i++) sv[i].isgone = 1; - errno = 0; - while ((d = readdir(dir))) { - if (d->d_name[0] == '.') continue; + + while (1) { + errno = 0; + d = readdir(dir); + if (!d) + break; + if (d->d_name[0] == '.') + continue; if (stat(d->d_name, &s) == -1) { warn2_cannot("stat ", d->d_name); - errno = 0; continue; } - if (!S_ISDIR(s.st_mode)) continue; + if (!S_ISDIR(s.st_mode)) + continue; for (i = 0; i < svnum; i++) { - if ((sv[i].ino == s.st_ino) && (sv[i].dev == s.st_dev)) { + if ((sv[i].ino == s.st_ino) +#if CHECK_DEVNO_TOO + && (sv[i].dev == s.st_dev) +#endif + ) { sv[i].isgone = 0; if (!sv[i].pid) runsv(i, d->d_name); @@ -143,147 +169,136 @@ static void runsvdir(void) /* new service */ struct service *svnew = realloc(sv, (i+1) * sizeof(*sv)); if (!svnew) { - warn3x("cannot start runsv ", d->d_name, - " too many services"); + warn2_cannot("start runsv ", d->d_name); continue; } sv = svnew; svnum++; memset(&sv[i], 0, sizeof(sv[i])); sv[i].ino = s.st_ino; +#if CHECK_DEVNO_TOO sv[i].dev = s.st_dev; - //sv[i].pid = 0; - //sv[i].isgone = 0; +#endif + /*sv[i].pid = 0;*/ + /*sv[i].isgone = 0;*/ runsv(i, d->d_name); - check = 1; + need_rescan = 1; } } - if (errno) { + i = errno; + closedir(dir); + if (i) { warn2_cannot("read directory ", svdir); - closedir(dir); - check = 1; + need_rescan = 1; return; } - closedir(dir); - /* SIGTERM removed runsv's */ + /* Send SIGTERM to runsv whose directories were not found (removed) */ for (i = 0; i < svnum; i++) { if (!sv[i].isgone) continue; if (sv[i].pid) kill(sv[i].pid, SIGTERM); - sv[i] = sv[--svnum]; - check = 1; + svnum--; + sv[i] = sv[svnum]; + i--; /* so that we don't skip new sv[i] (bug was here!) */ + need_rescan = 1; } } -static int setup_log(void) -{ - rploglen = strlen(rplog); - if (rploglen < 7) { - warnx("log must have at least seven characters"); - return 0; - } - if (pipe(logpipe)) { - warnx("cannot create pipe for log"); - return -1; - } - coe(logpipe[1]); - coe(logpipe[0]); - ndelay_on(logpipe[0]); - ndelay_on(logpipe[1]); - if (dup2(logpipe[1], 2) == -1) { - warnx("cannot set filedescriptor for log"); - return -1; - } - io[0].fd = logpipe[0]; - io[0].events = IOPAUSE_READ; - taia_now(&stamplog); - return 1; -} - -int runsvdir_main(int argc, char **argv); -int runsvdir_main(int argc, char **argv) +int runsvdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int runsvdir_main(int argc UNUSED_PARAM, char **argv) { struct stat s; - time_t mtime = 0; + dev_t last_dev = last_dev; /* for gcc */ + ino_t last_ino = last_ino; /* for gcc */ + time_t last_mtime = 0; int wstat; int curdir; int pid; - struct taia deadline; - struct taia now; - struct taia stampcheck; - char ch; + unsigned deadline; + unsigned now; + unsigned stampcheck; int i; - argv++; - if (!argv || !*argv) usage(); - if (**argv == '-') { - switch (*(*argv + 1)) { - case 'P': pgrp = 1; - case '-': ++argv; - } - if (!argv || !*argv) usage(); - } + INIT_G(); + + opt_complementary = "-1"; + set_pgrp = getopt32(argv, "P"); + argv += optind; - sig_catch(SIGTERM, s_term); - sig_catch(SIGHUP, s_hangup); + bb_signals_recursive((1 << SIGTERM) | (1 << SIGHUP), record_signo); svdir = *argv++; - if (argv && *argv) { + +#if ENABLE_FEATURE_RUNSVDIR_LOG + /* setup log */ + if (*argv) { rplog = *argv; - if (setup_log() != 1) { - rplog = 0; - warnx("log service disabled"); + rploglen = strlen(rplog); + if (rploglen < 7) { + warnx("log must have at least seven characters"); + } else if (piped_pair(logpipe)) { + warnx("cannot create pipe for log"); + } else { + close_on_exec_on(logpipe.rd); + close_on_exec_on(logpipe.wr); + ndelay_on(logpipe.rd); + ndelay_on(logpipe.wr); + if (dup2(logpipe.wr, 2) == -1) { + warnx("cannot set filedescriptor for log"); + } else { + pfd[0].fd = logpipe.rd; + pfd[0].events = POLLIN; + stamplog = monotonic_sec(); + goto run; + } } + rplog = NULL; + warnx("log service disabled"); } +run: +#endif curdir = open_read("."); if (curdir == -1) fatal2_cannot("open current directory", ""); - coe(curdir); + close_on_exec_on(curdir); - taia_now(&stampcheck); + stampcheck = monotonic_sec(); for (;;) { /* collect children */ for (;;) { - pid = wait_nohang(&wstat); - if (pid <= 0) break; + pid = wait_any_nohang(&wstat); + if (pid <= 0) + break; for (i = 0; i < svnum; i++) { if (pid == sv[i].pid) { /* runsv has gone */ sv[i].pid = 0; - check = 1; + need_rescan = 1; break; } } } - taia_now(&now); - if (now.sec.x < (stampcheck.sec.x - 3)) { - /* time warp */ - warnx("time warp: resetting time stamp"); - taia_now(&stampcheck); - taia_now(&now); - if (rplog) taia_now(&stamplog); - } - if (taia_less(&now, &stampcheck) == 0) { + now = monotonic_sec(); + if ((int)(now - stampcheck) >= 0) { /* wait at least a second */ - taia_uint(&deadline, 1); - taia_add(&stampcheck, &now, &deadline); + stampcheck = now + 1; if (stat(svdir, &s) != -1) { - if (check || s.st_mtime != mtime - || s.st_ino != ino || s.st_dev != dev + if (need_rescan || s.st_mtime != last_mtime + || s.st_ino != last_ino || s.st_dev != last_dev ) { /* svdir modified */ if (chdir(svdir) != -1) { - mtime = s.st_mtime; - dev = s.st_dev; - ino = s.st_ino; - check = 0; - if (now.sec.x <= (4611686018427387914ULL + (uint64_t)mtime)) - sleep(1); - runsvdir(); + last_mtime = s.st_mtime; + last_dev = s.st_dev; + last_ino = s.st_ino; + need_rescan = 0; + //if (now <= mtime) + // sleep(1); + do_rescan(); while (fchdir(curdir) == -1) { warn2_cannot("change directory, pausing", ""); sleep(5); @@ -295,39 +310,45 @@ int runsvdir_main(int argc, char **argv) warn2_cannot("stat ", svdir); } +#if ENABLE_FEATURE_RUNSVDIR_LOG if (rplog) { - if (taia_less(&now, &stamplog) == 0) { - write(logpipe[1], ".", 1); - taia_uint(&deadline, 900); - taia_add(&stamplog, &now, &deadline); + if ((int)(now - stamplog) >= 0) { + write(logpipe.wr, ".", 1); + stamplog = now + 900; } } - taia_uint(&deadline, check ? 1 : 5); - taia_add(&deadline, &now, &deadline); - + pfd[0].revents = 0; +#endif sig_block(SIGCHLD); + deadline = (need_rescan ? 1 : 5); +#if ENABLE_FEATURE_RUNSVDIR_LOG if (rplog) - iopause(io, 1, &deadline, &now); + poll(pfd, 1, deadline*1000); else - iopause(0, 0, &deadline, &now); +#endif + sleep(deadline); sig_unblock(SIGCHLD); - if (rplog && (io[0].revents | IOPAUSE_READ)) - while (read(logpipe[0], &ch, 1) > 0) +#if ENABLE_FEATURE_RUNSVDIR_LOG + if (pfd[0].revents & POLLIN) { + char ch; + while (read(logpipe.rd, &ch, 1) > 0) { if (ch) { for (i = 6; i < rploglen; i++) rplog[i-1] = rplog[i]; rplog[rploglen-1] = ch; } - - switch (exitsoon) { - case 1: - _exit(0); - case 2: + } + } +#endif + switch (bb_got_signal) { + case SIGHUP: for (i = 0; i < svnum; i++) if (sv[i].pid) kill(sv[i].pid, SIGTERM); - _exit(111); + // N.B. fall through + case SIGTERM: + _exit((SIGHUP == bb_got_signal) ? 111 : EXIT_SUCCESS); } } /* not reached */