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