From 35ac030f49a8ec2674f5aa1411e67338928b776b Mon Sep 17 00:00:00 2001 From: Lilah Tascheter Date: Tue, 6 Aug 2024 19:11:17 -0500 Subject: [PATCH] gnu: build: bootloader: Add efi-bootnums procedure. * 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(-) 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 ;;; Copyright © 2022 Denis 'GNUtoo' Carikli ;;; Copyright © 2022 Timothy Sample +;;; Copyright © 2024 Lilah Tascheter ;;; ;;; This file is part of GNU Guix. ;;; @@ -20,13 +21,25 @@ ;;; along with GNU Guix. If not, see . (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.