WIP: bees service
[jackhill/guix/guix.git] / gnu / bootloader.scm
CommitLineData
b09a8da4
MO
1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2017 David Craven <david@craven.ch>
7feefb3b 3;;; Copyright © 2017, 2020 Mathieu Othacehe <m.othacehe@gmail.com>
b09a8da4 4;;; Copyright © 2017 Leo Famulari <leo@famulari.name>
a28cfee8 5;;; Copyright © 2019 Ludovic Courtès <ludo@gnu.org>
21acd8d6 6;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
b09a8da4
MO
7;;;
8;;; This file is part of GNU Guix.
9;;;
10;;; GNU Guix is free software; you can redistribute it and/or modify it
11;;; under the terms of the GNU General Public License as published by
12;;; the Free Software Foundation; either version 3 of the License, or (at
13;;; your option) any later version.
14;;;
15;;; GNU Guix is distributed in the hope that it will be useful, but
16;;; WITHOUT ANY WARRANTY; without even the implied warranty of
17;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;;; GNU General Public License for more details.
19;;;
20;;; You should have received a copy of the GNU General Public License
21;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
22
23(define-module (gnu bootloader)
24 #:use-module (guix discovery)
74eeb11d
S
25 #:use-module (guix gexp)
26 #:use-module (guix profiles)
b09a8da4
MO
27 #:use-module (guix records)
28 #:use-module (guix ui)
29 #:use-module (srfi srfi-1)
a28cfee8 30 #:use-module (ice-9 match)
8b22107e
MO
31 #:export (menu-entry
32 menu-entry?
33 menu-entry-label
34 menu-entry-device
35 menu-entry-linux
36 menu-entry-linux-arguments
37 menu-entry-initrd
1975c754 38 menu-entry-device-mount-point
21acd8d6
JN
39 menu-entry-multiboot-kernel
40 menu-entry-multiboot-arguments
41 menu-entry-multiboot-modules
8b22107e 42
a28cfee8
LC
43 menu-entry->sexp
44 sexp->menu-entry
45
8b22107e 46 bootloader
b09a8da4
MO
47 bootloader?
48 bootloader-name
49 bootloader-package
50 bootloader-installer
7feefb3b 51 bootloader-disk-image-installer
b09a8da4
MO
52 bootloader-configuration-file
53 bootloader-configuration-file-generator
54
55 bootloader-configuration
56 bootloader-configuration?
57 bootloader-configuration-bootloader
045ebb3e 58 bootloader-configuration-target
b09a8da4
MO
59 bootloader-configuration-menu-entries
60 bootloader-configuration-default-entry
61 bootloader-configuration-timeout
8d058e7b 62 bootloader-configuration-keyboard-layout
b09a8da4
MO
63 bootloader-configuration-theme
64 bootloader-configuration-terminal-outputs
65 bootloader-configuration-terminal-inputs
66 bootloader-configuration-serial-unit
67 bootloader-configuration-serial-speed
68 bootloader-configuration-additional-configuration
69
70 %bootloaders
74eeb11d
S
71 lookup-bootloader-by-name
72
73 efi-bootloader-chain))
b09a8da4
MO
74
75\f
8b22107e
MO
76;;;
77;;; Menu-entry record.
78;;;
79
80(define-record-type* <menu-entry>
81 menu-entry make-menu-entry
82 menu-entry?
83 (label menu-entry-label)
84 (device menu-entry-device ; file system uuid, label, or #f
85 (default #f))
1975c754
DM
86 (device-mount-point menu-entry-device-mount-point
87 (default #f))
21acd8d6
JN
88 (linux menu-entry-linux
89 (default #f))
8b22107e
MO
90 (linux-arguments menu-entry-linux-arguments
91 (default '())) ; list of string-valued gexps
21acd8d6
JN
92 (initrd menu-entry-initrd ; file name of the initrd as a gexp
93 (default #f))
94 (multiboot-kernel menu-entry-multiboot-kernel
95 (default #f))
96 (multiboot-arguments menu-entry-multiboot-arguments
97 (default '())) ; list of string-valued gexps
98 (multiboot-modules menu-entry-multiboot-modules
99 (default '()))) ; list of multiboot commands, where
100 ; a command is a list of <string>
8b22107e 101
a28cfee8
LC
102(define (menu-entry->sexp entry)
103 "Return ENTRY serialized as an sexp."
104 (match entry
21acd8d6
JN
105 (($ <menu-entry> label device mount-point linux linux-arguments initrd #f
106 ())
a28cfee8
LC
107 `(menu-entry (version 0)
108 (label ,label)
109 (device ,device)
110 (device-mount-point ,mount-point)
111 (linux ,linux)
112 (linux-arguments ,linux-arguments)
21acd8d6
JN
113 (initrd ,initrd)))
114 (($ <menu-entry> label device mount-point #f () #f
115 multiboot-kernel multiboot-arguments multiboot-modules)
116 `(menu-entry (version 0)
117 (label ,label)
118 (device ,device)
119 (device-mount-point ,mount-point)
120 (multiboot-kernel ,multiboot-kernel)
121 (multiboot-arguments ,multiboot-arguments)
122 (multiboot-modules ,multiboot-modules)))))
a28cfee8
LC
123
124(define (sexp->menu-entry sexp)
125 "Turn SEXP, an sexp as returned by 'menu-entry->sexp', into a <menu-entry>
126record."
127 (match sexp
128 (('menu-entry ('version 0)
129 ('label label) ('device device)
130 ('device-mount-point mount-point)
131 ('linux linux) ('linux-arguments linux-arguments)
132 ('initrd initrd) _ ...)
133 (menu-entry
134 (label label)
135 (device device)
136 (device-mount-point mount-point)
137 (linux linux)
138 (linux-arguments linux-arguments)
21acd8d6
JN
139 (initrd initrd)))
140 (('menu-entry ('version 0)
141 ('label label) ('device device)
142 ('device-mount-point mount-point)
143 ('multiboot-kernel multiboot-kernel)
144 ('multiboot-arguments multiboot-arguments)
145 ('multiboot-modules multiboot-modules) _ ...)
146 (menu-entry
147 (label label)
148 (device device)
149 (device-mount-point mount-point)
150 (multiboot-kernel multiboot-kernel)
151 (multiboot-arguments multiboot-arguments)
152 (multiboot-modules multiboot-modules)))))
a28cfee8 153
8b22107e 154\f
b09a8da4
MO
155;;;
156;;; Bootloader record.
157;;;
158
159;; The <bootloader> record contains fields expressing how the bootloader
160;; should be installed. Every bootloader in gnu/bootloader/ directory
161;; has to be described by this record.
162
163(define-record-type* <bootloader>
164 bootloader make-bootloader
165 bootloader?
166 (name bootloader-name)
167 (package bootloader-package)
168 (installer bootloader-installer)
7feefb3b
MO
169 (disk-image-installer bootloader-disk-image-installer
170 (default #f))
b09a8da4
MO
171 (configuration-file bootloader-configuration-file)
172 (configuration-file-generator bootloader-configuration-file-generator))
173
174\f
175;;;
176;;; Bootloader configuration record.
177;;;
178
179;; The <bootloader-configuration> record contains bootloader independant
180;; configuration used to fill bootloader configuration file.
181
182(define-record-type* <bootloader-configuration>
183 bootloader-configuration make-bootloader-configuration
184 bootloader-configuration?
91b6873b
LC
185 (bootloader bootloader-configuration-bootloader) ;<bootloader>
186 (target bootloader-configuration-target ;string
187 (default #f))
ac9cd78e 188 (menu-entries bootloader-configuration-menu-entries ;list of <menu-entry>
91b6873b
LC
189 (default '()))
190 (default-entry bootloader-configuration-default-entry ;integer
191 (default 0))
192 (timeout bootloader-configuration-timeout ;seconds as integer
193 (default 5))
8d058e7b
LC
194 (keyboard-layout bootloader-configuration-keyboard-layout ;<keyboard-layout> | #f
195 (default #f))
91b6873b
LC
196 (theme bootloader-configuration-theme ;bootloader-specific theme
197 (default #f))
198 (terminal-outputs bootloader-configuration-terminal-outputs ;list of symbols
199 (default '(gfxterm)))
200 (terminal-inputs bootloader-configuration-terminal-inputs ;list of symbols
201 (default '()))
202 (serial-unit bootloader-configuration-serial-unit ;integer | #f
203 (default #f))
204 (serial-speed bootloader-configuration-serial-speed ;integer | #f
205 (default #f)))
b09a8da4
MO
206
207\f
208;;;
209;;; Bootloaders.
210;;;
211
212(define (bootloader-modules)
213 "Return the list of bootloader modules."
214 (all-modules (map (lambda (entry)
215 `(,entry . "gnu/bootloader"))
3c0128b0
LC
216 %load-path)
217 #:warn warn-about-load-error))
b09a8da4
MO
218
219(define %bootloaders
220 ;; The list of publically-known bootloaders.
221 (delay (fold-module-public-variables (lambda (obj result)
222 (if (bootloader? obj)
223 (cons obj result)
224 result))
225 '()
226 (bootloader-modules))))
227
228(define (lookup-bootloader-by-name name)
229 "Return the bootloader called NAME."
230 (or (find (lambda (bootloader)
231 (eq? name (bootloader-name bootloader)))
232 (force %bootloaders))
233 (leave (G_ "~a: no such bootloader~%") name)))
74eeb11d 234
ede4117f 235(define (efi-bootloader-profile files bootloader-package hooks)
74eeb11d
S
236 "Creates a profile with BOOTLOADER-PACKAGE and a directory collection/ with
237links to additional FILES from the store. This collection is meant to be used
238by the bootloader installer.
239
240FILES is a list of file or directory names from the store, which will be
241symlinked into the collection/ directory. If a directory name ends with '/',
242then the directory content instead of the directory itself will be symlinked
243into the collection/ directory.
244
245FILES may contain file like objects produced by functions like plain-file,
ede4117f
S
246local-file, etc., or package contents produced with file-append.
247
248HOOKS lists additional hook functions to modify the profile."
74eeb11d
S
249 (define (bootloader-collection manifest)
250 (define build
251 (with-imported-modules '((guix build utils)
252 (ice-9 ftw)
253 (srfi srfi-1)
254 (srfi srfi-26))
255 #~(begin
256 (use-modules ((guix build utils)
257 #:select (mkdir-p strip-store-file-name))
258 ((ice-9 ftw)
259 #:select (scandir))
260 ((srfi srfi-1)
261 #:select (append-map every remove))
262 ((srfi srfi-26)
263 #:select (cut)))
264 (define (symlink-to file directory transform)
265 "Creates a symlink to FILE named (TRANSFORM FILE) in DIRECTORY."
266 (symlink file (string-append directory "/" (transform file))))
267 (define (directory-content directory)
268 "Creates a list of absolute path names inside DIRECTORY."
269 (map (lambda (name)
270 (string-append directory name))
271 (or (scandir directory (lambda (name)
272 (not (member name '("." "..")))))
273 '())))
274 (define name-ends-with-/? (cut string-suffix? "/" <>))
275 (define (name-is-store-entry? name)
276 "Return #t if NAME is a direct store entry and nothing inside."
277 (not (string-index (strip-store-file-name name) #\/)))
278 (let* ((collection (string-append #$output "/collection"))
279 (files '#$files)
280 (directories (filter name-ends-with-/? files))
281 (names-from-directories
282 (append-map (lambda (directory)
283 (directory-content directory))
284 directories))
285 (names (append names-from-directories
286 (remove name-ends-with-/? files))))
287 (mkdir-p collection)
288 (if (every file-exists? names)
289 (begin
290 (for-each (lambda (name)
291 (symlink-to name collection
292 (if (name-is-store-entry? name)
293 strip-store-file-name
294 basename)))
295 names)
296 #t)
297 #f)))))
298
299 (gexp->derivation "bootloader-collection"
300 build
301 #:local-build? #t
302 #:substitutable? #f
303 #:properties
304 `((type . profile-hook)
305 (hook . bootloader-collection))))
306
307 (profile (content (packages->manifest (list bootloader-package)))
ede4117f
S
308 (name "bootloader-profile")
309 (hooks (append (list bootloader-collection) hooks))
74eeb11d
S
310 (locales? #f)
311 (allow-collisions? #f)
312 (relative-symlinks? #f)))
313
314(define* (efi-bootloader-chain files
315 final-bootloader
316 #:key
ede4117f 317 (hooks '())
74eeb11d
S
318 installer)
319 "Define a bootloader chain with FINAL-BOOTLOADER as the final bootloader and
320certain directories and files from the store given in the list of FILES.
321
322FILES may contain file like objects produced by functions like plain-file,
323local-file, etc., or package contents produced with file-append. They will be
324collected inside a directory collection/ inside a generated bootloader profile,
325which will be passed to the INSTALLER.
326
327If a directory name in FILES ends with '/', then the directory content instead
328of the directory itself will be symlinked into the collection/ directory.
329
ede4117f
S
330The procedures in the HOOKS list can be used to further modify the bootloader
331profile. It is possible to pass a single function instead of a list.
74eeb11d
S
332
333If the INSTALLER argument is used, then this function will be called to install
ede4117f 334the bootloader. Otherwise the installer of the FINAL-BOOTLOADER will be called."
74eeb11d
S
335 (let* ((final-installer (or installer
336 (bootloader-installer final-bootloader)))
337 (profile (efi-bootloader-profile files
338 (bootloader-package final-bootloader)
ede4117f
S
339 (if (list? hooks)
340 hooks
341 (list hooks)))))
74eeb11d
S
342 (bootloader
343 (inherit final-bootloader)
344 (package profile)
345 (installer
346 #~(lambda (bootloader target mount-point)
347 (#$final-installer bootloader target mount-point)
348 (copy-recursively
349 (string-append bootloader "/collection")
350 (string-append mount-point target)
351 #:follow-symlinks? #t
352 #:log (%make-void-port "w")))))))