vi: rearrange functions, no logic changes
[oweals/busybox.git] / runit / runsv.c
index 5b221e90ae4e51617af8198937d85aeeed29040f..ccc762d78088e70a01251b827d415172ee2dc49b 100644 (file)
@@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met:
    3. The name of the author may not be used to endorse or promote products
       derived from this software without specific prior written permission.
 
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
@@ -26,11 +26,26 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 /* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
-/* TODO: depends on runit_lib.c - review and reduce/eliminate */
 
-#include <sys/poll.h>
+//config:config RUNSV
+//config:      bool "runsv (7.8 kb)"
+//config:      default y
+//config:      help
+//config:      runsv starts and monitors a service and optionally an appendant log
+//config:      service.
+
+//applet:IF_RUNSV(APPLET(runsv, BB_DIR_USR_BIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_RUNSV) += runsv.o
+
+//usage:#define runsv_trivial_usage
+//usage:       "DIR"
+//usage:#define runsv_full_usage "\n\n"
+//usage:       "Start and monitor a service and optionally an appendant log service"
+
 #include <sys/file.h>
 #include "libbb.h"
+#include "common_bufsiz.h"
 #include "runit_lib.h"
 
 #if ENABLE_MONOTONIC_SYSCALL
@@ -45,16 +60,11 @@ static void gettimeofday_ns(struct timespec *ts)
 #else
 static void gettimeofday_ns(struct timespec *ts)
 {
-       if (sizeof(struct timeval) == sizeof(struct timespec)
-        && sizeof(((struct timeval*)ts)->tv_usec) == sizeof(ts->tv_nsec)
-       ) {
-               /* Cheat */
-               gettimeofday((void*)ts, NULL);
-               ts->tv_nsec *= 1000;
-       } else {
-               extern void BUG_need_to_implement_gettimeofday_ns(void);
-               BUG_need_to_implement_gettimeofday_ns();
-       }
+       BUILD_BUG_ON(sizeof(struct timeval) != sizeof(struct timespec));
+       BUILD_BUG_ON(sizeof(((struct timeval*)ts)->tv_usec) != sizeof(ts->tv_nsec));
+       /* Cheat */
+       gettimeofday((void*)ts, NULL);
+       ts->tv_nsec *= 1000;
 }
 #endif
 
@@ -96,7 +106,7 @@ struct globals {
        char *dir;
        struct svdir svd[2];
 } FIX_ALIASING;
-#define G (*(struct globals*)&bb_common_bufsiz1)
+#define G (*(struct globals*)bb_common_bufsiz1)
 #define haslog       (G.haslog      )
 #define sigterm      (G.sigterm     )
 #define pidchanged   (G.pidchanged  )
@@ -105,12 +115,13 @@ struct globals {
 #define dir          (G.dir         )
 #define svd          (G.svd         )
 #define INIT_G() do { \
+       setup_common_bufsiz(); \
        pidchanged = 1; \
 } while (0)
 
 static void fatal2_cannot(const char *m1, const char *m2)
 {
-       bb_perror_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2);
+       bb_perror_msg_and_die("%s: fatal: can't %s%s", dir, m1, m2);
        /* was exiting 111 */
 }
 static void fatal_cannot(const char *m)
@@ -120,12 +131,16 @@ static void fatal_cannot(const char *m)
 }
 static void fatal2x_cannot(const char *m1, const char *m2)
 {
-       bb_error_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2);
+       bb_error_msg_and_die("%s: fatal: can't %s%s", dir, m1, m2);
        /* was exiting 111 */
 }
+static void warn2_cannot(const char *m1, const char *m2)
+{
+       bb_perror_msg("%s: warning: can't %s%s", dir, m1, m2);
+}
 static void warn_cannot(const char *m)
 {
-       bb_perror_msg("%s: warning: cannot %s", dir, m);
+       warn2_cannot(m, "");
 }
 
 static void s_child(int sig_no UNUSED_PARAM)
@@ -139,19 +154,10 @@ static void s_term(int sig_no UNUSED_PARAM)
        write(selfpipe.wr, "", 1); /* XXX */
 }
 
-/* libbb candidate */
-static char *bb_stpcpy(char *p, const char *to_add)
-{
-       while ((*p = *to_add) != '\0') {
-               p++;
-               to_add++;
-       }
-       return p;
-}
-
 static int open_trunc_or_warn(const char *name)
 {
-       int fd = open_trunc(name);
+       /* Why O_NDELAY? */
+       int fd = open(name, O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT, 0644);
        if (fd < 0)
                bb_perror_msg("%s: warning: cannot open %s",
                                dir, name);
@@ -163,10 +169,25 @@ static void update_status(struct svdir *s)
        ssize_t sz;
        int fd;
        svstatus_t status;
+       const char *fstatus ="log/supervise/status";
+       const char *fstatusnew ="log/supervise/status.new";
+       const char *f_stat ="log/supervise/stat";
+       const char *fstatnew ="log/supervise/stat.new";
+       const char *fpid ="log/supervise/pid";
+       const char *fpidnew ="log/supervise/pid.new";
+
+       if (!s->islog) {
+               fstatus += 4;
+               fstatusnew += 4;
+               f_stat += 4;
+               fstatnew += 4;
+               fpid += 4;
+               fpidnew += 4;
+       }
 
        /* pid */
        if (pidchanged) {
-               fd = open_trunc_or_warn("supervise/pid.new");
+               fd = open_trunc_or_warn(fpidnew);
                if (fd < 0)
                        return;
                if (s->pid) {
@@ -175,14 +196,13 @@ static void update_status(struct svdir *s)
                        write(fd, spid, size);
                }
                close(fd);
-               if (rename_or_warn("supervise/pid.new",
-                   s->islog ? "log/supervise/pid" : "log/supervise/pid"+4))
+               if (rename_or_warn(fpidnew, fpid))
                        return;
                pidchanged = 0;
        }
 
        /* stat */
-       fd = open_trunc_or_warn("supervise/stat.new");
+       fd = open_trunc_or_warn(fstatnew);
        if (fd < -1)
                return;
 
@@ -191,26 +211,26 @@ static void update_status(struct svdir *s)
                char *p = stat_buf;
                switch (s->state) {
                case S_DOWN:
-                       p = bb_stpcpy(p, "down");
+                       p = stpcpy(p, "down");
                        break;
                case S_RUN:
-                       p = bb_stpcpy(p, "run");
+                       p = stpcpy(p, "run");
                        break;
                case S_FINISH:
-                       p = bb_stpcpy(p, "finish");
+                       p = stpcpy(p, "finish");
                        break;
                }
                if (s->ctrl & C_PAUSE)
-                       p = bb_stpcpy(p, ", paused");
+                       p = stpcpy(p, ", paused");
                if (s->ctrl & C_TERM)
-                       p = bb_stpcpy(p, ", got TERM");
+                       p = stpcpy(p, ", got TERM");
                if (s->state != S_DOWN)
                        switch (s->sd_want) {
                        case W_DOWN:
-                               p = bb_stpcpy(p, ", want down");
+                               p = stpcpy(p, ", want down");
                                break;
                        case W_EXIT:
-                               p = bb_stpcpy(p, ", want exit");
+                               p = stpcpy(p, ", want exit");
                                break;
                        }
                *p++ = '\n';
@@ -218,8 +238,7 @@ static void update_status(struct svdir *s)
                close(fd);
        }
 
-       rename_or_warn("supervise/stat.new",
-               s->islog ? "log/supervise/stat" : "log/supervise/stat"+4);
+       rename_or_warn(fstatnew, f_stat);
 
        /* supervise compatibility */
        memset(&status, 0, sizeof(status));
@@ -235,18 +254,17 @@ static void update_status(struct svdir *s)
        if (s->ctrl & C_TERM)
                status.got_term = 1;
        status.run_or_finish = s->state;
-       fd = open_trunc_or_warn("supervise/status.new");
+       fd = open_trunc_or_warn(fstatusnew);
        if (fd < 0)
                return;
        sz = write(fd, &status, sizeof(status));
        close(fd);
        if (sz != sizeof(status)) {
-               warn_cannot("write supervise/status.new");
-               unlink("supervise/status.new");
+               warn2_cannot("write ", fstatusnew);
+               unlink(fstatusnew);
                return;
        }
-       rename_or_warn("supervise/status.new",
-               s->islog ? "log/supervise/status" : "log/supervise/status"+4);
+       rename_or_warn(fstatusnew, fstatus);
 }
 
 static unsigned custom(struct svdir *s, char c)
@@ -264,26 +282,26 @@ static unsigned custom(struct svdir *s, char c)
                if (st.st_mode & S_IXUSR) {
                        pid = vfork();
                        if (pid == -1) {
-                               warn_cannot("vfork for control/?");
+                               warn2_cannot("vfork for ", a);
                                return 0;
                        }
                        if (pid == 0) {
                                /* child */
                                if (haslog && dup2(logpipe.wr, 1) == -1)
-                                       warn_cannot("setup stdout for control/?");
+                                       warn2_cannot("setup stdout for ", a);
                                execl(a, a, (char *) NULL);
-                               fatal_cannot("run control/?");
+                               fatal2_cannot("run ", a);
                        }
                        /* parent */
                        if (safe_waitpid(pid, &w, 0) == -1) {
-                               warn_cannot("wait for child control/?");
+                               warn2_cannot("wait for child ", a);
                                return 0;
                        }
                        return WEXITSTATUS(w) == 0;
                }
        } else {
                if (errno != ENOENT)
-                       warn_cannot("stat control/?");
+                       warn2_cannot("stat ", a);
        }
        return 0;
 }
@@ -385,13 +403,13 @@ static int ctrl(struct svdir *s, char c)
        case 'd': /* down */
                s->sd_want = W_DOWN;
                update_status(s);
-               if (s->pid && s->state != S_FINISH)
+               if (s->state == S_RUN)
                        stopservice(s);
                break;
        case 'u': /* up */
                s->sd_want = W_UP;
                update_status(s);
-               if (s->pid == 0)
+               if (s->state == S_DOWN)
                        startservice(s);
                break;
        case 'x': /* exit */
@@ -401,22 +419,22 @@ static int ctrl(struct svdir *s, char c)
                update_status(s);
                /* FALLTHROUGH */
        case 't': /* sig term */
-               if (s->pid && s->state != S_FINISH)
+               if (s->state == S_RUN)
                        stopservice(s);
                break;
        case 'k': /* sig kill */
-               if (s->pid && !custom(s, c))
+               if ((s->state == S_RUN) && !custom(s, c))
                        kill(s->pid, SIGKILL);
                s->state = S_DOWN;
                break;
        case 'p': /* sig pause */
-               if (s->pid && !custom(s, c))
+               if ((s->state == S_RUN) && !custom(s, c))
                        kill(s->pid, SIGSTOP);
                s->ctrl |= C_PAUSE;
                update_status(s);
                break;
        case 'c': /* sig cont */
-               if (s->pid && !custom(s, c))
+               if ((s->state == S_RUN) && !custom(s, c))
                        kill(s->pid, SIGCONT);
                s->ctrl &= ~C_PAUSE;
                update_status(s);
@@ -424,7 +442,7 @@ static int ctrl(struct svdir *s, char c)
        case 'o': /* once */
                s->sd_want = W_DOWN;
                update_status(s);
-               if (!s->pid)
+               if (s->state == S_DOWN)
                        startservice(s);
                break;
        case 'a': /* sig alarm */
@@ -448,11 +466,26 @@ static int ctrl(struct svdir *s, char c)
        }
        return 1;
  sendsig:
-       if (s->pid && !custom(s, c))
+       if ((s->state == S_RUN) && !custom(s, c))
                kill(s->pid, sig);
        return 1;
 }
 
+static void open_control(const char *f, struct svdir *s)
+{
+       struct stat st;
+       mkfifo(f, 0600);
+       if (stat(f, &st) == -1)
+               fatal2_cannot("stat ", f);
+       if (!S_ISFIFO(st.st_mode))
+               bb_error_msg_and_die("%s: fatal: %s exists but is not a fifo", dir, f);
+       s->fdcontrol = xopen(f, O_RDONLY|O_NDELAY);
+       close_on_exec_on(s->fdcontrol);
+       s->fdcontrolwrite = xopen(f, O_WRONLY|O_NDELAY);
+       close_on_exec_on(s->fdcontrolwrite);
+       update_status(s);
+}
+
 int runsv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int runsv_main(int argc UNUSED_PARAM, char **argv)
 {
@@ -523,7 +556,7 @@ int runsv_main(int argc UNUSED_PARAM, char **argv)
        }
        svd[0].fdlock = xopen3("log/supervise/lock"+4,
                        O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
-       if (lock_exnb(svd[0].fdlock) == -1)
+       if (flock(svd[0].fdlock, LOCK_EX | LOCK_NB) == -1)
                fatal_cannot("lock supervise/lock");
        close_on_exec_on(svd[0].fdlock);
        if (haslog) {
@@ -547,24 +580,14 @@ int runsv_main(int argc UNUSED_PARAM, char **argv)
                }
                svd[1].fdlock = xopen3("log/supervise/lock",
                                O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
-               if (lock_ex(svd[1].fdlock) == -1)
+               if (flock(svd[1].fdlock, LOCK_EX) == -1)
                        fatal_cannot("lock log/supervise/lock");
                close_on_exec_on(svd[1].fdlock);
        }
 
-       mkfifo("log/supervise/control"+4, 0600);
-       svd[0].fdcontrol = xopen("log/supervise/control"+4, O_RDONLY|O_NDELAY);
-       close_on_exec_on(svd[0].fdcontrol);
-       svd[0].fdcontrolwrite = xopen("log/supervise/control"+4, O_WRONLY|O_NDELAY);
-       close_on_exec_on(svd[0].fdcontrolwrite);
-       update_status(&svd[0]);
+       open_control("log/supervise/control"+4, &svd[0]);
        if (haslog) {
-               mkfifo("log/supervise/control", 0600);
-               svd[1].fdcontrol = xopen("log/supervise/control", O_RDONLY|O_NDELAY);
-               close_on_exec_on(svd[1].fdcontrol);
-               svd[1].fdcontrolwrite = xopen("log/supervise/control", O_WRONLY|O_NDELAY);
-               close_on_exec_on(svd[1].fdcontrolwrite);
-               update_status(&svd[1]);
+               open_control("log/supervise/control", &svd[1]);
        }
        mkfifo("log/supervise/ok"+4, 0600);
        fd = xopen("log/supervise/ok"+4, O_RDONLY|O_NDELAY);
@@ -617,7 +640,7 @@ int runsv_main(int argc UNUSED_PARAM, char **argv)
                                pidchanged = 1;
                                svd[0].ctrl &= ~C_TERM;
                                if (svd[0].state != S_FINISH) {
-                                       fd = open_read("finish");
+                                       fd = open("finish", O_RDONLY|O_NDELAY);
                                        if (fd != -1) {
                                                close(fd);
                                                svd[0].state = S_FINISH;