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