diff -ru runit-1.3.1/src/runsv.c runit-1.3.1.new/src/runsv.c --- runit-1.3.1/src/runsv.c 2005-08-24 15:14:39.427019666 -0500 +++ runit-1.3.1.new/src/runsv.c 2005-09-19 10:00:44.490650789 -0500 @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -39,6 +40,11 @@ #define W_UP 0 #define W_DOWN 1 #define W_EXIT 2 +/* exit type */ +#define ET_NOEXIT 0 +#define ET_NORMAL 1 +#define ET_SIGNAL 2 +#define ET_UNKNOWN 127 struct svdir { int pid; @@ -50,6 +56,10 @@ int fdcontrol; int fdcontrolwrite; int islog; + unsigned char runexit_type; + unsigned char runexit_val; + unsigned char finexit_type; + unsigned char finexit_val; }; struct svdir svd[2]; @@ -86,7 +96,7 @@ void update_status(struct svdir *s) { unsigned long l; int fd; - char status[20]; + char status[24]; char bspace[64]; buffer b; char spid[FMT_ULONG]; @@ -180,6 +190,10 @@ else status[18] =0; status[19] =s->state; + status[20] =s->runexit_type; + status[21] =s->runexit_val; + status[22] =s->finexit_type; + status[23] =s->finexit_val; if ((fd =open_trunc("supervise/status.new")) == -1) { warn("unable to open supervise/status.new"); return; @@ -399,6 +413,10 @@ svd[0].ctrl =C_NOOP; svd[0].want =W_UP; svd[0].islog =0; + svd[0].runexit_type =0; + svd[0].runexit_val =0; + svd[0].finexit_type =0; + svd[0].finexit_val =0; svd[1].pid =0; taia_now(&svd[0].start); if (stat("down", &s) != -1) svd[0].want =W_DOWN; @@ -416,6 +434,10 @@ svd[1].ctrl =C_NOOP; svd[1].want =W_UP; svd[1].islog =1; + svd[1].runexit_type =0; + svd[1].runexit_val =0; + svd[1].finexit_type =0; + svd[1].finexit_val =0; taia_now(&svd[1].start); if (stat("log/down", &s) != -1) svd[1].want =W_DOWN; @@ -540,13 +562,39 @@ svd[0].pid =0; pidchanged =1; svd[0].ctrl &=~C_TERM; - if (svd[0].state != S_FINISH) + if (svd[0].state != S_FINISH) { + if (WIFEXITED(wstat)) { + svd[0].runexit_type = ET_NORMAL; + svd[0].runexit_val = WEXITSTATUS(wstat); + } else if (WIFSIGNALED(wstat)) { + svd[0].runexit_type = ET_SIGNAL; + svd[0].runexit_val = WTERMSIG(wstat); + } else if(WIFSTOPPED(wstat)) { + /* do nothing */ + } else { + svd[0].runexit_type = ET_UNKNOWN; + svd[0].runexit_val = 0; + } if ((fd =open_read("finish")) != -1) { close(fd); svd[0].state =S_FINISH; update_status(&svd[0]); continue; } + } else { + if (WIFEXITED(wstat)) { + svd[0].finexit_type = ET_NORMAL; + svd[0].finexit_val = WEXITSTATUS(wstat); + } else if (WIFSIGNALED(wstat)) { + svd[0].finexit_type = ET_SIGNAL; + svd[0].finexit_val = WTERMSIG(wstat); + } else if(WIFSTOPPED(wstat)) { + /* do nothing */ + } else { + svd[0].finexit_type = ET_UNKNOWN; + svd[0].finexit_val = 0; + } + } svd[0].state =S_DOWN; taia_uint(&deadline, 1); taia_add(&deadline, &svd[0].start, &deadline); diff -ru runit-1.3.1/src/sv.c runit-1.3.1.new/src/sv.c --- runit-1.3.1/src/sv.c 2005-08-24 15:14:39.901422814 -0500 +++ runit-1.3.1.new/src/sv.c 2005-09-19 14:08:48.592763295 -0500 @@ -1,5 +1,6 @@ #include #include +#include #include #include "str.h" #include "strerr.h" @@ -48,7 +49,7 @@ int (*cbk)(char*) =0; int curdir, fd, r; -char svstatus[20]; +char svstatus[24]; char sulong[FMT_ULONG]; void usage() { @@ -63,6 +64,10 @@ strerr_warn4(FATAL, m1, m2, ": ", &strerr_sys); done(lsb ? 151 : 100); } +void fatal2x(char *m1, char *m2) { + strerr_warn3(FATAL, m1, m2, 0); + done(lsb ? 151 : 100); +} void out(char *p, char *m1) { buffer_puts(buffer_1, p); buffer_puts(buffer_1, *service); @@ -86,6 +91,124 @@ void outs2(const char *s) { buffer_puts(buffer_2, s); } void flush2(const char *s) { outs2(s); buffer_flush(buffer_2); } +typedef int (*flagprint_fn)(); +typedef struct statusflag { + char flagchar; + flagprint_fn printfunc; +} statusflag_t; + +#define MAX_FLAGPRINTFUNCS 16 +flagprint_fn flagprintfuncs[MAX_FLAGPRINTFUNCS] = { 0, }; +int flagprintfunccount = 0; /* number of printfuncs currently requested */ + +static inline int getPID() { + int 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]; + return pid; +} + +static int printULong(unsigned long ulong) { + char sulong[FMT_ULONG]; + memset(sulong, 0, FMT_ULONG); + fmt_ulong(sulong, ulong); + outs(sulong); + return 1; +} + +static inline int printExitData(int exit_type, int exit_val) { + switch(exit_type) { + case 0: + outs("none:"); + break; + case 1: + outs("exit:"); + break; + case 2: + outs("signal:"); + break; + default: + outs("unknown:"); + } + printULong(exit_val); + return 1; +} + +static int printRunExit() { + return printExitData(svstatus[20], svstatus[21]); +} + +static int printFinExit() { + return printExitData(svstatus[22], svstatus[23]); +} + +static int printPID() { + int pid = getPID(svstatus); + if(pid) printULong(pid); + else outs("-"); + return 1; +} + +static int printCurrentState() { + switch(svstatus[19]) { + case 0: + outs("down"); + break; + case 1: + outs("run"); + break; + case 2: + outs("finish"); + break; + default: + outs("error"); + return -1; + } + return 1; +} + +static int printWantState() { + switch(svstatus[17]) { + case 'u': + outs("up"); + break; + case 'd': + outs("down"); + break; + case 'x': + outs("exit"); + break; + default: + outs("error"); + return -1; + } + return 1; +} + +static int printUptime() { + struct tai svtai; /* from structure */ + struct tai now; /* current time*/ + + tai_now(&now); + tai_unpack(svstatus, &svtai); + if (tai_less(&now,&svtai)) svtai = now; + tai_sub(&svtai,&now,&svtai); + printULong(tai_approx(&svtai)); + return 1; +} + +const statusflag_t statusflags[] = { + {'r', printRunExit}, + {'f', printFinExit}, + {'p', printPID}, + {'s', printCurrentState}, + {'w', printWantState}, + {'u', printUptime}, + {0, 0}, +}; + + int svstatus_get() { if ((fd =open_write("supervise/ok")) == -1) { if (errno == error_nodevice) { @@ -100,10 +223,12 @@ warn("unable to open supervise/status"); return(-1); } - r =read(fd, svstatus, 20); + memset(svstatus, 0, 24); + r =read(fd, svstatus, 24); close(fd); switch(r) { case 20: break; + case 24: break; case -1: warn("unable to read supervise/status"); return(-1); default: warnx("unable to read supervise/status: bad format"); return(-1); } @@ -122,10 +247,7 @@ } normallyup =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]; + pid =getPID(); tai_unpack(svstatus, &tstatus); if (pid) { switch (svstatus[19]) { @@ -152,18 +274,28 @@ int status(char *unused) { r =svstatus_get(); switch(r) { case -1: if (lsb) done(4); case 0: return(0); } - r =svstatus_print(*service); - if (chdir("log") == -1) { - if (errno != error_noent) { - outs("; log: "); outs(WARN); - outs("unable to change to log service directory: "); - outs(error_str(errno)); + + if(flagprintfunccount == 0) { + r =svstatus_print(*service); + if (chdir("log") == -1) { + if (errno != error_noent) { + outs("; log: "); outs(WARN); + outs("unable to change to log service directory: "); + outs(error_str(errno)); + } } - } - else - if (svstatus_get()) { - outs("; "); svstatus_print("log"); + else + if (svstatus_get()) { + outs("; "); svstatus_print("log"); + } + } else { + int i; + outs(*service); + for(i = 0; i < flagprintfunccount; i++) { + outs(" "); + flagprintfuncs[i](); } + } flush("\n"); if (lsb) switch(r) { case 1: done(0); case 2: done(3); case 0: done(4); } return(r); @@ -319,17 +451,42 @@ 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; + if ((act == &status) && (**service == '-')) { + char *flag = (*service)+1; + while(*flag != 0) { + /* search for a function associated with this flag */ + int fnidx, foundFlag = 0; + for(fnidx = 0; statusflags[fnidx].flagchar != 0; fnidx++) { + if(flagprintfunccount == MAX_FLAGPRINTFUNCS) { + fatal("Excessive number of flag-based parameters provided"); + } + if(statusflags[fnidx].flagchar == *flag) { + flagprintfuncs[flagprintfunccount++] = statusflags[fnidx].printfunc; + foundFlag = 1; + break; + } + } + if(!foundFlag) { + char badFlag[3] = {'-', 'X', 0}; + badFlag[1] = *flag; + fatal2x("Invalid status flag provided: ", badFlag); + } + flag++; } + *service = 0; } else - if (chdir(*service) == -1) { - fail("unable to change to service directory"); - *service =0; + 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(acts) == -1) *service =0; if (fchdir(curdir) == -1) fatal("unable to change to original directory"); service++;