]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[block] Allow SAN boot device to be identified by an extra filename
authorMichael Brown <mcb30@ipxe.org>
Thu, 7 Mar 2024 13:31:29 +0000 (13:31 +0000)
committerMichael Brown <mcb30@ipxe.org>
Thu, 7 Mar 2024 13:31:29 +0000 (13:31 +0000)
Add an "--extra" option that can be used to specify an extra
(non-boot) filename that must exist within the booted filesystem.

Note that only files within the FAT-formatted bootable partition will
be visible to this filter.  Files within the operating system's root
disk (e.g. "/etc/redhat-release") are not generally accessible to the
firmware and so cannot be used as the existence check filter filename.

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 b3d9ccad38223bbac131d1f5d9fe3408eaac27b7..add0756da5a085237fb15101ac58f31376f89ef3 100644 (file)
@@ -47,8 +47,10 @@ struct sanboot_options {
        int no_describe;
        /** Keep SAN device */
        int keep;
-       /** Filename */
+       /** Boot filename */
        char *filename;
+       /** Required extra filename */
+       char *extra;
        /** UUID */
        struct uuid_option uuid;
 };
@@ -56,7 +58,7 @@ struct sanboot_options {
 /** "sanboot" option list */
 static union {
        /* "sanboot" takes all options */
-       struct option_descriptor sanboot[5];
+       struct option_descriptor sanboot[6];
        /* "sanhook" takes only --drive and --no-describe */
        struct option_descriptor sanhook[2];
        /* "sanunhook" takes only --drive */
@@ -71,6 +73,8 @@ static union {
                              struct sanboot_options, keep, parse_flag ),
                OPTION_DESC ( "filename", 'f', required_argument,
                              struct sanboot_options, filename, parse_string ),
+               OPTION_DESC ( "extra", 'e', required_argument,
+                             struct sanboot_options, extra, parse_string ),
                OPTION_DESC ( "uuid", 'u', required_argument,
                              struct sanboot_options, uuid, parse_uuid ),
        },
@@ -130,6 +134,7 @@ static int sanboot_core_exec ( int argc, char **argv,
 
        /* Construct configuration parameters */
        config.filename = opts.filename;
+       config.extra = opts.extra;
        config.uuid = opts.uuid.value;
 
        /* Construct flags */
index 9841edda5d9b30d97cc85a783a19a91fe864fa39..91c848b05dd9d35e222482d45947eaaf60b62ed5 100644 (file)
@@ -110,6 +110,8 @@ enum san_device_flags {
 struct san_boot_config {
        /** Boot filename (or NULL to use default) */
        const char *filename;
+       /** Required extra filename (or NULL to ignore) */
+       const char *extra;
        /** UUID (or NULL to ignore UUID) */
        union uuid *uuid;
 };
index f5b913f15aa9f322d4a43708cdba844b0a90b111..269b9abd7b7f1798f27f029e733215c1cd43531e 100644 (file)
@@ -506,55 +506,77 @@ static int efi_block_describe ( void ) {
 }
 
 /**
- * Check for existence of a file within a filesystem
+ * Open root directory within a filesystem
  *
  * @v drive            Drive number
  * @v handle           Filesystem handle
- * @v filename         Filename (or NULL to use default)
+ * @v root             Root directory file to fill in
  * @ret rc             Return status code
  */
-static int efi_block_filename ( unsigned int drive, EFI_HANDLE handle,
-                               const char *filename ) {
+static int efi_block_root ( unsigned int drive, EFI_HANDLE handle,
+                           EFI_FILE_PROTOCOL **root ) {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        EFI_GUID *protocol = &efi_simple_file_system_protocol_guid;
-       CHAR16 tmp[ filename ? ( strlen ( filename ) + 1 /* wNUL */ ) : 0 ];
        union {
                EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
                void *interface;
        } u;
-       CHAR16 *wname;
-       EFI_FILE_PROTOCOL *root;
-       EFI_FILE_PROTOCOL *file;
        EFI_STATUS efirc;
        int rc;
 
-       /* Construct filename */
-       if ( filename ) {
-               efi_snprintf ( tmp, sizeof ( tmp ), "%s", filename );
-               wname = tmp;
-       } else {
-               wname = efi_block_boot_filename;
-       }
-
-       /* Open file system protocol */
+       /* Open filesystem protocol */
        if ( ( efirc = bs->OpenProtocol ( handle, protocol, &u.interface,
                                          efi_image_handle, handle,
                                          EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
                rc = -EEFI ( efirc );
-               DBGC ( drive, "EFIBLK %#02x could not open %s device path: "
-                      "%s\n", drive, efi_handle_name ( handle ),
-                      strerror ( rc ) );
+               DBGC ( drive, "EFIBLK %#02x could not open %s filesystem: %s\n",
+                      drive, efi_handle_name ( handle ), strerror ( rc ) );
                goto err_open;
        }
 
        /* Open root volume */
-       if ( ( efirc = u.fs->OpenVolume ( u.fs, &root ) ) != 0 ) {
+       if ( ( efirc = u.fs->OpenVolume ( u.fs, root ) ) != 0 ) {
                rc = -EEFI ( efirc );
                DBGC ( drive, "EFIBLK %#02x could not open %s root: %s\n",
                       drive, efi_handle_name ( handle ), strerror ( rc ) );
                goto err_volume;
        }
 
+       /* Success */
+       rc = 0;
+
+ err_volume:
+       bs->CloseProtocol ( handle, protocol, efi_image_handle, handle );
+ err_open:
+       return rc;
+}
+
+/**
+ * Check for existence of a file within a filesystem
+ *
+ * @v drive            Drive number
+ * @v handle           Filesystem handle
+ * @v root             Root directory
+ * @v filename         Filename (or NULL to use default)
+ * @ret rc             Return status code
+ */
+static int efi_block_filename ( unsigned int drive, EFI_HANDLE handle,
+                               EFI_FILE_PROTOCOL *root,
+                               const char *filename ) {
+       CHAR16 tmp[ filename ? ( strlen ( filename ) + 1 /* wNUL */ ) : 0 ];
+       CHAR16 *wname;
+       EFI_FILE_PROTOCOL *file;
+       EFI_STATUS efirc;
+       int rc;
+
+       /* Construct filename */
+       if ( filename ) {
+               efi_snprintf ( tmp, sizeof ( tmp ), "%s", filename );
+               wname = tmp;
+       } else {
+               wname = efi_block_boot_filename;
+       }
+
        /* Try opening file */
        if ( ( efirc = root->Open ( root, &file, wname,
                                    EFI_FILE_MODE_READ, 0 ) ) != 0 ) {
@@ -570,10 +592,6 @@ static int efi_block_filename ( unsigned int drive, EFI_HANDLE handle,
 
        file->Close ( file );
  err_file:
-       root->Close ( root );
- err_volume:
-       bs->CloseProtocol ( handle, protocol, efi_image_handle, handle );
- err_open:
        return rc;
 }
 
@@ -597,6 +615,7 @@ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle,
                EFI_DEVICE_PATH_PROTOCOL *path;
                void *interface;
        } u;
+       EFI_FILE *root;
        union uuid guid;
        EFI_STATUS efirc;
        int rc;
@@ -639,16 +658,30 @@ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle,
                }
        }
 
+       /* Open root directory */
+       if ( ( rc = efi_block_root ( drive, handle, &root ) ) != 0 )
+               goto err_root;
+
        /* Check if filesystem contains boot filename */
-       if ( ( rc = efi_block_filename ( drive, handle,
+       if ( ( rc = efi_block_filename ( drive, handle, root,
                                         config->filename ) ) != 0 ) {
                goto err_filename;
        }
 
+       /* Check if filesystem contains additional filename, if applicable */
+       if ( config->extra &&
+            ( ( rc = efi_block_filename ( drive, handle, root,
+                                          config->extra ) ) != 0 ) ) {
+               goto err_extra;
+       }
+
        /* Success */
        rc = 0;
 
+ err_extra:
  err_filename:
+       root->Close ( root );
+ err_root:
  err_wrong_guid:
  err_no_guid:
  err_not_child: