@@ -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.
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(-)