Subject: Re: bug#40997: [raid] The bootloader can only be installed to a single drive

From: Maxim Cournoyer <[email-masked]>
Date: Sun, 08 Aug 2021 00:25:01 -0400

Hello,

[email-masked] writes:

> Using Guix System, the bootloader declaration doesn't currently seem to
> support being installed to multiple drives:
>
> (bootloader (bootloader-configuration
>                  (bootloader grub-bootloader)
>                  (target "/dev/sda")
>                  (terminal-outputs '(console))))
>  --8<---------------cut here---------------end--------------->8---
>
> I suggest to change it so that target can be passed a list like
>
> (bootloader (bootloader-configuration
>                  (bootloader grub-bootloader)
>                  (target '("/dev/sda" "/dev/sdb"))
>                  (terminal-outputs '(console))))
>  --8<---------------cut here---------------end--------------->8---
>
> This is useful when trying to boot a degraded RAID array.

The following patches do exactly this (target becomes the plural
targets).  I tested it on my system, disconnecting the first drive of my
RAID1 array, and could at least boot to GRUB fine (although full boot
failed due to https://issues.guix.gnu.org/40999).

Booting a VM using an image generated from the bare-bones.tmpl template
also worked fine.

>From a14403fdabbe987cb94a75977e7e62a0e0954e6b Mon Sep 17 00:00:00 2001
From: Maxim Cournoyer <[email-masked]>
Date: Fri, 6 Aug 2021 16:33:02 -0400
Subject: [PATCH 1/2] gnu: bootloader: Support multiple targets.

Fixes <https://issues.guix.gnu.org/40997>.

* gnu/bootloader.scm (<bootloader-configuration>): New 'targets' field.
(%bootloader-configuration-target): New procedure.
(bootloader-configuration-target): Add deprecation warning.
(bootloader-configuration-targets): New procedure.
* guix/scripts/system.scm (install): Access targets via
bootloader-configuration-targets.
(perform-action)[bootloader-target]: Remove unused argument and update doc.
Access targets via bootloader-configuration-targets and fix indentation.
(process-action): Access targets via bootloader-configuration-targets.
Do not provide the unused BOOTLOADER-TARGET argument when applying
`perform-action'.
* guix/scripts/system/reconfigure.scm (install-bootloader-program): Rename
DEVICE argument to DEVICES.  Adjust doc and comment.  Apply `installer' and
`disk-installer' for every DEVICES.
(install-bootloader): Access targets via bootloader-configuration-targets and
rename variable from DEVICE to DEVICES.
* gnu/tests/install.scm: Adjust accordingly.
* tests/guix-system.sh: Likewise.
* gnu/tests/reconfigure.scm (run-install-bootloader-test): Adjust the DEVICES
argument so that it is a list.
* doc/guix.texi: Update doc.
---
 doc/guix.texi                       | 91 +++++++++++++++--------------
 gnu/bootloader.scm                  | 22 ++++++-
 gnu/tests/install.scm               | 26 ++++-----
 gnu/tests/reconfigure.scm           |  2 +-
 guix/scripts/system.scm             | 20 +++----
 guix/scripts/system/reconfigure.scm | 22 ++++---
 tests/guix-system.sh                |  6 +-
 7 files changed, 108 insertions(+), 81 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index a826171f34..a9309d4d0c 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -2567,14 +2567,15 @@ in particular:
 
 @itemize
 @item
-Make sure the @code{bootloader-configuration} form refers to the target
-you want to install GRUB on.  It should mention @code{grub-bootloader} if
-you are installing GRUB in the legacy way, or @code{grub-efi-bootloader}
-for newer UEFI systems.  For legacy systems, the @code{target} field
-names a device, like @code{/dev/sda}; for UEFI systems it names a path
-to a mounted EFI partition, like @code{/boot/efi}; do make sure the path is
-currently mounted and a @code{file-system} entry is specified in your
-configuration.
+Make sure the @code{bootloader-configuration} form refers to the targets
+you want to install GRUB on.  It should mention @code{grub-bootloader}
+if you are installing GRUB in the legacy way, or
+@code{grub-efi-bootloader} for newer UEFI systems.  For legacy systems,
+the @code{targets} field contain the names of the devices, like
+@code{(list "/dev/sda")}; for UEFI systems it names the paths to mounted
+EFI partitions, like @code{(list "/boot/efi")}; do make sure the paths
+are currently mounted and a @code{file-system} entry is specified in
+your configuration.
 
 @item
 Be sure that your file system labels match the value of their respective
@@ -13478,7 +13479,7 @@ the @code{bootloader} field should contain something along these lines:
 @lisp
 (bootloader-configuration
   (bootloader grub-efi-bootloader)
-  (target "/boot/efi"))
+  (targets '("/boot/efi")))
 @end lisp
 
 @xref{Bootloader Configuration}, for more information on the available
@@ -14693,7 +14694,7 @@ configuration would look like:
   (keyboard-layout (keyboard-layout "tr"))  ;for the console
   (bootloader (bootloader-configuration
                 (bootloader grub-efi-bootloader)
-                (target "/boot/efi")
+                (targets '("/boot/efi"))
                 (keyboard-layout keyboard-layout))) ;for GRUB
   (services (cons (set-xorg-configuration
                     (xorg-configuration             ;for Xorg
@@ -33098,11 +33099,11 @@ in ``legacy'' BIOS mode.
 through TFTP@.  In combination with an NFS root file system this allows you to
 build a diskless Guix system.
 
-The installation of the @code{grub-efi-netboot-bootloader} generates the content
-of the TFTP root directory at @code{target}
-(@pxref{Bootloader Configuration, @code{target}}), to be served by a TFTP server.
- You may want to mount your TFTP server directory onto @code{target} to move the
-required files to the TFTP server automatically.
+The installation of the @code{grub-efi-netboot-bootloader} generates the
+content of the TFTP root directory at @code{targets} (@pxref{Bootloader
+Configuration, @code{targets}}), to be served by a TFTP server.  You may
+want to mount your TFTP server directories onto the @code{targets} to
+move the required files to the TFTP server automatically.
 
 If you plan to use an NFS root file system as well (actually if you mount the
 store from an NFS share), then the TFTP server needs to serve the file
@@ -33113,22 +33114,25 @@ files from the store will be accessed by GRUB through TFTP with their normal
 store path, for example as
 @file{tftp://tftp-server/gnu/store/…-initrd/initrd.cpio.gz}.
 
-Two symlinks are created to make this possible.  The first symlink is
-@code{target}@file{/efi/Guix/boot/grub/grub.cfg} pointing to
-@file{../../../boot/grub/grub.cfg},
-where @code{target} may be @file{/boot}.  In this case the link is not leaving
-the served TFTP root directory, but otherwise it does.  The second link is
-@code{target}@file{/gnu/store} and points to @file{../gnu/store}.  This link
-is leaving the served TFTP root directory.
-
-The assumption behind all this is that you have an NFS server exporting the root
-file system for your Guix system, and additionally a TFTP server exporting your
-@code{target} directory—usually @file{/boot}—from that same root file system for
-your Guix system.  In this constellation the symlinks will work.
-
-For other constellations you will have to program your own bootloader installer,
-which then takes care to make necessary files from the store accessible through
-TFTP, for example by copying them into the TFTP root directory at @code{target}.
+Two symlinks are created to make this possible.  For each target in the
+@code{targets} field, the first symlink is
+@samp{target}@file{/efi/Guix/boot/grub/grub.cfg} pointing to
+@file{../../../boot/grub/grub.cfg}, where @samp{target} may be
+@file{/boot}.  In this case the link is not leaving the served TFTP root
+directory, but otherwise it does.  The second link is
+@samp{target}@file{/gnu/store} and points to @file{../gnu/store}.  This
+link is leaving the served TFTP root directory.
+
+The assumption behind all this is that you have an NFS server exporting
+the root file system for your Guix system, and additionally a TFTP
+server exporting your @code{targets} directories—usually a single
+@file{/boot}—from that same root file system for your Guix system.  In
+this constellation the symlinks will work.
+
+For other constellations you will have to program your own bootloader
+installer, which then takes care to make necessary files from the store
+accessible through TFTP, for example by copying them into the TFTP root
+directory to your @code{targets}.
 
 It is important to note that symlinks pointing outside the TFTP root directory
 may need to be allowed in the configuration of your TFTP server.  Further the
@@ -33140,18 +33144,19 @@ NFS servers, you also need a properly configured DHCP server to make the booting
 over netboot possible.  For all this we can currently only recommend you to look
 for instructions about @acronym{PXE, Preboot eXecution Environment}.
 
-@item @code{target}
-This is a string denoting the target onto which to install the
+@item @code{targets}
+This is a list of strings denoting the targets onto which to install the
 bootloader.
 
-The interpretation depends on the bootloader in question.  For
-@code{grub-bootloader}, for example, it should be a device name understood by
-the bootloader @command{installer} command, such as @code{/dev/sda} or
-@code{(hd0)} (@pxref{Invoking grub-install,,, grub, GNU GRUB Manual}).  For
-@code{grub-efi-bootloader}, it should be the mount point of the EFI file
-system, usually @file{/boot/efi}.  For @code{grub-efi-netboot-bootloader},
-@code{target} should be the mount point corresponding to the TFTP root
-directory of your TFTP server.
+The interpretation of targets depends on the bootloader in question.
+For @code{grub-bootloader}, for example, they should be device names
+understood by the bootloader @command{installer} command, such as
+@code{/dev/sda} or @code{(hd0)} (@pxref{Invoking grub-install,,, grub,
+GNU GRUB Manual}).  For @code{grub-efi-bootloader}, they should be mount
+points of the EFI file system, usually @file{/boot/efi}.  For
+@code{grub-efi-netboot-bootloader}, @code{targets} should be the mount
+points corresponding to TFTP root directories served by your TFTP
+server.
 
 @item @code{menu-entries} (default: @code{()})
 A possibly empty list of @code{menu-entry} objects (see below), denoting
@@ -33567,7 +33572,7 @@ files, packages, and so on.  It also creates other essential files
 needed for the system to operate correctly---e.g., the @file{/etc},
 @file{/var}, and @file{/run} directories, and the @file{/bin/sh} file.
 
-This command also installs bootloader on the target specified in
+This command also installs bootloader on the targets specified in
 @file{my-os-config}, unless the @option{--no-bootloader} option was
 passed.
 
@@ -33963,7 +33968,7 @@ evaluates to.  As an example, @var{file} might contain a definition like this:
    (timezone "Etc/UTC")
    (bootloader (bootloader-configuration
                 (bootloader grub-bootloader)
-                (target "/dev/vda")
+                (targets '("/dev/vda"))
                 (terminal-outputs '(console))))
    (file-systems (cons (file-system
                         (mount-point "/")
diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm
index 6d7352ddd2..98807a4810 100644
--- a/gnu/bootloader.scm
+++ b/gnu/bootloader.scm
@@ -55,7 +55,8 @@
             bootloader-configuration
             bootloader-configuration?
             bootloader-configuration-bootloader
-            bootloader-configuration-target
+            bootloader-configuration-target ;deprecated
+            bootloader-configuration-targets
             bootloader-configuration-menu-entries
             bootloader-configuration-default-entry
             bootloader-configuration-timeout
@@ -183,7 +184,9 @@ record."
   bootloader-configuration make-bootloader-configuration
   bootloader-configuration?
   (bootloader         bootloader-configuration-bootloader) ;<bootloader>
-  (target             bootloader-configuration-target      ;string
+  (targets            %bootloader-configuration-targets    ;list of strings
+                      (default #f))
+  (target             %bootloader-configuration-target ;deprecated
                       (default #f))
   (menu-entries       bootloader-configuration-menu-entries ;list of <menu-entry>
                       (default '()))
@@ -204,6 +207,21 @@ record."
   (serial-speed       bootloader-configuration-serial-speed ;integer | #f
                       (default #f)))
 
+;;; Deprecated.
+(define (bootloader-configuration-target config)
+  (warning (G_ "the 'target' field is deprecated, please use 'targets' \
+instead~%"))
+  (%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 '().
+      (list #f)))
+
 
 ;;;
 ;;; Bootloaders.
diff --git a/gnu/tests/install.scm b/gnu/tests/install.scm
index 80604361e0..d7fafd210c 100644
--- a/gnu/tests/install.scm
+++ b/gnu/tests/install.scm
@@ -4,7 +4,7 @@
 ;;; Copyright © 2020 Mathieu Othacehe <[email-masked]>
 ;;; Copyright © 2020 Danny Milosavljevic <[email-masked]>
 ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <[email-masked]>
-;;; Copyright © 2020 Maxim Cournoyer <[email-masked]>
+;;; Copyright © 2020, 2021 Maxim Cournoyer <[email-masked]>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -97,7 +97,7 @@
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/vdb")))
+                 (targets (list "/dev/vdb"))))
     (kernel-arguments '("console=ttyS0"))
     (file-systems (cons (file-system
                           (device (file-system-label "my-root"))
@@ -135,7 +135,7 @@
 
     (bootloader (bootloader-configuration
                  (bootloader extlinux-bootloader-gpt)
-                 (target "/dev/vdb")))
+                 (targets (list "/dev/vdb"))))
     (kernel-arguments '("console=ttyS0"))
     (file-systems (cons (file-system
                           (device (file-system-label "my-root"))
@@ -418,7 +418,7 @@ per %test-installed-os, this test is expensive in terms of CPU and storage.")
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/vda")))
+                 (targets (list "/dev/vda"))))
     (kernel-arguments '("console=ttyS0"))
     (file-systems (cons (file-system
                           (device (file-system-label "my-root"))
@@ -549,7 +549,7 @@ partition.  In particular, home directories must be correctly created (see
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/vdb")))
+                 (targets (list "/dev/vdb"))))
     (kernel-arguments '("console=ttyS0"))
     (file-systems (cons* (file-system
                            (device (file-system-label "root-fs"))
@@ -626,7 +626,7 @@ where /gnu lives on a separate partition.")
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/vdb")))
+                 (targets (list "/dev/vdb"))))
     (kernel-arguments '("console=ttyS0"))
 
     ;; Add a kernel module for RAID-1 (aka. "mirror").
@@ -842,7 +842,7 @@ build (current-guix) and then store a couple of full system images.")
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/vdb")))
+                 (targets (list "/dev/vdb"))))
     (kernel-arguments '("console=ttyS0"))
 
     (mapped-devices (list (mapped-device
@@ -929,7 +929,7 @@ reboot\n")
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/vdb")))
+                 (targets (list "/dev/vdb"))))
 
     (mapped-devices (list (mapped-device
                            (source
@@ -1029,7 +1029,7 @@ store a couple of full system images.")
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/vdb")))
+                 (targets (list "/dev/vdb"))))
     (kernel-arguments '("console=ttyS0"))
     (file-systems (cons (file-system
                           (device (file-system-label "my-root"))
@@ -1103,7 +1103,7 @@ build (current-guix) and then store a couple of full system images.")
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/vdb")))
+                 (targets (list "/dev/vdb"))))
     (kernel-arguments '("console=ttyS0"))
 
     (file-systems (cons (file-system
@@ -1171,7 +1171,7 @@ RAID-0 (stripe) root partition.")
     (locale "en_US.UTF-8")
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/vdb")))
+                 (targets (list "/dev/vdb"))))
     (kernel-arguments '("console=ttyS0"))
     (file-systems (cons* (file-system
                            (device (file-system-label "btrfs-pool"))
@@ -1264,7 +1264,7 @@ build (current-guix) and then store a couple of full system images.")
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/vdb")))
+                 (targets (list "/dev/vdb"))))
     (kernel-arguments '("console=ttyS0"))
     (file-systems (cons (file-system
                           (device (file-system-label "my-root"))
@@ -1337,7 +1337,7 @@ build (current-guix) and then store a couple of full system images.")
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/vdb")))
+                 (targets (list "/dev/vdb"))))
     (kernel-arguments '("console=ttyS0"))
     (file-systems (cons (file-system
                           (device (file-system-label "my-root"))
diff --git a/gnu/tests/reconfigure.scm b/gnu/tests/reconfigure.scm
index 52beeef447..001b5d185a 100644
--- a/gnu/tests/reconfigure.scm
+++ b/gnu/tests/reconfigure.scm
@@ -261,7 +261,7 @@ bootloader's configuration file."
      ;; 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 "/")))))
+      (install-bootloader-program #f #f #f bootcfg bootcfg-file '(#f) "/")))))

 (define %test-switch-to-system
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index 40401d7e03..83bbefd3dc 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -253,7 +253,7 @@ the ownership of '~a' may be incorrect!~%")
                               #:target target)
           (return
            (info (G_ "bootloader successfully installed on '~a'~%")
-                 (bootloader-configuration-target bootloader))))))))
+                 (bootloader-configuration-targets bootloader))))))))
 
 
 ;;;
@@ -768,14 +768,13 @@ and TARGET arguments."
                          skip-safety-checks?
                          install-bootloader?
                          dry-run? derivations-only?
-                         use-substitutes? bootloader-target target
+                         use-substitutes? target
                          full-boot?
                          container-shared-network?
                          (mappings '())
                          (gc-root #f))
   "Perform ACTION for IMAGE.  INSTALL-BOOTLOADER? specifies whether to install
-bootloader; BOOTLOADER-TAGET is the target for the bootloader; TARGET is the
-target root directory.
+bootloader; TARGET is the target root directory.
 
 FULL-BOOT? is used for the 'vm' action; it determines whether to
 boot directly to the kernel or to the bootloader.  CONTAINER-SHARED-NETWORK?
@@ -856,13 +855,13 @@ static checks."
                                      #:target (or target "/"))
                  (return
                   (info (G_ "bootloader successfully installed on '~a'~%")
-                        (bootloader-configuration-target bootloader))))
+                        (bootloader-configuration-targets bootloader))))
                (with-shepherd-error-handling
-                 (upgrade-shepherd-services local-eval os)
-                 (return (format #t (G_ "\
+                (upgrade-shepherd-services local-eval os)
+                (return (format #t (G_ "\
 To complete the upgrade, run 'herd restart SERVICE' to stop,
 upgrade, and restart each service that was not automatically restarted.\n")))
-                 (return (format #t (G_ "\
+                (return (format #t (G_ "\
 Run 'herd status' to view the list of services on your system.\n"))))))
             ((init)
              (newline)
@@ -1218,9 +1217,9 @@ resulting from command-line parsing."
          (target-file (match args
                         ((first second) second)
                         (_ #f)))
-         (bootloader-target
+         (bootloader-targets
                       (and bootloader?
-                           (bootloader-configuration-target
+                           (bootloader-configuration-targets
                             (operating-system-bootloader os)))))
 
     (define (graph-backend)
@@ -1269,7 +1268,6 @@ resulting from command-line parsing."
                                                       opts)
                                #:install-bootloader? bootloader?
                                #:target target-file
-                               #:bootloader-target bootloader-target
                                #:gc-root (assoc-ref opts 'gc-root)))))
           #:target target
           #:system system)))
diff --git a/guix/scripts/system/reconfigure.scm b/guix/scripts/system/reconfigure.scm
index 49da6ecb16..bf23fb06af 100644
--- a/guix/scripts/system/reconfigure.scm
+++ b/guix/scripts/system/reconfigure.scm
@@ -207,10 +207,10 @@ services as defined by OS."
 
 (define (install-bootloader-program installer disk-installer
                                     bootloader-package bootcfg
-                                    bootcfg-file device target)
+                                    bootcfg-file devices target)
   "Return an executable store item that, upon being evaluated, will install
-BOOTCFG to BOOTCFG-FILE, a target file name, on DEVICE, a file system device,
-at TARGET, a mount point, and subsequently run INSTALLER from
+BOOTCFG to BOOTCFG-FILE, a target file name, on DEVICES, a list of file system
+devices, at TARGET, a mount point, and subsequently run INSTALLER from
 BOOTLOADER-PACKAGE."
   (program-file
    "install-bootloader.scm"
@@ -254,11 +254,17 @@ BOOTLOADER-PACKAGE."
                    ;; The bootloader might not support installation on a
                    ;; mounted directory using the BOOTLOADER-INSTALLER
                    ;; procedure. In that case, fallback to installing the
-                   ;; bootloader directly on DEVICE using the
+                   ;; bootloader directly on DEVICES using the
                    ;; BOOTLOADER-DISK-IMAGE-INSTALLER procedure.
                    (if #$installer
-                       (#$installer #$bootloader-package #$device #$target)
-                       (#$disk-installer #$bootloader-package 0 #$device)))
+                       (for-each (lambda (device)
+                                   (#$installer #$bootloader-package device
+                                                #$target))
+                                 '#$devices)
+                       (for-each (lambda (device)
+                                   (#$disk-installer #$bootloader-package
+                                                     0 device))
+                                 '#$devices)))
                  (lambda args
                    (delete-file new-gc-root)
                    (match args
@@ -284,7 +290,7 @@ additional configurations specified by MENU-ENTRIES can be selected."
          (disk-installer (and run-installer?
                               (bootloader-disk-image-installer bootloader)))
          (package (bootloader-package bootloader))
-         (device (bootloader-configuration-target configuration))
+         (devices (bootloader-configuration-targets configuration))
          (bootcfg-file (bootloader-configuration-file bootloader)))
     (eval #~(parameterize ((current-warning-port (%make-void-port "w")))
               (primitive-load #$(install-bootloader-program installer
@@ -292,7 +298,7 @@ additional configurations specified by MENU-ENTRIES can be selected."
                                                             package
                                                             bootcfg
                                                             bootcfg-file
-                                                            device
+                                                            devices
                                                             target))))))
 
 
diff --git a/tests/guix-system.sh b/tests/guix-system.sh
index 7e992e7bdb..6aab1f380a 100644
--- a/tests/guix-system.sh
+++ b/tests/guix-system.sh
@@ -115,7 +115,7 @@ cat > "$tmpfile" <<EOF
   (timezone "Europe/Paris")                           ; 6
   (locale "en_US.UTF-8")                              ; 7
 
-  (bootloader (GRUB-config (target "/dev/sdX")))      ; 9
+  (bootloader (GRUB-config (targets (list "/dev/sdX"))))        ; 9
   (file-systems (cons (file-system
                         (device (file-system-label "root"))
                         (mount-point "/")
@@ -168,7 +168,7 @@ OS_BASE='
 
   (bootloader (bootloader-configuration
                (bootloader grub-bootloader)
-               (target "/dev/sdX")))
+               (targets (list "/dev/sdX"))))
   (file-systems (cons (file-system
                         (device (file-system-label "root"))
                         (mount-point "/")
@@ -241,7 +241,7 @@ make_user_config ()
 
   (bootloader (bootloader-configuration
                 (bootloader grub-bootloader)
-                (target "/dev/sdX")))
+                (targets (list "/dev/sdX"))))
   (file-systems (cons (file-system
                         (device (file-system-label "root"))
                         (mount-point "/")
-- 
2.32.0

>From b237a30bda70818866885451ae999aa4be9038a9 Mon Sep 17 00:00:00 2001
From: Maxim Cournoyer <[email-masked]>
Date: Sat, 7 Aug 2021 15:07:47 -0400
Subject: [PATCH 2/2] Migrate to the new 'targets' field of
 bootloader-configuration.

The old 'target' field is deprecated; adjust the sources to use the new
'targets' one instead.

* doc/guix-cookbook.texi<target>: Replace by 'targets'.
* gnu/bootloader/grub.scm: Likewise.
* gnu/installer/parted.scm: Likewise.
* gnu/machine/digital-ocean.scm: Likewise.
* gnu/system/examples/asus-c201.tmpl: Likewise
* gnu/system/examples/bare-bones.tmpl: Likewise
* gnu/system/examples/bare-hurd.tmpl: Likewise
* gnu/system/examples/beaglebone-black.tmpl: Likewise
* gnu/system/examples/desktop.tmpl: Likewise
* gnu/system/examples/docker-image.tmpl: Likewise
* gnu/system/examples/lightweight-desktop.tmpl: Likewise
* gnu/system/examples/vm-image.tmpl: Likewise
* gnu/system/examples/yggdrasil.tmpl: Likewise
* gnu/system/hurd.scm: Likewise
* gnu/system/images/hurd.scm: Likewise
* gnu/system/images/novena.scm: Likewise
* gnu/system/images/pine64.scm: Likewise
* gnu/system/images/pinebook-pro.scm: Likewise
* gnu/system/images/rock64.scm: Likewise
* gnu/system/install.scm: Likewise
* gnu/system/vm.scm: Likewise
* gnu/tests.scm: Likewise
* gnu/tests/ganeti.scm: Likewise
* gnu/tests/install.scm: Likewise
* gnu/tests/nfs.scm: Likewise
* gnu/tests/telephony.scm: Likewise
* tests/boot-parameters.scm: Likewise
* tests/system.scm: Likewise
---
 doc/guix-cookbook.texi                       | 2 +-
 gnu/bootloader/grub.scm                      | 5 +++--
 gnu/installer/parted.scm                     | 4 ++--
 gnu/machine/digital-ocean.scm                | 2 +-
 gnu/system/examples/asus-c201.tmpl           | 2 +-
 gnu/system/examples/bare-bones.tmpl          | 2 +-
 gnu/system/examples/bare-hurd.tmpl           | 2 +-
 gnu/system/examples/beaglebone-black.tmpl    | 2 +-
 gnu/system/examples/desktop.tmpl             | 2 +-
 gnu/system/examples/docker-image.tmpl        | 2 +-
 gnu/system/examples/lightweight-desktop.tmpl | 2 +-
 gnu/system/examples/vm-image.tmpl            | 2 +-
 gnu/system/examples/yggdrasil.tmpl           | 2 +-
 gnu/system/hurd.scm                          | 2 +-
 gnu/system/images/hurd.scm                   | 2 +-
 gnu/system/images/novena.scm                 | 2 +-
 gnu/system/images/pine64.scm                 | 2 +-
 gnu/system/images/pinebook-pro.scm           | 2 +-
 gnu/system/images/rock64.scm                 | 2 +-
 gnu/system/install.scm                       | 6 +++---
 gnu/system/vm.scm                            | 2 +-
 gnu/tests.scm                                | 2 +-
 gnu/tests/ganeti.scm                         | 2 +-
 gnu/tests/install.scm                        | 4 ++--
 gnu/tests/nfs.scm                            | 2 +-
 gnu/tests/telephony.scm                      | 2 +-
 tests/boot-parameters.scm                    | 2 +-
 tests/system.scm                             | 4 ++--
 28 files changed, 35 insertions(+), 34 deletions(-)

diff --git a/doc/guix-cookbook.texi b/doc/guix-cookbook.texi
index 2e627ecc51..3cb5b59e69 100644
--- a/doc/guix-cookbook.texi
+++ b/doc/guix-cookbook.texi
@@ -1718,7 +1718,7 @@ operating-system dedicated to the @b{Pine A64 LTS} board.
    (locale "en_US.utf8")
    (bootloader (bootloader-configuration
                 (bootloader u-boot-pine64-lts-bootloader)
-                (target "/dev/vda")))
+                (targets '("/dev/vda"))))
    (initrd-modules '())
    (kernel linux-libre-arm64-generic)
    (file-systems (cons (file-system
diff --git a/gnu/bootloader/grub.scm b/gnu/bootloader/grub.scm
index ce146aba3c..d8e888ff40 100644
--- a/gnu/bootloader/grub.scm
+++ b/gnu/bootloader/grub.scm
@@ -647,11 +647,12 @@ below the directory TARGET for the system whose root is mounted at MOUNT-POINT.
 MOUNT-POINT is the last argument in 'guix system init /etc/config.scm mnt/point'
 or '/' for other 'guix system' commands.
 
-TARGET is the target argument given to the bootloader-configuration in
+Where TARGET comes from the targets argument given to the
+bootloader-configuration in:
 
 (operating-system
  (bootloader (bootloader-configuration
-              (target \"/boot\")
+              (targets '(\"/boot\"))
               …))
  …)
 
diff --git a/gnu/installer/parted.scm b/gnu/installer/parted.scm
index 1f9cec1d11..c000b1dec2 100644
--- a/gnu/installer/parted.scm
+++ b/gnu/installer/parted.scm
@@ -1356,9 +1356,9 @@ from (gnu system mapped-devices) and return it."
     `((bootloader-configuration
        ,@(if (efi-installation?)
              `((bootloader grub-efi-bootloader)
-               (target ,(default-esp-mount-point)))
+               (targets (list ,(default-esp-mount-point))))
              `((bootloader grub-bootloader)
-               (target ,root-partition-disk)))
+               (targets (list ,root-partition-disk))))
 
        ;; XXX: Assume we defined the 'keyboard-layout' field of
        ;; <operating-system> right above.
diff --git a/gnu/machine/digital-ocean.scm b/gnu/machine/digital-ocean.scm
index d97c300d18..90b66a54d9 100644
--- a/gnu/machine/digital-ocean.scm
+++ b/gnu/machine/digital-ocean.scm
@@ -235,7 +235,7 @@ cat > /etc/bootstrap-config.scm << EOF
   (timezone \"Etc/UTC\")
   (bootloader (bootloader-configuration
                (bootloader grub-bootloader)
-               (target \"/dev/vda\")
+               (targets '(\"/dev/vda\"))
                (terminal-outputs '(console))))
   (file-systems (cons (file-system
                         (mount-point \"/\")
diff --git a/gnu/system/examples/asus-c201.tmpl b/gnu/system/examples/asus-c201.tmpl
index c08f85367f..6b6aa706fa 100644
--- a/gnu/system/examples/asus-c201.tmpl
+++ b/gnu/system/examples/asus-c201.tmpl
@@ -14,7 +14,7 @@
   ;; "my-root" is the label of the target root file system.
   (bootloader (bootloader-configuration
                 (bootloader depthcharge-bootloader)
-                (target "/dev/mmcblk0p1")))
+                (targets '("/dev/mmcblk0p1"))))
 
   ;; The ASUS C201PA requires a very particular kernel to boot,
   ;; as well as the following arguments.
diff --git a/gnu/system/examples/bare-bones.tmpl b/gnu/system/examples/bare-bones.tmpl
index 1035ab1d60..387e4b12ba 100644
--- a/gnu/system/examples/bare-bones.tmpl
+++ b/gnu/system/examples/bare-bones.tmpl
@@ -15,7 +15,7 @@
   ;; root file system.
   (bootloader (bootloader-configuration
                 (bootloader grub-bootloader)
-                (target "/dev/sdX")))
+                (targets '("/dev/sdX"))))
   (file-systems (cons (file-system
                         (device (file-system-label "my-root"))
                         (mount-point "/")
diff --git a/gnu/system/examples/bare-hurd.tmpl b/gnu/system/examples/bare-hurd.tmpl
index 135ed23cb6..f0dd0cf742 100644
--- a/gnu/system/examples/bare-hurd.tmpl
+++ b/gnu/system/examples/bare-hurd.tmpl
@@ -32,7 +32,7 @@
     (inherit %hurd-default-operating-system)
     (bootloader (bootloader-configuration
                  (bootloader grub-minimal-bootloader)
-                 (target "/dev/sdX")))
+                 (targets '("/dev/sdX"))))
     (file-systems (cons (file-system
                           (device (file-system-label "my-root"))
                           (mount-point "/")
diff --git a/gnu/system/examples/beaglebone-black.tmpl b/gnu/system/examples/beaglebone-black.tmpl
index def05e807d..90dab62062 100644
--- a/gnu/system/examples/beaglebone-black.tmpl
+++ b/gnu/system/examples/beaglebone-black.tmpl
@@ -14,7 +14,7 @@
   ;; the label of the target root file system.
   (bootloader (bootloader-configuration
                (bootloader u-boot-beaglebone-black-bootloader)
-               (target "/dev/mmcblk1")))
+               (targets '("/dev/mmcblk1"))))
 
   ;; This module is required to mount the SD card.
   (initrd-modules (cons "omap_hsmmc" %base-initrd-modules))
diff --git a/gnu/system/examples/desktop.tmpl b/gnu/system/examples/desktop.tmpl
index 716b9feb8d..c928008c92 100644
--- a/gnu/system/examples/desktop.tmpl
+++ b/gnu/system/examples/desktop.tmpl
@@ -19,7 +19,7 @@
   ;; Partition mounted on /boot/efi.
   (bootloader (bootloader-configuration
                 (bootloader grub-efi-bootloader)
-                (target "/boot/efi")
+                (targets '("/boot/efi"))
                 (keyboard-layout keyboard-layout)))
 
   ;; Specify a mapped device for the encrypted root partition.
diff --git a/gnu/system/examples/docker-image.tmpl b/gnu/system/examples/docker-image.tmpl
index ca633cc838..bdc6afa6f0 100644
--- a/gnu/system/examples/docker-image.tmpl
+++ b/gnu/system/examples/docker-image.tmpl
@@ -35,7 +35,7 @@
   ;; This will be ignored.
   (bootloader (bootloader-configuration
                (bootloader grub-bootloader)
-               (target "does-not-matter")))
+               (targets '("does-not-matter"))))
   ;; This will be ignored, too.
   (file-systems (list (file-system
                         (device "does-not-matter")
diff --git a/gnu/system/examples/lightweight-desktop.tmpl b/gnu/system/examples/lightweight-desktop.tmpl
index d5a63dc457..d4330ecc8e 100644
--- a/gnu/system/examples/lightweight-desktop.tmpl
+++ b/gnu/system/examples/lightweight-desktop.tmpl
@@ -16,7 +16,7 @@
   ;; Partition mounted on /boot/efi.
   (bootloader (bootloader-configuration
                 (bootloader grub-efi-bootloader)
-                (target "/boot/efi")))
+                (targets '("/boot/efi"))))
 
   ;; Assume the target root file system is labelled "my-root",
   ;; and the EFI System Partition has UUID 1234-ABCD.
diff --git a/gnu/system/examples/vm-image.tmpl b/gnu/system/examples/vm-image.tmpl
index 697019e877..a59d91587b 100644
--- a/gnu/system/examples/vm-image.tmpl
+++ b/gnu/system/examples/vm-image.tmpl
@@ -51,7 +51,7 @@ accounts.\x1b[0m
   ;; Adjust as needed.
   (bootloader (bootloader-configuration
                (bootloader grub-bootloader)
-               (target "/dev/vda")
+               (targets '("/dev/vda"))
                (terminal-outputs '(console))))
   (file-systems (cons (file-system
                         (mount-point "/")
diff --git a/gnu/system/examples/yggdrasil.tmpl b/gnu/system/examples/yggdrasil.tmpl
index be80bf4de9..4d34f49b54 100644
--- a/gnu/system/examples/yggdrasil.tmpl
+++ b/gnu/system/examples/yggdrasil.tmpl
@@ -15,7 +15,7 @@
   ;; root file system.
   (bootloader (bootloader-configuration
                 (bootloader grub-bootloader)
-                (target "/dev/sdX")))
+                (targets '("/dev/sdX"))))
   (file-systems (cons (file-system
                         (device (file-system-label "my-root"))
                         (mount-point "/")
diff --git a/gnu/system/hurd.scm b/gnu/system/hurd.scm
index 8f3a27834b..685d16eac2 100644
--- a/gnu/system/hurd.scm
+++ b/gnu/system/hurd.scm
@@ -108,7 +108,7 @@
     (hurd hurd)
     (bootloader (bootloader-configuration
                  (bootloader grub-minimal-bootloader)
-                 (target "/dev/vda")))
+                 (targets '("/dev/vda"))))
     (initrd #f)
     (initrd-modules (lambda _ '()))
     (firmware '())
diff --git a/gnu/system/images/hurd.scm b/gnu/system/images/hurd.scm
index eac5b7f7e6..fc2dbe3209 100644
--- a/gnu/system/images/hurd.scm
+++ b/gnu/system/images/hurd.scm
@@ -42,7 +42,7 @@
     (inherit %hurd-default-operating-system)
     (bootloader (bootloader-configuration
                  (bootloader grub-minimal-bootloader)
-                 (target "/dev/sdX")))
+                 (targets '("/dev/sdX"))))
     (file-systems (cons (file-system
                           (device (file-system-label "my-root"))
                           (mount-point "/")
diff --git a/gnu/system/images/novena.scm b/gnu/system/images/novena.scm
index 1cd724ff88..63227af509 100644
--- a/gnu/system/images/novena.scm
+++ b/gnu/system/images/novena.scm
@@ -39,7 +39,7 @@
     (locale "en_US.utf8")
     (bootloader (bootloader-configuration
                  (bootloader u-boot-novena-bootloader)
-                 (target "/dev/vda")))
+                 (targets '("/dev/vda"))))
     (initrd-modules '("sdhci-esdhc-imx" "ahci_imx" "i2c-dev"))
     ;(kernel linux-libre-arm-generic)
     (kernel-arguments '("console=ttymxc1,115200"))
diff --git a/gnu/system/images/pine64.scm b/gnu/system/images/pine64.scm
index 613acd5cfd..808c71295f 100644
--- a/gnu/system/images/pine64.scm
+++ b/gnu/system/images/pine64.scm
@@ -38,7 +38,7 @@
     (locale "en_US.utf8")
     (bootloader (bootloader-configuration
                  (bootloader u-boot-pine64-lts-bootloader)
-                 (target "/dev/vda")))
+                 (targets '("/dev/vda"))))
     (initrd-modules '())
     (kernel linux-libre-arm64-generic)
     (file-systems (cons (file-system
diff --git a/gnu/system/images/pinebook-pro.scm b/gnu/system/images/pinebook-pro.scm
index b56a7ea409..991c86aa9f 100644
--- a/gnu/system/images/pinebook-pro.scm
+++ b/gnu/system/images/pinebook-pro.scm
@@ -38,7 +38,7 @@
     (locale "en_US.utf8")
     (bootloader (bootloader-configuration
                  (bootloader u-boot-pinebook-pro-rk3399-bootloader)
-                 (target "/dev/vda")))
+                 (targets '("/dev/vda"))))
     (initrd-modules '())
     (kernel linux-libre-arm64-generic)
     (file-systems (cons (file-system
diff --git a/gnu/system/images/rock64.scm b/gnu/system/images/rock64.scm
index 3f193e8528..68d3742adc 100644
--- a/gnu/system/images/rock64.scm
+++ b/gnu/system/images/rock64.scm
@@ -39,7 +39,7 @@
     (locale "en_US.utf8")
     (bootloader (bootloader-configuration
                  (bootloader u-boot-rock64-rk3328-bootloader)
-                 (target "/dev/sda")))
+                 (targets '("/dev/sda"))))
     (initrd-modules '())
     (kernel linux-libre-arm64-generic)
     (file-systems (cons (file-system
diff --git a/gnu/system/install.scm b/gnu/system/install.scm
index 7fa5c15324..f96e18ba63 100644
--- a/gnu/system/install.scm
+++ b/gnu/system/install.scm
@@ -453,7 +453,7 @@ Access documentation at any time by pressing Alt-F2.\x1b[0m
     (name-service-switch %mdns-host-lookup-nss)
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/sda")))
+                 (targets '("/dev/sda"))))
     (label (string-append "GNU Guix installation "
                           (package-version guix)))
 
@@ -528,7 +528,7 @@ operating-system's kernel-arguments (\"console=ttyS0\" or similar)."
     (bootloader (bootloader-configuration
                  (bootloader (bootloader (inherit u-boot-bootloader)
                               (package (make-u-boot-package board triplet))))
-                 (target bootloader-target)))))
+                 (targets (list bootloader-target))))))
 
 (define* (embedded-installation-os bootloader bootloader-target tty
                                    #:key (extra-modules '()))
@@ -540,7 +540,7 @@ The bootloader BOOTLOADER is installed to BOOTLOADER-TARGET."
     (inherit installation-os)
     (bootloader (bootloader-configuration
                  (bootloader bootloader)
-                 (target bootloader-target)))
+                 (targets (list bootloader-target))))
     (kernel linux-libre)
     (kernel-arguments
      (cons (string-append "console=" tty)
diff --git a/gnu/system/vm.scm b/gnu/system/vm.scm
index 3390f5a88f..a532be2dad 100644
--- a/gnu/system/vm.scm
+++ b/gnu/system/vm.scm
@@ -630,7 +630,7 @@ environment with the store shared with the host.  MAPPINGS is a list of
     (bootloader (bootloader-configuration
                   (inherit (operating-system-bootloader os))
                   (bootloader grub-bootloader)
-                  (target "/dev/vda")))
+                  (targets '("/dev/vda"))))
 
     (initrd (lambda (file-systems . rest)
               (apply (operating-system-initrd os)
diff --git a/gnu/tests.scm b/gnu/tests.scm
index eb636873a2..85f38ae8c9 100644
--- a/gnu/tests.scm
+++ b/gnu/tests.scm
@@ -222,7 +222,7 @@ the system under test."
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/sdX")))
+                 (targets '("/dev/sdX"))))
     (file-systems (cons (file-system
                           (device (file-system-label "my-root"))
                           (mount-point "/")
diff --git a/gnu/tests/ganeti.scm b/gnu/tests/ganeti.scm
index 19c26b86dd..b64a332dde 100644
--- a/gnu/tests/ganeti.scm
+++ b/gnu/tests/ganeti.scm
@@ -38,7 +38,7 @@
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/vda")))
+                 (targets '("/dev/vda"))))
     (file-systems (cons (file-system
                           (device (file-system-label "my-root"))
                           (mount-point "/")
diff --git a/gnu/tests/install.scm b/gnu/tests/install.scm
index d7fafd210c..130a4f76b0 100644
--- a/gnu/tests/install.scm
+++ b/gnu/tests/install.scm
@@ -494,7 +494,7 @@ reboot\n")
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/vdb")))
+                 (targets '("/dev/vdb"))))
     (kernel-arguments '("console=ttyS0"))
     (file-systems (cons* (file-system
                            (device (file-system-label "my-root"))
@@ -709,7 +709,7 @@ by 'mdadm'.")
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/vdb")))
+                 (targets '("/dev/vdb"))))
 
     ;; Note: Do not pass "console=ttyS0" so we can use our passphrase prompt
     ;; detection logic in 'enter-luks-passphrase'.
diff --git a/gnu/tests/nfs.scm b/gnu/tests/nfs.scm
index 9b2b785176..a0c091eadb 100644
--- a/gnu/tests/nfs.scm
+++ b/gnu/tests/nfs.scm
@@ -50,7 +50,7 @@
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/sdX")))
+                 (targets '("/dev/sdX"))))
     (file-systems %base-file-systems)
     (users %base-user-accounts)
     (packages (cons*
diff --git a/gnu/tests/telephony.scm b/gnu/tests/telephony.scm
index 1155a9dbc2..aeb6500c47 100644
--- a/gnu/tests/telephony.scm
+++ b/gnu/tests/telephony.scm
@@ -74,7 +74,7 @@
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/sdX")))
+                 (targets '("/dev/sdX"))))
     (file-systems (cons (file-system
                           (device (file-system-label "my-root"))
                           (mount-point "/")
diff --git a/tests/boot-parameters.scm b/tests/boot-parameters.scm
index 3deae564c4..b2799d0596 100644
--- a/tests/boot-parameters.scm
+++ b/tests/boot-parameters.scm
@@ -81,7 +81,7 @@
 
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/sda")))
+                 (targets '("/dev/sda"))))
     (file-systems (cons* (file-system
                            (device %default-root-device)
                            (mount-point %root-path)
diff --git a/tests/system.scm b/tests/system.scm
index 9416b950e6..019c720e65 100644
--- a/tests/system.scm
+++ b/tests/system.scm
@@ -39,7 +39,7 @@
     (locale "en_US.utf8")
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/sdX")))
+                 (targets '("/dev/sdX"))))
     (file-systems (cons %root-fs %base-file-systems))
 
     (users %base-user-accounts)))
@@ -56,7 +56,7 @@
     (locale "en_US.utf8")
     (bootloader (bootloader-configuration
                  (bootloader grub-bootloader)
-                 (target "/dev/sdX")))
+                 (targets '("/dev/sdX"))))
     (mapped-devices (list %luks-device))
     (file-systems (cons (file-system
                           (inherit %root-fs)
-- 
2.32.0

Thanks,

Maxim