1 /* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
2 /* TODO: depends on runit_lib.c - review and reduce/eliminate */
9 #define MAXSERVICES 1000
12 static unsigned long dev;
13 static unsigned long ino;
14 static struct service {
24 static int logpipe[2];
25 static iopause_fd io[1];
26 static struct taia stamplog;
30 #define usage() bb_show_usage()
31 static void fatal2_cannot(const char *m1, const char *m2)
33 bb_perror_msg_and_die("%s: fatal: cannot %s%s", svdir, m1, m2);
36 static void warn3x(const char *m1, const char *m2, const char *m3)
38 bb_error_msg("%s: warning: %s%s%s", svdir, m1, m2, m3);
40 static void warn2_cannot(const char *m1, const char *m2)
42 warn3x("cannot ", m1, m2);
44 static void warnx(const char *m1)
49 static void s_term(int sig_no)
53 static void s_hangup(int sig_no)
58 static void runsv(int no, const char *name)
63 warn2_cannot("fork for ", name);
70 prog[0] = (char*)"runsv";
71 prog[1] = (char*)name;
76 BB_EXECVP(prog[0], prog);
77 //pathexec_run(*prog, prog, (char* const*)environ);
78 fatal2_cannot("start runsv ", name);
83 static void runsvdir(void)
92 warn2_cannot("open directory ", svdir);
95 for (i = 0; i < svnum; i++)
98 while ((d = readdir(dir))) {
99 if (d->d_name[0] == '.') continue;
100 if (stat(d->d_name, &s) == -1) {
101 warn2_cannot("stat ", d->d_name);
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)) {
116 struct service *svnew = realloc(sv, (i+1) * sizeof(*sv));
118 warn3x("cannot start runsv ", d->d_name,
119 " too many services");
124 memset(&sv[i], 0, sizeof(sv[i]));
125 sv[i].ino = s.st_ino;
126 sv[i].dev = s.st_dev;
134 warn2_cannot("read directory ", svdir);
141 /* SIGTERM removed runsv's */
142 for (i = 0; i < svnum; i++) {
146 kill(sv[i].pid, SIGTERM);
152 static int setup_log(void)
154 rploglen = strlen(rplog);
156 warnx("log must have at least seven characters");
159 if (pipe(logpipe) == -1) {
160 warnx("cannot create pipe for log");
165 ndelay_on(logpipe[0]);
166 ndelay_on(logpipe[1]);
167 if (fd_copy(2, logpipe[1]) == -1) {
168 warnx("cannot set filedescriptor for log");
171 io[0].fd = logpipe[0];
172 io[0].events = IOPAUSE_READ;
177 int runsvdir_main(int argc, char **argv);
178 int runsvdir_main(int argc, char **argv)
185 struct taia deadline;
187 struct taia stampcheck;
192 if (!argv || !*argv) usage();
194 switch (*(*argv + 1)) {
198 if (!argv || !*argv) usage();
201 sig_catch(SIGTERM, s_term);
202 sig_catch(SIGHUP, s_hangup);
206 if (setup_log() != 1) {
208 warnx("log service disabled");
211 curdir = open_read(".");
213 fatal2_cannot("open current directory", "");
216 taia_now(&stampcheck);
219 /* collect children */
221 pid = wait_nohang(&wstat);
223 for (i = 0; i < svnum; i++) {
224 if (pid == sv[i].pid) {
234 if (now.sec.x < (stampcheck.sec.x - 3)) {
236 warnx("time warp: resetting time stamp");
237 taia_now(&stampcheck);
239 if (rplog) taia_now(&stamplog);
241 if (taia_less(&now, &stampcheck) == 0) {
242 /* wait at least a second */
243 taia_uint(&deadline, 1);
244 taia_add(&stampcheck, &now, &deadline);
246 if (stat(svdir, &s) != -1) {
247 if (check || s.st_mtime != mtime
248 || s.st_ino != ino || s.st_dev != dev
251 if (chdir(svdir) != -1) {
256 if (now.sec.x <= (4611686018427387914ULL + (uint64_t)mtime))
259 while (fchdir(curdir) == -1) {
260 warn2_cannot("change directory, pausing", "");
264 warn2_cannot("change directory to ", svdir);
267 warn2_cannot("stat ", svdir);
271 if (taia_less(&now, &stamplog) == 0) {
272 write(logpipe[1], ".", 1);
273 taia_uint(&deadline, 900);
274 taia_add(&stamplog, &now, &deadline);
277 taia_uint(&deadline, check ? 1 : 5);
278 taia_add(&deadline, &now, &deadline);
282 iopause(io, 1, &deadline, &now);
284 iopause(0, 0, &deadline, &now);
285 sig_unblock(SIGCHLD);
287 if (rplog && (io[0].revents | IOPAUSE_READ))
288 while (read(logpipe[0], &ch, 1) > 0)
290 for (i = 6; i < rploglen; i++)
291 rplog[i-1] = rplog[i];
292 rplog[rploglen-1] = ch;
299 for (i = 0; i < svnum; i++)
301 kill(sv[i].pid, SIGTERM);