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/interface/efi/efi_block.c | 85 ++++++++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 26 deletions(-) (limited to 'src/interface') 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