shepherd: Adjust 'fork+exec-command/container' for the Shepherd 0.9.

* gnu/build/shepherd.scm (exec-command*): New procedure, with code
formerly...
(make-forkexec-constructor/container): ... here.  Use it.
(fork+exec-command/container): Use 'fork+exec-command' only when
CONTAINER-SUPPORT? is false or PID is the current process.
This commit is contained in:
Ludovic Courtès 2022-03-30 16:10:18 +02:00
parent d4172babe0
commit 938448bf40
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5

View file

@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU ;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2017, 2018, 2019, 2020, 2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2020 Mathieu Othacehe <othacehe@gnu.org> ;;; Copyright © 2020 Mathieu Othacehe <othacehe@gnu.org>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
@ -103,8 +103,13 @@ (define* (read-pid-file/container pid pid-file #:key (max-delay 5))
separate mount and PID name space. Return the \"outer\" PID. " separate mount and PID name space. Return the \"outer\" PID. "
(match (container-excursion* pid (match (container-excursion* pid
(lambda () (lambda ()
(read-pid-file pid-file ;; XXX: Trick for Shepherd 0.9: prevent 'read-pid-file' from
#:max-delay max-delay))) ;; using (@ (fibers) sleep), which would try to suspend the
;; current task, which doesn't work in this extra process.
(with-continuation-barrier
(lambda ()
(read-pid-file pid-file
#:max-delay max-delay)))))
(#f (#f
;; Send SIGTERM to the whole process group. ;; Send SIGTERM to the whole process group.
(catch-system-error (kill (- pid) SIGTERM)) (catch-system-error (kill (- pid) SIGTERM))
@ -114,6 +119,26 @@ (define* (read-pid-file/container pid pid-file #:key (max-delay 5))
;; PID is always 1, but that's not what Shepherd needs to know. ;; PID is always 1, but that's not what Shepherd needs to know.
pid))) pid)))
(define* (exec-command* command #:key user group log-file pid-file
directory (environment-variables (environ)))
"Like 'exec-command', but first restore signal handles modified by
shepherd (PID 1)."
;; First restore the default handlers.
(for-each (cut sigaction <> SIG_DFL) %precious-signals)
;; Unblock any signals that have been blocked by the parent process.
(unblock-signals %precious-signals)
(mkdir-p "/var/run")
(clean-up pid-file)
(exec-command command
#:user user
#:group group
#:log-file log-file
#:directory directory
#:environment-variables environment-variables))
(define* (make-forkexec-constructor/container command (define* (make-forkexec-constructor/container command
#:key #:key
(namespaces (namespaces
@ -164,24 +189,14 @@ (define mounts
(let ((pid (run-container container-directory (let ((pid (run-container container-directory
mounts namespaces 1 mounts namespaces 1
(lambda () (lambda ()
;; First restore the default handlers. (exec-command* command
(for-each (cut sigaction <> SIG_DFL) #:user user
%precious-signals) #:group group
#:pid-file pid-file
;; Unblock any signals that have been blocked #:log-file log-file
;; by the parent process. #:directory directory
(unblock-signals %precious-signals) #:environment-variables
environment-variables)))))
(mkdir-p "/var/run")
(clean-up pid-file)
(exec-command command
#:user user
#:group group
#:log-file log-file
#:directory directory
#:environment-variables
environment-variables)))))
(if pid-file (if pid-file
(if (or (memq 'mnt namespaces) (memq 'pid namespaces)) (if (or (memq 'mnt namespaces) (memq 'pid namespaces))
(read-pid-file/container pid pid-file (read-pid-file/container pid pid-file
@ -209,14 +224,24 @@ (define (strip-pid args)
((head . rest) ((head . rest)
(loop rest (cons head result)))))) (loop rest (cons head result))))))
(let ((container-support? (let ((container-support? (file-exists? "/proc/self/ns")))
(file-exists? "/proc/self/ns")) (if (and container-support?
(fork-proc (lambda () (not (and pid (= pid (getpid)))))
(apply fork+exec-command command (container-excursion* pid
(strip-pid args))))) (lambda ()
(if container-support? ;; Note: In the Shepherd 0.9, 'fork+exec-command' expects to be
(container-excursion* pid fork-proc) ;; called from the shepherd process (because it creates a pipe to
(fork-proc)))) ;; capture stdout/stderr and spawns a logging fiber) so we cannot
;; use it here.
(match (primitive-fork)
(0 (dynamic-wind
(const #t)
(lambda ()
(apply exec-command* command (strip-pid args)))
(lambda ()
(primitive-_exit 127))))
(pid #t))))
(apply fork+exec-command command (strip-pid args)))))
;; Local Variables: ;; Local Variables:
;; eval: (put 'container-excursion* 'scheme-indent-function 1) ;; eval: (put 'container-excursion* 'scheme-indent-function 1)