29a3722f1b5de15793599f03e9f420e83383ea1d
[jackhill/guix/guix.git] / gnu / services / desktop.scm
1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2014-2022 Ludovic Courtès <ludo@gnu.org>
3 ;;; Copyright © 2015 Andy Wingo <wingo@igalia.com>
4 ;;; Copyright © 2015 Mark H Weaver <mhw@netris.org>
5 ;;; Copyright © 2016 Sou Bunnbu <iyzsong@gmail.com>
6 ;;; Copyright © 2017, 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
7 ;;; Copyright © 2017 Nikita <nikita@n0.is>
8 ;;; Copyright © 2018, 2020 Efraim Flashner <efraim@flashner.co.il>
9 ;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
10 ;;; Copyright © 2017, 2019 Christopher Baines <mail@cbaines.net>
11 ;;; Copyright © 2019 Tim Gesthuizen <tim.gesthuizen@yahoo.de>
12 ;;; Copyright © 2019 David Wilson <david@daviwil.com>
13 ;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr>
14 ;;; Copyright © 2020 Reza Alizadeh Majd <r.majd@pantherx.org>
15 ;;; Copyright © 2021 Brice Waegeneire <brice@waegenei.re>
16 ;;; Copyright © 2021 muradm <mail@muradm.net>
17 ;;;
18 ;;; This file is part of GNU Guix.
19 ;;;
20 ;;; GNU Guix is free software; you can redistribute it and/or modify it
21 ;;; under the terms of the GNU General Public License as published by
22 ;;; the Free Software Foundation; either version 3 of the License, or (at
23 ;;; your option) any later version.
24 ;;;
25 ;;; GNU Guix is distributed in the hope that it will be useful, but
26 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
27 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 ;;; GNU General Public License for more details.
29 ;;;
30 ;;; You should have received a copy of the GNU General Public License
31 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
32
33 (define-module (gnu services desktop)
34 #:use-module (gnu services)
35 #:use-module (gnu services shepherd)
36 #:use-module (gnu services base)
37 #:use-module (gnu services dbus)
38 #:use-module (gnu services avahi)
39 #:use-module (gnu services xorg)
40 #:use-module (gnu services networking)
41 #:use-module (gnu services sound)
42 #:use-module ((gnu system file-systems)
43 #:select (%control-groups
44 %elogind-file-systems
45 file-system))
46 #:autoload (gnu services sddm) (sddm-service-type)
47 #:use-module (gnu system)
48 #:use-module (gnu system setuid)
49 #:use-module (gnu system shadow)
50 #:use-module (gnu system uuid)
51 #:use-module (gnu system pam)
52 #:use-module (gnu packages glib)
53 #:use-module (gnu packages admin)
54 #:use-module (gnu packages cups)
55 #:use-module (gnu packages freedesktop)
56 #:use-module (gnu packages gnome)
57 #:use-module (gnu packages xfce)
58 #:use-module (gnu packages avahi)
59 #:use-module (gnu packages xdisorg)
60 #:use-module (gnu packages scanner)
61 #:use-module (gnu packages suckless)
62 #:use-module (gnu packages linux)
63 #:use-module (gnu packages libusb)
64 #:use-module (gnu packages lxqt)
65 #:use-module (gnu packages mate)
66 #:use-module (gnu packages nfs)
67 #:use-module (gnu packages enlightenment)
68 #:use-module (guix deprecation)
69 #:use-module (guix records)
70 #:use-module (guix packages)
71 #:use-module (guix store)
72 #:use-module (guix utils)
73 #:use-module (guix gexp)
74 #:use-module (srfi srfi-1)
75 #:use-module (ice-9 format)
76 #:use-module (ice-9 match)
77 #:export (<upower-configuration>
78 upower-configuration
79 upower-configuration?
80 upower-configuration-upower
81 upower-configuration-watts-up-pro?
82 upower-configuration-poll-batteries?
83 upower-configuration-ignore-lid?
84 upower-configuration-use-percentage-for-policy?
85 upower-configuration-percentage-low
86 upower-configuration-percentage-critical
87 upower-configuration-percentage-action
88 upower-configuration-time-low
89 upower-configuration-time-critical
90 upower-configuration-time-action
91 upower-configuration-critical-power-action
92
93 upower-service-type
94
95 udisks-configuration
96 udisks-configuration?
97 udisks-service
98 udisks-service-type
99
100 colord-service-type
101
102 geoclue-application
103 geoclue-configuration
104 geoclue-configuration?
105 %standard-geoclue-applications
106 geoclue-service
107 geoclue-service-type
108
109 bluetooth-service-type
110 bluetooth-configuration
111 bluetooth-configuration?
112 bluetooth-service
113
114 elogind-configuration
115 elogind-configuration?
116 elogind-service
117 elogind-service-type
118
119 %fontconfig-file-system
120 fontconfig-file-system-service
121
122 accountsservice-service-type
123 accountsservice-service
124
125 cups-pk-helper-service-type
126 sane-service-type
127
128 gnome-desktop-configuration
129 gnome-desktop-configuration?
130 gnome-desktop-service
131 gnome-desktop-service-type
132
133 mate-desktop-configuration
134 mate-desktop-configuration?
135 mate-desktop-service
136 mate-desktop-service-type
137
138 lxqt-desktop-configuration
139 lxqt-desktop-configuration?
140 lxqt-desktop-service-type
141
142 xfce-desktop-configuration
143 xfce-desktop-configuration?
144 xfce-desktop-service
145 xfce-desktop-service-type
146
147 x11-socket-directory-service
148
149 enlightenment-desktop-configuration
150 enlightenment-desktop-configuration?
151 enlightenment-desktop-service-type
152
153 inputattach-configuration
154 inputattach-configuration?
155 inputattach-service-type
156
157 polkit-wheel-service
158
159 gnome-keyring-configuration
160 gnome-keyring-configuration?
161 gnome-keyring-service-type
162
163 seatd-configuration
164 seatd-service-type
165
166 %desktop-services))
167
168 ;;; Commentary:
169 ;;;
170 ;;; This module contains service definitions for a "desktop" environment.
171 ;;;
172 ;;; Code:
173
174 \f
175 ;;;
176 ;;; Helpers.
177 ;;;
178
179 (define (bool value)
180 (if value "true\n" "false\n"))
181
182 (define (package-direct-input-selector input)
183 (lambda (package)
184 (match (assoc-ref (package-direct-inputs package) input)
185 ((package . _) package))))
186
187
188 \f
189 ;;;
190 ;;; Upower D-Bus service.
191 ;;;
192
193 (define-record-type* <upower-configuration>
194 upower-configuration make-upower-configuration
195 upower-configuration?
196 (upower upower-configuration-upower
197 (default upower))
198 (watts-up-pro? upower-configuration-watts-up-pro?
199 (default #f))
200 (poll-batteries? upower-configuration-poll-batteries?
201 (default #t))
202 (ignore-lid? upower-configuration-ignore-lid?
203 (default #f))
204 (use-percentage-for-policy? upower-configuration-use-percentage-for-policy?
205 (default #f))
206 (percentage-low upower-configuration-percentage-low
207 (default 10))
208 (percentage-critical upower-configuration-percentage-critical
209 (default 3))
210 (percentage-action upower-configuration-percentage-action
211 (default 2))
212 (time-low upower-configuration-time-low
213 (default 1200))
214 (time-critical upower-configuration-time-critical
215 (default 300))
216 (time-action upower-configuration-time-action
217 (default 120))
218 (critical-power-action upower-configuration-critical-power-action
219 (default 'hybrid-sleep)))
220
221 (define* upower-configuration-file
222 ;; Return an upower-daemon configuration file.
223 (match-lambda
224 (($ <upower-configuration> upower
225 watts-up-pro? poll-batteries? ignore-lid? use-percentage-for-policy?
226 percentage-low percentage-critical percentage-action time-low
227 time-critical time-action critical-power-action)
228 (plain-file "UPower.conf"
229 (string-append
230 "[UPower]\n"
231 "EnableWattsUpPro=" (bool watts-up-pro?)
232 "NoPollBatteries=" (bool (not poll-batteries?))
233 "IgnoreLid=" (bool ignore-lid?)
234 "UsePercentageForPolicy=" (bool use-percentage-for-policy?)
235 "PercentageLow=" (number->string percentage-low) "\n"
236 "PercentageCritical=" (number->string percentage-critical) "\n"
237 "PercentageAction=" (number->string percentage-action) "\n"
238 "TimeLow=" (number->string time-low) "\n"
239 "TimeCritical=" (number->string time-critical) "\n"
240 "TimeAction=" (number->string time-action) "\n"
241 "CriticalPowerAction=" (match critical-power-action
242 ('hybrid-sleep "HybridSleep")
243 ('hibernate "Hibernate")
244 ('power-off "PowerOff"))
245 "\n")))))
246
247 (define %upower-activation
248 #~(begin
249 (use-modules (guix build utils))
250 (mkdir-p "/var/lib/upower")))
251
252 (define (upower-dbus-service config)
253 (list (wrapped-dbus-service (upower-configuration-upower config)
254 "libexec/upowerd"
255 `(("UPOWER_CONF_FILE_NAME"
256 ,(upower-configuration-file config))))))
257
258 (define (upower-shepherd-service config)
259 "Return a shepherd service for UPower with CONFIG."
260 (let ((upower (upower-configuration-upower config))
261 (config (upower-configuration-file config)))
262 (list (shepherd-service
263 (documentation "Run the UPower power and battery monitor.")
264 (provision '(upower-daemon))
265 (requirement '(dbus-system udev))
266
267 (start #~(make-forkexec-constructor
268 (list (string-append #$upower "/libexec/upowerd"))
269 #:environment-variables
270 (list (string-append "UPOWER_CONF_FILE_NAME="
271 #$config))))
272 (stop #~(make-kill-destructor))))))
273
274 (define upower-service-type
275 (let ((upower-package (compose list upower-configuration-upower)))
276 (service-type (name 'upower)
277 (description
278 "Run @command{upowerd}}, a system-wide monitor for power
279 consumption and battery levels, with the given configuration settings. It
280 implements the @code{org.freedesktop.UPower} D-Bus interface, and is notably
281 used by GNOME.")
282 (extensions
283 (list (service-extension dbus-root-service-type
284 upower-dbus-service)
285 (service-extension shepherd-root-service-type
286 upower-shepherd-service)
287 (service-extension activation-service-type
288 (const %upower-activation))
289 (service-extension udev-service-type
290 upower-package)
291
292 ;; Make the 'upower' command visible.
293 (service-extension profile-service-type
294 upower-package)))
295 (default-value (upower-configuration)))))
296
297 \f
298 ;;;
299 ;;; GeoClue D-Bus service.
300 ;;;
301
302 ;; TODO: Export.
303 (define-record-type* <geoclue-configuration>
304 geoclue-configuration make-geoclue-configuration
305 geoclue-configuration?
306 (geoclue geoclue-configuration-geoclue
307 (default geoclue))
308 (whitelist geoclue-configuration-whitelist)
309 (wifi-geolocation-url geoclue-configuration-wifi-geolocation-url)
310 (submit-data? geoclue-configuration-submit-data?)
311 (wifi-submission-url geoclue-configuration-wifi-submission-url)
312 (submission-nick geoclue-configuration-submission-nick)
313 (applications geoclue-configuration-applications))
314
315 (define* (geoclue-application name #:key (allowed? #t) system? (users '()))
316 "Configure default GeoClue access permissions for an application. NAME is
317 the Desktop ID of the application, without the .desktop part. If ALLOWED? is
318 true, the application will have access to location information by default.
319 The boolean SYSTEM? value indicates that an application is a system component
320 or not. Finally USERS is a list of UIDs of all users for which this
321 application is allowed location info access. An empty users list means all
322 users are allowed."
323 (string-append
324 "[" name "]\n"
325 "allowed=" (bool allowed?)
326 "system=" (bool system?)
327 "users=" (string-join users ";") "\n"))
328
329 (define %standard-geoclue-applications
330 (list (geoclue-application "gnome-datetime-panel" #:system? #t)
331 (geoclue-application "epiphany" #:system? #f)
332 (geoclue-application "firefox" #:system? #f)))
333
334 (define* (geoclue-configuration-file config)
335 "Return a geoclue configuration file."
336 (plain-file "geoclue.conf"
337 (string-append
338 "[agent]\n"
339 "whitelist="
340 (string-join (geoclue-configuration-whitelist config)
341 ";") "\n"
342 "[wifi]\n"
343 "url=" (geoclue-configuration-wifi-geolocation-url config) "\n"
344 "submit-data=" (bool (geoclue-configuration-submit-data? config))
345 "submission-url="
346 (geoclue-configuration-wifi-submission-url config) "\n"
347 "submission-nick="
348 (geoclue-configuration-submission-nick config)
349 "\n"
350 (string-join (geoclue-configuration-applications config)
351 "\n"))))
352
353 (define (geoclue-dbus-service config)
354 (list (wrapped-dbus-service (geoclue-configuration-geoclue config)
355 "libexec/geoclue"
356 `(("GEOCLUE_CONFIG_FILE"
357 ,(geoclue-configuration-file config))))))
358
359 (define %geoclue-accounts
360 (list (user-group (name "geoclue") (system? #t))
361 (user-account
362 (name "geoclue")
363 (group "geoclue")
364 (system? #t)
365 (comment "GeoClue daemon user")
366 (home-directory "/var/empty")
367 (shell "/run/current-system/profile/sbin/nologin"))))
368
369 (define geoclue-service-type
370 (service-type (name 'geoclue)
371 (extensions
372 (list (service-extension dbus-root-service-type
373 geoclue-dbus-service)
374 (service-extension account-service-type
375 (const %geoclue-accounts))))
376 (description "Run the @command{geoclue} location service.
377 This service provides a D-Bus interface to allow applications to request
378 access to a user's physical location, and optionally to add information to
379 online location databases.")))
380
381 (define* (geoclue-service #:key (geoclue geoclue)
382 (whitelist '())
383 (wifi-geolocation-url
384 ;; Mozilla geolocation service:
385 "https://location.services.mozilla.com/v1/geolocate?key=geoclue")
386 (submit-data? #f)
387 (wifi-submission-url
388 "https://location.services.mozilla.com/v1/submit?key=geoclue")
389 (submission-nick "geoclue")
390 (applications %standard-geoclue-applications))
391 "Return a service that runs the @command{geoclue} location service. This
392 service provides a D-Bus interface to allow applications to request access to
393 a user's physical location, and optionally to add information to online
394 location databases. By default, only the GNOME date-time panel and the Icecat
395 and Epiphany web browsers are able to ask for the user's location, and in the
396 case of Icecat and Epiphany, both will ask the user for permission first. See
397 @uref{https://wiki.freedesktop.org/www/Software/GeoClue/, the geoclue web
398 site} for more information."
399 (service geoclue-service-type
400 (geoclue-configuration
401 (geoclue geoclue)
402 (whitelist whitelist)
403 (wifi-geolocation-url wifi-geolocation-url)
404 (submit-data? submit-data?)
405 (wifi-submission-url wifi-submission-url)
406 (submission-nick submission-nick)
407 (applications applications))))
408
409 \f
410 ;;;
411 ;;; Bluetooth.
412 ;;;
413
414 (define-record-type* <bluetooth-configuration>
415 bluetooth-configuration make-bluetooth-configuration
416 bluetooth-configuration?
417 (bluez bluetooth-configuration-bluez (default bluez))
418
419 ;;; [General]
420 (name bluetooth-configuration-name (default "BlueZ"))
421 (class bluetooth-configuration-class (default #x000000))
422 (discoverable-timeout
423 bluetooth-configuration-discoverable-timeout (default 180))
424 (always-pairable? bluetooth-configuration-always-pairable? (default #f))
425 (pairable-timeout bluetooth-configuration-pairable-timeout (default 0))
426
427 ;;; MAYBE: Exclude into separate <device-id> record-type?
428 (device-id bluetooth-configuration-device-id (default #f))
429 (reverse-service-discovery?
430 bluetooth-configuration-reverse-service-discovery (default #t))
431 (name-resolving? bluetooth-configuration-name-resolving? (default #t))
432 (debug-keys? bluetooth-configuration-debug-keys? (default #f))
433
434 ;;; Possible values:
435 ;;; 'dual, 'bredr, 'le
436 (controller-mode bluetooth-configuration-controller-mode (default 'dual))
437
438 ;;; Possible values:
439 ;;; 'off, 'single, 'multiple
440 (multi-profile bluetooth-configuration-multi-profile (default 'off))
441 (fast-connectable? bluetooth-configuration-fast-connectable? (default #f))
442
443 ;;; Possible values:
444 ;;; for LE mode: 'off, 'network/on, 'device
445 ;;; for Dual mode: 'off, 'network/on', 'device, 'limited-network, 'limited-device
446 ;;; Source: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/src/main.conf#n68
447 (privacy bluetooth-configuration-privacy (default 'off))
448
449 ;;; Possible values:
450 ;;; 'never, 'confirm, 'always
451 (just-works-repairing
452 bluetooth-configuration-just-works-repairing (default 'never))
453 (temporary-timeout bluetooth-configuration-temporary-timeout (default 30))
454 (refresh-discovery? bluetooth-configuration-refresh-discovery (default #t))
455
456 ;;; Possible values: #t, #f, (uuid <uuid>)
457 ;;; Possible UUIDs:
458 ;;; d4992530-b9ec-469f-ab01-6c481c47da1c (BlueZ Experimental Debug)
459 ;;; 671b10b5-42c0-4696-9227-eb28d1b049d6 (BlueZ Experimental Simultaneous Central and Peripheral)
460 ;;; 15c0a148-c273-11ea-b3de-0242ac130004 (BlueZ Experimental LL privacy)
461 ;;; 330859bc-7506-492d-9370-9a6f0614037f (BlueZ Experimental Bluetooth Quality Report)
462 ;;; a6695ace-ee7f-4fb9-881a-5fac66c629af (BlueZ Experimental Offload Codecs)
463 ;;; Source: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/src/main.conf#n110
464 (experimental bluetooth-configuration-experimental (default #f))
465 (remote-name-request-retry-delay
466 bluetooth-configuration-remote-name-request-retry-delay (default 300))
467
468 ;;; [BR]
469 (page-scan-type bluetooth-configuration-page-scan-type (default #f))
470 (page-scan-interval bluetooth-configuration-page-scan-interval (default #f))
471 (page-scan-window bluetooth-configuration-page-scan-window (default #f))
472 (inquiry-scan-type bluetooth-configuration-inquiry-scan-type (default #f))
473 (inquiry-scan-interval bluetooth-configuration-inquiry-scan-interval (default #f))
474 (inquiry-scan-window bluetooth-configuration-inquiry-scan-window (default #f))
475 (link-supervision-timeout bluetooth-configuration-link-supervision-timeout (default #f))
476 (page-timeout bluetooth-configuration-page-timeout (default #f))
477 (min-sniff-interval bluetooth-configuration-min-sniff-interval (default #f))
478 (max-sniff-interval bluetooth-configuration-max-sniff-interval (default #f))
479
480 ;;; [LE]
481 (min-advertisement-interval
482 bluetooth-configuration-min-advertisement-interval (default #f))
483 (max-advertisement-interval
484 bluetooth-configuration-max-advertisement-interval (default #f))
485 (multi-advertisement-rotation-interval
486 bluetooth-configuration-multi-advertisement-rotation-interval (default #f))
487 (scan-interval-auto-connect
488 bluetooth-configuration-scan-interval-auto-connect (default #f))
489 (scan-window-auto-connect
490 bluetooth-configuration-scan-window-auto-connect (default #f))
491 (scan-interval-suspend
492 bluetooth-configuration-scan-interval-suspend (default #f))
493 (scan-window-suspend
494 bluetooth-configuration-scan-window-suspend (default #f))
495 (scan-interval-discovery
496 bluetooth-configuration-scan-interval-discovery (default #f))
497 (scan-window-discovery
498 bluetooth-configuration-scan-window-discovery (default #f))
499 (scan-interval-adv-monitor
500 bluetooth-configuration-scan-interval-adv-monitor (default #f))
501 (scan-window-adv-monitor
502 bluetooth-configuration-scan-window-adv-monitor (default #f))
503 (scan-interval-connect
504 bluetooth-configuration-scan-interval-connect (default #f))
505 (scan-window-connect
506 bluetooth-configuration-scan-window-connect (default #f))
507 (min-connection-interval
508 bluetooth-configuration-min-connection-interval (default #f))
509 (max-connection-interval
510 bluetooth-configuration-max-connection-interval (default #f))
511 (connection-latency
512 bluetooth-configuration-connection-latency (default #f))
513 (connection-supervision-timeout
514 bluetooth-configuration-connection-supervision-timeout (default #f))
515 (autoconnect-timeout
516 bluetooth-configuration-autoconnect-timeout (default #f))
517 (adv-mon-allowlist-scan-duration
518 bluetooth-configuration-adv-mon-allowlist-scan-duration (default 300))
519 (adv-mon-no-filter-scan-duration
520 bluetooth-configuration-adv-mon-no-filter-scan-duration (default 500))
521 (enable-adv-mon-interleave-scan?
522 bluetooth-configuration-enable-adv-mon-interleave-scan (default #t))
523
524 ;;; [GATT]
525 ;;; Possible values: 'yes, 'no, 'always
526 (cache bluetooth-configuration-cache (default 'always))
527
528 ;;; Possible values: 7 ... 16, 0 (don't care)
529 (key-size bluetooth-configuration-key-size (default 0))
530
531 ;;; Possible values: 23 ... 517
532 (exchange-mtu bluetooth-configuration-exchange-mtu (default 517))
533
534 ;;; Possible values: 1 ... 5
535 (att-channels bluetooth-configuration-att-channels (default 3))
536
537 ;;; [AVDTP]
538 ;;; Possible values: 'basic, 'ertm
539 (session-mode bluetooth-configuration-session-mode (default 'basic))
540
541 ;;; Possible values: 'basic, 'streaming
542 (stream-mode bluetooth-configuration-stream-mode (default 'basic))
543
544 ;;; [Policy]
545 (reconnect-uuids bluetooth-configuration-reconnect-uuids (default '()))
546 (reconnect-attempts bluetooth-configuration-reconnect-attempts (default 7))
547 (reconnect-intervals bluetooth-configuration-reconnect-intervals
548 (default (list 1 2 4 8 16 32 64)))
549 (auto-enable? bluetooth-configuration-auto-enable? (default #f))
550 (resume-delay bluetooth-configuration-resume-delay (default 2))
551
552 ;;; [AdvMon]
553 ;;; Possible values:
554 ;;; "0x00", "0xFF",
555 ;;; "N = 0x00" ... "N = 0xFF"
556 ;;; Source: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/src/main.conf#n286
557 (rssi-sampling-period bluetooth-configuration-rssi-sampling-period
558 (default #xFF)))
559
560 (define (bluetooth-configuration-file config)
561 "Return a configuration file for the systemd bluetooth service, as a string."
562 (string-append
563 "[General]"
564 "\nName = " (bluetooth-configuration-name config)
565 "\nClass = " (string-append
566 "0x"
567 (format #f "~6,'0x" (bluetooth-configuration-class config)))
568 "\nDiscoverableTimeout = " (number->string
569 (bluetooth-configuration-discoverable-timeout
570 config))
571 "\nAlwaysPairable = " (bool (bluetooth-configuration-always-pairable?
572 config))
573 "\nPairableTimeout = " (number->string
574 (bluetooth-configuration-pairable-timeout
575 config))
576 (if (bluetooth-configuration-device-id config)
577 (string-append "\nDeviceID = " (bluetooth-configuration-device-id config))
578 "")
579 "\nReverseServiceDiscovery = " (bool
580 (bluetooth-configuration-reverse-service-discovery
581 config))
582 "\nNameResolving = " (bool (bluetooth-configuration-name-resolving? config))
583 "\nDebugKeys = " (bool (bluetooth-configuration-debug-keys? config))
584 "\nControllerMode = " (symbol->string
585 (bluetooth-configuration-controller-mode config))
586 "\nMultiProfile = " (symbol->string (bluetooth-configuration-multi-profile
587 config))
588 "\nFastConnectable = " (bool (bluetooth-configuration-fast-connectable? config))
589 "\nPrivacy = " (symbol->string (bluetooth-configuration-privacy config))
590 "\nJustWorksRepairing = " (symbol->string
591 (bluetooth-configuration-just-works-repairing config))
592 "\nTemporaryTimeout = " (number->string
593 (bluetooth-configuration-temporary-timeout config))
594 "\nRefreshDiscovery = " (bool (bluetooth-configuration-refresh-discovery config))
595 "\nExperimental = " (let ((experimental (bluetooth-configuration-experimental config)))
596 (cond ((or (eq? experimental #t)
597 (eq? experimental #f)) (bool experimental))
598 ((list? experimental)
599 (string-join (map uuid->string experimental) ","))))
600 "\nRemoteNameRequestRetryDelay = " (number->string
601 (bluetooth-configuration-remote-name-request-retry-delay
602 config))
603 "\n[BR]"
604 (if (bluetooth-configuration-page-scan-type config)
605 (string-append
606 "\nPageScanType = "
607 (number->string (bluetooth-configuration-page-scan-type config)))
608 "")
609 (if (bluetooth-configuration-page-scan-interval config)
610 (string-append
611 "\nPageScanInterval = "
612 (number->string (bluetooth-configuration-page-scan-interval config)))
613 "")
614 (if (bluetooth-configuration-page-scan-window config)
615 (string-append
616 "\nPageScanWindow = "
617 (number->string (bluetooth-configuration-page-scan-window config)))
618 "")
619 (if (bluetooth-configuration-inquiry-scan-type config)
620 (string-append
621 "\nInquiryScanType = "
622 (number->string (bluetooth-configuration-inquiry-scan-type config)))
623 "")
624 (if (bluetooth-configuration-inquiry-scan-interval config)
625 (string-append
626 "\nInquiryScanInterval = "
627 (number->string (bluetooth-configuration-inquiry-scan-interval config)))
628 "")
629 (if (bluetooth-configuration-inquiry-scan-window config)
630 (string-append
631 "\nInquiryScanWindow = "
632 (number->string (bluetooth-configuration-inquiry-scan-window config)))
633 "")
634 (if (bluetooth-configuration-link-supervision-timeout config)
635 (string-append
636 "\nLinkSupervisionTimeout = "
637 (number->string (bluetooth-configuration-link-supervision-timeout config)))
638 "")
639 (if (bluetooth-configuration-page-timeout config)
640 (string-append
641 "\nPageTimeout = "
642 (number->string (bluetooth-configuration-page-timeout config)))
643 "")
644 (if (bluetooth-configuration-min-sniff-interval config)
645 (string-append
646 "\nMinSniffInterval = "
647 (number->string (bluetooth-configuration-min-sniff-interval config)))
648 "")
649 (if (bluetooth-configuration-max-sniff-interval config)
650 (string-append
651 "\nMaxSniffInterval = "
652 (number->string (bluetooth-configuration-max-sniff-interval config)))
653 "")
654
655 "\n[LE]"
656 (if (bluetooth-configuration-min-advertisement-interval config)
657 (string-append
658 "\nMinAdvertisementInterval = "
659 (number->string (bluetooth-configuration-min-advertisement-interval config)))
660 "")
661 (if (bluetooth-configuration-max-advertisement-interval config)
662 (string-append
663 "\nMaxAdvertisementInterval = "
664 (number->string (bluetooth-configuration-max-advertisement-interval config)))
665 "")
666 (if (bluetooth-configuration-multi-advertisement-rotation-interval config)
667 (string-append
668 "\nMultiAdvertisementRotationInterval = "
669 (number->string
670 (bluetooth-configuration-multi-advertisement-rotation-interval config)))
671 "")
672 (if (bluetooth-configuration-scan-interval-auto-connect config)
673 (string-append
674 "\nScanIntervalAutoConnect = "
675 (number->string (bluetooth-configuration-scan-interval-auto-connect config)))
676 "")
677 (if (bluetooth-configuration-scan-window-auto-connect config)
678 (string-append
679 "\nScanWindowAutoConnect = "
680 (number->string (bluetooth-configuration-scan-window-auto-connect config)))
681 "")
682 (if (bluetooth-configuration-scan-interval-suspend config)
683 (string-append
684 "\nScanIntervalSuspend = "
685 (number->string (bluetooth-configuration-scan-interval-suspend config)))
686 "")
687 (if (bluetooth-configuration-scan-window-suspend config)
688 (string-append
689 "\nScanWindowSuspend = "
690 (number->string (bluetooth-configuration-scan-window-suspend config)))
691 "")
692 (if (bluetooth-configuration-scan-interval-discovery config)
693 (string-append
694 "\nScanIntervalDiscovery = "
695 (number->string (bluetooth-configuration-scan-interval-discovery config)))
696 "")
697 (if (bluetooth-configuration-scan-window-discovery config)
698 (string-append
699 "\nScanWindowDiscovery = "
700 (number->string (bluetooth-configuration-scan-window-discovery config)))
701 "")
702 (if (bluetooth-configuration-scan-interval-adv-monitor config)
703 (string-append
704 "\nScanIntervalAdvMonitor = "
705 (number->string (bluetooth-configuration-scan-interval-adv-monitor config)))
706 "")
707 (if (bluetooth-configuration-scan-window-adv-monitor config)
708 (string-append
709 "\nScanWindowAdvMonitor = "
710 (number->string (bluetooth-configuration-scan-window-adv-monitor config)))
711 "")
712 (if (bluetooth-configuration-scan-interval-connect config)
713 (string-append
714 "\nScanIntervalConnect = "
715 (number->string (bluetooth-configuration-scan-interval-connect config)))
716 "")
717 (if (bluetooth-configuration-scan-window-connect config)
718 (string-append
719 "\nScanWindowConnect = "
720 (number->string (bluetooth-configuration-scan-window-connect config)))
721 "")
722 (if (bluetooth-configuration-min-connection-interval config)
723 (string-append
724 "\nMinConnectionInterval = "
725 (number->string (bluetooth-configuration-min-connection-interval config)))
726 "")
727 (if (bluetooth-configuration-max-connection-interval config)
728 (string-append
729 "\nMaxConnectionInterval = "
730 (number->string (bluetooth-configuration-max-connection-interval config)))
731 "")
732 (if (bluetooth-configuration-connection-latency config)
733 (string-append
734 "\nConnectionLatency = "
735 (number->string (bluetooth-configuration-connection-latency config)))
736 "")
737 (if (bluetooth-configuration-connection-supervision-timeout config)
738 (string-append
739 "\nConnectionSupervisionTimeout = "
740 (number->string (bluetooth-configuration-connection-supervision-timeout config)))
741 "")
742 (if (bluetooth-configuration-autoconnect-timeout config)
743 (string-append
744 "\nAutoconnecttimeout = "
745 (number->string (bluetooth-configuration-autoconnect-timeout config)))
746 "")
747 "\nAdvMonAllowlistScanDuration = " (number->string
748 (bluetooth-configuration-adv-mon-allowlist-scan-duration
749 config))
750 "\nAdvMonNoFilterScanDuration = " (number->string
751 (bluetooth-configuration-adv-mon-no-filter-scan-duration
752 config))
753 "\nEnableAdvMonInterleaveScan = " (number->string
754 (if (eq? #t
755 (bluetooth-configuration-enable-adv-mon-interleave-scan
756 config))
757 1 0))
758
759 "\n[GATT]"
760 "\nCache = " (symbol->string (bluetooth-configuration-cache config))
761 "\nKeySize = " (number->string (bluetooth-configuration-key-size config))
762 "\nExchangeMTU = " (number->string (bluetooth-configuration-exchange-mtu config))
763 "\nChannels = " (number->string (bluetooth-configuration-att-channels config))
764
765 "\n[AVDTP]"
766 "\nSessionMode = " (symbol->string (bluetooth-configuration-session-mode config))
767 "\nStreamMode = " (symbol->string (bluetooth-configuration-stream-mode config))
768
769 "\n[Policy]"
770 (let ((uuids (bluetooth-configuration-reconnect-uuids config)))
771 (if (not (eq? '() uuids))
772 (string-append
773 "\nReconnectUUIDs = "
774 (string-join (map uuid->string uuids) ","))
775 ""))
776 "\nReconnectAttempts = " (number->string
777 (bluetooth-configuration-reconnect-attempts config))
778 "\nReconnectIntervals = " (string-join
779 (map number->string
780 (bluetooth-configuration-reconnect-intervals
781 config))
782 ",")
783 "\nAutoEnable = " (bool (bluetooth-configuration-auto-enable?
784 config))
785 "\nResumeDelay = " (number->string (bluetooth-configuration-resume-delay config))
786
787 "\n[AdvMon]"
788 "\nRSSISamplingPeriod = " (string-append
789 "0x"
790 (format #f "~2,'0x"
791 (bluetooth-configuration-rssi-sampling-period config)))))
792
793 (define (bluetooth-directory config)
794 (computed-file "etc-bluetooth"
795 #~(begin
796 (mkdir #$output)
797 (chdir #$output)
798 (call-with-output-file "main.conf"
799 (lambda (port)
800 (display #$(bluetooth-configuration-file config)
801 port))))))
802
803 (define (bluetooth-shepherd-service config)
804 "Return a shepherd service for @command{bluetoothd}."
805 (shepherd-service
806 (provision '(bluetooth))
807 (requirement '(dbus-system udev))
808 (documentation "Run the bluetoothd daemon.")
809 (start #~(make-forkexec-constructor
810 (list #$(file-append (bluetooth-configuration-bluez config)
811 "/libexec/bluetooth/bluetoothd"))))
812 (stop #~(make-kill-destructor))))
813
814 (define bluetooth-service-type
815 (service-type
816 (name 'bluetooth)
817 (extensions
818 (list (service-extension dbus-root-service-type
819 (compose list bluetooth-configuration-bluez))
820 (service-extension udev-service-type
821 (compose list bluetooth-configuration-bluez))
822 (service-extension etc-service-type
823 (lambda (config)
824 `(("bluetooth"
825 ,(bluetooth-directory config)))))
826 (service-extension shepherd-root-service-type
827 (compose list bluetooth-shepherd-service))))
828 (default-value (bluetooth-configuration))
829 (description "Run the @command{bluetoothd} daemon, which manages all the
830 Bluetooth devices and provides a number of D-Bus interfaces.")))
831
832 (define* (bluetooth-service #:key (bluez bluez) (auto-enable? #f))
833 "Return a service that runs the @command{bluetoothd} daemon, which manages
834 all the Bluetooth devices and provides a number of D-Bus interfaces. When
835 AUTO-ENABLE? is true, the bluetooth controller is powered automatically at
836 boot.
837
838 Users need to be in the @code{lp} group to access the D-Bus service.
839 "
840 (service bluetooth-service-type
841 (bluetooth-configuration
842 (bluez bluez)
843 (auto-enable? auto-enable?))))
844
845 \f
846 ;;;
847 ;;; Colord D-Bus service.
848 ;;;
849
850 (define %colord-activation
851 #~(begin
852 (use-modules (guix build utils))
853 (mkdir-p "/var/lib/colord")
854 (let ((user (getpwnam "colord")))
855 (chown "/var/lib/colord"
856 (passwd:uid user) (passwd:gid user)))))
857
858 (define %colord-accounts
859 (list (user-group (name "colord") (system? #t))
860 (user-account
861 (name "colord")
862 (group "colord")
863 (system? #t)
864 (comment "colord daemon user")
865 (home-directory "/var/empty")
866 (shell (file-append shadow "/sbin/nologin")))))
867
868 (define colord-service-type
869 (service-type (name 'colord)
870 (extensions
871 (list (service-extension account-service-type
872 (const %colord-accounts))
873 (service-extension activation-service-type
874 (const %colord-activation))
875
876 ;; Colord is a D-Bus service that dbus-daemon can
877 ;; activate.
878 (service-extension dbus-root-service-type list)
879
880 ;; Colord provides "color device" rules for udev.
881 (service-extension udev-service-type list)
882
883 ;; It provides polkit "actions".
884 (service-extension polkit-service-type list)))
885 (default-value colord)
886 (description
887 "Run @command{colord}, a system service with a D-Bus
888 interface to manage the color profiles of input and output devices such as
889 screens and scanners.")))
890
891 \f
892 ;;;
893 ;;; UDisks.
894 ;;;
895
896 (define-record-type* <udisks-configuration>
897 udisks-configuration make-udisks-configuration
898 udisks-configuration?
899 (udisks udisks-configuration-udisks
900 (default udisks)))
901
902 (define %udisks-activation
903 (with-imported-modules '((guix build utils))
904 #~(begin
905 (use-modules (guix build utils))
906
907 (let ((run-dir "/var/run/udisks2"))
908 (mkdir-p run-dir)
909 (chmod run-dir #o700)))))
910
911 (define udisks-service-type
912 (let ((udisks-package (lambda (config)
913 (list (udisks-configuration-udisks config)))))
914 (service-type (name 'udisks)
915 (extensions
916 (list (service-extension polkit-service-type
917 udisks-package)
918 (service-extension dbus-root-service-type
919 udisks-package)
920 (service-extension udev-service-type
921 udisks-package)
922 (service-extension activation-service-type
923 (const %udisks-activation))
924
925 ;; Profile 'udisksctl' & co. in the system profile.
926 (service-extension profile-service-type
927 udisks-package)))
928 (description "Run UDisks, a @dfn{disk management} daemon
929 that provides user interfaces with notifications and ways to mount/unmount
930 disks. Programs that talk to UDisks include the @command{udisksctl} command,
931 part of UDisks, and GNOME Disks."))))
932
933 (define* (udisks-service #:key (udisks udisks))
934 "Return a service for @uref{http://udisks.freedesktop.org/docs/latest/,
935 UDisks}, a @dfn{disk management} daemon that provides user interfaces with
936 notifications and ways to mount/unmount disks. Programs that talk to UDisks
937 include the @command{udisksctl} command, part of UDisks, and GNOME Disks."
938 (service udisks-service-type
939 (udisks-configuration (udisks udisks))))
940
941 \f
942 ;;;
943 ;;; Elogind login and seat management service.
944 ;;;
945
946 (define-record-type* <elogind-configuration> elogind-configuration
947 make-elogind-configuration
948 elogind-configuration?
949 (elogind elogind-package
950 (default elogind))
951 (kill-user-processes? elogind-kill-user-processes?
952 (default #f))
953 (kill-only-users elogind-kill-only-users
954 (default '()))
955 (kill-exclude-users elogind-kill-exclude-users
956 (default '("root")))
957 (inhibit-delay-max-seconds elogind-inhibit-delay-max-seconds
958 (default 5))
959 (handle-power-key elogind-handle-power-key
960 (default 'poweroff))
961 (handle-suspend-key elogind-handle-suspend-key
962 (default 'suspend))
963 (handle-hibernate-key elogind-handle-hibernate-key
964 ;; (default 'hibernate)
965 ;; XXX Ignore it for now, since we don't
966 ;; yet handle resume-from-hibernation in
967 ;; our initrd.
968 (default 'ignore))
969 (handle-lid-switch elogind-handle-lid-switch
970 (default 'suspend))
971 (handle-lid-switch-docked elogind-handle-lid-switch-docked
972 (default 'ignore))
973 (handle-lid-switch-external-power elogind-handle-lid-switch-external-power
974 (default 'ignore))
975 (power-key-ignore-inhibited? elogind-power-key-ignore-inhibited?
976 (default #f))
977 (suspend-key-ignore-inhibited? elogind-suspend-key-ignore-inhibited?
978 (default #f))
979 (hibernate-key-ignore-inhibited? elogind-hibernate-key-ignore-inhibited?
980 (default #f))
981 (lid-switch-ignore-inhibited? elogind-lid-switch-ignore-inhibited?
982 (default #t))
983 (holdoff-timeout-seconds elogind-holdoff-timeout-seconds
984 (default 30))
985 (idle-action elogind-idle-action
986 (default 'ignore))
987 (idle-action-seconds elogind-idle-action-seconds
988 (default (* 30 60)))
989 (runtime-directory-size-percent elogind-runtime-directory-size-percent
990 (default 10))
991 (runtime-directory-size elogind-runtime-directory-size
992 (default #f))
993 (remove-ipc? elogind-remove-ipc?
994 (default #t))
995
996 (suspend-state elogind-suspend-state
997 (default '("mem" "standby" "freeze")))
998 (suspend-mode elogind-suspend-mode
999 (default '()))
1000 (hibernate-state elogind-hibernate-state
1001 (default '("disk")))
1002 (hibernate-mode elogind-hibernate-mode
1003 (default '("platform" "shutdown")))
1004 (hybrid-sleep-state elogind-hybrid-sleep-state
1005 (default '("disk")))
1006 (hybrid-sleep-mode elogind-hybrid-sleep-mode
1007 (default
1008 '("suspend" "platform" "shutdown"))))
1009
1010 (define (elogind-configuration-file config)
1011 (define (yesno x)
1012 (match x
1013 (#t "yes")
1014 (#f "no")
1015 (_ (error "expected #t or #f, instead got:" x))))
1016 (define char-set:user-name
1017 (string->char-set "abcdefghijklmnopqrstuvwxyz0123456789_-"))
1018 (define (valid-list? l pred)
1019 (and-map (lambda (x) (string-every pred x)) l))
1020 (define (user-name-list users)
1021 (unless (valid-list? users char-set:user-name)
1022 (error "invalid user list" users))
1023 (string-join users " "))
1024 (define (enum val allowed)
1025 (unless (memq val allowed)
1026 (error "invalid value" val allowed))
1027 (symbol->string val))
1028 (define (non-negative-integer x)
1029 (unless (exact-integer? x) (error "not an integer" x))
1030 (when (negative? x) (error "negative number not allowed" x))
1031 (number->string x))
1032 (define handle-actions
1033 '(ignore poweroff reboot halt kexec suspend hibernate hybrid-sleep lock))
1034 (define (handle-action x)
1035 (enum x handle-actions))
1036 (define (sleep-list tokens)
1037 (unless (valid-list? tokens char-set:user-name)
1038 (error "invalid sleep list" tokens))
1039 (string-join tokens " "))
1040 (define-syntax ini-file-clause
1041 (syntax-rules ()
1042 ((_ config (prop (parser getter)))
1043 (string-append prop "=" (parser (getter config)) "\n"))
1044 ((_ config str)
1045 (string-append str "\n"))))
1046 (define-syntax-rule (ini-file config file clause ...)
1047 (plain-file file (string-append (ini-file-clause config clause) ...)))
1048 (ini-file
1049 config "logind.conf"
1050 "[Login]"
1051 ("KillUserProcesses" (yesno elogind-kill-user-processes?))
1052 ("KillOnlyUsers" (user-name-list elogind-kill-only-users))
1053 ("KillExcludeUsers" (user-name-list elogind-kill-exclude-users))
1054 ("InhibitDelayMaxSec" (non-negative-integer elogind-inhibit-delay-max-seconds))
1055 ("HandlePowerKey" (handle-action elogind-handle-power-key))
1056 ("HandleSuspendKey" (handle-action elogind-handle-suspend-key))
1057 ("HandleHibernateKey" (handle-action elogind-handle-hibernate-key))
1058 ("HandleLidSwitch" (handle-action elogind-handle-lid-switch))
1059 ("HandleLidSwitchDocked" (handle-action elogind-handle-lid-switch-docked))
1060 ("HandleLidSwitchExternalPower" (handle-action elogind-handle-lid-switch-external-power))
1061 ("PowerKeyIgnoreInhibited" (yesno elogind-power-key-ignore-inhibited?))
1062 ("SuspendKeyIgnoreInhibited" (yesno elogind-suspend-key-ignore-inhibited?))
1063 ("HibernateKeyIgnoreInhibited" (yesno elogind-hibernate-key-ignore-inhibited?))
1064 ("LidSwitchIgnoreInhibited" (yesno elogind-lid-switch-ignore-inhibited?))
1065 ("HoldoffTimeoutSec" (non-negative-integer elogind-holdoff-timeout-seconds))
1066 ("IdleAction" (handle-action elogind-idle-action))
1067 ("IdleActionSec" (non-negative-integer elogind-idle-action-seconds))
1068 ("RuntimeDirectorySize"
1069 (identity
1070 (lambda (config)
1071 (match (elogind-runtime-directory-size-percent config)
1072 (#f (non-negative-integer (elogind-runtime-directory-size config)))
1073 (percent (string-append (non-negative-integer percent) "%"))))))
1074 ("RemoveIPC" (yesno elogind-remove-ipc?))
1075 "[Sleep]"
1076 ("SuspendState" (sleep-list elogind-suspend-state))
1077 ("SuspendMode" (sleep-list elogind-suspend-mode))
1078 ("HibernateState" (sleep-list elogind-hibernate-state))
1079 ("HibernateMode" (sleep-list elogind-hibernate-mode))
1080 ("HybridSleepState" (sleep-list elogind-hybrid-sleep-state))
1081 ("HybridSleepMode" (sleep-list elogind-hybrid-sleep-mode))))
1082
1083 (define (elogind-dbus-service config)
1084 "Return a @file{org.freedesktop.login1.service} file that tells D-Bus how to
1085 \"start\" elogind. In practice though, our elogind is started when booting by
1086 shepherd. Thus, the @code{Exec} line of this @file{.service} file does not
1087 explain how to start elogind; instead, it spawns a wrapper that waits for the
1088 @code{elogind} shepherd service. This avoids a race condition where both
1089 @command{shepherd} and @command{dbus-daemon} would attempt to start elogind."
1090 ;; For more info on the elogind startup race, see
1091 ;; <https://issues.guix.gnu.org/55444>.
1092
1093 (define elogind
1094 (elogind-package config))
1095
1096 (define wrapper
1097 (program-file "elogind-dbus-shepherd-sync"
1098 (with-imported-modules '((gnu services herd))
1099 #~(begin
1100 (use-modules (gnu services herd)
1101 (srfi srfi-34))
1102
1103 (guard (c ((service-not-found-error? c)
1104 (format (current-error-port)
1105 "no elogind shepherd service~%")
1106 (exit 1))
1107 ((shepherd-error? c)
1108 (format (current-error-port)
1109 "elogind shepherd service not \
1110 started~%")
1111 (exit 2)))
1112 (wait-for-service 'elogind))))))
1113
1114 (define build
1115 (with-imported-modules '((guix build utils))
1116 #~(begin
1117 (use-modules (guix build utils)
1118 (ice-9 match))
1119
1120 (define service-directory
1121 "/share/dbus-1/system-services")
1122
1123 (mkdir-p (dirname (string-append #$output service-directory)))
1124 (copy-recursively (string-append #$elogind service-directory)
1125 (string-append #$output service-directory))
1126 (symlink (string-append #$elogind "/etc") ;for etc/dbus-1
1127 (string-append #$output "/etc"))
1128
1129 ;; Replace the "Exec=" line of the 'org.freedesktop.login1.service'
1130 ;; file with one that refers to WRAPPER instead of elogind.
1131 (match (find-files #$output "\\.service$")
1132 ((file)
1133 (substitute* file
1134 (("Exec[[:blank:]]*=.*" _)
1135 (string-append "Exec=" #$wrapper "\n"))))))))
1136
1137 (list (computed-file "elogind-dbus-service-wrapper" build)))
1138
1139 (define (pam-extension-procedure config)
1140 "Return an extension for PAM-ROOT-SERVICE-TYPE that ensures that all the PAM
1141 services use 'pam_elogind.so', a module that allows elogind to keep track of
1142 logged-in users (run 'loginctl' to see elogind's world view of users and
1143 seats.)"
1144 (define pam-elogind
1145 (pam-entry
1146 (control "required")
1147 (module (file-append (elogind-package config)
1148 "/lib/security/pam_elogind.so"))))
1149
1150 (list (lambda (pam)
1151 (pam-service
1152 (inherit pam)
1153 (session (cons pam-elogind (pam-service-session pam)))))))
1154
1155 (define (elogind-shepherd-service config)
1156 "Return a Shepherd service to start elogind according to @var{config}."
1157 (list (shepherd-service
1158 (requirement '(dbus-system))
1159 (provision '(elogind))
1160 (start #~(make-forkexec-constructor
1161 (list #$(file-append (elogind-package config)
1162 "/libexec/elogind/elogind"))
1163 #:environment-variables
1164 (list (string-append "ELOGIND_CONF_FILE="
1165 #$(elogind-configuration-file
1166 config)))))
1167 (stop #~(make-kill-destructor)))))
1168
1169 (define elogind-service-type
1170 (service-type (name 'elogind)
1171 (extensions
1172 (list (service-extension dbus-root-service-type
1173 elogind-dbus-service)
1174 (service-extension udev-service-type
1175 (compose list elogind-package))
1176 (service-extension polkit-service-type
1177 (compose list elogind-package))
1178
1179 ;; Start elogind from the Shepherd rather than waiting
1180 ;; for bus activation. This ensures that it can handle
1181 ;; events like lid close, etc.
1182 (service-extension shepherd-root-service-type
1183 elogind-shepherd-service)
1184
1185 ;; Provide the 'loginctl' command.
1186 (service-extension profile-service-type
1187 (compose list elogind-package))
1188
1189 ;; Extend PAM with pam_elogind.so.
1190 (service-extension pam-root-service-type
1191 pam-extension-procedure)
1192
1193 ;; We need /run/user, /run/systemd, etc.
1194 (service-extension file-system-service-type
1195 (const %elogind-file-systems))))
1196 (default-value (elogind-configuration))
1197 (description "Run the @command{elogind} login and seat
1198 management service. The @command{elogind} service integrates with PAM to
1199 allow other system components to know the set of logged-in users as well as
1200 their session types (graphical, console, remote, etc.). It can also clean up
1201 after users when they log out.")))
1202
1203 (define* (elogind-service #:key (config (elogind-configuration)))
1204 "Return a service that runs the @command{elogind} login and seat management
1205 service. The @command{elogind} service integrates with PAM to allow other
1206 system components to know the set of logged-in users as well as their session
1207 types (graphical, console, remote, etc.). It can also clean up after users
1208 when they log out."
1209 (service elogind-service-type config))
1210
1211 \f
1212 ;;;
1213 ;;; Fontconfig and other desktop file-systems.
1214 ;;;
1215
1216 (define %fontconfig-file-system
1217 (file-system
1218 (device "none")
1219 (mount-point "/var/cache/fontconfig")
1220 (type "tmpfs")
1221 (flags '(read-only))
1222 (check? #f)))
1223
1224 ;; The global fontconfig cache directory can sometimes contain stale entries,
1225 ;; possibly referencing fonts that have been GC'd, so mount it read-only.
1226 ;; As mentioned https://debbugs.gnu.org/cgi/bugreport.cgi?bug=36924#8 and
1227 ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=38046#10 and elsewhere.
1228 (define fontconfig-file-system-service
1229 (simple-service 'fontconfig-file-system
1230 file-system-service-type
1231 (list %fontconfig-file-system)))
1232 \f
1233 ;;;
1234 ;;; AccountsService service.
1235 ;;;
1236
1237 (define %accountsservice-activation
1238 #~(begin
1239 (use-modules (guix build utils))
1240 (mkdir-p "/var/lib/AccountsService")))
1241
1242 (define accountsservice-service-type
1243 (service-type (name 'accountsservice)
1244 (extensions
1245 (list (service-extension activation-service-type
1246 (const %accountsservice-activation))
1247 (service-extension dbus-root-service-type list)
1248 (service-extension polkit-service-type list)))
1249 (default-value accountsservice)
1250 (description "Run AccountsService, a system service available
1251 over D-Bus that can list available accounts, change their passwords, and so
1252 on. AccountsService integrates with PolicyKit to enable unprivileged users to
1253 acquire the capability to modify their system configuration.")))
1254
1255 (define* (accountsservice-service #:key (accountsservice accountsservice))
1256 "Return a service that runs AccountsService, a system service that
1257 can list available accounts, change their passwords, and so on.
1258 AccountsService integrates with PolicyKit to enable unprivileged users to
1259 acquire the capability to modify their system configuration.
1260 @uref{https://www.freedesktop.org/wiki/Software/AccountsService/, the
1261 accountsservice web site} for more information."
1262 (service accountsservice-service-type accountsservice))
1263
1264 \f
1265 ;;;
1266 ;;; cups-pk-helper service.
1267 ;;;
1268
1269 (define cups-pk-helper-service-type
1270 (service-type
1271 (name 'cups-pk-helper)
1272 (description
1273 "PolicyKit helper to configure CUPS with fine-grained privileges.")
1274 (extensions
1275 (list (service-extension dbus-root-service-type list)
1276 (service-extension polkit-service-type list)))
1277 (default-value cups-pk-helper)))
1278
1279 \f
1280 ;;;
1281 ;;; Scanner access via SANE.
1282 ;;;
1283
1284 (define %sane-accounts
1285 ;; The '60-libsane.rules' udev rules refers to the "scanner" group.
1286 (list (user-group (name "scanner") (system? #t))))
1287
1288 (define sane-service-type
1289 (service-type
1290 (name 'sane)
1291 (description
1292 "This service provides access to scanners @i{via}
1293 @uref{http://www.sane-project.org, SANE} by installing the necessary udev
1294 rules.")
1295 (default-value sane-backends-minimal)
1296 (extensions
1297 (list (service-extension udev-service-type list)
1298 (service-extension account-service-type
1299 (const %sane-accounts))))))
1300
1301
1302 \f
1303 ;;;
1304 ;;; GNOME desktop service.
1305 ;;;
1306
1307 (define-record-type* <gnome-desktop-configuration> gnome-desktop-configuration
1308 make-gnome-desktop-configuration
1309 gnome-desktop-configuration?
1310 (gnome gnome-package (default gnome)))
1311
1312 (define (gnome-packages config packages)
1313 "Return the list of GNOME dependencies from CONFIG which names are part of
1314 the given PACKAGES list."
1315 (let ((gnome (gnome-package config)))
1316 (map (lambda (name)
1317 ((package-direct-input-selector name) gnome))
1318 packages)))
1319
1320 (define (gnome-udev-rules config)
1321 "Return the list of GNOME dependencies that provide udev rules."
1322 (gnome-packages config '("gnome-settings-daemon")))
1323
1324 (define (gnome-polkit-settings config)
1325 "Return the list of GNOME dependencies that provide polkit actions and
1326 rules."
1327 (gnome-packages config
1328 '("gnome-settings-daemon"
1329 "gnome-control-center"
1330 "gnome-system-monitor"
1331 "gvfs")))
1332
1333 (define gnome-desktop-service-type
1334 (service-type
1335 (name 'gnome-desktop)
1336 (extensions
1337 (list (service-extension udev-service-type
1338 gnome-udev-rules)
1339 (service-extension polkit-service-type
1340 gnome-polkit-settings)
1341 (service-extension profile-service-type
1342 (compose list
1343 gnome-package))))
1344 (default-value (gnome-desktop-configuration))
1345 (description "Run the GNOME desktop environment.")))
1346
1347 (define-deprecated (gnome-desktop-service #:key (config
1348 (gnome-desktop-configuration)))
1349 gnome-desktop-service-type
1350 "Return a service that adds the @code{gnome} package to the system profile,
1351 and extends polkit with the actions from @code{gnome-settings-daemon}."
1352 (service gnome-desktop-service-type config))
1353
1354 ;; MATE Desktop service.
1355 ;; TODO: Add mate-screensaver.
1356
1357 (define-record-type* <mate-desktop-configuration> mate-desktop-configuration
1358 make-mate-desktop-configuration
1359 mate-desktop-configuration?
1360 (mate-package mate-package (default mate)))
1361
1362 (define (mate-polkit-extension config)
1363 "Return the list of packages for CONFIG's MATE package that extend polkit."
1364 (let ((mate (mate-package config)))
1365 (map (lambda (input)
1366 ((package-direct-input-selector input) mate))
1367 '("mate-system-monitor" ;kill, renice processes
1368 "mate-settings-daemon" ;date/time settings
1369 "mate-power-manager" ;modify brightness
1370 "mate-control-center" ;RandR, display properties FIXME
1371 "mate-applets")))) ;CPU frequency scaling
1372
1373 (define mate-desktop-service-type
1374 (service-type
1375 (name 'mate-desktop)
1376 (extensions
1377 (list (service-extension polkit-service-type
1378 mate-polkit-extension)
1379 (service-extension profile-service-type
1380 (compose list
1381 mate-package))))
1382 (default-value (mate-desktop-configuration))
1383 (description "Run the MATE desktop environment.")))
1384
1385 (define-deprecated (mate-desktop-service #:key
1386 (config
1387 (mate-desktop-configuration)))
1388 mate-desktop-service-type
1389 "Return a service that adds the @code{mate} package to the system profile,
1390 and extends polkit with the actions from @code{mate-settings-daemon}."
1391 (service mate-desktop-service-type config))
1392
1393 \f
1394 ;;;
1395 ;;; XFCE desktop service.
1396 ;;;
1397
1398 (define-record-type* <xfce-desktop-configuration> xfce-desktop-configuration
1399 make-xfce-desktop-configuration
1400 xfce-desktop-configuration?
1401 (xfce xfce-package (default xfce)))
1402
1403 (define (xfce-polkit-settings config)
1404 "Return the list of XFCE dependencies that provide polkit actions and
1405 rules."
1406 (let ((xfce (xfce-package config)))
1407 (map (lambda (name)
1408 ((package-direct-input-selector name) xfce))
1409 '("thunar"
1410 "xfce4-power-manager"))))
1411
1412 (define xfce-desktop-service-type
1413 (service-type
1414 (name 'xfce-desktop)
1415 (extensions
1416 (list (service-extension polkit-service-type
1417 xfce-polkit-settings)
1418 (service-extension profile-service-type
1419 (compose list xfce-package))))
1420 (default-value (xfce-desktop-configuration))
1421 (description "Run the Xfce desktop environment.")))
1422
1423 (define-deprecated (xfce-desktop-service #:key (config
1424 (xfce-desktop-configuration)))
1425 xfce-desktop-service-type
1426 "Return a service that adds the @code{xfce} package to the system profile,
1427 and extends polkit with the ability for @code{thunar} to manipulate the file
1428 system as root from within a user session, after the user has authenticated
1429 with the administrator's password."
1430 (service xfce-desktop-service-type config))
1431
1432 +\f
1433 ;;;
1434 ;;; Lxqt desktop service.
1435 ;;;
1436
1437 (define-record-type* <lxqt-desktop-configuration> lxqt-desktop-configuration
1438 make-lxqt-desktop-configuration
1439 lxqt-desktop-configuration?
1440 (lxqt lxqt-package
1441 (default lxqt)))
1442
1443 (define (lxqt-polkit-settings config)
1444 "Return the list of LXQt dependencies that provide polkit actions and
1445 rules."
1446 (let ((lxqt (lxqt-package config)))
1447 (map (lambda (name)
1448 ((package-direct-input-selector name) lxqt))
1449 '("lxqt-admin"))))
1450
1451 (define lxqt-desktop-service-type
1452 (service-type
1453 (name 'lxqt-desktop)
1454 (extensions
1455 (list (service-extension polkit-service-type
1456 lxqt-polkit-settings)
1457 (service-extension profile-service-type
1458 (compose list lxqt-package))))
1459 (default-value (lxqt-desktop-configuration))
1460 (description "Run LXQt desktop environment.")))
1461
1462 \f
1463 ;;;
1464 ;;; X11 socket directory service
1465 ;;;
1466
1467 (define x11-socket-directory-service
1468 ;; Return a service that creates /tmp/.X11-unix. When using X11, libxcb
1469 ;; takes care of creating that directory. However, when using XWayland, we
1470 ;; need to create beforehand. Thus, create it unconditionally here.
1471 (simple-service 'x11-socket-directory
1472 activation-service-type
1473 (with-imported-modules '((guix build utils))
1474 #~(begin
1475 (use-modules (guix build utils))
1476 (let ((directory "/tmp/.X11-unix"))
1477 (mkdir-p directory)
1478 (chmod directory #o1777))))))
1479 \f
1480 ;;;
1481 ;;; Enlightenment desktop service.
1482 ;;;
1483
1484 (define-record-type* <enlightenment-desktop-configuration>
1485 enlightenment-desktop-configuration make-enlightenment-desktop-configuration
1486 enlightenment-desktop-configuration?
1487 ;; <package>
1488 (enlightenment enlightenment-package
1489 (default enlightenment)))
1490
1491 (define (enlightenment-setuid-programs enlightenment-desktop-configuration)
1492 (match-record enlightenment-desktop-configuration
1493 <enlightenment-desktop-configuration>
1494 (enlightenment)
1495 (map file-like->setuid-program
1496 (list (file-append enlightenment
1497 "/lib/enlightenment/utils/enlightenment_sys")
1498 (file-append enlightenment
1499 "/lib/enlightenment/utils/enlightenment_system")
1500 (file-append enlightenment
1501 "/lib/enlightenment/utils/enlightenment_ckpasswd")))))
1502
1503 (define enlightenment-desktop-service-type
1504 (service-type
1505 (name 'enlightenment-desktop)
1506 (extensions
1507 (list (service-extension dbus-root-service-type
1508 (compose list
1509 (package-direct-input-selector
1510 "efl")
1511 enlightenment-package))
1512 (service-extension setuid-program-service-type
1513 enlightenment-setuid-programs)
1514 (service-extension profile-service-type
1515 (compose list
1516 enlightenment-package))))
1517 (default-value (enlightenment-desktop-configuration))
1518 (description
1519 "Return a service that adds the @code{enlightenment} package to the system
1520 profile, and extends dbus with the ability for @code{efl} to generate
1521 thumbnails and makes setuid the programs which enlightenment needs to function
1522 as expected.")))
1523
1524 \f
1525 ;;;
1526 ;;; inputattach-service-type
1527 ;;;
1528
1529 (define-record-type* <inputattach-configuration>
1530 inputattach-configuration
1531 make-inputattach-configuration
1532 inputattach-configuration?
1533 (device-type inputattach-configuration-device-type
1534 (default "wacom"))
1535 (device inputattach-configuration-device
1536 (default "/dev/ttyS0"))
1537 (baud-rate inputattach-configuration-baud-rate
1538 (default #f))
1539 (log-file inputattach-configuration-log-file
1540 (default #f)))
1541
1542 (define inputattach-shepherd-service
1543 (match-lambda
1544 (($ <inputattach-configuration> type device baud-rate log-file)
1545 (let ((args (append (if baud-rate
1546 (list "--baud" (number->string baud-rate))
1547 '())
1548 (list (string-append "--" type)
1549 device))))
1550 (list (shepherd-service
1551 (provision '(inputattach))
1552 (requirement '(udev))
1553 (documentation "inputattach daemon")
1554 (start #~(make-forkexec-constructor
1555 (cons (string-append #$inputattach
1556 "/bin/inputattach")
1557 (quote #$args))
1558 #:log-file #$log-file))
1559 (stop #~(make-kill-destructor))))))))
1560
1561 (define inputattach-service-type
1562 (service-type
1563 (name 'inputattach)
1564 (extensions
1565 (list (service-extension shepherd-root-service-type
1566 inputattach-shepherd-service)))
1567 (default-value (inputattach-configuration))
1568 (description "Return a service that runs inputattach on a device and
1569 dispatches events from it.")))
1570
1571 \f
1572 ;;;
1573 ;;; gnome-keyring-service-type
1574 ;;;
1575
1576 (define-record-type* <gnome-keyring-configuration> gnome-keyring-configuration
1577 make-gnome-keyring-configuration
1578 gnome-keyring-configuration?
1579 (keyring gnome-keyring-package (default gnome-keyring))
1580 (pam-services gnome-keyring-pam-services (default '(("gdm-password" . login)
1581 ("passwd" . passwd)))))
1582
1583 (define (pam-gnome-keyring config)
1584 (define (%pam-keyring-entry . arguments)
1585 (pam-entry
1586 (control "optional")
1587 (module (file-append (gnome-keyring-package config)
1588 "/lib/security/pam_gnome_keyring.so"))
1589 (arguments arguments)))
1590
1591 (list
1592 (lambda (service)
1593 (case (assoc-ref (gnome-keyring-pam-services config)
1594 (pam-service-name service))
1595 ((login)
1596 (pam-service
1597 (inherit service)
1598 (auth (append (pam-service-auth service)
1599 (list (%pam-keyring-entry))))
1600 (session (append (pam-service-session service)
1601 (list (%pam-keyring-entry "auto_start"))))))
1602 ((passwd)
1603 (pam-service
1604 (inherit service)
1605 (password (append (pam-service-password service)
1606 (list (%pam-keyring-entry))))))
1607 (else service)))))
1608
1609 (define gnome-keyring-service-type
1610 (service-type
1611 (name 'gnome-keyring)
1612 (extensions (list
1613 (service-extension pam-root-service-type pam-gnome-keyring)))
1614 (default-value (gnome-keyring-configuration))
1615 (description "Return a service, that adds the @code{gnome-keyring} package
1616 to the system profile and extends PAM with entries using
1617 @code{pam_gnome_keyring.so}, unlocking a user's login keyring when they log in
1618 or setting its password with passwd.")))
1619
1620 \f
1621 ;;;
1622 ;;; polkit-wheel-service -- Allow wheel group to perform admin actions
1623 ;;;
1624
1625 (define polkit-wheel
1626 (file-union
1627 "polkit-wheel"
1628 `(("share/polkit-1/rules.d/wheel.rules"
1629 ,(plain-file
1630 "wheel.rules"
1631 "polkit.addAdminRule(function(action, subject) {
1632 return [\"unix-group:wheel\"];
1633 });
1634 ")))))
1635
1636 (define polkit-wheel-service
1637 (simple-service 'polkit-wheel polkit-service-type (list polkit-wheel)))
1638
1639 \f
1640 ;;;
1641 ;;; seatd-service-type -- minimal seat management daemon
1642 ;;;
1643
1644 (define-record-type* <seatd-configuration> seatd-configuration
1645 make-seatd-configuration
1646 seatd-configuration?
1647 (seatd seatd-package (default seatd))
1648 (user seatd-user (default "root"))
1649 (group seatd-group (default "users"))
1650 (socket seatd-socket (default "/run/seatd.sock"))
1651 (logfile seatd-logfile (default "/var/log/seatd.log"))
1652 (loglevel seatd-loglevel (default "info")))
1653
1654 (define (seatd-shepherd-service config)
1655 (list (shepherd-service
1656 (documentation "Minimal seat management daemon")
1657 (requirement '())
1658 ;; TODO: once cgroups is separate dependency
1659 ;; here we should depend on it rather than elogind
1660 (provision '(seatd elogind))
1661 (start #~(make-forkexec-constructor
1662 (list #$(file-append (seatd-package config) "/bin/seatd")
1663 "-u" #$(seatd-user config)
1664 "-g" #$(seatd-group config))
1665 #:environment-variables
1666 (list (string-append "SEATD_LOGLEVEL="
1667 #$(seatd-loglevel config))
1668 (string-append "SEATD_DEFAULTPATH="
1669 #$(seatd-socket config)))
1670 #:log-file #$(seatd-logfile config)))
1671 (stop #~(make-kill-destructor)))))
1672
1673 (define seatd-environment
1674 (match-lambda
1675 (($ <seatd-configuration> _ _ _ socket)
1676 `(("SEATD_SOCK" . ,socket)))))
1677
1678 (define seatd-service-type
1679 (service-type
1680 (name 'seatd)
1681 (description "Seat management takes care of mediating access
1682 to shared devices (graphics, input), without requiring the
1683 applications needing access to be root.")
1684 (extensions
1685 (list
1686 (service-extension session-environment-service-type seatd-environment)
1687 ;; TODO: once cgroups is separate dependency we should not mount it here
1688 ;; for now it is mounted here, because elogind mounts it
1689 (service-extension file-system-service-type (const %control-groups))
1690 (service-extension shepherd-root-service-type seatd-shepherd-service)))
1691 (default-value (seatd-configuration))))
1692
1693 \f
1694 ;;;
1695 ;;; The default set of desktop services.
1696 ;;;
1697
1698 (define* (desktop-services-for-system #:optional
1699 (system (or (%current-target-system)
1700 (%current-system))))
1701 ;; List of services typically useful for a "desktop" use case.
1702
1703 ;; Since GDM depends on Rust (gdm -> gnome-shell -> gjs -> mozjs -> rust)
1704 ;; and Rust is currently unavailable on non-x86_64 platforms, default to
1705 ;; SDDM there (FIXME).
1706 (cons* (if (string-prefix? "x86_64" system)
1707 (service gdm-service-type)
1708 (service sddm-service-type))
1709
1710 ;; Screen lockers are a pretty useful thing and these are small.
1711 (screen-locker-service slock)
1712 (screen-locker-service xlockmore "xlock")
1713
1714 ;; Add udev rules for MTP devices so that non-root users can access
1715 ;; them.
1716 (simple-service 'mtp udev-service-type (list libmtp))
1717 ;; Add udev rules for scanners.
1718 (service sane-service-type)
1719 ;; Add polkit rules, so that non-root users in the wheel group can
1720 ;; perform administrative tasks (similar to "sudo").
1721 polkit-wheel-service
1722
1723 ;; Allow desktop users to also mount NTFS and NFS file systems
1724 ;; without root.
1725 (simple-service 'mount-setuid-helpers setuid-program-service-type
1726 (map (lambda (program)
1727 (setuid-program
1728 (program program)))
1729 (list (file-append nfs-utils "/sbin/mount.nfs")
1730 (file-append ntfs-3g "/sbin/mount.ntfs-3g"))))
1731
1732 ;; The global fontconfig cache directory can sometimes contain
1733 ;; stale entries, possibly referencing fonts that have been GC'd,
1734 ;; so mount it read-only.
1735 fontconfig-file-system-service
1736
1737 ;; NetworkManager and its applet.
1738 (service network-manager-service-type)
1739 (service wpa-supplicant-service-type) ;needed by NetworkManager
1740 (simple-service 'network-manager-applet
1741 profile-service-type
1742 (list network-manager-applet))
1743 (service modem-manager-service-type)
1744 (service usb-modeswitch-service-type)
1745
1746 ;; The D-Bus clique.
1747 (service avahi-service-type)
1748 (udisks-service)
1749 (service upower-service-type)
1750 (accountsservice-service)
1751 (service cups-pk-helper-service-type)
1752 (service colord-service-type)
1753 (geoclue-service)
1754 (service polkit-service-type)
1755 (elogind-service)
1756 (dbus-service)
1757
1758 (service ntp-service-type)
1759
1760 x11-socket-directory-service
1761
1762 (service pulseaudio-service-type)
1763 (service alsa-service-type)
1764
1765 %base-services))
1766
1767 (define-syntax %desktop-services
1768 (identifier-syntax (desktop-services-for-system)))
1769
1770 ;;; desktop.scm ends here