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 Denis 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;
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)
133 write(selfpipe[1], "", 1);
136 static void s_term(int sig_no)
139 write(selfpipe[1], "", 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 int rename_or_warn(const char *old, const char *new)
162 if (rename(old, new) == -1) {
163 bb_perror_msg("%s: warning: cannot rename %s to %s",
170 static void update_status(struct svdir *s)
178 fd = open_trunc_or_warn("supervise/pid.new");
182 char spid[sizeof(int)*3 + 2];
183 int size = sprintf(spid, "%u\n", (unsigned)s->pid);
184 write(fd, spid, size);
187 if (rename_or_warn("supervise/pid.new",
188 s->islog ? "log/supervise/pid" : "log/supervise/pid"+4))
194 fd = open_trunc_or_warn("supervise/stat.new");
199 char stat_buf[sizeof("finish, paused, got TERM, want down\n")];
203 p = add_str(p, "down");
206 p = add_str(p, "run");
209 p = add_str(p, "finish");
212 if (s->ctrl & C_PAUSE) p = add_str(p, ", paused");
213 if (s->ctrl & C_TERM) p = add_str(p, ", got TERM");
214 if (s->state != S_DOWN)
217 p = add_str(p, ", want down");
220 p = add_str(p, ", want exit");
224 write(fd, stat_buf, p - stat_buf);
228 rename_or_warn("supervise/stat.new",
229 s->islog ? "log/supervise/stat" : "log/supervise/stat"+4);
231 /* supervise compatibility */
232 memset(&status, 0, sizeof(status));
233 status.time_be64 = SWAP_BE64(s->start.tv_sec + 0x400000000000000aULL);
234 status.time_nsec_be32 = SWAP_BE32(s->start.tv_nsec);
235 status.pid_le32 = SWAP_LE32(s->pid);
236 if (s->ctrl & C_PAUSE)
242 if (s->ctrl & C_TERM)
244 status.run_or_finish = s->state;
245 fd = open_trunc_or_warn("supervise/status.new");
248 sz = write(fd, &status, sizeof(status));
250 if (sz != sizeof(status)) {
251 warn_cannot("write supervise/status.new");
252 unlink("supervise/status.new");
255 rename_or_warn("supervise/status.new",
256 s->islog ? "log/supervise/status" : "log/supervise/status"+4);
259 static unsigned custom(struct svdir *s, char c)
267 if (s->islog) return 0;
268 strcpy(a, "control/?");
270 if (stat(a, &st) == 0) {
271 if (st.st_mode & S_IXUSR) {
274 warn_cannot("fork for control/?");
278 if (haslog && dup2(logpipe[1], 1) == -1)
279 warn_cannot("setup stdout for control/?");
283 fatal_cannot("run control/?");
285 while (safe_waitpid(pid, &w, 0) == -1) {
286 warn_cannot("wait for child control/?");
289 return !wait_exitcode(w);
293 warn_cannot("stat control/?");
298 static void stopservice(struct svdir *s)
300 if (s->pid && !custom(s, 't')) {
301 kill(s->pid, SIGTERM);
305 if (s->want == W_DOWN) {
306 kill(s->pid, SIGCONT);
310 if (s->want == W_EXIT) {
311 kill(s->pid, SIGCONT);
316 static void startservice(struct svdir *s)
321 if (s->state == S_FINISH)
322 run[0] = (char*)"./finish";
324 run[0] = (char*)"./run";
330 stopservice(s); /* should never happen */
331 while ((p = fork()) == -1) {
332 warn_cannot("fork, sleeping");
339 xdup2(logpipe[0], 0);
343 xdup2(logpipe[1], 1);
347 signal(SIGCHLD, SIG_DFL);
348 signal(SIGTERM, SIG_DFL);
349 sig_unblock(SIGCHLD);
350 sig_unblock(SIGTERM);
352 fatal2_cannot(s->islog ? "start log/" : "start ", *run);
354 if (s->state != S_FINISH) {
355 gettimeofday_ns(&s->start);
364 static int ctrl(struct svdir *s, char c)
372 if (s->pid && s->state != S_FINISH)
387 case 't': /* sig term */
388 if (s->pid && s->state != S_FINISH)
391 case 'k': /* sig kill */
392 if (s->pid && !custom(s, c))
393 kill(s->pid, SIGKILL);
396 case 'p': /* sig pause */
397 if (s->pid && !custom(s, c))
398 kill(s->pid, SIGSTOP);
402 case 'c': /* sig cont */
403 if (s->pid && !custom(s, c))
404 kill(s->pid, SIGCONT);
405 if (s->ctrl & C_PAUSE)
415 case 'a': /* sig alarm */
418 case 'h': /* sig hup */
421 case 'i': /* sig int */
424 case 'q': /* sig quit */
427 case '1': /* sig usr1 */
430 case '2': /* sig usr2 */
436 if (s->pid && !custom(s, c))
441 int runsv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
442 int runsv_main(int argc, char **argv)
451 if (!argv[1] || argv[2])
456 close_on_exec_on(selfpipe[0]);
457 close_on_exec_on(selfpipe[1]);
458 ndelay_on(selfpipe[0]);
459 ndelay_on(selfpipe[1]);
462 sig_catch(SIGCHLD, s_child);
464 sig_catch(SIGTERM, s_term);
467 /* bss: svd[0].pid = 0; */
468 if (S_DOWN) svd[0].state = S_DOWN; /* otherwise already 0 (bss) */
469 if (C_NOOP) svd[0].ctrl = C_NOOP;
470 if (W_UP) svd[0].want = W_UP;
471 /* bss: svd[0].islog = 0; */
472 /* bss: svd[1].pid = 0; */
473 gettimeofday_ns(&svd[0].start);
474 if (stat("down", &s) != -1) svd[0].want = W_DOWN;
476 if (stat("log", &s) == -1) {
478 warn_cannot("stat ./log");
480 if (!S_ISDIR(s.st_mode)) {
482 warn_cannot("stat log/down: log is not a directory");
485 svd[1].state = S_DOWN;
486 svd[1].ctrl = C_NOOP;
489 gettimeofday_ns(&svd[1].start);
490 if (stat("log/down", &s) != -1)
491 svd[1].want = W_DOWN;
493 close_on_exec_on(logpipe[0]);
494 close_on_exec_on(logpipe[1]);
498 if (mkdir("supervise", 0700) == -1) {
499 r = readlink("supervise", buf, sizeof(buf));
501 if (r == sizeof(buf))
502 fatal2x_cannot("readlink ./supervise", ": name too long");
506 if ((errno != ENOENT) && (errno != EINVAL))
507 fatal_cannot("readlink ./supervise");
510 svd[0].fdlock = xopen3("log/supervise/lock"+4,
511 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
512 if (lock_exnb(svd[0].fdlock) == -1)
513 fatal_cannot("lock supervise/lock");
514 close_on_exec_on(svd[0].fdlock);
516 if (mkdir("log/supervise", 0700) == -1) {
517 r = readlink("log/supervise", buf, 256);
520 fatal2x_cannot("readlink ./log/supervise", ": name too long");
522 fd = xopen(".", O_RDONLY|O_NDELAY);
525 if (fchdir(fd) == -1)
526 fatal_cannot("change back to service directory");
530 if ((errno != ENOENT) && (errno != EINVAL))
531 fatal_cannot("readlink ./log/supervise");
534 svd[1].fdlock = xopen3("log/supervise/lock",
535 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
536 if (lock_ex(svd[1].fdlock) == -1)
537 fatal_cannot("lock log/supervise/lock");
538 close_on_exec_on(svd[1].fdlock);
541 mkfifo("log/supervise/control"+4, 0600);
542 svd[0].fdcontrol = xopen("log/supervise/control"+4, O_RDONLY|O_NDELAY);
543 close_on_exec_on(svd[0].fdcontrol);
544 svd[0].fdcontrolwrite = xopen("log/supervise/control"+4, O_WRONLY|O_NDELAY);
545 close_on_exec_on(svd[0].fdcontrolwrite);
546 update_status(&svd[0]);
548 mkfifo("log/supervise/control", 0600);
549 svd[1].fdcontrol = xopen("log/supervise/control", O_RDONLY|O_NDELAY);
550 close_on_exec_on(svd[1].fdcontrol);
551 svd[1].fdcontrolwrite = xopen("log/supervise/control", O_WRONLY|O_NDELAY);
552 close_on_exec_on(svd[1].fdcontrolwrite);
553 update_status(&svd[1]);
555 mkfifo("log/supervise/ok"+4, 0600);
556 fd = xopen("log/supervise/ok"+4, O_RDONLY|O_NDELAY);
557 close_on_exec_on(fd);
559 mkfifo("log/supervise/ok", 0600);
560 fd = xopen("log/supervise/ok", O_RDONLY|O_NDELAY);
561 close_on_exec_on(fd);
569 if (!svd[1].pid && svd[1].want == W_UP)
570 startservice(&svd[1]);
572 if (svd[0].want == W_UP || svd[0].state == S_FINISH)
573 startservice(&svd[0]);
575 x[0].fd = selfpipe[0];
576 x[0].events = POLLIN;
577 x[1].fd = svd[0].fdcontrol;
578 x[1].events = POLLIN;
579 /* x[2] is used only if haslog == 1 */
580 x[2].fd = svd[1].fdcontrol;
581 x[2].events = POLLIN;
582 sig_unblock(SIGTERM);
583 sig_unblock(SIGCHLD);
584 poll(x, 2 + haslog, 3600*1000);
588 while (read(selfpipe[0], &ch, 1) == 1)
595 child = wait_any_nohang(&wstat);
598 if ((child == -1) && (errno != EINTR))
600 if (child == svd[0].pid) {
603 svd[0].ctrl &=~ C_TERM;
604 if (svd[0].state != S_FINISH) {
605 fd = open_read("finish");
608 svd[0].state = S_FINISH;
609 update_status(&svd[0]);
613 svd[0].state = S_DOWN;
614 deadline = svd[0].start.tv_sec + 1;
615 gettimeofday_ns(&svd[0].start);
616 update_status(&svd[0]);
617 if (LESS(svd[0].start.tv_sec, deadline))
621 if (child == svd[1].pid) {
624 svd[1].state = S_DOWN;
625 svd[1].ctrl &= ~C_TERM;
626 deadline = svd[1].start.tv_sec + 1;
627 gettimeofday_ns(&svd[1].start);
628 update_status(&svd[1]);
629 if (LESS(svd[1].start.tv_sec, deadline))
634 if (read(svd[0].fdcontrol, &ch, 1) == 1)
637 if (read(svd[1].fdcontrol, &ch, 1) == 1)
645 if (svd[0].want == W_EXIT && svd[0].state == S_DOWN) {
648 if (svd[1].want != W_EXIT) {
649 svd[1].want = W_EXIT;
650 /* stopservice(&svd[1]); */
651 update_status(&svd[1]);