civodul pushed a commit to branch devel
in repository shepherd.

commit 926ac11a3ecee1b488777b977a4a1fb969d3b333
Author: Ludovic Courtès <l...@gnu.org>
AuthorDate: Thu Jun 6 22:45:14 2024 +0200

    service: ‘shutdown-services’ catches exceptions from ‘stop-service’.
    
    Fixes a bug introduced in c6f97c617d686e3ed0a19f670179c77e938e41a0
    whereby exceptions thrown by ‘stop-service’ would not be caught by
    ‘shutdown-services’; in turn, the ‘power-off’ action would throw after
    it has stopped the root service, hanging the system without powering it
    off.
    
    * modules/shepherd/service.scm (shutdown-services): Remove unnecessary
    ‘service-running?’ check.  Wrap ‘stop-service’ call in ‘guard’ and
    ignore any errors.
    * tests/power-off.sh: New file.
    * Makefile.am (TESTS): Add it.
---
 Makefile.am                  |  1 +
 modules/shepherd/service.scm | 15 +++++++--
 tests/power-off.sh           | 74 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 87 insertions(+), 3 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 17c79c0..d9aa541 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -280,6 +280,7 @@ TESTS =                                             \
   tests/close-on-exec.sh                       \
   tests/daemonize.sh                           \
   tests/eval-load.sh                           \
+  tests/power-off.sh                           \
   tests/services/monitoring.sh                 \
   tests/services/repl.sh                       \
   tests/services/timer.sh                      \
diff --git a/modules/shepherd/service.scm b/modules/shepherd/service.scm
index e6ce7f2..9d1564c 100644
--- a/modules/shepherd/service.scm
+++ b/modules/shepherd/service.scm
@@ -2728,9 +2728,18 @@ requested to be removed."
   ;; suspending via (@ (fibers) sleep), 'spawn-command', or similar.
   (for-each
    (lambda (service)
-     (when (and (service-running? service)
-                (not (eq? service root-service)))
-       (stop-service service)))
+     (unless (eq? service root-service)
+       (guard (c ((action-runtime-error? c)
+                  (local-output
+                   (l10n "Ignoring error while stopping ~a: ~s")
+                   (service-canonical-name service)
+                   (cons (action-runtime-error-key c)
+                         (action-runtime-error-arguments c))))
+                 (else
+                  (local-output
+                   (l10n "Ignoring unknown error while stopping ~a: ~s")
+                   (service-canonical-name service) c)))
+        (stop-service service))))
    (service-list)))
 
 (define (check-for-dead-services)
diff --git a/tests/power-off.sh b/tests/power-off.sh
new file mode 100644
index 0000000..ad8494a
--- /dev/null
+++ b/tests/power-off.sh
@@ -0,0 +1,74 @@
+# GNU Shepherd --- Check whether 'halt' works.
+# Copyright © 2024 Ludovic Courtès <l...@gnu.org>
+#
+# This file is part of the GNU Shepherd.
+#
+# The GNU Shepherd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# The GNU Shepherd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with the GNU Shepherd.  If not, see <http://www.gnu.org/licenses/>.
+
+shepherd --version
+herd --version
+
+socket="t-socket-$$"
+conf="t-conf-$$"
+log="t-log-$$"
+pid="t-pid-$$"
+witness="t-powered-off-$$"
+
+herd="herd -s $socket"
+
+trap "cat $log || true; rm -f $socket $conf $log $witness;
+      test -f $pid && kill \`cat $pid\` || true; rm -f $pid" EXIT
+
+cat > "$conf" <<EOF
+(register-services
+ (list (service
+        '(a)
+        #:start (const #t)
+         #:stop (lambda _ (throw 'boooo!)))  ;fails to stop
+       (service
+        '(b)
+         #:requirement '(a)
+        #:start (make-forkexec-constructor
+                  '("$SHELL" "-c"
+                    "trap 'echo ignoring SIGTERM' SIGTERM; while true; do 
sleep 1; done"))
+         #:stop (make-kill-destructor #:grace-period 0.5)
+        #:respawn? #t)))
+EOF
+
+rm -f "$pid" "$socket"
+shepherd -I -s "$socket" -c "$conf" --pid="$pid" --log="$log" &
+
+while ! test -f "$pid"; do sleep 0.5 ; done
+
+$herd start b
+$herd status
+
+service_pid="`$herd status b | grep PID \
+   | sed -es'/.*PID \([0-9]\+\) running.*$/\1/g'`"
+kill -0 "$service_pid"
+
+# Now make sure the 'power-off' action works even in the face of a 'stop'
+# method throwing an exception.
+
+$herd eval root "(set! (@ (shepherd system) power-off)
+   (lambda ()
+     (open-output-file \"$PWD/$witness\")
+     (primitive-exit 0)))"
+
+rm -f "$witness"
+halt -s "$socket"
+
+kill -0 "$service_pid" && false
+test -f "$witness"
+while kill -0 "$(cat "$pid")"; do sleep 1; done

Reply via email to