[block] Allow SAN boot device to be identified by filesystem label

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>
pull/1174/head
Michael Brown 2024-03-07 14:09:54 +00:00
parent 62b6d36335
commit 24a855f1fc
3 changed files with 81 additions and 1 deletions

View File

@ -51,6 +51,8 @@ struct sanboot_options {
char *filename; char *filename;
/** Required extra filename */ /** Required extra filename */
char *extra; char *extra;
/** Volume label */
char *label;
/** UUID */ /** UUID */
struct uuid_option uuid; struct uuid_option uuid;
}; };
@ -58,7 +60,7 @@ struct sanboot_options {
/** "sanboot" option list */ /** "sanboot" option list */
static union { static union {
/* "sanboot" takes all options */ /* "sanboot" takes all options */
struct option_descriptor sanboot[6]; struct option_descriptor sanboot[7];
/* "sanhook" takes only --drive and --no-describe */ /* "sanhook" takes only --drive and --no-describe */
struct option_descriptor sanhook[2]; struct option_descriptor sanhook[2];
/* "sanunhook" takes only --drive */ /* "sanunhook" takes only --drive */
@ -75,6 +77,8 @@ static union {
struct sanboot_options, filename, parse_string ), struct sanboot_options, filename, parse_string ),
OPTION_DESC ( "extra", 'e', required_argument, OPTION_DESC ( "extra", 'e', required_argument,
struct sanboot_options, extra, parse_string ), struct sanboot_options, extra, parse_string ),
OPTION_DESC ( "label", 'l', required_argument,
struct sanboot_options, label, parse_string ),
OPTION_DESC ( "uuid", 'u', required_argument, OPTION_DESC ( "uuid", 'u', required_argument,
struct sanboot_options, uuid, parse_uuid ), struct sanboot_options, uuid, parse_uuid ),
}, },
@ -135,6 +139,7 @@ static int sanboot_core_exec ( int argc, char **argv,
/* Construct configuration parameters */ /* Construct configuration parameters */
config.filename = opts.filename; config.filename = opts.filename;
config.extra = opts.extra; config.extra = opts.extra;
config.label = opts.label;
config.uuid = opts.uuid.value; config.uuid = opts.uuid.value;
/* Construct flags */ /* Construct flags */

View File

@ -112,6 +112,8 @@ struct san_boot_config {
const char *filename; const char *filename;
/** Required extra filename (or NULL to ignore) */ /** Required extra filename (or NULL to ignore) */
const char *extra; const char *extra;
/** Filesystem label (or NULL to ignore volume label) */
const char *label;
/** UUID (or NULL to ignore UUID) */ /** UUID (or NULL to ignore UUID) */
union uuid *uuid; union uuid *uuid;
}; };

View File

@ -32,7 +32,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <strings.h>
#include <errno.h> #include <errno.h>
#include <ipxe/refcnt.h> #include <ipxe/refcnt.h>
#include <ipxe/list.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/BlockIo.h>
#include <ipxe/efi/Protocol/SimpleFileSystem.h> #include <ipxe/efi/Protocol/SimpleFileSystem.h>
#include <ipxe/efi/Protocol/AcpiTable.h> #include <ipxe/efi/Protocol/AcpiTable.h>
#include <ipxe/efi/Guid/FileSystemInfo.h>
#include <ipxe/efi/efi_driver.h> #include <ipxe/efi/efi_driver.h>
#include <ipxe/efi/efi_strings.h> #include <ipxe/efi/efi_strings.h>
#include <ipxe/efi/efi_snp.h> #include <ipxe/efi/efi_snp.h>
@ -595,6 +598,68 @@ static int efi_block_filename ( unsigned int drive, EFI_HANDLE handle,
return rc; 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 * Check EFI block device filesystem match
* *
@ -675,9 +740,17 @@ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle,
goto err_extra; goto err_extra;
} }
/* Check volume label, if applicable */
if ( config->label &&
( ( rc = efi_block_label ( drive, root,
config->label ) ) != 0 ) ) {
goto err_label;
}
/* Success */ /* Success */
rc = 0; rc = 0;
err_label:
err_extra: err_extra:
err_filename: err_filename:
root->Close ( root ); root->Close ( root );