unofficial mirror of guix-patches@gnu.org 
 help / color / mirror / code / Atom feed
blob 6e71f30f0d3ac181d2b645ab104e4fd81b3e67fc 27483 bytes (raw)
name: gnu/bootloader/grub.scm 	 # note: path name is non-authoritative(*)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
 
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2016 Chris Marusich <cmmarusich@gmail.com>
;;; Copyright © 2017 Leo Famulari <leo@famulari.name>
;;; Copyright © 2017, 2020 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2019, 2020, 2023 Janneke Nieuwenhuizen <janneke@gnu.org>
;;; Copyright © 2019, 2020 Miguel Ángel Arruga Vivas <rosen644835@gmail.com>
;;; Copyright © 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2020 Stefan <stefan-guix@vodafonemail.de>
;;; Copyright © 2022 Karl Hallsby <karl@hallsby.com>
;;; Copyright © 2022 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
;;; Copyright © 2024 Tomas Volf <~@wolfsden.cz>
;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;; Copyright © 2024 Herman Rimm <herman@rimm.ee>
;;;
;;; This file is part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.

(define-module (gnu bootloader grub)
  #:use-module (gnu artwork)
  #:use-module (gnu bootloader)
  #:use-module (gnu packages bootloaders)
  #:autoload   (gnu packages gtk) (guile-cairo guile-rsvg)
  #:autoload   (gnu packages xorg) (xkeyboard-config)
  #:use-module (gnu system boot)
  #:use-module (gnu system file-systems)
  #:use-module (gnu system keyboard)
  #:use-module (gnu system locale)
  #:use-module (gnu system uuid)
  #:use-module (guix deprecation)
  #:use-module (guix diagnostics)
  #:use-module (guix gexp)
  #:use-module (guix i18n)
  #:use-module (guix records)
  #:use-module (guix utils)
  #:use-module (ice-9 match)
  #:use-module (srfi srfi-1)
  #:use-module (srfi srfi-26)
  #:use-module (srfi srfi-35)
  #:export (grub-theme
            grub-theme?
            grub-theme-image
            grub-theme-resolution
            grub-theme-color-normal
            grub-theme-color-highlight
            grub-theme-gfxmode

            grub.dir ; for (gnu build image) iso9660 images
            grub-bootloader
            grub-minimal-bootloader
            grub-efi-bootloader
            ;; deprecated
            grub-efi-removable-bootloader
            grub-efi32-bootloader
            grub-efi-netboot-bootloader
            grub-efi-netboot-removable-bootloader))

\f
;;;
;;; General utils.
;;;

(define (sanitize str)
  "In-G-exp procedure to sanitize a value for use in a GRUB script."
  #~(let ((glycerin (lambda (l r)
                      (if (pair? l) (append l r) (cons l r))))
          ;; In lieu of escaped-string from (guix read-print).
          (isopropyl (lambda (c)
                       (case c ((#\\ #\$ #\") '(#\\ ,c)) (else c)))))
      (use-modules (srfi srfi-1))
      (list->string (fold-right glycerin '()
                                (map isopropyl (string->list #$str))))))

(define* (search/target type targets var #:optional (port #f))
  "Returns a gexp of a GRUB search command for target TYPE, storing the
result in VAR.  Optionally outputs to the gexp PORT instead of returning
a string."
  (define (form name val)
    #~(format #$port "search.~a \"~a\" ~a~%" #$name #$val #$var))
  (with-targets targets
    ((type => (path :devpath) (device :device) (fs :fs)
              (label :label) (uuid :uuid))
     (cond ((member fs '("tftp" "nfs")) #~(format #$port "set ~a=tftp~%" #$var))
           (uuid (form "fs_uuid" (uuid->string uuid)))
           (label (form "fs_label" label))
           (else (form "file" (sanitize path)))))))

(define* (search/menu-entry device file var #:optional (port #f))
  "Return the GRUB 'search' command to look for DEVICE, which contains
FILE, a gexp.  The result is a gexp that can be inserted in the
grub.cfg-generation code to set the variable VAR.  This procedure is
able to handle DEVICEs unmounted at evaltime."
  (match device
    ;; Preferably refer to DEVICE by its UUID or label.  This is more
    ;; efficient and less ambiguous, see <http://bugs.gnu.org/22281>.
    ((? uuid? idfk) ; calling idfk uuid here errors for some reason
     #~(format #$port "search.fs_uuid ~a ~a~%" #$(uuid->string device) #$var))
    ((? file-system-label? label)
     #~(format #$port "search.fs_label \"~a\" ~a~%"
               #$(sanitize (file-system-label->string label)) #$var))
    ((? (lambda (device)
          (and (string? device) (string-contains device ":/"))) nfs-uri)
     ;; If the device is an NFS share, then we assume that the expected
     ;; file on that device (e.g. the GRUB background image or the kernel)
     ;; has to be loaded over the network.  Otherwise we would need an
     ;; additional device information for some local disk to look for that
     ;; file, which we do not have.
     ;;
     ;; TFTP is preferred to HTTP because it is used more widely and
     ;; specified in standards more widely--especially BOOTP/DHCPv4
     ;; defines a TFTP server for DHCP option 66, but not HTTP.
     ;;
     ;; Note: DHCPv6 specifies option 59 to contain a boot-file-url,
     ;; which can contain a HTTP or TFTP URL.
     ;;
     ;; Note: It is assumed that the file paths are of a similar
     ;; setup on both the TFTP server and the NFS server (it is
     ;; not possible to search for files on TFTP).
     ;;
     ;; TODO: Allow HTTP.
     #~(format #$port "set ~a=tftp~%" #$var))
    ((or #f (? string?))
     #~(format #$port "search.file \"~a\" ~a~%" #$(sanitize file) #$var))))

(define (when-list . xs) (filter identity xs))

\f
;;;
;;; Theming.
;;;

(define-record-type* <grub-theme>
  ;; Default theme contributed by Felipe López.
  grub-theme make-grub-theme grub-theme?
  (image           grub-theme-image
                   (default (file-append %artwork-repository
                                         "/grub/GuixSD-fully-black-4-3.svg")))
  (resolution      grub-theme-resolution
                   (default '(1024 . 768)))
  (color-normal    grub-theme-color-normal
                   (default '((fg . light-gray) (bg . black))))
  (color-highlight grub-theme-color-highlight
                   (default '((fg . yellow) (bg . black))))
  (gfxmode         grub-theme-gfxmode
                   (default '("auto"))))          ;list of string

(define (grub-theme-png theme)
  "Return the GRUB background image defined in THEME.  If the suffix of
the image file is \".svg\", then it is converted into a PNG file with
the resolution provided in CONFIG.  Returns #f if no file is provided."
  (match-record theme <grub-theme> (image resolution)
    (match resolution
      (((? number? width) . (? number? height))
       (computed-file "grub-image.png"
         (with-imported-modules '((gnu build svg) (guix build utils))
           (with-extensions (list guile-rsvg guile-cairo)
             #~(begin (use-modules (gnu build svg) (guix build utils))
                      (if (png-file? #$image) (copy-file #$image #$output)
                        (svg->png #$image #$output
                                  #:width #$width
                                  #:height #$height)))))))
      (_ image))))

\f
;;;
;;; Core config.
;;; GRUB architecture works by having a bootstage load up a core.img,
;;; which then sets the root and prefix variables, allowing grub to load
;;; its main config and modules, and then enter normal mode.  On i386-pc
;;; systems a boot.img is flashed which loads the core.img from the MBR
;;; gap, but on efi systems the core.img is just a PE executable, able
;;; to be booted directly.  We set up a minimal core.img capable of
;;; finding the user-configured 'install target to load its config from
;;; there.
;;;

(define (core.cfg targets store-crypto-devices)
  "Returns a filelike object for a core configuration file good enough to
decrypt STORE-CRYPTO-DEVICES and boot to normal."
  (define (crypto-device->cryptomount dev)
    (and (uuid? dev) ; ignore non-uuids - warning given by os
         #~(format port "cryptomount -u ~a~%"
                   ;; cryptomount only accepts UUID without the hyphen.
                   #$(string-delete #\- (uuid->string dev)))))

  (and=>
    (with-targets targets
      (('install => (path :devpath))
       #~(call-with-output-file #$output
           (lambda (port)
             #$@(filter ->bool
                  (map crypto-device->cryptomount store-crypto-devices))
             #$(search/target 'install targets "root" #~port)
             (format port "set \"prefix=($root)~a\"~%" #$(sanitize path))))))
    (cut computed-file "core.cfg" <>)))

;; XXX: Would a FORMAT symbol instead of string be better?
(define (core.cfg->core.img grub format bootloader-config
                            store-crypto-devices cfg fs)
  "Return a G-exp for a GRUB core image configured with CFG, built for
FORMAT and the file system FS."
  (let* ((tftp? (or (string=? fs "tftp") (string=? fs "nfs")))
         (bios? (string-prefix? format "pc"))
         (efi? (string=? format "efi"))
         (32? (bootloader-configuration-32bit? bootloader-config))
         (grub-format
           (cond ((string-prefix? "pc" format) "i386")
                 ((target-x86-32?) "i386")
                 ((target-x86-64?) (if 32? "i386" "x86_64"))
                 ((target-arm32?) "arm")
                 ((target-aarch64?) (if 32? "arm" "arm64"))
                 ((target-powerpc?) "powerpc")
                 ((target-riscv64?) "riscv64")
                 (else (raise (formatted-message
                                (G_ "unrecognized target arch '~a'!")
                                (or (%current-target-system)
                                    (%current-system)))))))
         (format (string-append grub-format "-" format
                                (if (and bios? tftp?) "-pxe" ""))))
    (with-imported-modules '((guix build utils))
      #~(begin
          (use-modules (guix build utils) (ice-9 textual-ports)
                       (srfi srfi-1))
          (apply invoke #$(file-append grub "/bin/grub-mkimage")
            "--output" #$output
            "--config" #$cfg
            "--prefix" "none" ; we override this in cfg
            ;; bios pxe uses pxeboot instead of diskboot - diff format
            "--format" #$format
            "--compression" "auto"
            ;; modules
            "minicmd"
            (append
              ;; disk drivers
              '#$(if bios? '("biosdisk") '())
              ;; partmaps
              ;; TODO: detect which to use.
              '#$(if tftp? '() '("part_msdos" "part_gpt"))
              ;; file systems
              '#$(cond ((member fs '("ext2" "ext3" "ext4")) '("ext2"))
                       ((member fs '("vfat" "fat32")) '("fat"))
                       ((and tftp? efi?) '("efinet"))
                       ((and tftp? bios?) '("pxe"))
                       (else (list fs)))
              ;; store crypto devs
              '#$(if (any uuid? store-crypto-devices)
                   '("luks" "luks2" "cryptomount") '())
              ;; search module that cfg uses
              (call-with-input-file #$cfg
                (lambda (port)
                   (let* ((str (get-string-all port))
                          (use (lambda (s) (string-contains str s))))
                     (cond ((use "search.fs_uuid") '("search_fs_uuid"))
                           ((use "search.fs_label") '("search_label"))
                           ((use "search.file") '("search_fs_file"))
                           (else '())))))))))))

;; XXX: Do we need LVM support here?
(define* (core.img grub format #:key bootloader-config store-crypto-devices
                               #:allow-other-keys)
  "The core image for GRUB, built for FORMAT."
  (let* ((targets (bootloader-configuration-targets bootloader-config))
         (cfg (core.cfg targets store-crypto-devices)))
    (and=>
      (and cfg
           (with-targets targets
             (('install => (fs :fs))
              (core.cfg->core.img grub format bootloader-config
                                  store-crypto-devices cfg fs))))
      (cut computed-file "core.img" <>
           #:options '(#:local-build? #t #:substitutable? #f)))))

\f
;;;
;;; Main config.
;;; This is what does the heavy lifting after core.img finds it.
;;;

;; TODO: use define-configuration.
(define (menu-entry->gexp entry extra-initrd port)
  (match-menu-entry
    entry
    (label device linux linux-arguments initrd multiboot-kernel
     multiboot-arguments multiboot-modules chain-loader)
    (let ((normalize-file
            (compose sanitize (cut normalize-file entry <>))))
      #~(begin
          (format #$port "menuentry ~s {~%  " #$label)
          #$(search/menu-entry
              device (or linux multiboot-kernel chain-loader) "boot" port)
          #$@(cond
               (linux
                 (list #~(format
                           #$port "  linux \"($boot)~a\" ~a~%"
                           #$(normalize-file linux)
                           ;; GRUB passes rest of the line _verbatim_.
                           (string-join (list #$@linux-arguments)))
                       #~(format #$port "  initrd ~a \"($boot)~a\"~%"
                                 (if #$extra-initrd
                                     (string-append "($boot)\""
                                                    (normalize-file
                                                      #$extra-initrd)
                                                    "\"")
                                     "")
                                 #$(normalize-file initrd))))
               ;; Previously, this provided a (wrong) root= argument.
               ;; Just don't bother anymore; better less info than
               ;; wrong info.
               (multiboot-kernel
                 (cons
                   #~(format #$port "  multiboot \"($boot)~a\" ~a~%"
                             #$(normalize-file multiboot-kernel)
                             (string-join (list #$@multiboot-arguments)))
                   (map (lambda (mod)
                          #~(format port "  module \"($boot)~a\"~%"
                                    #$(normalize-file mod)))
                        multiboot-modules)))
               (chain-loader
                 (list #~(format #$port "  chainloader \"~a\"~%"
                                 #$(normalize-file chain-loader)))))
          (format #$port "}~%")))))

;; TODO: use define-configuration.
(define (make-grub.cfg bootloader-config locale install menu-entries
                       old-entries terms->str outputs inputs theme)
  (define (colors->str c)
    (format #f "~a/~a" (assoc-ref c 'fg) (assoc-ref c 'bg)))

  (match-bootloader-configuration
    bootloader-config
    ;; XXX: Separate these fields into another record?
    (default-entry timeout serial-unit serial-speed)
    #~(call-with-output-file #$output
        (lambda (port)
          ;; preamble
          (format port "\
# This file was generated from your Guix configuration. Any changes
# will be lost upon reconfiguration~%")
          #$@(when-list
        ;; menu settings
               (and default-entry
                    #~(format port "set default=~a~%" #$default-entry))
               (and timeout
                    #~(format port "set timeout=~a~%" #$timeout))
        ;; gfxterm setup
               (and (memq 'gfxterm outputs)
                    #~(format
                        port "\
if loadfont unicode; then
  set gfxmode=~a
  insmod all_video
  insmod gfxterm
fi~%"
                        #$(string-join (grub-theme-gfxmode theme) ";")))
        ;; io
               (and (or serial-unit serial-speed)
                     #~(format
                         port "serial --unit=~a --speed=~a~%"
                         ;; Documented defaults are unit 0 at 9600 baud.
                         #$(number->string (or serial-unit 0))
                         #$(number->string (or serial-speed 9600))))
               (and (pair? outputs)
                    #~(format port "terminal_output ~a~%"
                              #$(terms->str outputs)))
               (and (pair? inputs)
                    #~(format port "terminal_input ~a~%"
                              #$(terms->str inputs)))
        ;; locale
               (and locale
                    #~(format port "\
set \"locale_dir=($root)~a/locales\"
set lang=~a~%"
                              #$(sanitize install)
                              #$(locale-definition-source
                                  (locale-name->definition locale))))
        ;; keyboard layout
               (and (bootloader-configuration-keyboard-layout
                      bootloader-config)
                    #~(format port "\
insmod keylayouts
keymap \"($root)~a/keymap~%\""
                              #$(sanitize install)))
        ;; theme
               (match-record theme <grub-theme>
                 (image color-normal color-highlight)
                 (and image
                      #~(format port "\
insmod png
if background_image \"($root)~a/image.png\"; then
  set color_normal=~a
  set color_highlight=~a
else
  set menu_color_normal=cyan/blue
  set menu_color_highlight=white/blue
fi~%"                           #$(sanitize install)
                                #$(colors->str color-normal)
                                #$(colors->str color-highlight)))))
        ;; menu entries
        #$@menu-entries
        #$@(if (pair? old-entries)
               (append (list #~(format
                                 port "submenu ~s {~%"
                                 "GNU system, old configurations..."))
                       old-entries
                       (list #~(format port "}~%")))
               '())
        (format port "\
if [ \"${grub_platform}\" == efi ]; then
  menuentry \"Firmware setup\" {
    fwsetup
  }
fi~%")))))

(define* (grub.cfg #:key bootloader-config
                         current-boot-alternative
                         old-boot-alternatives
                         locale
                         store-directory-prefix
                   #:allow-other-keys)
  "Returns a valid GRUB config given installer inputs.  Keymap and theme
image are taken from BOOTLOADER-CONFIG, LOCALE is provided explicitly."
  (match-bootloader-configuration
    bootloader-config
    ;; Can't match keyboard-layout here, because it's bound to its struct.
    (menu-entries targets extra-initrd theme terminal-outputs
     terminal-inputs)
    (define (entries->gexp entries)
      (map (cut menu-entry->gexp <> extra-initrd #~port)
           entries))

    (let* ((current-entry (boot-alternative->menu-entry
                            current-boot-alternative))
           (entries (entries->gexp (cons current-entry menu-entries)))
           (old-entries (entries->gexp (map boot-alternative->menu-entry
                                            old-boot-alternatives)))
           (terms->str (compose string-join (cut map symbol->string <>)))
           ;; Use the values provided, or the defaults otherwise.
           (outputs (or terminal-outputs '(gfxterm)))
           (inputs (or terminal-inputs '()))
           (theme (or theme (grub-theme))))
      (and=>
        (with-targets targets
          (('install => (install :devpath))
           (make-grub.cfg bootloader-config locale install entries
                          old-entries terms->str outputs inputs theme)))
        (cut computed-file "grub.cfg" <>
             ;; Since this file is rather unique, there's no point in
             ;; trying to substitute it.
             #:options '(#:local-build? #t #:substitutable? #f))))))

(define (keyboard-layout-file layout grub)
  "Process the X keyboard layout description LAYOUT, a <keyboard-layout>
record, and return a file in the format for GRUB keymaps.  LAYOUT must be
present in the 'share/X11/xkb/symbols/' directory of 'xkeyboard-config'."
  (computed-file
    (string-append "grub-keymap."
                   (string-map (match-lambda (#\, #\-) (chr chr))
                               (keyboard-layout-name layout)))
    (with-imported-modules '((guix build utils))
      #~(begin
          (use-modules (guix build utils))
          ;; 'grub-kbdcomp' passes all its arguments but '-o' to 'ckbcomp'
          ;; (from the 'console-setup' package).
          (invoke #+(file-append grub "/bin/grub-mklayout")
                  "-i" #+(keyboard-layout->console-keymap layout)
                  "-o" #$output)))))

(define* (grub.dir grub #:key bootloader-config locale
                        #:allow-other-keys . args)
  "Everything that should go in GRUB's prefix.  Includes fonts, modules,
locales, keymap, theme image, and grub.cfg."
  (let* ((theme (or (bootloader-configuration-theme bootloader-config)
                    (grub-theme)))
         (keyboard-layout (bootloader-configuration-keyboard-layout
                            bootloader-config))
         (lang (and=> locale (compose locale-definition-source
                                      locale-name->definition)))
         (lc-mesg (and lang (file-append grub "/share/locale" lang
                                         "/LC_MESSAGES/grub.mo"))))
    (computed-file "grub.dir"
      (with-imported-modules '((guix build utils))
        #~(begin
            (use-modules (guix build utils))
            (mkdir-p #$output)
            (chdir #$output)
            ;; grub files
            (copy-recursively #$(file-append grub "/lib/grub/") #$output
                              #:copy-file symlink)
            (mkdir "fonts")
            (symlink #$(file-append grub "/share/grub/unicode.pf2")
                     "fonts/unicode.pf2")
            ;; config file
            (symlink #$(apply grub.cfg args) "grub.cfg")
            ;; locales
            ;; XXX: Warn if missing?
            (when (and=> #$lc-mesg file-exists?)
              (mkdir "locales")
              (symlink #$lc-mesg
                       (string-append "locales/" #$lang ".mo")))
            ;; keymap
            #$@(when-list
                 (and keyboard-layout
                      #~(symlink #$(keyboard-layout-file keyboard-layout
                                                         grub)
                                 "keymap"))
            ;; image
                 (and (grub-theme-image theme)
                      #~(copy-file #$(grub-theme-png theme)
                                   "image.png")))))
      #:options '(#:local-build? #t #:substitutable? #f))))

\f
;;;
;;; Installers.
;;;

(define* (install-grub.dir grub #:key bootloader-config
                                #:allow-other-keys . args)
  (with-targets (bootloader-configuration-targets bootloader-config)
    (('install => (path :path))
     #~(copy-recursively #$(apply grub.dir grub args) #$path
                         #:log (%make-void-port "w")
                         #:follow-symlinks? #t
                         #:copy-file atomic-copy))))

(define (install-grub-bios grub)
  "Returns an installer for the bios-bootable grub package GRUB."
  (lambda* (#:key bootloader-config #:allow-other-keys . args)
    (gbegin (apply install-grub.dir grub args)
      (with-targets (bootloader-configuration-targets bootloader-config)
        (('disk => (device :device))
         #~(invoke #$(file-append grub "/sbin/grub-bios-setup") "-v" "-v"
                   "--directory" "/" ; can't be blank
                   "--device-map" "" ; no dev map - need to specify
                   "--boot-image"
                   #$(file-append grub "/lib/grub/i386-pc/boot.img")
                   "--core-image" #$(apply core.img grub "pc" args)
                   "--root-device" #$(string-append "hostdisk/" device)
                   #$device))))))

(define* (install-grub-efi #:key bootloader-config
                           #:allow-other-keys . args)
  "Installs GRUB into the system's UEFI bootloader, taking into account
user-specified requirements for a 32-bit or fallback bootloader."
  (let* ((32? (bootloader-configuration-32bit? bootloader-config))
         (grub (if 32? grub-efi32 grub-efi))
         (core (apply core.img grub "efi" args))
         (copy #~(lambda (dest) (copy-file #$core dest))))
    (gbegin (apply install-grub.dir grub args)
      (install-efi bootloader-config
                   #~`((,#$copy "grub.efi" . "GNU GRUB"))))))

\f
;;;
;;; Bootloaders.
;;;

(define %grub-default-targets
  (list (bootloader-target
          (type 'install)
          (offset 'root)
          (path "boot"))))

(define grub-bootloader
  (bootloader
    (name 'grub)
    (default-targets %grub-default-targets)
    (installer (install-grub-bios grub))))

(define grub-minimal-bootloader
  (bootloader
    (name 'grub)
    (default-targets %grub-default-targets)
    (installer (install-grub-bios grub-minimal))))

(define grub-efi-bootloader
  (bootloader
    (name 'grub-efi)
    (default-targets (list (bootloader-target
                             (type 'vendir)
                             (offset 'esp)
                             (path "EFI/Guix"))
                           (bootloader-target
                             (type 'install)
                             (offset 'esp)
                             (path "grub"))))
    (installer install-grub-efi)))

\f
;;;
;;; Deprecated!  Use the bootloader-config flags instead.  Or, in the
;;; case of netboot, set your 'install (or parent thereof) target fs to
;;; be "tftp" or "nfs".
;;;

(define (deprecated-installer installer removable? 32?)
  "INSTALLER with overrides for its bootloader-config argument."
  (lambda args
    (apply installer (substitute-keyword-arguments args
                       ((#:bootloader-config conf)
                        (bootloader-configuration
                          (inherit conf)
                          (efi-removable? removable?)
                          (32bit? 32?)))))))

(define-deprecated grub-efi-removable-bootloader grub-efi-bootloader
  (bootloader
    (inherit grub-efi-bootloader)
    (installer (deprecated-installer install-grub-efi #t #f))))

(define-deprecated grub-efi32-bootloader grub-efi-bootloader
  (bootloader
    (inherit grub-efi-bootloader)
    (installer (deprecated-installer install-grub-efi #f #t))))

(define %netboot-targets
  (list (bootloader-target
          (type 'install)
          (offset 'root)
          (path "boot")
          (file-system "tftp"))
        (bootloader-target
          (type 'vendir)
          (offset 'esp)
          (path "EFI/Guix"))))

(define-deprecated grub-efi-netboot-bootloader
                   grub-efi-bootloader
  (bootloader
    (inherit grub-efi-bootloader)
    (default-targets %netboot-targets)))

(define-deprecated grub-efi-netboot-removable-bootloader
                   grub-efi-bootloader
  (bootloader
    (inherit grub-efi-bootloader)
    (default-targets %netboot-targets)
    (installer (deprecated-installer install-grub-efi #t #f))))

debug log:

solving 6e71f30f0d ...
found 6e71f30f0d in https://yhetil.org/guix-patches/6db91ca2342d184c376c664843a5cbf838f46312.1727201267.git.herman@rimm.ee/
found 2723eda5f4 in https://git.savannah.gnu.org/cgit/guix.git
preparing index
index prepared:
100644 2723eda5f4d2333f1b2b899375e8e24c094f9d76	gnu/bootloader/grub.scm

applying [1/1] https://yhetil.org/guix-patches/6db91ca2342d184c376c664843a5cbf838f46312.1727201267.git.herman@rimm.ee/
diff --git a/gnu/bootloader/grub.scm b/gnu/bootloader/grub.scm
index 2723eda5f4..6e71f30f0d 100644

Checking patch gnu/bootloader/grub.scm...
Applied patch gnu/bootloader/grub.scm cleanly.

index at:
100644 6e71f30f0d3ac181d2b645ab104e4fd81b3e67fc	gnu/bootloader/grub.scm

(*) Git path names are given by the tree(s) the blob belongs to.
    Blobs themselves have no identifier aside from the hash of its contents.^

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).