]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[block] Allow SAN boot device to be identified by filesystem label
authorMichael Brown <mcb30@ipxe.org>
Thu, 7 Mar 2024 14:09:54 +0000 (14:09 +0000)
committerMichael Brown <mcb30@ipxe.org>
Thu, 7 Mar 2024 14:11:46 +0000 (14:11 +0000)
Add a "--label" option that can be used to specify a filesystem label,
to be matched against the FAT volume label.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/hci/commands/sanboot_cmd.c
src/include/ipxe/sanboot.h
src/interface/efi/efi_block.c

index add0756da5a085237fb15101ac58f31376f89ef3..6ab9e8844c9308c61043ef072c3e98e6fd2896e0 100644 (file)
@@ -51,6 +51,8 @@ struct sanboot_options {
        char *filename;
        /** Required extra filename */
        char *extra;
+       /** Volume label */
+       char *label;
        /** UUID */
        struct uuid_option uuid;
 };
@@ -58,7 +60,7 @@ struct sanboot_options {
 /** "sanboot" option list */
 static union {
        /* "sanboot" takes all options */
-       struct option_descriptor sanboot[6];
+       struct option_descriptor sanboot[7];
        /* "sanhook" takes only --drive and --no-describe */
        struct option_descriptor sanhook[2];
        /* "sanunhook" takes only --drive */
@@ -75,6 +77,8 @@ static union {
                              struct sanboot_options, filename, parse_string ),
                OPTION_DESC ( "extra", 'e', required_argument,
                              struct sanboot_options, extra, parse_string ),
+               OPTION_DESC ( "label", 'l', required_argument,
+                             struct sanboot_options, label, parse_string ),
                OPTION_DESC ( "uuid", 'u', required_argument,
                              struct sanboot_options, uuid, parse_uuid ),
        },
@@ -135,6 +139,7 @@ static int sanboot_core_exec ( int argc, char **argv,
        /* Construct configuration parameters */
        config.filename = opts.filename;
        config.extra = opts.extra;
+       config.label = opts.label;
        config.uuid = opts.uuid.value;
 
        /* Construct flags */
index 91c848b05dd9d35e222482d45947eaaf60b62ed5..e44367cdbbee2d8bc8712dc773ae9b65939b69e3 100644 (file)
@@ -112,6 +112,8 @@ struct san_boot_config {
        const char *filename;
        /** Required extra filename (or NULL to ignore) */
        const char *extra;
+       /** Filesystem label (or NULL to ignore volume label) */
+       const char *label;
        /** UUID (or NULL to ignore UUID) */
        union uuid *uuid;
 };
index 269b9abd7b7f1798f27f029e733215c1cd43531e..28a7f72345092a8fbd63a1e44d88b09d233ede42 100644 (file)
@@ -32,7 +32,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 
 #include <stddef.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
+#include <strings.h>
 #include <errno.h>
 #include <ipxe/refcnt.h>
 #include <ipxe/list.h>
@@ -51,6 +53,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <ipxe/efi/Protocol/BlockIo.h>
 #include <ipxe/efi/Protocol/SimpleFileSystem.h>
 #include <ipxe/efi/Protocol/AcpiTable.h>
+#include <ipxe/efi/Guid/FileSystemInfo.h>
 #include <ipxe/efi/efi_driver.h>
 #include <ipxe/efi/efi_strings.h>
 #include <ipxe/efi/efi_snp.h>
@@ -595,6 +598,68 @@ static int efi_block_filename ( unsigned int drive, EFI_HANDLE handle,
        return rc;
 }
 
+/**
+ * Check for EFI block device filesystem label
+ *
+ * @v drive            Drive number
+ * @v root             Root directory
+ * @v label            Volume label
+ * @ret rc             Return status code
+ */
+static int efi_block_label ( unsigned int drive, EFI_FILE_PROTOCOL *root,
+                            const char *label ) {
+       EFI_FILE_SYSTEM_INFO *info;
+       UINTN size;
+       char *actual;
+       EFI_STATUS efirc;
+       int rc;
+
+       /* Get length of file system information */
+       size = 0;
+       root->GetInfo ( root, &efi_file_system_info_id, &size, NULL );
+
+       /* Allocate file system information */
+       info = malloc ( size );
+       if ( ! info ) {
+               rc = -ENOMEM;
+               goto err_alloc_info;
+       }
+
+       /* Get file system information */
+       if ( ( efirc = root->GetInfo ( root, &efi_file_system_info_id, &size,
+                                      info ) ) != 0 ) {
+               rc = -EEFI ( efirc );
+               DBGC ( drive, "EFIBLK %#02x could not get filesystem info: "
+                      "%s\n", drive, strerror ( rc ) );
+               goto err_get_info;
+       }
+
+       /* Construct volume label for comparison */
+       if ( asprintf ( &actual, "%ls", info->VolumeLabel ) < 0 ) {
+               rc = -ENOMEM;
+               goto err_alloc_label;
+       }
+
+       /* Compare volume label */
+       if ( strcasecmp ( label, actual ) != 0 ) {
+               DBGC ( drive, "EFIBLK %#02x has wrong label \"%s\"\n",
+                      drive, actual );
+               rc = -ENOENT;
+               goto err_compare;
+       }
+
+       /* Success */
+       rc = 0;
+
+ err_compare:
+       free ( actual );
+ err_alloc_label:
+ err_get_info:
+       free ( info );
+ err_alloc_info:
+       return rc;
+}
+
 /**
  * Check EFI block device filesystem match
  *
@@ -675,9 +740,17 @@ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle,
                goto err_extra;
        }
 
+       /* Check volume label, if applicable */
+       if ( config->label &&
+            ( ( rc = efi_block_label ( drive, root,
+                                       config->label ) ) != 0 ) ) {
+               goto err_label;
+       }
+
        /* Success */
        rc = 0;
 
+ err_label:
  err_extra:
  err_filename:
        root->Close ( root );