services: Add 'nix-service-type'.
[jackhill/guix/guix.git] / gnu / services / base.scm
CommitLineData
db4fdc04 1;;; GNU Guix --- Functional package management for GNU
65a67bf7 2;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
34044d55 3;;; Copyright © 2015, 2016 Alex Kost <alezost@gmail.com>
5f4a446d 4;;; Copyright © 2015, 2016 Mark H Weaver <mhw@netris.org>
e10964ef 5;;; Copyright © 2015 Sou Bunnbu <iyzsong@gmail.com>
93d32da9 6;;; Copyright © 2016, 2017 Leo Famulari <leo@famulari.name>
b58cbf9a 7;;; Copyright © 2016 David Craven <david@craven.ch>
909147e4 8;;; Copyright © 2016 Ricardo Wurmus <rekado@elephly.net>
2d9dace8 9;;; Copyright © 2018 Mathieu Othacehe <m.othacehe@gmail.com>
db903549 10;;; Copyright © 2019 Efraim Flashner <efraim@flashner.co.il>
db4fdc04
LC
11;;;
12;;; This file is part of GNU Guix.
13;;;
14;;; GNU Guix is free software; you can redistribute it and/or modify it
15;;; under the terms of the GNU General Public License as published by
16;;; the Free Software Foundation; either version 3 of the License, or (at
17;;; your option) any later version.
18;;;
19;;; GNU Guix is distributed in the hope that it will be useful, but
20;;; WITHOUT ANY WARRANTY; without even the implied warranty of
21;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22;;; GNU General Public License for more details.
23;;;
24;;; You should have received a copy of the GNU General Public License
25;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
26
27(define-module (gnu services base)
e87f0591 28 #:use-module (guix store)
65a67bf7 29 #:use-module (guix deprecation)
db4fdc04 30 #:use-module (gnu services)
0190c1c0 31 #:use-module (gnu services shepherd)
6e828634 32 #:use-module (gnu system pam)
db4fdc04 33 #:use-module (gnu system shadow) ; 'user-account', etc.
d1ff5f9d 34 #:use-module (gnu system uuid)
0adfe95a 35 #:use-module (gnu system file-systems) ; 'file-system', etc.
060d62a7 36 #:use-module (gnu system mapped-devices)
278d486b
LC
37 #:use-module ((gnu system linux-initrd)
38 #:select (file-system-packages))
db4fdc04 39 #:use-module (gnu packages admin)
151a2c07 40 #:use-module ((gnu packages linux)
b58cbf9a 41 #:select (alsa-utils crda eudev e2fsprogs fuse gpm kbd lvm2 rng-tools))
db4fdc04 42 #:use-module ((gnu packages base)
412701b0 43 #:select (canonical-package glibc glibc-utf8-locales))
387e1754 44 #:use-module (gnu packages bash)
db4fdc04 45 #:use-module (gnu packages package-management)
8b3ad455 46 #:use-module ((gnu packages gnupg) #:select (guile-gcrypt))
9ee4c9ab 47 #:use-module (gnu packages linux)
46ec2707 48 #:use-module (gnu packages terminals)
e2f4b305 49 #:use-module ((gnu build file-systems)
2c071ce9 50 #:select (mount-flags->bit-mask))
b5f4e686 51 #:use-module (guix gexp)
6454b333 52 #:use-module (guix records)
943e1b97 53 #:use-module (guix modules)
8b3ad455 54 #:use-module ((guix self) #:select (make-config.scm))
db4fdc04
LC
55 #:use-module (srfi srfi-1)
56 #:use-module (srfi srfi-26)
6454b333 57 #:use-module (ice-9 match)
db4fdc04 58 #:use-module (ice-9 format)
e43e84ba
LC
59 #:export (fstab-service-type
60 root-file-system-service
aa1145df 61 file-system-service-type
2a13d05e 62 swap-service
206a28d8 63 user-processes-service-type
a00dd9fb 64 host-name-service
5eca9459 65 console-keymap-service
4a84a487
LC
66 %default-console-font
67 console-font-service-type
62ca0fdf 68 console-font-service
bb3062ad 69 virtual-terminal-service-type
c797fabe 70
c9436025
DM
71 static-networking
72
73 static-networking?
74 static-networking-interface
75 static-networking-ip
76 static-networking-netmask
77 static-networking-gateway
78 static-networking-requirement
79
80 static-networking-service
81 static-networking-service-type
82
c797fabe
RW
83 udev-configuration
84 udev-configuration?
85 udev-configuration-rules
0adfe95a 86 udev-service-type
151a2c07 87 udev-service
80e6f37e 88 udev-rule
6e644cfd 89 file->udev-rule
66e4f01c 90
317d3b47
DC
91 login-configuration
92 login-configuration?
93 login-service-type
94 login-service
95
9ee4c9ab
LF
96 agetty-configuration
97 agetty-configuration?
98 agetty-service
99 agetty-service-type
100
66e4f01c
LC
101 mingetty-configuration
102 mingetty-configuration?
db4fdc04 103 mingetty-service
cd6f6c22 104 mingetty-service-type
6454b333
LC
105
106 %nscd-default-caches
107 %nscd-default-configuration
108
109 nscd-configuration
110 nscd-configuration?
111
112 nscd-cache
113 nscd-cache?
114
0adfe95a 115 nscd-service-type
db4fdc04 116 nscd-service
ec2e2f6c
DC
117
118 syslog-configuration
119 syslog-configuration?
db4fdc04 120 syslog-service
9009538d 121 syslog-service-type
44abcb28 122 %default-syslog.conf
0adfe95a 123
5b58c28b 124 %default-authorized-guix-keys
0adfe95a
LC
125 guix-configuration
126 guix-configuration?
70dfa4e0
MO
127
128 guix-configuration-guix
129 guix-configuration-build-group
130 guix-configuration-build-accounts
131 guix-configuration-authorize-key?
132 guix-configuration-authorized-keys
133 guix-configuration-use-substitutes?
134 guix-configuration-substitute-urls
135 guix-configuration-extra-options
136 guix-configuration-log-file
70dfa4e0 137
8b198abe 138 guix-service
cd6f6c22 139 guix-service-type
1c52181f
LC
140 guix-publish-configuration
141 guix-publish-configuration?
f1e900a3
LC
142 guix-publish-configuration-guix
143 guix-publish-configuration-port
144 guix-publish-configuration-host
ee2691fa
LC
145 guix-publish-configuration-compression
146 guix-publish-configuration-compression-level ;deprecated
697ddb88 147 guix-publish-configuration-nar-path
a35136cb
LC
148 guix-publish-configuration-cache
149 guix-publish-configuration-ttl
1c52181f
LC
150 guix-publish-service
151 guix-publish-service-type
24e96431
152
153 gpm-configuration
154 gpm-configuration?
8664cc88
LC
155 gpm-service-type
156 gpm-service
0adfe95a 157
9009538d 158 urandom-seed-service-type
a535e122 159 urandom-seed-service
24e96431
160
161 rngd-configuration
162 rngd-configuration?
b58cbf9a
DC
163 rngd-service-type
164 rngd-service
46ec2707
DC
165
166 kmscon-configuration
167 kmscon-configuration?
168 kmscon-service-type
169
909147e4
RW
170 pam-limits-service-type
171 pam-limits-service
a535e122 172
8b198abe 173 %base-services))
db4fdc04
LC
174
175;;; Commentary:
176;;;
177;;; Base system services---i.e., services that 99% of the users will want to
178;;; use.
179;;;
180;;; Code:
181
206a28d8
LC
182
183\f
184;;;
185;;; User processes.
186;;;
187
188(define %do-not-kill-file
189 ;; Name of the file listing PIDs of processes that must survive when halting
190 ;; the system. Typical example is user-space file systems.
191 "/etc/shepherd/do-not-kill")
192
193(define (user-processes-shepherd-service requirements)
194 "Return the 'user-processes' Shepherd service with dependencies on
195REQUIREMENTS (a list of service names).
196
197This is a synchronization point used to make sure user processes and daemons
198get started only after crucial initial services have been started---file
199system mounts, etc. This is similar to the 'sysvinit' target in systemd."
200 (define grace-delay
201 ;; Delay after sending SIGTERM and before sending SIGKILL.
202 4)
203
204 (list (shepherd-service
205 (documentation "When stopped, terminate all user processes.")
206 (provision '(user-processes))
207 (requirement requirements)
208 (start #~(const #t))
209 (stop #~(lambda _
210 (define (kill-except omit signal)
211 ;; Kill all the processes with SIGNAL except those listed
212 ;; in OMIT and the current process.
213 (let ((omit (cons (getpid) omit)))
214 (for-each (lambda (pid)
215 (unless (memv pid omit)
216 (false-if-exception
217 (kill pid signal))))
218 (processes))))
219
220 (define omitted-pids
221 ;; List of PIDs that must not be killed.
222 (if (file-exists? #$%do-not-kill-file)
223 (map string->number
224 (call-with-input-file #$%do-not-kill-file
225 (compose string-tokenize
226 (@ (ice-9 rdelim) read-string))))
227 '()))
228
229 (define (now)
230 (car (gettimeofday)))
231
232 (define (sleep* n)
233 ;; Really sleep N seconds.
234 ;; Work around <http://bugs.gnu.org/19581>.
235 (define start (now))
236 (let loop ((elapsed 0))
237 (when (> n elapsed)
238 (sleep (- n elapsed))
239 (loop (- (now) start)))))
240
241 (define lset= (@ (srfi srfi-1) lset=))
242
243 (display "sending all processes the TERM signal\n")
244
245 (if (null? omitted-pids)
246 (begin
247 ;; Easy: terminate all of them.
248 (kill -1 SIGTERM)
249 (sleep* #$grace-delay)
250 (kill -1 SIGKILL))
251 (begin
252 ;; Kill them all except OMITTED-PIDS. XXX: We would
253 ;; like to (kill -1 SIGSTOP) to get a fixed list of
254 ;; processes, like 'killall5' does, but that seems
255 ;; unreliable.
256 (kill-except omitted-pids SIGTERM)
257 (sleep* #$grace-delay)
258 (kill-except omitted-pids SIGKILL)
259 (delete-file #$%do-not-kill-file)))
260
261 (let wait ()
262 ;; Reap children, if any, so that we don't end up with
263 ;; zombies and enter an infinite loop.
264 (let reap-children ()
265 (define result
266 (false-if-exception
267 (waitpid WAIT_ANY (if (null? omitted-pids)
268 0
269 WNOHANG))))
270
271 (when (and (pair? result)
272 (not (zero? (car result))))
273 (reap-children)))
274
275 (let ((pids (processes)))
276 (unless (lset= = pids (cons 1 omitted-pids))
277 (format #t "waiting for process termination\
278 (processes left: ~s)~%"
279 pids)
280 (sleep* 2)
281 (wait))))
282
283 (display "all processes have been terminated\n")
284 #f))
285 (respawn? #f))))
286
287(define user-processes-service-type
288 (service-type
289 (name 'user-processes)
290 (extensions (list (service-extension shepherd-root-service-type
291 user-processes-shepherd-service)))
292 (compose concatenate)
293 (extend append)
294
295 ;; The value is the list of Shepherd services 'user-processes' depends on.
296 ;; Extensions can add new services to this list.
297 (default-value '())
298
299 (description "The @code{user-processes} service is responsible for
300terminating all the processes so that the root file system can be re-mounted
301read-only, just before rebooting/halting. Processes still running after a few
302seconds after @code{SIGTERM} has been sent are terminated with
303@code{SIGKILL}.")))
304
0adfe95a
LC
305\f
306;;;
307;;; File systems.
308;;;
a00dd9fb 309
e43e84ba
LC
310(define (file-system->fstab-entry file-system)
311 "Return a @file{/etc/fstab} entry for @var{file-system}."
a5acc17a
LC
312 (string-append (match (file-system-device file-system)
313 ((? file-system-label? label)
314 (string-append "LABEL="
0d56d9c7 315 (file-system-label->string label)))
a5acc17a
LC
316 ((? uuid? uuid)
317 (string-append "UUID=" (uuid->string uuid)))
318 ((? string? device)
319 device))
e43e84ba
LC
320 "\t"
321 (file-system-mount-point file-system) "\t"
322 (file-system-type file-system) "\t"
323 (or (file-system-options file-system) "defaults") "\t"
324
325 ;; XXX: Omit the 'fs_freq' and 'fs_passno' fields because we
326 ;; don't have anything sensible to put in there.
327 ))
328
329(define (file-systems->fstab file-systems)
330 "Return a @file{/etc} entry for an @file{fstab} describing
331@var{file-systems}."
332 `(("fstab" ,(plain-file "fstab"
333 (string-append
334 "\
59e80445 335# This file was generated from your Guix configuration. Any changes
e43e84ba
LC
336# will be lost upon reboot or reconfiguration.\n\n"
337 (string-join (map file-system->fstab-entry
338 file-systems)
339 "\n")
340 "\n")))))
341
342(define fstab-service-type
343 ;; The /etc/fstab service.
344 (service-type (name 'fstab)
345 (extensions
346 (list (service-extension etc-service-type
347 file-systems->fstab)))
aa1145df 348 (compose concatenate)
6b9e1fef
LC
349 (extend append)
350 (description
351 "Populate the @file{/etc/fstab} based on the given file
352system objects.")))
e43e84ba 353
d4053c71
AK
354(define %root-file-system-shepherd-service
355 (shepherd-service
be1c2c54
LC
356 (documentation "Take care of the root file system.")
357 (provision '(root-file-system))
358 (start #~(const #t))
359 (stop #~(lambda _
360 ;; Return #f if successfully stopped.
361 (sync)
362
363 (call-with-blocked-asyncs
364 (lambda ()
365 (let ((null (%make-void-port "w")))
34044d55 366 ;; Close 'shepherd.log'.
be1c2c54 367 (display "closing log\n")
34044d55 368 ((@ (shepherd comm) stop-logging))
be1c2c54
LC
369
370 ;; Redirect the default output ports..
371 (set-current-output-port null)
372 (set-current-error-port null)
373
374 ;; Close /dev/console.
375 (for-each close-fdes '(0 1 2))
376
377 ;; At this point, there are no open files left, so the
378 ;; root file system can be re-mounted read-only.
379 (mount #f "/" #f
380 (logior MS_REMOUNT MS_RDONLY)
381 #:update-mtab? #f)
382
383 #f)))))
384 (respawn? #f)))
a00dd9fb 385
0adfe95a 386(define root-file-system-service-type
d4053c71
AK
387 (shepherd-service-type 'root-file-system
388 (const %root-file-system-shepherd-service)))
0adfe95a
LC
389
390(define (root-file-system-service)
391 "Return a service whose sole purpose is to re-mount read-only the root file
392system upon shutdown (aka. cleanly \"umounting\" root.)
393
394This service must be the root of the service dependency graph so that its
d4053c71 395'stop' action is invoked when shepherd is the only process left."
0adfe95a
LC
396 (service root-file-system-service-type #f))
397
d4053c71 398(define (file-system->shepherd-service-name file-system)
0adfe95a
LC
399 "Return the symbol that denotes the service mounting and unmounting
400FILE-SYSTEM."
401 (symbol-append 'file-system-
402 (string->symbol (file-system-mount-point file-system))))
403
d4053c71
AK
404(define (mapped-device->shepherd-service-name md)
405 "Return the symbol that denotes the shepherd service of MD, a <mapped-device>."
e502bf89
LC
406 (symbol-append 'device-mapping-
407 (string->symbol (mapped-device-target md))))
408
d4053c71 409(define dependency->shepherd-service-name
e502bf89
LC
410 (match-lambda
411 ((? mapped-device? md)
d4053c71 412 (mapped-device->shepherd-service-name md))
e502bf89 413 ((? file-system? fs)
d4053c71 414 (file-system->shepherd-service-name fs))))
e502bf89 415
d4053c71 416(define (file-system-shepherd-service file-system)
aa1145df
LC
417 "Return the shepherd service for @var{file-system}, or @code{#f} if
418@var{file-system} is not auto-mounted upon boot."
e43e84ba 419 (let ((target (file-system-mount-point file-system))
e43e84ba 420 (create? (file-system-create-mount-point? file-system))
26e34e1e
DM
421 (dependencies (file-system-dependencies file-system))
422 (packages (file-system-packages (list file-system))))
aa1145df 423 (and (file-system-mount? file-system)
943e1b97
LC
424 (with-imported-modules (source-module-closure
425 '((gnu build file-systems)))
a91c3fc7
LC
426 (shepherd-service
427 (provision (list (file-system->shepherd-service-name file-system)))
c106d03b 428 (requirement `(root-file-system udev
a91c3fc7
LC
429 ,@(map dependency->shepherd-service-name dependencies)))
430 (documentation "Check, mount, and unmount the given file system.")
431 (start #~(lambda args
9970ef61 432 #$(if create?
bf7ef1bb
JD
433 #~(mkdir-p #$target)
434 #t)
9328eafb
LC
435
436 (let (($PATH (getenv "PATH")))
437 ;; Make sure fsck.ext2 & co. can be found.
438 (dynamic-wind
439 (lambda ()
26e34e1e
DM
440 ;; Don’t display the PATH settings.
441 (with-output-to-port (%make-void-port "w")
442 (lambda ()
443 (set-path-environment-variable "PATH"
444 '("bin" "sbin")
445 '#$packages))))
9328eafb
LC
446 (lambda ()
447 (mount-file-system
1c65cca5
LC
448 (spec->file-system
449 '#$(file-system->spec file-system))
9328eafb
LC
450 #:root "/"))
451 (lambda ()
452 (setenv "PATH" $PATH)))
453 #t)))
a91c3fc7
LC
454 (stop #~(lambda args
455 ;; Normally there are no processes left at this point, so
456 ;; TARGET can be safely unmounted.
457
458 ;; Make sure PID 1 doesn't keep TARGET busy.
459 (chdir "/")
460
461 (umount #$target)
462 #f))
463
1c65cca5 464 ;; We need additional modules.
a91c3fc7 465 (modules `(((gnu build file-systems)
bf7ef1bb 466 #:select (mount-file-system))
1c65cca5 467 (gnu system file-systems)
aa1145df 468 ,@%default-modules)))))))
e43e84ba 469
a43aca97
LC
470(define (file-system-shepherd-services file-systems)
471 "Return the list of Shepherd services for FILE-SYSTEMS."
472 (let* ((file-systems (filter file-system-mount? file-systems)))
473 (define sink
474 (shepherd-service
475 (provision '(file-systems))
476 (requirement (cons* 'root-file-system 'user-file-systems
477 (map file-system->shepherd-service-name
478 file-systems)))
479 (documentation "Target for all the initially-mounted file systems")
480 (start #~(const #t))
481 (stop #~(const #f))))
482
6c445817
LC
483 (define known-mount-points
484 (map file-system-mount-point file-systems))
485
486 (define user-unmount
487 (shepherd-service
488 (documentation "Unmount manually-mounted file systems.")
489 (provision '(user-file-systems))
490 (start #~(const #t))
491 (stop #~(lambda args
492 (define (known? mount-point)
493 (member mount-point
494 (cons* "/proc" "/sys" '#$known-mount-points)))
495
496 ;; Make sure we don't keep the user's mount points busy.
497 (chdir "/")
498
499 (for-each (lambda (mount-point)
500 (format #t "unmounting '~a'...~%" mount-point)
501 (catch 'system-error
502 (lambda ()
503 (umount mount-point))
504 (lambda args
505 (let ((errno (system-error-errno args)))
506 (format #t "failed to unmount '~a': ~a~%"
507 mount-point (strerror errno))))))
508 (filter (negate known?) (mount-points)))
509 #f))))
510
511 (cons* sink user-unmount
512 (map file-system-shepherd-service file-systems))))
a43aca97 513
74685a43
LC
514(define (file-system-fstab-entries file-systems)
515 "Return the subset of @var{file-systems} that should have an entry in
516@file{/etc/fstab}."
517 ;; /etc/fstab is about telling fsck(8), mount(8), and umount(8) about
518 ;; relevant file systems they'll have to deal with. That excludes "pseudo"
519 ;; file systems.
520 ;;
521 ;; In particular, things like GIO (part of GLib) use it to determine the set
522 ;; of mounts, which is then used by graphical file managers and desktop
523 ;; environments to display "volume" icons. Thus, we really need to exclude
524 ;; those pseudo file systems from the list.
525 (remove (lambda (file-system)
526 (or (member (file-system-type file-system)
527 %pseudo-file-system-types)
528 (memq 'bind-mount (file-system-flags file-system))))
529 file-systems))
530
0adfe95a 531(define file-system-service-type
aa1145df 532 (service-type (name 'file-systems)
e43e84ba 533 (extensions
d4053c71 534 (list (service-extension shepherd-root-service-type
a43aca97 535 file-system-shepherd-services)
e43e84ba 536 (service-extension fstab-service-type
74685a43 537 file-system-fstab-entries)
206a28d8
LC
538
539 ;; Have 'user-processes' depend on 'file-systems'.
540 (service-extension user-processes-service-type
541 (const '(file-systems)))))
aa1145df 542 (compose concatenate)
6b9e1fef
LC
543 (extend append)
544 (description
545 "Provide Shepherd services to mount and unmount the given
546file systems, as well as corresponding @file{/etc/fstab} entries.")))
0adfe95a 547
d6e2a622 548
0adfe95a 549\f
a535e122
LF
550;;;
551;;; Preserve entropy to seed /dev/urandom on boot.
552;;;
553
554(define %random-seed-file
555 "/var/lib/random-seed")
556
a535e122
LF
557(define (urandom-seed-shepherd-service _)
558 "Return a shepherd service for the /dev/urandom seed."
559 (list (shepherd-service
560 (documentation "Preserve entropy across reboots for /dev/urandom.")
561 (provision '(urandom-seed))
4a32f58a
LC
562
563 ;; Depend on udev so that /dev/hwrng is available.
564 (requirement '(file-systems udev))
565
a535e122
LF
566 (start #~(lambda _
567 ;; On boot, write random seed into /dev/urandom.
568 (when (file-exists? #$%random-seed-file)
569 (call-with-input-file #$%random-seed-file
570 (lambda (seed)
571 (call-with-output-file "/dev/urandom"
572 (lambda (urandom)
573 (dump-port seed urandom))))))
9a56cf2b
LF
574
575 ;; Try writing from /dev/hwrng into /dev/urandom.
576 ;; It seems that the file /dev/hwrng always exists, even
577 ;; when there is no hardware random number generator
578 ;; available. So, we handle a failed read or any other error
579 ;; reported by the operating system.
580 (let ((buf (catch 'system-error
581 (lambda ()
582 (call-with-input-file "/dev/hwrng"
583 (lambda (hwrng)
584 (get-bytevector-n hwrng 512))))
585 ;; Silence is golden...
586 (const #f))))
587 (when buf
588 (call-with-output-file "/dev/urandom"
589 (lambda (urandom)
590 (put-bytevector urandom buf)))))
591
71cb237a
LF
592 ;; Immediately refresh the seed in case the system doesn't
593 ;; shut down cleanly.
594 (call-with-input-file "/dev/urandom"
595 (lambda (urandom)
596 (let ((previous-umask (umask #o077))
597 (buf (make-bytevector 512)))
598 (mkdir-p (dirname #$%random-seed-file))
599 (get-bytevector-n! urandom buf 0 512)
600 (call-with-output-file #$%random-seed-file
601 (lambda (seed)
602 (put-bytevector seed buf)))
603 (umask previous-umask))))
a535e122
LF
604 #t))
605 (stop #~(lambda _
606 ;; During shutdown, write from /dev/urandom into random seed.
607 (let ((buf (make-bytevector 512)))
608 (call-with-input-file "/dev/urandom"
609 (lambda (urandom)
8fe5d95e
LF
610 (let ((previous-umask (umask #o077)))
611 (get-bytevector-n! urandom buf 0 512)
71cb237a 612 (mkdir-p (dirname #$%random-seed-file))
8fe5d95e
LF
613 (call-with-output-file #$%random-seed-file
614 (lambda (seed)
615 (put-bytevector seed buf)))
616 (umask previous-umask))
a535e122
LF
617 #t)))))
618 (modules `((rnrs bytevectors)
619 (rnrs io ports)
620 ,@%default-modules)))))
621
622(define urandom-seed-service-type
623 (service-type (name 'urandom-seed)
624 (extensions
625 (list (service-extension shepherd-root-service-type
4e9fd508
LC
626 urandom-seed-shepherd-service)
627
628 ;; Have 'user-processes' depend on 'urandom-seed'.
629 ;; This ensures that user processes and daemons don't
630 ;; start until we have seeded the PRNG.
631 (service-extension user-processes-service-type
632 (const '(urandom-seed)))))
8faaf8d7 633 (default-value #f)
6b9e1fef
LC
634 (description
635 "Seed the @file{/dev/urandom} pseudo-random number
636generator (RNG) with the value recorded when the system was last shut
637down.")))
a535e122 638
65a67bf7
LC
639(define-deprecated (urandom-seed-service)
640 urandom-seed-service-type
641 (service urandom-seed-service-type))
a535e122 642
b58cbf9a
DC
643
644;;;
645;;; Add hardware random number generator to entropy pool.
646;;;
647
648(define-record-type* <rngd-configuration>
649 rngd-configuration make-rngd-configuration
650 rngd-configuration?
651 (rng-tools rngd-configuration-rng-tools) ;package
652 (device rngd-configuration-device)) ;string
653
654(define rngd-service-type
655 (shepherd-service-type
656 'rngd
657 (lambda (config)
658 (define rng-tools (rngd-configuration-rng-tools config))
659 (define device (rngd-configuration-device config))
660
661 (define rngd-command
9e41130b 662 (list (file-append rng-tools "/sbin/rngd")
b58cbf9a
DC
663 "-f" "-r" device))
664
665 (shepherd-service
666 (documentation "Add TRNG to entropy pool.")
667 (requirement '(udev))
668 (provision '(trng))
669 (start #~(make-forkexec-constructor #$@rngd-command))
670 (stop #~(make-kill-destructor))))))
671
672(define* (rngd-service #:key
673 (rng-tools rng-tools)
674 (device "/dev/hwrng"))
675 "Return a service that runs the @command{rngd} program from @var{rng-tools}
676to add @var{device} to the kernel's entropy pool. The service will fail if
677@var{device} does not exist."
678 (service rngd-service-type
679 (rngd-configuration
680 (rng-tools rng-tools)
681 (device device))))
682
e10964ef 683\f
0adfe95a
LC
684;;;
685;;; Console & co.
686;;;
687
688(define host-name-service-type
d4053c71 689 (shepherd-service-type
00184239 690 'host-name
0adfe95a 691 (lambda (name)
d4053c71 692 (shepherd-service
0adfe95a
LC
693 (documentation "Initialize the machine's host name.")
694 (provision '(host-name))
695 (start #~(lambda _
696 (sethostname #$name)))
697 (respawn? #f)))))
a00dd9fb 698
db4fdc04 699(define (host-name-service name)
51da7ca0 700 "Return a service that sets the host name to @var{name}."
0adfe95a 701 (service host-name-service-type name))
db4fdc04 702
bb3062ad
LC
703(define virtual-terminal-service-type
704 ;; Ensure that virtual terminals run in UTF-8 mode. This is the case by
705 ;; default with recent Linux kernels, but this service allows us to ensure
706 ;; this. This service must start before any 'term-' service so that newly
707 ;; created terminals inherit this property. See
708 ;; <https://bugs.gnu.org/30505> for a discussion.
709 (shepherd-service-type
710 'virtual-terminal
711 (lambda (utf8?)
09b7300c
LC
712 (let ((knob "/sys/module/vt/parameters/default_utf8"))
713 (shepherd-service
714 (documentation "Set virtual terminals in UTF-8 module.")
715 (provision '(virtual-terminal))
716 (requirement '(root-file-system))
717 (start #~(lambda _
718 ;; In containers /sys is read-only so don't insist on
719 ;; writing to this file.
720 (unless (= 1 (call-with-input-file #$knob read))
721 (call-with-output-file #$knob
722 (lambda (port)
723 (display 1 port))))
724 #t))
725 (stop #~(const #f)))))
bb3062ad 726 #t)) ;default to UTF-8
62ca0fdf 727
0adfe95a 728(define console-keymap-service-type
d4053c71 729 (shepherd-service-type
00184239 730 'console-keymap
b3d05f48 731 (lambda (files)
d4053c71 732 (shepherd-service
0adfe95a
LC
733 (documentation (string-append "Load console keymap (loadkeys)."))
734 (provision '(console-keymap))
735 (start #~(lambda _
9fc037fe 736 (zero? (system* #$(file-append kbd "/bin/loadkeys")
b3d05f48 737 #$@files))))
0adfe95a
LC
738 (respawn? #f)))))
739
3a665637
LC
740(define-deprecated (console-keymap-service #:rest files)
741 #f
b3d05f48
AK
742 "Return a service to load console keymaps from @var{files}."
743 (service console-keymap-service-type files))
0adfe95a 744
4a84a487
LC
745(define %default-console-font
746 ;; Note: 'LatGrkCyr-8x16' has the advantage of providing three common
747 ;; scripts as well as glyphs for em dash, quotation marks, and other Unicode
748 ;; codepoints notably found in the UTF-8 manual.
749 "LatGrkCyr-8x16")
750
751(define (console-font-shepherd-services tty+font)
752 "Return a list of Shepherd services for each pair in TTY+FONT."
753 (map (match-lambda
754 ((tty . font)
755 (let ((device (string-append "/dev/" tty)))
756 (shepherd-service
757 (documentation "Load a Unicode console font.")
758 (provision (list (symbol-append 'console-font-
759 (string->symbol tty))))
760
761 ;; Start after mingetty has been started on TTY, otherwise the settings
762 ;; are ignored.
763 (requirement (list (symbol-append 'term-
764 (string->symbol tty))))
765
766 (start #~(lambda _
787e8a80
LC
767 ;; It could be that mingetty is not fully ready yet,
768 ;; which we check by calling 'ttyname'.
769 (let loop ((i 10))
770 (unless (or (zero? i)
771 (call-with-input-file #$device
772 (lambda (port)
773 (false-if-exception (ttyname port)))))
774 (usleep 500)
775 (loop (- i 1))))
776
bb3062ad
LC
777 ;; Assume the VT is already in UTF-8 mode, thanks to
778 ;; the 'virtual-terminal' service.
779 ;;
780 ;; 'setfont' returns EX_OSERR (71) when an
781 ;; KDFONTOP ioctl fails, for example. Like
782 ;; systemd's vconsole support, let's not treat
783 ;; this as an error.
784 (case (status:exit-val
785 (system* #$(file-append kbd "/bin/setfont")
786 "-C" #$device #$font))
787 ((0 71) #t)
788 (else #f))))
4a84a487
LC
789 (stop #~(const #t))
790 (respawn? #f)))))
791 tty+font))
0adfe95a 792
4a84a487
LC
793(define console-font-service-type
794 (service-type (name 'console-fonts)
795 (extensions
796 (list (service-extension shepherd-root-service-type
797 console-font-shepherd-services)))
798 (compose concatenate)
6b9e1fef
LC
799 (extend append)
800 (description
801 "Install the given fonts on the specified ttys (fonts are per
802virtual console on GNU/Linux). The value of this service is a list of
803tty/font pairs like:
804
805@example
806'((\"tty1\" . \"LatGrkCyr-8x16\"))
807@end example\n")))
5eca9459 808
62ca0fdf 809(define* (console-font-service tty #:optional (font "LatGrkCyr-8x16"))
4a84a487
LC
810 "This procedure is deprecated in favor of @code{console-font-service-type}.
811
812Return a service that sets up Unicode support in @var{tty} and loads
62ca0fdf 813@var{font} for that tty (fonts are per virtual console in Linux.)"
4a84a487
LC
814 (simple-service (symbol-append 'console-font- (string->symbol tty))
815 console-font-service-type `((,tty . ,font))))
62ca0fdf 816
317d3b47
DC
817(define %default-motd
818 (plain-file "motd" "This is the GNU operating system, welcome!\n\n"))
819
820(define-record-type* <login-configuration>
821 login-configuration make-login-configuration
822 login-configuration?
823 (motd login-configuration-motd ;file-like
824 (default %default-motd))
825 ;; Allow empty passwords by default so that first-time users can log in when
826 ;; the 'root' account has just been created.
827 (allow-empty-passwords? login-configuration-allow-empty-passwords?
828 (default #t))) ;Boolean
829
830(define (login-pam-service config)
831 "Return the list of PAM service needed for CONF."
832 ;; Let 'login' be known to PAM.
833 (list (unix-pam-service "login"
e6b1a224 834 #:login-uid? #t
317d3b47
DC
835 #:allow-empty-passwords?
836 (login-configuration-allow-empty-passwords? config)
837 #:motd
838 (login-configuration-motd config))))
839
840(define login-service-type
841 (service-type (name 'login)
842 (extensions (list (service-extension pam-root-service-type
6b9e1fef 843 login-pam-service)))
178bce41 844 (default-value (login-configuration))
6b9e1fef
LC
845 (description
846 "Provide a console log-in service as specified by its
847configuration value, a @code{login-configuration} object.")))
317d3b47
DC
848
849(define* (login-service #:optional (config (login-configuration)))
850 "Return a service configure login according to @var{config}, which specifies
851the message of the day, among other things."
852 (service login-service-type config))
853
9ee4c9ab
LF
854(define-record-type* <agetty-configuration>
855 agetty-configuration make-agetty-configuration
856 agetty-configuration?
857 (agetty agetty-configuration-agetty ;<package>
858 (default util-linux))
5a9902c8 859 (tty agetty-configuration-tty) ;string | #f
9ee4c9ab
LF
860 (term agetty-term ;string | #f
861 (default #f))
862 (baud-rate agetty-baud-rate ;string | #f
863 (default #f))
864 (auto-login agetty-auto-login ;list of strings | #f
865 (default #f))
866 (login-program agetty-login-program ;gexp
867 (default (file-append shadow "/bin/login")))
868 (login-pause? agetty-login-pause? ;Boolean
869 (default #f))
870 (eight-bits? agetty-eight-bits? ;Boolean
871 (default #f))
872 (no-reset? agetty-no-reset? ;Boolean
873 (default #f))
874 (remote? agetty-remote? ;Boolean
875 (default #f))
876 (flow-control? agetty-flow-control? ;Boolean
877 (default #f))
878 (host agetty-host ;string | #f
879 (default #f))
880 (no-issue? agetty-no-issue? ;Boolean
881 (default #f))
882 (init-string agetty-init-string ;string | #f
883 (default #f))
884 (no-clear? agetty-no-clear? ;Boolean
885 (default #f))
886 (local-line agetty-local-line ;always | never | auto
887 (default #f))
888 (extract-baud? agetty-extract-baud? ;Boolean
889 (default #f))
890 (skip-login? agetty-skip-login? ;Boolean
891 (default #f))
892 (no-newline? agetty-no-newline? ;Boolean
893 (default #f))
894 (login-options agetty-login-options ;string | #f
895 (default #f))
896 (chroot agetty-chroot ;string | #f
897 (default #f))
898 (hangup? agetty-hangup? ;Boolean
899 (default #f))
900 (keep-baud? agetty-keep-baud? ;Boolean
901 (default #f))
902 (timeout agetty-timeout ;integer | #f
903 (default #f))
904 (detect-case? agetty-detect-case? ;Boolean
905 (default #f))
906 (wait-cr? agetty-wait-cr? ;Boolean
907 (default #f))
908 (no-hints? agetty-no-hints? ;Boolean
909 (default #f))
910 (no-hostname? agetty-no hostname? ;Boolean
911 (default #f))
912 (long-hostname? agetty-long-hostname? ;Boolean
913 (default #f))
914 (erase-characters agetty-erase-characters ;string | #f
915 (default #f))
916 (kill-characters agetty-kill-characters ;string | #f
917 (default #f))
918 (chdir agetty-chdir ;string | #f
919 (default #f))
920 (delay agetty-delay ;integer | #f
921 (default #f))
922 (nice agetty-nice ;integer | #f
923 (default #f))
924 ;; "Escape hatch" for passing arbitrary command-line arguments.
925 (extra-options agetty-extra-options ;list of strings
926 (default '()))
927;;; XXX Unimplemented for now!
928;;; (issue-file agetty-issue-file ;file-like
929;;; (default #f))
930 )
931
5a9902c8
DM
932(define (default-serial-port)
933 "Return a gexp that determines a reasonable default serial port
934to use as the tty. This is primarily useful for headless systems."
935 #~(begin
936 ;; console=device,options
937 ;; device: can be tty0, ttyS0, lp0, ttyUSB0 (serial).
938 ;; options: BBBBPNF. P n|o|e, N number of bits,
939 ;; F flow control (r RTS)
940 (let* ((not-comma (char-set-complement (char-set #\,)))
941 (command (linux-command-line))
942 (agetty-specs (find-long-options "agetty.tty" command))
943 (console-specs (filter (lambda (spec)
944 (and (string-prefix? "tty" spec)
945 (not (or
946 (string-prefix? "tty0" spec)
947 (string-prefix? "tty1" spec)
948 (string-prefix? "tty2" spec)
949 (string-prefix? "tty3" spec)
950 (string-prefix? "tty4" spec)
951 (string-prefix? "tty5" spec)
952 (string-prefix? "tty6" spec)
953 (string-prefix? "tty7" spec)
954 (string-prefix? "tty8" spec)
955 (string-prefix? "tty9" spec)))))
956 (find-long-options "console" command)))
957 (specs (append agetty-specs console-specs)))
958 (match specs
959 (() #f)
960 ((spec _ ...)
961 ;; Extract device name from first spec.
962 (match (string-tokenize spec not-comma)
963 ((device-name _ ...)
964 device-name)))))))
965
9ee4c9ab
LF
966(define agetty-shepherd-service
967 (match-lambda
968 (($ <agetty-configuration> agetty tty term baud-rate auto-login
969 login-program login-pause? eight-bits? no-reset? remote? flow-control?
970 host no-issue? init-string no-clear? local-line extract-baud?
971 skip-login? no-newline? login-options chroot hangup? keep-baud? timeout
972 detect-case? wait-cr? no-hints? no-hostname? long-hostname?
973 erase-characters kill-characters chdir delay nice extra-options)
974 (list
975 (shepherd-service
5a9902c8 976 (modules '((ice-9 match) (gnu build linux-boot)))
9ee4c9ab 977 (documentation "Run agetty on a tty.")
5a9902c8 978 (provision (list (symbol-append 'term- (string->symbol (or tty "auto")))))
9ee4c9ab
LF
979
980 ;; Since the login prompt shows the host name, wait for the 'host-name'
981 ;; service to be done. Also wait for udev essentially so that the tty
982 ;; text is not lost in the middle of kernel messages (see also
983 ;; mingetty-shepherd-service).
984 (requirement '(user-processes host-name udev))
985
c32e3dde
DM
986 (start #~(lambda args
987 (let ((defaulted-tty #$(or tty (default-serial-port))))
988 (apply
989 (if defaulted-tty
990 (make-forkexec-constructor
991 (list #$(file-append util-linux "/sbin/agetty")
992 #$@extra-options
993 #$@(if eight-bits?
994 #~("--8bits")
995 #~())
996 #$@(if no-reset?
997 #~("--noreset")
998 #~())
999 #$@(if remote?
1000 #~("--remote")
1001 #~())
1002 #$@(if flow-control?
1003 #~("--flow-control")
1004 #~())
1005 #$@(if host
1006 #~("--host" #$host)
1007 #~())
1008 #$@(if no-issue?
1009 #~("--noissue")
1010 #~())
1011 #$@(if init-string
1012 #~("--init-string" #$init-string)
1013 #~())
1014 #$@(if no-clear?
1015 #~("--noclear")
1016 #~())
9ee4c9ab
LF
1017;;; FIXME This doesn't work as expected. According to agetty(8), if this option
1018;;; is not passed, then the default is 'auto'. However, in my tests, when that
1019;;; option is selected, agetty never presents the login prompt, and the
1020;;; term-ttyS0 service respawns every few seconds.
c32e3dde
DM
1021 #$@(if local-line
1022 #~(#$(match local-line
1023 ('auto "--local-line=auto")
1024 ('always "--local-line=always")
1025 ('never "-local-line=never")))
1026 #~())
1027 #$@(if tty
1028 #~()
1029 #~("--keep-baud"))
1030 #$@(if extract-baud?
1031 #~("--extract-baud")
1032 #~())
1033 #$@(if skip-login?
1034 #~("--skip-login")
1035 #~())
1036 #$@(if no-newline?
1037 #~("--nonewline")
1038 #~())
1039 #$@(if login-options
1040 #~("--login-options" #$login-options)
1041 #~())
1042 #$@(if chroot
1043 #~("--chroot" #$chroot)
1044 #~())
1045 #$@(if hangup?
1046 #~("--hangup")
1047 #~())
1048 #$@(if keep-baud?
1049 #~("--keep-baud")
1050 #~())
1051 #$@(if timeout
1052 #~("--timeout" #$(number->string timeout))
1053 #~())
1054 #$@(if detect-case?
1055 #~("--detect-case")
1056 #~())
1057 #$@(if wait-cr?
1058 #~("--wait-cr")
1059 #~())
1060 #$@(if no-hints?
1061 #~("--nohints?")
1062 #~())
1063 #$@(if no-hostname?
1064 #~("--nohostname")
1065 #~())
1066 #$@(if long-hostname?
1067 #~("--long-hostname")
1068 #~())
1069 #$@(if erase-characters
1070 #~("--erase-chars" #$erase-characters)
1071 #~())
1072 #$@(if kill-characters
1073 #~("--kill-chars" #$kill-characters)
1074 #~())
1075 #$@(if chdir
1076 #~("--chdir" #$chdir)
1077 #~())
1078 #$@(if delay
1079 #~("--delay" #$(number->string delay))
1080 #~())
1081 #$@(if nice
1082 #~("--nice" #$(number->string nice))
1083 #~())
1084 #$@(if auto-login
1085 (list "--autologin" auto-login)
1086 '())
1087 #$@(if login-program
1088 #~("--login-program" #$login-program)
1089 #~())
1090 #$@(if login-pause?
1091 #~("--login-pause")
1092 #~())
1093 defaulted-tty
1094 #$@(if baud-rate
1095 #~(#$baud-rate)
1096 #~())
1097 #$@(if term
1098 #~(#$term)
1099 #~())))
1100 (const #f)) ; never start.
1101 args))))
9ee4c9ab
LF
1102 (stop #~(make-kill-destructor)))))))
1103
1104(define agetty-service-type
1105 (service-type (name 'agetty)
1106 (extensions (list (service-extension shepherd-root-service-type
6b9e1fef
LC
1107 agetty-shepherd-service)))
1108 (description
1109 "Provide console login using the @command{agetty}
1110program.")))
9ee4c9ab
LF
1111
1112(define* (agetty-service config)
1113 "Return a service to run agetty according to @var{config}, which specifies
1114the tty to run, among other things."
1115 (service agetty-service-type config))
1116
66e4f01c
LC
1117(define-record-type* <mingetty-configuration>
1118 mingetty-configuration make-mingetty-configuration
1119 mingetty-configuration?
1120 (mingetty mingetty-configuration-mingetty ;<package>
1121 (default mingetty))
1122 (tty mingetty-configuration-tty) ;string
66e4f01c
LC
1123 (auto-login mingetty-auto-login ;string | #f
1124 (default #f))
1125 (login-program mingetty-login-program ;gexp
1126 (default #f))
1127 (login-pause? mingetty-login-pause? ;Boolean
317d3b47 1128 (default #f)))
0adfe95a 1129
d4053c71 1130(define mingetty-shepherd-service
0adfe95a 1131 (match-lambda
317d3b47
DC
1132 (($ <mingetty-configuration> mingetty tty auto-login login-program
1133 login-pause?)
0adfe95a 1134 (list
d4053c71 1135 (shepherd-service
0adfe95a
LC
1136 (documentation "Run mingetty on an tty.")
1137 (provision (list (symbol-append 'term- (string->symbol tty))))
1138
1139 ;; Since the login prompt shows the host name, wait for the 'host-name'
1140 ;; service to be done. Also wait for udev essentially so that the tty
1141 ;; text is not lost in the middle of kernel messages (XXX).
bb3062ad 1142 (requirement '(user-processes host-name udev virtual-terminal))
0adfe95a 1143
7e0a6fac
DM
1144 (start #~(make-forkexec-constructor
1145 (list #$(file-append mingetty "/sbin/mingetty")
a043b5b8
LC
1146 "--noclear"
1147
1148 ;; Avoiding 'vhangup' allows us to avoid 'setfont'
1149 ;; errors down the path where various ioctls get
1150 ;; EIO--see 'hung_up_tty_ioctl' in driver/tty/tty_io.c
1151 ;; in Linux.
1152 "--nohangup" #$tty
1153
7e0a6fac
DM
1154 #$@(if auto-login
1155 #~("--autologin" #$auto-login)
1156 #~())
1157 #$@(if login-program
1158 #~("--loginprog" #$login-program)
1159 #~())
1160 #$@(if login-pause?
1161 #~("--loginpause")
1162 #~()))))
0adfe95a
LC
1163 (stop #~(make-kill-destructor)))))))
1164
1165(define mingetty-service-type
1166 (service-type (name 'mingetty)
d4053c71 1167 (extensions (list (service-extension shepherd-root-service-type
6b9e1fef
LC
1168 mingetty-shepherd-service)))
1169 (description
1170 "Provide console login using the @command{mingetty}
1171program.")))
0adfe95a
LC
1172
1173(define* (mingetty-service config)
1174 "Return a service to run mingetty according to @var{config}, which specifies
1175the tty to run, among other things."
1176 (service mingetty-service-type config))
db4fdc04 1177
6454b333
LC
1178(define-record-type* <nscd-configuration> nscd-configuration
1179 make-nscd-configuration
1180 nscd-configuration?
1181 (log-file nscd-configuration-log-file ;string
1182 (default "/var/log/nscd.log"))
1183 (debug-level nscd-debug-level ;integer
1184 (default 0))
1185 ;; TODO: See nscd.conf in glibc for other options to add.
1186 (caches nscd-configuration-caches ;list of <nscd-cache>
b893f1ae
LC
1187 (default %nscd-default-caches))
1188 (name-services nscd-configuration-name-services ;list of <packages>
1189 (default '()))
1190 (glibc nscd-configuration-glibc ;<package>
1191 (default (canonical-package glibc))))
6454b333
LC
1192
1193(define-record-type* <nscd-cache> nscd-cache make-nscd-cache
1194 nscd-cache?
1195 (database nscd-cache-database) ;symbol
1196 (positive-time-to-live nscd-cache-positive-time-to-live) ;integer
1197 (negative-time-to-live nscd-cache-negative-time-to-live
1198 (default 20)) ;integer
1199 (suggested-size nscd-cache-suggested-size ;integer ("default module
1200 ;of hash table")
1201 (default 211))
1202 (check-files? nscd-cache-check-files? ;Boolean
1203 (default #t))
1204 (persistent? nscd-cache-persistent? ;Boolean
1205 (default #t))
1206 (shared? nscd-cache-shared? ;Boolean
1207 (default #t))
1208 (max-database-size nscd-cache-max-database-size ;integer
1209 (default (* 32 (expt 2 20))))
1210 (auto-propagate? nscd-cache-auto-propagate? ;Boolean
1211 (default #t)))
1212
1213(define %nscd-default-caches
1214 ;; Caches that we want to enable by default. Note that when providing an
1215 ;; empty nscd.conf, all caches are disabled.
1216 (list (nscd-cache (database 'hosts)
1217
1218 ;; Aggressively cache the host name cache to improve
1219 ;; privacy and resilience.
1220 (positive-time-to-live (* 3600 12))
1221 (negative-time-to-live 20)
1222 (persistent? #t))
1223
1224 (nscd-cache (database 'services)
1225
1226 ;; Services are unlikely to change, so we can be even more
1227 ;; aggressive.
1228 (positive-time-to-live (* 3600 24))
1229 (negative-time-to-live 3600)
1230 (check-files? #t) ;check /etc/services changes
1231 (persistent? #t))))
1232
1233(define %nscd-default-configuration
1234 ;; Default nscd configuration.
1235 (nscd-configuration))
1236
1237(define (nscd.conf-file config)
1238 "Return the @file{nscd.conf} configuration file for @var{config}, an
1239@code{<nscd-configuration>} object."
1240 (define cache->config
1241 (match-lambda
be1c2c54
LC
1242 (($ <nscd-cache> (= symbol->string database)
1243 positive-ttl negative-ttl size check-files?
1244 persistent? shared? max-size propagate?)
1245 (string-append "\nenable-cache\t" database "\tyes\n"
1246
1247 "positive-time-to-live\t" database "\t"
1248 (number->string positive-ttl) "\n"
1249 "negative-time-to-live\t" database "\t"
1250 (number->string negative-ttl) "\n"
1251 "suggested-size\t" database "\t"
1252 (number->string size) "\n"
1253 "check-files\t" database "\t"
1254 (if check-files? "yes\n" "no\n")
1255 "persistent\t" database "\t"
1256 (if persistent? "yes\n" "no\n")
1257 "shared\t" database "\t"
1258 (if shared? "yes\n" "no\n")
1259 "max-db-size\t" database "\t"
1260 (number->string max-size) "\n"
1261 "auto-propagate\t" database "\t"
1262 (if propagate? "yes\n" "no\n")))))
6454b333
LC
1263
1264 (match config
1265 (($ <nscd-configuration> log-file debug-level caches)
be1c2c54
LC
1266 (plain-file "nscd.conf"
1267 (string-append "\
6454b333 1268# Configuration of libc's name service cache daemon (nscd).\n\n"
be1c2c54
LC
1269 (if log-file
1270 (string-append "logfile\t" log-file)
1271 "")
1272 "\n"
1273 (if debug-level
1274 (string-append "debug-level\t"
1275 (number->string debug-level))
1276 "")
1277 "\n"
1278 (string-concatenate
1279 (map cache->config caches)))))))
6454b333 1280
d3f75179
LC
1281(define (nscd-action-procedure nscd config option)
1282 ;; XXX: This is duplicated from mcron; factorize.
1283 #~(lambda (_ . args)
1284 ;; Run 'nscd' in a pipe so we can explicitly redirect its output to
1285 ;; 'current-output-port', which at this stage is bound to the client
1286 ;; connection.
1287 (let ((pipe (apply open-pipe* OPEN_READ #$nscd
1288 "-f" #$config #$option args)))
1289 (let loop ()
1290 (match (read-line pipe 'concat)
1291 ((? eof-object?)
1292 (catch 'system-error
1293 (lambda ()
1294 (zero? (close-pipe pipe)))
1295 (lambda args
1296 ;; There's a race with the SIGCHLD handler, which could
1297 ;; call 'waitpid' before 'close-pipe' above does. If we
33572a36
LC
1298 ;; get ECHILD, that means we lost the race; in that case, we
1299 ;; cannot tell what the exit code was (FIXME).
d3f75179
LC
1300 (or (= ECHILD (system-error-errno args))
1301 (apply throw args)))))
1302 (line
1303 (display line)
1304 (loop)))))))
1305
1306(define (nscd-actions nscd config)
1307 "Return Shepherd actions for NSCD."
1308 ;; Make this functionality available as actions because that's a simple way
1309 ;; to run the right 'nscd' binary with the right config file.
1310 (list (shepherd-action
1311 (name 'statistics)
1312 (documentation "Display statistics about nscd usage.")
1313 (procedure (nscd-action-procedure nscd config "--statistics")))
1314 (shepherd-action
1315 (name 'invalidate)
1316 (documentation
1317 "Invalidate the given cache--e.g., 'hosts' for host name lookups.")
1318 (procedure (nscd-action-procedure nscd config "--invalidate")))))
1319
d4053c71
AK
1320(define (nscd-shepherd-service config)
1321 "Return a shepherd service for CONFIG, an <nscd-configuration> object."
d3f75179
LC
1322 (let ((nscd (file-append (nscd-configuration-glibc config)
1323 "/sbin/nscd"))
1324 (nscd.conf (nscd.conf-file config))
0adfe95a 1325 (name-services (nscd-configuration-name-services config)))
d4053c71 1326 (list (shepherd-service
0adfe95a
LC
1327 (documentation "Run libc's name service cache daemon (nscd).")
1328 (provision '(nscd))
1329 (requirement '(user-processes))
1330 (start #~(make-forkexec-constructor
d3f75179 1331 (list #$nscd "-f" #$nscd.conf "--foreground")
0adfe95a 1332
04101d99
LC
1333 ;; Wait for the PID file. However, the PID file is
1334 ;; written before nscd is actually listening on its
1335 ;; socket (XXX).
1336 #:pid-file "/var/run/nscd/nscd.pid"
1337
0adfe95a
LC
1338 #:environment-variables
1339 (list (string-append "LD_LIBRARY_PATH="
1340 (string-join
1341 (map (lambda (dir)
1342 (string-append dir "/lib"))
1343 (list #$@name-services))
1344 ":")))))
d3f75179
LC
1345 (stop #~(make-kill-destructor))
1346 (modules `((ice-9 popen) ;for the actions
1347 (ice-9 rdelim)
1348 (ice-9 match)
1349 ,@%default-modules))
1350 (actions (nscd-actions nscd nscd.conf))))))
0adfe95a
LC
1351
1352(define nscd-activation
1353 ;; Actions to take before starting nscd.
1354 #~(begin
1355 (use-modules (guix build utils))
1356 (mkdir-p "/var/run/nscd")
49f9d7f6
LC
1357 (mkdir-p "/var/db/nscd") ;for the persistent cache
1358
1359 ;; In libc 2.25 nscd uses inotify to watch /etc/resolv.conf, but only if
c298fb13
LC
1360 ;; that file exists when it is started. Thus create it here. Note: on
1361 ;; some systems, such as when NetworkManager is used, /etc/resolv.conf
1362 ;; is a symlink, hence 'lstat'.
1363 (unless (false-if-exception (lstat "/etc/resolv.conf"))
49f9d7f6
LC
1364 (call-with-output-file "/etc/resolv.conf"
1365 (lambda (port)
1366 (display "# This is a placeholder.\n" port))))))
0adfe95a
LC
1367
1368(define nscd-service-type
1369 (service-type (name 'nscd)
1370 (extensions
1371 (list (service-extension activation-service-type
1372 (const nscd-activation))
d4053c71
AK
1373 (service-extension shepherd-root-service-type
1374 nscd-shepherd-service)))
0adfe95a
LC
1375
1376 ;; This can be extended by providing additional name services
1377 ;; such as nss-mdns.
1378 (compose concatenate)
1379 (extend (lambda (config name-services)
1380 (nscd-configuration
1381 (inherit config)
1382 (name-services (append
1383 (nscd-configuration-name-services config)
6b9e1fef 1384 name-services)))))
db903549 1385 (default-value %nscd-default-configuration)
6b9e1fef
LC
1386 (description
1387 "Runs libc's @dfn{name service cache daemon} (nscd) with the
1388given configuration---an @code{<nscd-configuration>} object. @xref{Name
1389Service Switch}, for an example.")))
0adfe95a 1390
b893f1ae 1391(define* (nscd-service #:optional (config %nscd-default-configuration))
6454b333 1392 "Return a service that runs libc's name service cache daemon (nscd) with the
b893f1ae
LC
1393given @var{config}---an @code{<nscd-configuration>} object. @xref{Name
1394Service Switch}, for an example."
0adfe95a
LC
1395 (service nscd-service-type config))
1396
ec2e2f6c
DC
1397
1398(define-record-type* <syslog-configuration>
1399 syslog-configuration make-syslog-configuration
1400 syslog-configuration?
1401 (syslogd syslog-configuration-syslogd
9e41130b 1402 (default (file-append inetutils "/libexec/syslogd")))
ec2e2f6c
DC
1403 (config-file syslog-configuration-config-file
1404 (default %default-syslog.conf)))
1405
0adfe95a 1406(define syslog-service-type
d4053c71 1407 (shepherd-service-type
00184239 1408 'syslog
ec2e2f6c 1409 (lambda (config)
d4053c71 1410 (shepherd-service
0adfe95a
LC
1411 (documentation "Run the syslog daemon (syslogd).")
1412 (provision '(syslogd))
1413 (requirement '(user-processes))
1414 (start #~(make-forkexec-constructor
ec2e2f6c 1415 (list #$(syslog-configuration-syslogd config)
afa54a38
LC
1416 "--rcfile" #$(syslog-configuration-config-file config))
1417 #:pid-file "/var/run/syslog.pid"))
0adfe95a 1418 (stop #~(make-kill-destructor))))))
be1c2c54
LC
1419
1420;; Snippet adapted from the GNU inetutils manual.
1421(define %default-syslog.conf
1422 (plain-file "syslog.conf" "
1f3fc60d 1423 # Log all error messages, authentication messages of
db4fdc04
LC
1424 # level notice or higher and anything of level err or
1425 # higher to the console.
1426 # Don't log private authentication messages!
6a191274 1427 *.alert;auth.notice;authpriv.none /dev/console
db4fdc04
LC
1428
1429 # Log anything (except mail) of level info or higher.
1430 # Don't log private authentication messages!
1431 *.info;mail.none;authpriv.none /var/log/messages
1432
b6d8066d
AW
1433 # Like /var/log/messages, but also including \"debug\"-level logs.
1434 *.debug;mail.none;authpriv.none /var/log/debug
1435
db4fdc04
LC
1436 # Same, in a different place.
1437 *.info;mail.none;authpriv.none /dev/tty12
1438
1439 # The authpriv file has restricted access.
1440 authpriv.* /var/log/secure
1441
1442 # Log all the mail messages in one place.
1443 mail.* /var/log/maillog
be1c2c54 1444"))
0adfe95a 1445
ec2e2f6c
DC
1446(define* (syslog-service #:optional (config (syslog-configuration)))
1447 "Return a service that runs @command{syslogd} and takes
1448@var{<syslog-configuration>} as a parameter.
44abcb28
LC
1449
1450@xref{syslogd invocation,,, inetutils, GNU Inetutils}, for more
1451information on the configuration file syntax."
ec2e2f6c
DC
1452 (service syslog-service-type config))
1453
db4fdc04 1454
909147e4
RW
1455(define pam-limits-service-type
1456 (let ((security-limits
1457 ;; Create /etc/security containing the provided "limits.conf" file.
1458 (lambda (limits-file)
1459 `(("security"
1460 ,(computed-file
1461 "security"
1462 #~(begin
1463 (mkdir #$output)
1464 (stat #$limits-file)
1465 (symlink #$limits-file
1466 (string-append #$output "/limits.conf"))))))))
1467 (pam-extension
1468 (lambda (pam)
1469 (let ((pam-limits (pam-entry
1470 (control "required")
1471 (module "pam_limits.so")
1472 (arguments '("conf=/etc/security/limits.conf")))))
1473 (if (member (pam-service-name pam)
1474 '("login" "su" "slim"))
1475 (pam-service
1476 (inherit pam)
1477 (session (cons pam-limits
1478 (pam-service-session pam))))
1479 pam)))))
1480 (service-type
1481 (name 'limits)
1482 (extensions
1483 (list (service-extension etc-service-type security-limits)
1484 (service-extension pam-root-service-type
6b9e1fef
LC
1485 (lambda _ (list pam-extension)))))
1486 (description
1487 "Install the specified resource usage limits by populating
1488@file{/etc/security/limits.conf} and using the @code{pam_limits}
1489authentication module."))))
909147e4
RW
1490
1491(define* (pam-limits-service #:optional (limits '()))
1492 "Return a service that makes selected programs respect the list of
1493pam-limits-entry specified in LIMITS via pam_limits.so."
1494 (service pam-limits-service-type
1495 (plain-file "limits.conf"
1496 (string-join (map pam-limits-entry->string limits)
1497 "\n"))))
1498
1c52181f
LC
1499\f
1500;;;
1501;;; Guix services.
1502;;;
1503
db4fdc04 1504(define* (guix-build-accounts count #:key
ab6a279a 1505 (group "guixbuild")
db4fdc04 1506 (shadow shadow))
309d87c3
LC
1507 "Return a list of COUNT user accounts for Guix build users with the given
1508GID."
5250a4f2
LC
1509 (unfold (cut > <> count)
1510 (lambda (n)
1511 (user-account
1512 (name (format #f "guixbuilder~2,'0d" n))
1513 (system? #t)
5250a4f2
LC
1514 (group group)
1515
1516 ;; guix-daemon expects GROUP to be listed as a
1517 ;; supplementary group too:
1518 ;; <http://lists.gnu.org/archive/html/bug-guix/2013-01/msg00239.html>.
1519 (supplementary-groups (list group "kvm"))
1520
1521 (comment (format #f "Guix Build User ~2d" n))
1522 (home-directory "/var/empty")
9e41130b 1523 (shell (file-append shadow "/sbin/nologin"))))
5250a4f2
LC
1524 1+
1525 1))
db4fdc04 1526
8b3ad455
LC
1527(define not-config?
1528 ;; Select (guix …) and (gnu …) modules, except (guix config).
1529 (match-lambda
1530 (('guix 'config) #f)
1531 (('guix rest ...) #t)
1532 (('gnu rest ...) #t)
1533 (rest #f)))
1534
970ebdae
LC
1535(define (hydra-key-authorization keys guix)
1536 "Return a gexp with code to register KEYS, a list of files containing 'guix
1537archive' public keys, with GUIX."
8b3ad455
LC
1538 (define default-acl
1539 (with-extensions (list guile-gcrypt)
1540 (with-imported-modules `(((guix config) => ,(make-config.scm))
8b3ad455
LC
1541 ,@(source-module-closure '((guix pki))
1542 #:select? not-config?))
1543 (computed-file "acl"
1544 #~(begin
1545 (use-modules (guix pki)
1546 (gcrypt pk-crypto)
1547 (ice-9 rdelim))
1548
1549 (define keys
1550 (map (lambda (file)
1551 (call-with-input-file file
1552 (compose string->canonical-sexp
1553 read-string)))
1554 '(#$@keys)))
1555
1556 (call-with-output-file #$output
1557 (lambda (port)
1558 (write-acl (public-keys->acl keys)
1559 port))))))))
1560
1561 (with-imported-modules '((guix build utils))
1562 #~(begin
1563 (use-modules (guix build utils))
1564
1565 (unless (file-exists? "/etc/guix/acl")
1566 (mkdir-p "/etc/guix")
1567 (copy-file #+default-acl "/etc/guix/acl")
1568 (chmod "/etc/guix/acl" #o600)))))
2c5c696c 1569
5b58c28b
LC
1570(define %default-authorized-guix-keys
1571 ;; List of authorized substitute keys.
c22c9fa5 1572 (list (file-append guix "/share/guix/hydra.gnu.org.pub")
be5622e7 1573 (file-append guix "/share/guix/berlin.guixsd.org.pub")))
5b58c28b 1574
0adfe95a
LC
1575(define-record-type* <guix-configuration>
1576 guix-configuration make-guix-configuration
1577 guix-configuration?
1578 (guix guix-configuration-guix ;<package>
1579 (default guix))
1580 (build-group guix-configuration-build-group ;string
1581 (default "guixbuild"))
1582 (build-accounts guix-configuration-build-accounts ;integer
1583 (default 10))
1584 (authorize-key? guix-configuration-authorize-key? ;Boolean
1585 (default #t))
5b58c28b
LC
1586 (authorized-keys guix-configuration-authorized-keys ;list of gexps
1587 (default %default-authorized-guix-keys))
0adfe95a
LC
1588 (use-substitutes? guix-configuration-use-substitutes? ;Boolean
1589 (default #t))
b0b9f6e0
LC
1590 (substitute-urls guix-configuration-substitute-urls ;list of strings
1591 (default %default-substitute-urls))
88554b5d
LC
1592 (chroot-directories guix-configuration-chroot-directories ;list of file-like/strings
1593 (default '()))
3bee4b61
LC
1594 (max-silent-time guix-configuration-max-silent-time ;integer
1595 (default 0))
1596 (timeout guix-configuration-timeout ;integer
1597 (default 0))
f4596f76
LC
1598 (log-compression guix-configuration-log-compression
1599 (default 'bzip2))
0adfe95a
LC
1600 (extra-options guix-configuration-extra-options ;list of strings
1601 (default '()))
dc0ef095
LC
1602 (log-file guix-configuration-log-file ;string
1603 (default "/var/log/guix-daemon.log"))
93d32da9 1604 (http-proxy guix-http-proxy ;string | #f
b191f0a6
LF
1605 (default #f))
1606 (tmpdir guix-tmpdir ;string | #f
93d32da9 1607 (default #f)))
0adfe95a
LC
1608
1609(define %default-guix-configuration
1610 (guix-configuration))
1611
d4053c71
AK
1612(define (guix-shepherd-service config)
1613 "Return a <shepherd-service> for the Guix daemon service with CONFIG."
f4596f76
LC
1614 (match-record config <guix-configuration>
1615 (guix build-group build-accounts authorize-key? authorized-keys
1616 use-substitutes? substitute-urls max-silent-time timeout
88554b5d
LC
1617 log-compression extra-options log-file http-proxy tmpdir
1618 chroot-directories)
f4596f76
LC
1619 (list (shepherd-service
1620 (documentation "Run the Guix daemon.")
1621 (provision '(guix-daemon))
1622 (requirement '(user-processes))
88554b5d 1623 (modules '((srfi srfi-1)))
f4596f76
LC
1624 (start
1625 #~(make-forkexec-constructor
88554b5d
LC
1626 (cons* #$(file-append guix "/bin/guix-daemon")
1627 "--build-users-group" #$build-group
1628 "--max-silent-time" #$(number->string max-silent-time)
1629 "--timeout" #$(number->string timeout)
1630 "--log-compression" #$(symbol->string log-compression)
1631 #$@(if use-substitutes?
1632 '()
1633 '("--no-substitutes"))
1634 "--substitute-urls" #$(string-join substitute-urls)
1635 #$@extra-options
1636
1637 ;; Add CHROOT-DIRECTORIES and all their dependencies (if
1638 ;; these are store items) to the chroot.
1639 (append-map (lambda (file)
1640 (append-map (lambda (directory)
1641 (list "--chroot-directory"
1642 directory))
1643 (call-with-input-file file
1644 read)))
1645 '#$(map references-file chroot-directories)))
f4596f76
LC
1646
1647 #:environment-variables
1648 (list #$@(if http-proxy
1649 (list (string-append "http_proxy=" http-proxy))
1650 '())
1651 #$@(if tmpdir
1652 (list (string-append "TMPDIR=" tmpdir))
7e4bc215
LC
1653 '())
1654
1655 ;; Make sure we run in a UTF-8 locale so that 'guix
1656 ;; offload' correctly restores nars that contain UTF-8
1657 ;; file names such as 'nss-certs'. See
1658 ;; <https://bugs.gnu.org/32942>.
1659 (string-append "GUIX_LOCPATH="
1660 #$glibc-utf8-locales "/lib/locale")
1661 "LC_ALL=en_US.utf8")
f4596f76
LC
1662
1663 #:log-file #$log-file))
1664 (stop #~(make-kill-destructor))))))
0adfe95a
LC
1665
1666(define (guix-accounts config)
1667 "Return the user accounts and user groups for CONFIG."
1668 (match config
1669 (($ <guix-configuration> _ build-group build-accounts)
1670 (cons (user-group
1671 (name build-group)
1672 (system? #t)
1673
1674 ;; Use a fixed GID so that we can create the store with the right
1675 ;; owner.
1676 (id 30000))
1677 (guix-build-accounts build-accounts
1678 #:group build-group)))))
1679
1680(define (guix-activation config)
1681 "Return the activation gexp for CONFIG."
1682 (match config
5b58c28b 1683 (($ <guix-configuration> guix build-group build-accounts authorize-key? keys)
0adfe95a 1684 ;; Assume that the store has BUILD-GROUP as its group. We could
0af94ad5 1685 ;; otherwise call 'chown' here, but the problem is that on a COW overlayfs,
0adfe95a
LC
1686 ;; chown leads to an entire copy of the tree, which is a bad idea.
1687
0bc02bec 1688 ;; Optionally authorize substitute server keys.
5f4a446d 1689 (if authorize-key?
970ebdae 1690 (hydra-key-authorization keys guix)
5f4a446d 1691 #~#f))))
0adfe95a 1692
88554b5d
LC
1693(define* (references-file item #:optional (name "references"))
1694 "Return a file that contains the list of references of ITEM."
1695 (if (struct? item) ;lowerable object
1696 (computed-file name
1697 (with-imported-modules (source-module-closure
1698 '((guix build store-copy)))
1699 #~(begin
1700 (use-modules (guix build store-copy))
1701
1702 (call-with-output-file #$output
1703 (lambda (port)
6892f0a2
LC
1704 (write (map store-info-item
1705 (call-with-input-file "graph"
1706 read-reference-graph))
88554b5d
LC
1707 port)))))
1708 #:options `(#:local-build? #f
1709 #:references-graphs (("graph" ,item))))
1710 (plain-file name "()")))
1711
0adfe95a
LC
1712(define guix-service-type
1713 (service-type
1714 (name 'guix)
1715 (extensions
d4053c71 1716 (list (service-extension shepherd-root-service-type guix-shepherd-service)
0adfe95a 1717 (service-extension account-service-type guix-accounts)
9a8b9eb8
LC
1718 (service-extension activation-service-type guix-activation)
1719 (service-extension profile-service-type
3d3c5650 1720 (compose list guix-configuration-guix))))
88554b5d
LC
1721
1722 ;; Extensions can specify extra directories to add to the build chroot.
1723 (compose concatenate)
1724 (extend (lambda (config directories)
1725 (guix-configuration
1726 (inherit config)
1727 (chroot-directories
1728 (append (guix-configuration-chroot-directories config)
1729 directories)))))
1730
6b9e1fef
LC
1731 (default-value (guix-configuration))
1732 (description
1733 "Run the build daemon of GNU@tie{}Guix, aka. @command{guix-daemon}.")))
0adfe95a 1734
84a2de36
LC
1735(define-deprecated (guix-service #:optional
1736 (config %default-guix-configuration))
1737 guix-service-type
0adfe95a
LC
1738 "Return a service that runs the Guix build daemon according to
1739@var{config}."
1740 (service guix-service-type config))
1741
1c52181f
LC
1742
1743(define-record-type* <guix-publish-configuration>
1744 guix-publish-configuration make-guix-publish-configuration
1745 guix-publish-configuration?
1746 (guix guix-publish-configuration-guix ;package
1747 (default guix))
1748 (port guix-publish-configuration-port ;number
1749 (default 80))
1750 (host guix-publish-configuration-host ;string
697ddb88 1751 (default "localhost"))
ee2691fa
LC
1752 (compression guix-publish-configuration-compression
1753 (thunked)
1754 (default (default-compression this-record
1755 (current-source-location))))
1756 (compression-level %guix-publish-configuration-compression-level ;deprecated
1757 (default #f))
f2767d3e 1758 (nar-path guix-publish-configuration-nar-path ;string
a35136cb
LC
1759 (default "nar"))
1760 (cache guix-publish-configuration-cache ;#f | string
1761 (default #f))
1762 (workers guix-publish-configuration-workers ;#f | integer
1763 (default #f))
1764 (ttl guix-publish-configuration-ttl ;#f | integer
1765 (default #f)))
1c52181f 1766
ee2691fa
LC
1767(define-deprecated (guix-publish-configuration-compression-level config)
1768 "Return a compression level, the old way."
1769 (match (guix-publish-configuration-compression config)
1770 (((_ level) _ ...) level)))
1771
1772(define (default-compression config properties)
1773 "Return the default 'guix publish' compression according to CONFIG, and
1774raise a deprecation warning if the 'compression-level' field was used."
1775 (match (%guix-publish-configuration-compression-level config)
1776 (#f
1777 '(("gzip" 3)))
1778 (level
1779 (warn-about-deprecation 'compression-level properties
1780 #:replacement 'compression)
1781 `(("gzip" ,level)))))
1782
1783(define (guix-publish-shepherd-service config)
1784 (define (config->compression-options config)
1785 (match (guix-publish-configuration-compression config)
1786 (() ;empty list means "no compression"
1787 '("-C0"))
1788 (lst
1789 (append-map (match-lambda
1790 ((type level)
1791 `("-C" ,(string-append type ":"
1792 (number->string level)))))
1793 lst))))
1794
1795 (match-record config <guix-publish-configuration>
1796 (guix port host nar-path cache workers ttl)
1797 (list (shepherd-service
1798 (provision '(guix-publish))
1799 (requirement '(guix-daemon))
1800 (start #~(make-forkexec-constructor
1801 (list #$(file-append guix "/bin/guix")
1802 "publish" "-u" "guix-publish"
1803 "-p" #$(number->string port)
1804 #$@(config->compression-options config)
1805 (string-append "--nar-path=" #$nar-path)
1806 (string-append "--listen=" #$host)
1807 #$@(if workers
1808 #~((string-append "--workers="
1809 #$(number->string
1810 workers)))
1811 #~())
1812 #$@(if ttl
1813 #~((string-append "--ttl="
1814 #$(number->string ttl)
1815 "s"))
1816 #~())
1817 #$@(if cache
1818 #~((string-append "--cache=" #$cache))
1819 #~()))
1820
1821 ;; Make sure we run in a UTF-8 locale so we can produce
1822 ;; nars for packages that contain UTF-8 file names such
1823 ;; as 'nss-certs'. See <https://bugs.gnu.org/26948>.
1824 #:environment-variables
1825 (list (string-append "GUIX_LOCPATH="
1826 #$glibc-utf8-locales "/lib/locale")
1827 "LC_ALL=en_US.utf8")))
1828 (stop #~(make-kill-destructor))))))
1c52181f
LC
1829
1830(define %guix-publish-accounts
1831 (list (user-group (name "guix-publish") (system? #t))
1832 (user-account
1833 (name "guix-publish")
1834 (group "guix-publish")
1835 (system? #t)
1836 (comment "guix publish user")
1837 (home-directory "/var/empty")
9e41130b 1838 (shell (file-append shadow "/sbin/nologin")))))
1c52181f 1839
a35136cb
LC
1840(define (guix-publish-activation config)
1841 (let ((cache (guix-publish-configuration-cache config)))
1842 (if cache
1843 (with-imported-modules '((guix build utils))
1844 #~(begin
1845 (use-modules (guix build utils))
1846
1847 (mkdir-p #$cache)
1848 (let* ((pw (getpw "guix-publish"))
1849 (uid (passwd:uid pw))
1850 (gid (passwd:gid pw)))
1851 (chown #$cache uid gid))))
1852 #t)))
1853
1c52181f
LC
1854(define guix-publish-service-type
1855 (service-type (name 'guix-publish)
1856 (extensions
d4053c71
AK
1857 (list (service-extension shepherd-root-service-type
1858 guix-publish-shepherd-service)
1c52181f 1859 (service-extension account-service-type
a35136cb
LC
1860 (const %guix-publish-accounts))
1861 (service-extension activation-service-type
1862 guix-publish-activation)))
6b9e1fef
LC
1863 (default-value (guix-publish-configuration))
1864 (description
1865 "Add a Shepherd service running @command{guix publish}, a
1866command that allows you to share pre-built binaries with others over HTTP.")))
1c52181f 1867
84a2de36
LC
1868(define-deprecated (guix-publish-service #:key (guix guix)
1869 (port 80) (host "localhost"))
1870 guix-publish-service-type
1c52181f
LC
1871 "Return a service that runs @command{guix publish} listening on @var{host}
1872and @var{port} (@pxref{Invoking guix publish}).
1873
1874This assumes that @file{/etc/guix} already contains a signing key pair as
1875created by @command{guix archive --generate-key} (@pxref{Invoking guix
1876archive}). If that is not the case, the service will fail to start."
f1e900a3 1877 ;; Deprecated.
1c52181f
LC
1878 (service guix-publish-service-type
1879 (guix-publish-configuration (guix guix) (port port) (host host))))
1880
0adfe95a
LC
1881\f
1882;;;
1883;;; Udev.
1884;;;
1885
1886(define-record-type* <udev-configuration>
1887 udev-configuration make-udev-configuration
1888 udev-configuration?
1889 (udev udev-configuration-udev ;<package>
fd779db9 1890 (default eudev))
0adfe95a
LC
1891 (rules udev-configuration-rules ;list of <package>
1892 (default '())))
db4fdc04 1893
ecd06ca9
LC
1894(define (udev-rules-union packages)
1895 "Return the union of the @code{lib/udev/rules.d} directories found in each
1896item of @var{packages}."
1897 (define build
4ee96a79
LC
1898 (with-imported-modules '((guix build union)
1899 (guix build utils))
1900 #~(begin
1901 (use-modules (guix build union)
1902 (guix build utils)
1903 (srfi srfi-1)
1904 (srfi srfi-26))
ecd06ca9 1905
4ee96a79
LC
1906 (define %standard-locations
1907 '("/lib/udev/rules.d" "/libexec/udev/rules.d"))
ecd06ca9 1908
4ee96a79
LC
1909 (define (rules-sub-directory directory)
1910 ;; Return the sub-directory of DIRECTORY containing udev rules, or
1911 ;; #f if none was found.
1912 (find directory-exists?
1913 (map (cut string-append directory <>) %standard-locations)))
ecd06ca9 1914
4ee96a79
LC
1915 (mkdir-p (string-append #$output "/lib/udev"))
1916 (union-build (string-append #$output "/lib/udev/rules.d")
1917 (filter-map rules-sub-directory '#$packages)))))
ecd06ca9 1918
4ee96a79 1919 (computed-file "udev-rules" build))
ecd06ca9 1920
80e6f37e
RW
1921(define (udev-rule file-name contents)
1922 "Return a directory with a udev rule file FILE-NAME containing CONTENTS."
1923 (computed-file file-name
4ee96a79
LC
1924 (with-imported-modules '((guix build utils))
1925 #~(begin
1926 (use-modules (guix build utils))
1927
1928 (define rules.d
1929 (string-append #$output "/lib/udev/rules.d"))
1930
1931 (mkdir-p rules.d)
1932 (call-with-output-file
1933 (string-append rules.d "/" #$file-name)
1934 (lambda (port)
1935 (display #$contents port)))))))
7f28bf9a 1936
6e644cfd
MC
1937(define (file->udev-rule file-name file)
1938 "Return a directory with a udev rule file FILE-NAME which is a copy of FILE."
1939 (computed-file file-name
1940 (with-imported-modules '((guix build utils))
1941 #~(begin
1942 (use-modules (guix build utils))
1943
1944 (define rules.d
1945 (string-append #$output "/lib/udev/rules.d"))
1946
1947 (define file-copy-dest
1948 (string-append rules.d "/" #$file-name))
1949
1950 (mkdir-p rules.d)
1951 (copy-file #$file file-copy-dest)))))
1952
80e6f37e
RW
1953(define kvm-udev-rule
1954 ;; Return a directory with a udev rule that changes the group of /dev/kvm to
1955 ;; "kvm" and makes it #o660. Apparently QEMU-KVM used to ship this rule,
1956 ;; but now we have to add it by ourselves.
1957
1958 ;; Build users are part of the "kvm" group, so we can fearlessly make
1959 ;; /dev/kvm 660 (see <http://bugs.gnu.org/18994>, for background.)
1960 (udev-rule "90-kvm.rules"
1961 "KERNEL==\"kvm\", GROUP=\"kvm\", MODE=\"0660\"\n"))
1962
d4053c71
AK
1963(define udev-shepherd-service
1964 ;; Return a <shepherd-service> for UDEV with RULES.
0adfe95a
LC
1965 (match-lambda
1966 (($ <udev-configuration> udev rules)
80e6f37e 1967 (let* ((rules (udev-rules-union (cons* udev kvm-udev-rule rules)))
0adfe95a
LC
1968 (udev.conf (computed-file "udev.conf"
1969 #~(call-with-output-file #$output
1970 (lambda (port)
1971 (format port
1972 "udev_rules=\"~a/lib/udev/rules.d\"\n"
1973 #$rules))))))
1974 (list
d4053c71 1975 (shepherd-service
0adfe95a
LC
1976 (provision '(udev))
1977
1978 ;; Udev needs /dev to be a 'devtmpfs' mount so that new device nodes can
1979 ;; be added: see
1980 ;; <http://www.linuxfromscratch.org/lfs/view/development/chapter07/udev.html>.
1981 (requirement '(root-file-system))
1982
1983 (documentation "Populate the /dev directory, dynamically.")
1984 (start #~(lambda ()
0adfe95a 1985 (define udevd
7fd30825
LC
1986 ;; 'udevd' from eudev.
1987 #$(file-append udev "/sbin/udevd"))
0adfe95a
LC
1988
1989 (define (wait-for-udevd)
1990 ;; Wait until someone's listening on udevd's control
1991 ;; socket.
1992 (let ((sock (socket AF_UNIX SOCK_SEQPACKET 0)))
1993 (let try ()
1994 (catch 'system-error
1995 (lambda ()
1996 (connect sock PF_UNIX "/run/udev/control")
1997 (close-port sock))
1998 (lambda args
1999 (format #t "waiting for udevd...~%")
2000 (usleep 500000)
2001 (try))))))
2002
2003 ;; Allow udev to find the modules.
2004 (setenv "LINUX_MODULE_DIRECTORY"
2005 "/run/booted-system/kernel/lib/modules")
2006
2007 ;; The first one is for udev, the second one for eudev.
2008 (setenv "UDEV_CONFIG_FILE" #$udev.conf)
2009 (setenv "EUDEV_RULES_DIRECTORY"
9fc037fe 2010 #$(file-append rules "/lib/udev/rules.d"))
0adfe95a 2011
86e6b4c9
DM
2012 (let* ((kernel-release
2013 (utsname:release (uname)))
2014 (linux-module-directory
2015 (getenv "LINUX_MODULE_DIRECTORY"))
2016 (directory
2017 (string-append linux-module-directory "/"
2018 kernel-release))
2019 (old-umask (umask #o022)))
23784f0c
LC
2020 ;; If we're in a container, DIRECTORY might not exist,
2021 ;; for instance because the host runs a different
2022 ;; kernel. In that case, skip it; we'll just miss a few
2023 ;; nodes like /dev/fuse.
2024 (when (file-exists? directory)
2025 (make-static-device-nodes directory))
86e6b4c9
DM
2026 (umask old-umask))
2027
7fd30825
LC
2028 (let ((pid (fork+exec-command (list udevd))))
2029 ;; Wait until udevd is up and running. This appears to
2030 ;; be needed so that the events triggered below are
2031 ;; actually handled.
2032 (wait-for-udevd)
2033
2034 ;; Trigger device node creation.
2035 (system* #$(file-append udev "/bin/udevadm")
2036 "trigger" "--action=add")
2037
2038 ;; Wait for things to settle down.
2039 (system* #$(file-append udev "/bin/udevadm")
2040 "settle")
2041 pid)))
0adfe95a
LC
2042 (stop #~(make-kill-destructor))
2043
2044 ;; When halting the system, 'udev' is actually killed by
2045 ;; 'user-processes', i.e., before its own 'stop' method was called.
2046 ;; Thus, make sure it is not respawned.
86e6b4c9
DM
2047 (respawn? #f)
2048 ;; We need additional modules.
2049 (modules `((gnu build linux-boot)
bafcf1f3
LC
2050 ,@%default-modules))
2051
2052 (actions (list (shepherd-action
2053 (name 'rules)
2054 (documentation "Display the directory containing
2055the udev rules in use.")
2056 (procedure #~(lambda (_)
2057 (display #$rules)
2058 (newline))))))))))))
0adfe95a
LC
2059
2060(define udev-service-type
2061 (service-type (name 'udev)
2062 (extensions
d4053c71
AK
2063 (list (service-extension shepherd-root-service-type
2064 udev-shepherd-service)))
0adfe95a
LC
2065
2066 (compose concatenate) ;concatenate the list of rules
2067 (extend (lambda (config rules)
2068 (match config
2069 (($ <udev-configuration> udev initial-rules)
2070 (udev-configuration
2071 (udev udev)
6b9e1fef 2072 (rules (append initial-rules rules)))))))
fd779db9 2073 (default-value (udev-configuration))
6b9e1fef
LC
2074 (description
2075 "Run @command{udev}, which populates the @file{/dev}
2076directory dynamically. Get extra rules from the packages listed in the
2077@code{rules} field of its value, @code{udev-configuration} object.")))
0adfe95a 2078
255f7308 2079(define* (udev-service #:key (udev eudev) (rules '()))
ecd06ca9
LC
2080 "Run @var{udev}, which populates the @file{/dev} directory dynamically. Get
2081extra rules from the packages listed in @var{rules}."
0adfe95a
LC
2082 (service udev-service-type
2083 (udev-configuration (udev udev) (rules rules))))
2084
0adfe95a 2085(define swap-service-type
d4053c71 2086 (shepherd-service-type
00184239 2087 'swap
0adfe95a
LC
2088 (lambda (device)
2089 (define requirement
2090 (if (string-prefix? "/dev/mapper/" device)
2091 (list (symbol-append 'device-mapping-
2092 (string->symbol (basename device))))
2093 '()))
2094
d4053c71 2095 (shepherd-service
0adfe95a
LC
2096 (provision (list (symbol-append 'swap- (string->symbol device))))
2097 (requirement `(udev ,@requirement))
2098 (documentation "Enable the given swap device.")
2099 (start #~(lambda ()
2100 (restart-on-EINTR (swapon #$device))
2101 #t))
2102 (stop #~(lambda _
2103 (restart-on-EINTR (swapoff #$device))
2104 #f))
2105 (respawn? #f)))))
5dae0186 2106
2a13d05e
LC
2107(define (swap-service device)
2108 "Return a service that uses @var{device} as a swap device."
0adfe95a 2109 (service swap-service-type device))
2a13d05e 2110
5986e941
LC
2111(define %default-gpm-options
2112 ;; Default options for GPM.
2113 '("-m" "/dev/input/mice" "-t" "ps2"))
2114
8664cc88
LC
2115(define-record-type* <gpm-configuration>
2116 gpm-configuration make-gpm-configuration gpm-configuration?
5986e941
LC
2117 (gpm gpm-configuration-gpm ;package
2118 (default gpm))
2119 (options gpm-configuration-options ;list of strings
2120 (default %default-gpm-options)))
8664cc88 2121
d4053c71 2122(define gpm-shepherd-service
8664cc88 2123 (match-lambda
a907d997 2124 (($ <gpm-configuration> gpm options)
d4053c71 2125 (list (shepherd-service
8664cc88
LC
2126 (requirement '(udev))
2127 (provision '(gpm))
2128 (start #~(lambda ()
2129 ;; 'gpm' runs in the background and sets a PID file.
2130 ;; Note that it requires running as "root".
2131 (false-if-exception (delete-file "/var/run/gpm.pid"))
9fc037fe 2132 (fork+exec-command (list #$(file-append gpm "/sbin/gpm")
8664cc88
LC
2133 #$@options))
2134
2135 ;; Wait for the PID file to appear; declare failure if
2136 ;; it doesn't show up.
2137 (let loop ((i 3))
2138 (or (file-exists? "/var/run/gpm.pid")
2139 (if (zero? i)
2140 #f
2141 (begin
2142 (sleep 1)
2143 (loop (1- i))))))))
2144
2145 (stop #~(lambda (_)
2146 ;; Return #f if successfully stopped.
9fc037fe 2147 (not (zero? (system* #$(file-append gpm "/sbin/gpm")
8664cc88
LC
2148 "-k"))))))))))
2149
2150(define gpm-service-type
2151 (service-type (name 'gpm)
2152 (extensions
d4053c71 2153 (list (service-extension shepherd-root-service-type
6b9e1fef 2154 gpm-shepherd-service)))
5986e941 2155 (default-value (gpm-configuration))
6b9e1fef
LC
2156 (description
2157 "Run GPM, the general-purpose mouse daemon, with the given
2158command-line options. GPM allows users to use the mouse in the console,
2159notably to select, copy, and paste text. The default options use the
2160@code{ps2} protocol, which works for both USB and PS/2 mice.")))
8664cc88 2161
65a67bf7
LC
2162(define-deprecated (gpm-service #:key (gpm gpm)
2163 (options %default-gpm-options))
2164 gpm-service-type
8664cc88
LC
2165 "Run @var{gpm}, the general-purpose mouse daemon, with the given
2166command-line @var{options}. GPM allows users to use the mouse in the console,
2167notably to select, copy, and paste text. The default value of @var{options}
2168uses the @code{ps2} protocol, which works for both USB and PS/2 mice.
2169
2170This service is not part of @var{%base-services}."
2171 ;; To test in QEMU, use "-usbdevice mouse" and then, in the monitor, use
2172 ;; "info mice" and "mouse_set X" to use the right mouse.
2173 (service gpm-service-type
2174 (gpm-configuration (gpm gpm) (options options))))
2175
46ec2707
DC
2176(define-record-type* <kmscon-configuration>
2177 kmscon-configuration make-kmscon-configuration
2178 kmscon-configuration?
2179 (kmscon kmscon-configuration-kmscon
2180 (default kmscon))
2181 (virtual-terminal kmscon-configuration-virtual-terminal)
2182 (login-program kmscon-configuration-login-program
9fc037fe 2183 (default (file-append shadow "/bin/login")))
46ec2707
DC
2184 (login-arguments kmscon-configuration-login-arguments
2185 (default '("-p")))
2d9dace8
MO
2186 (auto-login kmscon-configuration-auto-login
2187 (default #f))
46ec2707
DC
2188 (hardware-acceleration? kmscon-configuration-hardware-acceleration?
2189 (default #f))) ; #t causes failure
2190
2191(define kmscon-service-type
2192 (shepherd-service-type
2193 'kmscon
2194 (lambda (config)
2195 (let ((kmscon (kmscon-configuration-kmscon config))
2196 (virtual-terminal (kmscon-configuration-virtual-terminal config))
2197 (login-program (kmscon-configuration-login-program config))
2198 (login-arguments (kmscon-configuration-login-arguments config))
2d9dace8 2199 (auto-login (kmscon-configuration-auto-login config))
46ec2707
DC
2200 (hardware-acceleration? (kmscon-configuration-hardware-acceleration? config)))
2201
2202 (define kmscon-command
2203 #~(list
9fc037fe 2204 #$(file-append kmscon "/bin/kmscon") "--login"
46ec2707 2205 "--vt" #$virtual-terminal
f4e8bc5f 2206 "--no-switchvt" ;Prevent a switch to the virtual terminal.
46ec2707 2207 #$@(if hardware-acceleration? '("--hwaccel") '())
2d9dace8
MO
2208 "--login" "--"
2209 #$login-program #$@login-arguments
2210 #$@(if auto-login
2211 #~(#$auto-login)
2212 #~())))
46ec2707
DC
2213
2214 (shepherd-service
2215 (documentation "kmscon virtual terminal")
76421cf0 2216 (requirement '(user-processes udev dbus-system))
46ec2707
DC
2217 (provision (list (symbol-append 'term- (string->symbol virtual-terminal))))
2218 (start #~(make-forkexec-constructor #$kmscon-command))
2219 (stop #~(make-kill-destructor)))))))
2220
c9436025
DM
2221(define-record-type* <static-networking>
2222 static-networking make-static-networking
2223 static-networking?
2224 (interface static-networking-interface)
2225 (ip static-networking-ip)
2226 (netmask static-networking-netmask
2227 (default #f))
2228 (gateway static-networking-gateway ;FIXME: doesn't belong here
2229 (default #f))
2230 (provision static-networking-provision
2231 (default #f))
2232 (requirement static-networking-requirement
2233 (default '()))
2234 (name-servers static-networking-name-servers ;FIXME: doesn't belong here
2235 (default '())))
2236
2237(define static-networking-shepherd-service
2238 (match-lambda
2239 (($ <static-networking> interface ip netmask gateway provision
2240 requirement name-servers)
2241 (let ((loopback? (and provision (memq 'loopback provision))))
2242 (shepherd-service
2243
2244 (documentation
2245 "Bring up the networking interface using a static IP address.")
2246 (requirement requirement)
2247 (provision (or provision
2248 (list (symbol-append 'networking-
2249 (string->symbol interface)))))
2250
2251 (start #~(lambda _
2252 ;; Return #t if successfully started.
2253 (let* ((addr (inet-pton AF_INET #$ip))
2254 (sockaddr (make-socket-address AF_INET addr 0))
2255 (mask (and #$netmask
2256 (inet-pton AF_INET #$netmask)))
2257 (maskaddr (and mask
2258 (make-socket-address AF_INET
2259 mask 0)))
2260 (gateway (and #$gateway
2261 (inet-pton AF_INET #$gateway)))
2262 (gatewayaddr (and gateway
2263 (make-socket-address AF_INET
2264 gateway 0))))
2265 (configure-network-interface #$interface sockaddr
2266 (logior IFF_UP
2267 #$(if loopback?
2268 #~IFF_LOOPBACK
2269 0))
2270 #:netmask maskaddr)
2271 (when gateway
2272 (let ((sock (socket AF_INET SOCK_DGRAM 0)))
2273 (add-network-route/gateway sock gatewayaddr)
2274 (close-port sock))))))
2275 (stop #~(lambda _
2276 ;; Return #f is successfully stopped.
2277 (let ((sock (socket AF_INET SOCK_STREAM 0)))
2278 (when #$gateway
2279 (delete-network-route sock
2280 (make-socket-address
2281 AF_INET INADDR_ANY 0)))
2282 (set-network-interface-flags sock #$interface 0)
2283 (close-port sock)
241358dc 2284 #f)))
c9436025
DM
2285 (respawn? #f))))))
2286
2287(define (static-networking-etc-files interfaces)
2288 "Return a /etc/resolv.conf entry for INTERFACES or the empty list."
2289 (match (delete-duplicates
2290 (append-map static-networking-name-servers
2291 interfaces))
2292 (()
2293 '())
2294 ((name-servers ...)
2295 (let ((content (string-join
2296 (map (cut string-append "nameserver " <>)
2297 name-servers)
2298 "\n" 'suffix)))
2299 `(("resolv.conf"
2300 ,(plain-file "resolv.conf"
2301 (string-append "\
2302# Generated by 'static-networking-service'.\n"
2303 content))))))))
2304
2305(define (static-networking-shepherd-services interfaces)
2306 "Return the list of Shepherd services to bring up INTERFACES, a list of
2307<static-networking> objects."
2308 (define (loopback? service)
2309 (memq 'loopback (shepherd-service-provision service)))
2310
2311 (let ((services (map static-networking-shepherd-service interfaces)))
2312 (match (remove loopback? services)
2313 (()
2314 ;; There's no interface other than 'loopback', so we assume that the
2315 ;; 'networking' service will be provided by dhclient or similar.
2316 services)
2317 ((non-loopback ...)
2318 ;; Assume we're providing all the interfaces, and thus, provide a
2319 ;; 'networking' service.
2320 (cons (shepherd-service
2321 (provision '(networking))
2322 (requirement (append-map shepherd-service-provision
2323 services))
2324 (start #~(const #t))
2325 (stop #~(const #f))
2326 (documentation "Bring up all the networking interfaces."))
2327 services)))))
2328
2329(define static-networking-service-type
2330 ;; The service type for statically-defined network interfaces.
2331 (service-type (name 'static-networking)
2332 (extensions
2333 (list
2334 (service-extension shepherd-root-service-type
2335 static-networking-shepherd-services)
2336 (service-extension etc-service-type
2337 static-networking-etc-files)))
2338 (compose concatenate)
2339 (extend append)
2340 (description
2341 "Turn up the specified network interfaces upon startup,
2342with the given IP address, gateway, netmask, and so on. The value for
2343services of this type is a list of @code{static-networking} objects, one per
2344network interface.")))
2345
2346(define* (static-networking-service interface ip
2347 #:key
2348 netmask gateway provision
2349 ;; Most interfaces require udev to be usable.
2350 (requirement '(udev))
2351 (name-servers '()))
2352 "Return a service that starts @var{interface} with address @var{ip}. If
2353@var{netmask} is true, use it as the network mask. If @var{gateway} is true,
2354it must be a string specifying the default network gateway.
2355
2356This procedure can be called several times, one for each network
2357interface of interest. Behind the scenes what it does is extend
2358@code{static-networking-service-type} with additional network interfaces
2359to handle."
2360 (simple-service 'static-network-interface
2361 static-networking-service-type
2362 (list (static-networking (interface interface) (ip ip)
2363 (netmask netmask) (gateway gateway)
2364 (provision provision)
2365 (requirement requirement)
2366 (name-servers name-servers)))))
2367
8664cc88 2368\f
8b198abe
LC
2369(define %base-services
2370 ;; Convenience variable holding the basic services.
178bce41 2371 (list (service login-service-type)
317d3b47 2372
bb3062ad 2373 (service virtual-terminal-service-type)
4a84a487
LC
2374 (service console-font-service-type
2375 (map (lambda (tty)
2376 (cons tty %default-console-font))
2377 '("tty1" "tty2" "tty3" "tty4" "tty5" "tty6")))
317d3b47 2378
76a2b2db
EF
2379 (service agetty-service-type (agetty-configuration
2380 (extra-options '("-L")) ; no carrier detect
2381 (term "vt100")
2382 (tty #f))) ; automatic
2383
2384 (service mingetty-service-type (mingetty-configuration
2385 (tty "tty1")))
2386 (service mingetty-service-type (mingetty-configuration
2387 (tty "tty2")))
2388 (service mingetty-service-type (mingetty-configuration
2389 (tty "tty3")))
2390 (service mingetty-service-type (mingetty-configuration
2391 (tty "tty4")))
2392 (service mingetty-service-type (mingetty-configuration
2393 (tty "tty5")))
2394 (service mingetty-service-type (mingetty-configuration
2395 (tty "tty6")))
317d3b47 2396
8de3e4b3
LC
2397 (service static-networking-service-type
2398 (list (static-networking (interface "lo")
2399 (ip "127.0.0.1")
db8ed7ce 2400 (requirement '())
8de3e4b3 2401 (provision '(loopback)))))
317d3b47 2402 (syslog-service)
8faaf8d7 2403 (service urandom-seed-service-type)
7194745a 2404 (service guix-service-type)
db903549 2405 (service nscd-service-type)
317d3b47
DC
2406
2407 ;; The LVM2 rules are needed as soon as LVM2 or the device-mapper is
2408 ;; used, so enable them by default. The FUSE and ALSA rules are
2409 ;; less critical, but handy.
fd779db9
EF
2410 (service udev-service-type
2411 (udev-configuration
2412 (rules (list lvm2 fuse alsa-utils crda))))
387e1754
LC
2413
2414 (service special-files-service-type
2415 `(("/bin/sh" ,(file-append (canonical-package bash)
2416 "/bin/sh"))))))
8b198abe 2417
db4fdc04 2418;;; base.scm ends here