summary refs log tree commit diff
path: root/gnu/services
diff options
context:
space:
mode:
authorJakub Kądziołka <kuba@kadziolka.net>2020-04-29 11:08:42 +0200
committerJakub Kądziołka <kuba@kadziolka.net>2020-04-29 11:08:42 +0200
commit4035c3e3525599c3aa958d498c5bc789a4adffc3 (patch)
treee55a02215fcdb635d0504fc129526bfbf66abd14 /gnu/services
parent492b82bd4d592276e65c4b9bfbe1b679a00ff09f (diff)
parent4f0f46e4af0e342d84c5ad448258702029601e4b (diff)
downloadguix-4035c3e3525599c3aa958d498c5bc789a4adffc3.tar.gz
Merge branch 'master' into staging
Diffstat (limited to 'gnu/services')
-rw-r--r--gnu/services/base.scm278
-rw-r--r--gnu/services/desktop.scm23
-rw-r--r--gnu/services/docker.scm3
-rw-r--r--gnu/services/linux.scm56
-rw-r--r--gnu/services/mail.scm7
-rw-r--r--gnu/services/networking.scm119
-rw-r--r--gnu/services/sddm.scm2
-rw-r--r--gnu/services/shepherd.scm138
-rw-r--r--gnu/services/spice.scm2
-rw-r--r--gnu/services/telephony.scm4
-rw-r--r--gnu/services/virtualization.scm2
-rw-r--r--gnu/services/web.scm79
-rw-r--r--gnu/services/xorg.scm1
13 files changed, 507 insertions, 207 deletions
diff --git a/gnu/services/base.scm b/gnu/services/base.scm
index 8d9a563e2b..2913478e4a 100644
--- a/gnu/services/base.scm
+++ b/gnu/services/base.scm
@@ -12,6 +12,7 @@
 ;;; Copyright © 2019 John Soo <jsoo1@asu.edu>
 ;;; Copyright © 2019 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
 ;;; Copyright © 2020 Florian Pelz <pelzflorian@pelzflorian.de>
+;;; Copyright © 2020 Brice Waegeneire <brice@waegenei.re>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -61,11 +62,11 @@
   #:use-module (srfi srfi-26)
   #:use-module (ice-9 match)
   #:use-module (ice-9 format)
+  #:re-export (user-processes-service-type)       ;backwards compatibility
   #:export (fstab-service-type
             root-file-system-service
             file-system-service-type
             swap-service
-            user-processes-service-type
             host-name-service
             console-keymap-service
             %default-console-font
@@ -92,6 +93,7 @@
             udev-service
             udev-rule
             file->udev-rule
+            udev-rules-service
 
             login-configuration
             login-configuration?
@@ -187,128 +189,6 @@
 
 
 ;;;
-;;; User processes.
-;;;
-
-(define %do-not-kill-file
-  ;; Name of the file listing PIDs of processes that must survive when halting
-  ;; the system.  Typical example is user-space file systems.
-  "/etc/shepherd/do-not-kill")
-
-(define (user-processes-shepherd-service requirements)
-  "Return the 'user-processes' Shepherd service with dependencies on
-REQUIREMENTS (a list of service names).
-
-This is a synchronization point used to make sure user processes and daemons
-get started only after crucial initial services have been started---file
-system mounts, etc.  This is similar to the 'sysvinit' target in systemd."
-  (define grace-delay
-    ;; Delay after sending SIGTERM and before sending SIGKILL.
-    4)
-
-  (list (shepherd-service
-         (documentation "When stopped, terminate all user processes.")
-         (provision '(user-processes))
-         (requirement requirements)
-         (start #~(const #t))
-         (stop #~(lambda _
-                   (define (kill-except omit signal)
-                     ;; Kill all the processes with SIGNAL except those listed
-                     ;; in OMIT and the current process.
-                     (let ((omit (cons (getpid) omit)))
-                       (for-each (lambda (pid)
-                                   (unless (memv pid omit)
-                                     (false-if-exception
-                                      (kill pid signal))))
-                                 (processes))))
-
-                   (define omitted-pids
-                     ;; List of PIDs that must not be killed.
-                     (if (file-exists? #$%do-not-kill-file)
-                         (map string->number
-                              (call-with-input-file #$%do-not-kill-file
-                                (compose string-tokenize
-                                         (@ (ice-9 rdelim) read-string))))
-                         '()))
-
-                   (define (now)
-                     (car (gettimeofday)))
-
-                   (define (sleep* n)
-                     ;; Really sleep N seconds.
-                     ;; Work around <http://bugs.gnu.org/19581>.
-                     (define start (now))
-                     (let loop ((elapsed 0))
-                       (when (> n elapsed)
-                         (sleep (- n elapsed))
-                         (loop (- (now) start)))))
-
-                   (define lset= (@ (srfi srfi-1) lset=))
-
-                   (display "sending all processes the TERM signal\n")
-
-                   (if (null? omitted-pids)
-                       (begin
-                         ;; Easy: terminate all of them.
-                         (kill -1 SIGTERM)
-                         (sleep* #$grace-delay)
-                         (kill -1 SIGKILL))
-                       (begin
-                         ;; Kill them all except OMITTED-PIDS.  XXX: We would
-                         ;; like to (kill -1 SIGSTOP) to get a fixed list of
-                         ;; processes, like 'killall5' does, but that seems
-                         ;; unreliable.
-                         (kill-except omitted-pids SIGTERM)
-                         (sleep* #$grace-delay)
-                         (kill-except omitted-pids SIGKILL)
-                         (delete-file #$%do-not-kill-file)))
-
-                   (let wait ()
-                     ;; Reap children, if any, so that we don't end up with
-                     ;; zombies and enter an infinite loop.
-                     (let reap-children ()
-                       (define result
-                         (false-if-exception
-                          (waitpid WAIT_ANY (if (null? omitted-pids)
-                                                0
-                                                WNOHANG))))
-
-                       (when (and (pair? result)
-                                  (not (zero? (car result))))
-                         (reap-children)))
-
-                     (let ((pids (processes)))
-                       (unless (lset= = pids (cons 1 omitted-pids))
-                         (format #t "waiting for process termination\
- (processes left: ~s)~%"
-                                 pids)
-                         (sleep* 2)
-                         (wait))))
-
-                   (display "all processes have been terminated\n")
-                   #f))
-         (respawn? #f))))
-
-(define user-processes-service-type
-  (service-type
-   (name 'user-processes)
-   (extensions (list (service-extension shepherd-root-service-type
-                                        user-processes-shepherd-service)))
-   (compose concatenate)
-   (extend append)
-
-   ;; The value is the list of Shepherd services 'user-processes' depends on.
-   ;; Extensions can add new services to this list.
-   (default-value '())
-
-   (description "The @code{user-processes} service is responsible for
-terminating all the processes so that the root file system can be re-mounted
-read-only, just before rebooting/halting.  Processes still running after a few
-seconds after @code{SIGTERM} has been sent are terminated with
-@code{SIGKILL}.")))
-
-
-;;;
 ;;; File systems.
 ;;;
 
@@ -679,7 +559,7 @@ down.")))
         (documentation "Add TRNG to entropy pool.")
         (requirement '(udev))
         (provision '(trng))
-        (start #~(make-forkexec-constructor #$@rngd-command))
+        (start #~(make-forkexec-constructor '#$rngd-command))
         (stop #~(make-kill-destructor))))))
 
 (define* (rngd-service #:key
@@ -1436,10 +1316,17 @@ Service Switch}, for an example."
       (documentation "Run the syslog daemon (syslogd).")
       (provision '(syslogd))
       (requirement '(user-processes))
-      (start #~(make-forkexec-constructor
-                (list #$(syslog-configuration-syslogd config)
-                      "--rcfile" #$(syslog-configuration-config-file config))
-                #:pid-file "/var/run/syslog.pid"))
+      (start #~(let ((spawn (make-forkexec-constructor
+                             (list #$(syslog-configuration-syslogd config)
+                                   "--rcfile"
+                                   #$(syslog-configuration-config-file config))
+                             #:pid-file "/var/run/syslog.pid")))
+                 (lambda ()
+                   ;; Set the umask such that file permissions are #o640.
+                   (let ((mask (umask #o137))
+                         (pid  (spawn)))
+                     (umask mask)
+                     pid))))
       (stop #~(make-kill-destructor))))))
 
 ;; Snippet adapted from the GNU inetutils manual.
@@ -1633,6 +1520,30 @@ archive' public keys, with GUIX."
 (define %default-guix-configuration
   (guix-configuration))
 
+(define shepherd-set-http-proxy-action
+  ;; Shepherd action to change the HTTP(S) proxy.
+  (shepherd-action
+   (name 'set-http-proxy)
+   (documentation
+    "Change the HTTP(S) proxy used by 'guix-daemon' and restart it.")
+   (procedure #~(lambda* (_ #:optional proxy)
+                  (let ((environment (environ)))
+                    ;; A bit of a hack: communicate PROXY to the 'start'
+                    ;; method via environment variables.
+                    (if proxy
+                        (begin
+                          (format #t "changing HTTP/HTTPS \
+proxy of 'guix-daemon' to ~s...~%"
+                                  proxy)
+                          (setenv "http_proxy" proxy))
+                        (begin
+                          (format #t "clearing HTTP/HTTPS \
+proxy of 'guix-daemon'...~%")
+                          (unsetenv "http_proxy")))
+                    (action 'guix-daemon 'restart)
+                    (environ environment)
+                    #t)))))
+
 (define (guix-shepherd-service config)
   "Return a <shepherd-service> for the Guix daemon service with CONFIG."
   (match-record config <guix-configuration>
@@ -1644,47 +1555,58 @@ archive' public keys, with GUIX."
            (documentation "Run the Guix daemon.")
            (provision '(guix-daemon))
            (requirement '(user-processes))
+           (actions (list shepherd-set-http-proxy-action))
            (modules '((srfi srfi-1)))
            (start
-            #~(make-forkexec-constructor
-               (cons* #$(file-append guix "/bin/guix-daemon")
-                      "--build-users-group" #$build-group
-                      "--max-silent-time" #$(number->string max-silent-time)
-                      "--timeout" #$(number->string timeout)
-                      "--log-compression" #$(symbol->string log-compression)
-                      #$@(if use-substitutes?
-                             '()
-                             '("--no-substitutes"))
-                      "--substitute-urls" #$(string-join substitute-urls)
-                      #$@extra-options
-
-                      ;; Add CHROOT-DIRECTORIES and all their dependencies (if
-                      ;; these are store items) to the chroot.
-                      (append-map (lambda (file)
-                                    (append-map (lambda (directory)
-                                                  (list "--chroot-directory"
-                                                        directory))
-                                                (call-with-input-file file
-                                                  read)))
-                                  '#$(map references-file chroot-directories)))
-
-               #:environment-variables
-               (list #$@(if http-proxy
-                            (list (string-append "http_proxy=" http-proxy))
-                            '())
-                     #$@(if tmpdir
-                            (list (string-append "TMPDIR=" tmpdir))
-                            '())
-
-                     ;; Make sure we run in a UTF-8 locale so that 'guix
-                     ;; offload' correctly restores nars that contain UTF-8
-                     ;; file names such as 'nss-certs'.  See
-                     ;; <https://bugs.gnu.org/32942>.
-                     (string-append "GUIX_LOCPATH="
-                                    #$glibc-utf8-locales "/lib/locale")
-                     "LC_ALL=en_US.utf8")
-
-               #:log-file #$log-file))
+            #~(lambda _
+                (define proxy
+                  ;; HTTP/HTTPS proxy.  The 'http_proxy' variable is set by
+                  ;; the 'set-http-proxy' action.
+                  (or (getenv "http_proxy") #$http-proxy))
+
+                (fork+exec-command
+                 (cons* #$(file-append guix "/bin/guix-daemon")
+                        "--build-users-group" #$build-group
+                        "--max-silent-time" #$(number->string max-silent-time)
+                        "--timeout" #$(number->string timeout)
+                        "--log-compression" #$(symbol->string log-compression)
+                        #$@(if use-substitutes?
+                               '()
+                               '("--no-substitutes"))
+                        "--substitute-urls" #$(string-join substitute-urls)
+                        #$@extra-options
+
+                        ;; Add CHROOT-DIRECTORIES and all their dependencies
+                        ;; (if these are store items) to the chroot.
+                        (append-map (lambda (file)
+                                      (append-map (lambda (directory)
+                                                    (list "--chroot-directory"
+                                                          directory))
+                                                  (call-with-input-file file
+                                                    read)))
+                                    '#$(map references-file
+                                            chroot-directories)))
+
+                 #:environment-variables
+                 (append (list #$@(if tmpdir
+                                      (list (string-append "TMPDIR=" tmpdir))
+                                      '())
+
+                               ;; Make sure we run in a UTF-8 locale so that
+                               ;; 'guix offload' correctly restores nars that
+                               ;; contain UTF-8 file names such as
+                               ;; 'nss-certs'.  See
+                               ;; <https://bugs.gnu.org/32942>.
+                               (string-append "GUIX_LOCPATH="
+                                              #$glibc-utf8-locales
+                                              "/lib/locale")
+                               "LC_ALL=en_US.utf8")
+                         (if proxy
+                             (list (string-append "http_proxy=" proxy)
+                                   (string-append "https_proxy=" proxy))
+                             '()))
+
+                 #:log-file #$log-file)))
            (stop #~(make-kill-destructor))))))
 
 (define (guix-accounts config)
@@ -2122,6 +2044,26 @@ extra rules from the packages listed in @var{rules}."
   (service udev-service-type
            (udev-configuration (udev udev) (rules rules))))
 
+(define* (udev-rules-service name rules #:key (groups '()))
+  "Return a service that extends udev-service-type with RULES and
+account-service-type with GROUPS as system groups.  This works by creating a
+singleton service type NAME-udev-rules, of which the returned service is an
+instance."
+  (let* ((name (symbol-append name '-udev-rules))
+         (account-extension
+          (const (map (lambda (group)
+                        (user-group (name group) (system? #t)))
+                      groups)))
+         (udev-extension (const (list rules)))
+         (type (service-type
+                (name name)
+                (extensions (list
+                             (service-extension
+                              account-service-type account-extension)
+                             (service-extension
+                              udev-service-type udev-extension))))))
+    (service type #f)))
+
 (define swap-service-type
   (shepherd-service-type
    'swap
@@ -2444,6 +2386,8 @@ to handle."
         (service guix-service-type)
         (service nscd-service-type)
 
+        (service rottlog-service-type)
+
         ;; The LVM2 rules are needed as soon as LVM2 or the device-mapper is
         ;; used, so enable them by default.  The FUSE and ALSA rules are
         ;; less critical, but handy.
diff --git a/gnu/services/desktop.scm b/gnu/services/desktop.scm
index 16ee4d3537..e165d87c5f 100644
--- a/gnu/services/desktop.scm
+++ b/gnu/services/desktop.scm
@@ -10,6 +10,7 @@
 ;;; Copyright © 2017, 2019 Christopher Baines <mail@cbaines.net>
 ;;; Copyright © 2019 Tim Gesthuizen <tim.gesthuizen@yahoo.de>
 ;;; Copyright © 2019 David Wilson <david@daviwil.com>
+;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -451,8 +452,8 @@ site} for more information."
    (requirement '(dbus-system udev))
    (documentation "Run the bluetoothd daemon.")
    (start #~(make-forkexec-constructor
-             (string-append #$(bluetooth-configuration-bluez config)
-                            "/libexec/bluetooth/bluetoothd")))
+             (list #$(file-append (bluetooth-configuration-bluez config)
+                                  "/libexec/bluetooth/bluetoothd"))))
    (stop #~(make-kill-destructor))))
 
 (define bluetooth-service-type
@@ -892,7 +893,7 @@ rules.")
 (define-record-type* <gnome-desktop-configuration> gnome-desktop-configuration
   make-gnome-desktop-configuration
   gnome-desktop-configuration?
-  (gnome-package gnome-package (default gnome)))
+  (gnome gnome-package (default gnome)))
 
 (define (gnome-polkit-settings config)
   "Return the list of GNOME dependencies that provide polkit actions and
@@ -932,15 +933,23 @@ and extends polkit with the actions from @code{gnome-settings-daemon}."
   mate-desktop-configuration?
   (mate-package mate-package (default mate)))
 
+(define (mate-polkit-extension config)
+  "Return the list of packages for CONFIG's MATE package that extend polkit."
+  (let ((mate (mate-package config)))
+    (map (lambda (input)
+           ((package-direct-input-selector input) mate))
+         '("mate-system-monitor"                  ;kill, renice processes
+           "mate-settings-daemon"                 ;date/time settings
+           "mate-power-manager"                   ;modify brightness
+           "mate-control-center"                  ;RandR, display properties FIXME
+           "mate-applets"))))                     ;CPU frequency scaling
+
 (define mate-desktop-service-type
   (service-type
    (name 'mate-desktop)
    (extensions
     (list (service-extension polkit-service-type
-                             (compose list
-                                      (package-direct-input-selector
-                                       "mate-settings-daemon")
-                                      mate-package))
+                             mate-polkit-extension)
           (service-extension profile-service-type
                              (compose list
                                       mate-package))))
diff --git a/gnu/services/docker.scm b/gnu/services/docker.scm
index 04f9127346..d6dc792821 100644
--- a/gnu/services/docker.scm
+++ b/gnu/services/docker.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2018 Danny Milosavljevic <dannym@scratchpost.org>
+;;; Copyright © 2020 Jakub Kądziołka <kuba@kadziolka.net>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -94,7 +95,7 @@ loop-back communications.")
                           file-system-/sys/fs/cgroup/cpuset
                           file-system-/sys/fs/cgroup/devices
                           file-system-/sys/fs/cgroup/memory
-                          ; TODO: file-system-/sys/fs/cgroup/pids
+                          file-system-/sys/fs/cgroup/pids
                           networking
                           udev))
            (start #~(make-forkexec-constructor
diff --git a/gnu/services/linux.scm b/gnu/services/linux.scm
index caa0326c31..12934c2084 100644
--- a/gnu/services/linux.scm
+++ b/gnu/services/linux.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
+;;; Copyright © 2020 Brice Waegeneire <brice@waegenei.re>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -25,6 +26,8 @@
   #:use-module (gnu packages linux)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-26)
+  #:use-module (srfi srfi-34)
+  #:use-module (srfi srfi-35)
   #:use-module (ice-9 match)
   #:export (earlyoom-configuration
             earlyoom-configuration?
@@ -37,7 +40,9 @@
             earlyoom-configuration-ignore-positive-oom-score-adj?
             earlyoom-configuration-show-debug-messages?
             earlyoom-configuration-send-notification-command
-            earlyoom-service-type))
+            earlyoom-service-type
+
+            kernel-module-loader-service-type))
 
 
 ;;;
@@ -123,3 +128,52 @@ representation."
     (list (service-extension shepherd-root-service-type
                              (compose list earlyoom-shepherd-service))))
    (description "Run @command{earlyoom}, the Early OOM daemon.")))
+
+
+;;;
+;;; Kernel module loader.
+;;;
+
+(define kernel-module-loader-shepherd-service
+  (match-lambda
+    ((and (? list? kernel-modules) ((? string?) ...))
+     (list
+      (shepherd-service
+       (documentation "Load kernel modules.")
+       (provision '(kernel-module-loader))
+       (requirement '(file-systems))
+       (one-shot? #t)
+       (modules `((srfi srfi-1)
+                  (srfi srfi-34)
+                  (srfi srfi-35)
+                  (rnrs io ports)
+                  ,@%default-modules))
+       (start
+        #~(lambda _
+            (cond
+             ((null? '#$kernel-modules) #t)
+             ((file-exists? "/proc/sys/kernel/modprobe")
+              (let ((modprobe (call-with-input-file
+                               "/proc/sys/kernel/modprobe" get-line)))
+                (guard (c ((message-condition? c)
+                           (format (current-error-port) "~a~%"
+                                   (condition-message c))
+                           #f))
+                  (every (lambda (module)
+                         (invoke/quiet modprobe "--" module))
+                         '#$kernel-modules))))
+             (else
+               (format (current-error-port) "error: ~a~%"
+                       "Kernel is missing loadable module support.")
+               #f)))))))))
+
+(define kernel-module-loader-service-type
+  (service-type
+   (name 'kernel-module-loader)
+   (description "Load kernel modules.")
+   (extensions
+    (list (service-extension shepherd-root-service-type
+                             kernel-module-loader-shepherd-service)))
+   (compose concatenate)
+   (extend append)
+   (default-value '())))
diff --git a/gnu/services/mail.scm b/gnu/services/mail.scm
index 7791780dfc..cfcaf4601b 100644
--- a/gnu/services/mail.scm
+++ b/gnu/services/mail.scm
@@ -1544,9 +1544,10 @@ greyed out, instead of only later giving \"not selectable\" popup error.
            (start #~(make-forkexec-constructor
                      (list (string-append #$dovecot "/sbin/dovecot")
                            "-F")))
-           (stop #~(make-forkexec-constructor
-                    (list (string-append #$dovecot "/sbin/dovecot")
-                          "stop")))))))
+           (stop #~(lambda _
+                     (invoke #$(file-append dovecot "/sbin/dovecot")
+                             "stop")
+                     #f))))))
 
 (define %dovecot-pam-services
   (list (unix-pam-service "dovecot")))
diff --git a/gnu/services/networking.scm b/gnu/services/networking.scm
index 618dd95969..383b2b0d04 100644
--- a/gnu/services/networking.scm
+++ b/gnu/services/networking.scm
@@ -32,6 +32,7 @@
 (define-module (gnu services networking)
   #:use-module (gnu services)
   #:use-module (gnu services base)
+  #:use-module (gnu services configuration)
   #:use-module (gnu services shepherd)
   #:use-module (gnu services dbus)
   #:use-module (gnu system shadow)
@@ -140,6 +141,18 @@
             wpa-supplicant-configuration-extra-options
             wpa-supplicant-service-type
 
+            hostapd-configuration
+            hostapd-configuration?
+            hostapd-configuration-package
+            hostapd-configuration-interface
+            hostapd-configuration-ssid
+            hostapd-configuration-broadcast-ssid?
+            hostapd-configuration-channel
+            hostapd-configuration-driver
+            hostapd-service-type
+
+            simulated-wifi-service-type
+
             openvswitch-service-type
             openvswitch-configuration
 
@@ -1360,6 +1373,112 @@ implements authentication, key negotiation and more for wireless networks.")
 
 
 ;;;
+;;; Hostapd.
+;;;
+
+(define-record-type* <hostapd-configuration>
+  hostapd-configuration make-hostapd-configuration
+  hostapd-configuration?
+  (package           hostapd-configuration-package
+                     (default hostapd))
+  (interface         hostapd-configuration-interface ;string
+                     (default "wlan0"))
+  (ssid              hostapd-configuration-ssid)  ;string
+  (broadcast-ssid?   hostapd-configuration-broadcast-ssid? ;Boolean
+                     (default #t))
+  (channel           hostapd-configuration-channel ;integer
+                     (default 1))
+  (driver            hostapd-configuration-driver ;string
+                     (default "nl80211"))
+  ;; See <https://w1.fi/cgit/hostap/plain/hostapd/hostapd.conf> for a list of
+  ;; additional options we could add.
+  (extra-settings    hostapd-configuration-extra-settings ;string
+                     (default "")))
+
+(define (hostapd-configuration-file config)
+  "Return the configuration file for CONFIG, a <hostapd-configuration>."
+  (match-record config <hostapd-configuration>
+    (interface ssid broadcast-ssid? channel driver extra-settings)
+    (plain-file "hostapd.conf"
+                (string-append "\
+# Generated from your Guix configuration.
+
+interface=" interface "
+ssid=" ssid "
+ignore_broadcast_ssid=" (if broadcast-ssid? "0" "1") "
+channel=" (number->string channel) "\n"
+extra-settings "\n"))))
+
+(define* (hostapd-shepherd-services config #:key (requirement '()))
+  "Return Shepherd services for hostapd."
+  (list (shepherd-service
+         (provision '(hostapd))
+         (requirement `(user-processes ,@requirement))
+         (documentation "Run the hostapd WiFi access point daemon.")
+         (start #~(make-forkexec-constructor
+                   (list #$(file-append hostapd "/sbin/hostapd")
+                         #$(hostapd-configuration-file config))
+                   #:log-file "/var/log/hostapd.log"))
+         (stop #~(make-kill-destructor)))))
+
+(define hostapd-service-type
+  (service-type
+   (name 'hostapd)
+   (extensions
+    (list (service-extension shepherd-root-service-type
+                             hostapd-shepherd-services)))
+   (description
+    "Run the @uref{https://w1.fi/hostapd/, hostapd} daemon for Wi-Fi access
+points and authentication servers.")))
+
+(define (simulated-wifi-shepherd-services config)
+  "Return Shepherd services to run hostapd with CONFIG, a
+<hostapd-configuration>, as well as services to set up WiFi hardware
+simulation."
+  (append (hostapd-shepherd-services config
+                                     #:requirement
+                                     '(unblocked-wifi
+                                       mac-simulation-module))
+          (list (shepherd-service
+                 (provision '(unblocked-wifi))
+                 (requirement '(file-systems mac-simulation-module))
+                 (documentation
+                  "Unblock WiFi devices for use by mac80211_hwsim.")
+                 (start #~(lambda _
+                            (invoke #$(file-append util-linux "/sbin/rfkill")
+                                    "unblock" "0")
+                            (invoke #$(file-append util-linux "/sbin/rfkill")
+                                    "unblock" "1")))
+                 (one-shot? #t))
+                (shepherd-service
+                 (provision '(mac-simulation-module))
+                 (requirement '(file-systems))
+                 (modules '((guix build utils)))
+                 (documentation
+                  "Load the mac80211_hwsim Linux kernel module.")
+                 (start (with-imported-modules '((guix build utils))
+                          #~(lambda _
+                              ;; XXX: We can't use 'load-linux-module*' here because it
+                              ;; expects a flat module directory.
+                              (setenv "LINUX_MODULE_DIRECTORY"
+                                      "/run/booted-system/kernel/lib/modules")
+                              (invoke #$(file-append kmod "/bin/modprobe")
+                                      "mac80211_hwsim"))))
+                 (one-shot? #t)))))
+
+(define simulated-wifi-service-type
+  (service-type
+   (name 'simulated-wifi)
+   (extensions
+    (list (service-extension shepherd-root-service-type
+                             simulated-wifi-shepherd-services)))
+   (default-value (hostapd-configuration
+                   (interface "wlan1")
+                   (ssid "Test Network")))
+   (description "Run hostapd to simulate WiFi connectivity.")))
+
+
+;;;
 ;;; Open vSwitch
 ;;;
 
diff --git a/gnu/services/sddm.scm b/gnu/services/sddm.scm
index 1921afce95..59f8b16985 100644
--- a/gnu/services/sddm.scm
+++ b/gnu/services/sddm.scm
@@ -170,7 +170,7 @@ Relogin="              (if (sddm-configuration-relogin? config)
   (list (shepherd-service
          (documentation "SDDM display manager.")
          (requirement '(user-processes))
-         (provision '(display-manager))
+         (provision '(xorg-server display-manager))
          (start #~(make-forkexec-constructor #$sddm-command))
          (stop #~(make-kill-destructor)))))
 
diff --git a/gnu/services/shepherd.scm b/gnu/services/shepherd.scm
index d483ff1a15..2f30c6c907 100644
--- a/gnu/services/shepherd.scm
+++ b/gnu/services/shepherd.scm
@@ -63,7 +63,9 @@
 
             shepherd-service-lookup-procedure
             shepherd-service-back-edges
-            shepherd-service-upgrade))
+            shepherd-service-upgrade
+
+            user-processes-service-type))
 
 ;;; Commentary:
 ;;;
@@ -269,7 +271,11 @@ and return the resulting '.go' file."
                          (module-use! env (resolve-interface '(oop goops)))
                          (module-use! env (resolve-interface '(shepherd service)))
                          (compile-file #$file #:output-file #$output
-                                       #:env env))))))
+                                       #:env env)))
+
+                   ;; It's faster to build locally than to download.
+                   #:options '(#:local-build? #t
+                               #:substitutable? #f))))
 
 (define (shepherd-configuration-file services)
   "Return the shepherd configuration file for SERVICES."
@@ -287,6 +293,12 @@ and return the resulting '.go' file."
           (default-environment-variables
             '("PATH=/run/current-system/profile/bin"))
 
+          ;; Booting off a DVD, especially on a slow machine, can make
+          ;; everything slow.  Thus, increase the timeout compared to the
+          ;; default 5s in the Shepherd 0.7.0.  See
+          ;; <https://bugs.gnu.org/40572>.
+          (default-pid-file-timeout 30)
+
           ;; Arrange to spawn a REPL if something goes wrong.  This is better
           ;; than a kernel panic.
           (call-with-error-handling
@@ -404,4 +416,126 @@ need to be restarted to complete their upgrade."
 
   (values to-unload to-restart))
 
+
+;;;
+;;; User processes.
+;;;
+
+(define %do-not-kill-file
+  ;; Name of the file listing PIDs of processes that must survive when halting
+  ;; the system.  Typical example is user-space file systems.
+  "/etc/shepherd/do-not-kill")
+
+(define (user-processes-shepherd-service requirements)
+  "Return the 'user-processes' Shepherd service with dependencies on
+REQUIREMENTS (a list of service names).
+
+This is a synchronization point used to make sure user processes and daemons
+get started only after crucial initial services have been started---file
+system mounts, etc.  This is similar to the 'sysvinit' target in systemd."
+  (define grace-delay
+    ;; Delay after sending SIGTERM and before sending SIGKILL.
+    4)
+
+  (list (shepherd-service
+         (documentation "When stopped, terminate all user processes.")
+         (provision '(user-processes))
+         (requirement requirements)
+         (start #~(const #t))
+         (stop #~(lambda _
+                   (define (kill-except omit signal)
+                     ;; Kill all the processes with SIGNAL except those listed
+                     ;; in OMIT and the current process.
+                     (let ((omit (cons (getpid) omit)))
+                       (for-each (lambda (pid)
+                                   (unless (memv pid omit)
+                                     (false-if-exception
+                                      (kill pid signal))))
+                                 (processes))))
+
+                   (define omitted-pids
+                     ;; List of PIDs that must not be killed.
+                     (if (file-exists? #$%do-not-kill-file)
+                         (map string->number
+                              (call-with-input-file #$%do-not-kill-file
+                                (compose string-tokenize
+                                         (@ (ice-9 rdelim) read-string))))
+                         '()))
+
+                   (define (now)
+                     (car (gettimeofday)))
+
+                   (define (sleep* n)
+                     ;; Really sleep N seconds.
+                     ;; Work around <http://bugs.gnu.org/19581>.
+                     (define start (now))
+                     (let loop ((elapsed 0))
+                       (when (> n elapsed)
+                         (sleep (- n elapsed))
+                         (loop (- (now) start)))))
+
+                   (define lset= (@ (srfi srfi-1) lset=))
+
+                   (display "sending all processes the TERM signal\n")
+
+                   (if (null? omitted-pids)
+                       (begin
+                         ;; Easy: terminate all of them.
+                         (kill -1 SIGTERM)
+                         (sleep* #$grace-delay)
+                         (kill -1 SIGKILL))
+                       (begin
+                         ;; Kill them all except OMITTED-PIDS.  XXX: We would
+                         ;; like to (kill -1 SIGSTOP) to get a fixed list of
+                         ;; processes, like 'killall5' does, but that seems
+                         ;; unreliable.
+                         (kill-except omitted-pids SIGTERM)
+                         (sleep* #$grace-delay)
+                         (kill-except omitted-pids SIGKILL)
+                         (delete-file #$%do-not-kill-file)))
+
+                   (let wait ()
+                     ;; Reap children, if any, so that we don't end up with
+                     ;; zombies and enter an infinite loop.
+                     (let reap-children ()
+                       (define result
+                         (false-if-exception
+                          (waitpid WAIT_ANY (if (null? omitted-pids)
+                                                0
+                                                WNOHANG))))
+
+                       (when (and (pair? result)
+                                  (not (zero? (car result))))
+                         (reap-children)))
+
+                     (let ((pids (processes)))
+                       (unless (lset= = pids (cons 1 omitted-pids))
+                         (format #t "waiting for process termination\
+ (processes left: ~s)~%"
+                                 pids)
+                         (sleep* 2)
+                         (wait))))
+
+                   (display "all processes have been terminated\n")
+                   #f))
+         (respawn? #f))))
+
+(define user-processes-service-type
+  (service-type
+   (name 'user-processes)
+   (extensions (list (service-extension shepherd-root-service-type
+                                        user-processes-shepherd-service)))
+   (compose concatenate)
+   (extend append)
+
+   ;; The value is the list of Shepherd services 'user-processes' depends on.
+   ;; Extensions can add new services to this list.
+   (default-value '())
+
+   (description "The @code{user-processes} service is responsible for
+terminating all the processes so that the root file system can be re-mounted
+read-only, just before rebooting/halting.  Processes still running after a few
+seconds after @code{SIGTERM} has been sent are terminated with
+@code{SIGKILL}.")))
+
 ;;; shepherd.scm ends here
diff --git a/gnu/services/spice.scm b/gnu/services/spice.scm
index 8a835fe78e..fd85dc234f 100644
--- a/gnu/services/spice.scm
+++ b/gnu/services/spice.scm
@@ -54,7 +54,7 @@
       (documentation "Spice vdagentd service")
       (requirement '(udev))
       (provision '(spice-vdagentd))
-      (start #~(make-forkexec-constructor #$@spice-vdagentd-command))
+      (start #~(make-forkexec-constructor '#$spice-vdagentd-command))
       (stop #~(make-kill-destructor)))))
 
 (define spice-vdagent-profile
diff --git a/gnu/services/telephony.scm b/gnu/services/telephony.scm
index 0a735315b4..e1259cc2df 100644
--- a/gnu/services/telephony.scm
+++ b/gnu/services/telephony.scm
@@ -182,7 +182,9 @@
            "welcometext=" welcome-text "\n"
            "port=" (number->string port) "\n"
            (if server-password (list "serverpassword=" server-password "\n") '())
-           (if max-user-bandwidth (list "bandwidth=" (number->string max-user-bandwidth)) '())
+           (if max-user-bandwidth (list "bandwidth="
+                                        (number->string max-user-bandwidth) "\n")
+               '())
            "users=" (number->string max-users) "\n"
            "uname=" user "\n"
            "database=" database-file "\n"
diff --git a/gnu/services/virtualization.scm b/gnu/services/virtualization.scm
index d473c5342e..989e439d5d 100644
--- a/gnu/services/virtualization.scm
+++ b/gnu/services/virtualization.scm
@@ -285,7 +285,7 @@ and max_workers parameter.")
     (string "3:remote 4:event")
     "Logging filters.
 
-A filter allows to select a different logging level for a given category
+A filter allows selecting a different logging level for a given category
 of logs
 The format for a filter is one of:
 @itemize
diff --git a/gnu/services/web.scm b/gnu/services/web.scm
index fa5c34d5af..dcbe6ee16f 100644
--- a/gnu/services/web.scm
+++ b/gnu/services/web.scm
@@ -9,7 +9,7 @@
 ;;; Copyright © 2018 Pierre-Antoine Rouby <pierre-antoine.rouby@inria.fr>
 ;;; Copyright © 2017, 2018, 2019 Christopher Baines <mail@cbaines.net>
 ;;; Copyright © 2018 Marius Bakke <mbakke@fastmail.com>
-;;; Copyright © 2019 Florian Pelz <pelzflorian@pelzflorian.de>
+;;; Copyright © 2019, 2020 Florian Pelz <pelzflorian@pelzflorian.de>
 ;;; Copyright © 2020 Ricardo Wurmus <rekado@elephly.net>
 ;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr>
 ;;;
@@ -262,6 +262,14 @@
             patchwork-virtualhost
             patchwork-service-type
 
+            <mumi-configuration>
+            mumi-configuration
+            mumi-configuration?
+            mumi-configuration-mumi
+            mumi-configuration-mailer?
+            mumi-configuration-sender
+            mumi-configuration-smtp
+
             mumi-service-type))
 
 ;;; Commentary:
@@ -644,8 +652,8 @@ of index files."
            "user nginx nginx;\n"
            "pid " run-directory "/pid;\n"
            "error_log " log-directory "/error.log info;\n"
-           (map emit-global-directive global-directives)
            (map emit-load-module modules)
+           (map emit-global-directive global-directives)
            "http {\n"
            "    client_body_temp_path " run-directory "/client_body_temp;\n"
            "    proxy_temp_path " run-directory "/proxy_temp;\n"
@@ -1678,6 +1686,14 @@ WSGIPassAuthorization On
 ;;; Mumi.
 ;;;
 
+(define-record-type* <mumi-configuration>
+  mumi-configuration make-mumi-configuration
+  mumi-configuration?
+  (mumi    mumi-configuration-mumi (default mumi))
+  (mailer? mumi-configuration-mailer? (default #t))
+  (sender  mumi-configuration-sender (default #f))
+  (smtp    mumi-configuration-smtp (default #f)))
+
 (define %mumi-activation
   (with-imported-modules '((guix build utils))
     #~(begin
@@ -1702,25 +1718,43 @@ WSGIPassAuthorization On
          (home-directory "/var/empty")
          (shell (file-append shadow "/sbin/nologin")))))
 
-(define (mumi-shepherd-services mumi)
-  (list (shepherd-service
-         (provision '(mumi))
-         (documentation "Mumi bug-tracking web interface.")
-         (requirement '(networking))
-         (start #~(make-forkexec-constructor
-                   '(#$(file-append mumi "/bin/mumi"))
-                   #:user "mumi" #:group "mumi"
-                   #:log-file "/var/log/mumi.log"))
-         (stop #~(make-kill-destructor)))
-        (shepherd-service
-         (provision '(mumi-worker))
-         (documentation "Mumi bug-tracking web interface.")
-         (requirement '(networking))
-         (start #~(make-forkexec-constructor
-                   '(#$(file-append mumi "/bin/mumi") "--worker")
-                   #:user "mumi" #:group "mumi"
-                   #:log-file "/var/log/mumi.worker.log"))
-         (stop #~(make-kill-destructor)))))
+(define (mumi-shepherd-services config)
+  (match config
+    (($ <mumi-configuration> mumi mailer? sender smtp)
+     (list (shepherd-service
+            (provision '(mumi))
+            (documentation "Mumi bug-tracking web interface.")
+            (requirement '(networking))
+            (start #~(make-forkexec-constructor
+                      `(#$(file-append mumi "/bin/mumi") "web"
+                        ,@(if #$mailer? '() '("--disable-mailer")))
+                      #:user "mumi" #:group "mumi"
+                      #:log-file "/var/log/mumi.log"))
+            (stop #~(make-kill-destructor)))
+           (shepherd-service
+            (provision '(mumi-worker))
+            (documentation "Mumi bug-tracking web interface database worker.")
+            (requirement '(networking))
+            (start #~(make-forkexec-constructor
+                      '(#$(file-append mumi "/bin/mumi") "worker")
+                      #:user "mumi" #:group "mumi"
+                      #:log-file "/var/log/mumi.worker.log"))
+            (stop #~(make-kill-destructor)))
+           (shepherd-service
+            (provision '(mumi-mailer))
+            (documentation "Mumi bug-tracking web interface mailer.")
+            (requirement '(networking))
+            (start #~(make-forkexec-constructor
+                      `(#$(file-append mumi "/bin/mumi") "mailer"
+                        ,@(if #$sender
+                              (list (string-append "--sender=" #$sender))
+                              '())
+                        ,@(if #$smtp
+                              (list (string-append "--smtp=" #$smtp))
+                              '()))
+                      #:user "mumi" #:group "mumi"
+                      #:log-file "/var/log/mumi.mailer.log"))
+            (stop #~(make-kill-destructor)))))))
 
 (define mumi-service-type
   (service-type
@@ -1734,4 +1768,5 @@ WSGIPassAuthorization On
                              mumi-shepherd-services)))
    (description
     "Run Mumi, a Web interface to the Debbugs bug-tracking server.")
-   (default-value mumi)))
+   (default-value
+     (mumi-configuration))))
diff --git a/gnu/services/xorg.scm b/gnu/services/xorg.scm
index 09379d40c3..d0196a299e 100644
--- a/gnu/services/xorg.scm
+++ b/gnu/services/xorg.scm
@@ -798,6 +798,7 @@ the GNOME desktop environment.")
         (user-account
          (name "gdm")
          (group "gdm")
+         (supplementary-groups '("video"))
          (system? #t)
          (comment "GNOME Display Manager user")
          (home-directory "/var/lib/gdm")