unofficial mirror of guix-patches@gnu.org 
 help / color / mirror / code / Atom feed
From: Stefan <stefan-guix@vodafonemail.de>
To: Danny Milosavljevic <dannym@scratchpost.org>
Cc: 41066@debbugs.gnu.org
Subject: [bug#41066] [PATCH] gnu: bootloader: Support for chain loading.
Date: Sun, 4 Oct 2020 18:31:22 +0200	[thread overview]
Message-ID: <023CBBED-35CD-4AD3-97C4-0DE0B7623B9A@vodafonemail.de> (raw)
In-Reply-To: <3197004D-0131-4781-99FD-60EBE434E794@vodafonemail.de>

* gnu/bootloader.scm (bootloader-profile): New internal function to build a
profile from packages and files with a collection of contents to install.
(bootloader-chain): New function to chain a bootloader with contents of
additional bootloader or other packages and additional files like configuration
files or device-trees.

This allows to chain GRUB with U-Boot, device-tree-files, plain configuration
files, etc. mainly for single-board-computers like this:

(operating-system
  (bootloader
    (bootloader-configurationa
      (bootloader
        (bootloader-chain grub-efi-netboot-bootloader
                          (list u-boot-my-scb
                                firmware)
                          '("libexec/u-boot.bin"
                            "firmware/")
                          (list (plain-file "config.txt"
                                            "kernel=u-boot.bin"))
                          #:installer (install-grub-efi-netboot "efi/boot"))
        (target "/boot"))))
  …)
---
 gnu/bootloader.scm | 143 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 142 insertions(+), 1 deletion(-)

diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index 2eebb8e9d9..e9d80bf45a 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -22,6 +22,8 @@
 
 (define-module (gnu bootloader)
   #:use-module (guix discovery)
+  #:use-module (guix gexp)
+  #:use-module (guix profiles)
   #:use-module (guix records)
   #:use-module (guix ui)
   #:use-module (srfi srfi-1)
@@ -66,7 +68,9 @@
             bootloader-configuration-additional-configuration
 
             %bootloaders
-            lookup-bootloader-by-name))
+            lookup-bootloader-by-name
+
+            bootloader-chain))
 
 ^L
 ;;;
@@ -227,3 +231,140 @@ record."
               (eq? name (bootloader-name bootloader)))
             (force %bootloaders))
       (leave (G_ "~a: no such bootloader~%") name)))
+
+(define (bootloader-profile packages package-contents files)
+  "Creates a profile with PACKAGES and additional FILES.  The new profile will
+contain a directory collection/ with links to selected PACKAGE-CONTENTS and
+FILES.  This collection is meant to be used by the bootloader installer.
+
+PACKAGE-CONTENTS is a list of file or directory names relative to the PACKAGES,
+which will be symlinked into the collection/ directory.  If a directory name
+ends with '/', then the directory content instead of the directory itself will
+be symlinked into the collection/ directory.
+
+FILES is a list of file like objects produced by functions like plain-file,
+local-file, etc., which will be symlinked into the collection/ directory, too."
+  (define (bootloader-collection manifest)
+    (define build
+        (with-imported-modules '((guix build utils)
+                                 (ice-9 ftw)
+                                 (srfi srfi-1))
+          #~(begin
+            (use-modules ((guix build utils) #:select (mkdir-p))
+                         ((ice-9 ftw) #:select (scandir))
+                         ((srfi srfi-1) #:select (append-map remove)))
+            (define (symlink-to file directory transform-name)
+              "Creates a symlink with transformed name to FILE in DIRECTORY."
+              (when (file-exists? file)
+                    (symlink file
+                             (string-append
+                              directory "/"
+                              (transform-name (basename file))))))
+            (define (remove-hash basename)
+              "Returns the basename of a store entry without the hash."
+              ;; A plain-file inside the store has a name like
+              ;; gnu/store/9x6y7j75qy9z6iv21byrbyj4yy8hb490-config.txt.
+              ;; From its basename we drop the hash.
+              ;; Therefore we expects the first '-' at index 32.
+              ;; Otherwise the basename itself is returned.
+              (if (and (> (string-length basename) 33)
+                       (= (string-index basename #\- 0 33) 32))
+                  (substring basename 33)
+                  (basename)))
+            (define (directory-content directory)
+              "Creates a list of absolute path names inside DIRECTORY."
+              (map (lambda (name)
+                     (string-append directory name))
+                   (sort (or (scandir directory
+                                      (lambda (name)
+                                        (not (member name '("." "..")))))
+                             '())
+                         string<?)))
+            (define (select-names select names)
+              "Set SELECT to 'filter' or 'remove' names ending with '/'."
+              (select (lambda (name)
+                        (string-suffix? "/" name))
+                      names))
+            (define (filter-names-without-slash names)
+              (select-names remove names))
+            (define (filter-names-with-slash names)
+              (select-names filter names))
+            (let* ((collection (string-append #$output "/collection"))
+                   (packages '#$(map (lambda (entry)
+                                       (manifest-entry-item entry))
+                                     (manifest-entries manifest)))
+                   (contents (append-map
+                               (lambda (name)
+                                 (map (lambda (package)
+                                        (string-append package "/" name))
+                                      packages))
+                               '#$package-contents))
+                   (directories (filter-names-with-slash contents))
+                   (names-from-directories
+                    (append-map (lambda (directory)
+                                  (directory-content directory))
+                                directories))
+                   (names (append names-from-directories
+                                  (filter-names-without-slash contents))))
+              (mkdir-p collection)
+              (for-each (lambda (name)
+                          (symlink-to name collection identity))
+                        names)
+              (for-each (lambda (file)
+                          (symlink-to file collection remove-hash))
+                        '#$files))
+            #t)))
+
+    (gexp->derivation "bootloader-collection"
+                      build
+                      #:local-build? #t
+                      #:substitutable? #f
+                      #:properties
+                      `((type . profile-hook)
+                        (hook . bootloader-collection))))
+
+  (profile (content (packages->manifest packages))
+           (name "bootloader-profile")
+           (hooks (list bootloader-collection))
+           (locales? #f)
+           (allow-collisions? #f)
+           (relative-symlinks? #f)))
+
+(define* (bootloader-chain final-bootloader
+                           bootloader-packages
+                           bootloader-package-contents
+                           #:optional (files '())
+                           #:key installer)
+  "Defines a bootloader chain with the FINAL-BOOTLOADER as the final bootloader
+and certain directories and files given in the BOOTLOADER-PACKAGE-CONTENTS list
+relative to list of BOOTLOADER-PACKAGES and additional FILES.
+
+Along with the installation of the FINAL-BOOTLOADER these additional FILES and
+BOOTLOADER-PACKAGE-CONTENTS will be copied into the bootloader target directory.
+
+If a directory name in BOOTLOADER-PACKAGE-CONTENTS ends with '/', then the
+directory content instead of the directory itself will be copied.
+
+FILES is a list of file like objects produced by functions like plain-file,
+local-file, etc.
+
+If the INSTALLER argument is used, then this will be used as the bootloader
+installer.  Otherwise the intaller of the FINAL-BOOTLOADER will be used."
+  (let* ((final-installer (or installer
+                              (bootloader-installer final-bootloader)))
+         (profile (bootloader-profile
+                   (cons (bootloader-package final-bootloader)
+                         bootloader-packages)
+                   bootloader-package-contents
+                   files)))
+    (bootloader
+     (inherit final-bootloader)
+     (package profile)
+     (installer
+      #~(lambda (bootloader target mount-point)
+          (#$final-installer bootloader target mount-point)
+          (copy-recursively
+           (string-append bootloader "/collection")
+           (string-append mount-point target)
+           #:follow-symlinks? #t
+           #:log (%make-void-port "w")))))))
-- 
2.26.0





  reply	other threads:[~2020-10-04 16:32 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-03 23:34 [bug#41066] [PATCH] gnu: grub: Support for chain loading Stefan
2020-05-24 11:13 ` Danny Milosavljevic
2020-05-24 13:21   ` Stefan
2020-10-04 16:31     ` Stefan [this message]
2020-10-10  9:31       ` [bug#41066] [PATCH] gnu: bootloader: " Stefan
2020-10-18 11:20         ` Stefan
2020-10-18 11:21           ` Stefan
2020-10-22 17:46             ` Danny Milosavljevic
2020-10-23 12:48               ` Ludovic Courtès
2020-10-24  1:30                 ` Danny Milosavljevic
2020-10-24 16:22                   ` Ludovic Courtès
2020-10-25  0:33                     ` Danny Milosavljevic
2020-10-25 16:58                       ` Stefan
2020-10-25 16:59                         ` Stefan
2020-11-02 15:42                           ` Danny Milosavljevic
2020-11-02 16:21                             ` Mathieu Othacehe
2020-11-03  9:07                               ` Ludovic Courtès
2020-11-03  9:32                                 ` Mathieu Othacehe
2020-11-07 21:14                                   ` Stefan
2020-11-07 21:15                                     ` Stefan
2020-10-26 10:37                       ` Ludovic Courtès
2020-11-16  9:33             ` bug#41066: " Danny Milosavljevic
2020-11-17 14:26               ` [bug#41066] " Stefan
2020-11-17 15:47                 ` Danny Milosavljevic
2020-11-17 16:17                   ` Danny Milosavljevic
2020-11-17 20:27                   ` Stefan
2020-11-18 18:05                     ` Danny Milosavljevic
2020-11-18 18:20                       ` Stefan
2020-11-28 22:14                         ` [bug#41066] [PATCH] gnu: bootloader: Improve support " Stefan
2020-12-12 17:14                           ` Stefan
2020-12-13 14:42                             ` Danny Milosavljevic
2020-12-13 17:24                               ` Stefan
2020-12-13 19:28                                 ` Stefan
2020-12-28 19:02                                   ` Stefan
2021-03-27 16:48                                     ` bug#41066: " Stefan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://guix.gnu.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=023CBBED-35CD-4AD3-97C4-0DE0B7623B9A@vodafonemail.de \
    --to=stefan-guix@vodafonemail.de \
    --cc=41066@debbugs.gnu.org \
    --cc=dannym@scratchpost.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

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

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