[PATCH] Preparation for bootloader rewrite.

  • Open
  • quality assurance status badge
Details
3 participants
  • Herman Rimm
  • Lilah Tascheter
  • Ryan
Owner
unassigned
Submitted by
Herman Rimm
Severity
normal
Blocked by
H
H
Herman Rimm wrote on 12 Sep 18:58 +0200
[PATCH] guix: scripts: Rewrite reinstall-bootloader to use provenance data.
(address . guix-patches@gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
20240912165818.21580-1-herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

Looking up bootloaders by name is broken because (extlinux) bootloaders
share a name. Also, bootloader-configuration data is significant to
bootloader installation, so it shouldn't just use the default values.
Installation can rely on the provenance service instead, which should be
present for the vast majority of systems.

* guix/scripts/system.scm (install-bootloader-from-os,
install-bootloader-from-provenance): Add procedures.
(reinstall-bootloader): Remove procedure.
(switch-to-system-generation, process-command): Use
install-bootloader-from-provenance.

Change-Id: I5713a43ad4f9f32a129d980db06d70de16b03f27
---
Hello,

This requires patches from #69343. #72457 is big and I thought it would
be nice to separately review whatever possible, hence the new issue.

This is [PATCH v5 01/15] from issue #72457, but with a modified commit
description and the addition of an install-bootloader-from-os procedure,
to reduce nesting and only define local variables when relevant.

The (gnu tests reconfigure) tests all pass, though I myself cannot
roll-back or switch-generations for unrelated reasons. So please let me
know if this patch creates any trouble with the aformentioned and if you
have ideas for additional (gnu tests reconfigure) tests.

Thanks,
Herman

gnu/bootloader.scm | 2 ++
guix/scripts/system.scm | 72 +++++++++++++++--------------------------
2 files changed, 28 insertions(+), 46 deletions(-)

Toggle diff (125 lines)
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index f32e90e79d..61311b32cb 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -7,6 +7,8 @@
;;; Copyright © 2022 Josselin Poiret <dev@jpoiret.xyz>
;;; Copyright © 2022 Reza Alizadeh Majd <r.majd@pantherx.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.
;;;
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index 0f7d864e06..d14dfd8d81 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -88,6 +88,7 @@ (define-module (guix scripts system)
#:use-module (srfi srfi-37)
#:use-module (ice-9 format)
#:use-module (ice-9 match)
+ #:use-module (ice-9 receive)
#:use-module (rnrs bytevectors)
#:export (guix-system
read-operating-system
@@ -377,61 +378,39 @@ (define (switch-to-system-generation store spec)
(activate (string-append generation "/activate")))
(if number
(begin
- (reinstall-bootloader store number)
+ (install-bootloader-from-provenance store number)
(switch-to-generation* %system-profile number)
(unless-file-not-found (primitive-load activate)))
(leave (G_ "cannot switch to system generation '~a'~%") spec))))
-(define* (system-bootloader-name #:optional (system %system-profile))
- "Return the bootloader name stored in SYSTEM's \"parameters\" file."
- (let ((params (unless-file-not-found
- (read-boot-parameters-file system))))
- (boot-parameters-bootloader-name params)))
-
-(define (reinstall-bootloader store number)
- "Re-install bootloader for existing system profile generation NUMBER.
-STORE is an open connection to the store."
- (let* ((generation (generation-file-name %system-profile number))
- ;; Detect the bootloader used in %system-profile.
- (bootloader (lookup-bootloader-by-name (system-bootloader-name)))
-
- ;; Use the detected bootloader with default configuration.
- ;; It will be enough to allow the system to boot.
- (bootloader-config (bootloader-configuration
- (bootloader bootloader)))
-
- ;; Make the specified system generation the default entry.
- (chosen-alternative (generation->boot-alternative
- %system-profile number))
- (params (boot-alternative-parameters chosen-alternative))
- (locale (boot-parameters-locale params))
- (store-crypto-devices (boot-parameters-store-crypto-devices params))
- (store-directory-prefix
- (boot-parameters-store-directory-prefix params))
- (old-generations
- (delv number (reverse (generation-numbers %system-profile))))
- (previous-boot-alternatives (profile->boot-alternatives
- %system-profile old-generations))
- (entries (list (boot-parameters->menu-entry params)))
- (old-entries (map boot-parameters->menu-entry
- (map boot-alternative-parameters
- previous-boot-alternatives))))
+(define (install-bootloader-from-os store number os)
+ "Re-install an old bootloader defined in <operating-system> record OS,
+for system profile generation NUMBER, with store STORE."
+ (let* ((os (read-operating-system os))
+ (bootloader-config (operating-system-bootloader os))
+ (numbers (generation-numbers %system-profile))
+ (numbers (delv number (reverse numbers)))
+ (old (profile->boot-alternatives %system-profile numbers))
+ (bootcfg (operating-system-bootcfg os old)))
(run-with-store store
- (mlet* %store-monad
- ((bootcfg (lower-object
- ((bootloader-configuration-file-generator bootloader)
- bootloader-config entries
- #:locale locale
- #:store-crypto-devices store-crypto-devices
- #:store-directory-prefix store-directory-prefix
- #:old-entries old-entries)))
- (drvs -> (list bootcfg)))
+ (mlet* %store-monad ((bootcfg (lower-object bootcfg))
+ (drvs -> (list bootcfg)))
(mbegin %store-monad
(built-derivations drvs)
;; Only install bootloader configuration file.
(install-bootloader local-eval bootloader-config bootcfg
#:run-installer? #f))))))
+(define (install-bootloader-from-provenance store number)
+ "Re-install an old bootloader using provenance data for system profile
+generation NUMBER with store STORE."
+ (receive (_ os)
+ (system-provenance (generation-file-name %system-profile number))
+ (if os
+ (install-bootloader-from-os store number os)
+ (leave (G_ "cannot rollback to generation '~a': no provenance~%")
+ number))))
+
;;;
;;; Graphs.
@@ -1413,10 +1392,11 @@ (define-syntax-rule (with-store* store exp ...)
(let ((pattern (match args
(() #f)
((pattern) pattern)
- (x (leave (G_ "wrong number of arguments~%"))))))
+ (_ (leave (G_ "wrong number of arguments~%")))))
+ (number (generation-number %system-profile)))
(with-store* store
(delete-matching-generations store %system-profile pattern)
- (reinstall-bootloader store (generation-number %system-profile)))))
+ (install-bootloader-from-provenance store number))))
((switch-generation)
(let ((pattern (match args
((pattern) pattern)
--
2.45.2
H
H
Herman Rimm wrote on 20 Sep 12:37 +0200
[PATCH v2 00/15] Preparation for bootloader rewrite.
(address . 73202@debbugs.gnu.org)
cover.1726827025.git.herman@rimm.ee
Hello,

Patch #1 is now patch #5. This patches series adds the procedures,
macros and record used in #72457. I am not sure how to test these on
their own. Feel free to write some small tests, if you think of any.
If I failed to described a change or did it poorly, please let me know.

Patch #11 and patches with fewer changes can be merged out of order.

Yesterday I had trouble using control@debbugs.gnu.org to block one issue
on another. So if you could make this issue block on #69343, and #72457
block on this, I would appreciate that.

Cheers,
Herman

Herman Rimm (3):
guix: utils: Add flatten and flat-map from haunt.
guix: records: Add wrap-element procedure.
gnu: bootloader: Match records outside the module.

Lilah Tascheter (12):
gnu: bootloader: Remove deprecated bootloader-configuration field.
gnu: system: Remove useless boot parameters.
gnu: tests: reconfigure: Remove bootloader install test.
guix: scripts: Remove unused code.
guix: scripts: Rewrite reinstall-bootloader to use provenance data.
gnu: bootloader: Add bootloader-target record and infastructure.
gnu: bootloader: Add bootloader-configurations->gexp.
gnu: bootloader: Add device-subvol field to menu-entry record.
gnu: build: bootloader: Add efi-bootnums procedure.
gnu: bootloader: Install any bootloader to ESP.
gnu: system: boot: Add procedure.
teams: Add bootloading team.

doc/guix.texi | 34 +--
etc/teams.scm | 10 +
gnu/bootloader.scm | 504 +++++++++++++++++++++++++++++++++-----
gnu/build/bootloader.scm | 161 +++++++-----
gnu/build/image.scm | 23 +-
gnu/image.scm | 4 +
gnu/system.scm | 7 -
gnu/system/boot.scm | 14 +-
gnu/system/image.scm | 22 +-
gnu/tests/reconfigure.scm | 86 +------
guix/records.scm | 7 +
guix/scripts/system.scm | 96 +++-----
guix/ui.scm | 9 +
guix/utils.scm | 26 ++
tests/boot-parameters.scm | 18 +-
15 files changed, 677 insertions(+), 344 deletions(-)


base-commit: 9292d35ab63055e3752e698710a1a408cc7de7fd
--
2.45.2
H
H
Herman Rimm wrote on 20 Sep 12:37 +0200
[PATCH v2 01/15] gnu: bootloader: Remove deprecated bootloader-configuration field.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
19cb7c8d9d8d8cf1693007365a6867674325ccab.1726827025.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/bootloader.scm (warn-target-field-deprecation): Delete sanitizer.
(bootloader-configuration)[target]: Remove deprecated field.
(bootloader-configuration-target): Delete procedure.
(bootloader-configuration-targets): Do not use target field.

Change-Id: I3654d160f7306bb45a78b82ea6b249ff4281f739
---
gnu/bootloader.scm | 18 +-----------------
1 file changed, 1 insertion(+), 17 deletions(-)

Toggle diff (55 lines)
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index f32e90e79d..865521e6e5 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -66,7 +66,6 @@ (define-module (gnu bootloader)
bootloader-configuration
bootloader-configuration?
bootloader-configuration-bootloader
- bootloader-configuration-target ;deprecated
bootloader-configuration-targets
bootloader-configuration-menu-entries
bootloader-configuration-default-entry
@@ -244,24 +243,14 @@ (define-record-type* <bootloader>
;; The <bootloader-configuration> record contains bootloader independant
;; configuration used to fill bootloader configuration file.
-(define-with-syntax-properties (warn-target-field-deprecation
- (value properties))
- (when value
- (warning (source-properties->location properties)
- (G_ "the 'target' field is deprecated, please use 'targets' \
-instead~%")))
- value)
(define-record-type* <bootloader-configuration>
bootloader-configuration make-bootloader-configuration
bootloader-configuration?
(bootloader
- bootloader-configuration-bootloader) ;<bootloader>
+ bootloader-configuration-bootloader) ;<bootloader>
(targets %bootloader-configuration-targets
(default #f)) ;list of strings
- (target %bootloader-configuration-target ;deprecated
- (default #f)
- (sanitize warn-target-field-deprecation))
(menu-entries bootloader-configuration-menu-entries
(default '())) ;list of <menu-entry>
(default-entry bootloader-configuration-default-entry
@@ -285,14 +274,9 @@ (define-record-type* <bootloader-configuration>
(extra-initrd bootloader-configuration-extra-initrd
(default #f))) ;string | #f
-(define-deprecated (bootloader-configuration-target config)
- bootloader-configuration-targets
- (%bootloader-configuration-target config))
(define (bootloader-configuration-targets config)
(or (%bootloader-configuration-targets config)
- ;; TODO: Remove after the deprecated 'target' field is removed.
- (list (%bootloader-configuration-target config))
;; XXX: At least the GRUB installer (see (gnu bootloader grub)) has this
;; peculiar behavior of installing fonts and GRUB modules when DEVICE is #f,
;; hence the default value of '(#f) rather than '().
--
2.45.2
H
H
Herman Rimm wrote on 20 Sep 12:37 +0200
[PATCH v2 02/15] gnu: system: Remove useless boot parameters.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
7779b50c171a053248705ebd18f6b7ba4ea68a48.1726827025.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/system.scm (operating-system-boot-parameters,
operating-system-boot-parameters-file): Delete bootloader-menu-entries.
* gnu/system/boot.scm (boot-parameters)[bootloader-menu-entries]: Delete
field.
(read-boot-parameters): Don't read bootloader-menu-entries.
* tests/boot-parameters.scm (%grub-boot-parameters,
test-read-boot-parameters, test-read-boot-parameters): Don't include
bootloader-menu-entries.
("read, bootloader-menu-entries, default value"): Delete test.

Change-Id: I46d9cff4604dbfcf654b0820fdb77e72aecffbb4
---
gnu/system.scm | 7 -------
gnu/system/boot.scm | 8 --------
tests/boot-parameters.scm | 18 +++++-------------
3 files changed, 5 insertions(+), 28 deletions(-)

Toggle diff (145 lines)
diff --git a/gnu/system.scm b/gnu/system.scm
index 25afa96295..a3eee5aa24 100644
--- a/gnu/system.scm
+++ b/gnu/system.scm
@@ -1298,8 +1298,6 @@ (define* (operating-system-boot-parameters os root-device
(initrd initrd)
(multiboot-modules multiboot-modules)
(bootloader-name bootloader-name)
- (bootloader-menu-entries
- (bootloader-configuration-menu-entries (operating-system-bootloader os)))
(locale locale)
(store-device (ensure-not-/dev (file-system-device store)))
(store-directory-prefix (btrfs-store-subvolume-file-name file-systems))
@@ -1341,11 +1339,6 @@ (define* (operating-system-boot-parameters-file os)
#$(boot-parameters-multiboot-modules params)))
#~())
(bootloader-name #$(boot-parameters-bootloader-name params))
- (bootloader-menu-entries
- #$(map menu-entry->sexp
- (or (and=> (operating-system-bootloader os)
- bootloader-configuration-menu-entries)
- '())))
(locale #$(boot-parameters-locale params))
(store
(device
diff --git a/gnu/system/boot.scm b/gnu/system/boot.scm
index 833caef496..a898ab9549 100644
--- a/gnu/system/boot.scm
+++ b/gnu/system/boot.scm
@@ -54,7 +54,6 @@ (define-module (gnu system boot)
boot-parameters-label
boot-parameters-root-device
boot-parameters-bootloader-name
- boot-parameters-bootloader-menu-entries
boot-parameters-store-crypto-devices
boot-parameters-store-device
boot-parameters-store-directory-prefix
@@ -112,8 +111,6 @@ (define-record-type* <boot-parameters>
;; partition.
(root-device boot-parameters-root-device)
(bootloader-name boot-parameters-bootloader-name)
- (bootloader-menu-entries ;list of <menu-entry>
- boot-parameters-bootloader-menu-entries)
(store-device boot-parameters-store-device)
(store-mount-point boot-parameters-store-mount-point)
(store-directory-prefix boot-parameters-store-directory-prefix)
@@ -174,11 +171,6 @@ (define (read-boot-parameters port)
((_ args) args)
(#f 'grub))) ; for compatibility reasons.
- (bootloader-menu-entries
- (match (assq 'bootloader-menu-entries rest)
- ((_ entries) (map sexp->menu-entry entries))
- (#f '())))
-
;; In the past, we would store the directory name of linux instead of
;; the absolute file name of its image. Detect that and correct it.
(kernel (if (string=? kernel (direct-store-path kernel))
diff --git a/tests/boot-parameters.scm b/tests/boot-parameters.scm
index 2e7976aa6c..e1dc4620c3 100644
--- a/tests/boot-parameters.scm
+++ b/tests/boot-parameters.scm
@@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2019, 2020 Miguel Ángel Arruga Vivas <rosen644835@gmail.com>
;;; Copyright © 2022 Josselin Poiret <dev@jpoiret.xyz>
+;;; Copyright © 2024 Herman Rimm <herman@rimm.ee>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -34,6 +35,7 @@ (define-module (test-boot-parameters)
#:use-module (guix gexp)
#:use-module (guix store)
#:use-module (guix tests)
+ #:use-module (ice-9 format)
#:use-module (srfi srfi-34)
#:use-module (srfi srfi-64)
#:use-module (rnrs bytevectors))
@@ -64,7 +66,6 @@ (define %root-path "/")
(define %grub-boot-parameters
(boot-parameters
(bootloader-name 'grub)
- (bootloader-menu-entries '())
(root-device %default-root-device)
(label %default-label)
(kernel %default-kernel)
@@ -107,7 +108,6 @@ (define* (test-read-boot-parameters
#:key
(version %boot-parameters-version)
(bootloader-name 'grub)
- (bootloader-menu-entries '())
(label %default-label)
(root-device (quote-uuid %default-root-device))
(kernel %default-kernel)
@@ -127,7 +127,7 @@ (define* (test-read-boot-parameters
(cond ((eq? 'false val) (format #false fmt #false))
(val (format #false fmt val))
(else "")))
- (format #false "(boot-parameters~a~a~a~a~a~a~a~a~a~a)"
+ (format #f "(boot-parameters~@{~a~})"
(sexp-or-nothing " (version ~S)" version)
(sexp-or-nothing " (label ~S)" label)
(sexp-or-nothing " (root-device ~S)" root-device)
@@ -135,7 +135,7 @@ (define* (test-read-boot-parameters
(sexp-or-nothing " (kernel-arguments ~S)" kernel-arguments)
(sexp-or-nothing " (initrd ~S)" initrd)
(if with-store
- (format #false " (store~a~a~a~a)"
+ (format #f " (store~@{~a~})"
(sexp-or-nothing " (device ~S)" store-device)
(sexp-or-nothing " (mount-point ~S)"
store-mount-point)
@@ -145,9 +145,7 @@ (define* (test-read-boot-parameters
store-crypto-devices))
"")
(sexp-or-nothing " (locale ~S)" locale)
- (sexp-or-nothing " (bootloader-name ~a)" bootloader-name)
- (sexp-or-nothing " (bootloader-menu-entries ~S)"
- bootloader-menu-entries)))
+ (sexp-or-nothing " (bootloader-name ~a)" bootloader-name)))
(let ((str (generate-boot-parameters)))
(call-with-input-string str read-boot-parameters)))
@@ -170,7 +168,6 @@ (define* (test-read-boot-parameters
(test-assert "read, construction, optional fields"
(and (test-read-boot-parameters #:bootloader-name #false)
- (test-read-boot-parameters #:bootloader-menu-entries #false)
(test-read-boot-parameters #:kernel-arguments #false)
(test-read-boot-parameters #:with-store #false)
(test-read-boot-parameters #:store-device #false)
@@ -223,11 +220,6 @@ (define* (test-read-boot-parameters
(boot-parameters-bootloader-name
(test-read-boot-parameters #:bootloader-name #false)))
-(test-eq "read, bootloader-menu-entries, default value"
- '()
- (boot-parameters-bootloader-menu-entries
- (test-read-boot-parameters #:bootloader-menu-entries #false)))
-
(test-eq "read, kernel-arguments, default value"
'()
(boot-parameters-kernel-arguments
--
2.45.2
H
H
Herman Rimm wrote on 20 Sep 12:37 +0200
[PATCH v2 03/15] gnu: tests: reconfigure: Remove bootloader install test.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
58bd6e83712e96acd4c2c29ed7ff8be3c75a9d5a.1726827025.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/tests/reconfigure.scm (%test-install-bootloader): Delete variable.
(run-install-bootloader-test): Delete procedure.

Change-Id: I3654d160f7306bb45a78b82ea6b249ff4281f739
---
gnu/tests/reconfigure.scm | 86 +--------------------------------------
1 file changed, 1 insertion(+), 85 deletions(-)

Toggle diff (110 lines)
diff --git a/gnu/tests/reconfigure.scm b/gnu/tests/reconfigure.scm
index bcc7645fa3..8aa5311171 100644
--- a/gnu/tests/reconfigure.scm
+++ b/gnu/tests/reconfigure.scm
@@ -30,8 +30,7 @@ (define-module (gnu tests reconfigure)
#:use-module (guix scripts system reconfigure)
#:use-module (guix store)
#:export (%test-switch-to-system
- %test-upgrade-services
- %test-install-bootloader))
+ %test-upgrade-services))
;;; Commentary:
;;;
@@ -178,83 +177,6 @@ (define* (run-upgrade-services-test)
(disable (upgrade-services-program '() '() '(dummy) '())))
(test enable disable))))
-(define* (run-install-bootloader-test)
- "Run a test of an OS running INSTALL-BOOTLOADER-PROGRAM, which installs a
-bootloader's configuration file."
- (define os
- (marionette-operating-system
- (simple-operating-system)
- #:imported-modules '((gnu services herd)
- (guix combinators))))
-
- (define vm (virtual-machine
- (operating-system os)
- (volatile? #f)))
-
- (define (test script)
- (with-imported-modules '((gnu build marionette))
- #~(begin
- (use-modules (gnu build marionette)
- (ice-9 regex)
- (srfi srfi-1)
- (srfi srfi-64))
-
- (define marionette
- (make-marionette (list #$vm)))
-
- ;; Return the system generation paths that have GRUB menu entries.
- (define (generations-in-grub-cfg marionette)
- (let ((grub-cfg (marionette-eval
- '(begin
- (use-modules (rnrs io ports))
- (call-with-input-file "/boot/grub/grub.cfg"
- get-string-all))
- marionette)))
- (map (lambda (parameter)
- (second (string-split (match:substring parameter) #\=)))
- (list-matches "system=[^ ]*" grub-cfg))))
-
- (test-runner-current (system-test-runner #$output))
- (test-begin "install-bootloader")
-
- (test-assert "no prior menu entry for system generation"
- (not (member #$os (generations-in-grub-cfg marionette))))
-
- (test-assert "script successfully evaluated"
- (marionette-eval
- '(primitive-load #$script)
- marionette))
-
- (test-assert "menu entry created for system generation"
- (member #$os (generations-in-grub-cfg marionette)))
-
- (test-end))))
-
- (let* ((bootloader ((compose bootloader-configuration-bootloader
- operating-system-bootloader)
- os))
- ;; The typical use-case for 'install-bootloader-program' is to read
- ;; the boot parameters for the existing menu entries on the system,
- ;; parse them with 'boot-parameters->menu-entry', and pass the
- ;; results to 'operating-system-bootcfg'. However, to obtain boot
- ;; parameters, we would need to start the marionette, which we should
- ;; ideally avoid doing outside of the 'test' G-Expression. Thus, we
- ;; generate a bootloader configuration for the script as if there
- ;; were no existing menu entries. In the grand scheme of things, this
- ;; matters little -- these tests should not make assertions about the
- ;; behavior of 'operating-system-bootcfg'.
- (bootcfg (operating-system-bootcfg os '()))
- (bootcfg-file (bootloader-configuration-file bootloader)))
- (gexp->derivation
- "install-bootloader"
- ;; Due to the read-only nature of the virtual machines used in the system
- ;; test suite, the bootloader installer script is omitted. 'grub-install'
- ;; would attempt to write directly to the virtual disk if the
- ;; installation script were run.
- (test
- (install-bootloader-program #f #f #f bootcfg bootcfg-file '(#f) "/")))))
-
-
(define %test-switch-to-system
(system-test
(name "switch-to-system")
@@ -267,9 +189,3 @@ (define %test-upgrade-services
(description "Upgrade the Shepherd by unloading obsolete services and
loading new services.")
(value (run-upgrade-services-test))))
-
-(define %test-install-bootloader
- (system-test
- (name "install-bootloader")
- (description "Install a bootloader and its configuration file.")
- (value (run-install-bootloader-test))))
--
2.45.2
H
H
Herman Rimm wrote on 20 Sep 12:37 +0200
[PATCH v2 04/15] guix: scripts: Remove unused code.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
adc9c69d8284ac445cc0281d7921e41970c4b0f1.1726827025.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* guix/scripts/system.scm (bootloader-installer-script): Delete.

Change-Id: Ic1e0a523c814e4f1bf44b2721f5658f00066b0ab
---
guix/scripts/system.scm | 22 ----------------------
1 file changed, 22 deletions(-)

Toggle diff (35 lines)
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index 0f7d864e06..83a4de39d0 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -757,28 +757,6 @@ (define (maybe-suggest-running-guix-pull)
(warning (G_ "Consider running 'guix pull' before 'reconfigure'.~%"))
(warning (G_ "Failing to do that may downgrade your system!~%"))))
-(define (bootloader-installer-script installer
- bootloader device target)
- "Return a file calling INSTALLER gexp with given BOOTLOADER, DEVICE
-and TARGET arguments."
- (scheme-file "bootloader-installer"
- (with-imported-modules '((gnu build bootloader)
- (guix build utils))
- #~(begin
- (use-modules (gnu build bootloader)
- (guix build utils)
- (ice-9 binary-ports)
- (srfi srfi-34)
- (srfi srfi-35))
-
- (guard (c ((message-condition? c) ;XXX: i18n
- (format (current-error-port) "error: ~a~%"
- (condition-message c))
- (exit 1)))
- (#$installer #$bootloader #$device #$target)
- (info (G_ "bootloader successfully installed on '~a'~%")
- #$device))))))
-
(define (local-eval exp)
"Evaluate EXP, a G-Expression, in-place."
(mlet* %store-monad ((lowered (lower-gexp exp))
--
2.45.2
H
H
Herman Rimm wrote on 20 Sep 12:37 +0200
[PATCH v2 06/15] guix: utils: Add flatten and flat-map from haunt.
(address . 73202@debbugs.gnu.org)
fa66024b117d156422da77f50e1c2461410de125.1726827025.git.herman@rimm.ee
* guix/utils.scm (flatten, flat-map): Add procedures.

Change-Id: I1d7d49fd02115e3de09ed69bcf5f55a10423162e
---
guix/utils.scm | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)

Toggle diff (46 lines)
diff --git a/guix/utils.scm b/guix/utils.scm
index d8ce6ed886..e37c2d8770 100644
--- a/guix/utils.scm
+++ b/guix/utils.scm
@@ -139,6 +139,9 @@ (define-module (guix utils)
with-environment-variables
arguments-from-environment-variable
+ flatten
+ flat-map
+
config-directory
cache-directory
@@ -1027,6 +1030,29 @@ (define (with-atomic-file-output file proc)
(false-if-exception (delete-file template))
(close-port out)))))
+;; TODO: bring over other utility procedures from (haunt utils).
+(define* (flatten lst #:optional depth)
+ "Return a list that recursively concatenates the sub-lists of LST,
+up to DEPTH levels deep. When DEPTH is #f, the entire tree is
+flattened."
+ (if (and (number? depth) (zero? depth))
+ lst
+ (fold-right (match-lambda*
+ (((sub-list ...) memo)
+ (append (flatten sub-list (and depth (1- depth)))
+ memo))
+ ((elem memo)
+ (cons elem memo)))
+ '()
+ lst)))
+
+(define (flat-map proc . lsts)
+ "Apply PROC to each element of each list in LSTS and return a new
+list in which nested lists are concatenated into the result.
+
+For example, the list (1 2 (3)) would be flattened to (1 2 3)."
+ (flatten (apply map proc lsts) 1))
+
(define* (xdg-directory variable suffix #:key (ensure? #t))
"Return the name of the XDG directory that matches VARIABLE and SUFFIX,
after making sure that it exists if ENSURE? is true. VARIABLE is an
--
2.45.2
H
H
Herman Rimm wrote on 20 Sep 12:37 +0200
[PATCH v2 07/15] guix: records: Add wrap-element procedure.
(address . 73202@debbugs.gnu.org)
b901da23e25dd80eaebfe8e0379cf0f0da62f825.1726827025.git.herman@rimm.ee
* guix/records.scm (wrap-element): Add procedure.

Change-Id: If121c5d856e815776830282a0701a73e5ae2a7e7
---
guix/records.scm | 7 +++++++
1 file changed, 7 insertions(+)

Toggle diff (34 lines)
diff --git a/guix/records.scm b/guix/records.scm
index c084441441..b521a59257 100644
--- a/guix/records.scm
+++ b/guix/records.scm
@@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2012-2024 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Mark H Weaver <mhw@netris.org>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -31,6 +32,8 @@ (define-module (guix records)
alist->record
object->fields
recutils->alist
+ wrap-element
+
match-record
match-record-lambda))
@@ -606,6 +609,10 @@ (define (recutils->alist port)
(else
(error "unmatched line" line))))))))
+(define (wrap-element x)
+ "Sanitize a record field value X to a list."
+ (if (list? x) x (list x)))
+
;;;
;;; Pattern matching.
--
2.45.2
H
H
Herman Rimm wrote on 20 Sep 12:37 +0200
[PATCH v2 08/15] gnu: bootloader: Add bootloader-target record and infastructure.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
221de7ca9881aa279048d2e71bbed6263b26b165.1726827025.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/bootloader.scm (bootloader-target): New record.
(&target-error): New condition.
(pathcat, get-target-of-type, parent-of, unfold-pathcat, target-base?,
type-major?, ensure, ensure-target-types, ensure-majors, gbegin): New
procedures.
(define-literal, with-targets, :path, :devpath, :device, :fs, :label,
:uuid): New macros.
* guix/ui.scm (call-with-error-handling)[target-error?]: Handle
target-errors.

Change-Id: I3f07c9096dd8b91c04449b6360b3b7d21640da14
---
gnu/bootloader.scm | 229 ++++++++++++++++++++++++++++++++++++++++++++-
guix/ui.scm | 9 ++
2 files changed, 233 insertions(+), 5 deletions(-)

Toggle diff (305 lines)
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index 3ea50a4004..0c24996205 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -7,6 +7,7 @@
;;; Copyright © 2022 Josselin Poiret <dev@jpoiret.xyz>
;;; Copyright © 2022 Reza Alizadeh Majd <r.majd@pantherx.org>
;;; Copyright © 2024 Tomas Volf <~@wolfsden.cz>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -24,19 +25,28 @@
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (gnu bootloader)
+ #:autoload (gnu build file-systems)
+ (read-partition-label read-partition-uuid
+ find-partition-by-label find-partition-by-uuid)
#:use-module (gnu system file-systems)
#:use-module (gnu system uuid)
- #:use-module (guix gexp)
- #:use-module (guix profiles)
- #:use-module (guix records)
+ #:autoload (guix build syscalls)
+ (mounts mount-source mount-point mount-type)
#:use-module (guix deprecation)
- #:use-module ((guix ui) #:select (warn-about-load-error))
#:use-module (guix diagnostics)
+ #:use-module (guix gexp)
#:use-module (guix i18n)
+ #:use-module (guix modules)
+ #:use-module (guix profiles)
+ #:use-module (guix records)
+ #:use-module (guix utils)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 receive)
+ #:use-module (rnrs bytevectors)
#:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
#:use-module (srfi srfi-34)
#:use-module (srfi srfi-35)
- #:use-module (ice-9 match)
#:export (menu-entry
menu-entry?
menu-entry-label
@@ -62,6 +72,25 @@ (define-module (gnu bootloader)
bootloader-configuration-file
bootloader-configuration-file-generator
+ bootloader-target
+ bootloader-target?
+ bootloader-target-type
+ bootloader-target-expected?
+ bootloader-target-path
+ bootloader-target-offset
+ bootloader-target-device
+ bootloader-target-file-system
+ bootloader-target-label
+ bootloader-target-uuid
+
+ target-error?
+ target-error-type
+ target-error-targets
+
+ gbegin
+ :path :devpath :device :fs :label :uuid
+ with-targets
+
bootloader-configuration
bootloader-configuration?
bootloader-configuration-bootloader
@@ -232,6 +261,196 @@ (define-record-type* <bootloader>
(configuration-file bootloader-configuration-file)
(configuration-file-generator bootloader-configuration-file-generator))
+
+;;;
+;;; Bootloader target record.
+;;;
+
+;; <bootloader-target> represents different kinds of targets in a
+;; normalized form.
+
+(define-record-type* <bootloader-target>
+ bootloader-target make-bootloader-target bootloader-target?
+ (type bootloader-target-type) ; symbol
+ (expected? bootloader-target-expected? (default #f)) ; bool
+
+ (path bootloader-target-path (default #f)) ; string|#f
+ (offset bootloader-target-offset (thunked) ; symbol|#f
+ (default (and (bootloader-target-path this-record)
+ (not (eq? (bootloader-target-type this-record) 'root))
+ 'root)))
+ (device bootloader-target-device (default #f)) ; string|#f
+ (file-system bootloader-target-file-system (default #f)) ; string|#f
+ (label bootloader-target-label (default #f)) ; string|#f
+ (uuid bootloader-target-uuid (default #f))) ; uuid|#f
+
+(define-condition-type &target-error &error target-error?
+ (type target-error-type)
+ (targets target-error-targets))
+
+(define (pathcat p1 p2)
+ (string-append (string-trim-right p1 #\/) "/" (string-trim p2 #\/)))
+
+(define* (get-target-of-type type targets #:optional require?)
+ "Finds a target in TARGETS of type TYPE, returns REQUIRE? if #false,
+or provides an error otherwise."
+ (define (type? target)
+ (eq? type (bootloader-target-type target)))
+ (match (filter type? targets)
+ ((target _ ...) target)
+ (_ (and require?
+ (raise
+ (condition
+ (&message (message (G_ "required, but not provided")))
+ (&target-error (type type) (targets targets))))))))
+
+(define (parent-of target targets)
+ "Resolve the parent of TARGET in TARGETS, return #f if orphan."
+ (and=> (bootloader-target-offset target)
+ (cut get-target-of-type <> targets #t)))
+
+(define (unfold-pathcat target targets)
+ "Find the full VFS path of TARGET."
+ (let ((quit (lambda (t) (not (and=> t bootloader-target-path))))
+ (parent-of (cut parent-of <> targets)))
+ (reduce pathcat #f
+ (unfold quit bootloader-target-path parent-of target))))
+
+(define (target-base? t)
+ (or (not t) (match-record t <bootloader-target>
+ (expected? offset device label uuid)
+ (or device label uuid (not offset) expected?))))
+
+(define (type-major? target) (memq target '(root esp disk)))
+
+(define (ensure types targets end)
+ (let* ((used-in (cute unfold end identity (cut parent-of <> targets) <>))
+ (cons-in (lambda (t) (cons t (used-in t))))
+ (ensure (map (cut get-target-of-type <> targets #t) types)))
+ (filter identity (apply append (map cons-in ensure)))))
+
+(define* (ensure-target-types types targets #:optional (base? #f))
+ "Ensures all TYPES are provided in TARGETS. Returns #t iff every ensured
+target and its requirements are fully provided. Errors out when a required TYPE
+isn't provided. When BASE?, only ensure path requirements up to a device."
+ (not (any bootloader-target-expected?
+ (ensure types targets (if base? target-base? not)))))
+
+(define (ensure-majors types targets)
+ "Errors out when a required TYPE isn't provided, or when use of multiple major
+targets is detected."
+ (let* ((all (map bootloader-target-type (ensure types targets target-base?)))
+ (majors (delete-duplicates (filter type-major? all) eq?)))
+ (if (< (length majors) 2) #t
+ (raise (condition (&message (message (G_ "multiple major targets used")))
+ (&target-error (type majors) (targets targets)))))))
+
+
+
+(define (gbegin . gex)
+ "Sequence provided g-expressions."
+ (case (length gex) ((0) #f) ((1) (car gex)) (else #~(begin #$@gex))))
+
+;; syntax matching on free literals breaks easily, so bind them
+(define-syntax-rule (define-literal id) (define-syntax id (syntax-rules ())))
+(define-literal :path)
+(define-literal :devpath)
+(define-literal :device)
+(define-literal :fs)
+(define-literal :label)
+(define-literal :uuid)
+
+(define-syntax with-targets
+ (cut syntax-case <> ()
+ ((_ targets-expr block ...)
+ (let* ((genvars (compose generate-temporaries make-list))
+ (targets (car (genvars 1))))
+ (define (resolve in target base)
+ (with-syntax ((target target) (base base) (targets targets))
+ (syntax-case in
+ (:path :devpath :device :fs :label :uuid)
+ ((name _) (not (identifier? #'name))
+ #`(_ (syntax-error "binds must be to identifiers" #,in)))
+ ((name :device) #'(name (bootloader-target-device base)))
+ ((name :label) #'(name (bootloader-target-label base)))
+ ((name :uuid) #'(name (bootloader-target-uuid base)))
+ ((name :fs) #'(name (bootloader-target-file-system base)))
+ ((name :path) #'(name (unfold-pathcat target targets)))
+ ((name :devpath)
+ #'(name (if (target-base? target)
+ "/"
+ (pathcat "/" (bootloader-target-path target)))))
+ (_ #`(_ (syntax-error "invalid binding spec" #,in))))))
+
+ (define (binds spec)
+ (syntax-case spec (=>)
+ ((type => binds ...)
+ (with-syntax (((target base) (genvars 2)) (targets targets))
+ (append
+ #`((get (lambda (t) (get-target-of-type t targets #t)))
+ (target (get type))
+ (base (if (target-base? target)
+ target
+ (get (bootloader-target-offset target)))))
+ (map (cut resolve <> #'target #'base) #'(binds ...)))))
+ (_ #f)))
+
+ (define blocks
+ (cut syntax-case <> ()
+ ((spec ... expr)
+ (let* ((path? (cut syntax-case <> (:path) ((_ :path) #t) (_ #f)))
+ (qualified? (cut syntax-case <> (=>)
+ ((_ => spec ...) (any path? #'(spec ...)))
+ (_ #f)))
+ (specs #'(spec ...))
+ (lets (apply append (filter-map binds specs)))
+ (type (cut syntax-case <> (=>)
+ ((t => _ ...) #'t) (t #'t))))
+ (receive (full part) (partition qualified? specs)
+ #`(and (ensure-majors (list #,@(map type specs)) #,targets)
+ (ensure-target-types (list #,@(map type part))
+ #,targets #t)
+ (ensure-target-types (list #,@(map type full))
+ #,targets #f)
+ (let* #,lets expr)))))
+ (bad #'(syntax-error "malformed block" bad))))
+ "Using the list TARGETS, evaluate and sequence each BLOCK to produce a
+gexp. BLOCK is a set of SPECs followed by an EXPR (evaluating to a gexp).
+Each SPEC denotes a type of target to guard EXPR on their existance and
+full-qualification. This procedure is linear in regard to BLOCKs.
+
+SPEC may be of the following forms:
+@itemize
+@item 'TYPE Requires TYPE to be fully present or promised. Errors otherwise.
+@item ('TYPE => (VAR COMPONENT) ...): As type, but also binds variables. TYPE's
+ COMPONENT is bound to the variable VAR as described below.
+@end itemize
+
+Available COMPONENTs are:
+@itemize
+@item :path (fully-qualified)
+@item :devpath (relative from device)
+@item :device (auto-detected from uuid and label if not user-provided)
+@item :fs
+@item :label
+@item :uuid
+@end itemize
+
+Note that installers may be called multiple times with different targets being
+fully-qualified. To ensure that targets aren't installed multiple times, make sure
+that each BLOCK ensures at least one major target, either directly or indirectly.
+Likewise, at most one major target should be ensured per BLOCK, under the same
+conditions. Major targets originate from disk image handling, and are currently:
+@itemize
+@item disk
+@item root
+@item esp
+@end itemize"
+ #`(let ((#,targets targets-expr))
+ (apply gbegin (filter identity
+ (list #,@(map blocks #'(block ...))))))))
+ (bad #'(syntax-error "must provide targets" bad))))
+
;;;
;;; Bootloader configuration record.
diff --git a/guix/ui.scm b/guix/ui.scm
index 966f0611f6..0b1455cb3c 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -19,6 +19,7 @@
;;; Copyright © 2018 Steve Sprang <scs@stevesprang.com>
;;; Copyright © 2022 Taiju HIGASHI <higashi@taiju.info>
;;; Copyright © 2022 Liliana Marie Prikler <liliana.prikler@gmail.com>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -36,6 +37,8 @@
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (guix ui) ;import in user interfaces only
+ #:use-module ((gnu bootloader)
+ #:select (target-error? target-error-type target-error-targets))
#:use-module (guix i18n)
#:use-module (guix colors)
#:use-module (guix diagnostics)
@@ -861,6 +864,12 @@ (define (call-with-error-handling thunk)
(invoke-error-stop-signal c)
(cons (invoke-error-program c)
(invoke-error-arguments c))))
+ ((target-error? c)
+ (leave (G_ "bootloader-target '~a'~@[: ~a~] ~
+ among the following targets:~%~{~y~}")
+ (target-error-type c)
+ (and (message-condition? c) (condition-message c))
+ (target-error-targets c)))
((formatted-message? c)
(apply report-error
--
2.45.2
H
H
Herman Rimm wrote on 20 Sep 12:37 +0200
[PATCH v2 09/15] gnu: bootloader: Add bootloader-configurations->gexp.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
36b06c055689a23a29e1ad8cc0e2617a1f57f900.1726827025.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/bootloader.scm (bootloader)[default-targets]: Add field.
(target-overrides, normalize, bootloader-configuration->gexp,
bootloader-configurations->gexp): New procedures.

Change-Id: I3654d160f7306bb45a78b82ea6b249ff4281f739
---
gnu/bootloader.scm | 108 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 108 insertions(+)

Toggle diff (142 lines)
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index 0c24996205..c77de6f55e 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -67,6 +67,7 @@ (define-module (gnu bootloader)
bootloader?
bootloader-name
bootloader-package
+ bootloader-default-targets
bootloader-installer
bootloader-disk-image-installer
bootloader-configuration-file
@@ -107,6 +108,8 @@ (define-module (gnu bootloader)
bootloader-configuration-device-tree-support?
bootloader-configuration-extra-initrd
+ bootloader-configuration->gexp
+ bootloader-configurations->gexp
efi-bootloader-chain))
@@ -255,6 +258,7 @@ (define-record-type* <bootloader>
bootloader?
(name bootloader-name)
(package bootloader-package)
+ (default-targets bootloader-default-targets (default '()))
(installer bootloader-installer)
(disk-image-installer bootloader-disk-image-installer
(default #f))
@@ -498,6 +502,110 @@ (define (bootloader-configuration-targets config)
;; hence the default value of '(#f) rather than '().
(list #f)))
+
+;;;
+;;; Bootloader installation paths.
+;;;
+
+(define (target-overrides . layers)
+ (let* ((types (flat-map (cute map bootloader-target-type <>) layers))
+ ;; TODO: use loop instead of fold for early termination.
+ (pred (lambda (type layer found)
+ (or found (get-target-of-type type layer))))
+ (find (lambda (type) (fold (cute pred type <> <>) #f layers))))
+ (filter identity (map find (delete-duplicates types)))))
+
+(define (normalize targets)
+ "Augments TARGETS with filesystem information at runtime, allowing
+users to specify a lot less information. Puts TARGETS into a normal
+form, where each path is fully specified up to a device offset."
+ (define (mass m)
+ `((,(mount-source m) . ,m)
+ (,(mount-point m) . ,m)))
+
+ (define (accessible=> d f)
+ (and d (access? d R_OK) (f d)))
+
+ (define (fixuuid target)
+ (match-record target <bootloader-target> (uuid file-system)
+ (let ((type (cond ((not file-system) 'dce)
+ ((member file-system '("vfat" "fat32")) 'fat)
+ ((string=? file-system "ntfs") 'ntfs)
+ ((string=? file-system "iso9660") 'iso9660)
+ (else 'dce))))
+ (bootloader-target (inherit target)
+ (uuid (cond ((uuid? uuid) uuid)
+ ((bytevector? uuid) (bytevector->uuid uuid type))
+ ((string? uuid) (string->uuid uuid type))
+ (else #f)))))))
+
+ (define (arborify target targets)
+ (let* ((up (lambda (t) (and t (parent-of t targets))))
+ (proto (unfold target-base? identity up (up target) list))
+ (chain (reverse (cons target proto))))
+ (bootloader-target
+ (inherit target)
+ (offset (and=> (car chain) bootloader-target-type))
+ (path (reduce pathcat #f (map bootloader-target-path (cdr chain)))))))
+
+ (let ((amounts (delay (apply append (map mass (mounts))))))
+ (define (assoc-mnt f)
+ (lambda (v) (and=> (assoc-ref (force amounts) v) f)))
+
+ (define (scrape target)
+ (match-record target <bootloader-target>
+ (expected? path offset device label uuid file-system)
+ (if expected? target
+ (bootloader-target
+ (inherit target)
+ (device (or device
+ (false-if-exception
+ (or (and=> uuid find-partition-by-uuid)
+ (and=> label find-partition-by-label)))
+ (and path ((assoc-mnt mount-source)
+ (unfold-pathcat target targets)))))
+ (label (or label (accessible=> device read-partition-label)))
+ (uuid (or uuid (accessible=> device read-partition-uuid)))
+ (file-system (or file-system (and=> device (assoc-mnt mount-type))))
+ (offset (and path offset))
+ (path (or path (and=> device (assoc-mnt mount-point))))))))
+
+ (let ((mid (map (compose fixuuid scrape) targets)))
+ (map (cut arborify <> mid) mid))))
+
+(define* (bootloader-configuration->gexp bootloader-config args #:key
+ (root-offset "/") (overrides '()))
+ "Returns a gexp to install BOOTLOADER-CONFIG to its targets, passing ARGS
+to each installer alongside the additional #:bootloader-config keyword
+arguments. Target OVERRIDES are applied and all path targets have ROOT-OFFSET
+applied. The following keyword arguments are expected in ARGS:
+@enumerate
+@item current-boot-alternative
+@item old-boot-alternatives
+@item locale (from bootmeta)
+@item store-directory-prefix (from bootmeta)
+@item store-crypto-devices (from bootmeta)
+@end enumerate"
+ (let* ((bootloader (bootloader-configuration-bootloader bootloader-config))
+ (installer (bootloader-installer bootloader))
+ (auto-targets (list (bootloader-target
+ (type 'root)
+ (path root-offset)
+ (offset #f))))
+ (targets (target-overrides
+ overrides
+ (bootloader-configuration-targets bootloader-config)
+ auto-targets
+ (bootloader-default-targets bootloader)))
+ (conf (bootloader-configuration
+ (inherit bootloader-config)
+ (targets (normalize targets)))))
+ (apply installer #:bootloader-config conf args)))
+
+(define (bootloader-configurations->gexp bootloader-configs . rest)
+ (apply gbegin (filter-map (cut apply bootloader-configuration->gexp <> rest)
+ bootloader-configs)))
+
;;;
;;; Bootloaders.
--
2.45.2
H
H
Herman Rimm wrote on 20 Sep 12:37 +0200
[PATCH v2 05/15] guix: scripts: Rewrite reinstall-bootloader to use provenance data.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
5b95c2bdceeeefb36857f7dfb869d19140fbae9d.1726827025.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

Looking up bootloaders by name is broken because (extlinux) bootloaders
share a name. Also, bootloader-configuration data is significant to
bootloader installation, so it shouldn't just use the default values.
Installation can rely on the provenance service instead, which should be
present for the vast majority of systems.

* gnu/bootloader.scm (%bootloaders): Delete variable.
(lookup-bootloader-by-name, bootloader-modules): Delete procedures.
* guix/scripts/system.scm (install-bootloader-from-os,
install-bootloader-from-provenance): Add procedures.
(reinstall-bootloader): Remove procedure.
(switch-to-system-generation, process-command): Use
install-bootloader-from-provenance.

Change-Id: I5713a43ad4f9f32a129d980db06d70de16b03f27
---
gnu/bootloader.scm | 26 ---------------
guix/scripts/system.scm | 74 ++++++++++++++++-------------------------
2 files changed, 28 insertions(+), 72 deletions(-)

Toggle diff (172 lines)
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index 865521e6e5..3ea50a4004 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -26,7 +26,6 @@
(define-module (gnu bootloader)
#:use-module (gnu system file-systems)
#:use-module (gnu system uuid)
- #:use-module (guix discovery)
#:use-module (guix gexp)
#:use-module (guix profiles)
#:use-module (guix records)
@@ -79,8 +78,6 @@ (define-module (gnu bootloader)
bootloader-configuration-device-tree-support?
bootloader-configuration-extra-initrd
- %bootloaders
- lookup-bootloader-by-name
efi-bootloader-chain))
@@ -287,29 +284,6 @@ (define (bootloader-configuration-targets config)
;;; Bootloaders.
;;;
-(define (bootloader-modules)
- "Return the list of bootloader modules."
- (all-modules (map (lambda (entry)
- `(,entry . "gnu/bootloader"))
- %load-path)
- #:warn warn-about-load-error))
-
-(define %bootloaders
- ;; The list of publically-known bootloaders.
- (delay (fold-module-public-variables (lambda (obj result)
- (if (bootloader? obj)
- (cons obj result)
- result))
- '()
- (bootloader-modules))))
-
-(define (lookup-bootloader-by-name name)
- "Return the bootloader called NAME."
- (or (find (lambda (bootloader)
- (eq? name (bootloader-name bootloader)))
- (force %bootloaders))
- (leave (G_ "~a: no such bootloader~%") name)))
-
(define (efi-bootloader-profile packages files hooks)
"Creates a profile from the lists of PACKAGES and FILES from the store.
This profile is meant to be used by the bootloader-installer.
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index 83a4de39d0..d23f9153e5 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -11,6 +11,8 @@
;;; Copyright © 2021 Brice Waegeneire <brice@waegenei.re>
;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com>
;;; Copyright © 2022 Tobias Geerinckx-Rice <me@tobias.gr>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
+;;; Copyright © 2024 Herman Rimm <herman@rimm.ee>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -88,6 +90,7 @@ (define-module (guix scripts system)
#:use-module (srfi srfi-37)
#:use-module (ice-9 format)
#:use-module (ice-9 match)
+ #:use-module (ice-9 receive)
#:use-module (rnrs bytevectors)
#:export (guix-system
read-operating-system
@@ -377,61 +380,39 @@ (define (switch-to-system-generation store spec)
(activate (string-append generation "/activate")))
(if number
(begin
- (reinstall-bootloader store number)
+ (install-bootloader-from-provenance store number)
(switch-to-generation* %system-profile number)
(unless-file-not-found (primitive-load activate)))
(leave (G_ "cannot switch to system generation '~a'~%") spec))))
-(define* (system-bootloader-name #:optional (system %system-profile))
- "Return the bootloader name stored in SYSTEM's \"parameters\" file."
- (let ((params (unless-file-not-found
- (read-boot-parameters-file system))))
- (boot-parameters-bootloader-name params)))
-
-(define (reinstall-bootloader store number)
- "Re-install bootloader for existing system profile generation NUMBER.
-STORE is an open connection to the store."
- (let* ((generation (generation-file-name %system-profile number))
- ;; Detect the bootloader used in %system-profile.
- (bootloader (lookup-bootloader-by-name (system-bootloader-name)))
-
- ;; Use the detected bootloader with default configuration.
- ;; It will be enough to allow the system to boot.
- (bootloader-config (bootloader-configuration
- (bootloader bootloader)))
-
- ;; Make the specified system generation the default entry.
- (chosen-alternative (generation->boot-alternative
- %system-profile number))
- (params (boot-alternative-parameters chosen-alternative))
- (locale (boot-parameters-locale params))
- (store-crypto-devices (boot-parameters-store-crypto-devices params))
- (store-directory-prefix
- (boot-parameters-store-directory-prefix params))
- (old-generations
- (delv number (reverse (generation-numbers %system-profile))))
- (previous-boot-alternatives (profile->boot-alternatives
- %system-profile old-generations))
- (entries (list (boot-parameters->menu-entry params)))
- (old-entries (map boot-parameters->menu-entry
- (map boot-alternative-parameters
- previous-boot-alternatives))))
+(define (install-bootloader-from-os store number os)
+ "Re-install an old bootloader defined in <operating-system> record OS,
+for system profile generation NUMBER, with store STORE."
+ (let* ((os (read-operating-system os))
+ (bootloader-config (operating-system-bootloader os))
+ (numbers (generation-numbers %system-profile))
+ (numbers (delv number (reverse numbers)))
+ (old (profile->boot-alternatives %system-profile numbers))
+ (bootcfg (operating-system-bootcfg os old)))
(run-with-store store
- (mlet* %store-monad
- ((bootcfg (lower-object
- ((bootloader-configuration-file-generator bootloader)
- bootloader-config entries
- #:locale locale
- #:store-crypto-devices store-crypto-devices
- #:store-directory-prefix store-directory-prefix
- #:old-entries old-entries)))
- (drvs -> (list bootcfg)))
+ (mlet* %store-monad ((bootcfg (lower-object bootcfg))
+ (drvs -> (list bootcfg)))
(mbegin %store-monad
(built-derivations drvs)
;; Only install bootloader configuration file.
(install-bootloader local-eval bootloader-config bootcfg
#:run-installer? #f))))))
+(define (install-bootloader-from-provenance store number)
+ "Re-install an old bootloader using provenance data for system profile
+generation NUMBER with store STORE."
+ (receive (_ os)
+ (system-provenance (generation-file-name %system-profile number))
+ (if os
+ (install-bootloader-from-os store number os)
+ (leave (G_ "cannot rollback to generation '~a': no provenance~%")
+ number))))
+
;;;
;;; Graphs.
@@ -1391,10 +1372,11 @@ (define (process-command command args opts)
(let ((pattern (match args
(() #f)
((pattern) pattern)
- (x (leave (G_ "wrong number of arguments~%"))))))
+ (_ (leave (G_ "wrong number of arguments~%")))))
+ (number (generation-number %system-profile)))
(with-store* store
(delete-matching-generations store %system-profile pattern)
- (reinstall-bootloader store (generation-number %system-profile)))))
+ (install-bootloader-from-provenance store number))))
((switch-generation)
(let ((pattern (match args
((pattern) pattern)
--
2.45.2
H
H
Herman Rimm wrote on 20 Sep 12:37 +0200
[PATCH v2 10/15] gnu: bootloader: Add device-subvol field to menu-entry record.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
9ebe41c442f375788d3783fb780d11f8bdf3ed75.1726827025.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/bootloader.scm (menu-entry-device-subvol): Add and export field.
(normalize-file): Add procedure.
(device->sexp): Match device-subvol and include in S-expression.
(sexp->menu-entry): Try match device-subvol and include in menu-entry.
* gnu/system/boot.scm (boot-parameters->menu-entry): Add device-subvol
value to menu-entry.

Change-Id: I3654d160f7306bb45a78b82ea6b249ff4281f739
---
gnu/bootloader.scm | 51 ++++++++++++++++++++++++++++++++++-----------
gnu/system/boot.scm | 2 ++
2 files changed, 41 insertions(+), 12 deletions(-)

Toggle diff (168 lines)
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index c77de6f55e..f1352122a9 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -51,15 +51,17 @@ (define-module (gnu bootloader)
menu-entry?
menu-entry-label
menu-entry-device
+ menu-entry-device-mount-point
+ menu-entry-device-subvol
menu-entry-linux
menu-entry-linux-arguments
menu-entry-initrd
- menu-entry-device-mount-point
menu-entry-multiboot-kernel
menu-entry-multiboot-arguments
menu-entry-multiboot-modules
menu-entry-chain-loader
+ normalize-file
menu-entry->sexp
sexp->menu-entry
@@ -126,6 +128,8 @@ (define-record-type* <menu-entry>
(default #f))
(device-mount-point menu-entry-device-mount-point
(default #f))
+ (device-subvol menu-entry-device-subvol
+ (default #f))
(linux menu-entry-linux
(default #f))
(linux-arguments menu-entry-linux-arguments
@@ -142,6 +146,18 @@ (define-record-type* <menu-entry>
(chain-loader menu-entry-chain-loader
(default #f))) ; string, path of efi file
+(define (normalize-file entry file)
+ "Normalize a file FILE stored in a menu entry into one suitable for a
+bootloader. Realizes device-mount-point and device-subvol."
+ (match-menu-entry entry (device-mount-point device-subvol)
+ ;; Avoid using cut procedure from SRFI-26 inside G-exp.
+ (let ((mount (and=> device-mount-point (cut string-trim <> #\/))))
+ #~(let* ((file (string-trim #$file #\/))
+ (file (if (and #$mount (string-prefix? #$mount file))
+ (substring file (string-length #$mount))
+ file)))
+ (string-append (or #$device-subvol "") "/" file)))))
+
(define (report-menu-entry-error menu-entry)
(raise
(condition
@@ -169,7 +185,7 @@ (define (menu-entry->sexp entry)
`(label ,(file-system-label->string label)))
(_ device)))
(match entry
- (($ <menu-entry> label device mount-point
+ (($ <menu-entry> label device mount-point subvol
(? identity linux) linux-arguments (? identity initrd)
#f () () #f)
`(menu-entry (version 0)
@@ -178,8 +194,9 @@ (define (menu-entry->sexp entry)
(device-mount-point ,mount-point)
(linux ,linux)
(linux-arguments ,linux-arguments)
- (initrd ,initrd)))
- (($ <menu-entry> label device mount-point #f () #f
+ (initrd ,initrd)
+ (device-subvol ,subvol)))
+ (($ <menu-entry> label device mount-point subvol #f () #f
(? identity multiboot-kernel) multiboot-arguments
multiboot-modules #f)
`(menu-entry (version 0)
@@ -188,19 +205,23 @@ (define (menu-entry->sexp entry)
(device-mount-point ,mount-point)
(multiboot-kernel ,multiboot-kernel)
(multiboot-arguments ,multiboot-arguments)
- (multiboot-modules ,multiboot-modules)))
- (($ <menu-entry> label device mount-point #f () #f #f () ()
+ (multiboot-modules ,multiboot-modules)
+ (device-subvol ,subvol)))
+ (($ <menu-entry> label device mount-point subvol #f () #f #f () ()
(? identity chain-loader))
`(menu-entry (version 0)
(label ,label)
(device ,(device->sexp device))
(device-mount-point ,mount-point)
- (chain-loader ,chain-loader)))
+ (chain-loader ,chain-loader)
+ (device-subvol ,subvol)))
(_ (report-menu-entry-error entry))))
(define (sexp->menu-entry sexp)
"Turn SEXP, an sexp as returned by 'menu-entry->sexp', into a <menu-entry>
record."
+ ;; XXX: The match ORs shadow subvol.
+ (define subvol #f)
(define (sexp->device device-sexp)
(match device-sexp
(('uuid type uuid-string)
@@ -213,35 +234,41 @@ (define (sexp->menu-entry sexp)
('label label) ('device device)
('device-mount-point mount-point)
('linux linux) ('linux-arguments linux-arguments)
- ('initrd initrd) _ ...)
+ ('initrd initrd)
+ (or ('device-subvol subvol _ ...) (_ ...)))
(menu-entry
(label label)
(device (sexp->device device))
(device-mount-point mount-point)
+ (device-subvol subvol)
(linux linux)
(linux-arguments linux-arguments)
(initrd initrd)))
(('menu-entry ('version 0)
('label label) ('device device)
- ('device-mount-point mount-point)
+ ('device-mount-point mount-point) ('device-subvol subvol)
('multiboot-kernel multiboot-kernel)
('multiboot-arguments multiboot-arguments)
- ('multiboot-modules multiboot-modules) _ ...)
+ ('multiboot-modules multiboot-modules)
+ (or ('device-subvol subvol _ ...) (_ ...)))
(menu-entry
(label label)
(device (sexp->device device))
(device-mount-point mount-point)
+ (device-subvol subvol)
(multiboot-kernel multiboot-kernel)
(multiboot-arguments multiboot-arguments)
(multiboot-modules multiboot-modules)))
(('menu-entry ('version 0)
('label label) ('device device)
- ('device-mount-point mount-point)
- ('chain-loader chain-loader) _ ...)
+ ('device-mount-point mount-point) ('device-subvol subvol)
+ ('chain-loader chain-loader)
+ (or ('device-subvol subvol _ ...) (_ ...)))
(menu-entry
(label label)
(device (sexp->device device))
(device-mount-point mount-point)
+ (device-subvol subvol)
(chain-loader chain-loader)))))
diff --git a/gnu/system/boot.scm b/gnu/system/boot.scm
index a898ab9549..8a183ebe3a 100644
--- a/gnu/system/boot.scm
+++ b/gnu/system/boot.scm
@@ -16,6 +16,7 @@
;;; Copyright © 2021 raid5atemyhomework <raid5atemyhomework@protonmail.com>
;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
;;; Copyright © 2023 Felix Lechner <felix.lechner@lease-up.com>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -332,6 +333,7 @@ (define (boot-parameters->menu-entry conf)
(label (boot-parameters-label conf))
(device (boot-parameters-store-device conf))
(device-mount-point (boot-parameters-store-mount-point conf))
+ (device-subvol (boot-parameters-store-directory-prefix conf))
(linux (and (not multiboot?) kernel))
(linux-arguments (if (not multiboot?)
(boot-parameters-kernel-arguments conf)
--
2.45.2
H
H
Herman Rimm wrote on 20 Sep 12:37 +0200
[PATCH v2 11/15] gnu: build: bootloader: Add efi-bootnums procedure.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
5bb21b9075822392a90e3e5aeb4e5daa2fcfff82.1726827025.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/build/bootloader.scm (atomic-copy, efi-bootnums): Add procedures.
(in-temporary-directory): Add macro.

Change-Id: I3654d160f7306bb45a78b82ea6b249ff4281f739
---
gnu/build/bootloader.scm | 48 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 47 insertions(+), 1 deletion(-)

Toggle diff (88 lines)
diff --git a/gnu/build/bootloader.scm b/gnu/build/bootloader.scm
index af6063a884..3934e03aee 100644
--- a/gnu/build/bootloader.scm
+++ b/gnu/build/bootloader.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2019 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2022 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
;;; Copyright © 2022 Timothy Sample <samplet@ngyro.com>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -20,13 +21,25 @@
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (gnu build bootloader)
+ #:autoload (guix build syscalls) (free-disk-space)
#:use-module (guix build utils)
#:use-module (guix utils)
#:use-module (ice-9 binary-ports)
+ #:use-module (guix diagnostics)
+ #:use-module (guix i18n)
#:use-module (ice-9 format)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 popen)
+ #:use-module (ice-9 receive)
+ #:use-module (ice-9 regex)
#:use-module (rnrs io ports)
#:use-module (rnrs io simple)
- #:export (write-file-on-device
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
+ #:use-module (srfi srfi-35)
+ #:export (atomic-copy
+ in-temporary-directory
+ write-file-on-device
install-efi-loader))
@@ -34,6 +47,21 @@ (define-module (gnu build bootloader)
;;; Writing utils.
;;;
+(define (atomic-copy from to)
+ (let ((pivot (string-append to ".new")))
+ (copy-file from pivot)
+ (rename-file pivot to)))
+
+(define-syntax-rule (in-temporary-directory blocks ...)
+ "Run BLOCKS while chdir'd into a temporary directory."
+ ;; Under POSIX.1-2008, mkdtemp must make the dir with 700 perms.
+ (let* ((tmp (or (getenv "TMPDIR") "/tmp"))
+ (dir (mkdtemp (string-append tmp "/guix-bootloader.XXXXXX")))
+ (cwd (getcwd)))
+ (dynamic-wind (lambda () (chdir dir))
+ (lambda () blocks ...)
+ (lambda () (chdir cwd) (delete-file-recursively dir)))))
+
(define (write-file-on-device file size device offset)
"Write SIZE bytes from FILE to DEVICE starting at OFFSET."
(call-with-input-file file
@@ -56,6 +84,24 @@ (define (write-file-on-device file size device offset)
;;; EFI bootloader.
;;;
+;; XXX: Parsing efibootmgr output may be kinda jank. A better way may exist.
+(define (efi-bootnums efibootmgr)
+ "Returns '(path . bootnum) pairs for each EFI boot entry. bootnum is
+a string, and path is backslash-deliminated and relative to the ESP."
+ (let* ((pipe (open-pipe* OPEN_READ efibootmgr))
+ (text (get-string-all pipe))
+ (status (status:exit-val (close-pipe pipe)))
+ (bootnum-pattern
+ "^Boot([0-9a-fA-F]+).*[^A-Za-z]File\\(([^)]+)\\)$"))
+ (unless (zero? status)
+ (raise-exception
+ (formatted-message (G_ "efibootmgr exited with error code ~a") status)))
+ (fold-matches (make-regexp bootnum-pattern regexp/newline) text '()
+ (lambda (match acc)
+ (let* ((path (match:substring match 2))
+ (bootnum (match:substring match 1)))
+ (cons (cons path bootnum) acc))))))
+
(define* (install-efi grub grub-config esp #:key targets)
"Write a self-contained GRUB EFI loader to the mounted ESP using
GRUB-CONFIG.
--
2.45.2
H
H
Herman Rimm wrote on 20 Sep 12:37 +0200
[PATCH v2 13/15] gnu: bootloader: Match records outside the module.
(address . 73202@debbugs.gnu.org)
a872720357926e5b9df856bf793fd84a95917207.1726827025.git.herman@rimm.ee
* gnu/bootloader.scm (match-bootloader-configuration, match-menu-entry):
Add macros.

Change-Id: I42cb7541045314c37ffef98fe6efe7f46acd9d9b
---
gnu/bootloader.scm | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)

Toggle diff (45 lines)
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index 6b08e61492..b1ed187aa2 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -8,6 +8,7 @@
;;; Copyright © 2022 Reza Alizadeh Majd <r.majd@pantherx.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.
;;;
@@ -115,6 +116,9 @@ (define-module (gnu bootloader)
bootloader-configuration->gexp
bootloader-configurations->gexp
+ match-bootloader-configuration
+ match-menu-entry
+
%efi-supported-systems
efi-arch
install-efi
@@ -642,6 +646,20 @@ (define (bootloader-configurations->gexp bootloader-configs . rest)
(apply gbegin (filter-map (cut apply bootloader-configuration->gexp <> rest)
bootloader-configs)))
+;; In lieu of exporting bootloader-configuration and menu-entry RTDs.
+(define-syntax match-bootloader-configuration
+ (syntax-rules ()
+ "Bind each BOOTLOADER-CONFIGURATION field in FIELDS."
+ ((_ bootloader-configuration (fields ...) body ...)
+ (match-record bootloader-configuration <bootloader-configuration>
+ (fields ...) body ...))))
+
+(define-syntax match-menu-entry
+ (syntax-rules ()
+ "Bind each MENU-ENTRY field in FIELDS."
+ ((_ menu-entry (fields ...) body ...)
+ (match-record menu-entry <menu-entry> (fields ...) body ...))))
+
;;;
;;; Bootloader installation to ESP.
--
2.45.2
H
H
Herman Rimm wrote on 20 Sep 12:37 +0200
[PATCH v2 12/15] gnu: bootloader: Install any bootloader to ESP.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
52e31df0e5a3a0d0c4b015d135d5eb0ce3e4829e.1726827025.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/bootloader.scm (efi-arch, install-efi): New procedures.
(%efi-supported-systems, lazy-efibootmgr): New variables.
(bootloader-configuration)[efi-removable?, 32bit?]: New fields.
(match-bootloader-configuration, match-menu-entry): New macros.
* gnu/build/bootloader.scm (install-efi-loader): Delete procedure.
(install-efi): Rewrite to support installation of any efi bootloader.
* gnu/build/image.scm (initialize-efi32-partition): Deprecate.
(initialize-efi-partitition): Only create EFI directory.
* gnu/image.scm (partition)[target]: New field in order to support
dynamic provision of image partitions as bootloader targets.
* gnu/system/image.scm (root-partition, esp-partition): Use target
field.
* gnu/system/image.scm (esp32-partition, efi32-disk-partition,
efi32-raw-image-type): Deprecate.
* doc/guix.texi (Creating System Images)[image Reference]<partition
Reference>: Add target field.
[Instantiate an Image]: Update examples and update formatting.
<efi32-disk-image, efi32-raw-image-type>: Delete.
<pinebook-pro-image-type, rock64-image-type>: Reword slightly.

Change-Id: I3654d160f7306bb45a78b82ea6b249ff4281f739
---
doc/guix.texi | 34 ++++++------
gnu/bootloader.scm | 56 ++++++++++++++++++-
gnu/build/bootloader.scm | 115 ++++++++++++++++++++-------------------
gnu/build/image.scm | 23 ++------
gnu/image.scm | 4 ++
gnu/system/image.scm | 22 +++-----
6 files changed, 150 insertions(+), 104 deletions(-)

Toggle diff (412 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index f7fb4b4cc3..eb24ab9798 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -130,6 +130,7 @@
Copyright @copyright{} 2024 Dariqq@*
Copyright @copyright{} 2024 Denis 'GNUtoo' Carikli@*
Copyright @copyright{} 2024 Fabio Natali@*
+Copyright @copyright{} 2024 Lilah Tascheter@*
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -47950,6 +47951,12 @@ partition Reference
this flag set, usually the root one. The @code{'esp} flag identifies a
UEFI System Partition.
+@item @code{target} (default: @var{#f})
+If provided, this partition provides itself as a bootloader target
+(@pxref{Bootloader Configuration}). Most commonly, this is used to provide the
+@code{'root} and @code{'esp} targets, with the root partition and EFI System
+Partition, respectively, though this can provide any target necessary.
+
@item @code{initializer} (default: @code{#false})
The partition initializer procedure as a gexp. This procedure is called
to populate a partition. If no initializer is passed, the
@@ -47998,6 +48005,7 @@ Instantiate an Image
(label "GNU-ESP")
(file-system "vfat")
(flags '(esp))
+ (target 'esp)
(initializer (gexp initialize-efi-partition)))
(partition
(size (* 50 MiB))
@@ -48014,15 +48022,17 @@ Instantiate an Image
(label root-label)
(file-system "ext4")
(flags '(boot))
+ (target 'root)
(initializer (gexp initialize-root-partition))))))
@end lisp
-Note that the first and third partitions use generic initializers
-procedures, initialize-efi-partition and initialize-root-partition
-respectively. The initialize-efi-partition installs a GRUB EFI loader
-that is loading the GRUB bootloader located in the root partition. The
-initialize-root-partition instantiates a complete system as defined by
-the @code{%simple-os} operating-system.
+Note that the first and third partitions use generic initializer
+procedures, @code{initialize-efi-partition} and
+@code{initialize-root-partition} respectively.
+@code{initialize-efi-partition} simply creates the directory structure
+for an EFI bootloader to install itself to.
+@code{initialize-root-partition} instantiates a complete system as
+defined by the @code{%simple-os} operating-system.
You can now run:
@@ -48079,10 +48089,6 @@ Instantiate an Image
@code{i686} machines, supporting BIOS or UEFI booting.
@end defvar
-@defvar efi32-disk-image
-Same as @code{efi-disk-image} but with a 32 bits EFI partition.
-@end defvar
-
@defvar iso9660-image
An ISO-9660 image composed of a single bootable partition. This image
can also be used on most @code{x86_64} and @code{i686} machines.
@@ -48173,10 +48179,6 @@ image-type Reference
Build an image based on the @code{efi-disk-image} image.
@end defvar
-@defvar efi32-raw-image-type
-Build an image based on the @code{efi32-disk-image} image.
-@end defvar
-
@defvar qcow2-image-type
Build an image based on the @code{mbr-disk-image} image but with the
@code{compressed-qcow2} image format.
@@ -48204,14 +48206,14 @@ image-type Reference
@defvar pinebook-pro-image-type
Build an image that is targeting the Pinebook Pro machine. The MBR
image contains a single partition starting at a @code{9MiB} offset. The
-@code{u-boot-pinebook-pro-rk3399-bootloader} bootloader will be
+@code{u-boot-pinebook-pro-rk3399-bootloader} bootloader can be
installed in this gap.
@end defvar
@defvar rock64-image-type
Build an image that is targeting the Rock64 machine. The MBR image
contains a single partition starting at a @code{16MiB} offset. The
-@code{u-boot-rock64-rk3328-bootloader} bootloader will be installed in
+@code{u-boot-rock64-rk3328-bootloader} bootloader can be installed in
this gap.
@end defvar
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index f1352122a9..6b08e61492 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -100,6 +100,8 @@ (define-module (gnu bootloader)
bootloader-configuration-targets
bootloader-configuration-menu-entries
bootloader-configuration-default-entry
+ bootloader-configuration-efi-removable?
+ bootloader-configuration-32bit?
bootloader-configuration-timeout
bootloader-configuration-keyboard-layout
bootloader-configuration-theme
@@ -113,6 +115,9 @@ (define-module (gnu bootloader)
bootloader-configuration->gexp
bootloader-configurations->gexp
+ %efi-supported-systems
+ efi-arch
+ install-efi
efi-bootloader-chain))
@@ -502,6 +507,10 @@ (define-record-type* <bootloader-configuration>
(default '())) ;list of <menu-entry>
(default-entry bootloader-configuration-default-entry
(default 0)) ;integer
+ (efi-removable? bootloader-configuration-efi-removable?
+ (default #f)) ;bool
+ (32bit? bootloader-configuration-32bit?
+ (default #f)) ;bool
(timeout bootloader-configuration-timeout
(default 5)) ;seconds as integer
(keyboard-layout bootloader-configuration-keyboard-layout
@@ -635,9 +644,54 @@ (define (bootloader-configurations->gexp bootloader-configs . rest)
;;;
-;;; Bootloaders.
+;;; Bootloader installation to ESP.
;;;
+;; systems currently supported by efi-arch. should be used for packages relying
+;; on it.
+(define %efi-supported-systems
+ '("i686-linux" "x86_64-linux" "armhf-linux" "aarch64-linux" "riscv64-linux"))
+
+(define* (efi-arch #:key (target (or (%current-target-system) (%current-system)))
+ (32? #f))
+ "Returns the UEFI architecture name for the current target, in lowercase."
+ (cond ((target-x86-32? target) "ia32")
+ ((target-x86-64? target) (if 32? "ia32" "x64"))
+ ((target-arm32? target) "arm")
+ ((target-aarch64? target) (if 32? "arm" "aa64"))
+ ((target-riscv64? target) (if 32? "riscv32" "riscv64"))
+ (else (raise (formatted-message (G_ "no UEFI standard arch for ~a!")
+ target)))))
+
+(define (lazy-efibootmgr)
+ "Lazy-loaded efibootmgr package, in order to prevent circular refs."
+ (module-ref (resolve-interface '(gnu packages linux)) 'efibootmgr))
+
+(define (install-efi bootloader-config plan)
+ "Returns a gexp installing PLAN to the ESP, as denoted by the 'vendir target.
+PLAN is a gexp of a list of '(BUILDER DEST-BASENAME . LABEL) triples, that
+should be in boot order. If the user selects a removable bootloader, only the
+first entry in PLAN is used."
+ (match-record bootloader-config <bootloader-configuration>
+ (targets efi-removable? 32bit?)
+ (if efi-removable?
+ ;; Hard code the output location to a well-known path recognized by
+ ;; compliant firmware. See "3.5.1.1 Removable Media Boot Behaviour":
+ ;; http://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf
+ (with-targets targets
+ (('esp => (path :path))
+ #~(let ((boot #$(string-append path "/EFI/BOOT"))
+ (arch #$(string-upcase (efi-arch #:32? 32bit?)))
+ (builder (car (car #$plan))))
+ (mkdir-p boot)
+ ;; Only realize the first planspec.
+ (builder (string-append boot "/BOOT" arch ".EFI")))))
+ ;; Install normally if not configured as removable.
+ (with-targets targets
+ (('vendir => (vendir :path) (loader :devpath) (disk :device))
+ #~(install-efi #+(file-append (lazy-efibootmgr) "/sbin/efibootmgr")
+ #$vendir #$loader #$disk #$plan))))))
+
(define (efi-bootloader-profile packages files hooks)
"Creates a profile from the lists of PACKAGES and FILES from the store.
This profile is meant to be used by the bootloader-installer.
diff --git a/gnu/build/bootloader.scm b/gnu/build/bootloader.scm
index 3934e03aee..064466bd33 100644
--- a/gnu/build/bootloader.scm
+++ b/gnu/build/bootloader.scm
@@ -23,8 +23,6 @@
(define-module (gnu build bootloader)
#:autoload (guix build syscalls) (free-disk-space)
#:use-module (guix build utils)
- #:use-module (guix utils)
- #:use-module (ice-9 binary-ports)
#:use-module (guix diagnostics)
#:use-module (guix i18n)
#:use-module (ice-9 format)
@@ -40,7 +38,7 @@ (define-module (gnu build bootloader)
#:export (atomic-copy
in-temporary-directory
write-file-on-device
- install-efi-loader))
+ install-efi))
;;;
@@ -102,57 +100,62 @@ (define (efi-bootnums efibootmgr)
(bootnum (match:substring match 1)))
(cons (cons path bootnum) acc))))))
-(define* (install-efi grub grub-config esp #:key targets)
- "Write a self-contained GRUB EFI loader to the mounted ESP using
-GRUB-CONFIG.
-
-If TARGETS is set, use its car as the GRUB image format and its cdr as
-the output filename. Otherwise, use defaults for the host platform."
- (let* ((system %host-type)
- ;; Hard code the output location to a well-known path recognized by
- ;; compliant firmware. See "3.5.1.1 Removable Media Boot Behaviour":
- ;; http://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf
- (grub-mkstandalone (string-append grub "/bin/grub-mkstandalone"))
- (efi-directory (string-append esp "/EFI/BOOT"))
- ;; Map grub target names to boot file names.
- (efi-targets (or targets
- (cond ((string-prefix? "x86_64" system)
- '("x86_64-efi" . "BOOTX64.EFI"))
- ((string-prefix? "i686" system)
- '("i386-efi" . "BOOTIA32.EFI"))
- ((string-prefix? "armhf" system)
- '("arm-efi" . "BOOTARM.EFI"))
- ((string-prefix? "aarch64" system)
- '("arm64-efi" . "BOOTAA64.EFI"))))))
- ;; grub-mkstandalone requires a TMPDIR to prepare the firmware image.
- (setenv "TMPDIR" esp)
-
- (mkdir-p efi-directory)
- (invoke grub-mkstandalone "-O" (car efi-targets)
- "-o" (string-append efi-directory "/"
- (cdr efi-targets))
- ;; Graft the configuration file onto the image.
- (string-append "boot/grub/grub.cfg=" grub-config))))
-
-(define* (install-efi-loader grub-efi esp #:key targets)
- "Install in ESP directory the given GRUB-EFI bootloader. Configure it to
-load the Grub bootloader located in the 'Guix_image' root partition.
-
-If TARGETS is set, use its car as the GRUB image format and its cdr as
-the output filename. Otherwise, use defaults for the host platform."
- (let ((grub-config "grub.cfg"))
- (call-with-output-file grub-config
- (lambda (port)
- ;; Create a tiny configuration file telling the embedded grub where to
- ;; load the real thing. XXX This is quite fragile, and can prevent
- ;; the image from booting when there's more than one volume with this
- ;; label present. Reproducible almost-UUIDs could reduce the risk
- ;; (not eliminate it).
- (format port
- "insmod part_msdos~@
- insmod part_gpt~@
- search --set=root --label Guix_image~@
- configfile /boot/grub/grub.cfg~%")))
- (install-efi grub-efi grub-config esp #:targets targets)
- (delete-file grub-config)))
+(define (install-efi efibootmgr vendir loader* disk plan)
+ "See also install-efi in (gnu bootloader)."
+ (let* ((loader (string-map (match-lambda (#\/ #\\) (x x)) loader*))
+ (bootnums (filter (compose (cut string-prefix? loader <>) car)
+ (efi-bootnums efibootmgr)))
+ (plan-files (map cadr plan)))
+ (define (size file) (if (file-exists? file) (stat:size (stat file)) 0))
+ (define (vendirof file) (string-append vendir "/" file))
+ (define (loaderof file) (string-append loader "\\" file))
+ (define (delete-boot num file)
+ (invoke efibootmgr "--quiet" "--bootnum" num "--delete-bootnum")
+ (when (file-exists? file) (delete-file file)))
+ (mkdir-p vendir)
+ ;; Delete old entries first, to clear up space.
+ (for-each (lambda (spec) ; '(path . bootnum)
+ (let* ((s (substring (car spec) (string-length loader)))
+ (file (substring s (if (string-prefix? "\\" s) 1 0))))
+ (unless (member file plan-files)
+ (delete-boot (cdr spec) (vendirof file)))))
+ bootnums)
+ ;; New and updated entries.
+ (in-temporary-directory
+ (for-each
+ (lambda (spec)
+ (let* ((builder (car spec)) (name (cadr spec))
+ (dest (vendirof name)) (loadest (loaderof name))
+ (rest (reverse (cdr (member name plan-files)))))
+ ;; Build to a temporary file so we can check its size.
+ (builder name)
+ ;; Disk space is usually limited on ESPs.
+ ;; Try to clear space as we install new bootloaders.
+ (if (while (> (- (size name) (size dest)) (free-disk-space vendir))
+ (let ((del (find (compose file-exists? vendirof) rest)))
+ (if del (delete-file (vendirof del)) (break #t))))
+ (begin
+ (and=> (assoc-ref bootnums loadest) (cut delete-boot <> dest))
+ (warning (G_ "ESP too small for bootloader ~a!~%") name))
+ ;; The ESP is too small for atomic copy.
+ (begin
+ (copy-file name dest)
+ (unless (assoc loadest bootnums)
+ (invoke
+ efibootmgr "--quiet" "--create-only" "--label"
+ (cddr spec) "--disk" disk "--loader" loadest))))
+ (delete-file name)))
+ plan))
+ ;; Verify that at least the first entry was installed.
+ (unless (file-exists? (vendirof (cadr (car plan))))
+ ;; Extremely fatal error so we use leave instead of raise.
+ (leave (G_ "not enough space in ESP to install bootloader!
+ SYSTEM WILL NOT BOOT UNLESS THIS IS FIXED!~%")))
+ ;; Some UEFI systems will refuse to acknowledge the existence of boot
+ ;; entries unless they're in bootorder, so just shove everything in there.
+ (invoke
+ efibootmgr "--quiet" "--bootorder"
+ ;; Recall efi-bootnums to get a fresh list with new installs.
+ (let ((num (cute assoc-ref (efi-bootnums efibootmgr) <>))) ; cute is eager
+ (string-join (filter-map (compose num loaderof) plan-files) ",")))))
diff --git a/gnu/build/image.scm b/gnu/build/image.scm
index 6ca0a428e0..1b2d4da814 100644
--- a/gnu/build/image.scm
+++ b/gnu/build/image.scm
@@ -8,6 +8,7 @@
;;; Copyright © 2022 Pavel Shlyak <p.shlyak@pantherx.org>
;;; Copyright © 2022 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -28,6 +29,7 @@ (define-module (gnu build image)
#:use-module (guix build store-copy)
#:use-module (guix build syscalls)
#:use-module (guix build utils)
+ #:use-module (guix deprecation)
#:use-module (guix store database)
#:use-module (guix utils)
#:use-module (gnu build bootloader)
@@ -181,23 +183,10 @@ (define* (register-closure prefix closure
#:prefix prefix
#:registration-time %epoch)))))
-(define* (initialize-efi-partition root
- #:key
- grub-efi
- #:allow-other-keys)
- "Install in ROOT directory, an EFI loader using GRUB-EFI."
- (install-efi-loader grub-efi root))
-
-(define* (initialize-efi32-partition root
- #:key
- grub-efi32
- #:allow-other-keys)
- "Install in ROOT directory, an EFI 32bit loader using GRUB-EFI32."
- (install-efi-loader grub-efi32 root
- #:targets (cond ((target-x86?)
- '("i386-efi" . "BOOTIA32.EFI"))
- ((target-arm?)
- '("arm-efi" . "BOOTARM.EFI")))))
+(define (initialize-efi-partition root . rest)
+ (mkdir-p (string-append root "/EFI")))
+
+(define-deprecated/alias initialize-efi32-partition initialize-efi-partition)
(define* (initialize-root-partition root
#:key
diff --git a/gnu/image.scm b/gnu/image.scm
index 7fb06dec10..c6cc264147 100644
--- a/gnu/image.scm
+++ b/gnu/image.scm
@@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2020, 2022 Mathieu Othacehe <othacehe@gnu.org>
;;; Copyright © 2023 Oleg Pykhalov <go.wigust@gmail.com>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -35,6 +36,7 @@ (define-module (gnu image)
partition-label
partition-uuid
partition-flags
+ partition-target
partition-initializer
image
@@ -131,6 +133,8 @@ (define-record-type* <partition> partition make-partition
(flags partition-flags
(default '()) ;list of symbols
(sanitize validate-partition-flags))
+ (target partition-target ; bootloader target type: symbol | #f
+ (default #f))
(initializer partition-initializer
(default #false))) ;gexp | #false
diff --git a/gnu/system/image.scm b/gnu/system/image.scm
index b0c96c60f0..8ac91800ad 100644
--- a/gnu/system/image.scm
+++ b/gnu/system/image.scm
@@ -6,6 +6,7 @@
;;; Copyright © 2022 Alex Griffin <a@ajgrf.com>
;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
;;; Copyright © 2023 Oleg Pykhalov <go.wigust@gmail.com>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;;
;;; This file is part of GNU Gu
This message was truncated. Download the full message here.
H
H
Herman Rimm wrote on 20 Sep 12:38 +0200
[PATCH v2 15/15] teams: Add bootloading team.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
2c080f11d3e0b6e6268f6c0ff704c2114de3ef8a.1726827025.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

Might as well, to help ease the transition.

* etc/teams.scm (bootloaders): New team.
(Lilah Tascheter): Create and add to above.

Change-Id: I63620f4e3151bb8e3d0bdf619fc70501af6397a0
---
etc/teams.scm | 10 ++++++++++
1 file changed, 10 insertions(+)

Toggle diff (30 lines)
diff --git a/etc/teams.scm b/etc/teams.scm
index 9239021b39..2150a7aad1 100755
--- a/etc/teams.scm
+++ b/etc/teams.scm
@@ -328,6 +328,12 @@ (define-team embedded
#:scope (list "gnu/packages/bootloaders.scm"
"gnu/packages/firmware.scm")))
+(define-team bootloaders
+ (team 'bootloaders
+ #:name "Bootloaders"
+ #:scope (list "gnu/bootloader.scm"
+ (make-regexp* "^gnu/bootloader/"))))
+
(define-team rust
(team 'rust
#:name "Rust"
@@ -749,6 +755,10 @@ (define-member (person "André Batista"
"nandre@riseup.net")
mozilla)
+(define-member (person "Lilah Tascheter"
+ "lilah@lunabee.space")
+ bootloaders)
+
(define (find-team name)
(or (hash-ref %teams (string->symbol name))
--
2.45.2
H
H
Herman Rimm wrote on 20 Sep 12:37 +0200
[PATCH v2 14/15] gnu: system: boot: Add procedure.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
d40ec140d3581178b5a5fcbb16876621f5900b52.1726827025.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/system/boot.scm (boot-alternative->menu-entry): New procedure.

Change-Id: Id68fb3d39e6d9aca9267f3884cf54f2e7a08b353
---
gnu/system/boot.scm | 4 ++++
1 file changed, 4 insertions(+)

Toggle diff (24 lines)
diff --git a/gnu/system/boot.scm b/gnu/system/boot.scm
index 8a183ebe3a..2040984cbf 100644
--- a/gnu/system/boot.scm
+++ b/gnu/system/boot.scm
@@ -81,6 +81,7 @@ (define-module (gnu system boot)
epoch->date-string
decorated-boot-label
boot-parameters->menu-entry
+ boot-alternative->menu-entry
ensure-not-/dev
system-linux-image-file-name))
@@ -347,6 +348,9 @@ (define (boot-parameters->menu-entry conf)
(boot-parameters-multiboot-modules conf)
'())))))
+(define boot-alternative->menu-entry
+ (compose boot-parameters->menu-entry boot-alternative-parameters))
+
(define (ensure-not-/dev device)
"If DEVICE starts with a slash, return #f. This is meant to filter out
Linux device names such as /dev/sda, and to preserve GRUB device names and
--
2.45.2
L
L
Lilah Tascheter wrote on 20 Sep 15:42 +0200
(address . control@debbugs.gnu.org)
23990aeff364fc233963f4801b269f91c80ed9b7.camel@lunabee.space
block 73202 with 69343
block 72457 with 73202
L
L
Lilah Tascheter wrote on 20 Sep 15:46 +0200
(address . control@debbugs.gnu.org)
675d766af7df47325dc2635ce6f4e33752eb7df7.camel@lunabee.space
retitle 73202 [PATCH] Preparation for bootloader rewrite.
H
H
Herman Rimm wrote on 21 Sep 12:57 +0200
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
irawmqi6j6krolsuttvtzpujsbsjhapofceq6cpch3psw22mvm@wrbedbw4ewzm
Hello,

I posted revision v5 of #69343. If you would like to apply v2 of this
issue on it, use git am -3 and pick the conflicting change made by patch
#5 as is. Also note that the changes made by patch #14 are now included
in v5 of #69343.

Cheers,
Herman
L
L
Lilah Tascheter wrote on 25 Sep 22:58 +0200
(address . 73202@debbugs.gnu.org)(name . Herman Rimm)(address . herman@rimm.ee)
4ff19a6ca2cb04710ac9609666c0f69cfc88567f.camel@lunabee.space
hey herman!

Toggle quote (1 lines)
> use git am -3
fails on a clean pull/am due to lack of commit blobs. I'm not quite
sure how to fix that myself, would you be able to just re-send the
rebased patch series?

thanks!
H
H
Herman Rimm wrote on 26 Sep 12:08 +0200
[PATCH v3 01/14] gnu: bootloader: Remove deprecated bootloader-configuration field.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
74c789e74594d538308d33633ed8540283dcde49.1727345067.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/bootloader.scm (warn-target-field-deprecation): Delete sanitizer.
(bootloader-configuration)[target]: Remove deprecated field.
(bootloader-configuration-target): Delete procedure.
(bootloader-configuration-targets): Do not use target field.

Change-Id: I3654d160f7306bb45a78b82ea6b249ff4281f739
---
gnu/bootloader.scm | 18 +-----------------
1 file changed, 1 insertion(+), 17 deletions(-)

Toggle diff (57 lines)
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index f32e90e79d..865521e6e5 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -66,7 +66,6 @@ (define-module (gnu bootloader)
bootloader-configuration
bootloader-configuration?
bootloader-configuration-bootloader
- bootloader-configuration-target ;deprecated
bootloader-configuration-targets
bootloader-configuration-menu-entries
bootloader-configuration-default-entry
@@ -244,24 +243,14 @@ (define-record-type* <bootloader>
;; The <bootloader-configuration> record contains bootloader independant
;; configuration used to fill bootloader configuration file.
-(define-with-syntax-properties (warn-target-field-deprecation
- (value properties))
- (when value
- (warning (source-properties->location properties)
- (G_ "the 'target' field is deprecated, please use 'targets' \
-instead~%")))
- value)
(define-record-type* <bootloader-configuration>
bootloader-configuration make-bootloader-configuration
bootloader-configuration?
(bootloader
- bootloader-configuration-bootloader) ;<bootloader>
+ bootloader-configuration-bootloader) ;<bootloader>
(targets %bootloader-configuration-targets
(default #f)) ;list of strings
- (target %bootloader-configuration-target ;deprecated
- (default #f)
- (sanitize warn-target-field-deprecation))
(menu-entries bootloader-configuration-menu-entries
(default '())) ;list of <menu-entry>
(default-entry bootloader-configuration-default-entry
@@ -285,14 +274,9 @@ (define-record-type* <bootloader-configuration>
(extra-initrd bootloader-configuration-extra-initrd
(default #f))) ;string | #f
-(define-deprecated (bootloader-configuration-target config)
- bootloader-configuration-targets
- (%bootloader-configuration-target config))
(define (bootloader-configuration-targets config)
(or (%bootloader-configuration-targets config)
- ;; TODO: Remove after the deprecated 'target' field is removed.
- (list (%bootloader-configuration-target config))
;; XXX: At least the GRUB installer (see (gnu bootloader grub)) has this
;; peculiar behavior of installing fonts and GRUB modules when DEVICE is #f,
;; hence the default value of '(#f) rather than '().

base-commit: db3ec7f65bd04741f1d97a9a3bbd3d96f12caa52
--
2.45.2
H
H
Herman Rimm wrote on 26 Sep 12:08 +0200
[PATCH v3 02/14] gnu: system: Remove useless boot parameters.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
c0d6bcb2d8c56569b96ac9674de337188dd77c0b.1727345067.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/system.scm (operating-system-boot-parameters,
operating-system-boot-parameters-file): Delete bootloader-menu-entries.
* gnu/system/boot.scm (boot-parameters)[bootloader-menu-entries]: Delete
field.
(read-boot-parameters): Don't read bootloader-menu-entries.
* tests/boot-parameters.scm (%grub-boot-parameters,
test-read-boot-parameters, test-read-boot-parameters): Don't include
bootloader-menu-entries.
("read, bootloader-menu-entries, default value"): Delete test.

Change-Id: I46d9cff4604dbfcf654b0820fdb77e72aecffbb4
---
gnu/system.scm | 7 -------
gnu/system/boot.scm | 8 --------
tests/boot-parameters.scm | 18 +++++-------------
3 files changed, 5 insertions(+), 28 deletions(-)

Toggle diff (145 lines)
diff --git a/gnu/system.scm b/gnu/system.scm
index 25afa96295..a3eee5aa24 100644
--- a/gnu/system.scm
+++ b/gnu/system.scm
@@ -1298,8 +1298,6 @@ (define* (operating-system-boot-parameters os root-device
(initrd initrd)
(multiboot-modules multiboot-modules)
(bootloader-name bootloader-name)
- (bootloader-menu-entries
- (bootloader-configuration-menu-entries (operating-system-bootloader os)))
(locale locale)
(store-device (ensure-not-/dev (file-system-device store)))
(store-directory-prefix (btrfs-store-subvolume-file-name file-systems))
@@ -1341,11 +1339,6 @@ (define* (operating-system-boot-parameters-file os)
#$(boot-parameters-multiboot-modules params)))
#~())
(bootloader-name #$(boot-parameters-bootloader-name params))
- (bootloader-menu-entries
- #$(map menu-entry->sexp
- (or (and=> (operating-system-bootloader os)
- bootloader-configuration-menu-entries)
- '())))
(locale #$(boot-parameters-locale params))
(store
(device
diff --git a/gnu/system/boot.scm b/gnu/system/boot.scm
index de312c7208..54e5673a54 100644
--- a/gnu/system/boot.scm
+++ b/gnu/system/boot.scm
@@ -51,7 +51,6 @@ (define-module (gnu system boot)
boot-parameters-label
boot-parameters-root-device
boot-parameters-bootloader-name
- boot-parameters-bootloader-menu-entries
boot-parameters-store-crypto-devices
boot-parameters-store-device
boot-parameters-store-directory-prefix
@@ -110,8 +109,6 @@ (define-record-type* <boot-parameters>
;; partition.
(root-device boot-parameters-root-device)
(bootloader-name boot-parameters-bootloader-name)
- (bootloader-menu-entries ;list of <menu-entry>
- boot-parameters-bootloader-menu-entries)
(store-device boot-parameters-store-device)
(store-mount-point boot-parameters-store-mount-point)
(store-directory-prefix boot-parameters-store-directory-prefix)
@@ -172,11 +169,6 @@ (define (read-boot-parameters port)
((_ args) args)
(#f 'grub))) ; for compatibility reasons.
- (bootloader-menu-entries
- (match (assq 'bootloader-menu-entries rest)
- ((_ entries) (map sexp->menu-entry entries))
- (#f '())))
-
;; In the past, we would store the directory name of linux instead of
;; the absolute file name of its image. Detect that and correct it.
(kernel (if (string=? kernel (direct-store-path kernel))
diff --git a/tests/boot-parameters.scm b/tests/boot-parameters.scm
index 2e7976aa6c..e1dc4620c3 100644
--- a/tests/boot-parameters.scm
+++ b/tests/boot-parameters.scm
@@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2019, 2020 Miguel Ángel Arruga Vivas <rosen644835@gmail.com>
;;; Copyright © 2022 Josselin Poiret <dev@jpoiret.xyz>
+;;; Copyright © 2024 Herman Rimm <herman@rimm.ee>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -34,6 +35,7 @@ (define-module (test-boot-parameters)
#:use-module (guix gexp)
#:use-module (guix store)
#:use-module (guix tests)
+ #:use-module (ice-9 format)
#:use-module (srfi srfi-34)
#:use-module (srfi srfi-64)
#:use-module (rnrs bytevectors))
@@ -64,7 +66,6 @@ (define %root-path "/")
(define %grub-boot-parameters
(boot-parameters
(bootloader-name 'grub)
- (bootloader-menu-entries '())
(root-device %default-root-device)
(label %default-label)
(kernel %default-kernel)
@@ -107,7 +108,6 @@ (define* (test-read-boot-parameters
#:key
(version %boot-parameters-version)
(bootloader-name 'grub)
- (bootloader-menu-entries '())
(label %default-label)
(root-device (quote-uuid %default-root-device))
(kernel %default-kernel)
@@ -127,7 +127,7 @@ (define* (test-read-boot-parameters
(cond ((eq? 'false val) (format #false fmt #false))
(val (format #false fmt val))
(else "")))
- (format #false "(boot-parameters~a~a~a~a~a~a~a~a~a~a)"
+ (format #f "(boot-parameters~@{~a~})"
(sexp-or-nothing " (version ~S)" version)
(sexp-or-nothing " (label ~S)" label)
(sexp-or-nothing " (root-device ~S)" root-device)
@@ -135,7 +135,7 @@ (define* (test-read-boot-parameters
(sexp-or-nothing " (kernel-arguments ~S)" kernel-arguments)
(sexp-or-nothing " (initrd ~S)" initrd)
(if with-store
- (format #false " (store~a~a~a~a)"
+ (format #f " (store~@{~a~})"
(sexp-or-nothing " (device ~S)" store-device)
(sexp-or-nothing " (mount-point ~S)"
store-mount-point)
@@ -145,9 +145,7 @@ (define* (test-read-boot-parameters
store-crypto-devices))
"")
(sexp-or-nothing " (locale ~S)" locale)
- (sexp-or-nothing " (bootloader-name ~a)" bootloader-name)
- (sexp-or-nothing " (bootloader-menu-entries ~S)"
- bootloader-menu-entries)))
+ (sexp-or-nothing " (bootloader-name ~a)" bootloader-name)))
(let ((str (generate-boot-parameters)))
(call-with-input-string str read-boot-parameters)))
@@ -170,7 +168,6 @@ (define* (test-read-boot-parameters
(test-assert "read, construction, optional fields"
(and (test-read-boot-parameters #:bootloader-name #false)
- (test-read-boot-parameters #:bootloader-menu-entries #false)
(test-read-boot-parameters #:kernel-arguments #false)
(test-read-boot-parameters #:with-store #false)
(test-read-boot-parameters #:store-device #false)
@@ -223,11 +220,6 @@ (define* (test-read-boot-parameters
(boot-parameters-bootloader-name
(test-read-boot-parameters #:bootloader-name #false)))
-(test-eq "read, bootloader-menu-entries, default value"
- '()
- (boot-parameters-bootloader-menu-entries
- (test-read-boot-parameters #:bootloader-menu-entries #false)))
-
(test-eq "read, kernel-arguments, default value"
'()
(boot-parameters-kernel-arguments
--
2.45.2
H
H
Herman Rimm wrote on 26 Sep 12:09 +0200
[PATCH v3 03/14] gnu: tests: reconfigure: Remove bootloader install test.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
b5b6223c077c323b2bb40e2266b233c46bda8730.1727345067.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/tests/reconfigure.scm (%test-install-bootloader): Delete variable.
(run-install-bootloader-test): Delete procedure.

Change-Id: I3654d160f7306bb45a78b82ea6b249ff4281f739
---
gnu/tests/reconfigure.scm | 86 +--------------------------------------
1 file changed, 1 insertion(+), 85 deletions(-)

Toggle diff (110 lines)
diff --git a/gnu/tests/reconfigure.scm b/gnu/tests/reconfigure.scm
index bcc7645fa3..8aa5311171 100644
--- a/gnu/tests/reconfigure.scm
+++ b/gnu/tests/reconfigure.scm
@@ -30,8 +30,7 @@ (define-module (gnu tests reconfigure)
#:use-module (guix scripts system reconfigure)
#:use-module (guix store)
#:export (%test-switch-to-system
- %test-upgrade-services
- %test-install-bootloader))
+ %test-upgrade-services))
;;; Commentary:
;;;
@@ -178,83 +177,6 @@ (define* (run-upgrade-services-test)
(disable (upgrade-services-program '() '() '(dummy) '())))
(test enable disable))))
-(define* (run-install-bootloader-test)
- "Run a test of an OS running INSTALL-BOOTLOADER-PROGRAM, which installs a
-bootloader's configuration file."
- (define os
- (marionette-operating-system
- (simple-operating-system)
- #:imported-modules '((gnu services herd)
- (guix combinators))))
-
- (define vm (virtual-machine
- (operating-system os)
- (volatile? #f)))
-
- (define (test script)
- (with-imported-modules '((gnu build marionette))
- #~(begin
- (use-modules (gnu build marionette)
- (ice-9 regex)
- (srfi srfi-1)
- (srfi srfi-64))
-
- (define marionette
- (make-marionette (list #$vm)))
-
- ;; Return the system generation paths that have GRUB menu entries.
- (define (generations-in-grub-cfg marionette)
- (let ((grub-cfg (marionette-eval
- '(begin
- (use-modules (rnrs io ports))
- (call-with-input-file "/boot/grub/grub.cfg"
- get-string-all))
- marionette)))
- (map (lambda (parameter)
- (second (string-split (match:substring parameter) #\=)))
- (list-matches "system=[^ ]*" grub-cfg))))
-
- (test-runner-current (system-test-runner #$output))
- (test-begin "install-bootloader")
-
- (test-assert "no prior menu entry for system generation"
- (not (member #$os (generations-in-grub-cfg marionette))))
-
- (test-assert "script successfully evaluated"
- (marionette-eval
- '(primitive-load #$script)
- marionette))
-
- (test-assert "menu entry created for system generation"
- (member #$os (generations-in-grub-cfg marionette)))
-
- (test-end))))
-
- (let* ((bootloader ((compose bootloader-configuration-bootloader
- operating-system-bootloader)
- os))
- ;; The typical use-case for 'install-bootloader-program' is to read
- ;; the boot parameters for the existing menu entries on the system,
- ;; parse them with 'boot-parameters->menu-entry', and pass the
- ;; results to 'operating-system-bootcfg'. However, to obtain boot
- ;; parameters, we would need to start the marionette, which we should
- ;; ideally avoid doing outside of the 'test' G-Expression. Thus, we
- ;; generate a bootloader configuration for the script as if there
- ;; were no existing menu entries. In the grand scheme of things, this
- ;; matters little -- these tests should not make assertions about the
- ;; behavior of 'operating-system-bootcfg'.
- (bootcfg (operating-system-bootcfg os '()))
- (bootcfg-file (bootloader-configuration-file bootloader)))
- (gexp->derivation
- "install-bootloader"
- ;; Due to the read-only nature of the virtual machines used in the system
- ;; test suite, the bootloader installer script is omitted. 'grub-install'
- ;; would attempt to write directly to the virtual disk if the
- ;; installation script were run.
- (test
- (install-bootloader-program #f #f #f bootcfg bootcfg-file '(#f) "/")))))
-
-
(define %test-switch-to-system
(system-test
(name "switch-to-system")
@@ -267,9 +189,3 @@ (define %test-upgrade-services
(description "Upgrade the Shepherd by unloading obsolete services and
loading new services.")
(value (run-upgrade-services-test))))
-
-(define %test-install-bootloader
- (system-test
- (name "install-bootloader")
- (description "Install a bootloader and its configuration file.")
- (value (run-install-bootloader-test))))
--
2.45.2
H
H
Herman Rimm wrote on 26 Sep 12:09 +0200
[PATCH v3 04/14] guix: scripts: Remove unused code.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
219bd42a8b9bdb6c8c2c6181538c2e06d5c2c8f6.1727345067.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* guix/scripts/system.scm (bootloader-installer-script): Delete.

Change-Id: Ic1e0a523c814e4f1bf44b2721f5658f00066b0ab
---
guix/scripts/system.scm | 22 ----------------------
1 file changed, 22 deletions(-)

Toggle diff (35 lines)
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index 0fd153a278..881f2de104 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -754,28 +754,6 @@ (define (maybe-suggest-running-guix-pull)
(warning (G_ "Consider running 'guix pull' before 'reconfigure'.~%"))
(warning (G_ "Failing to do that may downgrade your system!~%"))))
-(define (bootloader-installer-script installer
- bootloader device target)
- "Return a file calling INSTALLER gexp with given BOOTLOADER, DEVICE
-and TARGET arguments."
- (scheme-file "bootloader-installer"
- (with-imported-modules '((gnu build bootloader)
- (guix build utils))
- #~(begin
- (use-modules (gnu build bootloader)
- (guix build utils)
- (ice-9 binary-ports)
- (srfi srfi-34)
- (srfi srfi-35))
-
- (guard (c ((message-condition? c) ;XXX: i18n
- (format (current-error-port) "error: ~a~%"
- (condition-message c))
- (exit 1)))
- (#$installer #$bootloader #$device #$target)
- (info (G_ "bootloader successfully installed on '~a'~%")
- #$device))))))
-
(define (local-eval exp)
"Evaluate EXP, a G-Expression, in-place."
(mlet* %store-monad ((lowered (lower-gexp exp))
--
2.45.2
H
H
Herman Rimm wrote on 26 Sep 12:09 +0200
[PATCH v3 05/14] guix: scripts: Rewrite reinstall-bootloader to use provenance data.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
de896f29150ecc2d0bc731ddb571296f94ca5b15.1727345067.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

Looking up bootloaders by name is broken because (extlinux) bootloaders
share a name. Also, bootloader-configuration data is significant to
bootloader installation, so it shouldn't just use the default values.
Installation can rely on the provenance service instead, which should be
present for the vast majority of systems.

* gnu/bootloader.scm (%bootloaders): Delete variable.
(lookup-bootloader-by-name, bootloader-modules): Delete procedures.
* guix/scripts/system.scm (install-bootloader-from-os,
install-bootloader-from-provenance): Add procedures.
(reinstall-bootloader): Remove procedure.
(switch-to-system-generation, process-command): Use
install-bootloader-from-provenance.

Change-Id: I5713a43ad4f9f32a129d980db06d70de16b03f27
---
gnu/bootloader.scm | 26 ---------------
guix/scripts/system.scm | 73 ++++++++++++++++-------------------------
2 files changed, 28 insertions(+), 71 deletions(-)

Toggle diff (171 lines)
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index 865521e6e5..3ea50a4004 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -26,7 +26,6 @@
(define-module (gnu bootloader)
#:use-module (gnu system file-systems)
#:use-module (gnu system uuid)
- #:use-module (guix discovery)
#:use-module (guix gexp)
#:use-module (guix profiles)
#:use-module (guix records)
@@ -79,8 +78,6 @@ (define-module (gnu bootloader)
bootloader-configuration-device-tree-support?
bootloader-configuration-extra-initrd
- %bootloaders
- lookup-bootloader-by-name
efi-bootloader-chain))
@@ -287,29 +284,6 @@ (define (bootloader-configuration-targets config)
;;; Bootloaders.
;;;
-(define (bootloader-modules)
- "Return the list of bootloader modules."
- (all-modules (map (lambda (entry)
- `(,entry . "gnu/bootloader"))
- %load-path)
- #:warn warn-about-load-error))
-
-(define %bootloaders
- ;; The list of publically-known bootloaders.
- (delay (fold-module-public-variables (lambda (obj result)
- (if (bootloader? obj)
- (cons obj result)
- result))
- '()
- (bootloader-modules))))
-
-(define (lookup-bootloader-by-name name)
- "Return the bootloader called NAME."
- (or (find (lambda (bootloader)
- (eq? name (bootloader-name bootloader)))
- (force %bootloaders))
- (leave (G_ "~a: no such bootloader~%") name)))
-
(define (efi-bootloader-profile packages files hooks)
"Creates a profile from the lists of PACKAGES and FILES from the store.
This profile is meant to be used by the bootloader-installer.
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index 881f2de104..6b6bb46975 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -11,6 +11,8 @@
;;; Copyright © 2021 Brice Waegeneire <brice@waegenei.re>
;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com>
;;; Copyright © 2022 Tobias Geerinckx-Rice <me@tobias.gr>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
+;;; Copyright © 2024 Herman Rimm <herman@rimm.ee>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -88,6 +90,7 @@ (define-module (guix scripts system)
#:use-module (srfi srfi-37)
#:use-module (ice-9 format)
#:use-module (ice-9 match)
+ #:use-module (ice-9 receive)
#:use-module (rnrs bytevectors)
#:export (guix-system
read-operating-system
@@ -375,60 +378,39 @@ (define (switch-to-system-generation store spec)
(activate (string-append generation "/activate")))
(if number
(begin
- (reinstall-bootloader store number)
+ (install-bootloader-from-provenance store number)
(switch-to-generation* %system-profile number)
(unless-file-not-found (primitive-load activate)))
(leave (G_ "cannot switch to system generation '~a'~%") spec))))
-(define* (system-bootloader-name #:optional (system %system-profile))
- "Return the bootloader name stored in SYSTEM's \"parameters\" file."
- (let ((params (unless-file-not-found
- (read-boot-parameters-file system))))
- (boot-parameters-bootloader-name params)))
-
-(define (reinstall-bootloader store number)
- "Re-install bootloader for existing system profile generation NUMBER.
-STORE is an open connection to the store."
- (let* ((generation (generation-file-name %system-profile number))
- ;; Detect the bootloader used in %system-profile.
- (bootloader (lookup-bootloader-by-name (system-bootloader-name)))
-
- ;; Use the detected bootloader with default configuration.
- ;; It will be enough to allow the system to boot.
- (bootloader-config (bootloader-configuration
- (bootloader bootloader)))
-
- ;; Make the specified system generation the default entry.
- (chosen-alternative (generation->boot-alternative
- %system-profile number))
- (params (boot-alternative-parameters chosen-alternative))
- (locale (boot-parameters-locale params))
- (store-crypto-devices (boot-parameters-store-crypto-devices params))
- (store-directory-prefix
- (boot-parameters-store-directory-prefix params))
- (old-generations
- (delv number (reverse (generation-numbers %system-profile))))
- (previous-boot-alternatives (profile->boot-alternatives
- %system-profile old-generations))
- (entries (list (boot-parameters->menu-entry params)))
- (old-entries (map boot-alternative->menu-entry
- previous-boot-alternatives)))
+(define (install-bootloader-from-os store number os)
+ "Re-install an old bootloader defined in <operating-system> record OS,
+for system profile generation NUMBER, with store STORE."
+ (let* ((os (read-operating-system os))
+ (bootloader-config (operating-system-bootloader os))
+ (numbers (generation-numbers %system-profile))
+ (numbers (delv number (reverse numbers)))
+ (old (profile->boot-alternatives %system-profile numbers))
+ (bootcfg (operating-system-bootcfg os old)))
(run-with-store store
- (mlet* %store-monad
- ((bootcfg (lower-object
- ((bootloader-configuration-file-generator bootloader)
- bootloader-config entries
- #:locale locale
- #:store-crypto-devices store-crypto-devices
- #:store-directory-prefix store-directory-prefix
- #:old-entries old-entries)))
- (drvs -> (list bootcfg)))
+ (mlet* %store-monad ((bootcfg (lower-object bootcfg))
+ (drvs -> (list bootcfg)))
(mbegin %store-monad
(built-derivations drvs)
;; Only install bootloader configuration file.
(install-bootloader local-eval bootloader-config bootcfg
#:run-installer? #f))))))
+(define (install-bootloader-from-provenance store number)
+ "Re-install an old bootloader using provenance data for system profile
+generation NUMBER with store STORE."
+ (receive (_ os)
+ (system-provenance (generation-file-name %system-profile number))
+ (if os
+ (install-bootloader-from-os store number os)
+ (leave (G_ "cannot rollback to generation '~a': no provenance~%")
+ number))))
+
;;;
;;; Graphs.
@@ -1387,10 +1369,11 @@ (define (process-command command args opts)
(let ((pattern (match args
(() #f)
((pattern) pattern)
- (x (leave (G_ "wrong number of arguments~%"))))))
+ (_ (leave (G_ "wrong number of arguments~%")))))
+ (number (generation-number %system-profile)))
(with-store* store
(delete-matching-generations store %system-profile pattern)
- (reinstall-bootloader store (generation-number %system-profile)))))
+ (install-bootloader-from-provenance store number))))
((switch-generation)
(let ((pattern (match args
((pattern) pattern)
--
2.45.2
H
H
Herman Rimm wrote on 26 Sep 12:09 +0200
[PATCH v3 06/14] guix: utils: Add flatten and flat-map from haunt.
(address . 73202@debbugs.gnu.org)
fd8c84f59bae1ee4122809f164b851633089dd82.1727345067.git.herman@rimm.ee
* guix/utils.scm (flatten, flat-map): Add procedures.

Change-Id: I1d7d49fd02115e3de09ed69bcf5f55a10423162e
---
guix/utils.scm | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)

Toggle diff (46 lines)
diff --git a/guix/utils.scm b/guix/utils.scm
index f161cb4ef3..2740552a75 100644
--- a/guix/utils.scm
+++ b/guix/utils.scm
@@ -139,6 +139,9 @@ (define-module (guix utils)
with-environment-variables
arguments-from-environment-variable
+ flatten
+ flat-map
+
config-directory
cache-directory
@@ -1028,6 +1031,29 @@ (define (with-atomic-file-output file proc)
(false-if-exception (delete-file template))
(close-port out)))))
+;; TODO: bring over other utility procedures from (haunt utils).
+(define* (flatten lst #:optional depth)
+ "Return a list that recursively concatenates the sub-lists of LST,
+up to DEPTH levels deep. When DEPTH is #f, the entire tree is
+flattened."
+ (if (and (number? depth) (zero? depth))
+ lst
+ (fold-right (match-lambda*
+ (((sub-list ...) memo)
+ (append (flatten sub-list (and depth (1- depth)))
+ memo))
+ ((elem memo)
+ (cons elem memo)))
+ '()
+ lst)))
+
+(define (flat-map proc . lsts)
+ "Apply PROC to each element of each list in LSTS and return a new
+list in which nested lists are concatenated into the result.
+
+For example, the list (1 2 (3)) would be flattened to (1 2 3)."
+ (flatten (apply map proc lsts) 1))
+
(define* (xdg-directory variable suffix #:key (ensure? #t))
"Return the name of the XDG directory that matches VARIABLE and SUFFIX,
after making sure that it exists if ENSURE? is true. VARIABLE is an
--
2.45.2
H
H
Herman Rimm wrote on 26 Sep 12:09 +0200
[PATCH v3 07/14] guix: records: Add wrap-element procedure.
(address . 73202@debbugs.gnu.org)
016d2352f78fa879b32d3794f74082fadfe89285.1727345067.git.herman@rimm.ee
* guix/records.scm (wrap-element): Add procedure.

Change-Id: If121c5d856e815776830282a0701a73e5ae2a7e7
---
guix/records.scm | 7 +++++++
1 file changed, 7 insertions(+)

Toggle diff (34 lines)
diff --git a/guix/records.scm b/guix/records.scm
index c084441441..b521a59257 100644
--- a/guix/records.scm
+++ b/guix/records.scm
@@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2012-2024 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Mark H Weaver <mhw@netris.org>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -31,6 +32,8 @@ (define-module (guix records)
alist->record
object->fields
recutils->alist
+ wrap-element
+
match-record
match-record-lambda))
@@ -606,6 +609,10 @@ (define (recutils->alist port)
(else
(error "unmatched line" line))))))))
+(define (wrap-element x)
+ "Sanitize a record field value X to a list."
+ (if (list? x) x (list x)))
+
;;;
;;; Pattern matching.
--
2.45.2
H
H
Herman Rimm wrote on 26 Sep 12:09 +0200
[PATCH v3 08/14] gnu: bootloader: Add bootloader-target record and infastructure.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
d7820e89fbf046495d02e860f015c83fce0a7d18.1727345067.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/bootloader.scm (bootloader-target): New record.
(&target-error): New condition.
(pathcat, get-target-of-type, parent-of, unfold-pathcat, target-base?,
type-major?, ensure, ensure-target-types, ensure-majors, gbegin): New
procedures.
(define-literal, with-targets, :path, :devpath, :device, :fs, :label,
:uuid): New macros.
* guix/ui.scm (call-with-error-handling)[target-error?]: Handle
target-errors.

Change-Id: I3f07c9096dd8b91c04449b6360b3b7d21640da14
---
gnu/bootloader.scm | 229 ++++++++++++++++++++++++++++++++++++++++++++-
guix/ui.scm | 9 ++
2 files changed, 233 insertions(+), 5 deletions(-)

Toggle diff (305 lines)
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index 3ea50a4004..0c24996205 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -7,6 +7,7 @@
;;; Copyright © 2022 Josselin Poiret <dev@jpoiret.xyz>
;;; Copyright © 2022 Reza Alizadeh Majd <r.majd@pantherx.org>
;;; Copyright © 2024 Tomas Volf <~@wolfsden.cz>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -24,19 +25,28 @@
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (gnu bootloader)
+ #:autoload (gnu build file-systems)
+ (read-partition-label read-partition-uuid
+ find-partition-by-label find-partition-by-uuid)
#:use-module (gnu system file-systems)
#:use-module (gnu system uuid)
- #:use-module (guix gexp)
- #:use-module (guix profiles)
- #:use-module (guix records)
+ #:autoload (guix build syscalls)
+ (mounts mount-source mount-point mount-type)
#:use-module (guix deprecation)
- #:use-module ((guix ui) #:select (warn-about-load-error))
#:use-module (guix diagnostics)
+ #:use-module (guix gexp)
#:use-module (guix i18n)
+ #:use-module (guix modules)
+ #:use-module (guix profiles)
+ #:use-module (guix records)
+ #:use-module (guix utils)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 receive)
+ #:use-module (rnrs bytevectors)
#:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
#:use-module (srfi srfi-34)
#:use-module (srfi srfi-35)
- #:use-module (ice-9 match)
#:export (menu-entry
menu-entry?
menu-entry-label
@@ -62,6 +72,25 @@ (define-module (gnu bootloader)
bootloader-configuration-file
bootloader-configuration-file-generator
+ bootloader-target
+ bootloader-target?
+ bootloader-target-type
+ bootloader-target-expected?
+ bootloader-target-path
+ bootloader-target-offset
+ bootloader-target-device
+ bootloader-target-file-system
+ bootloader-target-label
+ bootloader-target-uuid
+
+ target-error?
+ target-error-type
+ target-error-targets
+
+ gbegin
+ :path :devpath :device :fs :label :uuid
+ with-targets
+
bootloader-configuration
bootloader-configuration?
bootloader-configuration-bootloader
@@ -232,6 +261,196 @@ (define-record-type* <bootloader>
(configuration-file bootloader-configuration-file)
(configuration-file-generator bootloader-configuration-file-generator))
+
+;;;
+;;; Bootloader target record.
+;;;
+
+;; <bootloader-target> represents different kinds of targets in a
+;; normalized form.
+
+(define-record-type* <bootloader-target>
+ bootloader-target make-bootloader-target bootloader-target?
+ (type bootloader-target-type) ; symbol
+ (expected? bootloader-target-expected? (default #f)) ; bool
+
+ (path bootloader-target-path (default #f)) ; string|#f
+ (offset bootloader-target-offset (thunked) ; symbol|#f
+ (default (and (bootloader-target-path this-record)
+ (not (eq? (bootloader-target-type this-record) 'root))
+ 'root)))
+ (device bootloader-target-device (default #f)) ; string|#f
+ (file-system bootloader-target-file-system (default #f)) ; string|#f
+ (label bootloader-target-label (default #f)) ; string|#f
+ (uuid bootloader-target-uuid (default #f))) ; uuid|#f
+
+(define-condition-type &target-error &error target-error?
+ (type target-error-type)
+ (targets target-error-targets))
+
+(define (pathcat p1 p2)
+ (string-append (string-trim-right p1 #\/) "/" (string-trim p2 #\/)))
+
+(define* (get-target-of-type type targets #:optional require?)
+ "Finds a target in TARGETS of type TYPE, returns REQUIRE? if #false,
+or provides an error otherwise."
+ (define (type? target)
+ (eq? type (bootloader-target-type target)))
+ (match (filter type? targets)
+ ((target _ ...) target)
+ (_ (and require?
+ (raise
+ (condition
+ (&message (message (G_ "required, but not provided")))
+ (&target-error (type type) (targets targets))))))))
+
+(define (parent-of target targets)
+ "Resolve the parent of TARGET in TARGETS, return #f if orphan."
+ (and=> (bootloader-target-offset target)
+ (cut get-target-of-type <> targets #t)))
+
+(define (unfold-pathcat target targets)
+ "Find the full VFS path of TARGET."
+ (let ((quit (lambda (t) (not (and=> t bootloader-target-path))))
+ (parent-of (cut parent-of <> targets)))
+ (reduce pathcat #f
+ (unfold quit bootloader-target-path parent-of target))))
+
+(define (target-base? t)
+ (or (not t) (match-record t <bootloader-target>
+ (expected? offset device label uuid)
+ (or device label uuid (not offset) expected?))))
+
+(define (type-major? target) (memq target '(root esp disk)))
+
+(define (ensure types targets end)
+ (let* ((used-in (cute unfold end identity (cut parent-of <> targets) <>))
+ (cons-in (lambda (t) (cons t (used-in t))))
+ (ensure (map (cut get-target-of-type <> targets #t) types)))
+ (filter identity (apply append (map cons-in ensure)))))
+
+(define* (ensure-target-types types targets #:optional (base? #f))
+ "Ensures all TYPES are provided in TARGETS. Returns #t iff every ensured
+target and its requirements are fully provided. Errors out when a required TYPE
+isn't provided. When BASE?, only ensure path requirements up to a device."
+ (not (any bootloader-target-expected?
+ (ensure types targets (if base? target-base? not)))))
+
+(define (ensure-majors types targets)
+ "Errors out when a required TYPE isn't provided, or when use of multiple major
+targets is detected."
+ (let* ((all (map bootloader-target-type (ensure types targets target-base?)))
+ (majors (delete-duplicates (filter type-major? all) eq?)))
+ (if (< (length majors) 2) #t
+ (raise (condition (&message (message (G_ "multiple major targets used")))
+ (&target-error (type majors) (targets targets)))))))
+
+
+
+(define (gbegin . gex)
+ "Sequence provided g-expressions."
+ (case (length gex) ((0) #f) ((1) (car gex)) (else #~(begin #$@gex))))
+
+;; syntax matching on free literals breaks easily, so bind them
+(define-syntax-rule (define-literal id) (define-syntax id (syntax-rules ())))
+(define-literal :path)
+(define-literal :devpath)
+(define-literal :device)
+(define-literal :fs)
+(define-literal :label)
+(define-literal :uuid)
+
+(define-syntax with-targets
+ (cut syntax-case <> ()
+ ((_ targets-expr block ...)
+ (let* ((genvars (compose generate-temporaries make-list))
+ (targets (car (genvars 1))))
+ (define (resolve in target base)
+ (with-syntax ((target target) (base base) (targets targets))
+ (syntax-case in
+ (:path :devpath :device :fs :label :uuid)
+ ((name _) (not (identifier? #'name))
+ #`(_ (syntax-error "binds must be to identifiers" #,in)))
+ ((name :device) #'(name (bootloader-target-device base)))
+ ((name :label) #'(name (bootloader-target-label base)))
+ ((name :uuid) #'(name (bootloader-target-uuid base)))
+ ((name :fs) #'(name (bootloader-target-file-system base)))
+ ((name :path) #'(name (unfold-pathcat target targets)))
+ ((name :devpath)
+ #'(name (if (target-base? target)
+ "/"
+ (pathcat "/" (bootloader-target-path target)))))
+ (_ #`(_ (syntax-error "invalid binding spec" #,in))))))
+
+ (define (binds spec)
+ (syntax-case spec (=>)
+ ((type => binds ...)
+ (with-syntax (((target base) (genvars 2)) (targets targets))
+ (append
+ #`((get (lambda (t) (get-target-of-type t targets #t)))
+ (target (get type))
+ (base (if (target-base? target)
+ target
+ (get (bootloader-target-offset target)))))
+ (map (cut resolve <> #'target #'base) #'(binds ...)))))
+ (_ #f)))
+
+ (define blocks
+ (cut syntax-case <> ()
+ ((spec ... expr)
+ (let* ((path? (cut syntax-case <> (:path) ((_ :path) #t) (_ #f)))
+ (qualified? (cut syntax-case <> (=>)
+ ((_ => spec ...) (any path? #'(spec ...)))
+ (_ #f)))
+ (specs #'(spec ...))
+ (lets (apply append (filter-map binds specs)))
+ (type (cut syntax-case <> (=>)
+ ((t => _ ...) #'t) (t #'t))))
+ (receive (full part) (partition qualified? specs)
+ #`(and (ensure-majors (list #,@(map type specs)) #,targets)
+ (ensure-target-types (list #,@(map type part))
+ #,targets #t)
+ (ensure-target-types (list #,@(map type full))
+ #,targets #f)
+ (let* #,lets expr)))))
+ (bad #'(syntax-error "malformed block" bad))))
+ "Using the list TARGETS, evaluate and sequence each BLOCK to produce a
+gexp. BLOCK is a set of SPECs followed by an EXPR (evaluating to a gexp).
+Each SPEC denotes a type of target to guard EXPR on their existance and
+full-qualification. This procedure is linear in regard to BLOCKs.
+
+SPEC may be of the following forms:
+@itemize
+@item 'TYPE Requires TYPE to be fully present or promised. Errors otherwise.
+@item ('TYPE => (VAR COMPONENT) ...): As type, but also binds variables. TYPE's
+ COMPONENT is bound to the variable VAR as described below.
+@end itemize
+
+Available COMPONENTs are:
+@itemize
+@item :path (fully-qualified)
+@item :devpath (relative from device)
+@item :device (auto-detected from uuid and label if not user-provided)
+@item :fs
+@item :label
+@item :uuid
+@end itemize
+
+Note that installers may be called multiple times with different targets being
+fully-qualified. To ensure that targets aren't installed multiple times, make sure
+that each BLOCK ensures at least one major target, either directly or indirectly.
+Likewise, at most one major target should be ensured per BLOCK, under the same
+conditions. Major targets originate from disk image handling, and are currently:
+@itemize
+@item disk
+@item root
+@item esp
+@end itemize"
+ #`(let ((#,targets targets-expr))
+ (apply gbegin (filter identity
+ (list #,@(map blocks #'(block ...))))))))
+ (bad #'(syntax-error "must provide targets" bad))))
+
;;;
;;; Bootloader configuration record.
diff --git a/guix/ui.scm b/guix/ui.scm
index fe059ba089..663b814da6 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -19,6 +19,7 @@
;;; Copyright © 2018 Steve Sprang <scs@stevesprang.com>
;;; Copyright © 2022 Taiju HIGASHI <higashi@taiju.info>
;;; Copyright © 2022 Liliana Marie Prikler <liliana.prikler@gmail.com>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -36,6 +37,8 @@
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (guix ui) ;import in user interfaces only
+ #:use-module ((gnu bootloader)
+ #:select (target-error? target-error-type target-error-targets))
#:use-module (guix i18n)
#:use-module (guix colors)
#:use-module (guix diagnostics)
@@ -862,6 +865,12 @@ (define (call-with-error-handling thunk)
(invoke-error-stop-signal c)
(cons (invoke-error-program c)
(invoke-error-arguments c))))
+ ((target-error? c)
+ (leave (G_ "bootloader-target '~a'~@[: ~a~] ~
+ among the following targets:~%~{~y~}")
+ (target-error-type c)
+ (and (message-condition? c) (condition-message c))
+ (target-error-targets c)))
((formatted-message? c)
(apply report-error
--
2.45.2
H
H
Herman Rimm wrote on 26 Sep 12:09 +0200
[PATCH v3 09/14] gnu: bootloader: Add bootloader-configurations->gexp.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
2ce2a5d1b077a35dcfc95c707703f8c0a11bf3b2.1727345067.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/bootloader.scm (bootloader)[default-targets]: Add field.
(target-overrides, normalize, bootloader-configuration->gexp,
bootloader-configurations->gexp): New procedures.

Change-Id: I3654d160f7306bb45a78b82ea6b249ff4281f739
---
gnu/bootloader.scm | 108 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 108 insertions(+)

Toggle diff (142 lines)
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index 0c24996205..c77de6f55e 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -67,6 +67,7 @@ (define-module (gnu bootloader)
bootloader?
bootloader-name
bootloader-package
+ bootloader-default-targets
bootloader-installer
bootloader-disk-image-installer
bootloader-configuration-file
@@ -107,6 +108,8 @@ (define-module (gnu bootloader)
bootloader-configuration-device-tree-support?
bootloader-configuration-extra-initrd
+ bootloader-configuration->gexp
+ bootloader-configurations->gexp
efi-bootloader-chain))
@@ -255,6 +258,7 @@ (define-record-type* <bootloader>
bootloader?
(name bootloader-name)
(package bootloader-package)
+ (default-targets bootloader-default-targets (default '()))
(installer bootloader-installer)
(disk-image-installer bootloader-disk-image-installer
(default #f))
@@ -498,6 +502,110 @@ (define (bootloader-configuration-targets config)
;; hence the default value of '(#f) rather than '().
(list #f)))
+
+;;;
+;;; Bootloader installation paths.
+;;;
+
+(define (target-overrides . layers)
+ (let* ((types (flat-map (cute map bootloader-target-type <>) layers))
+ ;; TODO: use loop instead of fold for early termination.
+ (pred (lambda (type layer found)
+ (or found (get-target-of-type type layer))))
+ (find (lambda (type) (fold (cute pred type <> <>) #f layers))))
+ (filter identity (map find (delete-duplicates types)))))
+
+(define (normalize targets)
+ "Augments TARGETS with filesystem information at runtime, allowing
+users to specify a lot less information. Puts TARGETS into a normal
+form, where each path is fully specified up to a device offset."
+ (define (mass m)
+ `((,(mount-source m) . ,m)
+ (,(mount-point m) . ,m)))
+
+ (define (accessible=> d f)
+ (and d (access? d R_OK) (f d)))
+
+ (define (fixuuid target)
+ (match-record target <bootloader-target> (uuid file-system)
+ (let ((type (cond ((not file-system) 'dce)
+ ((member file-system '("vfat" "fat32")) 'fat)
+ ((string=? file-system "ntfs") 'ntfs)
+ ((string=? file-system "iso9660") 'iso9660)
+ (else 'dce))))
+ (bootloader-target (inherit target)
+ (uuid (cond ((uuid? uuid) uuid)
+ ((bytevector? uuid) (bytevector->uuid uuid type))
+ ((string? uuid) (string->uuid uuid type))
+ (else #f)))))))
+
+ (define (arborify target targets)
+ (let* ((up (lambda (t) (and t (parent-of t targets))))
+ (proto (unfold target-base? identity up (up target) list))
+ (chain (reverse (cons target proto))))
+ (bootloader-target
+ (inherit target)
+ (offset (and=> (car chain) bootloader-target-type))
+ (path (reduce pathcat #f (map bootloader-target-path (cdr chain)))))))
+
+ (let ((amounts (delay (apply append (map mass (mounts))))))
+ (define (assoc-mnt f)
+ (lambda (v) (and=> (assoc-ref (force amounts) v) f)))
+
+ (define (scrape target)
+ (match-record target <bootloader-target>
+ (expected? path offset device label uuid file-system)
+ (if expected? target
+ (bootloader-target
+ (inherit target)
+ (device (or device
+ (false-if-exception
+ (or (and=> uuid find-partition-by-uuid)
+ (and=> label find-partition-by-label)))
+ (and path ((assoc-mnt mount-source)
+ (unfold-pathcat target targets)))))
+ (label (or label (accessible=> device read-partition-label)))
+ (uuid (or uuid (accessible=> device read-partition-uuid)))
+ (file-system (or file-system (and=> device (assoc-mnt mount-type))))
+ (offset (and path offset))
+ (path (or path (and=> device (assoc-mnt mount-point))))))))
+
+ (let ((mid (map (compose fixuuid scrape) targets)))
+ (map (cut arborify <> mid) mid))))
+
+(define* (bootloader-configuration->gexp bootloader-config args #:key
+ (root-offset "/") (overrides '()))
+ "Returns a gexp to install BOOTLOADER-CONFIG to its targets, passing ARGS
+to each installer alongside the additional #:bootloader-config keyword
+arguments. Target OVERRIDES are applied and all path targets have ROOT-OFFSET
+applied. The following keyword arguments are expected in ARGS:
+@enumerate
+@item current-boot-alternative
+@item old-boot-alternatives
+@item locale (from bootmeta)
+@item store-directory-prefix (from bootmeta)
+@item store-crypto-devices (from bootmeta)
+@end enumerate"
+ (let* ((bootloader (bootloader-configuration-bootloader bootloader-config))
+ (installer (bootloader-installer bootloader))
+ (auto-targets (list (bootloader-target
+ (type 'root)
+ (path root-offset)
+ (offset #f))))
+ (targets (target-overrides
+ overrides
+ (bootloader-configuration-targets bootloader-config)
+ auto-targets
+ (bootloader-default-targets bootloader)))
+ (conf (bootloader-configuration
+ (inherit bootloader-config)
+ (targets (normalize targets)))))
+ (apply installer #:bootloader-config conf args)))
+
+(define (bootloader-configurations->gexp bootloader-configs . rest)
+ (apply gbegin (filter-map (cut apply bootloader-configuration->gexp <> rest)
+ bootloader-configs)))
+
;;;
;;; Bootloaders.
--
2.45.2
H
H
Herman Rimm wrote on 26 Sep 12:09 +0200
[PATCH v3 10/14] gnu: bootloader: Add device-subvol field to menu-entry record.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
33b51456dc709d17c8be3776471e0599f83eaec1.1727345067.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/bootloader.scm (menu-entry-device-subvol): Add and export field.
(normalize-file): Add procedure.
(device->sexp): Match device-subvol and include in S-expression.
(sexp->menu-entry): Try match device-subvol and include in menu-entry.
* gnu/system/boot.scm (boot-parameters->menu-entry): Add device-subvol
value to menu-entry.

Change-Id: I3654d160f7306bb45a78b82ea6b249ff4281f739
---
gnu/bootloader.scm | 51 ++++++++++++++++++++++++++++++++++-----------
gnu/system/boot.scm | 1 +
2 files changed, 40 insertions(+), 12 deletions(-)

Toggle diff (160 lines)
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index c77de6f55e..f1352122a9 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -51,15 +51,17 @@ (define-module (gnu bootloader)
menu-entry?
menu-entry-label
menu-entry-device
+ menu-entry-device-mount-point
+ menu-entry-device-subvol
menu-entry-linux
menu-entry-linux-arguments
menu-entry-initrd
- menu-entry-device-mount-point
menu-entry-multiboot-kernel
menu-entry-multiboot-arguments
menu-entry-multiboot-modules
menu-entry-chain-loader
+ normalize-file
menu-entry->sexp
sexp->menu-entry
@@ -126,6 +128,8 @@ (define-record-type* <menu-entry>
(default #f))
(device-mount-point menu-entry-device-mount-point
(default #f))
+ (device-subvol menu-entry-device-subvol
+ (default #f))
(linux menu-entry-linux
(default #f))
(linux-arguments menu-entry-linux-arguments
@@ -142,6 +146,18 @@ (define-record-type* <menu-entry>
(chain-loader menu-entry-chain-loader
(default #f))) ; string, path of efi file
+(define (normalize-file entry file)
+ "Normalize a file FILE stored in a menu entry into one suitable for a
+bootloader. Realizes device-mount-point and device-subvol."
+ (match-menu-entry entry (device-mount-point device-subvol)
+ ;; Avoid using cut procedure from SRFI-26 inside G-exp.
+ (let ((mount (and=> device-mount-point (cut string-trim <> #\/))))
+ #~(let* ((file (string-trim #$file #\/))
+ (file (if (and #$mount (string-prefix? #$mount file))
+ (substring file (string-length #$mount))
+ file)))
+ (string-append (or #$device-subvol "") "/" file)))))
+
(define (report-menu-entry-error menu-entry)
(raise
(condition
@@ -169,7 +185,7 @@ (define (menu-entry->sexp entry)
`(label ,(file-system-label->string label)))
(_ device)))
(match entry
- (($ <menu-entry> label device mount-point
+ (($ <menu-entry> label device mount-point subvol
(? identity linux) linux-arguments (? identity initrd)
#f () () #f)
`(menu-entry (version 0)
@@ -178,8 +194,9 @@ (define (menu-entry->sexp entry)
(device-mount-point ,mount-point)
(linux ,linux)
(linux-arguments ,linux-arguments)
- (initrd ,initrd)))
- (($ <menu-entry> label device mount-point #f () #f
+ (initrd ,initrd)
+ (device-subvol ,subvol)))
+ (($ <menu-entry> label device mount-point subvol #f () #f
(? identity multiboot-kernel) multiboot-arguments
multiboot-modules #f)
`(menu-entry (version 0)
@@ -188,19 +205,23 @@ (define (menu-entry->sexp entry)
(device-mount-point ,mount-point)
(multiboot-kernel ,multiboot-kernel)
(multiboot-arguments ,multiboot-arguments)
- (multiboot-modules ,multiboot-modules)))
- (($ <menu-entry> label device mount-point #f () #f #f () ()
+ (multiboot-modules ,multiboot-modules)
+ (device-subvol ,subvol)))
+ (($ <menu-entry> label device mount-point subvol #f () #f #f () ()
(? identity chain-loader))
`(menu-entry (version 0)
(label ,label)
(device ,(device->sexp device))
(device-mount-point ,mount-point)
- (chain-loader ,chain-loader)))
+ (chain-loader ,chain-loader)
+ (device-subvol ,subvol)))
(_ (report-menu-entry-error entry))))
(define (sexp->menu-entry sexp)
"Turn SEXP, an sexp as returned by 'menu-entry->sexp', into a <menu-entry>
record."
+ ;; XXX: The match ORs shadow subvol.
+ (define subvol #f)
(define (sexp->device device-sexp)
(match device-sexp
(('uuid type uuid-string)
@@ -213,35 +234,41 @@ (define (sexp->menu-entry sexp)
('label label) ('device device)
('device-mount-point mount-point)
('linux linux) ('linux-arguments linux-arguments)
- ('initrd initrd) _ ...)
+ ('initrd initrd)
+ (or ('device-subvol subvol _ ...) (_ ...)))
(menu-entry
(label label)
(device (sexp->device device))
(device-mount-point mount-point)
+ (device-subvol subvol)
(linux linux)
(linux-arguments linux-arguments)
(initrd initrd)))
(('menu-entry ('version 0)
('label label) ('device device)
- ('device-mount-point mount-point)
+ ('device-mount-point mount-point) ('device-subvol subvol)
('multiboot-kernel multiboot-kernel)
('multiboot-arguments multiboot-arguments)
- ('multiboot-modules multiboot-modules) _ ...)
+ ('multiboot-modules multiboot-modules)
+ (or ('device-subvol subvol _ ...) (_ ...)))
(menu-entry
(label label)
(device (sexp->device device))
(device-mount-point mount-point)
+ (device-subvol subvol)
(multiboot-kernel multiboot-kernel)
(multiboot-arguments multiboot-arguments)
(multiboot-modules multiboot-modules)))
(('menu-entry ('version 0)
('label label) ('device device)
- ('device-mount-point mount-point)
- ('chain-loader chain-loader) _ ...)
+ ('device-mount-point mount-point) ('device-subvol subvol)
+ ('chain-loader chain-loader)
+ (or ('device-subvol subvol _ ...) (_ ...)))
(menu-entry
(label label)
(device (sexp->device device))
(device-mount-point mount-point)
+ (device-subvol subvol)
(chain-loader chain-loader)))))
diff --git a/gnu/system/boot.scm b/gnu/system/boot.scm
index 54e5673a54..98fcd2b3a0 100644
--- a/gnu/system/boot.scm
+++ b/gnu/system/boot.scm
@@ -328,6 +328,7 @@ (define (boot-parameters->menu-entry conf)
(label (boot-parameters-label conf))
(device (boot-parameters-store-device conf))
(device-mount-point (boot-parameters-store-mount-point conf))
+ (device-subvol (boot-parameters-store-directory-prefix conf))
(linux (and (not multiboot?) kernel))
(linux-arguments (if (not multiboot?)
(boot-parameters-kernel-arguments conf)
--
2.45.2
H
H
Herman Rimm wrote on 26 Sep 12:09 +0200
[PATCH v3 11/14] gnu: build: bootloader: Add efi-bootnums procedure.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
3063da96c7b9dc3db63dbc96d2238f6ed742b857.1727345067.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/build/bootloader.scm (atomic-copy, efi-bootnums): Add procedures.
(in-temporary-directory): Add macro.

Change-Id: I3654d160f7306bb45a78b82ea6b249ff4281f739
---
gnu/build/bootloader.scm | 48 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 47 insertions(+), 1 deletion(-)

Toggle diff (88 lines)
diff --git a/gnu/build/bootloader.scm b/gnu/build/bootloader.scm
index af6063a884..3934e03aee 100644
--- a/gnu/build/bootloader.scm
+++ b/gnu/build/bootloader.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2019 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2022 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
;;; Copyright © 2022 Timothy Sample <samplet@ngyro.com>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -20,13 +21,25 @@
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (gnu build bootloader)
+ #:autoload (guix build syscalls) (free-disk-space)
#:use-module (guix build utils)
#:use-module (guix utils)
#:use-module (ice-9 binary-ports)
+ #:use-module (guix diagnostics)
+ #:use-module (guix i18n)
#:use-module (ice-9 format)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 popen)
+ #:use-module (ice-9 receive)
+ #:use-module (ice-9 regex)
#:use-module (rnrs io ports)
#:use-module (rnrs io simple)
- #:export (write-file-on-device
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
+ #:use-module (srfi srfi-35)
+ #:export (atomic-copy
+ in-temporary-directory
+ write-file-on-device
install-efi-loader))
@@ -34,6 +47,21 @@ (define-module (gnu build bootloader)
;;; Writing utils.
;;;
+(define (atomic-copy from to)
+ (let ((pivot (string-append to ".new")))
+ (copy-file from pivot)
+ (rename-file pivot to)))
+
+(define-syntax-rule (in-temporary-directory blocks ...)
+ "Run BLOCKS while chdir'd into a temporary directory."
+ ;; Under POSIX.1-2008, mkdtemp must make the dir with 700 perms.
+ (let* ((tmp (or (getenv "TMPDIR") "/tmp"))
+ (dir (mkdtemp (string-append tmp "/guix-bootloader.XXXXXX")))
+ (cwd (getcwd)))
+ (dynamic-wind (lambda () (chdir dir))
+ (lambda () blocks ...)
+ (lambda () (chdir cwd) (delete-file-recursively dir)))))
+
(define (write-file-on-device file size device offset)
"Write SIZE bytes from FILE to DEVICE starting at OFFSET."
(call-with-input-file file
@@ -56,6 +84,24 @@ (define (write-file-on-device file size device offset)
;;; EFI bootloader.
;;;
+;; XXX: Parsing efibootmgr output may be kinda jank. A better way may exist.
+(define (efi-bootnums efibootmgr)
+ "Returns '(path . bootnum) pairs for each EFI boot entry. bootnum is
+a string, and path is backslash-deliminated and relative to the ESP."
+ (let* ((pipe (open-pipe* OPEN_READ efibootmgr))
+ (text (get-string-all pipe))
+ (status (status:exit-val (close-pipe pipe)))
+ (bootnum-pattern
+ "^Boot([0-9a-fA-F]+).*[^A-Za-z]File\\(([^)]+)\\)$"))
+ (unless (zero? status)
+ (raise-exception
+ (formatted-message (G_ "efibootmgr exited with error code ~a") status)))
+ (fold-matches (make-regexp bootnum-pattern regexp/newline) text '()
+ (lambda (match acc)
+ (let* ((path (match:substring match 2))
+ (bootnum (match:substring match 1)))
+ (cons (cons path bootnum) acc))))))
+
(define* (install-efi grub grub-config esp #:key targets)
"Write a self-contained GRUB EFI loader to the mounted ESP using
GRUB-CONFIG.
--
2.45.2
H
H
Herman Rimm wrote on 26 Sep 12:09 +0200
[PATCH v3 13/14] gnu: bootloader: Match records outside the module.
(address . 73202@debbugs.gnu.org)
b04fb48f74331addc5eb380e46ccb8750d8545b5.1727345067.git.herman@rimm.ee
* gnu/bootloader.scm (match-bootloader-configuration, match-menu-entry):
Add macros.

Change-Id: I42cb7541045314c37ffef98fe6efe7f46acd9d9b
---
gnu/bootloader.scm | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)

Toggle diff (45 lines)
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index 6b08e61492..b1ed187aa2 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -8,6 +8,7 @@
;;; Copyright © 2022 Reza Alizadeh Majd <r.majd@pantherx.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.
;;;
@@ -115,6 +116,9 @@ (define-module (gnu bootloader)
bootloader-configuration->gexp
bootloader-configurations->gexp
+ match-bootloader-configuration
+ match-menu-entry
+
%efi-supported-systems
efi-arch
install-efi
@@ -642,6 +646,20 @@ (define (bootloader-configurations->gexp bootloader-configs . rest)
(apply gbegin (filter-map (cut apply bootloader-configuration->gexp <> rest)
bootloader-configs)))
+;; In lieu of exporting bootloader-configuration and menu-entry RTDs.
+(define-syntax match-bootloader-configuration
+ (syntax-rules ()
+ "Bind each BOOTLOADER-CONFIGURATION field in FIELDS."
+ ((_ bootloader-configuration (fields ...) body ...)
+ (match-record bootloader-configuration <bootloader-configuration>
+ (fields ...) body ...))))
+
+(define-syntax match-menu-entry
+ (syntax-rules ()
+ "Bind each MENU-ENTRY field in FIELDS."
+ ((_ menu-entry (fields ...) body ...)
+ (match-record menu-entry <menu-entry> (fields ...) body ...))))
+
;;;
;;; Bootloader installation to ESP.
--
2.45.2
H
H
Herman Rimm wrote on 26 Sep 12:09 +0200
[PATCH v3 14/14] teams: Add bootloading team.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
5bca06489688f23265bec3e96fb94412acd05b0f.1727345067.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

Might as well, to help ease the transition.

* etc/teams.scm (bootloaders): New team.
(Lilah Tascheter): Create and add to above.

Change-Id: I63620f4e3151bb8e3d0bdf619fc70501af6397a0
---
etc/teams.scm | 10 ++++++++++
1 file changed, 10 insertions(+)

Toggle diff (30 lines)
diff --git a/etc/teams.scm b/etc/teams.scm
index 9239021b39..2150a7aad1 100755
--- a/etc/teams.scm
+++ b/etc/teams.scm
@@ -328,6 +328,12 @@ (define-team embedded
#:scope (list "gnu/packages/bootloaders.scm"
"gnu/packages/firmware.scm")))
+(define-team bootloaders
+ (team 'bootloaders
+ #:name "Bootloaders"
+ #:scope (list "gnu/bootloader.scm"
+ (make-regexp* "^gnu/bootloader/"))))
+
(define-team rust
(team 'rust
#:name "Rust"
@@ -749,6 +755,10 @@ (define-member (person "André Batista"
"nandre@riseup.net")
mozilla)
+(define-member (person "Lilah Tascheter"
+ "lilah@lunabee.space")
+ bootloaders)
+
(define (find-team name)
(or (hash-ref %teams (string->symbol name))
--
2.45.2
H
H
Herman Rimm wrote on 26 Sep 12:09 +0200
[PATCH v3 12/14] gnu: bootloader: Install any bootloader to ESP.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
e5a67b99cf8792af7870903e8517bc42b60c9528.1727345067.git.herman@rimm.ee
From: Lilah Tascheter <lilah@lunabee.space>

* gnu/bootloader.scm (efi-arch, install-efi): New procedures.
(%efi-supported-systems, lazy-efibootmgr): New variables.
(bootloader-configuration)[efi-removable?, 32bit?]: New fields.
(match-bootloader-configuration, match-menu-entry): New macros.
* gnu/build/bootloader.scm (install-efi-loader): Delete procedure.
(install-efi): Rewrite to support installation of any efi bootloader.
* gnu/build/image.scm (initialize-efi32-partition): Deprecate.
(initialize-efi-partitition): Only create EFI directory.
* gnu/image.scm (partition)[target]: New field in order to support
dynamic provision of image partitions as bootloader targets.
* gnu/system/image.scm (root-partition, esp-partition): Use target
field.
* gnu/system/image.scm (esp32-partition, efi32-disk-partition,
efi32-raw-image-type): Deprecate.
* doc/guix.texi (Creating System Images)[image Reference]<partition
Reference>: Add target field.
[Instantiate an Image]: Update examples and update formatting.
<efi32-disk-image, efi32-raw-image-type>: Delete.
<pinebook-pro-image-type, rock64-image-type>: Reword slightly.

Change-Id: I3654d160f7306bb45a78b82ea6b249ff4281f739
---
doc/guix.texi | 34 ++++++------
gnu/bootloader.scm | 56 ++++++++++++++++++-
gnu/build/bootloader.scm | 115 ++++++++++++++++++++-------------------
gnu/build/image.scm | 23 ++------
gnu/image.scm | 4 ++
gnu/system/image.scm | 22 +++-----
6 files changed, 150 insertions(+), 104 deletions(-)

Toggle diff (412 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 38a4650977..2f6d72f793 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -130,6 +130,7 @@
Copyright @copyright{} 2024 Dariqq@*
Copyright @copyright{} 2024 Denis 'GNUtoo' Carikli@*
Copyright @copyright{} 2024 Fabio Natali@*
+Copyright @copyright{} 2024 Lilah Tascheter@*
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -48163,6 +48164,12 @@ partition Reference
this flag set, usually the root one. The @code{'esp} flag identifies a
UEFI System Partition.
+@item @code{target} (default: @var{#f})
+If provided, this partition provides itself as a bootloader target
+(@pxref{Bootloader Configuration}). Most commonly, this is used to provide the
+@code{'root} and @code{'esp} targets, with the root partition and EFI System
+Partition, respectively, though this can provide any target necessary.
+
@item @code{initializer} (default: @code{#false})
The partition initializer procedure as a gexp. This procedure is called
to populate a partition. If no initializer is passed, the
@@ -48211,6 +48218,7 @@ Instantiate an Image
(label "GNU-ESP")
(file-system "vfat")
(flags '(esp))
+ (target 'esp)
(initializer (gexp initialize-efi-partition)))
(partition
(size (* 50 MiB))
@@ -48227,15 +48235,17 @@ Instantiate an Image
(label root-label)
(file-system "ext4")
(flags '(boot))
+ (target 'root)
(initializer (gexp initialize-root-partition))))))
@end lisp
-Note that the first and third partitions use generic initializers
-procedures, initialize-efi-partition and initialize-root-partition
-respectively. The initialize-efi-partition installs a GRUB EFI loader
-that is loading the GRUB bootloader located in the root partition. The
-initialize-root-partition instantiates a complete system as defined by
-the @code{%simple-os} operating-system.
+Note that the first and third partitions use generic initializer
+procedures, @code{initialize-efi-partition} and
+@code{initialize-root-partition} respectively.
+@code{initialize-efi-partition} simply creates the directory structure
+for an EFI bootloader to install itself to.
+@code{initialize-root-partition} instantiates a complete system as
+defined by the @code{%simple-os} operating-system.
You can now run:
@@ -48292,10 +48302,6 @@ Instantiate an Image
@code{i686} machines, supporting BIOS or UEFI booting.
@end defvar
-@defvar efi32-disk-image
-Same as @code{efi-disk-image} but with a 32 bits EFI partition.
-@end defvar
-
@defvar iso9660-image
An ISO-9660 image composed of a single bootable partition. This image
can also be used on most @code{x86_64} and @code{i686} machines.
@@ -48386,10 +48392,6 @@ image-type Reference
Build an image based on the @code{efi-disk-image} image.
@end defvar
-@defvar efi32-raw-image-type
-Build an image based on the @code{efi32-disk-image} image.
-@end defvar
-
@defvar qcow2-image-type
Build an image based on the @code{mbr-disk-image} image but with the
@code{compressed-qcow2} image format.
@@ -48417,14 +48419,14 @@ image-type Reference
@defvar pinebook-pro-image-type
Build an image that is targeting the Pinebook Pro machine. The MBR
image contains a single partition starting at a @code{9MiB} offset. The
-@code{u-boot-pinebook-pro-rk3399-bootloader} bootloader will be
+@code{u-boot-pinebook-pro-rk3399-bootloader} bootloader can be
installed in this gap.
@end defvar
@defvar rock64-image-type
Build an image that is targeting the Rock64 machine. The MBR image
contains a single partition starting at a @code{16MiB} offset. The
-@code{u-boot-rock64-rk3328-bootloader} bootloader will be installed in
+@code{u-boot-rock64-rk3328-bootloader} bootloader can be installed in
this gap.
@end defvar
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index f1352122a9..6b08e61492 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -100,6 +100,8 @@ (define-module (gnu bootloader)
bootloader-configuration-targets
bootloader-configuration-menu-entries
bootloader-configuration-default-entry
+ bootloader-configuration-efi-removable?
+ bootloader-configuration-32bit?
bootloader-configuration-timeout
bootloader-configuration-keyboard-layout
bootloader-configuration-theme
@@ -113,6 +115,9 @@ (define-module (gnu bootloader)
bootloader-configuration->gexp
bootloader-configurations->gexp
+ %efi-supported-systems
+ efi-arch
+ install-efi
efi-bootloader-chain))
@@ -502,6 +507,10 @@ (define-record-type* <bootloader-configuration>
(default '())) ;list of <menu-entry>
(default-entry bootloader-configuration-default-entry
(default 0)) ;integer
+ (efi-removable? bootloader-configuration-efi-removable?
+ (default #f)) ;bool
+ (32bit? bootloader-configuration-32bit?
+ (default #f)) ;bool
(timeout bootloader-configuration-timeout
(default 5)) ;seconds as integer
(keyboard-layout bootloader-configuration-keyboard-layout
@@ -635,9 +644,54 @@ (define (bootloader-configurations->gexp bootloader-configs . rest)
;;;
-;;; Bootloaders.
+;;; Bootloader installation to ESP.
;;;
+;; systems currently supported by efi-arch. should be used for packages relying
+;; on it.
+(define %efi-supported-systems
+ '("i686-linux" "x86_64-linux" "armhf-linux" "aarch64-linux" "riscv64-linux"))
+
+(define* (efi-arch #:key (target (or (%current-target-system) (%current-system)))
+ (32? #f))
+ "Returns the UEFI architecture name for the current target, in lowercase."
+ (cond ((target-x86-32? target) "ia32")
+ ((target-x86-64? target) (if 32? "ia32" "x64"))
+ ((target-arm32? target) "arm")
+ ((target-aarch64? target) (if 32? "arm" "aa64"))
+ ((target-riscv64? target) (if 32? "riscv32" "riscv64"))
+ (else (raise (formatted-message (G_ "no UEFI standard arch for ~a!")
+ target)))))
+
+(define (lazy-efibootmgr)
+ "Lazy-loaded efibootmgr package, in order to prevent circular refs."
+ (module-ref (resolve-interface '(gnu packages linux)) 'efibootmgr))
+
+(define (install-efi bootloader-config plan)
+ "Returns a gexp installing PLAN to the ESP, as denoted by the 'vendir target.
+PLAN is a gexp of a list of '(BUILDER DEST-BASENAME . LABEL) triples, that
+should be in boot order. If the user selects a removable bootloader, only the
+first entry in PLAN is used."
+ (match-record bootloader-config <bootloader-configuration>
+ (targets efi-removable? 32bit?)
+ (if efi-removable?
+ ;; Hard code the output location to a well-known path recognized by
+ ;; compliant firmware. See "3.5.1.1 Removable Media Boot Behaviour":
+ ;; http://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf
+ (with-targets targets
+ (('esp => (path :path))
+ #~(let ((boot #$(string-append path "/EFI/BOOT"))
+ (arch #$(string-upcase (efi-arch #:32? 32bit?)))
+ (builder (car (car #$plan))))
+ (mkdir-p boot)
+ ;; Only realize the first planspec.
+ (builder (string-append boot "/BOOT" arch ".EFI")))))
+ ;; Install normally if not configured as removable.
+ (with-targets targets
+ (('vendir => (vendir :path) (loader :devpath) (disk :device))
+ #~(install-efi #+(file-append (lazy-efibootmgr) "/sbin/efibootmgr")
+ #$vendir #$loader #$disk #$plan))))))
+
(define (efi-bootloader-profile packages files hooks)
"Creates a profile from the lists of PACKAGES and FILES from the store.
This profile is meant to be used by the bootloader-installer.
diff --git a/gnu/build/bootloader.scm b/gnu/build/bootloader.scm
index 3934e03aee..064466bd33 100644
--- a/gnu/build/bootloader.scm
+++ b/gnu/build/bootloader.scm
@@ -23,8 +23,6 @@
(define-module (gnu build bootloader)
#:autoload (guix build syscalls) (free-disk-space)
#:use-module (guix build utils)
- #:use-module (guix utils)
- #:use-module (ice-9 binary-ports)
#:use-module (guix diagnostics)
#:use-module (guix i18n)
#:use-module (ice-9 format)
@@ -40,7 +38,7 @@ (define-module (gnu build bootloader)
#:export (atomic-copy
in-temporary-directory
write-file-on-device
- install-efi-loader))
+ install-efi))
;;;
@@ -102,57 +100,62 @@ (define (efi-bootnums efibootmgr)
(bootnum (match:substring match 1)))
(cons (cons path bootnum) acc))))))
-(define* (install-efi grub grub-config esp #:key targets)
- "Write a self-contained GRUB EFI loader to the mounted ESP using
-GRUB-CONFIG.
-
-If TARGETS is set, use its car as the GRUB image format and its cdr as
-the output filename. Otherwise, use defaults for the host platform."
- (let* ((system %host-type)
- ;; Hard code the output location to a well-known path recognized by
- ;; compliant firmware. See "3.5.1.1 Removable Media Boot Behaviour":
- ;; http://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf
- (grub-mkstandalone (string-append grub "/bin/grub-mkstandalone"))
- (efi-directory (string-append esp "/EFI/BOOT"))
- ;; Map grub target names to boot file names.
- (efi-targets (or targets
- (cond ((string-prefix? "x86_64" system)
- '("x86_64-efi" . "BOOTX64.EFI"))
- ((string-prefix? "i686" system)
- '("i386-efi" . "BOOTIA32.EFI"))
- ((string-prefix? "armhf" system)
- '("arm-efi" . "BOOTARM.EFI"))
- ((string-prefix? "aarch64" system)
- '("arm64-efi" . "BOOTAA64.EFI"))))))
- ;; grub-mkstandalone requires a TMPDIR to prepare the firmware image.
- (setenv "TMPDIR" esp)
-
- (mkdir-p efi-directory)
- (invoke grub-mkstandalone "-O" (car efi-targets)
- "-o" (string-append efi-directory "/"
- (cdr efi-targets))
- ;; Graft the configuration file onto the image.
- (string-append "boot/grub/grub.cfg=" grub-config))))
-
-(define* (install-efi-loader grub-efi esp #:key targets)
- "Install in ESP directory the given GRUB-EFI bootloader. Configure it to
-load the Grub bootloader located in the 'Guix_image' root partition.
-
-If TARGETS is set, use its car as the GRUB image format and its cdr as
-the output filename. Otherwise, use defaults for the host platform."
- (let ((grub-config "grub.cfg"))
- (call-with-output-file grub-config
- (lambda (port)
- ;; Create a tiny configuration file telling the embedded grub where to
- ;; load the real thing. XXX This is quite fragile, and can prevent
- ;; the image from booting when there's more than one volume with this
- ;; label present. Reproducible almost-UUIDs could reduce the risk
- ;; (not eliminate it).
- (format port
- "insmod part_msdos~@
- insmod part_gpt~@
- search --set=root --label Guix_image~@
- configfile /boot/grub/grub.cfg~%")))
- (install-efi grub-efi grub-config esp #:targets targets)
- (delete-file grub-config)))
+(define (install-efi efibootmgr vendir loader* disk plan)
+ "See also install-efi in (gnu bootloader)."
+ (let* ((loader (string-map (match-lambda (#\/ #\\) (x x)) loader*))
+ (bootnums (filter (compose (cut string-prefix? loader <>) car)
+ (efi-bootnums efibootmgr)))
+ (plan-files (map cadr plan)))
+ (define (size file) (if (file-exists? file) (stat:size (stat file)) 0))
+ (define (vendirof file) (string-append vendir "/" file))
+ (define (loaderof file) (string-append loader "\\" file))
+ (define (delete-boot num file)
+ (invoke efibootmgr "--quiet" "--bootnum" num "--delete-bootnum")
+ (when (file-exists? file) (delete-file file)))
+ (mkdir-p vendir)
+ ;; Delete old entries first, to clear up space.
+ (for-each (lambda (spec) ; '(path . bootnum)
+ (let* ((s (substring (car spec) (string-length loader)))
+ (file (substring s (if (string-prefix? "\\" s) 1 0))))
+ (unless (member file plan-files)
+ (delete-boot (cdr spec) (vendirof file)))))
+ bootnums)
+ ;; New and updated entries.
+ (in-temporary-directory
+ (for-each
+ (lambda (spec)
+ (let* ((builder (car spec)) (name (cadr spec))
+ (dest (vendirof name)) (loadest (loaderof name))
+ (rest (reverse (cdr (member name plan-files)))))
+ ;; Build to a temporary file so we can check its size.
+ (builder name)
+ ;; Disk space is usually limited on ESPs.
+ ;; Try to clear space as we install new bootloaders.
+ (if (while (> (- (size name) (size dest)) (free-disk-space vendir))
+ (let ((del (find (compose file-exists? vendirof) rest)))
+ (if del (delete-file (vendirof del)) (break #t))))
+ (begin
+ (and=> (assoc-ref bootnums loadest) (cut delete-boot <> dest))
+ (warning (G_ "ESP too small for bootloader ~a!~%") name))
+ ;; The ESP is too small for atomic copy.
+ (begin
+ (copy-file name dest)
+ (unless (assoc loadest bootnums)
+ (invoke
+ efibootmgr "--quiet" "--create-only" "--label"
+ (cddr spec) "--disk" disk "--loader" loadest))))
+ (delete-file name)))
+ plan))
+ ;; Verify that at least the first entry was installed.
+ (unless (file-exists? (vendirof (cadr (car plan))))
+ ;; Extremely fatal error so we use leave instead of raise.
+ (leave (G_ "not enough space in ESP to install bootloader!
+ SYSTEM WILL NOT BOOT UNLESS THIS IS FIXED!~%")))
+ ;; Some UEFI systems will refuse to acknowledge the existence of boot
+ ;; entries unless they're in bootorder, so just shove everything in there.
+ (invoke
+ efibootmgr "--quiet" "--bootorder"
+ ;; Recall efi-bootnums to get a fresh list with new installs.
+ (let ((num (cute assoc-ref (efi-bootnums efibootmgr) <>))) ; cute is eager
+ (string-join (filter-map (compose num loaderof) plan-files) ",")))))
diff --git a/gnu/build/image.scm b/gnu/build/image.scm
index 6ca0a428e0..1b2d4da814 100644
--- a/gnu/build/image.scm
+++ b/gnu/build/image.scm
@@ -8,6 +8,7 @@
;;; Copyright © 2022 Pavel Shlyak <p.shlyak@pantherx.org>
;;; Copyright © 2022 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -28,6 +29,7 @@ (define-module (gnu build image)
#:use-module (guix build store-copy)
#:use-module (guix build syscalls)
#:use-module (guix build utils)
+ #:use-module (guix deprecation)
#:use-module (guix store database)
#:use-module (guix utils)
#:use-module (gnu build bootloader)
@@ -181,23 +183,10 @@ (define* (register-closure prefix closure
#:prefix prefix
#:registration-time %epoch)))))
-(define* (initialize-efi-partition root
- #:key
- grub-efi
- #:allow-other-keys)
- "Install in ROOT directory, an EFI loader using GRUB-EFI."
- (install-efi-loader grub-efi root))
-
-(define* (initialize-efi32-partition root
- #:key
- grub-efi32
- #:allow-other-keys)
- "Install in ROOT directory, an EFI 32bit loader using GRUB-EFI32."
- (install-efi-loader grub-efi32 root
- #:targets (cond ((target-x86?)
- '("i386-efi" . "BOOTIA32.EFI"))
- ((target-arm?)
- '("arm-efi" . "BOOTARM.EFI")))))
+(define (initialize-efi-partition root . rest)
+ (mkdir-p (string-append root "/EFI")))
+
+(define-deprecated/alias initialize-efi32-partition initialize-efi-partition)
(define* (initialize-root-partition root
#:key
diff --git a/gnu/image.scm b/gnu/image.scm
index 7fb06dec10..c6cc264147 100644
--- a/gnu/image.scm
+++ b/gnu/image.scm
@@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2020, 2022 Mathieu Othacehe <othacehe@gnu.org>
;;; Copyright © 2023 Oleg Pykhalov <go.wigust@gmail.com>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -35,6 +36,7 @@ (define-module (gnu image)
partition-label
partition-uuid
partition-flags
+ partition-target
partition-initializer
image
@@ -131,6 +133,8 @@ (define-record-type* <partition> partition make-partition
(flags partition-flags
(default '()) ;list of symbols
(sanitize validate-partition-flags))
+ (target partition-target ; bootloader target type: symbol | #f
+ (default #f))
(initializer partition-initializer
(default #false))) ;gexp | #false
diff --git a/gnu/system/image.scm b/gnu/system/image.scm
index b0c96c60f0..8ac91800ad 100644
--- a/gnu/system/image.scm
+++ b/gnu/system/image.scm
@@ -6,6 +6,7 @@
;;; Copyright © 2022 Alex Griffin <a@ajgrf.com>
;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
;;; Copyright © 2023 Oleg Pykhalov <go.wigust@gmail.com>
+;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;;
;;; This file is part of GNU Gu
This message was truncated. Download the full message here.
H
H
Herman Rimm wrote on 3 Oct 22:32 +0200
[PATCH] Preparation for bootloader rewrite.
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
4fnudiucjxequd3m4ayy7drqsgjokybfvsu6l2tbssurhlr5wd@odqr53qw5qqz
Hi Lilah,

I wrote a series of annotated Guile code snippets, regarding an
alternative implementation of bootloader-target, and example user
configuration (with tftp/NFS). See below, and please let me know what
you think.

Cheers,
Herman

;; In (gnu bootloader grub):
(define (grub-efi-default-targets esp)
(tree->target ; like arborify
(bootloader-target
(type 'esp)
(path esp)
(targets ; counterpart of offset
(list (bootloader-target
(type 'vendir)
(path "EFI/Guix"))
(bootloader-target
(type 'install)
(path "grub")))))))

;; This is the same as (grub-efi-default-targets "boot"). It could be
;; exported standalone, instead of using bootloader default-targets.
(define %grub-efi-default-targets
'((esp . "/boot")
(install . "/boot/EFI/Guix")
(vendir . "/boot/grub")))

;; A simple consequence of this change is that this:
(with-targets %grub-efi-default-targets
(('install => (path :path))
...))
;; becomes:
(let ((install-path (assoc-ref %grub-efi-default-targets 'install)))
...)

;; But e.g. device is provided separately (or derived from path):
(with-targets %grub-efi-default-targets
(('esp => (device :device))
...))
;; becomes:
(let* ((path (assoc-ref %grub-efi-default-targets 'esp))
;; A single root-device is provided in addition to targets.
(device (root-device->block-device root-device path)))
...)

;; This procedure is in (gnu bootloader). Something like:
(define (root-device->block-device device path)
(match device
((? block-device?) device) ; string with /dev/ prefix
((? uuid?) (find-partition-for-uuid device))
((? string?) (find-partition-for-label device))
;; This might be necessary, but should not be relied on.
(_ (mount-source (find-mount path)))))

;; Example user configuration:
(define %grub-efi-bootloader
(bootloader-configuration
(bootloader grub-efi-bootloader)
;; This is for bootloader configuration (not installation), e.g.
;; GRUB search or install-efi disk argument.
(root-device "UUID, label, or block device.")
;; This is complementary to root-device. It will configure some
;; files to be fetched remotely instead of installed.
(tftp "Varies for UEFI/GRUB/U-Boot.")))

(operating-system
(bootloader (list %grub-efi-bootloader))
;; This is shared between bootloaders. Ideally, it does not affect
;; which files are installed or their contents, but only the location.
(bootloader-targets (grub-efi-default-targets "boot")))
L
L
Lilah Tascheter wrote on 4 Oct 07:07 +0200
(address . 73202@debbugs.gnu.org)(name . Herman Rimm)(address . herman@rimm.ee)
bf58219d6ebb940af92cbbc4f8a735b873a88964.camel@lunabee.space
hey herman!

Toggle quote (13 lines)
> ;; In (gnu bootloader grub):
> (define (grub-efi-default-targets esp)
>   (tree->target ; like arborify
>                 (bootloader-target
>                   (type 'esp)
>                   (path esp)
>                   (targets ; counterpart of offset
>                            (list (bootloader-target
>                                    (type 'vendir)
>                                    (path "EFI/Guix"))
>                                  (bootloader-target
>                                    (type 'install)
>                                    (path "grub")))))))
how would this handle root offsets, eg by guix system init? is
everything assumed to be offset from root? I'm also worried about
indentation growing too quickly. otherwise, though, it's definately an
improvement over offset!

Toggle quote (34 lines)
> ;; This is the same as (grub-efi-default-targets "boot").  It could
> be
> ;; exported standalone, instead of using bootloader default-targets.
> (define %grub-efi-default-targets
>   '((esp     . "/boot")
>     (install . "/boot/EFI/Guix")
>     (vendir  . "/boot/grub")))
>
> ;; A simple consequence of this change is that this:
> (with-targets %grub-efi-default-targets
>   (('install => (path :path))
>    ...))
> ;; becomes:
> (let ((install-path (assoc-ref %grub-efi-default-targets 'install)))
>   ...)
>
> ;; But e.g. device is provided separately (or derived from path):
> (with-targets %grub-efi-default-targets
>   (('esp => (device :device))
>    ...))
> ;; becomes:
> (let* ((path (assoc-ref %grub-efi-default-targets 'esp))
>        ;; A single root-device is provided in addition to targets.
>        (device (root-device->block-device root-device path)))
>   ...)
>
> ;; This procedure is in (gnu bootloader).  Something like:
> (define (root-device->block-device device path)
>   (match device
>     ((? block-device?) device) ; string with /dev/ prefix
>     ((? uuid?) (find-partition-for-uuid device))
>     ((? string?) (find-partition-for-label device))
>     ;; This might be necessary, but should not be relied on.
>     (_ (mount-source (find-mount path)))))
how are you replacing device-local paths? some bootloaders need that
information to access files before fully loading. also, if the path,
device, label, and uuid fields are combined, the guix system image
won't be able to get all the info it needs to the bootloader
installers. uuid or label needs to be there to identify the device on-
boot, but also path, device, and devpath are required to actually
install bootloader files.

also, one reason with-targets exists is as a safeguard for future
people writing bootloaders. guix system image tends to be overlooked,
so it performs checks to make sure the bootloader targets requested are
available during image generation.


Toggle quote (17 lines)
> ;; Example user configuration:
> (define %grub-efi-bootloader
>   (bootloader-configuration
>     (bootloader grub-efi-bootloader)
>     ;; This is for bootloader configuration (not installation), e.g.
>     ;; GRUB search or install-efi disk argument.
>     (root-device "UUID, label, or block device.")
>     ;; This is complementary to root-device.  It will configure some
>     ;; files to be fetched remotely instead of installed.
>     (tftp "Varies for UEFI/GRUB/U-Boot.")))
>
> (operating-system
>   (bootloader (list %grub-efi-bootloader))
>   ;; This is shared between bootloaders.  Ideally, it does not affect
>   ;; which files are installed or their contents, but only the
> location.
>   (bootloader-targets (grub-efi-default-targets "boot")))
I do really like the conceptual separation between configuration and
installation! though, users would now need to enter the root device
details three times, potentially in inconsistant formats.

- lilah
H
H
Herman Rimm wrote on 4 Oct 15:55 +0200
(address . 73202@debbugs.gnu.org)(name . Lilah Tascheter)(address . lilah@lunabee.space)
sgg7cef5h7fj7sl3ypvy3k77v6zoi2wsvn6zc2mloyvyntce5o@b3anleonz5hf
Hello,

On Fri, Oct 04, 2024 at 12:07:16AM -0500, Lilah Tascheter wrote:
Toggle quote (3 lines)
> > (define (grub-efi-default-targets esp)
> how would this handle root offsets, eg by guix system init? is
> everything assumed to be offset from root?
For every (key . value) in targets, prefix value with root-offset. Or
if the target tree is still available, extend it:

(bootloader-target
(type 'root)
(path root-offset)
(targets (list %target-tree)))

It works under the assumption that bootloader-target paths will not be
referenced in bootloader configuration files. When that does not hold,
e.g. in the (make-)grub.cfg procedure, then I think either the target
paths (or tree) need to be unprefixed (or unwrapped); or the root should
be offset implicitly, i.e. doing the installation in a chroot.

Toggle quote (1 lines)
> I'm also worried about indentation growing too quickly.
Do you have a use case in mind, with more than three levels of nesting?

Toggle quote (1 lines)
> otherwise, though, it's definately an improvement over offset!
Thanks. Using the assumption that Guix only works with UNIX file
systems and not DOS-derivatives or exotic data stores, it only allows
constructing a tree and not a forest or (cyclic) graph, respectively.

Toggle quote (2 lines)
> how are you replacing device-local paths? some bootloaders need that
> information to access files before fully loading.
I guess when device-local paths are required, a targets tree should be
provided and queried using the with-targets macro. They could also be
cast from target paths, with a warning.

Toggle quote (4 lines)
> also, if the path, device, label, and uuid fields are combined, the
> guix system image won't be able to get all the info it needs to the
> bootloader installers. uuid or label needs to be there to identify the
> device on-boot,
So I have tried combining the path field into the device field, but I'm
now in favor of using a target tree/paths field together with a combined
block device, file system label, or UUID field. Here the assumption is
that any of the aformentioned types can be derived from any other, e.g.
with find-partition-by-uuid and read-partition-label. If a bootloader
cannot use a provided type, or find other required types, it should
throw an error. If you have a use case where both a block device and a
(potentially unrelated) UUID are configured, please let me know.

Toggle quote (2 lines)
> but also path, device, and devpath are required to actually install
> bootloader files.
I think the device could be installation-agnostic and anything related
to installation could be a different bootloader, or a field like tftp.

Toggle quote (4 lines)
> also, one reason with-targets exists is as a safeguard for future
> people writing bootloaders. guix system image tends to be overlooked,
> so it performs checks to make sure the bootloader targets requested
> are available during image generation.
What do you think about having required types per bootloader, and tests
for trees generated from image partitions in (gnu tests image) instead?

That reminds me: I would like to add a supported file systems field to
the bootloader, so that if the file system found for root-device is not
supported, it throws a little error.

Toggle quote (9 lines)
> > (operating-system
> > � (bootloader (list %grub-efi-bootloader))
> > � ;; This is shared between bootloaders.� Ideally, it does not affect
> > � ;; which files are installed or their contents, but only the
> > location.
> > � (bootloader-targets (grub-efi-default-targets "boot")))
> I do really like the conceptual separation between configuration and
> installation! though, users would now need to enter the root device
> details three times, potentially in inconsistant formats.
Thanks, I think the two examples below could work pretty well.

Cheers,
Herman

(define %boot-fs
(file-system
(device (uuid "E6A5-FEBB" 'fat32))
(mount-point "/boot") ; Taken as ESP.
;; Cannot be used to configure e.g. GRUB netboot, but it would be
;; nice to assert (support? bootloader type) in fs->bootloader.
(type "vfat")))
(operating-system
(bootloader ;; Procedure defined in (gnu system file-systems).
(file-system->grub-efi-bootloader %boot-fs))
...)

;; bootloader->file-system would not work as well. An OS field (macro)
;; to define both simultaneously at a high level could be useful though.
(operating-system
(file-systems-with-bootloader
;; Irrelevant for file-systems.
(bootloader grub-efi-bootloader)
;; Relevant as a file-system and bootloader installation.
�� (boot-device "UUID, label, or block device.")
(mount-point "/boot")
�� (type "vfat")
;; Not relevant to bootloader. Default values given.
(root-file-system (mounted-root-fs)) ; Error if not found.
;; Cons the generated boot FS and mounted root FS to this.
(file-systems %base-file-systems))
...)
H
H
Herman Rimm wrote on 7 Oct 21:23 +0200
(address . 73202@debbugs.gnu.org)
3dfiwbdyv2ymwuaeovbhluxm2ozng3iafs73bdw3dsqtnjzjy3@t2qdnxln5n2p
Hello Ryan,

On Mon, Oct 07, 2024 at 12:59:16PM -0400, Ryan wrote:
Toggle quote (3 lines)
> Right now, I have Guix master branch checked out @7e63a35f, and am under the
> assumption that the order of patching should be as follows: 69343->73202
> ->72457. Is this correct?
Almost, v6 of 72457 additionally requires v2 of 70131.

Toggle quote (2 lines)
> I can apply 69343 cleanly, however trying to apply
> the latest patchsets for 73202 or 72457 fail immediately, complaining that
Yeah, applying 73202 after 69343 using 'mumi am' immediately returns:

Applying: gnu: bootloader: Install any bootloader to ESP.
error: patch failed: gnu/bootloader.scm:113
error: gnu/bootloader.scm: patch does not apply
error: patch failed: gnu/build/bootloader.scm:23
error: gnu/build/bootloader.scm: patch does not apply
Patch failed at 0001 gnu: bootloader: Install any bootloader to ESP.

Very strange because this is not [PATCH v3 01/14], but [PATCH v3 12/14].
Manually downloading the patches from [1] and applying them seems to
work, until again [PATCH v3 12/14]. Looking closer at the download of
it (34), it seems to actually be [PATCH v3 14/14]... Besides that, your
message here does not appear on [1], or [2] for October 07. Do you know
why that is?

But anyway, Lilah also had trouble applying v6 of 72457. v7 of 72457
will be independent of 70131, and hopefully possible to apply. For now,
you can get patches similar to those in 70131, 69343, 73202, 72457, and
68524 (UKI bootloader) from my git repository, by running:

git checkout 7e63a35f
git fetch herman
git cherry-pick herman/lint-order..herman/uki-efi-bootloader-stable

Cheers,
Herman

R
(address . 73202@debbugs.gnu.org)
D4PQFMVBOY9A.242RIPH57D7GV@rschanz.org
Hi all, question about this entire patchset. I would like to do some testing
and play around with this myself, but I cannot for the life of me figure out
how it's supposed to be patched on top of the main tree, if someone could
clarify.

Right now, I have Guix master branch checked out @7e63a35f, and am under the
assumption that the order of patching should be as follows: 69343->73202
->72457. Is this correct? I can apply 69343 cleanly, however trying to apply
the latest patchsets for 73202 or 72457 fail immediately, complaining that
either I cannot build fake ancestors (attempting a 3-way merge) or that various
files do not match the index. I'm assuming I am missing some more patchsets
somewhere, but am unsure which are dependent on one another.

Hoping for some clarification so I can get my local tree all patched and begin
some testing (nothing too special, just want to set up UKIs on x86_64 but it
could be some insight nonetheless!)

Thanks!

---
Best,
Ryan S
R
(address . 73202@debbugs.gnu.org)
D4QI1I2N5HOS.26ALTDNH2YQZ8@rschanz.org
Hi Herman,

Toggle quote (8 lines)
> On Mon, Oct 07, 2024 at 09:23:14PM +0200, Herman wrote:
> Very strange because this is not [PATCH v3 01/14], but [PATCH v3 12/14].
> Manually downloading the patches from [1] and applying them seems to
> work, until again [PATCH v3 12/14]. Looking closer at the download of
> it (34), it seems to actually be [PATCH v3 14/14]... Besides that, your
> message here does not appear on [1], or [2] for October 07. Do you know
> why that is?

Very odd, do you think this is a bug in mumi of some kind? I'm new to email
based git workflows, so I've been leaning a mumi for a lot of my setup. Didn't
even think to look if it was trying to apply patches in the correct order, I
just assumed it was and I was doing something wrong.

To your second point, I have the same question. My current theory is that I am
new enough to the mailing lists that I have to go through some sort of approval
process before my emails appear in the actual list and subsequent mumi site,
but I have no proof of this, other than my posts historically taking many hours
to actually appear. Maybe I am doing something wrong?

Toggle quote (10 lines)
> But anyway, Lilah also had trouble applying v6 of 72457. v7 of 72457
> will be independent of 70131, and hopefully possible to apply. For now,
> you can get patches similar to those in 70131, 69343, 73202, 72457, and
> 68524 (UKI bootloader) from my git repository, by running:
>
> git checkout 7e63a35f
> git remote add herman https://codeberg.org/herman_rimm/guix.git
> git fetch herman
> git cherry-pick herman/lint-order..herman/uki-efi-bootloader-stable

Thanks for linking your tree (and adding the helpful instructions!) Glad to
report I cherry-picked the commits without any issues. I'll continue working
on my changes I am making to my system (that integrates these changes) and
report on the proper issues if I run into anything!

---
Best,
Ryan S
L
L
Lilah Tascheter wrote on 8 Oct 19:23 +0200
(address . 73202@debbugs.gnu.org)
41288336fe2cfc4b311b16c704a735c27e776d79.camel@lunabee.space
ugh forgot to send this to the mailing list, so resending:

Toggle quote (2 lines)
> Very odd, do you think this is a bug in mumi of some kind?

yep! I tried to message guix-devel about it but nobody responded. no
clue where to report mumi bugs. a control message I sent caused mumi's
message download links to be offset one back, resulting in a request to
download any email (both in the cli and the web ui) to return the
previous email in order.

it sucks.
L
L
Lilah Tascheter wrote on 8 Oct 20:05 +0200
(address . 73202@debbugs.gnu.org)(name . Herman Rimm)(address . herman@rimm.ee)
3586f7df3cbecf867bc82ac21c46bd067616d3f0.camel@lunabee.space
hi!!

Toggle quote (3 lines)
> > I'm also worried about indentation growing too quickly.
> Do you have a use case in mind, with more than three levels of
> nesting?
yeah good point :p

Toggle quote (13 lines)
> > also, if the path, device, label, and uuid fields are combined, the
> > guix system image won't be able to get all the info it needs to the
> > bootloader installers. uuid or label needs to be there to identify
> > the device on-boot,
> So I have tried combining the path field into the device field, but
> I'mnow in favor of using a target tree/paths field together with a
> combined block device, file system label, or UUID field.  Here the
> assumption is that any of the aformentioned types can be derived from
> any other, e.g. with find-partition-by-uuid and read-partition-
> label.  If a bootloader cannot use a provided type, or find other
> required types, it should throw an error.  If you have a use case
> where both a block device and a (potentially unrelated) UUID are
> configured, please let me know.
alright, that sounds great! would work for image gen, and can't think
of a reason why distinct uuids and devices would be supplied.

Toggle quote (17 lines)
>
> > but also path, device, and devpath are required to actually install
> > bootloader files.
> I think the device could be installation-agnostic and anything
> related
> to installation could be a different bootloader, or a field like
> tftp.

> > also, one reason with-targets exists is as a safeguard for future
> > people writing bootloaders. guix system image tends to be
> > overlooked,
> > so it performs checks to make sure the bootloader targets requested
> > are available during image generation.
> What do you think about having required types per bootloader, and
> tests
> for trees generated from image partitions in (gnu tests image)
> instead?
oh yeah that's a way better idea! offloads the test work from runtime
to, well, testing.


Toggle quote (3 lines)
> That reminds me: I would like to add a supported file systems field
> to the bootloader, so that if the file system found for root-device
> is not supported, it throws a little error.
sounds good, make sure the field supports specifying that all
filesystems are supported though (mostly just because of bootloaders
that install a kernel directly, like uki-efi).

Toggle quote (29 lines)
> (define %boot-fs
>   (file-system
>     (device (uuid "E6A5-FEBB" 'fat32))
>     (mount-point "/boot") ; Taken as ESP.
>     ;; Cannot be used to configure e.g. GRUB netboot, but it would be
>     ;; nice to assert (support? bootloader type) in fs->bootloader.
>     (type "vfat")))
> (operating-system
>   (bootloader ;; Procedure defined in (gnu system file-systems).
>               (file-system->grub-efi-bootloader %boot-fs))
>   ...)
>
> ;; bootloader->file-system would not work as well.  An OS field
> (macro)
> ;; to define both simultaneously at a high level could be useful
> though.
> (operating-system
>   (file-systems-with-bootloader
>     ;; Irrelevant for file-systems.
>     (bootloader grub-efi-bootloader)
>     ;; Relevant as a file-system and bootloader installation.
>     (boot-device "UUID, label, or block device.")
>     (mount-point "/boot")
>     (type "vfat")
>     ;; Not relevant to bootloader.  Default values given.
>     (root-file-system (mounted-root-fs)) ; Error if not found.
>     ;; Cons the generated boot FS and mounted root FS to this.
>     (file-systems %base-file-systems))
>   ...)
so, the benefit here is that bootloader builds would be deterministic
from the bootloader-configuration, right? I feel like a new top-level
macro, that requires specific fields for each possible device type is
unwieldly. it's also potentially important to be able to install
multiple distinct bootloaders with distinct configurations, for eg
u-boot->uefi chainloading or raid arrays. how about something like the
following:

(operating-system
(bootloader (list (grub-efi-bootloader
;; ... remove the bootloader-configuration record
;; entirely, and have each bootloader take their
;; own config. apart from targets and
;; menu-entries (which we can split off), there
;; aren't really any shared config opts anyway.
;; assoc-fs assocs a path with a file-system type
;; from the operating-system record (delay
;; or thunk the bootloader field so that images
;; can override file-systems?)
(root (assoc-fs file-systems "/")))))
;; have your original targets system in place
(bootloader-targets ...)
;; non-grub replacement for menu-entries, potentially with a
;; %base-boot-options thing for the autogenerated ones per
;; guix system generation?
(boot-options ...))

with a field sanitizer to make singular entries into lists, to simplify
single-bootloader use. devpaths would then be able to be generated by
the bootloader using the configuration target information.

honestly, then maybe just specify a target field (taking a symbol) in
the file-system record, and have assoc-fs take either a target symbol
or mount path. have bootloader-targets be generated from the file-
systems, with the bootloader-targets field just specifying non-
filesystem block devices.

I think parts of that may be similar to what you were originally
intending? I'm sorry, if so.

- lilah
?
Your comment

Commenting via the web interface is currently disabled.

To comment on this conversation send an email to 73202@debbugs.gnu.org

To respond to this issue using the mumi CLI, first switch to it
mumi current 73202
Then, you may apply the latest patchset in this issue (with sign off)
mumi am -- -s
Or, compose a reply to this issue
mumi compose
Or, send patches to this issue
mumi send-email *.patch