Merge pull request #7 from marineam/gptprio

Generic GPT partition search commands
This commit is contained in:
Michael Marineau 2014-12-05 16:46:27 -08:00
commit 4f35e11003
11 changed files with 326 additions and 25 deletions

View file

@ -1244,6 +1244,8 @@ program = {
name = gpt_unit_test;
common = tests/gpt_unit_test.c;
common = tests/lib/unit_test.c;
common = grub-core/commands/search_part_label.c;
common = grub-core/commands/search_part_uuid.c;
common = grub-core/disk/host.c;
common = grub-core/kern/emu/hostfs.c;
common = grub-core/lib/gpt.c;

View file

@ -1020,6 +1020,16 @@ module = {
common = commands/search_label.c;
};
module = {
name = search_part_uuid;
common = commands/search_part_uuid.c;
};
module = {
name = search_part_label;
common = commands/search_part_label.c;
};
module = {
name = setpci;
common = commands/setpci.c;

View file

@ -141,20 +141,8 @@ grub_find_next (const char *disk_name,
if (!*part_name)
goto done;
*part_guid =
grub_xasprintf ("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
grub_le_to_cpu32 (part_found->guid.data1),
grub_le_to_cpu16 (part_found->guid.data2),
grub_le_to_cpu16 (part_found->guid.data3),
part_found->guid.data4[0],
part_found->guid.data4[1],
part_found->guid.data4[2],
part_found->guid.data4[3],
part_found->guid.data4[4],
part_found->guid.data4[5],
part_found->guid.data4[6],
part_found->guid.data4[7]);
if (!*part_name)
*part_guid = grub_gpt_guid_to_str (&part_found->guid);
if (!*part_guid)
goto done;
grub_errno = GRUB_ERR_NONE;

View file

@ -30,6 +30,9 @@
#include <grub/i18n.h>
#include <grub/disk.h>
#include <grub/partition.h>
#if defined(DO_SEARCH_PART_UUID) || defined(DO_SEARCH_PART_LABEL)
#include <grub/gpt_partition.h>
#endif
GRUB_MOD_LICENSE ("GPLv3+");
@ -90,6 +93,44 @@ iterate_device (const char *name, void *data)
}
grub_free (buf);
}
#elif defined(DO_SEARCH_PART_UUID)
{
grub_device_t dev;
char *quid;
dev = grub_device_open (name);
if (dev)
{
if (grub_gpt_part_uuid (dev, &quid) == GRUB_ERR_NONE)
{
if (grub_strcasecmp (quid, ctx->key) == 0)
found = 1;
grub_free (quid);
}
grub_device_close (dev);
}
}
#elif defined(DO_SEARCH_PART_LABEL)
{
grub_device_t dev;
char *quid;
dev = grub_device_open (name);
if (dev)
{
if (grub_gpt_part_label (dev, &quid) == GRUB_ERR_NONE)
{
if (grub_strcmp (quid, ctx->key) == 0)
found = 1;
grub_free (quid);
}
grub_device_close (dev);
}
}
#else
{
/* SEARCH_FS_UUID or SEARCH_LABEL */
@ -313,6 +354,10 @@ static grub_command_t cmd;
#ifdef DO_SEARCH_FILE
GRUB_MOD_INIT(search_fs_file)
#elif defined(DO_SEARCH_PART_UUID)
GRUB_MOD_INIT(search_part_uuid)
#elif defined(DO_SEARCH_PART_LABEL)
GRUB_MOD_INIT(search_part_label)
#elif defined (DO_SEARCH_FS_UUID)
GRUB_MOD_INIT(search_fs_uuid)
#else
@ -327,6 +372,10 @@ GRUB_MOD_INIT(search_label)
#ifdef DO_SEARCH_FILE
GRUB_MOD_FINI(search_fs_file)
#elif defined(DO_SEARCH_PART_UUID)
GRUB_MOD_FINI(search_part_uuid)
#elif defined(DO_SEARCH_PART_LABEL)
GRUB_MOD_FINI(search_part_label)
#elif defined (DO_SEARCH_FS_UUID)
GRUB_MOD_FINI(search_fs_uuid)
#else

View file

@ -0,0 +1,5 @@
#define DO_SEARCH_PART_LABEL 1
#define FUNC_NAME grub_search_part_label
#define COMMAND_NAME "search.part_label"
#define HELP_MESSAGE N_("Search devices by partition label. If VARIABLE is specified, the first device found is set to a variable.")
#include "search.c"

View file

@ -0,0 +1,5 @@
#define DO_SEARCH_PART_UUID 1
#define FUNC_NAME grub_search_part_uuid
#define COMMAND_NAME "search.part_uuid"
#define HELP_MESSAGE N_("Search devices by partition UUID. If VARIABLE is specified, the first device found is set to a variable.")
#include "search.c"

View file

@ -36,6 +36,10 @@ static const struct grub_arg_option options[] =
0, 0},
{"fs-uuid", 'u', 0, N_("Search devices by a filesystem UUID."),
0, 0},
{"part-label", 'L', 0, N_("Search devices by a partition label."),
0, 0},
{"part-uuid", 'U', 0, N_("Search devices by a partition UUID."),
0, 0},
{"set", 's', GRUB_ARG_OPTION_OPTIONAL,
N_("Set a variable to the first device found."), N_("VARNAME"),
ARG_TYPE_STRING},
@ -71,6 +75,8 @@ enum options
SEARCH_FILE,
SEARCH_LABEL,
SEARCH_FS_UUID,
SEARCH_PART_LABEL,
SEARCH_PART_UUID,
SEARCH_SET,
SEARCH_NO_FLOPPY,
SEARCH_HINT,
@ -183,6 +189,12 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
else if (state[SEARCH_FS_UUID].set)
grub_search_fs_uuid (id, var, state[SEARCH_NO_FLOPPY].set,
hints, nhints);
else if (state[SEARCH_PART_LABEL].set)
grub_search_part_label (id, var, state[SEARCH_NO_FLOPPY].set,
hints, nhints);
else if (state[SEARCH_PART_UUID].set)
grub_search_part_uuid (id, var, state[SEARCH_NO_FLOPPY].set,
hints, nhints);
else if (state[SEARCH_FILE].set)
grub_search_fs_file (id, var, state[SEARCH_NO_FLOPPY].set,
hints, nhints);

View file

@ -18,7 +18,9 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/charset.h>
#include <grub/crypto.h>
#include <grub/device.h>
#include <grub/disk.h>
#include <grub/misc.h>
#include <grub/mm.h>
@ -31,6 +33,81 @@ GRUB_MOD_LICENSE ("GPLv3+");
static grub_uint8_t grub_gpt_magic[] = GRUB_GPT_HEADER_MAGIC;
char *
grub_gpt_guid_to_str (grub_gpt_guid_t *guid)
{
return grub_xasprintf ("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
grub_le_to_cpu32 (guid->data1),
grub_le_to_cpu16 (guid->data2),
grub_le_to_cpu16 (guid->data3),
guid->data4[0], guid->data4[1],
guid->data4[2], guid->data4[3],
guid->data4[4], guid->data4[5],
guid->data4[6], guid->data4[7]);
}
static grub_err_t
grub_gpt_device_partentry (grub_device_t device,
struct grub_gpt_partentry *entry)
{
grub_disk_t disk = device->disk;
grub_partition_t p;
grub_err_t err;
if (!disk || !disk->partition)
return grub_error (GRUB_ERR_BUG, "not a partition");
if (grub_strcmp (disk->partition->partmap->name, "gpt"))
return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a GPT partition");
p = disk->partition;
disk->partition = p->parent;
err = grub_disk_read (disk, p->offset, p->index, sizeof (*entry), entry);
disk->partition = p;
return err;
}
grub_err_t
grub_gpt_part_label (grub_device_t device, char **label)
{
struct grub_gpt_partentry entry;
const grub_size_t name_len = ARRAY_SIZE (entry.name);
const grub_size_t label_len = name_len * GRUB_MAX_UTF8_PER_UTF16 + 1;
grub_size_t i;
grub_uint8_t *end;
if (grub_gpt_device_partentry (device, &entry))
return grub_errno;
*label = grub_malloc (label_len);
if (!*label)
return grub_errno;
for (i = 0; i < name_len; i++)
entry.name[i] = grub_le_to_cpu16 (entry.name[i]);
end = grub_utf16_to_utf8 ((grub_uint8_t *) *label, entry.name, name_len);
*end = '\0';
return GRUB_ERR_NONE;
}
grub_err_t
grub_gpt_part_uuid (grub_device_t device, char **uuid)
{
struct grub_gpt_partentry entry;
if (grub_gpt_device_partentry (device, &entry))
return grub_errno;
*uuid = grub_gpt_guid_to_str (&entry.guid);
if (!*uuid)
return grub_errno;
return GRUB_ERR_NONE;
}
static grub_uint64_t
grub_gpt_size_to_sectors (grub_gpt_t gpt, grub_size_t size)
{

View file

@ -33,6 +33,10 @@ struct grub_gpt_guid
typedef struct grub_gpt_guid grub_gpt_guid_t;
typedef struct grub_gpt_guid grub_gpt_part_type_t;
/* Format the raw little-endian GUID as a newly allocated string. */
char * grub_gpt_guid_to_str (grub_gpt_guid_t *guid);
#define GRUB_GPT_GUID_INIT(a, b, c, d1, d2, d3, d4, d5, d6, d7, d8) \
{ \
grub_cpu_to_le32_compile_time (a), \
@ -45,6 +49,10 @@ typedef struct grub_gpt_guid grub_gpt_part_type_t;
GRUB_GPT_GUID_INIT (0x0, 0x0, 0x0, \
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
#define GRUB_GPT_PARTITION_TYPE_EFI_SYSTEM \
GRUB_GPT_GUID_INIT (0xc12a7328, 0xf81f, 0x11d2, \
0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b)
#define GRUB_GPT_PARTITION_TYPE_BIOS_BOOT \
GRUB_GPT_GUID_INIT (0x21686148, 0x6449, 0x6e6f, \
0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49)
@ -88,7 +96,7 @@ struct grub_gpt_partentry
grub_uint64_t start;
grub_uint64_t end;
grub_uint64_t attrib;
char name[72];
grub_uint16_t name[36];
} GRUB_PACKED;
enum grub_gpt_part_attr_offset
@ -212,4 +220,16 @@ grub_err_t grub_gpt_pmbr_check (struct grub_msdos_partition_mbr *mbr);
grub_err_t grub_gpt_header_check (struct grub_gpt_header *gpt,
unsigned int log_sector_size);
/* Utilities for simple partition data lookups, usage is intended to
* be similar to fs->label and fs->uuid functions. */
/* Return the partition label of the device DEVICE in LABEL.
* The label is in a new buffer and should be freed by the caller. */
grub_err_t grub_gpt_part_label (grub_device_t device, char **label);
/* Return the partition uuid of the device DEVICE in UUID.
* The label is in a new buffer and should be freed by the caller. */
grub_err_t grub_gpt_part_uuid (grub_device_t device, char **uuid);
#endif /* ! GRUB_GPT_PARTITION_HEADER */

View file

@ -25,5 +25,9 @@ void grub_search_fs_uuid (const char *key, const char *var, int no_floppy,
char **hints, unsigned nhints);
void grub_search_label (const char *key, const char *var, int no_floppy,
char **hints, unsigned nhints);
void grub_search_part_uuid (const char *key, const char *var, int no_floppy,
char **hints, unsigned nhints);
void grub_search_part_label (const char *key, const char *var, int no_floppy,
char **hints, unsigned nhints);
#endif

View file

@ -21,10 +21,12 @@
#include <grub/disk.h>
#include <grub/emu/hostdisk.h>
#include <grub/emu/misc.h>
#include <grub/env.h>
#include <grub/err.h>
#include <grub/gpt_partition.h>
#include <grub/msdos_partition.h>
#include <grub/lib/hexdump.h>
#include <grub/search.h>
#include <grub/test.h>
#include <errno.h>
@ -89,12 +91,12 @@ struct test_data
};
/* Sample primary GPT header for an empty 1MB disk. */
/* Sample primary GPT header for a 1MB disk. */
static const struct grub_gpt_header example_primary = {
.magic = GRUB_GPT_HEADER_MAGIC,
.version = GRUB_GPT_HEADER_VERSION,
.headersize = sizeof (struct grub_gpt_header),
.crc32 = grub_cpu_to_le32_compile_time (0x7cd8642c),
.crc32 = grub_cpu_to_le32_compile_time (0xb985abe0),
.header_lba = grub_cpu_to_le64_compile_time (PRIMARY_HEADER_SECTOR),
.alternate_lba = grub_cpu_to_le64_compile_time (BACKUP_HEADER_SECTOR),
.start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR),
@ -104,7 +106,52 @@ static const struct grub_gpt_header example_primary = {
.partitions = grub_cpu_to_le64_compile_time (PRIMARY_TABLE_SECTOR),
.maxpart = grub_cpu_to_le32_compile_time (TABLE_ENTRIES),
.partentry_size = grub_cpu_to_le32_compile_time (ENTRY_SIZE),
.partentry_crc32 = grub_cpu_to_le32_compile_time (0xab54d286),
.partentry_crc32 = grub_cpu_to_le32_compile_time (0x074e052c),
};
static const struct grub_gpt_partentry example_entries[TABLE_ENTRIES] = {
{
.type = GRUB_GPT_PARTITION_TYPE_EFI_SYSTEM,
.guid = GRUB_GPT_GUID_INIT (0xa0f1792e, 0xb4ce, 0x4136, 0xbc, 0xf2,
0x1a, 0xfc, 0x13, 0x3c, 0x28, 0x28),
.start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR),
.end = grub_cpu_to_le64_compile_time (0x3f),
.attrib = 0x0,
.name = {
grub_cpu_to_le16_compile_time ('E'),
grub_cpu_to_le16_compile_time ('F'),
grub_cpu_to_le16_compile_time ('I'),
grub_cpu_to_le16_compile_time (' '),
grub_cpu_to_le16_compile_time ('S'),
grub_cpu_to_le16_compile_time ('Y'),
grub_cpu_to_le16_compile_time ('S'),
grub_cpu_to_le16_compile_time ('T'),
grub_cpu_to_le16_compile_time ('E'),
grub_cpu_to_le16_compile_time ('M'),
0x0,
}
},
{
.type = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT,
.guid = GRUB_GPT_GUID_INIT (0x876c898d, 0x1b40, 0x4727, 0xa1, 0x61,
0xed, 0xf9, 0xb5, 0x48, 0x66, 0x74),
.start = grub_cpu_to_le64_compile_time (0x40),
.end = grub_cpu_to_le64_compile_time (0x7f),
.attrib = grub_cpu_to_le64_compile_time (
1ULL << GRUB_GPT_PART_ATTR_OFFSET_LEGACY_BIOS_BOOTABLE),
.name = {
grub_cpu_to_le16_compile_time ('B'),
grub_cpu_to_le16_compile_time ('I'),
grub_cpu_to_le16_compile_time ('O'),
grub_cpu_to_le16_compile_time ('S'),
grub_cpu_to_le16_compile_time (' '),
grub_cpu_to_le16_compile_time ('B'),
grub_cpu_to_le16_compile_time ('O'),
grub_cpu_to_le16_compile_time ('O'),
grub_cpu_to_le16_compile_time ('T'),
0x0,
}
},
};
/* And the backup header. */
@ -112,7 +159,7 @@ static const struct grub_gpt_header example_backup = {
.magic = GRUB_GPT_HEADER_MAGIC,
.version = GRUB_GPT_HEADER_VERSION,
.headersize = sizeof (struct grub_gpt_header),
.crc32 = grub_cpu_to_le32_compile_time (0xcfaa4a27),
.crc32 = grub_cpu_to_le32_compile_time (0x0af785eb),
.header_lba = grub_cpu_to_le64_compile_time (BACKUP_HEADER_SECTOR),
.alternate_lba = grub_cpu_to_le64_compile_time (PRIMARY_HEADER_SECTOR),
.start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR),
@ -122,7 +169,7 @@ static const struct grub_gpt_header example_backup = {
.partitions = grub_cpu_to_le64_compile_time (BACKUP_TABLE_SECTOR),
.maxpart = grub_cpu_to_le32_compile_time (TABLE_ENTRIES),
.partentry_size = grub_cpu_to_le32_compile_time (ENTRY_SIZE),
.partentry_crc32 = grub_cpu_to_le32_compile_time (0xab54d286),
.partentry_crc32 = grub_cpu_to_le32_compile_time (0x074e052c),
};
/* Sample protective MBR for the same 1MB disk. Note, this matches
@ -192,6 +239,10 @@ reset_disk (struct test_data *data)
memcpy (&data->raw->mbr, &example_pmbr, sizeof (data->raw->mbr));
memcpy (&data->raw->primary_header, &example_primary,
sizeof (data->raw->primary_header));
memcpy (&data->raw->primary_entries, &example_entries,
sizeof (data->raw->primary_entries));
memcpy (&data->raw->backup_entries, &example_entries,
sizeof (data->raw->backup_entries));
memcpy (&data->raw->backup_header, &example_backup,
sizeof (data->raw->backup_header));
@ -270,11 +321,7 @@ read_disk (struct test_data *data)
gpt = grub_gpt_read (data->dev->disk);
if (gpt == NULL)
{
grub_print_error ();
grub_fatal ("grub_gpt_read failed");
}
grub_fatal ("grub_gpt_read failed: %s", grub_errmsg);
return gpt;
}
@ -489,6 +536,84 @@ repair_test (void)
close_disk (&data);
}
static void
search_label_test (void)
{
struct test_data data;
const char *test_result;
char *expected_result;
open_disk (&data);
expected_result = grub_xasprintf ("%s,gpt1", data.dev->disk->name);
grub_env_unset ("test_result");
grub_search_part_label ("EFI SYSTEM", "test_result", 0, NULL, 0);
test_result = grub_env_get ("test_result");
grub_test_assert (test_result && strcmp (test_result, expected_result) == 0,
"wrong device: %s (%s)", test_result, expected_result);
grub_free (expected_result);
expected_result = grub_xasprintf ("%s,gpt2", data.dev->disk->name);
grub_env_unset ("test_result");
grub_search_part_label ("BIOS BOOT", "test_result", 0, NULL, 0);
test_result = grub_env_get ("test_result");
grub_test_assert (test_result && strcmp (test_result, expected_result) == 0,
"wrong device: %s (%s)", test_result, expected_result);
grub_free (expected_result);
grub_env_unset ("test_result");
grub_search_part_label ("bogus name", "test_result", 0, NULL, 0);
test_result = grub_env_get ("test_result");
grub_test_assert (test_result == NULL,
"unexpected device: %s", test_result);
grub_test_assert (grub_errno == GRUB_ERR_FILE_NOT_FOUND,
"unexpected error: %s", grub_errmsg);
grub_errno = GRUB_ERR_NONE;
close_disk (&data);
}
static void
search_uuid_test (void)
{
struct test_data data;
const char gpt1_uuid[] = "A0F1792E-B4CE-4136-BCF2-1AFC133C2828";
const char gpt2_uuid[] = "876c898d-1b40-4727-a161-edf9b5486674";
const char bogus_uuid[] = "1534c928-c50e-4866-9daf-6a9fd7918a76";
const char *test_result;
char *expected_result;
open_disk (&data);
expected_result = grub_xasprintf ("%s,gpt1", data.dev->disk->name);
grub_env_unset ("test_result");
grub_search_part_uuid (gpt1_uuid, "test_result", 0, NULL, 0);
test_result = grub_env_get ("test_result");
grub_test_assert (test_result && strcmp (test_result, expected_result) == 0,
"wrong device: %s (%s)", test_result, expected_result);
grub_free (expected_result);
expected_result = grub_xasprintf ("%s,gpt2", data.dev->disk->name);
grub_env_unset ("test_result");
grub_search_part_uuid (gpt2_uuid, "test_result", 0, NULL, 0);
test_result = grub_env_get ("test_result");
grub_test_assert (test_result && strcmp (test_result, expected_result) == 0,
"wrong device: %s (%s)", test_result, expected_result);
grub_free (expected_result);
grub_env_unset ("test_result");
grub_search_part_uuid (bogus_uuid, "test_result", 0, NULL, 0);
test_result = grub_env_get ("test_result");
grub_test_assert (test_result == NULL,
"unexpected device: %s", test_result);
grub_test_assert (grub_errno == GRUB_ERR_FILE_NOT_FOUND,
"unexpected error: %s", grub_errmsg);
grub_errno = GRUB_ERR_NONE;
close_disk (&data);
}
void
grub_unit_test_init (void)
{
@ -501,6 +626,8 @@ grub_unit_test_init (void)
grub_test_register ("gpt_read_invalid_test", read_invalid_entries_test);
grub_test_register ("gpt_read_fallback_test", read_fallback_test);
grub_test_register ("gpt_repair_test", repair_test);
grub_test_register ("gpt_search_label_test", search_label_test);
grub_test_register ("gpt_search_uuid_test", search_uuid_test);
}
void
@ -512,5 +639,7 @@ grub_unit_test_fini (void)
grub_test_unregister ("gpt_read_invalid_test");
grub_test_unregister ("gpt_read_fallback_test");
grub_test_unregister ("gpt_repair_test");
grub_test_unregister ("gpt_search_label_test");
grub_test_unregister ("gpt_search_uuid_test");
grub_fini_all ();
}