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> */
31 //config: bool "runsv (8.2 kb)"
34 //config: runsv starts and monitors a service and optionally an appendant log
37 //applet:IF_RUNSV(APPLET(runsv, BB_DIR_USR_BIN, BB_SUID_DROP))
39 //kbuild:lib-$(CONFIG_RUNSV) += runsv.o
41 //usage:#define runsv_trivial_usage
43 //usage:#define runsv_full_usage "\n\n"
44 //usage: "Start and monitor a service and optionally an appendant log service"
48 #include "common_bufsiz.h"
49 #include "runit_lib.h"
51 #if ENABLE_MONOTONIC_SYSCALL
52 #include <sys/syscall.h>
54 static void gettimeofday_ns(struct timespec
*ts
)
56 clock_gettime(CLOCK_REALTIME
, ts
);
59 static void gettimeofday_ns(struct timespec
*ts
)
61 if (sizeof(struct timeval
) == sizeof(struct timespec
)
62 && sizeof(((struct timeval
*)ts
)->tv_usec
) == sizeof(ts
->tv_nsec
)
65 xgettimeofday((void*)ts
);
68 /* For example, musl has "incompatible" layouts */
71 ts
->tv_sec
= tv
.tv_sec
;
72 ts
->tv_nsec
= tv
.tv_usec
* 1000;
77 /* Compare possibly overflowing unsigned counters */
78 #define LESS(a,b) ((int)((unsigned)(b) - (unsigned)(a)) > 0)
99 struct timespec start
;
110 struct fd_pair selfpipe
;
111 struct fd_pair logpipe
;
115 #define G (*(struct globals*)bb_common_bufsiz1)
116 #define haslog (G.haslog )
117 #define sigterm (G.sigterm )
118 #define pidchanged (G.pidchanged )
119 #define selfpipe (G.selfpipe )
120 #define logpipe (G.logpipe )
123 #define INIT_G() do { \
124 setup_common_bufsiz(); \
128 static void fatal2_cannot(const char *m1
, const char *m2
)
130 bb_perror_msg_and_die("%s: fatal: can't %s%s", dir
, m1
, m2
);
131 /* was exiting 111 */
133 static void fatal_cannot(const char *m
)
135 fatal2_cannot(m
, "");
136 /* was exiting 111 */
138 static void fatal2x_cannot(const char *m1
, const char *m2
)
140 bb_error_msg_and_die("%s: fatal: can't %s%s", dir
, m1
, m2
);
141 /* was exiting 111 */
143 static void warn2_cannot(const char *m1
, const char *m2
)
145 bb_perror_msg("%s: warning: can't %s%s", dir
, m1
, m2
);
147 static void warn_cannot(const char *m
)
152 /* SIGCHLD/TERM handler is reentrancy-safe because they are unmasked
153 * only over poll() call, not over memory allocations
154 * or printouts. Do not need to save/restore errno either,
155 * as poll() error is not checked there.
157 static void s_chld_term(int sig_no
)
159 if (sig_no
== SIGTERM
)
161 write(selfpipe
.wr
, "", 1);
164 static int open_trunc_or_warn(const char *name
)
167 int fd
= open(name
, O_WRONLY
| O_NDELAY
| O_TRUNC
| O_CREAT
, 0644);
169 bb_perror_msg("%s: warning: cannot open %s",
174 static void update_status(struct svdir
*s
)
179 const char *fstatus
="log/supervise/status";
180 const char *fstatusnew
="log/supervise/status.new";
181 const char *f_stat
="log/supervise/stat";
182 const char *fstatnew
="log/supervise/stat.new";
183 const char *fpid
="log/supervise/pid";
184 const char *fpidnew
="log/supervise/pid.new";
197 fd
= open_trunc_or_warn(fpidnew
);
201 char spid
[sizeof(int)*3 + 2];
202 int size
= sprintf(spid
, "%u\n", (unsigned)s
->pid
);
203 write(fd
, spid
, size
);
206 if (rename_or_warn(fpidnew
, fpid
))
212 fd
= open_trunc_or_warn(fstatnew
);
217 char stat_buf
[sizeof("finish, paused, got TERM, want down\n")];
221 p
= stpcpy(p
, "down");
224 p
= stpcpy(p
, "run");
227 p
= stpcpy(p
, "finish");
230 if (s
->ctrl
& C_PAUSE
)
231 p
= stpcpy(p
, ", paused");
232 if (s
->ctrl
& C_TERM
)
233 p
= stpcpy(p
, ", got TERM");
234 if (s
->state
!= S_DOWN
)
235 switch (s
->sd_want
) {
237 p
= stpcpy(p
, ", want down");
240 p
= stpcpy(p
, ", want exit");
244 write(fd
, stat_buf
, p
- stat_buf
);
248 rename_or_warn(fstatnew
, f_stat
);
250 /* supervise compatibility */
251 memset(&status
, 0, sizeof(status
));
252 status
.time_be64
= SWAP_BE64(s
->start
.tv_sec
+ 0x400000000000000aULL
);
253 status
.time_nsec_be32
= SWAP_BE32(s
->start
.tv_nsec
);
254 status
.pid_le32
= SWAP_LE32(s
->pid
);
255 if (s
->ctrl
& C_PAUSE
)
257 if (s
->sd_want
== W_UP
)
261 if (s
->ctrl
& C_TERM
)
263 status
.run_or_finish
= s
->state
;
264 fd
= open_trunc_or_warn(fstatusnew
);
267 sz
= write(fd
, &status
, sizeof(status
));
269 if (sz
!= sizeof(status
)) {
270 warn2_cannot("write ", fstatusnew
);
274 rename_or_warn(fstatusnew
, fstatus
);
277 static unsigned custom(struct svdir
*s
, char c
)
286 strcpy(a
, "control/?");
287 a
[8] = c
; /* replace '?' */
288 if (stat(a
, &st
) == 0) {
289 if (st
.st_mode
& S_IXUSR
) {
292 warn2_cannot("vfork for ", a
);
297 if (haslog
&& dup2(logpipe
.wr
, 1) == -1)
298 warn2_cannot("setup stdout for ", a
);
299 execl(a
, a
, (char *) NULL
);
300 fatal2_cannot("run ", a
);
303 if (safe_waitpid(pid
, &w
, 0) == -1) {
304 warn2_cannot("wait for child ", a
);
307 return WEXITSTATUS(w
) == 0;
311 warn2_cannot("stat ", a
);
316 static void stopservice(struct svdir
*s
)
318 if (s
->pid
&& !custom(s
, 't')) {
319 kill(s
->pid
, SIGTERM
);
323 if (s
->sd_want
== W_DOWN
) {
324 kill(s
->pid
, SIGCONT
);
328 if (s
->sd_want
== W_EXIT
) {
329 kill(s
->pid
, SIGCONT
);
334 static void startservice(struct svdir
*s
)
338 char exitcode
[sizeof(int)*3 + 2];
340 if (s
->state
== S_FINISH
) {
341 /* Two arguments are given to ./finish. The first one is ./run exit code,
342 * or -1 if ./run didnt exit normally. The second one is
343 * the least significant byte of the exit status as determined by waitpid;
344 * for instance it is 0 if ./run exited normally, and the signal number
345 * if ./run was terminated by a signal. If runsv cannot start ./run
346 * for some reason, the exit code is 111 and the status is 0.
350 if (WIFEXITED(s
->wstat
)) {
351 *utoa_to_buf(WEXITSTATUS(s
->wstat
), exitcode
, sizeof(exitcode
)) = '\0';
355 //if (WIFSIGNALED(s->wstat)) {
356 arg
[2] = utoa(WTERMSIG(s
->wstat
));
366 stopservice(s
); /* should never happen */
367 while ((p
= vfork()) == -1) {
368 warn_cannot("vfork, sleeping");
374 /* NB: bug alert! right order is close, then dup2 */
378 xdup2(logpipe
.rd
, 0);
381 xdup2(logpipe
.wr
, 1);
384 /* Non-ignored signals revert to SIG_DFL on exec.
385 * But we can get signals BEFORE execl(), unlikely as that may be.
386 * SIGCHLD is safe (would merely write to selfpipe),
387 * but SIGTERM would set sigterm = 1 (with vfork, we affect parent).
390 /*signal(SIGCHLD, SIG_DFL);*/
391 signal(SIGTERM
, SIG_DFL
);
392 sig_unblock(SIGCHLD
);
393 sig_unblock(SIGTERM
);
394 execv(arg
[0], (char**) arg
);
395 fatal2_cannot(s
->islog
? "start log/" : "start ", arg
[0]);
398 if (s
->state
!= S_FINISH
) {
399 gettimeofday_ns(&s
->start
);
408 static int ctrl(struct svdir
*s
, char c
)
416 if (s
->state
== S_RUN
)
422 if (s
->state
== S_DOWN
)
431 case 't': /* sig term */
432 if (s
->state
== S_RUN
)
435 case 'k': /* sig kill */
436 if ((s
->state
== S_RUN
) && !custom(s
, c
))
437 kill(s
->pid
, SIGKILL
);
440 case 'p': /* sig pause */
441 if ((s
->state
== S_RUN
) && !custom(s
, c
))
442 kill(s
->pid
, SIGSTOP
);
446 case 'c': /* sig cont */
447 if ((s
->state
== S_RUN
) && !custom(s
, c
))
448 kill(s
->pid
, SIGCONT
);
455 if (s
->state
== S_DOWN
)
458 case 'a': /* sig alarm */
461 case 'h': /* sig hup */
464 case 'i': /* sig int */
467 case 'q': /* sig quit */
470 case '1': /* sig usr1 */
473 case '2': /* sig usr2 */
479 if ((s
->state
== S_RUN
) && !custom(s
, c
))
484 static void open_control(const char *f
, struct svdir
*s
)
488 if (stat(f
, &st
) == -1)
489 fatal2_cannot("stat ", f
);
490 if (!S_ISFIFO(st
.st_mode
))
491 bb_error_msg_and_die("%s: fatal: %s exists but is not a fifo", dir
, f
);
492 s
->fdcontrol
= xopen(f
, O_RDONLY
|O_NDELAY
);
493 close_on_exec_on(s
->fdcontrol
);
494 s
->fdcontrolwrite
= xopen(f
, O_WRONLY
|O_NDELAY
);
495 close_on_exec_on(s
->fdcontrolwrite
);
499 int runsv_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
500 int runsv_main(int argc UNUSED_PARAM
, char **argv
)
509 dir
= single_argv(argv
);
511 xpiped_pair(selfpipe
);
512 close_on_exec_on(selfpipe
.rd
);
513 close_on_exec_on(selfpipe
.wr
);
514 ndelay_on(selfpipe
.rd
);
515 ndelay_on(selfpipe
.wr
);
519 /* No particular reason why we don't set SA_RESTART
520 * (poll() wouldn't restart regardless of that flag),
521 * we just follow what runit-2.1.2 does:
523 bb_signals_norestart(0
529 /* bss: svd[0].pid = 0; */
530 if (S_DOWN
) svd
[0].state
= S_DOWN
; /* otherwise already 0 (bss) */
531 if (C_NOOP
) svd
[0].ctrl
= C_NOOP
;
532 if (W_UP
) svd
[0].sd_want
= W_UP
;
533 /* bss: svd[0].islog = 0; */
534 /* bss: svd[1].pid = 0; */
535 gettimeofday_ns(&svd
[0].start
);
536 if (stat("down", &s
) != -1)
537 svd
[0].sd_want
= W_DOWN
;
539 if (stat("log", &s
) == -1) {
541 warn_cannot("stat ./log");
543 if (!S_ISDIR(s
.st_mode
)) {
545 warn_cannot("stat log/down: log is not a directory");
548 svd
[1].state
= S_DOWN
;
549 svd
[1].ctrl
= C_NOOP
;
550 svd
[1].sd_want
= W_UP
;
552 gettimeofday_ns(&svd
[1].start
);
553 if (stat("log/down", &s
) != -1)
554 svd
[1].sd_want
= W_DOWN
;
555 xpiped_pair(logpipe
);
556 close_on_exec_on(logpipe
.rd
);
557 close_on_exec_on(logpipe
.wr
);
561 if (mkdir("supervise", 0700) == -1) {
562 r
= readlink("supervise", buf
, sizeof(buf
));
564 if (r
== sizeof(buf
))
565 fatal2x_cannot("readlink ./supervise", ": name too long");
569 if ((errno
!= ENOENT
) && (errno
!= EINVAL
))
570 fatal_cannot("readlink ./supervise");
573 svd
[0].fdlock
= xopen3("log/supervise/lock"+4,
574 O_WRONLY
|O_NDELAY
|O_APPEND
|O_CREAT
, 0600);
575 if (flock(svd
[0].fdlock
, LOCK_EX
| LOCK_NB
) == -1)
576 fatal_cannot("lock supervise/lock");
577 close_on_exec_on(svd
[0].fdlock
);
579 if (mkdir("log/supervise", 0700) == -1) {
580 r
= readlink("log/supervise", buf
, 256);
583 fatal2x_cannot("readlink ./log/supervise", ": name too long");
585 fd
= xopen(".", O_RDONLY
|O_NDELAY
);
588 if (fchdir(fd
) == -1)
589 fatal_cannot("change back to service directory");
593 if ((errno
!= ENOENT
) && (errno
!= EINVAL
))
594 fatal_cannot("readlink ./log/supervise");
597 svd
[1].fdlock
= xopen3("log/supervise/lock",
598 O_WRONLY
|O_NDELAY
|O_APPEND
|O_CREAT
, 0600);
599 if (flock(svd
[1].fdlock
, LOCK_EX
) == -1)
600 fatal_cannot("lock log/supervise/lock");
601 close_on_exec_on(svd
[1].fdlock
);
604 open_control("log/supervise/control"+4, &svd
[0]);
606 open_control("log/supervise/control", &svd
[1]);
608 mkfifo("log/supervise/ok"+4, 0600);
609 fd
= xopen("log/supervise/ok"+4, O_RDONLY
|O_NDELAY
);
610 close_on_exec_on(fd
);
612 mkfifo("log/supervise/ok", 0600);
613 fd
= xopen("log/supervise/ok", O_RDONLY
|O_NDELAY
);
614 close_on_exec_on(fd
);
622 if (!svd
[1].pid
&& svd
[1].sd_want
== W_UP
)
623 startservice(&svd
[1]);
625 if (svd
[0].sd_want
== W_UP
|| svd
[0].state
== S_FINISH
)
626 startservice(&svd
[0]);
628 x
[0].fd
= selfpipe
.rd
;
629 x
[0].events
= POLLIN
;
630 x
[1].fd
= svd
[0].fdcontrol
;
631 x
[1].events
= POLLIN
;
632 /* x[2] is used only if haslog == 1 */
633 x
[2].fd
= svd
[1].fdcontrol
;
634 x
[2].events
= POLLIN
;
635 sig_unblock(SIGTERM
);
636 sig_unblock(SIGCHLD
);
637 poll(x
, 2 + haslog
, 3600*1000);
638 /* NB: signal handlers can trash errno of poll() */
642 while (read(selfpipe
.rd
, &ch
, 1) == 1)
649 child
= wait_any_nohang(&wstat
);
652 if ((child
== -1) && (errno
!= EINTR
))
654 if (child
== svd
[0].pid
) {
655 svd
[0].wstat
= wstat
;
658 svd
[0].ctrl
&= ~C_TERM
;
659 if (svd
[0].state
!= S_FINISH
) {
660 fd
= open("finish", O_RDONLY
|O_NDELAY
);
663 svd
[0].state
= S_FINISH
;
664 update_status(&svd
[0]);
668 svd
[0].state
= S_DOWN
;
669 deadline
= svd
[0].start
.tv_sec
+ 1;
670 gettimeofday_ns(&svd
[0].start
);
671 update_status(&svd
[0]);
672 if (LESS(svd
[0].start
.tv_sec
, deadline
))
676 if (child
== svd
[1].pid
) {
677 svd
[0].wstat
= wstat
;
680 svd
[1].state
= S_DOWN
;
681 svd
[1].ctrl
&= ~C_TERM
;
682 deadline
= svd
[1].start
.tv_sec
+ 1;
683 gettimeofday_ns(&svd
[1].start
);
684 update_status(&svd
[1]);
685 if (LESS(svd
[1].start
.tv_sec
, deadline
))
690 if (read(svd
[0].fdcontrol
, &ch
, 1) == 1)
693 if (read(svd
[1].fdcontrol
, &ch
, 1) == 1)
701 if (svd
[0].sd_want
== W_EXIT
&& svd
[0].state
== S_DOWN
) {
704 if (svd
[1].sd_want
!= W_EXIT
) {
705 svd
[1].sd_want
= W_EXIT
;
706 /* stopservice(&svd[1]); */
707 update_status(&svd
[1]);