summary refs log tree commit diff
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
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.
-rw-r--r--doc/upgrade.html9
-rw-r--r--man/runsv.824
-rw-r--r--package/CHANGES7
-rw-r--r--src/runsv.c67
4 files changed, 90 insertions, 17 deletions
diff --git a/doc/upgrade.html b/doc/upgrade.html
index 9865c85..cb08f36 100644
--- a/doc/upgrade.html
+++ b/doc/upgrade.html
@@ -9,6 +9,13 @@
 <hr>
 <h1>runit - upgrading from previous versions</h1>
 <hr>
+<h3>1.1.0 to 1.2.0</h3>
+With this version the <a href="runsv.8.html">runsv</a> program makes
+controlling the service through commands normally sent by
+<a href="runsvctrl.8.html">runsvctrl</a> configurable;
+arbitrary actions through external programs can optionally be specified, and
+signalling of the service disabled if desired.
+See the <a href="runsv.8.html">man page</a> for details.
 <h3>1.0.x to 1.1.0</h3>
 The <a href="svlogd.8.html">svlogd</a> program now interprets the ``e'' and
 ``E'' configuration options so that they can be combined to select or
@@ -19,7 +26,7 @@ It also provides the new ``t'' and ``N'' configuration options, see the
 The <a href="chpst.8.html">chpst</a> program supports adjusting the nice
 level through the new -n command line option.
 <p>
-Staring with this version, <tt>/etc/runit/2</tt> by default runs the
+Starting with this version, <tt>/etc/runit/2</tt> by default runs the
 <a href="runsvdir.8.html">runsvdir</a> program with the -P option.
 To adapt edit <tt>/etc/runit/2</tt> and change the invocation of
 <a href="runsvdir.8.html">runsvdir</a> accordingly, see
diff --git a/man/runsv.8 b/man/runsv.8
index eafad0c..c6b5a77 100644
--- a/man/runsv.8
+++ b/man/runsv.8
@@ -157,6 +157,30 @@ ignores unknown characters written to the control pipe.
 usually blocks if no
 .B runsv
 process is running in the service directory.
+.SH CUSTOMIZE CONTROL
+For each control character
+.I c
+sent to the control pipe,
+.B runsv
+first checks if
+.I service\fR/control/\fIc
+exists and is executable.
+If so, it starts
+.I service\fR/control/\fIc
+and waits for it to terminate, before interpreting the command.
+If the program exits with return code 0,
+.B runsv
+refrains from sending the service the corresponding signal.
+The command
+.I o
+is always considered as command
+.IR u .
+The
+.IR u ,
+.IR e ,
+and
+.I x
+commands of an optional log service cannot be customized.
 .SH SIGNALS
 If
 .B runsv
diff --git a/package/CHANGES b/package/CHANGES
index 1f3f9f2..291b13d 100644
--- a/package/CHANGES
+++ b/package/CHANGES
@@ -1,3 +1,10 @@
+runit 1.2.0
+
+  * 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.
+
 runit 1.1.0
 Sat, 06 Nov 2004 17:21:11 +0000
   * svlogd.c: new config option t timeout (thx Enrico Scholz); config
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);