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 =&check;
-  switch (*action) {
-  case 'x': case 'e':
-    acts ="x"; break;
-  case 'X': case 'E':
-    acts ="x"; kll =1; cbk =&check; break;
-  case 'D':
-    acts ="d"; kll =1; cbk =&check; break;
-  case 'T':
-    acts ="tc"; kll =1; cbk =&check; break;
-  case 'c':
-    if (!str_diff(action, "check")) { act =0; acts ="C"; cbk =&check; 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 =&check; break; }
-    if (!str_diff(action, "start")) { acts ="u"; cbk =&check; break; }
-    if (!str_diff(action, "stop")) { acts ="d"; cbk =&check; break; }
-    if (lsb && str_diff(action, "status")) usage();
-    act =&status; cbk =0; break;
-  case 'r':
-    if (!str_diff(action, "restart")) { acts ="tcu"; cbk =&check; break; }
-    usage();
-  case 'f':
-    if (!str_diff(action, "force-reload"))
-      { acts ="tc"; kll =1; cbk =&check; break; }
-    if (!str_diff(action, "force-restart"))
-      { acts ="tcu"; kll =1; cbk =&check; break; }
-    if (!str_diff(action, "force-shutdown"))
-      { acts ="x"; kll =1; cbk =&check; break; }
-    if (!str_diff(action, "force-stop"))
-      { acts ="d"; kll =1; cbk =&check; 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 =&check;
+    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 != '.')) {

Reply via email to