Welcome to little lamb

Code » anopa » commit ab4bd8c

stop: Change how --all works

author Olivier Brunel
2015-11-21 16:33:09 UTC
committer Olivier Brunel
2015-11-24 13:08:46 UTC
parent 458548cc57c53ab6b399ec0b0f6a08ead1c9baa9

stop: Change how --all works

Now --all only means stopping all up services, nothing else. When specified a
second time, then mode "stop-all" is enabled, which means:

- for all down services, send 'x' to their s6-supervise
- send 'dx' instead of 'd' to the s6-supervise of up services
- ignore dependency error (i.e. always stop everything)

So same as before, only with stopping s6-supervise of down services, to properly
bring the entire supervised tree down (assuming s6-svscan is down already, ofc).

doc/aa-stop.pod +18 -18
src/anopa/aa-stop.c +36 -4
src/scripts/aa-stage3 +1 -1

diff --git a/doc/aa-stop.pod b/doc/aa-stop.pod
index ef0b901..1452573 100644
--- a/doc/aa-stop.pod
+++ b/doc/aa-stop.pod
@@ -13,14 +13,12 @@ B<aa-stop> [B<-D>] [B<-r> I<repodir>] [B<-l> I<listdir>] [B<-a>]
 
 =item B<-a, --all>
 
-Stops all running/started services. This option is intended to be used during
-stage 3; When used, you shouldn't specify any service on the command line.
+Stops all running/started services.
 
-Note that when used, failing dependencies will not cause not to stop services.
-That is, is A needs B, stopping B would depend on stopping A first, and if that
-failed B wouldn't be stopped (Stopping failed: Failed dependency: A).
-However with this option B would be stopped, as if A had been successfully
-stopped.
+Specify this option twice to enable "stop-all" mode, intended to bring down the
+entire supervised tree (i.e. be used during stage 3, after B<s6-svscan> has been
+brought down).
+When used, you shouldn't specify any service on the command line.
 
 Also see below for more implications.
 
@@ -104,15 +102,18 @@ following differences :
 B<aa-stop>(1) will check if the service is running, and if not simply announce
 it as not up.
 
-When B<--all> is used, instead of 'd' the commands 'dx' are sent to the
-service's B<s6-supervise>, so that after bringing the service down it exits as
-well. This is obviously all intended to bring the supervised tree all down, as
-is expected when using B<--all> (usually from stage 3).
+If the "stop-all" mode is enabled (i.e. option B<--all> used twice), failing
+dependencies will not cause not to stop services.  That is, is A needs B,
+stopping B would depend on stopping A first, and if that failed B wouldn't be
+stopped (Stopping failed: Failed dependency: A).  However with this mode B
+would be stopped, as if A had been successfully stopped.
 
-Note that if a service was not running, no 'x' command is sent so the
-B<s6-supervise> process of the service are kept running. This isn't a problem,
-since they'll simply exit when sending SIGTERM to all process further down in
-stage 3.
+Additionally, B<aa-stop>(1) will send command 'x' to B<s6-supervise> of all down
+services, while it will send commands 'dx' (instead of 'd') to the up services'
+B<s6-supervise>, so that after bringing their services down they exit as well.
+This is obviously all intended to bring the supervised tree all down, as is
+expected, and shouldn't be used if B<s6-svscan> is still running (as it would
+bring the B<s6-supervise> back up).
 
 =head2 Service not up
 
@@ -125,12 +126,11 @@ was up then, but will be down by the time B<aa-stop>(1) wants to stop it. E.g.
 because other services stopped first caused it to stop/crash.
 
 In such a case, the message "Stopping service..." will be shown, and
-B<aa-stop>(1) will send the command(s) as usual; But it won't check for errors
+B<aa-stop>(1) will send the command as usual; But it won't check for errors
 (nor wait for the 'd' event) and simply report the service as "Not up" instead.
 
 This should ensure that e.g. s6 doesn't restart the service, or stops it if that
-was already (being) done, and in case B<--all> was used that the B<s6-supervise>
-process(es) will exit as expected.
+was already (being) done.
 
 =head1 STOPPING A ONE-SHOT SERVICE
 
diff --git a/src/anopa/aa-stop.c b/src/anopa/aa-stop.c
index 4f2da5c..8abc0f9 100644
--- a/src/anopa/aa-stop.c
+++ b/src/anopa/aa-stop.c
@@ -36,6 +36,7 @@
 #include <skalibs/uint.h>
 #include <skalibs/tai.h>
 #include <skalibs/djbunix.h>
+#include <s6/s6-supervise.h>
 #include <anopa/common.h>
 #include <anopa/err.h>
 #include <anopa/init_repo.h>
@@ -283,12 +284,36 @@ close_fd (int fd)
     close_fd_for (fd, -1);
 }
 
+static void
+stop_supervise_for (int si)
+{
+    aa_service *s = aa_service (si);
+    int l_sn = strlen (aa_service_name (s));
+    char dir[l_sn + 1 + sizeof (S6_SUPERVISE_CTLDIR) + 8];
+    int r;
+
+    if (s->st.type != AA_TYPE_LONGRUN)
+        return;
+
+    aa_bs_noflush (AA_OUT, "Stopping s6-supervise for ");
+    aa_bs_noflush (AA_OUT, aa_service_name (s));
+    aa_bs_flush (AA_OUT, "...\n");
+
+    byte_copy (dir, l_sn, aa_service_name (s));
+    byte_copy (dir + l_sn, 9 + sizeof (S6_SUPERVISE_CTLDIR), "/" S6_SUPERVISE_CTLDIR "/control");
+
+    r = s6_svc_write (dir, "x", 1);
+    if (r < 0)
+        aa_strerr_warnu2sys ("stop s6-supervise for ", aa_service_name (s));
+}
+
 int
 main (int argc, char * const argv[])
 {
     PROG = "aa-stop";
     const char *path_repo = "/run/services";
     const char *path_list = NULL;
+    int all = 0;
     int i;
 
     aa_secs_timeout = DEFAULT_TIMEOUT_SECS;
@@ -315,7 +340,10 @@ main (int argc, char * const argv[])
         switch (c)
         {
             case 'a':
-                mode = AA_MODE_STOP_ALL | (mode & AA_MODE_IS_DRY);
+                if (all)
+                    mode = AA_MODE_STOP_ALL | (mode & AA_MODE_IS_DRY);
+                else
+                    all = 1;
                 break;
 
             case 'D':
@@ -365,8 +393,7 @@ main (int argc, char * const argv[])
     cols = get_cols (1);
     is_utf8 = is_locale_utf8 ();
 
-    if ((mode & AA_MODE_STOP_ALL && (path_list || argc > 0))
-            || (!(mode & AA_MODE_STOP_ALL) && !path_list && argc < 1))
+    if ((all && (path_list || argc > 0)) || (!all && !path_list && argc < 1))
         dieusage (1);
 
     if (aa_init_repo (path_repo, (mode & AA_MODE_IS_DRY) ? AA_REPO_READ : AA_REPO_WRITE) < 0)
@@ -390,7 +417,7 @@ main (int argc, char * const argv[])
             aa_strerr_diefu1sys (-r, "read repository directory");
     }
 
-    if (mode & AA_MODE_STOP_ALL)
+    if (all)
     {
         /* to stop all (up) services, since we've preloaded everything, simply
          * means moving all services from tmp to main list. We just need to make
@@ -407,7 +434,12 @@ main (int argc, char * const argv[])
                 remove_from_list (&aa_tmp_list, si);
             }
             else
+            {
                 ++i;
+
+                if ((mode & AA_MODE_STOP_ALL) && aa_service (si)->st.code == ERR_NOT_UP)
+                    stop_supervise_for (si);
+            }
         }
     }
     else if (path_list)
diff --git a/src/scripts/aa-stage3 b/src/scripts/aa-stage3
index f93b89d..25cab4d 100755
--- a/src/scripts/aa-stage3
+++ b/src/scripts/aa-stage3
@@ -44,7 +44,7 @@ foreground { aa-echo -DB "Stage 3: Preparing ${1}..." }
 # Stop all running services -- s6-svscan did only exec into us, leaving the
 # whole supervised tree intact. Here we stop everything (longrun & oneshot) in
 # order.
-foreground { emptyenv -c s6-setsid aa-ctty -Ds aa-stop -D -ak uncaught-logs }
+foreground { emptyenv -c s6-setsid aa-ctty -Ds aa-stop -D -aak uncaught-logs }
 # We left the catch-all running (in case), make sure everything will exit
 # properly when we send TERM
 foreground { s6-svc -x /run/services/uncaught-logs }