2 Copyright (c) 2001-2006, Gerrit Pape
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 /* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
29 /* TODO: depends on runit_lib.c - review and reduce/eliminate */
34 #include "runit_lib.h"
36 #if ENABLE_MONOTONIC_SYSCALL
37 #include <sys/syscall.h>
39 /* libc has incredibly messy way of doing this,
40 * typically requiring -lrt. We just skip all this mess */
41 static void gettimeofday_ns(struct timespec *ts)
43 syscall(__NR_clock_gettime, CLOCK_REALTIME, ts);
46 static void gettimeofday_ns(struct timespec *ts)
48 if (sizeof(struct timeval) == sizeof(struct timespec)
49 && sizeof(((struct timeval*)ts)->tv_usec) == sizeof(ts->tv_nsec)
52 gettimeofday((void*)ts, NULL);
55 extern void BUG_need_to_implement_gettimeofday_ns(void);
56 BUG_need_to_implement_gettimeofday_ns();
61 /* Compare possibly overflowing unsigned counters */
62 #define LESS(a,b) ((int)((unsigned)(b) - (unsigned)(a)) > 0)
83 struct timespec start;
93 struct fd_pair selfpipe;
94 struct fd_pair logpipe;
98 #define G (*(struct globals*)&bb_common_bufsiz1)
99 #define haslog (G.haslog )
100 #define sigterm (G.sigterm )
101 #define pidchanged (G.pidchanged )
102 #define selfpipe (G.selfpipe )
103 #define logpipe (G.logpipe )
111 static void fatal2_cannot(const char *m1, const char *m2)
113 bb_perror_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2);
114 /* was exiting 111 */
116 static void fatal_cannot(const char *m)
118 fatal2_cannot(m, "");
119 /* was exiting 111 */
121 static void fatal2x_cannot(const char *m1, const char *m2)
123 bb_error_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2);
124 /* was exiting 111 */
126 static void warn_cannot(const char *m)
128 bb_perror_msg("%s: warning: cannot %s", dir, m);
131 static void s_child(int sig_no ATTRIBUTE_UNUSED)
133 write(selfpipe.wr, "", 1);
136 static void s_term(int sig_no ATTRIBUTE_UNUSED)
139 write(selfpipe.wr, "", 1); /* XXX */
142 static char *add_str(char *p, const char *to_add)
144 while ((*p = *to_add) != '\0') {
151 static int open_trunc_or_warn(const char *name)
153 int fd = open_trunc(name);
155 bb_perror_msg("%s: warning: cannot open %s",
160 static void update_status(struct svdir *s)
168 fd = open_trunc_or_warn("supervise/pid.new");
172 char spid[sizeof(int)*3 + 2];
173 int size = sprintf(spid, "%u\n", (unsigned)s->pid);
174 write(fd, spid, size);
177 if (rename_or_warn("supervise/pid.new",
178 s->islog ? "log/supervise/pid" : "log/supervise/pid"+4))
184 fd = open_trunc_or_warn("supervise/stat.new");
189 char stat_buf[sizeof("finish, paused, got TERM, want down\n")];
193 p = add_str(p, "down");
196 p = add_str(p, "run");
199 p = add_str(p, "finish");
202 if (s->ctrl & C_PAUSE) p = add_str(p, ", paused");
203 if (s->ctrl & C_TERM) p = add_str(p, ", got TERM");
204 if (s->state != S_DOWN)
207 p = add_str(p, ", want down");
210 p = add_str(p, ", want exit");
214 write(fd, stat_buf, p - stat_buf);
218 rename_or_warn("supervise/stat.new",
219 s->islog ? "log/supervise/stat" : "log/supervise/stat"+4);
221 /* supervise compatibility */
222 memset(&status, 0, sizeof(status));
223 status.time_be64 = SWAP_BE64(s->start.tv_sec + 0x400000000000000aULL);
224 status.time_nsec_be32 = SWAP_BE32(s->start.tv_nsec);
225 status.pid_le32 = SWAP_LE32(s->pid);
226 if (s->ctrl & C_PAUSE)
232 if (s->ctrl & C_TERM)
234 status.run_or_finish = s->state;
235 fd = open_trunc_or_warn("supervise/status.new");
238 sz = write(fd, &status, sizeof(status));
240 if (sz != sizeof(status)) {
241 warn_cannot("write supervise/status.new");
242 unlink("supervise/status.new");
245 rename_or_warn("supervise/status.new",
246 s->islog ? "log/supervise/status" : "log/supervise/status"+4);
249 static unsigned custom(struct svdir *s, char c)
257 if (s->islog) return 0;
258 strcpy(a, "control/?");
259 a[8] = c; /* replace '?' */
260 if (stat(a, &st) == 0) {
261 if (st.st_mode & S_IXUSR) {
264 warn_cannot("vfork for control/?");
269 if (haslog && dup2(logpipe.wr, 1) == -1)
270 warn_cannot("setup stdout for control/?");
274 fatal_cannot("run control/?");
277 while (safe_waitpid(pid, &w, 0) == -1) {
278 warn_cannot("wait for child control/?");
281 return !wait_exitcode(w);
285 warn_cannot("stat control/?");
290 static void stopservice(struct svdir *s)
292 if (s->pid && !custom(s, 't')) {
293 kill(s->pid, SIGTERM);
297 if (s->want == W_DOWN) {
298 kill(s->pid, SIGCONT);
302 if (s->want == W_EXIT) {
303 kill(s->pid, SIGCONT);
308 static void startservice(struct svdir *s)
313 if (s->state == S_FINISH)
314 run[0] = (char*)"./finish";
316 run[0] = (char*)"./run";
322 stopservice(s); /* should never happen */
323 while ((p = vfork()) == -1) {
324 warn_cannot("vfork, sleeping");
330 /* NB: bug alert! right order is close, then dup2 */
334 xdup2(logpipe.rd, 0);
337 xdup2(logpipe.wr, 1);
344 sig_unblock(SIGCHLD);
345 sig_unblock(SIGTERM);
347 fatal2_cannot(s->islog ? "start log/" : "start ", *run);
350 if (s->state != S_FINISH) {
351 gettimeofday_ns(&s->start);
360 static int ctrl(struct svdir *s, char c)
368 if (s->pid && s->state != S_FINISH)
383 case 't': /* sig term */
384 if (s->pid && s->state != S_FINISH)
387 case 'k': /* sig kill */
388 if (s->pid && !custom(s, c))
389 kill(s->pid, SIGKILL);
392 case 'p': /* sig pause */
393 if (s->pid && !custom(s, c))
394 kill(s->pid, SIGSTOP);
398 case 'c': /* sig cont */
399 if (s->pid && !custom(s, c))
400 kill(s->pid, SIGCONT);
401 if (s->ctrl & C_PAUSE)
411 case 'a': /* sig alarm */
414 case 'h': /* sig hup */
417 case 'i': /* sig int */
420 case 'q': /* sig quit */
423 case '1': /* sig usr1 */
426 case '2': /* sig usr2 */
432 if (s->pid && !custom(s, c))
437 int runsv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
438 int runsv_main(int argc ATTRIBUTE_UNUSED, char **argv)
447 if (!argv[1] || argv[2])
451 xpiped_pair(selfpipe);
452 close_on_exec_on(selfpipe.rd);
453 close_on_exec_on(selfpipe.wr);
454 ndelay_on(selfpipe.rd);
455 ndelay_on(selfpipe.wr);
458 bb_signals_recursive(1 << SIGCHLD, s_child);
460 bb_signals_recursive(1 << SIGTERM, s_term);
463 /* bss: svd[0].pid = 0; */
464 if (S_DOWN) svd[0].state = S_DOWN; /* otherwise already 0 (bss) */
465 if (C_NOOP) svd[0].ctrl = C_NOOP;
466 if (W_UP) svd[0].want = W_UP;
467 /* bss: svd[0].islog = 0; */
468 /* bss: svd[1].pid = 0; */
469 gettimeofday_ns(&svd[0].start);
470 if (stat("down", &s) != -1) svd[0].want = W_DOWN;
472 if (stat("log", &s) == -1) {
474 warn_cannot("stat ./log");
476 if (!S_ISDIR(s.st_mode)) {
478 warn_cannot("stat log/down: log is not a directory");
481 svd[1].state = S_DOWN;
482 svd[1].ctrl = C_NOOP;
485 gettimeofday_ns(&svd[1].start);
486 if (stat("log/down", &s) != -1)
487 svd[1].want = W_DOWN;
488 xpiped_pair(logpipe);
489 close_on_exec_on(logpipe.rd);
490 close_on_exec_on(logpipe.wr);
494 if (mkdir("supervise", 0700) == -1) {
495 r = readlink("supervise", buf, sizeof(buf));
497 if (r == sizeof(buf))
498 fatal2x_cannot("readlink ./supervise", ": name too long");
502 if ((errno != ENOENT) && (errno != EINVAL))
503 fatal_cannot("readlink ./supervise");
506 svd[0].fdlock = xopen3("log/supervise/lock"+4,
507 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
508 if (lock_exnb(svd[0].fdlock) == -1)
509 fatal_cannot("lock supervise/lock");
510 close_on_exec_on(svd[0].fdlock);
512 if (mkdir("log/supervise", 0700) == -1) {
513 r = readlink("log/supervise", buf, 256);
516 fatal2x_cannot("readlink ./log/supervise", ": name too long");
518 fd = xopen(".", O_RDONLY|O_NDELAY);
521 if (fchdir(fd) == -1)
522 fatal_cannot("change back to service directory");
526 if ((errno != ENOENT) && (errno != EINVAL))
527 fatal_cannot("readlink ./log/supervise");
530 svd[1].fdlock = xopen3("log/supervise/lock",
531 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
532 if (lock_ex(svd[1].fdlock) == -1)
533 fatal_cannot("lock log/supervise/lock");
534 close_on_exec_on(svd[1].fdlock);
537 mkfifo("log/supervise/control"+4, 0600);
538 svd[0].fdcontrol = xopen("log/supervise/control"+4, O_RDONLY|O_NDELAY);
539 close_on_exec_on(svd[0].fdcontrol);
540 svd[0].fdcontrolwrite = xopen("log/supervise/control"+4, O_WRONLY|O_NDELAY);
541 close_on_exec_on(svd[0].fdcontrolwrite);
542 update_status(&svd[0]);
544 mkfifo("log/supervise/control", 0600);
545 svd[1].fdcontrol = xopen("log/supervise/control", O_RDONLY|O_NDELAY);
546 close_on_exec_on(svd[1].fdcontrol);
547 svd[1].fdcontrolwrite = xopen("log/supervise/control", O_WRONLY|O_NDELAY);
548 close_on_exec_on(svd[1].fdcontrolwrite);
549 update_status(&svd[1]);
551 mkfifo("log/supervise/ok"+4, 0600);
552 fd = xopen("log/supervise/ok"+4, O_RDONLY|O_NDELAY);
553 close_on_exec_on(fd);
555 mkfifo("log/supervise/ok", 0600);
556 fd = xopen("log/supervise/ok", O_RDONLY|O_NDELAY);
557 close_on_exec_on(fd);
565 if (!svd[1].pid && svd[1].want == W_UP)
566 startservice(&svd[1]);
568 if (svd[0].want == W_UP || svd[0].state == S_FINISH)
569 startservice(&svd[0]);
571 x[0].fd = selfpipe.rd;
572 x[0].events = POLLIN;
573 x[1].fd = svd[0].fdcontrol;
574 x[1].events = POLLIN;
575 /* x[2] is used only if haslog == 1 */
576 x[2].fd = svd[1].fdcontrol;
577 x[2].events = POLLIN;
578 sig_unblock(SIGTERM);
579 sig_unblock(SIGCHLD);
580 poll(x, 2 + haslog, 3600*1000);
584 while (read(selfpipe.rd, &ch, 1) == 1)
591 child = wait_any_nohang(&wstat);
594 if ((child == -1) && (errno != EINTR))
596 if (child == svd[0].pid) {
599 svd[0].ctrl &=~ C_TERM;
600 if (svd[0].state != S_FINISH) {
601 fd = open_read("finish");
604 svd[0].state = S_FINISH;
605 update_status(&svd[0]);
609 svd[0].state = S_DOWN;
610 deadline = svd[0].start.tv_sec + 1;
611 gettimeofday_ns(&svd[0].start);
612 update_status(&svd[0]);
613 if (LESS(svd[0].start.tv_sec, deadline))
617 if (child == svd[1].pid) {
620 svd[1].state = S_DOWN;
621 svd[1].ctrl &= ~C_TERM;
622 deadline = svd[1].start.tv_sec + 1;
623 gettimeofday_ns(&svd[1].start);
624 update_status(&svd[1]);
625 if (LESS(svd[1].start.tv_sec, deadline))
630 if (read(svd[0].fdcontrol, &ch, 1) == 1)
633 if (read(svd[1].fdcontrol, &ch, 1) == 1)
641 if (svd[0].want == W_EXIT && svd[0].state == S_DOWN) {
644 if (svd[1].want != W_EXIT) {
645 svd[1].want = W_EXIT;
646 /* stopservice(&svd[1]); */
647 update_status(&svd[1]);