123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744 |
- #include <sys/file.h>
- #include "libbb.h"
- #include "common_bufsiz.h"
- #include "runit_lib.h"
- struct globals {
- const char *acts;
- char **service;
- unsigned rc;
- uint64_t tstart, tnow;
- svstatus_t svstatus;
- smallint islog;
- } FIX_ALIASING;
- #define G (*(struct globals*)bb_common_bufsiz1)
- #define acts (G.acts )
- #define service (G.service )
- #define rc (G.rc )
- #define tstart (G.tstart )
- #define tnow (G.tnow )
- #define svstatus (G.svstatus )
- #define islog (G.islog )
- #define INIT_G() do { \
- setup_common_bufsiz(); \
- \
- memset(&G, 0, sizeof(G)); \
- } while (0)
- #define str_equal(s,t) (strcmp((s), (t)) == 0)
- static void fatal_cannot(const char *m1) NORETURN;
- static void fatal_cannot(const char *m1)
- {
- bb_perror_msg("fatal: can't %s", m1);
- _exit(151);
- }
- static void out(const char *p, const char *m1)
- {
- printf("%s%s%s: %s", p, *service, islog ? "/log" : "", m1);
- if (errno) {
- printf(": "STRERROR_FMT STRERROR_ERRNO);
- }
- bb_putchar('\n');
- }
- #define WARN "warning: "
- #define OK "ok: "
- static void fail(const char *m1)
- {
- ++rc;
- out("fail: ", m1);
- }
- static void failx(const char *m1)
- {
- errno = 0;
- fail(m1);
- }
- static void warn(const char *m1)
- {
- ++rc;
-
- out("warning: ", m1);
- }
- static void ok(const char *m1)
- {
- errno = 0;
- out(OK, m1);
- }
- static int svstatus_get(void)
- {
- int fd, r;
- fd = open("supervise/ok", O_WRONLY|O_NDELAY);
- if (fd == -1) {
- if (errno == ENODEV) {
- *acts == 'x' ? ok("runsv not running")
- : failx("runsv not running");
- return 0;
- }
- warn("can't open supervise/ok");
- return -1;
- }
- close(fd);
- fd = open("supervise/status", O_RDONLY|O_NDELAY);
- if (fd == -1) {
- warn("can't open supervise/status");
- return -1;
- }
- r = read(fd, &svstatus, 20);
- close(fd);
- switch (r) {
- case 20:
- break;
- case -1:
- warn("can't read supervise/status");
- return -1;
- default:
- errno = 0;
- warn("can't read supervise/status: bad format");
- return -1;
- }
- return 1;
- }
- static unsigned svstatus_print(const char *m)
- {
- int diff;
- int pid;
- int normallyup = 0;
- struct stat s;
- uint64_t timestamp;
- if (stat("down", &s) == -1) {
- if (errno != ENOENT) {
- bb_perror_msg(WARN"can't stat %s/down", *service);
- return 0;
- }
- normallyup = 1;
- }
- pid = SWAP_LE32(svstatus.pid_le32);
- timestamp = SWAP_BE64(svstatus.time_be64);
- switch (svstatus.run_or_finish) {
- case 0: printf("down: "); break;
- case 1: printf("run: "); break;
- case 2: printf("finish: "); break;
- }
- printf("%s: ", m);
- if (svstatus.run_or_finish)
- printf("(pid %d) ", pid);
- diff = tnow - timestamp;
- printf("%us", (diff < 0 ? 0 : diff));
- if (pid) {
- if (!normallyup) printf(", normally down");
- if (svstatus.paused) printf(", paused");
- if (svstatus.want == 'd') printf(", want down");
- if (svstatus.got_term) printf(", got TERM");
- } else {
- if (normallyup) printf(", normally up");
- if (svstatus.want == 'u') printf(", want up");
- }
- return pid ? 1 : 2;
- }
- static int status(const char *unused UNUSED_PARAM)
- {
- int r;
- if (svstatus_get() <= 0)
- return 0;
- r = svstatus_print(*service);
- islog = 1;
- if (chdir("log") == -1) {
- if (errno != ENOENT) {
- printf("; ");
- warn("can't change directory");
- } else
- bb_putchar('\n');
- } else {
- printf("; ");
- if (svstatus_get()) {
- r = svstatus_print("log");
- bb_putchar('\n');
- }
- }
- islog = 0;
- return r;
- }
- static int checkscript(void)
- {
- char *prog[2];
- struct stat s;
- int pid, w;
- if (stat("check", &s) == -1) {
- if (errno == ENOENT) return 1;
- bb_perror_msg(WARN"can't stat %s/check", *service);
- return 0;
- }
-
- prog[0] = (char*)"./check";
- prog[1] = NULL;
- pid = spawn(prog);
- if (pid <= 0) {
- bb_perror_msg(WARN"can't %s child %s/check", "run", *service);
- return 0;
- }
- while (safe_waitpid(pid, &w, 0) == -1) {
- bb_perror_msg(WARN"can't %s child %s/check", "wait for", *service);
- return 0;
- }
- return WEXITSTATUS(w) == 0;
- }
- static int check(const char *a)
- {
- int r;
- unsigned pid_le32;
- uint64_t timestamp;
- r = svstatus_get();
- if (r == -1)
- return -1;
- while (*a) {
- if (r == 0) {
- if (*a == 'x')
- return 1;
- return -1;
- }
- pid_le32 = svstatus.pid_le32;
- switch (*a) {
- case 'x':
- return 0;
- case 'u':
- if (!pid_le32 || svstatus.run_or_finish != 1)
- return 0;
- if (!checkscript())
- return 0;
- break;
- case 'd':
- if (pid_le32 || svstatus.run_or_finish != 0)
- return 0;
- break;
- case 'C':
- if (pid_le32 && !checkscript())
- return 0;
- break;
- case 't':
- case 'k':
- if (!pid_le32 && svstatus.want == 'd')
- break;
- timestamp = SWAP_BE64(svstatus.time_be64);
- if ((tstart > timestamp) || !pid_le32 || svstatus.got_term || !checkscript())
- return 0;
- break;
- case 'o':
- timestamp = SWAP_BE64(svstatus.time_be64);
- if ((!pid_le32 && tstart > timestamp) || (pid_le32 && svstatus.want != 'd'))
- return 0;
- break;
- case 'p':
- if (pid_le32 && !svstatus.paused)
- return 0;
- break;
- case 'c':
- if (pid_le32 && svstatus.paused)
- return 0;
- break;
- }
- ++a;
- }
- printf(OK);
- svstatus_print(*service);
- bb_putchar('\n');
- return 1;
- }
- static int control(const char *a)
- {
- int fd, r, l;
- if (svstatus_get() <= 0)
- return -1;
- if (svstatus.want == *a && (*a != 'd' || svstatus.got_term == 1))
- return 0;
- fd = open("supervise/control", O_WRONLY|O_NDELAY);
- if (fd == -1) {
- if (errno != ENODEV)
- warn("can't open supervise/control");
- else
- *a == 'x' ? ok("runsv not running") : failx("runsv not running");
- return -1;
- }
- l = strlen(a);
- r = write(fd, a, l);
- close(fd);
- if (r != l) {
- warn("can't write to supervise/control");
- return -1;
- }
- return 1;
- }
- static int sv(char **argv)
- {
- char *x;
- char *action;
- const char *varservice = CONFIG_SV_DEFAULT_SERVICE_DIR;
- unsigned waitsec = 7;
- smallint kll = 0;
- int verbose = 0;
- int (*act)(const char*);
- int (*cbk)(const char*);
- int curdir;
- INIT_G();
- xfunc_error_retval = 100;
- x = getenv("SVDIR");
- if (x) varservice = x;
- x = getenv("SVWAIT");
- if (x) waitsec = xatou(x);
- getopt32(argv, "^" "w:+v" "\0" "vv" ,
- &waitsec, &verbose
- );
- argv += optind;
- action = *argv++;
- if (!action || !*argv) bb_show_usage();
- tnow = time(NULL) + 0x400000000000000aULL;
- tstart = tnow;
- curdir = open(".", O_RDONLY|O_NDELAY);
- if (curdir == -1)
- fatal_cannot("open current directory");
- act = &control;
- acts = "s";
- cbk = ✓
- switch (*action) {
- case 'x':
- case 'e':
- acts = "x";
- if (!verbose) cbk = NULL;
- break;
- case 'X':
- case 'E':
- acts = "x";
- kll = 1;
- break;
- case 'D':
- acts = "d";
- kll = 1;
- break;
- case 'T':
- acts = "tc";
- kll = 1;
- break;
- case 't':
- if (str_equal(action, "try-restart")) {
- acts = "tc";
- break;
- }
- case 'c':
- if (str_equal(action, "check")) {
- act = NULL;
- acts = "C";
- break;
- }
- case 'u': case 'd': case 'o': case 'p': case 'h':
- case 'a': case 'i': case 'k': case 'q': case '1': case '2':
- action[1] = '\0';
- acts = action;
- if (!verbose)
- cbk = NULL;
- break;
- case 's':
- if (str_equal(action, "shutdown")) {
- acts = "x";
- break;
- }
- if (str_equal(action, "start")) {
- acts = "u";
- break;
- }
- if (str_equal(action, "stop")) {
- acts = "d";
- break;
- }
-
- act = &status;
- cbk = NULL;
- break;
- case 'r':
- if (str_equal(action, "restart")) {
- acts = "tcu";
- break;
- }
- if (str_equal(action, "reload")) {
- acts = "h";
- break;
- }
- bb_show_usage();
- case 'f':
- if (str_equal(action, "force-reload")) {
- acts = "tc";
- kll = 1;
- break;
- }
- if (str_equal(action, "force-restart")) {
- acts = "tcu";
- kll = 1;
- break;
- }
- if (str_equal(action, "force-shutdown")) {
- acts = "x";
- kll = 1;
- break;
- }
- if (str_equal(action, "force-stop")) {
- acts = "d";
- kll = 1;
- break;
- }
- default:
- bb_show_usage();
- }
- service = argv;
- while ((x = *service) != NULL) {
- if (x[0] != '/' && x[0] != '.'
- && x[0] != '\0' && x[strlen(x) - 1] != '/'
- ) {
- if (chdir(varservice) == -1)
- goto chdir_failed_0;
- }
- if (chdir(x) == -1) {
- chdir_failed_0:
- fail("can't change to service directory");
- goto nullify_service_0;
- }
- if (act && (act(acts) == -1)) {
- nullify_service_0:
- *service = (char*) -1L;
- }
- if (fchdir(curdir) == -1)
- fatal_cannot("change to original directory");
- service++;
- }
- if (cbk) while (1) {
- int want_exit;
- int diff;
- diff = tnow - tstart;
- service = argv;
- want_exit = 1;
- while ((x = *service) != NULL) {
- if (x == (char*) -1L)
- goto next;
- if (x[0] != '/' && x[0] != '.') {
- if (chdir(varservice) == -1)
- goto chdir_failed;
- }
- if (chdir(x) == -1) {
- chdir_failed:
- fail("can't change to service directory");
- goto nullify_service;
- }
- if (cbk(acts) != 0)
- goto nullify_service;
- want_exit = 0;
- if (diff >= waitsec) {
- printf(kll ? "kill: " : "timeout: ");
- if (svstatus_get() > 0) {
- svstatus_print(x);
- ++rc;
- }
- bb_putchar('\n');
- if (kll)
- control("k");
- nullify_service:
- *service = (char*) -1L;
- }
- if (fchdir(curdir) == -1)
- fatal_cannot("change to original directory");
- next:
- service++;
- }
- if (want_exit) break;
- usleep(420000);
- tnow = time(NULL) + 0x400000000000000aULL;
- }
- return rc > 99 ? 99 : rc;
- }
- #if ENABLE_SV
- int sv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
- int sv_main(int argc UNUSED_PARAM, char **argv)
- {
- return sv(argv);
- }
- #endif
- #if ENABLE_SVC
- int svc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
- int svc_main(int argc UNUSED_PARAM, char **argv)
- {
- char command[2];
- const char *optstring;
- unsigned opts;
- optstring = "udopchaitkx";
- opts = getopt32(argv, optstring);
- argv += optind;
- if (!argv[0] || !opts)
- bb_show_usage();
- argv -= 2;
- if (optind > 2) {
- argv--;
- argv[2] = (char*)"--";
- }
- argv[0] = (char*)"sv";
- argv[1] = command;
- command[1] = '\0';
- do {
- if (opts & 1) {
- int r;
- command[0] = *optstring;
-
- GETOPT_RESET();
- r = sv(argv);
- if (r)
- return 1;
- }
- optstring++;
- opts >>= 1;
- } while (opts);
- return 0;
- }
- #endif
|