runit

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 458e39242e04c74201aea3a56fec2d913a1bab94
parent 4f980a523dcc75ab77beadcc036ee45c95505c9f
Author: Gerrit Pape <pape@smarden.org>
Date:   Sat, 23 Jul 2005 12:08:56 +0000

  * sv.c: new sv program to control services, optionally can be linked to
    /etc/init.d/ as lsb "init script" command line interface.
  * Makefile, TARGETS: adapt.

Diffstat:
Msrc/Makefile | 6++++++
Msrc/TARGETS | 2++
Asrc/sv.c | 318+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 326 insertions(+), 0 deletions(-)

diff --git a/src/Makefile b/src/Makefile @@ -24,6 +24,9 @@ runsvstat: load runsvstat.o unix.a byte.a time.a runsvctrl: load runsvctrl.o unix.a byte.a ./load runsvctrl unix.a byte.a +sv: load sv.o unix.a byte.a time.a + ./load sv unix.a byte.a time.a + svwaitup: load svwaitup.o unix.a byte.a time.a ./load svwaitup unix.a byte.a time.a @@ -61,6 +64,9 @@ runsvstat.o: compile sysdeps runsvstat.c runsvctrl.o: compile runsvctrl.c ./compile runsvctrl.c +sv.o: compile sysdeps sv.c + ./compile sv.c + svwaitup.o: compile sysdeps svwaitup.c ./compile svwaitup.c diff --git a/src/TARGETS b/src/TARGETS @@ -10,6 +10,8 @@ runsvstat runsvstat.o runsvctrl runsvctrl.o +sv +sv.o svwaitdown svwaitdown.o svwaitup diff --git a/src/sv.c b/src/sv.c @@ -0,0 +1,318 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include "str.h" +#include "strerr.h" +#include "error.h" +#include "sgetopt.h" +#include "open.h" +#include "env.h" +#include "buffer.h" +#include "fmt.h" +#include "scan.h" +#include "tai.h" +#include "taia.h" + +#define USAGE " [-v] [-w sec] action service ..." +#define USAGELSB " [-w sec] action" + +#define VERSION "$Id$" + +#define FATAL "fatal: " +#define FAIL "fail: " +#define WARN "warning: " +#define OK "ok: " + +/* #define VARSERVICE "./" */ +#define VARSERVICE "/var/service/" +/* #define ETCRUNITRUNSV "/etc/runit/runsv/" */ +#define USLEEPDELAY 250000 + +char *progname; +char *action; +char actch =0; +char **service; +char **servicex; +unsigned int services; +unsigned int rc =0; +unsigned int lsb; +unsigned int verbose =0; +unsigned long wait =7; +struct taia tstart, tnow, tdiff; +struct tai tstatus; + +int (*act)() =0; +int (*cbk)() =0; + +int curdir, fd, r; +char svstatus[20]; +char sulong[FMT_ULONG]; + +void usage() { + if (!lsb) strerr_die4x(100, "usage: ", progname, USAGE, "\n"); + strerr_die4x(2, "usage: ", progname, USAGELSB, "\n"); +} +void done(unsigned int e) { if (curdir != -1) fchdir(curdir); _exit(e); } +void fatal(char *m1) { + strerr_warn3(FATAL, m1, ": ", &strerr_sys); + done(lsb ? 150 : 100); } +void fatal2(char *m1, char *m2) { + strerr_warn4(FATAL, m1, m2, ": ", &strerr_sys); + done(lsb ? 150 : 100); +} +void out(char *p, char *m1) { + buffer_puts(buffer_1, p); + buffer_puts(buffer_1, *service); + buffer_puts(buffer_1, ": "); + buffer_puts(buffer_1, m1); + if (errno) { + buffer_puts(buffer_1, ": "); + buffer_puts(buffer_1, error_str(errno)); + } + buffer_puts(buffer_1, "\n"); + buffer_flush(buffer_1); +} +void fail(char *m1) { ++rc; out(FAIL, m1); } +void failx(char *m1) { errno =0; fail(m1); } +void warn(char *m1) { ++rc; out(WARN, m1); } +void warnx(char *m1) { errno =0; warn(m1); } +void ok(char *m1) { errno =0; out(OK, m1); } + +int svstatus_get() { + if ((fd =open_write("supervise/ok")) == -1) { + if (errno == error_nodevice) { + actch == 'x' ? ok("runsv not running") : failx("runsv not running"); + return(0); + } + warn("unable to open supervise/ok"); + return(-1); + } + close(fd); + if ((fd =open_read("supervise/status")) == -1) { + warn("unable to open supervise/status"); + return(-1); + } + r =read(fd, svstatus, 20); + close(fd); + switch(r) { + case 20: break; + case -1: warn("unable to read supervise/status"); return(-1); + default: warnx("unable to read supervise/status: bad format"); return(-1); + } + return(1); +} +unsigned int svstatus_print() { + int pid; + int normallyup =0; + struct stat s; + + if (stat("down", &s) == -1) { + if (errno != error_noent) { + warn("unable to stat down"); + return(0); + } + normallyup =1; + } + buffer_puts(buffer_1, *service); + // buffer_puts(buffer_1, ": status: "); + buffer_puts(buffer_1, ": "); + + pid =(unsigned char) svstatus[15]; + pid <<=8; pid +=(unsigned char)svstatus[14]; + pid <<=8; pid +=(unsigned char)svstatus[13]; + pid <<=8; pid +=(unsigned char)svstatus[12]; + tai_unpack(svstatus, &tstatus); + if (pid) { + switch (svstatus[19]) { + case 1: buffer_puts(buffer_1, "run "); break; + case 2: buffer_puts(buffer_1, "finish "); break; + } + buffer_puts(buffer_1, "(pid "); + buffer_put(buffer_1, sulong, fmt_ulong(sulong, pid)); + buffer_puts(buffer_1, ") "); + } + else + buffer_puts(buffer_1, "down "); + buffer_put(buffer_1, sulong, + fmt_ulong(sulong, tnow.sec.x < tstatus.x ? 0 : tnow.sec.x -tstatus.x)); + buffer_puts(buffer_1, "s"); + if (pid && !normallyup) buffer_puts(buffer_1,", normally down"); + if (!pid && normallyup) buffer_puts(buffer_1,", normally up"); + if (pid && svstatus[16]) buffer_puts(buffer_1,", paused"); + if (!pid && (svstatus[17] == 'u')) buffer_puts(buffer_1,", want up"); + if (pid && (svstatus[17] == 'd')) buffer_puts(buffer_1,", want down"); + if (pid && svstatus[18]) buffer_puts(buffer_1, ", got TERM"); + buffer_puts(buffer_1, "\n"); + buffer_flush(buffer_1); + return(pid ? 1 : 2); +} +int status() { + r =svstatus_get(); + switch(r) { case -1: if (lsb) done(4); case 0: return(0); } + buffer_puts(buffer_1, "status: "); + r =svstatus_print(); + if (lsb) switch(r) { case 1: done(0); case 2: done(3); case 0: done(4); } + return(r); +} + +int check() { + unsigned int pid; + + /* + r =svstatus_get(); + switch(r) { case 0: ++rc; case -1: return(-1); } + */ + if (svstatus_get() <= 0) return(-1); + pid =(unsigned char) svstatus[15]; + pid <<=8; pid +=(unsigned char)svstatus[14]; + pid <<=8; pid +=(unsigned char)svstatus[13]; + pid <<=8; pid +=(unsigned char)svstatus[12]; + switch (actch) { + case 'u': if (!pid) return(0); break; + case 'd': if (pid) return(0); break; + case 't': + tai_unpack(svstatus, &tstatus); + if ((tstart.sec.x > tstatus.x) || ! pid || svstatus[18]) return(0); + break; + case 'o': + tai_unpack(svstatus, &tstatus); + if ((! pid && tstart.sec.x > tstatus.x) || (pid && svstatus[17] != 'd')) + return(0); + } + buffer_puts(buffer_1, OK); + svstatus_print(); + return(1); +} +int check_shtdown() { + if ((r =svstatus_get()) == -1) return(-1); + if (r == 0) return(1); + return(0); +} + +int control() { + if (svstatus_get() <= 0) return(-1); + if (svstatus[17] == actch) return(0); + if ((fd =open_write("supervise/control")) == -1) { + if (errno != error_nodevice) + warn("unable to open supervise/control"); + else + actch == 'x' ? ok("runsv not running") : failx("runsv not running"); + return(-1); + } + r =write(fd, &actch, 1); + close(fd); + if (r != 1) { + warn("unable to write to supervise/control"); + return(-1); + } + return(1); +} + +int main(int argc, char **argv) { + unsigned int i, done; + char *x; + + progname =*argv; + for (i =str_len(*argv); i; --i) if ((*argv)[i -1] == '/') break; + *argv +=i; + optprogname =progname =*argv; + service =argv; + services =1; + lsb =(str_diff(progname, "sv")); + if ((x =env_get("SVWAIT"))) scan_ulong(x, &wait); + while ((i =getopt(argc, (const char* const*)argv, "w:vV")) != opteof) { + switch(i) { + case 'w': scan_ulong(optarg, &wait); + case 'v': verbose =1; break; + case 'V': strerr_warn1("$Id$", 0); + case '?': usage(); + } + } + argv +=optind; argc -=optind; + if (!(action =*argv++)) usage(); --argc; + if (!lsb) { + service =argv; + services =argc; + } + if (! *service) usage(); + + taia_now(&tnow); tstart =tnow; + if ((curdir =open_read(".")) == -1) fatal("unable to open current directory"); + + act =&control; + if (verbose) cbk =&check; + switch (*action) { + case 'x': case 'e': action ="x"; + case 'u': case 'd': case 'o': case 't': case 'p': case 'c': case 'h': + case 'a': case 'i': case 'k': case 'q': case '1': case '2': + actch =*action; break; + case 's': + if (!str_diff(action, "shutdown")) { + actch ='x'; cbk =&check_shtdown; break; + } + if (!str_diff(action, "start")) { actch ='u'; cbk =&check; break; } + if (!str_diff(action, "stop")) { actch ='d'; cbk =&check; break; } + if (lsb && str_diff(action, "status")) usage(); + act =&status; cbk =0; break; + case 'r': + if (!str_diff(action, "restart")) { actch ='t'; cbk =&check; break; } + usage(); + case 'f': + if (!str_diff(action, "force-reload")) { actch ='t'; cbk =&check; break; } + default: + usage(); + } + + servicex =service; + for (i =0; i < services; ++i) { + if ((**service != '/') && (**service != '.')) { + if ((chdir(VARSERVICE) == -1) || (chdir(*service) == -1)) { + fail("unable to change to service directory"); + *service =0; + } + } + else + if (chdir(*service) == -1) { + fail("unable to change to service directory"); + *service =0; + } + if (*service) if (act() == -1) *service =0; + if (fchdir(curdir) == -1) fatal("unable to change to original directory"); + service++; + } + + if (*cbk) + for (;;) { + taia_sub(&tdiff, &tnow, &tstart); + service =servicex; done =1; + for (i =0; i < services; ++i, ++service) { + if (! *service) continue; + if ((**service != '/') && (**service != '.')) { + if ((chdir(VARSERVICE) == -1) || (chdir(*service) == -1)) { + fail("unable to change to service directory"); + *service =0; + } + } + else + if (chdir(*service) == -1) { + fail("unable to change to service directory"); + *service =0; + } + if (taia_approx(&tdiff) > wait) { + buffer_puts(buffer_1, "timeout "); + sulong[fmt_ulong(sulong, wait)] =0; + buffer_puts(buffer_1, sulong); + buffer_puts(buffer_1, "s: "); + if (svstatus_get() > 0) { svstatus_print(); ++rc; } + *service =0; + } + if (*service) { if (cbk() != 0) *service =0; else done =0; } + if (fchdir(curdir) == -1) + fatal("unable to change to original directory"); + } + if (done) break; + usleep(USLEEPDELAY); + taia_now(&tnow); + } + return(rc); +}