linux-initrd: Wait a bit longer for partitions to appear.
[jackhill/guix/guix.git] / gnu / services / base.scm
CommitLineData
db4fdc04
LC
1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2013, 2014 Ludovic Courtès <ludo@gnu.org>
3;;;
4;;; This file is part of GNU Guix.
5;;;
6;;; GNU Guix is free software; you can redistribute it and/or modify it
7;;; under the terms of the GNU General Public License as published by
8;;; the Free Software Foundation; either version 3 of the License, or (at
9;;; your option) any later version.
10;;;
11;;; GNU Guix is distributed in the hope that it will be useful, but
12;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
18
19(define-module (gnu services base)
185f6691
LC
20 #:use-module ((guix store)
21 #:select (%store-prefix))
db4fdc04 22 #:use-module (gnu services)
4a3b3b07 23 #:use-module (gnu services networking)
db4fdc04
LC
24 #:use-module (gnu system shadow) ; 'user-account', etc.
25 #:use-module (gnu system linux) ; 'pam-service', etc.
26 #:use-module (gnu packages admin)
151a2c07 27 #:use-module ((gnu packages linux)
1b09031f 28 #:select (udev kbd e2fsprogs))
db4fdc04 29 #:use-module ((gnu packages base)
23ed63a1 30 #:select (glibc-final))
db4fdc04 31 #:use-module (gnu packages package-management)
2c071ce9
LC
32 #:use-module ((guix build linux-initrd)
33 #:select (mount-flags->bit-mask))
b5f4e686 34 #:use-module (guix gexp)
db4fdc04
LC
35 #:use-module (guix monads)
36 #:use-module (srfi srfi-1)
37 #:use-module (srfi srfi-26)
38 #:use-module (ice-9 format)
a00dd9fb 39 #:export (root-file-system-service
023f391c 40 file-system-service
a00dd9fb
LC
41 user-processes-service
42 host-name-service
62ca0fdf 43 console-font-service
151a2c07 44 udev-service
db4fdc04
LC
45 mingetty-service
46 nscd-service
47 syslog-service
8b198abe
LC
48 guix-service
49 %base-services))
db4fdc04
LC
50
51;;; Commentary:
52;;;
53;;; Base system services---i.e., services that 99% of the users will want to
54;;; use.
55;;;
56;;; Code:
57
a00dd9fb
LC
58(define (root-file-system-service)
59 "Return a service whose sole purpose is to re-mount read-only the root file
60system upon shutdown (aka. cleanly \"umounting\" root.)
61
62This service must be the root of the service dependency graph so that its
63'stop' action is invoked when dmd is the only process left."
a00dd9fb
LC
64 (with-monad %store-monad
65 (return
66 (service
67 (documentation "Take care of the root file system.")
68 (provision '(root-file-system))
69 (start #~(const #t))
70 (stop #~(lambda _
71 ;; Return #f if successfully stopped.
23ed63a1 72 (sync)
a00dd9fb
LC
73
74 (call-with-blocked-asyncs
75 (lambda ()
76 (let ((null (%make-void-port "w")))
77 ;; Close 'dmd.log'.
78 (display "closing log\n")
79 ;; XXX: Ideally we'd use 'stop-logging', but that one
80 ;; doesn't actually close the port as of dmd 0.1.
81 (close-port (@@ (dmd comm) log-output-port))
82 (set! (@@ (dmd comm) log-output-port) null)
83
84 ;; Redirect the default output ports..
85 (set-current-output-port null)
86 (set-current-error-port null)
87
88 ;; Close /dev/console.
89 (for-each close-fdes '(0 1 2))
90
23ed63a1 91 ;; At this point, there are no open files left, so the
a00dd9fb 92 ;; root file system can be re-mounted read-only.
23ed63a1
LC
93 (mount #f "/" #f
94 (logior MS_REMOUNT MS_RDONLY)
95 #:update-mtab? #f)
96
97 #f)))))
a00dd9fb
LC
98 (respawn? #f)))))
99
023f391c 100(define* (file-system-service device target type
2c071ce9
LC
101 #:key (flags '()) (check? #t)
102 create-mount-point? options (title 'any))
023f391c 103 "Return a service that mounts DEVICE on TARGET as a file system TYPE with
d4c87617
LC
104OPTIONS. TITLE is a symbol specifying what kind of name DEVICE is: 'label for
105a partition label, 'device for a device file name, or 'any. When CHECK? is
4e469051 106true, check the file system before mounting it. When CREATE-MOUNT-POINT? is
2c071ce9
LC
107true, create TARGET if it does not exist yet. FLAGS is a list of symbols,
108such as 'read-only' etc."
023f391c
LC
109 (with-monad %store-monad
110 (return
111 (service
112 (provision (list (symbol-append 'file-system- (string->symbol target))))
113 (requirement '(root-file-system))
114 (documentation "Check, mount, and unmount the given file system.")
115 (start #~(lambda args
d4c87617 116 (let ((device (canonicalize-device-spec #$device '#$title)))
4e469051
LC
117 #$(if create-mount-point?
118 #~(mkdir-p #$target)
119 #~#t)
d4c87617 120 #$(if check?
1b09031f
LC
121 #~(begin
122 ;; Make sure fsck.ext2 & co. can be found.
123 (setenv "PATH"
124 (string-append
125 #$e2fsprogs "/sbin:"
126 "/run/current-system/profile/sbin:"
127 (getenv "PATH")))
128 (check-file-system device #$type))
d4c87617 129 #~#t)
2c071ce9
LC
130 (mount device #$target #$type
131 #$(mount-flags->bit-mask flags)
132 #$options))
023f391c
LC
133 #t))
134 (stop #~(lambda args
135 ;; Normally there are no processes left at this point, so
136 ;; TARGET can be safely unmounted.
137 (umount #$target)
138 #f))))))
139
7d57cfd3
LC
140(define %do-not-kill-file
141 ;; Name of the file listing PIDs of processes that must survive when halting
142 ;; the system. Typical example is user-space file systems.
143 "/etc/dmd/do-not-kill")
144
023f391c 145(define* (user-processes-service requirements #:key (grace-delay 2))
a00dd9fb
LC
146 "Return the service that is responsible for terminating all the processes so
147that the root file system can be re-mounted read-only, just before
148rebooting/halting. Processes still running GRACE-DELAY seconds after SIGTERM
149has been sent are terminated with SIGKILL.
150
023f391c
LC
151The returned service will depend on 'root-file-system' and on all the services
152listed in REQUIREMENTS.
153
a00dd9fb
LC
154All the services that spawn processes must depend on this one so that they are
155stopped before 'kill' is called."
156 (with-monad %store-monad
157 (return (service
158 (documentation "When stopped, terminate all user processes.")
159 (provision '(user-processes))
023f391c 160 (requirement (cons 'root-file-system requirements))
a00dd9fb
LC
161 (start #~(const #t))
162 (stop #~(lambda _
7d57cfd3
LC
163 (define (kill-except omit signal)
164 ;; Kill all the processes with SIGNAL except those
165 ;; listed in OMIT and the current process.
166 (let ((omit (cons (getpid) omit)))
167 (for-each (lambda (pid)
168 (unless (memv pid omit)
169 (false-if-exception
170 (kill pid signal))))
171 (processes))))
172
173 (define omitted-pids
174 ;; List of PIDs that must not be killed.
175 (if (file-exists? #$%do-not-kill-file)
176 (map string->number
177 (call-with-input-file #$%do-not-kill-file
178 (compose string-tokenize
179 (@ (ice-9 rdelim) read-string))))
180 '()))
181
a00dd9fb
LC
182 ;; When this happens, all the processes have been
183 ;; killed, including 'deco', so DMD-OUTPUT-PORT and
184 ;; thus CURRENT-OUTPUT-PORT are dangling.
185 (call-with-output-file "/dev/console"
186 (lambda (port)
187 (display "sending all processes the TERM signal\n"
188 port)))
189
7d57cfd3
LC
190 (if (null? omitted-pids)
191 (begin
192 ;; Easy: terminate all of them.
193 (kill -1 SIGTERM)
194 (sleep #$grace-delay)
195 (kill -1 SIGKILL))
196 (begin
197 ;; Kill them all except OMITTED-PIDS. XXX: We
198 ;; would like to (kill -1 SIGSTOP) to get a fixed
199 ;; list of processes, like 'killall5' does, but
200 ;; that seems unreliable.
201 (kill-except omitted-pids SIGTERM)
202 (sleep #$grace-delay)
203 (kill-except omitted-pids SIGKILL)
204 (delete-file #$%do-not-kill-file)))
a00dd9fb
LC
205
206 (display "all processes have been terminated\n")
207 #f))
208 (respawn? #f)))))
209
db4fdc04 210(define (host-name-service name)
51da7ca0 211 "Return a service that sets the host name to @var{name}."
db4fdc04
LC
212 (with-monad %store-monad
213 (return (service
214 (documentation "Initialize the machine's host name.")
215 (provision '(host-name))
b5f4e686
LC
216 (start #~(lambda _
217 (sethostname #$name)))
db4fdc04
LC
218 (respawn? #f)))))
219
62ca0fdf
LC
220(define (unicode-start tty)
221 "Return a gexp to start Unicode support on @var{tty}."
222
223 ;; We have to run 'unicode_start' in a pipe so that when it invokes the
224 ;; 'tty' command, that command returns TTY.
225 #~(begin
226 (let ((pid (primitive-fork)))
227 (case pid
228 ((0)
229 (close-fdes 0)
230 (dup2 (open-fdes #$tty O_RDONLY) 0)
231 (close-fdes 1)
232 (dup2 (open-fdes #$tty O_WRONLY) 1)
233 (execl (string-append #$kbd "/bin/unicode_start")
234 "unicode_start"))
235 (else
236 (zero? (cdr (waitpid pid))))))))
237
238(define* (console-font-service tty #:optional (font "LatGrkCyr-8x16"))
239 "Return a service that sets up Unicode support in @var{tty} and loads
240@var{font} for that tty (fonts are per virtual console in Linux.)"
241 ;; Note: 'LatGrkCyr-8x16' has the advantage of providing three common
242 ;; scripts as well as glyphs for em dash, quotation marks, and other Unicode
243 ;; codepoints notably found in the UTF-8 manual.
244 (let ((device (string-append "/dev/" tty)))
245 (with-monad %store-monad
246 (return (service
247 (documentation "Load a Unicode console font.")
248 (provision (list (symbol-append 'console-font-
249 (string->symbol tty))))
250
251 ;; Start after mingetty has been started on TTY, otherwise the
252 ;; settings are ignored.
253 (requirement (list (symbol-append 'term-
254 (string->symbol tty))))
255
256 (start #~(lambda _
257 (and #$(unicode-start device)
258 (zero?
259 (system* (string-append #$kbd "/bin/setfont")
260 "-C" #$device #$font)))))
261 (stop #~(const #t))
262 (respawn? #f))))))
263
db4fdc04
LC
264(define* (mingetty-service tty
265 #:key
266 (motd (text-file "motd" "Welcome.\n"))
52322163
LC
267 auto-login
268 login-program
269 login-pause?
51da7ca0
LC
270
271 ;; Allow empty passwords by default so that
272 ;; first-time users can log in when the 'root'
273 ;; account has just been created.
db4fdc04 274 (allow-empty-passwords? #t))
52322163
LC
275 "Return a service to run mingetty on @var{tty}.
276
277When @var{allow-empty-passwords?} is true, allow empty log-in password. When
278@var{auto-login} is true, it must be a user name under which to log-in
279automatically. @var{login-pause?} can be set to @code{#t} in conjunction with
280@var{auto-login}, in which case the user will have to press a key before the
281login shell is launched.
282
283When true, @var{login-program} is a gexp or a monadic gexp denoting the name
284of the log-in program (the default is the @code{login} program from the Shadow
285tool suite.)
286
287@var{motd} is a monadic value containing a text file to use as
51da7ca0 288the ``message of the day''."
52322163
LC
289 (mlet %store-monad ((motd motd)
290 (login-program (cond ((gexp? login-program)
291 (return login-program))
292 ((not login-program)
293 (return #f))
294 (else
295 login-program))))
db4fdc04
LC
296 (return
297 (service
298 (documentation (string-append "Run mingetty on " tty "."))
299 (provision (list (symbol-append 'term- (string->symbol tty))))
300
301 ;; Since the login prompt shows the host name, wait for the 'host-name'
302 ;; service to be done.
a00dd9fb 303 (requirement '(user-processes host-name))
db4fdc04 304
b5f4e686 305 (start #~(make-forkexec-constructor
1c6b445b
LC
306 (list (string-append #$mingetty "/sbin/mingetty")
307 "--noclear" #$tty
308 #$@(if auto-login
309 #~("--autologin" #$auto-login)
310 #~())
311 #$@(if login-program
312 #~("--loginprog" #$login-program)
313 #~())
314 #$@(if login-pause?
315 #~("--loginpause")
316 #~()))))
b5f4e686 317 (stop #~(make-kill-destructor))
db4fdc04
LC
318
319 (pam-services
320 ;; Let 'login' be known to PAM. All the mingetty services will have
321 ;; that PAM service, but that's fine because they're all identical and
322 ;; duplicates are removed.
323 (list (unix-pam-service "login"
324 #:allow-empty-passwords? allow-empty-passwords?
325 #:motd motd)))))))
326
327(define* (nscd-service #:key (glibc glibc-final))
328 "Return a service that runs libc's name service cache daemon (nscd)."
b5f4e686 329 (with-monad %store-monad
db4fdc04
LC
330 (return (service
331 (documentation "Run libc's name service cache daemon (nscd).")
332 (provision '(nscd))
a00dd9fb 333 (requirement '(user-processes))
4b2615e1
LC
334
335 (activate #~(begin
336 (use-modules (guix build utils))
337 (mkdir-p "/var/run/nscd")))
338
1c6b445b
LC
339 (start #~(make-forkexec-constructor
340 (list (string-append #$glibc "/sbin/nscd")
341 "-f" "/dev/null" "--foreground")))
b5f4e686 342 (stop #~(make-kill-destructor))
db4fdc04 343
b5f4e686 344 (respawn? #f)))))
db4fdc04
LC
345
346(define (syslog-service)
51da7ca0 347 "Return a service that runs @code{syslogd} with reasonable default settings."
db4fdc04
LC
348
349 ;; Snippet adapted from the GNU inetutils manual.
350 (define contents "
1f3fc60d 351 # Log all error messages, authentication messages of
db4fdc04
LC
352 # level notice or higher and anything of level err or
353 # higher to the console.
354 # Don't log private authentication messages!
6a191274 355 *.alert;auth.notice;authpriv.none /dev/console
db4fdc04
LC
356
357 # Log anything (except mail) of level info or higher.
358 # Don't log private authentication messages!
359 *.info;mail.none;authpriv.none /var/log/messages
360
361 # Same, in a different place.
362 *.info;mail.none;authpriv.none /dev/tty12
363
364 # The authpriv file has restricted access.
365 authpriv.* /var/log/secure
366
367 # Log all the mail messages in one place.
368 mail.* /var/log/maillog
369")
370
371 (mlet %store-monad
b5f4e686 372 ((syslog.conf (text-file "syslog.conf" contents)))
db4fdc04
LC
373 (return
374 (service
375 (documentation "Run the syslog daemon (syslogd).")
376 (provision '(syslogd))
a00dd9fb 377 (requirement '(user-processes))
b5f4e686 378 (start
1c6b445b
LC
379 #~(make-forkexec-constructor
380 (list (string-append #$inetutils "/libexec/syslogd")
381 "--no-detach" "--rcfile" #$syslog.conf)))
b5f4e686 382 (stop #~(make-kill-destructor))))))
db4fdc04
LC
383
384(define* (guix-build-accounts count #:key
ab6a279a 385 (group "guixbuild")
db4fdc04 386 (first-uid 30001)
db4fdc04
LC
387 (shadow shadow))
388 "Return a list of COUNT user accounts for Guix build users, with UIDs
389starting at FIRST-UID, and under GID."
390 (with-monad %store-monad
391 (return (unfold (cut > <> count)
392 (lambda (n)
393 (user-account
394 (name (format #f "guixbuilder~2,'0d" n))
459dd9ea 395 (system? #t)
db4fdc04 396 (uid (+ first-uid n -1))
ab6a279a 397 (group group)
3d116a70
LC
398
399 ;; guix-daemon expects GROUP to be listed as a
400 ;; supplementary group too:
401 ;; <http://lists.gnu.org/archive/html/bug-guix/2013-01/msg00239.html>.
402 (supplementary-groups (list group))
403
db4fdc04
LC
404 (comment (format #f "Guix Build User ~2d" n))
405 (home-directory "/var/empty")
b5f4e686 406 (shell #~(string-append #$shadow "/sbin/nologin"))))
db4fdc04
LC
407 1+
408 1))))
409
2c5c696c
LC
410(define (hydra-key-authorization guix)
411 "Return a gexp with code to register the hydra.gnu.org public key with
412GUIX."
413 #~(unless (file-exists? "/etc/guix/acl")
414 (let ((pid (primitive-fork)))
415 (case pid
416 ((0)
417 (let* ((key (string-append #$guix
418 "/share/guix/hydra.gnu.org.pub"))
419 (port (open-file key "r0b")))
420 (format #t "registering public key '~a'...~%" key)
421 (close-port (current-input-port))
2c5c696c
LC
422 (dup port 0)
423 (execl (string-append #$guix "/bin/guix")
424 "guix" "archive" "--authorize")
425 (exit 1)))
426 (else
427 (let ((status (cdr (waitpid pid))))
428 (unless (zero? status)
429 (format (current-error-port) "warning: \
430failed to register hydra.gnu.org public key: ~a~%" status))))))))
431
db4fdc04 432(define* (guix-service #:key (guix guix) (builder-group "guixbuild")
c11a6eb1
LC
433 (build-accounts 10) authorize-hydra-key?
434 (use-substitutes? #t)
435 (extra-options '()))
51da7ca0
LC
436 "Return a service that runs the build daemon from @var{guix}, and has
437@var{build-accounts} user accounts available under @var{builder-group}.
2c5c696c 438
51da7ca0
LC
439When @var{authorize-hydra-key?} is true, the @code{hydra.gnu.org} public key
440provided by @var{guix} is authorized upon activation, meaning that substitutes
c11a6eb1
LC
441from @code{hydra.gnu.org} are used by default.
442
443If @var{use-substitutes?} is false, the daemon is run with
444@option{--no-substitutes} (@pxref{Invoking guix-daemon,
445@option{--no-substitutes}}).
446
447Finally, @var{extra-options} is a list of additional command-line options
448passed to @command{guix-daemon}."
185f6691 449 (define activate
e97c5be9
LC
450 ;; Assume that the store has BUILDER-GROUP as its group. We could
451 ;; otherwise call 'chown' here, but the problem is that on a COW unionfs,
452 ;; chown leads to an entire copy of the tree, which is a bad idea.
185f6691 453
e97c5be9
LC
454 ;; Optionally authorize hydra.gnu.org's key.
455 (and authorize-hydra-key?
456 (hydra-key-authorization guix)))
185f6691 457
b5f4e686 458 (mlet %store-monad ((accounts (guix-build-accounts build-accounts
ab6a279a 459 #:group builder-group)))
db4fdc04
LC
460 (return (service
461 (provision '(guix-daemon))
a00dd9fb 462 (requirement '(user-processes))
b5f4e686 463 (start
1c6b445b
LC
464 #~(make-forkexec-constructor
465 (list (string-append #$guix "/bin/guix-daemon")
c11a6eb1
LC
466 "--build-users-group" #$builder-group
467 #$@(if use-substitutes?
468 '()
469 '("--no-substitutes"))
470 #$@extra-options)))
b5f4e686 471 (stop #~(make-kill-destructor))
db4fdc04
LC
472 (user-accounts accounts)
473 (user-groups (list (user-group
474 (name builder-group)
41717509 475 (system? #t)
e97c5be9
LC
476
477 ;; Use a fixed GID so that we can create the
478 ;; store with the right owner.
479 (id 30000))))
185f6691 480 (activate activate)))))
db4fdc04 481
151a2c07
LC
482(define* (udev-service #:key (udev udev))
483 "Run @var{udev}, which populates the @file{/dev} directory dynamically."
484 (with-monad %store-monad
485 (return (service
486 (provision '(udev))
a69576ea
LC
487
488 ;; Udev needs /dev to be a 'devtmpfs' mount so that new device
489 ;; nodes can be added: see
490 ;; <http://www.linuxfromscratch.org/lfs/view/development/chapter07/udev.html>.
7f239fd3 491 (requirement '(root-file-system))
a69576ea
LC
492
493 (documentation "Populate the /dev directory, dynamically.")
151a2c07 494 (start #~(lambda ()
1c6b445b
LC
495 (define udevd
496 (string-append #$udev "/libexec/udev/udevd"))
497
ed09bb11
LC
498 (define (wait-for-udevd)
499 ;; Wait until someone's listening on udevd's control
500 ;; socket.
501 (let ((sock (socket AF_UNIX SOCK_SEQPACKET 0)))
502 (let try ()
503 (catch 'system-error
504 (lambda ()
505 (connect sock PF_UNIX "/run/udev/control")
506 (close-port sock))
507 (lambda args
508 (format #t "waiting for udevd...~%")
509 (usleep 500000)
510 (try))))))
511
081c5b2d
LC
512 ;; Allow udev to find the modules.
513 (setenv "LINUX_MODULE_DIRECTORY"
514 "/run/booted-system/kernel/lib/modules")
515
151a2c07
LC
516 (let ((pid (primitive-fork)))
517 (case pid
518 ((0)
1c6b445b 519 (exec-command (list udevd)))
151a2c07 520 (else
ed09bb11
LC
521 ;; Wait until udevd is up and running. This
522 ;; appears to be needed so that the events
523 ;; triggered below are actually handled.
524 (wait-for-udevd)
525
526 ;; Trigger device node creation.
527 (system* (string-append #$udev "/bin/udevadm")
528 "trigger" "--action=add")
529
081c5b2d
LC
530 ;; Wait for things to settle down.
531 (system* (string-append #$udev "/bin/udevadm")
532 "settle")
151a2c07
LC
533 pid)))))
534 (stop #~(make-kill-destructor))))))
535
8b198abe
LC
536(define %base-services
537 ;; Convenience variable holding the basic services.
538 (let ((motd (text-file "motd" "
539This is the GNU operating system, welcome!\n\n")))
62ca0fdf
LC
540 (list (console-font-service "tty1")
541 (console-font-service "tty2")
542 (console-font-service "tty3")
543 (console-font-service "tty4")
544 (console-font-service "tty5")
545 (console-font-service "tty6")
546
547 (mingetty-service "tty1" #:motd motd)
8b198abe
LC
548 (mingetty-service "tty2" #:motd motd)
549 (mingetty-service "tty3" #:motd motd)
550 (mingetty-service "tty4" #:motd motd)
551 (mingetty-service "tty5" #:motd motd)
552 (mingetty-service "tty6" #:motd motd)
4a3b3b07
LC
553 (static-networking-service "lo" "127.0.0.1"
554 #:provision '(loopback))
8b198abe
LC
555 (syslog-service)
556 (guix-service)
151a2c07
LC
557 (nscd-service)
558 (udev-service))))
8b198abe 559
db4fdc04 560;;; base.scm ends here