mirror of
https://github.com/ipxe/ipxe
synced 2025-12-28 10:32:52 +03:00
[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 <mcb30@ipxe.org>
This commit is contained in:
@@ -47,8 +47,10 @@ struct sanboot_options {
|
|||||||
int no_describe;
|
int no_describe;
|
||||||
/** Keep SAN device */
|
/** Keep SAN device */
|
||||||
int keep;
|
int keep;
|
||||||
/** Filename */
|
/** Boot filename */
|
||||||
char *filename;
|
char *filename;
|
||||||
|
/** Required extra filename */
|
||||||
|
char *extra;
|
||||||
/** UUID */
|
/** UUID */
|
||||||
struct uuid_option uuid;
|
struct uuid_option uuid;
|
||||||
};
|
};
|
||||||
@@ -56,7 +58,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[5];
|
struct option_descriptor sanboot[6];
|
||||||
/* "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 */
|
||||||
@@ -71,6 +73,8 @@ static union {
|
|||||||
struct sanboot_options, keep, parse_flag ),
|
struct sanboot_options, keep, parse_flag ),
|
||||||
OPTION_DESC ( "filename", 'f', required_argument,
|
OPTION_DESC ( "filename", 'f', required_argument,
|
||||||
struct sanboot_options, filename, parse_string ),
|
struct sanboot_options, filename, parse_string ),
|
||||||
|
OPTION_DESC ( "extra", 'e', required_argument,
|
||||||
|
struct sanboot_options, extra, 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 ),
|
||||||
},
|
},
|
||||||
@@ -130,6 +134,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.uuid = opts.uuid.value;
|
config.uuid = opts.uuid.value;
|
||||||
|
|
||||||
/* Construct flags */
|
/* Construct flags */
|
||||||
|
|||||||
@@ -110,6 +110,8 @@ enum san_device_flags {
|
|||||||
struct san_boot_config {
|
struct san_boot_config {
|
||||||
/** Boot filename (or NULL to use default) */
|
/** Boot filename (or NULL to use default) */
|
||||||
const char *filename;
|
const char *filename;
|
||||||
|
/** Required extra filename (or NULL to ignore) */
|
||||||
|
const char *extra;
|
||||||
/** UUID (or NULL to ignore UUID) */
|
/** UUID (or NULL to ignore UUID) */
|
||||||
union uuid *uuid;
|
union uuid *uuid;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -506,24 +506,65 @@ 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 drive Drive number
|
||||||
* @v handle Filesystem handle
|
* @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
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int efi_block_filename ( unsigned int drive, EFI_HANDLE handle,
|
static int efi_block_root ( unsigned int drive, EFI_HANDLE handle,
|
||||||
const char *filename ) {
|
EFI_FILE_PROTOCOL **root ) {
|
||||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||||
EFI_GUID *protocol = &efi_simple_file_system_protocol_guid;
|
EFI_GUID *protocol = &efi_simple_file_system_protocol_guid;
|
||||||
CHAR16 tmp[ filename ? ( strlen ( filename ) + 1 /* wNUL */ ) : 0 ];
|
|
||||||
union {
|
union {
|
||||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
|
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
|
||||||
void *interface;
|
void *interface;
|
||||||
} u;
|
} u;
|
||||||
|
EFI_STATUS efirc;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* 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 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 ) {
|
||||||
|
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;
|
CHAR16 *wname;
|
||||||
EFI_FILE_PROTOCOL *root;
|
|
||||||
EFI_FILE_PROTOCOL *file;
|
EFI_FILE_PROTOCOL *file;
|
||||||
EFI_STATUS efirc;
|
EFI_STATUS efirc;
|
||||||
int rc;
|
int rc;
|
||||||
@@ -536,25 +577,6 @@ static int efi_block_filename ( unsigned int drive, EFI_HANDLE handle,
|
|||||||
wname = efi_block_boot_filename;
|
wname = efi_block_boot_filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open file system 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 ) );
|
|
||||||
goto err_open;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open root volume */
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try opening file */
|
/* Try opening file */
|
||||||
if ( ( efirc = root->Open ( root, &file, wname,
|
if ( ( efirc = root->Open ( root, &file, wname,
|
||||||
EFI_FILE_MODE_READ, 0 ) ) != 0 ) {
|
EFI_FILE_MODE_READ, 0 ) ) != 0 ) {
|
||||||
@@ -570,10 +592,6 @@ static int efi_block_filename ( unsigned int drive, EFI_HANDLE handle,
|
|||||||
|
|
||||||
file->Close ( file );
|
file->Close ( file );
|
||||||
err_file:
|
err_file:
|
||||||
root->Close ( root );
|
|
||||||
err_volume:
|
|
||||||
bs->CloseProtocol ( handle, protocol, efi_image_handle, handle );
|
|
||||||
err_open:
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -597,6 +615,7 @@ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle,
|
|||||||
EFI_DEVICE_PATH_PROTOCOL *path;
|
EFI_DEVICE_PATH_PROTOCOL *path;
|
||||||
void *interface;
|
void *interface;
|
||||||
} u;
|
} u;
|
||||||
|
EFI_FILE *root;
|
||||||
union uuid guid;
|
union uuid guid;
|
||||||
EFI_STATUS efirc;
|
EFI_STATUS efirc;
|
||||||
int rc;
|
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 */
|
/* Check if filesystem contains boot filename */
|
||||||
if ( ( rc = efi_block_filename ( drive, handle,
|
if ( ( rc = efi_block_filename ( drive, handle, root,
|
||||||
config->filename ) ) != 0 ) {
|
config->filename ) ) != 0 ) {
|
||||||
goto err_filename;
|
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 */
|
/* Success */
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
|
||||||
|
err_extra:
|
||||||
err_filename:
|
err_filename:
|
||||||
|
root->Close ( root );
|
||||||
|
err_root:
|
||||||
err_wrong_guid:
|
err_wrong_guid:
|
||||||
err_no_guid:
|
err_no_guid:
|
||||||
err_not_child:
|
err_not_child:
|
||||||
|
|||||||
Reference in New Issue
Block a user