civodul pushed a commit to branch main
in repository shepherd.

commit 4d8161fbede998ad813cbecd317c27b38f400253
Author: Ludovic Courtès <[email protected]>
AuthorDate: Sun Apr 13 11:52:41 2025 +0200

    shepherd: Open the socket before starting the root service.
    
    * modules/shepherd.scm (call-with-server-socket): Remove call to
    ‘stop-service’.  Call ‘exit’ on failure.
    (run-daemon): Replace #:socket-file with #:socket and remove call to
    ‘call-with-server-socket’.
    (main): Wrap body in ‘call-with-server-socket’.
    * tests/basic.sh: Test it.
---
 modules/shepherd.scm | 273 +++++++++++++++++++++++++--------------------------
 tests/basic.sh       |   4 +-
 2 files changed, 138 insertions(+), 139 deletions(-)

diff --git a/modules/shepherd.scm b/modules/shepherd.scm
index 68e402b..a1bfebb 100644
--- a/modules/shepherd.scm
+++ b/modules/shepherd.scm
@@ -62,16 +62,13 @@ socket file at FILE-NAME upon exit of PROC.  Return the 
values of PROC."
                      (report-error (l10n "while opening socket '~a': ~a: ~a")
                                    file-name proc
                                    (strerror (system-error-errno args)))
-                     ;; Stop services that were started from the config file
-                     ;; and quit.
-                     (stop-service root-service)))))))
-    (and sock
-         (catch #t
-           (lambda ()
-             (proc sock))
-           (lambda args
-             (close sock)
-             (apply throw args))))))
+                     (exit 1)))))))
+    (catch #t
+      (lambda ()
+        (proc sock))
+      (lambda args
+        (close sock)
+        (apply throw args)))))
 
 (define (maybe-signal-port signals)
   "Return a signal port for SIGNALS, using 'signalfd' on GNU/Linux, or #f if
@@ -213,7 +210,7 @@ configuration file '~a': ~s")
                                      (const 'timeout)))))
 
 (define* (run-daemon #:key (config-file (default-config-file))
-                     socket-file pid-file signal-port poll-services?)
+                     socket pid-file signal-port poll-services?)
   (define (signal-thunk signal-port)
     ;; Thunk that waits for signals (particularly SIGCHLD) and handles them.
     (if signal-port
@@ -286,36 +283,33 @@ configuration file '~a': ~s")
   ;; prematurely.
   (sigaction SIGPIPE SIG_IGN)
 
-  (if (not socket-file)
+  (if (not socket)
       ;; Get commands from the standard input port.
       (process-textual-commands (current-input-port))
       ;; Process the data arriving at a socket.
-      (call-with-server-socket
-       socket-file
-       (lambda (sock)
-
-         ;; Possibly write out our PID, which means we're ready to accept
-         ;; connections.  XXX: What if we daemonized already?
-         (match pid-file
-           ((? string? file)
-            (with-atomic-file-output pid-file
-              (cute display (getpid) <>)))
-           (#t (display (getpid)))
-           (_  #t))
-
-         ;; Enter some sort of a REPL for commands.
-         (let next-command ()
-           (match (accept sock (logior SOCK_NONBLOCK SOCK_CLOEXEC))
-             ((command-source . client-address)
-              (setvbuf command-source 'block 1024)
-              (set-port-encoding! command-source "UTF-8")
-              (set-port-conversion-strategy! command-source 'error)
-              (spawn-fiber
-               (lambda ()
-                 (process-connection command-source))))
-             (_ #f))
-
-           (next-command))))))
+      (begin
+        ;; Possibly write out our PID, which means we're ready to accept
+        ;; connections.
+        (match pid-file
+          ((? string? file)
+           (with-atomic-file-output pid-file
+             (cute display (getpid) <>)))
+          (#t (display (getpid)))
+          (_  #t))
+
+        ;; Enter some sort of a REPL for commands.
+        (let next-command ()
+          (match (accept socket (logior SOCK_NONBLOCK SOCK_CLOEXEC))
+            ((command-source . client-address)
+             (setvbuf command-source 'block 1024)
+             (set-port-encoding! command-source "UTF-8")
+             (set-port-conversion-strategy! command-source 'error)
+             (spawn-fiber
+              (lambda ()
+                (process-connection command-source))))
+            (_ #f))
+
+          (next-command)))))
 
 ;; In Guile 3.0.x, 'call-with-input-file' & co. do not open their files as
 ;; O_CLOEXEC.  The two procedures below address that.
@@ -497,107 +491,110 @@ fork in the child process."
     (unless (getenv "GUILE_WARN_DEPRECATED")
       (debug-enable 'warn-deprecated))
 
-    ;; Enable logging as first action.
-    (parameterize ((log-output-port (cdr log-input+output))
-
-                   ;; Send warnings such as deprecation warnings to the log.
-                   (current-warning-port (cdr log-input+output))
-
-                   (%current-logfile-date-format
-                    (if syslog?
-                        ""                        ;for the "built-in" logger
-                        default-logfile-date-format))
-                   (%current-service-output-port
-                    ;; Send output to log and clients.
-                    (make-shepherd-output-port
-                     (if (or silent? syslog?)
-                         ;; By default we'd write both to /dev/log and to
-                         ;; stdout.  Redirect stdout to the bitbucket so we
-                         ;; don't log twice.
-                         (%make-void-port "w")
-                         (current-output-port))))
-
-                   ;; In Guile 3.0.10, calling 'environ' from the top-level
-                   ;; triggers a warning so do it from here.
-                   (default-environment-variables (environ)))
-
-      (parameterize ((current-output-port (%current-service-output-port)))
-        (set-port-encoding! (log-output-port) "UTF-8")
-        (set-port-encoding! (%current-service-output-port) "UTF-8")
-
-        ;; Log provenance info.
-        (format #t "~a ~a (Guile ~a, ~a)~%"
-                package-name Version
-                (version) %host-type)
-
-        (when (= 1 (getpid))
-          ;; When running as PID 1, disable hard reboots upon ctrl-alt-del.
-          ;; Instead, the kernel will send us SIGINT so that we can gracefully
-          ;; shut down.  See ctrlaltdel(8) and kernel/reboot.c.
-          (catch 'system-error
+    (call-with-server-socket
+     socket-file
+     (lambda (socket)
+       ;; Enable logging as first action.
+       (parameterize ((log-output-port (cdr log-input+output))
+
+                      ;; Send warnings such as deprecation warnings to the log.
+                      (current-warning-port (cdr log-input+output))
+
+                      (%current-logfile-date-format
+                       (if syslog?
+                           ""                     ;for the "built-in" logger
+                           default-logfile-date-format))
+                      (%current-service-output-port
+                       ;; Send output to log and clients.
+                       (make-shepherd-output-port
+                        (if (or silent? syslog?)
+                            ;; By default we'd write both to /dev/log and to
+                            ;; stdout.  Redirect stdout to the bitbucket so we
+                            ;; don't log twice.
+                            (%make-void-port "w")
+                            (current-output-port))))
+
+                      ;; In Guile 3.0.10, calling 'environ' from the top-level
+                      ;; triggers a warning so do it from here.
+                      (default-environment-variables (environ)))
+
+         (parameterize ((current-output-port (%current-service-output-port)))
+           (set-port-encoding! (log-output-port) "UTF-8")
+           (set-port-encoding! (%current-service-output-port) "UTF-8")
+
+           ;; Log provenance info.
+           (format #t "~a ~a (Guile ~a, ~a)~%"
+                   package-name Version
+                   (version) %host-type)
+
+           (when (= 1 (getpid))
+             ;; When running as PID 1, disable hard reboots upon ctrl-alt-del.
+             ;; Instead, the kernel will send us SIGINT so that we can 
gracefully
+             ;; shut down.  See ctrlaltdel(8) and kernel/reboot.c.
+             (catch 'system-error
+               (lambda ()
+                 (disable-reboot-on-ctrl-alt-del))
+               (lambda args
+                 (let ((err (system-error-errno args)))
+                   ;; When in a separate PID namespace, we get EINVAL (see
+                   ;; 'reboot_pid_ns' in kernel/pid_namespace.c.)  We get 
EPERM in
+                   ;; a user namespace that lacks CAP_SYS_BOOT.
+                   ;; ENOSYS is returned in runc environments due to seccomp
+                   ;; defaults: 
<https://github.com/opencontainers/runc/pull/2750>.
+                   (unless (member err (list EINVAL EPERM ENOSYS))
+                     (apply throw args)))))
+
+             ;; Load the SIGSEGV/SIGABRT handler.  This is what allows PID 1 to
+             ;; dump core on "/", should something go wrong.
+             (false-if-exception
+              (dynamic-link (string-append %pkglibdir "/crash-handler"))))
+
+           ;; Run Fibers in such a way that it does not create any POSIX 
thread,
+           ;; because POSIX threads and 'fork' cannot be used together.
+           (run-fibers
             (lambda ()
-              (disable-reboot-on-ctrl-alt-del))
-            (lambda args
-              (let ((err (system-error-errno args)))
-                ;; When in a separate PID namespace, we get EINVAL (see
-                ;; 'reboot_pid_ns' in kernel/pid_namespace.c.)  We get EPERM in
-                ;; a user namespace that lacks CAP_SYS_BOOT.
-                ;; ENOSYS is returned in runc environments due to seccomp
-                ;; defaults: 
<https://github.com/opencontainers/runc/pull/2750>.
-                (unless (member err (list EINVAL EPERM ENOSYS))
-                  (apply throw args)))))
-
-          ;; Load the SIGSEGV/SIGABRT handler.  This is what allows PID 1 to
-          ;; dump core on "/", should something go wrong.
-          (false-if-exception
-           (dynamic-link (string-append %pkglibdir "/crash-handler"))))
-
-        ;; Run Fibers in such a way that it does not create any POSIX thread,
-        ;; because POSIX threads and 'fork' cannot be used together.
-        (run-fibers
-         (lambda ()
-           (with-process-monitor
-             (with-service-registry
-
-               ;; Register and start the 'root' service.
-               (register-services (list root-service))
-               (start-service root-service)
-
-               (if syslog?
-                   (spawn-service-system-logger (car log-input+output)
-                                                #:service root-service)
-                   (spawn-service-file-logger (or logfile
-                                                  (if (= 1 (getpid))
-                                                      (system-default-log-file)
-                                                      (user-default-log-file)))
-                                              (car log-input+output)
-                                              #:service root-service))
-
-               ;; Replace the default 'system*' binding with one that
-               ;; cooperates instead of blocking on 'waitpid'.  Replace
-               ;; 'primitive-load' (in C as of 3.0.9) with one that does
-               ;; not introduce a continuation barrier.  Replace 'sleep' to
-               ;; avoid blocking in user code such as 'start' methods.
-               (replace-core-bindings!
-                (newline (lambda* (#:optional (port (current-output-port)))
-                           ;; As of Guile 3.0.10, 'newline' is written in C
-                           ;; and thus a continuation barrier.  Replace it.
-                           (put-char port #\newline)))
-                (system* (lambda command
-                           (spawn-command command #:directory (getcwd))))
-                (system spawn-shell-command)
-                (primitive-load primitive-load*)
-                (call-with-input-file call-with-input-file/close-on-exec)
-                (call-with-output-file call-with-output-file/close-on-exec)
-                ((@ (guile) sleep) (@ (fibers) sleep)))
-
-               (run-daemon #:socket-file socket-file
-                           #:config-file (or config-file (default-config-file))
-                           #:pid-file pid-file
-                           #:signal-port signal-port
-                           #:poll-services? poll-services?))))
-         #:parallelism 1                          ;don't create POSIX threads
-         #:hz 0)))))       ;disable preemption, which would require POSIX 
threads
+              (with-process-monitor
+                (with-service-registry
+
+                  ;; Register and start the 'root' service.
+                  (register-services (list root-service))
+                  (start-service root-service)
+
+                  (if syslog?
+                      (spawn-service-system-logger (car log-input+output)
+                                                   #:service root-service)
+                      (spawn-service-file-logger (or logfile
+                                                     (if (= 1 (getpid))
+                                                         
(system-default-log-file)
+                                                         
(user-default-log-file)))
+                                                 (car log-input+output)
+                                                 #:service root-service))
+
+                  ;; Replace the default 'system*' binding with one that
+                  ;; cooperates instead of blocking on 'waitpid'.  Replace
+                  ;; 'primitive-load' (in C as of 3.0.9) with one that does
+                  ;; not introduce a continuation barrier.  Replace 'sleep' to
+                  ;; avoid blocking in user code such as 'start' methods.
+                  (replace-core-bindings!
+                   (newline (lambda* (#:optional (port (current-output-port)))
+                              ;; As of Guile 3.0.10, 'newline' is written in C
+                              ;; and thus a continuation barrier.  Replace it.
+                              (put-char port #\newline)))
+                   (system* (lambda command
+                              (spawn-command command #:directory (getcwd))))
+                   (system spawn-shell-command)
+                   (primitive-load primitive-load*)
+                   (call-with-input-file call-with-input-file/close-on-exec)
+                   (call-with-output-file call-with-output-file/close-on-exec)
+                   ((@ (guile) sleep) (@ (fibers) sleep)))
+
+                  (run-daemon #:socket socket
+                              #:config-file (or config-file 
(default-config-file))
+                              #:pid-file pid-file
+                              #:signal-port signal-port
+                              #:poll-services? poll-services?))))
+            #:parallelism 1                       ;don't create POSIX threads
+            #:hz 0)))))))       ;disable preemption, which would require POSIX 
threads
 
 (define* (quit-exception-handler key #:optional value)
   "Handle the 'quit' exception, rebooting if we're running as root."
diff --git a/tests/basic.sh b/tests/basic.sh
index 69b3a83..2214e78 100644
--- a/tests/basic.sh
+++ b/tests/basic.sh
@@ -1,5 +1,5 @@
 # GNU Shepherd --- Test basic communication capabilities.
-# Copyright © 2013-2014, 2016-2019, 2022-2024 Ludovic Courtès <[email protected]>
+# Copyright © 2013-2014, 2016-2019, 2022-2025 Ludovic Courtès <[email protected]>
 # Copyright © 2016 Mathieu Lirzin <[email protected]>
 # Copyright © 2014 Alex Sassmannshausen <[email protected]>
 #
@@ -74,6 +74,8 @@ cat > "$conf"<<EOF
         #:respawn? #f)))
 EOF
 
+shepherd -I -s /does/not/exist/sock -c "$conf" && false
+
 rm -f "$pid"
 shepherd -I -s "$socket" -c "$conf" -l "$log" --pid="$pid" &
 

Reply via email to