Package: runit
Version: 2.1.2-32
Severity: wishlist
Tags: patch

Hi!

As I glanced over discussion of adding runit support into
init-system-helpers (thx, Lorenzo), it seemed that it would simplify
things to have a way to force runsvdir re-scan service directory without
waiting for up to 5 seconds.

I prepared prelimitary patch, that implements this feature. When
runsvdir receives SIGALRM, it rescans service directory and writes
timestamp into `.force-rescan' file.

Here I request review. Is this feature really needed. Is timestamp file
needed? Maybe there are simplier ways to implement it?

Making `runit-init` to forward SIGALRM to `runsvdir' does not seems
hard, if we agree on this design.

Here is code:

From fd2712368863c3661bc04d9507883b72e71e3f70 Mon Sep 17 00:00:00 2001
From: Dmitry Bogatov <[email protected]>
Date: Mon, 15 Jul 2019 23:51:43 +0000
Subject: [PATCH 1/2] Make runsvdir(8) rescan directory on SIGALARM

Generally runsvdir(8) rescans service directory every 5 seconds. This patch
makes it possbile to force rescan by sending SIGALARM.

This feature is wanted by maintainer scripts of packages that want to perform
some action after service was started. Obliviously, hanging installation
process for 5 seconds is sub-optimal in such situation.
---
 runit-2.1.2/src/Makefile   |  4 ++--
 runit-2.1.2/src/runsvdir.c | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/runit-2.1.2/src/Makefile b/runit-2.1.2/src/Makefile
index a5f3558..28db6fd 100644
--- a/runit-2.1.2/src/Makefile
+++ b/runit-2.1.2/src/Makefile
@@ -14,8 +14,8 @@ runit-init: load runit-init.o unix.a byte.a
 runsv: load runsv.o unix.a byte.a time.a
        ./load runsv unix.a byte.a time.a
 
-runsvdir: load runsvdir.o unix.a byte.a time.a
-       ./load runsvdir unix.a byte.a time.a
+runsvdir: load runsvdir.o unix.a fmt_ptime.o byte.a time.a byte.a
+       ./load runsvdir unix.a fmt_ptime.o byte.a time.a byte.a
 
 runsvstat: load runsvstat.o unix.a byte.a time.a
        ./load runsvstat unix.a byte.a time.a
diff --git a/runit-2.1.2/src/runsvdir.c b/runit-2.1.2/src/runsvdir.c
index c45b4ee..7ac7999 100644
--- a/runit-2.1.2/src/runsvdir.c
+++ b/runit-2.1.2/src/runsvdir.c
@@ -15,10 +15,17 @@
 #include "iopause.h"
 #include "sig.h"
 #include "ndelay.h"
+#include "fmt_ptime.h"
 
 #define USAGE " [-P] dir"
 #define VERSION "$Id: ecebd0a50510e91639c6a45dda8b0947aa8eb885 $"
 
+/*
+ * After rescan of {svdir} that was forced by sig_alarm (as opposed to regular
+ * rescan once every 5 seconds) is finished, timestamp is written to this path
+ * (relative to {svdir}).
+ */
+#define FORCED_RESCAN "./.forced-rescan"
 #define MAXSERVICES 1000
 
 char *progname;
@@ -40,6 +47,7 @@ iopause_fd io[1];
 struct taia stamplog;
 int exitsoon =0;
 int pgrp =0;
+int siga =0;
 
 void usage () { strerr_die4x(1, "usage: ", progname, USAGE, "\n"); }
 void fatal(char *m1, char *m2) {
@@ -53,6 +61,28 @@ void warn3x(char *m1, char *m2, char *m3) {
 } 
 void s_term() { exitsoon =1; }
 void s_hangup() { exitsoon =2; }
+void s_alarm() { siga = 1; }
+
+void report_forced_rescan() {
+  struct taia stamp;
+  char buf[26];
+  int fd;
+
+  taia_now(&stamp);
+  fmt_taia(buf, &stamp);
+  buf[25] =0;
+
+  fd =open_trunc(FORCED_RESCAN);
+  if (fd == -1) {
+    warn3x("failed to open", FORCED_RESCAN, buf);
+    return;
+  }
+
+  if (write(fd, buf, 25) != 25)
+    warn3x("failed to write", FORCED_RESCAN, buf);
+
+  close(fd);
+}
 
 void runsv(int no, char *name) {
   int pid;
@@ -70,6 +100,7 @@ void runsv(int no, char *name) {
     prog[2] =0;
     sig_uncatch(sig_hangup);
     sig_uncatch(sig_term);
+    sig_uncatch(sig_alarm);
     if (pgrp) setsid();
     pathexec_run(*prog, prog, (char * const *)environ);
     fatal("unable to start runsv ", name);
@@ -183,6 +214,7 @@ int main(int argc, char **argv) {
 
   sig_catch(sig_term, s_term);
   sig_catch(sig_hangup, s_hangup);
+  sig_catch(sig_alarm, s_alarm);
   svdir =*argv++;
   if (argv && *argv) {
     rplog =*argv;
@@ -236,6 +268,10 @@ int main(int argc, char **argv) {
             if (now.sec.x <= (4611686018427387914ULL +(uint64)mtime))
               sleep(1);
             runsvdir();
+            if (siga) {
+              report_forced_rescan();
+              siga =0;
+            }
             while (fchdir(curdir) == -1) {
               warn("unable to change directory, pausing", 0);
               sleep(5);

From d9e37e0f9f303a3d25eb31a5a78d277e176b29c6 Mon Sep 17 00:00:00 2001
From: Dmitry Bogatov <[email protected]>
Date: Fri, 26 Jul 2019 07:23:35 +0000
Subject: [PATCH 2/2] Add regression test for forced-rescan feature

---
 runit-2.1.2/src/Makefile        |  1 +
 runit-2.1.2/src/t/runtest.sh    | 41 +++++++++++++++++++++++++++++++++
 runit-2.1.2/src/t/timestamp/run |  3 +++
 3 files changed, 45 insertions(+)
 create mode 100755 runit-2.1.2/src/t/runtest.sh
 create mode 100755 runit-2.1.2/src/t/timestamp/run

diff --git a/runit-2.1.2/src/Makefile b/runit-2.1.2/src/Makefile
index 28db6fd..07cbff7 100644
--- a/runit-2.1.2/src/Makefile
+++ b/runit-2.1.2/src/Makefile
@@ -4,6 +4,7 @@ default: sysdeps $(IT)
 
 check: $(IT)
        ./check-local $(IT)
+       cd t && runsvdir=../runsvdir ./runtest.sh
 
 runit: load runit.o unix.a byte.a
        ./load runit unix.a byte.a
diff --git a/runit-2.1.2/src/t/runtest.sh b/runit-2.1.2/src/t/runtest.sh
new file mode 100755
index 0000000..c9fc5b3
--- /dev/null
+++ b/runit-2.1.2/src/t/runtest.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+set -eu
+
+: "${runsvdir:=runsvdir}"
+
+rm -rf timestamp/supervise/ service/
+rm -f ./timestamp.txt
+
+mkdir service
+
+"${runsvdir}" ./service &
+echo "pid = $!"
+# Wait till runsvdir scans directory and concludes it is empty
+sleep 1 
+now=$(date +%s)
+echo "now = ${now}"
+ln -sf ../timestamp service/
+kill -ALRM $!
+sleep 0.5
+kill -0 $!
+
+# Wait until runsvdir discovers "service/timestamp" symbolic link
+# and executes "service/timestamp/run" script, which would create
+# "./timestamp" file.
+
+while ! test -f ./timestamp.txt ; do
+    sleep 0.01
+done
+
+new=$(cat timestamp.txt)
+echo "new = ${new}"
+kill -HUP $!
+
+if [[ $((new - now)) -lt 2 ]] ; then
+    echo "fine. forced-rescan seems to work"
+    exit 0
+else
+    echo "bad. forced-rescan took too long"
+    exit 1
+fi
+    
diff --git a/runit-2.1.2/src/t/timestamp/run b/runit-2.1.2/src/t/timestamp/run
new file mode 100755
index 0000000..4c13d68
--- /dev/null
+++ b/runit-2.1.2/src/t/timestamp/run
@@ -0,0 +1,3 @@
+#!/bin/sh
+date +%s > ../timestamp.txt
+sv down .

Attachment: pgpRq6xazVbga.pgp
Description: PGP signature

Reply via email to