From 62b6d363351fb5d8890cdcd36c949d6d8563b4e9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 7 Mar 2024 13:31:29 +0000 Subject: [block] Allow SAN boot device to be identified by an extra filename 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 --- src/hci/commands/sanboot_cmd.c | 9 ++++- src/include/ipxe/sanboot.h | 2 + src/interface/efi/efi_block.c | 85 +++++++++++++++++++++++++++++------------- 3 files changed, 68 insertions(+), 28 deletions(-) diff --git a/src/hci/commands/sanboot_cmd.c b/src/hci/commands/sanboot_cmd.c index b3d9cca..add0756 100644 --- a/src/hci/commands/sanboot_cmd.c +++ b/src/hci/commands/sanboot_cmd.c @@ -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 */ diff --git a/src/include/ipxe/sanboot.h b/src/include/ipxe/sanboot.h index 9841edd..91c848b 100644 --- a/src/include/ipxe/sanboot.h +++ b/src/include/ipxe/sanboot.h @@ -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; }; diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index f5b913f..269b9ab 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -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: -- cgit v1.1