summary refs log tree commit diff
path: root/src/runsv.c
diff options
context:
space:
mode:
authorGerrit Pape <pape@smarden.org>2004-12-12 18:17:14 +0000
committerGerrit Pape <pape@smarden.org>2004-12-12 18:17:14 +0000
commitaf4f84fb543641fbd8ce847d43fe8b773cfbf0eb (patch)
treecdf551bd31718bc1e4a5795ac6d182454b273095 /src/runsv.c
parentf6710c0dce8fcc5ea1e60e1b13aadd936c4104fa (diff)
downloadrunit-af4f84fb543641fbd8ce847d43fe8b773cfbf0eb.tar.gz
runit-af4f84fb543641fbd8ce847d43fe8b773cfbf0eb.tar.xz
runit-af4f84fb543641fbd8ce847d43fe8b773cfbf0eb.zip
* doc/upgrade.html: typo.
  * runsv.c: support custom control commands through control/ directory,
    optionally switch off sending signal.
  * man/runsv.8: document custom control commands.
Diffstat (limited to 'src/runsv.c')
-rw-r--r--src/runsv.c67
1 files changed, 51 insertions, 16 deletions
diff --git a/src/runsv.c b/src/runsv.c
index 3e826aa..eaf300c 100644
--- a/src/runsv.c
+++ b/src/runsv.c
@@ -18,6 +18,7 @@
 #include "fd.h"
 #include "buffer.h"
 #include "fmt.h"
+#include "byte.h"
 
 #define USAGE " dir"
 
@@ -200,7 +201,39 @@ void update_status(struct svdir *s) {
       warn("unable to rename supervise/status.new to supervise/status");
   }
 }
+unsigned int custom(char c) {
+  int pid;
+  int w;
+  char a[7];
+  struct stat st;
+  char *prog[2];
 
+  byte_copy(a, 7, "ctrl/?");
+  a[5] =c;
+  if (stat(a, &st) == 0) {
+    if (st.st_mode & S_IXUSR) {
+      if ((pid =fork()) == -1) {
+	warn("unable to fork for ctrl/?");
+	return(0);
+      }
+      if (! pid) {
+	if (haslog && fd_copy(1, logpipe[1]) == -1)
+	  warn("unable to setup stdout for ctrl/?");
+	prog[0] =a;
+	prog[1] =0;
+	execve(a, prog, environ);
+      }
+      if (wait_pid(&w, pid) == -1) {
+	warn("unable to wait for child ctrl/?");
+	return(0);
+      }
+      return(! wait_exitcode(w));
+    }
+  }
+  else
+    if (errno != error_noent) warn("unable to stat ctrl/?");
+  return(0);
+}
 void stopservice(struct svdir *s) {
   if (s->pid) kill(s->pid, SIGTERM);
   s->ctrl |=C_TERM;
@@ -214,8 +247,10 @@ void startservice(struct svdir *s) {
 
   if (s->state == S_FINISH)
     run[0] ="./finish";
-  else
+  else {
     run[0] ="./run";
+    if (! s->islog) custom('u');
+  }
   run[1] =0;
 
   if (s->pid != 0) stopservice(s); /* should never happen */
@@ -259,64 +294,64 @@ void startservice(struct svdir *s) {
   update_status(s);
   sleep(1);
 }
-
 int ctrl(struct svdir *s, char c) {
   switch(c) {
   case 'd': /* down */
     s->want =W_DOWN;
-    if (s->pid && s->state != S_FINISH) stopservice(s);
-    else update_status(s);
+    update_status(s);
+    if (s->pid && s->state != S_FINISH && ! custom(c)) stopservice(s);
     break;
   case 'u': /* up */
     s->want =W_UP;
+    update_status(s);
     if (s->pid == 0) startservice(s);
-    else update_status(s);
     break;
   case 'e':
   case 'x': /* exit */
     if (s->islog) break;
     s->want =W_EXIT;
-    if (s->pid && s->state != S_FINISH) stopservice(s);
+    update_status(s);
+    if (s->pid && s->state != S_FINISH && ! custom(c)) stopservice(s);
     break;
   case 't': /* sig term */
-    if (s->pid && s->state != S_FINISH) stopservice(s);
+    if (s->pid && s->state != S_FINISH && ! custom(c)) stopservice(s);
     break;
   case 'k': /* sig kill */
     if (s->pid) kill(s->pid, SIGKILL);
     s->state =S_DOWN;
     break;
   case 'p': /* sig pause */
-    kill(s->pid, SIGSTOP);
+    if (s->pid && ! custom(c)) kill(s->pid, SIGSTOP);
     s->ctrl |=C_PAUSE;
     update_status(s);
     break;
   case 'c': /* sig cont */
-    kill(s->pid, SIGCONT);
+    if (s->pid && ! custom(c)) kill(s->pid, SIGCONT);
     if (s->ctrl & C_PAUSE) s->ctrl &=~C_PAUSE;
     update_status(s);
     break;
   case 'o': /* once */
     s->want =W_DOWN;
+    update_status(s);
     if (! s->pid) startservice(s);
-    else update_status(s);
     break;
   case 'a': /* sig alarm */
-    if (s->pid) kill(s->pid, SIGALRM);
+    if (s->pid && ! custom(c)) kill(s->pid, SIGALRM);
     break;
   case 'h': /* sig hup */
-    if (s->pid) kill(s->pid, SIGHUP);
+    if (s->pid && ! custom(c)) kill(s->pid, SIGHUP);
     break;
   case 'i': /* sig int */
-    if (s->pid) kill(s->pid, SIGINT);
+    if (s->pid && ! custom(c)) kill(s->pid, SIGINT);
     break;
   case 'q': /* sig quit */
-    if (s->pid) kill(s->pid, SIGQUIT);
+    if (s->pid && ! custom(c)) kill(s->pid, SIGQUIT);
     break;
   case '1': /* sig usr1 */
-    if (s->pid) kill(s->pid, SIGUSR1);
+    if (s->pid && ! custom(c)) kill(s->pid, SIGUSR1);
     break;
   case '2': /* sig usr2 */
-    if (s->pid) kill(s->pid, SIGUSR2);
+    if (s->pid && ! custom(c)) kill(s->pid, SIGUSR2);
     break;
   }
   return(1);