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/?");
260 if (stat(a, &st) == 0) {
261 if (st.st_mode & S_IXUSR) {
264 warn_cannot("fork for control/?");
268 if (haslog && dup2(logpipe.wr, 1) == -1)
269 warn_cannot("setup stdout for control/?");
273 fatal_cannot("run control/?");
275 while (safe_waitpid(pid, &w, 0) == -1) {
276 warn_cannot("wait for child control/?");
279 return !wait_exitcode(w);
283 warn_cannot("stat control/?");
288 static void stopservice(struct svdir *s)
290 if (s->pid && !custom(s, 't')) {
291 kill(s->pid, SIGTERM);
295 if (s->want == W_DOWN) {
296 kill(s->pid, SIGCONT);
300 if (s->want == W_EXIT) {
301 kill(s->pid, SIGCONT);
306 static void startservice(struct svdir *s)
311 if (s->state == S_FINISH)
312 run[0] = (char*)"./finish";
314 run[0] = (char*)"./run";
320 stopservice(s); /* should never happen */
321 while ((p = fork()) == -1) {
322 warn_cannot("fork, sleeping");
328 /* NB: bug alert! right order is close, then dup2 */
332 xdup2(logpipe.rd, 0);
335 xdup2(logpipe.wr, 1);
342 sig_unblock(SIGCHLD);
343 sig_unblock(SIGTERM);
345 fatal2_cannot(s->islog ? "start log/" : "start ", *run);
347 if (s->state != S_FINISH) {
348 gettimeofday_ns(&s->start);
357 static int ctrl(struct svdir *s, char c)
365 if (s->pid && s->state != S_FINISH)
380 case 't': /* sig term */
381 if (s->pid && s->state != S_FINISH)
384 case 'k': /* sig kill */
385 if (s->pid && !custom(s, c))
386 kill(s->pid, SIGKILL);
389 case 'p': /* sig pause */
390 if (s->pid && !custom(s, c))
391 kill(s->pid, SIGSTOP);
395 case 'c': /* sig cont */
396 if (s->pid && !custom(s, c))
397 kill(s->pid, SIGCONT);
398 if (s->ctrl & C_PAUSE)
408 case 'a': /* sig alarm */
411 case 'h': /* sig hup */
414 case 'i': /* sig int */
417 case 'q': /* sig quit */
420 case '1': /* sig usr1 */
423 case '2': /* sig usr2 */
429 if (s->pid && !custom(s, c))
434 int runsv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
435 int runsv_main(int argc ATTRIBUTE_UNUSED, char **argv)
444 if (!argv[1] || argv[2])
448 xpiped_pair(selfpipe);
449 close_on_exec_on(selfpipe.rd);
450 close_on_exec_on(selfpipe.wr);
451 ndelay_on(selfpipe.rd);
452 ndelay_on(selfpipe.wr);
455 bb_signals_recursive(1 << SIGCHLD, s_child);
457 bb_signals_recursive(1 << SIGTERM, s_term);
460 /* bss: svd[0].pid = 0; */
461 if (S_DOWN) svd[0].state = S_DOWN; /* otherwise already 0 (bss) */
462 if (C_NOOP) svd[0].ctrl = C_NOOP;
463 if (W_UP) svd[0].want = W_UP;
464 /* bss: svd[0].islog = 0; */
465 /* bss: svd[1].pid = 0; */
466 gettimeofday_ns(&svd[0].start);
467 if (stat("down", &s) != -1) svd[0].want = W_DOWN;
469 if (stat("log", &s) == -1) {
471 warn_cannot("stat ./log");
473 if (!S_ISDIR(s.st_mode)) {
475 warn_cannot("stat log/down: log is not a directory");
478 svd[1].state = S_DOWN;
479 svd[1].ctrl = C_NOOP;
482 gettimeofday_ns(&svd[1].start);
483 if (stat("log/down", &s) != -1)
484 svd[1].want = W_DOWN;
485 xpiped_pair(logpipe);
486 close_on_exec_on(logpipe.rd);
487 close_on_exec_on(logpipe.wr);
491 if (mkdir("supervise", 0700) == -1) {
492 r = readlink("supervise", buf, sizeof(buf));
494 if (r == sizeof(buf))
495 fatal2x_cannot("readlink ./supervise", ": name too long");
499 if ((errno != ENOENT) && (errno != EINVAL))
500 fatal_cannot("readlink ./supervise");
503 svd[0].fdlock = xopen3("log/supervise/lock"+4,
504 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
505 if (lock_exnb(svd[0].fdlock) == -1)
506 fatal_cannot("lock supervise/lock");
507 close_on_exec_on(svd[0].fdlock);
509 if (mkdir("log/supervise", 0700) == -1) {
510 r = readlink("log/supervise", buf, 256);
513 fatal2x_cannot("readlink ./log/supervise", ": name too long");
515 fd = xopen(".", O_RDONLY|O_NDELAY);
518 if (fchdir(fd) == -1)
519 fatal_cannot("change back to service directory");
523 if ((errno != ENOENT) && (errno != EINVAL))
524 fatal_cannot("readlink ./log/supervise");
527 svd[1].fdlock = xopen3("log/supervise/lock",
528 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
529 if (lock_ex(svd[1].fdlock) == -1)
530 fatal_cannot("lock log/supervise/lock");
531 close_on_exec_on(svd[1].fdlock);
534 mkfifo("log/supervise/control"+4, 0600);
535 svd[0].fdcontrol = xopen("log/supervise/control"+4, O_RDONLY|O_NDELAY);
536 close_on_exec_on(svd[0].fdcontrol);
537 svd[0].fdcontrolwrite = xopen("log/supervise/control"+4, O_WRONLY|O_NDELAY);
538 close_on_exec_on(svd[0].fdcontrolwrite);
539 update_status(&svd[0]);
541 mkfifo("log/supervise/control", 0600);
542 svd[1].fdcontrol = xopen("log/supervise/control", O_RDONLY|O_NDELAY);
543 close_on_exec_on(svd[1].fdcontrol);
544 svd[1].fdcontrolwrite = xopen("log/supervise/control", O_WRONLY|O_NDELAY);
545 close_on_exec_on(svd[1].fdcontrolwrite);
546 update_status(&svd[1]);
548 mkfifo("log/supervise/ok"+4, 0600);
549 fd = xopen("log/supervise/ok"+4, O_RDONLY|O_NDELAY);
550 close_on_exec_on(fd);
552 mkfifo("log/supervise/ok", 0600);
553 fd = xopen("log/supervise/ok", O_RDONLY|O_NDELAY);
554 close_on_exec_on(fd);
562 if (!svd[1].pid && svd[1].want == W_UP)
563 startservice(&svd[1]);
565 if (svd[0].want == W_UP || svd[0].state == S_FINISH)
566 startservice(&svd[0]);
568 x[0].fd = selfpipe.rd;
569 x[0].events = POLLIN;
570 x[1].fd = svd[0].fdcontrol;
571 x[1].events = POLLIN;
572 /* x[2] is used only if haslog == 1 */
573 x[2].fd = svd[1].fdcontrol;
574 x[2].events = POLLIN;
575 sig_unblock(SIGTERM);
576 sig_unblock(SIGCHLD);
577 poll(x, 2 + haslog, 3600*1000);
581 while (read(selfpipe.rd, &ch, 1) == 1)
588 child = wait_any_nohang(&wstat);
591 if ((child == -1) && (errno != EINTR))
593 if (child == svd[0].pid) {
596 svd[0].ctrl &=~ C_TERM;
597 if (svd[0].state != S_FINISH) {
598 fd = open_read("finish");
601 svd[0].state = S_FINISH;
602 update_status(&svd[0]);
606 svd[0].state = S_DOWN;
607 deadline = svd[0].start.tv_sec + 1;
608 gettimeofday_ns(&svd[0].start);
609 update_status(&svd[0]);
610 if (LESS(svd[0].start.tv_sec, deadline))
614 if (child == svd[1].pid) {
617 svd[1].state = S_DOWN;
618 svd[1].ctrl &= ~C_TERM;
619 deadline = svd[1].start.tv_sec + 1;
620 gettimeofday_ns(&svd[1].start);
621 update_status(&svd[1]);
622 if (LESS(svd[1].start.tv_sec, deadline))
627 if (read(svd[0].fdcontrol, &ch, 1) == 1)
630 if (read(svd[1].fdcontrol, &ch, 1) == 1)
638 if (svd[0].want == W_EXIT && svd[0].state == S_DOWN) {
641 if (svd[1].want != W_EXIT) {
642 svd[1].want = W_EXIT;
643 /* stopservice(&svd[1]); */
644 update_status(&svd[1]);