tags 375433 patch thanks Hi,
Allied-Visions GmbH developed a patch to support custom commands (such as reload) in sv's initscript emulation. This required some changes in the way sv handles commands. You can now have /service/foo/custom/reload, and sv reload foo will execute that. This makes it possible to finally seamlessly support e.g. Debian package upgrades where the original initscript has been replaced by a symlink pointing to sv. Best regards, Andras -- Andras Korn <korn at chardonnay.math.bme.hu> <http://chardonnay.math.bme.hu/~korn/> QOTD: cat dad*.dna mom*.dna >baby.out
Index: sv.c =================================================================== --- sv.c (revision 144) +++ sv.c (revision 146) @@ -29,6 +29,9 @@ #define TIMEOUT "timeout: " #define KILL "kill: " +char custom_command_[64]; +char *custom_command = custom_command_+7; + char *progname; char *action; char *acts; @@ -204,6 +207,43 @@ return(!wait_exitcode(w)); } +int execute_custom_command() +{ + char *prog[2]; + int pid, w; + + if ((pid =fork()) == -1) { + outs2(WARN); outs2("unable to fork for "); outs2(*service); + outs2(custom_command); outs2(error_str(errno)); flush2("\n"); + return(0); + } + if (!pid) { + /* Probably faster than a for cycle for 9 bytes) */ + custom_command_[0] = 'c'; + custom_command_[1] = 'u'; + custom_command_[2] = 's'; + custom_command_[3] = 't'; + custom_command_[4] = 'o'; + custom_command_[5] = 'm'; + custom_command_[6] = '/'; + prog[0] =custom_command_; + prog[1] =0; + close(1); + execve(custom_command_, prog, environ); + outs2(WARN); outs2("unable to run "); outs2(*service); outs2("/");outs2(custom_command_);outs2(": "); + outs2(error_str(errno)); flush2("\n"); + _exit(0); + } + while (wait_pid(&w, pid) == -1) { + if (errno == error_intr) continue; + outs2(WARN); outs2("unable to wait for child "); outs2(*service); + outs2("/");outs2(custom_command_);outs2(": ");outs2(error_str(errno)); flush2("\n"); + return(0); + } + return(!wait_exitcode(w)); + +} + int check(char *a) { unsigned int pid; @@ -216,6 +256,9 @@ pid <<=8; pid +=(unsigned char)svstatus[12]; switch (*a) { case 'x': return(0); + case '0': + execute_custom_command(); + break; case 'u': if (!pid || svstatus[19] != 1) return(0); if (!checkscript()) return(0); @@ -261,9 +304,62 @@ return(1); } +typedef enum { + argf_kll = 1, /* Set kll to 1 */ + argf_act0 = 2, /* Set act to 0 */ + argf_acts = 4, /* Set act to &status */ +} arg_flag_t; + +typedef struct { + char *name; + char *acts; + void *cbk; + arg_flag_t flags; +} arg_t ; + +/* Built in arguments - what is not listed here is taken as custom */ +arg_t arguments[] = { +/* Argument acts cbk flags */ + {"exit", "x", NULL, 0}, + {"x", "x", NULL, 0}, + {"Exit", "x", check, argf_kll}, + {"X", "x", check, argf_kll}, + {"D", "d", check, argf_kll}, + {"T", "tc", check, argf_kll}, + {"c", "C", check, argf_act0}, + {"check", "C", check, argf_act0}, + {"tc", "tc", NULL, 0}, + {"tcu", "tcu", NULL, 0}, + {"down", "d", NULL, 0}, + {"once", "o", NULL, 0}, + {"up", "u", NULL, 0}, + {"pause", "p", NULL, 0}, + {"cont", "c", NULL, 0}, + {"hup", "h", NULL, 0}, + {"alarm", "a", NULL, 0}, + {"interrupt", "i", NULL, 0}, + {"quit", "q", NULL, 0}, + {"term", "t", NULL, 0}, + {"kill", "k", NULL, 0}, + {"1", "1", NULL, 0}, + {"2", "2", NULL, 0}, + {"shutdown", "x", check, 0}, + {"start", "u", check, 0}, + {"stop", "d", check, 0}, + {"status", "s", NULL, argf_acts}, + {"s", "s", check, argf_acts}, + {"restart", "tcu", check, 0}, + {"force-reload", "tc", check, argf_kll}, + {"force-restart", "tcu", check, argf_kll}, + {"force-shutdown", "x", check, argf_kll}, + {"force-stop", "d", check, argf_kll}, + {NULL, NULL, NULL, 0} /* terminator record */ +} ; + int main(int argc, char **argv) { unsigned int i, done; char *x; + arg_t *arg; progname =*argv; for (i =str_len(*argv); i; --i) if ((*argv)[i -1] == '/') break; @@ -293,42 +389,34 @@ act =&control; acts ="s"; if (verbose) cbk =✓ - switch (*action) { - case 'x': case 'e': - acts ="x"; break; - case 'X': case 'E': - acts ="x"; kll =1; cbk =✓ break; - case 'D': - acts ="d"; kll =1; cbk =✓ break; - case 'T': - acts ="tc"; kll =1; cbk =✓ break; - case 'c': - if (!str_diff(action, "check")) { act =0; acts ="C"; cbk =✓ break; } - case 'u': case 'd': case 'o': case 't': case 'p': case 'h': - case 'a': case 'i': case 'k': case 'q': case '1': case '2': - action[1] =0; acts =action; break; - case 's': - if (!str_diff(action, "shutdown")) { acts ="x"; cbk =✓ break; } - if (!str_diff(action, "start")) { acts ="u"; cbk =✓ break; } - if (!str_diff(action, "stop")) { acts ="d"; cbk =✓ break; } - if (lsb && str_diff(action, "status")) usage(); - act =&status; cbk =0; break; - case 'r': - if (!str_diff(action, "restart")) { acts ="tcu"; cbk =✓ break; } - usage(); - case 'f': - if (!str_diff(action, "force-reload")) - { acts ="tc"; kll =1; cbk =✓ break; } - if (!str_diff(action, "force-restart")) - { acts ="tcu"; kll =1; cbk =✓ break; } - if (!str_diff(action, "force-shutdown")) - { acts ="x"; kll =1; cbk =✓ break; } - if (!str_diff(action, "force-stop")) - { acts ="d"; kll =1; cbk =✓ break; } - default: - usage(); + + /* Compare action to all known attributes */ + for(arg = arguments; arg->name != NULL; arg++) { + if (!(str_diff(arg->name, action))) { + acts = arg->acts; + cbk = arg->cbk; + if ((arg->flags & argf_kll) != 0) + kll = 1; + if ((arg->flags & argf_act0) != 0) + act = 0; + if ((arg->flags & argf_acts) != 0) + act = &status; + break; + } } + /* If argument is not found in the table, it is custom */ + if (arg->name == NULL) { + char *in, *out; + int len; + act =0; + acts ="0"; + cbk =✓ + for(in = action, out = custom_command, len=sizeof(custom_command_)-8; (*in != '\0') && (len > 0); in++, out++, len--) + *out = *in; + *out = '\0'; + } + servicex =service; for (i =0; i < services; ++i) { if ((**service != '/') && (**service != '.')) {