Merge branch 'master' into staging
[jackhill/guix/guix.git] / gnu / system / linux-initrd.scm
1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
3 ;;; Copyright © 2016 Mark H Weaver <mhw@netris.org>
4 ;;; Copyright © 2016 Jan Nieuwenhuizen <janneke@gnu.org>
5 ;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
6 ;;;
7 ;;; This file is part of GNU Guix.
8 ;;;
9 ;;; GNU Guix is free software; you can redistribute it and/or modify it
10 ;;; under the terms of the GNU General Public License as published by
11 ;;; the Free Software Foundation; either version 3 of the License, or (at
12 ;;; your option) any later version.
13 ;;;
14 ;;; GNU Guix is distributed in the hope that it will be useful, but
15 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;;; GNU General Public License for more details.
18 ;;;
19 ;;; You should have received a copy of the GNU General Public License
20 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
21
22 (define-module (gnu system linux-initrd)
23 #:use-module (guix monads)
24 #:use-module (guix store)
25 #:use-module (guix gexp)
26 #:use-module (guix utils)
27 #:use-module ((guix store)
28 #:select (%store-prefix))
29 #:use-module ((guix derivations)
30 #:select (derivation->output-path))
31 #:use-module (guix modules)
32 #:use-module (gnu packages compression)
33 #:use-module (gnu packages disk)
34 #:use-module (gnu packages linux)
35 #:use-module (gnu packages guile)
36 #:use-module ((gnu packages make-bootstrap)
37 #:select (%guile-static-stripped))
38 #:use-module (gnu system file-systems)
39 #:use-module (gnu system mapped-devices)
40 #:use-module (ice-9 match)
41 #:use-module (ice-9 regex)
42 #:use-module (ice-9 vlist)
43 #:use-module (srfi srfi-1)
44 #:use-module (srfi srfi-26)
45 #:export (expression->initrd
46 %base-initrd-modules
47 raw-initrd
48 file-system-packages
49 base-initrd))
50
51 \f
52 ;;; Commentary:
53 ;;;
54 ;;; Tools to build initial RAM disks (initrd's) for Linux-Libre, and in
55 ;;; particular initrd's that run Guile.
56 ;;;
57 ;;; Code:
58
59
60 (define* (expression->initrd exp
61 #:key
62 (guile %guile-static-stripped)
63 (gzip gzip)
64 (name "guile-initrd")
65 (system (%current-system)))
66 "Return a derivation that builds a Linux initrd (a gzipped cpio archive)
67 containing GUILE and that evaluates EXP, a G-expression, upon booting. All
68 the derivations referenced by EXP are automatically copied to the initrd."
69
70 ;; General Linux overview in `Documentation/early-userspace/README' and
71 ;; `Documentation/filesystems/ramfs-rootfs-initramfs.txt'.
72
73 (define init
74 (program-file "init" exp #:guile guile))
75
76 (define builder
77 (with-imported-modules (source-module-closure
78 '((gnu build linux-initrd)))
79 #~(begin
80 (use-modules (gnu build linux-initrd))
81
82 (mkdir #$output)
83
84 ;; The guile used in the initrd must be present in the store, so
85 ;; that module loading works once the root is switched.
86 ;;
87 ;; To ensure that is the case, add an explicit reference to the
88 ;; guile package used in the initrd to the output.
89 ;;
90 ;; This fixes guix-patches bug #28399, "Fix mysql activation, and
91 ;; add a basic test".
92 (call-with-output-file (string-append #$ output "/references")
93 (lambda (port)
94 (simple-format port "~A\n" #$guile)))
95
96 (build-initrd (string-append #$output "/initrd")
97 #:guile #$guile
98 #:init #$init
99 ;; Copy everything INIT refers to into the initrd.
100 #:references-graphs '("closure")
101 #:gzip (string-append #$gzip "/bin/gzip")))))
102
103 (gexp->derivation name builder
104 #:references-graphs `(("closure" ,init))))
105
106 (define (flat-linux-module-directory linux modules)
107 "Return a flat directory containing the Linux kernel modules listed in
108 MODULES and taken from LINUX."
109 (define build-exp
110 (with-imported-modules (source-module-closure
111 '((guix build utils)
112 (gnu build linux-modules)))
113 #~(begin
114 (use-modules (ice-9 match) (ice-9 regex)
115 (srfi srfi-1)
116 (guix build utils)
117 (gnu build linux-modules))
118
119 (define (string->regexp str)
120 ;; Return a regexp that matches STR exactly.
121 (string-append "^" (regexp-quote str) "$"))
122
123 (define module-dir
124 (string-append #$linux "/lib/modules"))
125
126 (define (lookup module)
127 (let ((name (ensure-dot-ko module)))
128 (match (find-files module-dir (string->regexp name))
129 ((file)
130 file)
131 (()
132 (error "module not found" name module-dir))
133 ((_ ...)
134 (error "several modules by that name"
135 name module-dir)))))
136
137 (define modules
138 (let ((modules (map lookup '#$modules)))
139 (append modules
140 (recursive-module-dependencies modules
141 #:lookup-module lookup))))
142
143 (mkdir #$output)
144 (for-each (lambda (module)
145 (format #t "copying '~a'...~%" module)
146 (copy-file module
147 (string-append #$output "/"
148 (basename module))))
149 (delete-duplicates modules)))))
150
151 (computed-file "linux-modules" build-exp))
152
153 (define* (raw-initrd file-systems
154 #:key
155 (linux linux-libre)
156 (linux-modules '())
157 (mapped-devices '())
158 (helper-packages '())
159 qemu-networking?
160 volatile-root?
161 (on-error 'debug))
162 "Return a monadic derivation that builds a raw initrd, with kernel
163 modules taken from LINUX. FILE-SYSTEMS is a list of file-systems to be
164 mounted by the initrd, possibly in addition to the root file system specified
165 on the kernel command line via '--root'. LINUX-MODULES is a list of kernel
166 modules to be loaded at boot time. MAPPED-DEVICES is a list of device
167 mappings to realize before FILE-SYSTEMS are mounted.
168 HELPER-PACKAGES is a list of packages to be copied in the initrd. It may include
169 e2fsck/static or other packages needed by the initrd to check root partition.
170
171 When QEMU-NETWORKING? is true, set up networking with the standard QEMU
172 parameters.
173
174 When VOLATILE-ROOT? is true, the root file system is writable but any changes
175 to it are lost.
176
177 ON-ERROR is passed to 'call-with-error-handling'; it determines what happens
178 upon error."
179 (define device-mapping-commands
180 ;; List of gexps to open the mapped devices.
181 (map (lambda (md)
182 (let* ((source (mapped-device-source md))
183 (target (mapped-device-target md))
184 (type (mapped-device-type md))
185 (open (mapped-device-kind-open type)))
186 (open source target)))
187 mapped-devices))
188
189 (define kodir
190 (flat-linux-module-directory linux linux-modules))
191
192 (expression->initrd
193 (with-imported-modules (source-module-closure
194 '((gnu build linux-boot)
195 (guix build utils)
196 (guix build bournish)
197 (gnu system file-systems)
198 (gnu build file-systems)))
199 #~(begin
200 (use-modules (gnu build linux-boot)
201 (gnu system file-systems)
202 (guix build utils)
203 (guix build bournish) ;add the 'bournish' meta-command
204 (srfi srfi-26)
205
206 ;; FIXME: The following modules are for
207 ;; LUKS-DEVICE-MAPPING. We should instead propagate
208 ;; this info via gexps.
209 ((gnu build file-systems)
210 #:select (find-partition-by-luks-uuid))
211 (rnrs bytevectors))
212
213 (with-output-to-port (%make-void-port "w")
214 (lambda ()
215 (set-path-environment-variable "PATH" '("bin" "sbin")
216 '#$helper-packages)))
217
218 (boot-system #:mounts
219 (map spec->file-system
220 '#$(map file-system->spec file-systems))
221 #:pre-mount (lambda ()
222 (and #$@device-mapping-commands))
223 #:linux-modules '#$linux-modules
224 #:linux-module-directory '#$kodir
225 #:qemu-guest-networking? #$qemu-networking?
226 #:volatile-root? '#$volatile-root?
227 #:on-error '#$on-error)))
228 #:name "raw-initrd"))
229
230 (define* (file-system-packages file-systems #:key (volatile-root? #f))
231 "Return the list of statically-linked, stripped packages to check
232 FILE-SYSTEMS."
233 `(,@(if (find (lambda (fs)
234 (string-prefix? "ext" (file-system-type fs)))
235 file-systems)
236 (list e2fsck/static)
237 '())
238 ,@(if (find (lambda (fs)
239 (string-suffix? "fat" (file-system-type fs)))
240 file-systems)
241 (list fatfsck/static)
242 '())
243 ,@(if (find (file-system-type-predicate "btrfs") file-systems)
244 (list btrfs-progs/static)
245 '())))
246
247 (define-syntax vhash ;TODO: factorize
248 (syntax-rules (=>)
249 "Build a vhash with the given key/value mappings."
250 ((_)
251 vlist-null)
252 ((_ (key others ... => value) rest ...)
253 (vhash-cons key value
254 (vhash (others ... => value) rest ...)))
255 ((_ (=> value) rest ...)
256 (vhash rest ...))))
257
258 (define-syntax lookup-procedure
259 (syntax-rules (else)
260 "Return a procedure that lookups keys in the given dictionary."
261 ((_ mapping ... (else default))
262 (let ((table (vhash mapping ...)))
263 (lambda (key)
264 (match (vhash-assoc key table)
265 (#f default)
266 ((key . value) value)))))))
267
268 (define file-system-type-modules
269 ;; Given a file system type, return the list of modules it needs.
270 (lookup-procedure ("cifs" => '("md4" "ecb" "cifs"))
271 ("9p" => '("9p" "9pnet_virtio"))
272 ("btrfs" => '("btrfs"))
273 ("iso9660" => '("isofs"))
274 (else '())))
275
276 (define (file-system-modules file-systems)
277 "Return the list of Linux modules needed to mount FILE-SYSTEMS."
278 (append-map (compose file-system-type-modules file-system-type)
279 file-systems))
280
281 (define* (default-initrd-modules #:optional (system (%current-system)))
282 "Return the list of modules included in the initrd by default."
283 (define virtio-modules
284 ;; Modules for Linux para-virtualized devices, for use in QEMU guests.
285 '("virtio_pci" "virtio_balloon" "virtio_blk" "virtio_net"
286 "virtio_console"))
287
288 `("ahci" ;for SATA controllers
289 "usb-storage" "uas" ;for the installation image etc.
290 "usbhid" "hid-generic" "hid-apple" ;keyboards during early boot
291 "dm-crypt" "xts" "serpent_generic" "wp512" ;for encrypted root partitions
292 "nls_iso8859-1" ;for `mkfs.fat`, et.al
293 ,@(if (string-match "^(x86_64|i[3-6]86)-" system)
294 '("pata_acpi" "pata_atiixp" ;for ATA controllers
295 "isci") ;for SAS controllers like Intel C602
296 '())
297
298 ,@virtio-modules))
299
300 (define-syntax %base-initrd-modules
301 ;; This more closely matches our naming convention.
302 (identifier-syntax (default-initrd-modules)))
303
304 (define* (base-initrd file-systems
305 #:key
306 (linux linux-libre)
307 (linux-modules '())
308 (mapped-devices '())
309 qemu-networking?
310 volatile-root?
311 (extra-modules '()) ;deprecated
312 (on-error 'debug))
313 "Return a monadic derivation that builds a generic initrd, with kernel
314 modules taken from LINUX. FILE-SYSTEMS is a list of file-systems to be
315 mounted by the initrd, possibly in addition to the root file system specified
316 on the kernel command line via '--root'. MAPPED-DEVICES is a list of device
317 mappings to realize before FILE-SYSTEMS are mounted.
318
319 QEMU-NETWORKING? and VOLATILE-ROOT? behaves as in raw-initrd.
320
321 The initrd is automatically populated with all the kernel modules necessary
322 for FILE-SYSTEMS and for the given options. Additional kernel
323 modules can be listed in LINUX-MODULES. They will be added to the initrd, and
324 loaded at boot time in the order in which they appear."
325 (define linux-modules*
326 ;; Modules added to the initrd and loaded from the initrd.
327 `(,@linux-modules
328 ,@(file-system-modules file-systems)
329 ,@(if volatile-root?
330 '("overlay")
331 '())
332 ,@extra-modules))
333
334 (define helper-packages
335 (file-system-packages file-systems #:volatile-root? volatile-root?))
336
337 (raw-initrd file-systems
338 #:linux linux
339 #:linux-modules linux-modules*
340 #:mapped-devices mapped-devices
341 #:helper-packages helper-packages
342 #:qemu-networking? qemu-networking?
343 #:volatile-root? volatile-root?
344 #:on-error on-error))
345
346 ;;; linux-initrd.scm ends here