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
This commit is contained in:
Lilah Tascheter 2024-08-06 19:11:17 -05:00 committed by Ryan Schanzenbacher
parent b52e2a33f8
commit 35ac030f49
Signed by: ryan77627
GPG key ID: 81B0E222A3E2308E

View file

@ -3,6 +3,7 @@
;;; Copyright © 2019 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2019 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2022 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org> ;;; Copyright © 2022 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
;;; Copyright © 2022 Timothy Sample <samplet@ngyro.com> ;;; Copyright © 2022 Timothy Sample <samplet@ngyro.com>
;;; Copyright © 2024 Lilah Tascheter <lilah@lunabee.space>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
;;; ;;;
@ -20,13 +21,25 @@
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (gnu build bootloader) (define-module (gnu build bootloader)
#:autoload (guix build syscalls) (free-disk-space)
#:use-module (guix build utils) #:use-module (guix build utils)
#:use-module (guix utils) #:use-module (guix utils)
#:use-module (ice-9 binary-ports) #:use-module (ice-9 binary-ports)
#:use-module (guix diagnostics)
#:use-module (guix i18n)
#:use-module (ice-9 format) #: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 ports)
#:use-module (rnrs io simple) #: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)) install-efi-loader))
@ -34,6 +47,21 @@ (define-module (gnu build bootloader)
;;; Writing utils. ;;; 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) (define (write-file-on-device file size device offset)
"Write SIZE bytes from FILE to DEVICE starting at OFFSET." "Write SIZE bytes from FILE to DEVICE starting at OFFSET."
(call-with-input-file file (call-with-input-file file
@ -56,6 +84,24 @@ (define (write-file-on-device file size device offset)
;;; EFI bootloader. ;;; 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) (define* (install-efi grub grub-config esp #:key targets)
"Write a self-contained GRUB EFI loader to the mounted ESP using "Write a self-contained GRUB EFI loader to the mounted ESP using
GRUB-CONFIG. GRUB-CONFIG.