services: Add secret-service-type.
[jackhill/guix/guix.git] / gnu / build / image.scm
CommitLineData
f19cf27c
MO
1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
3;;; Copyright © 2016 Christopher Allan Webber <cwebber@dustycloud.org>
4;;; Copyright © 2016, 2017 Leo Famulari <leo@famulari.name>
5;;; Copyright © 2017 Marius Bakke <mbakke@fastmail.com>
6;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr>
7;;; Copyright © 2020 Mathieu Othacehe <m.othacehe@gmail.com>
8;;;
9;;; This file is part of GNU Guix.
10;;;
11;;; GNU Guix is free software; you can redistribute it and/or modify it
12;;; under the terms of the GNU General Public License as published by
13;;; the Free Software Foundation; either version 3 of the License, or (at
14;;; your option) any later version.
15;;;
16;;; GNU Guix is distributed in the hope that it will be useful, but
17;;; WITHOUT ANY WARRANTY; without even the implied warranty of
18;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;;; GNU General Public License for more details.
20;;;
21;;; You should have received a copy of the GNU General Public License
22;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
23
24(define-module (gnu build image)
25 #:use-module (guix build store-copy)
26 #:use-module (guix build syscalls)
27 #:use-module (guix build utils)
28 #:use-module (guix store database)
29 #:use-module (gnu build bootloader)
30 #:use-module (gnu build install)
31 #:use-module (gnu build linux-boot)
32 #:use-module (gnu image)
33 #:use-module (gnu system uuid)
34 #:use-module (ice-9 ftw)
35 #:use-module (ice-9 match)
36 #:use-module (srfi srfi-19)
37 #:use-module (srfi srfi-34)
38 #:use-module (srfi srfi-35)
39 #:export (make-partition-image
40 genimage
41 initialize-efi-partition
42 initialize-root-partition
43
44 make-iso9660-image))
45
46(define (sexp->partition sexp)
47 "Take SEXP, a tuple as returned by 'partition->gexp', and turn it into a
48<partition> record."
49 (match sexp
bd3716f6 50 ((size file-system file-system-options label uuid)
f19cf27c
MO
51 (partition (size size)
52 (file-system file-system)
bd3716f6 53 (file-system-options file-system-options)
f19cf27c
MO
54 (label label)
55 (uuid uuid)))))
56
57(define (size-in-kib size)
58 "Convert SIZE expressed in bytes, to kilobytes and return it as a string."
59 (number->string
60 (inexact->exact (ceiling (/ size 1024)))))
61
62(define (estimate-partition-size root)
63 "Given the ROOT directory, evalute and return its size. As this doesn't
64take the partition metadata size into account, take a 25% margin."
65 (* 1.25 (file-size root)))
66
16f9124d
MO
67(define* (make-ext-image partition target root
68 #:key
69 (owner-uid 0)
70 (owner-gid 0))
71 "Handle the creation of EXT2/3/4 partition images. See
72'make-partition-image'."
f19cf27c 73 (let ((size (partition-size partition))
16f9124d 74 (fs (partition-file-system partition))
bd3716f6 75 (fs-options (partition-file-system-options partition))
f19cf27c
MO
76 (label (partition-label partition))
77 (uuid (partition-uuid partition))
bd3716f6
MO
78 (journal-options "lazy_itable_init=1,lazy_journal_init=1"))
79 (apply invoke
7f75a7ec 80 `("fakeroot" "mke2fs" "-t" ,fs "-d" ,root
bd3716f6
MO
81 "-L" ,label "-U" ,(uuid->string uuid)
82 "-E" ,(format #f "root_owner=~a:~a,~a"
83 owner-uid owner-gid journal-options)
84 ,@fs-options
85 ,target
86 ,(format #f "~ak"
87 (size-in-kib
88 (if (eq? size 'guess)
89 (estimate-partition-size root)
90 size)))))))
f19cf27c
MO
91
92(define* (make-vfat-image partition target root)
93 "Handle the creation of VFAT partition images. See 'make-partition-image'."
94 (let ((size (partition-size partition))
95 (label (partition-label partition)))
7f75a7ec
MO
96 (invoke "fakeroot" "mkdosfs" "-n" label "-C" target
97 "-F" "16" "-S" "1024"
f19cf27c
MO
98 (size-in-kib
99 (if (eq? size 'guess)
100 (estimate-partition-size root)
101 size)))
102 (for-each (lambda (file)
103 (unless (member file '("." ".."))
104 (invoke "mcopy" "-bsp" "-i" target
105 (string-append root "/" file)
106 (string-append "::" file))))
107 (scandir root))))
108
109(define* (make-partition-image partition-sexp target root)
110 "Create and return the image of PARTITION-SEXP as TARGET. Use the given
111ROOT directory to populate the image."
112 (let* ((partition (sexp->partition partition-sexp))
113 (type (partition-file-system partition)))
114 (cond
16f9124d
MO
115 ((string-prefix? "ext" type)
116 (make-ext-image partition target root))
f19cf27c
MO
117 ((string=? type "vfat")
118 (make-vfat-image partition target root))
119 (else
120 (format (current-error-port)
121 "Unsupported partition type~%.")))))
122
123(define* (genimage config target)
124 "Use genimage to generate in TARGET directory, the image described in the
125given CONFIG file."
126 ;; genimage needs a 'root' directory.
127 (mkdir "root")
128 (invoke "genimage" "--config" config
129 "--outputpath" target))
130
131(define* (register-closure prefix closure
132 #:key
133 (deduplicate? #t) (reset-timestamps? #t)
4b9eecd3
JN
134 (schema (sql-schema))
135 (wal-mode? #t))
f19cf27c
MO
136 "Register CLOSURE in PREFIX, where PREFIX is the directory name of the
137target store and CLOSURE is the name of a file containing a reference graph as
138produced by #:references-graphs.. As a side effect, if RESET-TIMESTAMPS? is
139true, reset timestamps on store files and, if DEDUPLICATE? is true,
4b9eecd3
JN
140deduplicates files common to CLOSURE and the rest of PREFIX. Pass WAL-MODE?
141to call-with-database."
f19cf27c 142 (let ((items (call-with-input-file closure read-reference-graph)))
97a46055
LC
143 (parameterize ((sql-schema schema))
144 (with-database (store-database-file #:prefix prefix) db
4b9eecd3
JN
145 #:wal-mode? wal-mode?
146 (register-items db items
147 #:prefix prefix
148 #:deduplicate? deduplicate?
149 #:reset-timestamps? reset-timestamps?
150 #:registration-time %epoch)))))
f19cf27c
MO
151
152(define* (initialize-efi-partition root
153 #:key
05f37c16 154 grub-efi
f19cf27c 155 #:allow-other-keys)
72d1562a 156 "Install in ROOT directory, an EFI loader using GRUB-EFI."
05f37c16 157 (install-efi-loader grub-efi root))
f19cf27c
MO
158
159(define* (initialize-root-partition root
160 #:key
161 bootcfg
162 bootcfg-location
9c1adb24
MO
163 bootloader-package
164 bootloader-installer
f19cf27c
MO
165 (deduplicate? #t)
166 references-graphs
167 (register-closures? #t)
168 system-directory
8423c2d3 169 make-device-nodes
4b9eecd3 170 (wal-mode? #t)
f19cf27c
MO
171 #:allow-other-keys)
172 "Initialize the given ROOT directory. Use BOOTCFG and BOOTCFG-LOCATION to
173install the bootloader configuration.
174
175If REGISTER-CLOSURES? is true, register REFERENCES-GRAPHS in the store. If
176DEDUPLICATE? is true, then also deduplicate files common to CLOSURES and the
4b9eecd3
JN
177rest of the store when registering the closures. SYSTEM-DIRECTORY is the name
178of the directory of the 'system' derivation. Pass WAL-MODE? to
179register-closure."
f19cf27c
MO
180 (populate-root-file-system system-directory root)
181 (populate-store references-graphs root)
182
c77b9285 183 ;; Populate /dev.
8423c2d3
MO
184 (when make-device-nodes
185 (make-device-nodes root))
c77b9285 186
f19cf27c
MO
187 (when register-closures?
188 (for-each (lambda (closure)
189 (register-closure root
190 closure
191 #:reset-timestamps? #t
4b9eecd3
JN
192 #:deduplicate? deduplicate?
193 #:wal-mode? wal-mode?))
f19cf27c
MO
194 references-graphs))
195
9c1adb24
MO
196 (when bootloader-installer
197 (display "installing bootloader...\n")
198 (bootloader-installer bootloader-package #f root))
f19cf27c
MO
199 (when bootcfg
200 (install-boot-config bootcfg bootcfg-location root)))
201
202(define* (make-iso9660-image xorriso grub-mkrescue-environment
203 grub bootcfg system-directory root target
204 #:key (volume-id "Guix_image") (volume-uuid #f)
205 register-closures? (references-graphs '())
206 (compression? #t))
207 "Given a GRUB package, creates an iso image as TARGET, using BOOTCFG as
208GRUB configuration and OS-DRV as the stuff in it."
209 (define grub-mkrescue
210 (string-append grub "/bin/grub-mkrescue"))
211
212 (define grub-mkrescue-sed.sh
213 (string-append (getcwd) "/" "grub-mkrescue-sed.sh"))
214
215 ;; Use a modified version of grub-mkrescue-sed.sh, see below.
216 (copy-file (string-append xorriso
217 "/bin/grub-mkrescue-sed.sh")
218 grub-mkrescue-sed.sh)
219
220 ;; Force grub-mkrescue-sed.sh to use the build directory instead of /tmp
221 ;; that is read-only inside the build container.
222 (substitute* grub-mkrescue-sed.sh
223 (("/tmp/") (string-append (getcwd) "/"))
224 (("MKRESCUE_SED_XORRISO_ARGS \\$x")
225 (format #f "MKRESCUE_SED_XORRISO_ARGS $(echo $x | sed \"s|/tmp|~a|\")"
226 (getcwd))))
227
228 ;; 'grub-mkrescue' calls out to mtools programs to create 'efi.img', a FAT
229 ;; file system image, and mtools honors SOURCE_DATE_EPOCH for the mtime of
230 ;; those files. The epoch for FAT is Jan. 1st 1980, not 1970, so choose
231 ;; that.
232 (setenv "SOURCE_DATE_EPOCH"
233 (number->string
234 (time-second
235 (date->time-utc (make-date 0 0 0 0 1 1 1980 0)))))
236
237 ;; Our patched 'grub-mkrescue' honors this environment variable and passes
238 ;; it to 'mformat', which makes it the serial number of 'efi.img'. This
239 ;; allows for deterministic builds.
240 (setenv "GRUB_FAT_SERIAL_NUMBER"
241 (number->string (if volume-uuid
242
243 ;; On 32-bit systems the 2nd argument must be
244 ;; lower than 2^32.
245 (string-hash (iso9660-uuid->string volume-uuid)
246 (- (expt 2 32) 1))
247
248 #x77777777)
249 16))
250
251 (setenv "MKRESCUE_SED_MODE" "original")
252 (setenv "MKRESCUE_SED_XORRISO" (string-append xorriso "/bin/xorriso"))
253 (setenv "MKRESCUE_SED_IN_EFI_NO_PT" "yes")
254
255 (for-each (match-lambda
256 ((name . value) (setenv name value)))
257 grub-mkrescue-environment)
258
259 (apply invoke grub-mkrescue
260 (string-append "--xorriso=" grub-mkrescue-sed.sh)
261 "-o" target
262 (string-append "boot/grub/grub.cfg=" bootcfg)
263 root
264 "--"
265 ;; Set all timestamps to 1.
266 "-volume_date" "all_file_dates" "=1"
267
268 `(,@(if compression?
269 '(;; ‘zisofs’ compression reduces the total image size by
270 ;; ~60%.
271 "-zisofs" "level=9:block_size=128k" ; highest compression
272 ;; It's transparent to our Linux-Libre kernel but not to
273 ;; GRUB. Don't compress the kernel, initrd, and other
274 ;; files read by grub.cfg, as well as common
275 ;; already-compressed file names.
276 "-find" "/" "-type" "f"
277 ;; XXX Even after "--" above, and despite documentation
278 ;; claiming otherwise, "-or" is stolen by grub-mkrescue
279 ;; which then chokes on it (as ‘-o …’) and dies. Don't use
280 ;; "-or".
281 "-not" "-wholename" "/boot/*"
282 "-not" "-wholename" "/System/*"
283 "-not" "-name" "unicode.pf2"
284 "-not" "-name" "bzImage"
285 "-not" "-name" "*.gz" ; initrd & all man pages
286 "-not" "-name" "*.png" ; includes grub-image.png
287 "-exec" "set_filter" "--zisofs"
288 "--")
289 '())
290 "-volid" ,(string-upcase volume-id)
291 ,@(if volume-uuid
292 `("-volume_date" "uuid"
293 ,(string-filter (lambda (value)
294 (not (char=? #\- value)))
295 (iso9660-uuid->string
296 volume-uuid)))
297 '()))))