From 486486e19abcbf3c9d49369ab056bafa00a94cf8 Mon Sep 17 00:00:00 2001 From: Leandro Dorileo Date: Thu, 12 Sep 2019 12:12:28 -0700 Subject: [PATCH] bootman: improve filesystem detection Improve the internal filesystem detection, with these changes we can reuse this code elsewhere and be more efficient - other areas needing the filesystem knowledge can use this mapping strategies adding a more precise and centralized code to that. This patch also makes sure to keep tests and filesystem checks more consistent. When mounting we were assuming the /boot filesystem to always be vfat, with this code now we can have /boot partitions with whatever filesystem we support (for now: vfat, ext[2-4]). Signed-off-by: Leandro Dorileo --- src/bootman/bootman.c | 8 +- src/bootman/bootman.h | 7 ++ src/bootman/bootman_private.h | 5 ++ src/bootman/sysconfig.c | 149 +++++++++++++++++++++++--------- tests/check-core.c | 2 +- tests/check-grub2.c | 2 +- tests/check-legacy.c | 2 +- tests/check-probe.c | 2 +- tests/check-select-bootloader.c | 18 ++-- tests/check-syslinux.c | 2 +- tests/check-uefi.c | 2 +- 11 files changed, 142 insertions(+), 57 deletions(-) diff --git a/src/bootman/bootman.c b/src/bootman/bootman.c index 6a58e2b..6b3b1fe 100644 --- a/src/bootman/bootman.c +++ b/src/bootman/bootman.c @@ -414,6 +414,7 @@ int mount_boot(BootManager *self, char **boot_directory) autofree(char) *boot_dir = NULL; int ret = -1; char *root_base = NULL; + const char *fs_name = NULL; if (!boot_directory) { goto out; @@ -481,7 +482,12 @@ int mount_boot(BootManager *self, char **boot_directory) } LOG_INFO("Mounting boot device %s at %s", root_base, boot_dir); - if (cbm_system_mount(root_base, boot_dir, "vfat", MS_MGC_VAL, "") < 0) { + + fs_name = cbm_get_fstype_name(root_base); + CHECK_FATAL_GOTO(!fs_name, out, "Could not determine fstype of: %s", + root_base); + + if (cbm_system_mount(root_base, boot_dir, fs_name, MS_MGC_VAL, "") < 0) { LOG_FATAL("FATAL: Cannot mount boot device %s on %s: %s", root_base, boot_dir, diff --git a/src/bootman/bootman.h b/src/bootman/bootman.h index 258fef5..2ef205d 100644 --- a/src/bootman/bootman.h +++ b/src/bootman/bootman.h @@ -29,6 +29,13 @@ typedef enum { BOOTLOADER_OPERATION_MAX = 1 << 5 } BootLoaderOperation; +typedef enum { + FSTYPE_VFAT = 1 << 0, + FSTYPE_EXT2 = 1 << 1, + FSTYPE_EXT3 = 1 << 2, + FSTYPE_EXT4 = 1 << 3, +} FilesystemType; + /** * Maximum length for each component in a kernel identifier */ diff --git a/src/bootman/bootman_private.h b/src/bootman/bootman_private.h index d71d033..9efb987 100644 --- a/src/bootman/bootman_private.h +++ b/src/bootman/bootman_private.h @@ -74,6 +74,11 @@ int detect_and_mount_boot(BootManager *self, char **boot_dir); */ int kernel_compare_reverse(const void *a, const void *b); +/** + * Given a boot_device returns the filesystem name, if unknown filesystem returns NULL. + */ +const char *cbm_get_fstype_name(const char *boot_device); + /* * Editor modelines - https://www.wireshark.org/tools/modelines.html * diff --git a/src/bootman/sysconfig.c b/src/bootman/sysconfig.c index bf4ff4f..2594d30 100644 --- a/src/bootman/sysconfig.c +++ b/src/bootman/sysconfig.c @@ -28,6 +28,30 @@ #define CBM_BOOTVAR_TEST_MODE_VAR "CBM_BOOTVAR_TEST_MODE" +struct FilesystemMap { + char *name; + int id; +}; + +static const struct FilesystemMap _fsmap[] = { + { + .id = FSTYPE_VFAT, + .name = "vfat", + }, + { + .id = FSTYPE_EXT2, + .name = "ext2", + }, + { + .id = FSTYPE_EXT3, + .name = "ext3", + }, + { + .id = FSTYPE_EXT4, + .name = "ext4", + }, +}; + void cbm_free_sysconfig(SystemConfig *config) { if (!config) { @@ -39,51 +63,94 @@ void cbm_free_sysconfig(SystemConfig *config) free(config); } -int cbm_get_fstype(const char *boot_device) +static const struct FilesystemMap *cbm_find_fstype(const char *fsname) { - int rc; - blkid_probe pr; - const char *data; - int ret = 0; + int i; + int length = sizeof(_fsmap) / sizeof(struct FilesystemMap); + + for (i = 0; i < length; i++) { + const struct FilesystemMap *curr = &_fsmap[i]; + if (!strcmp(curr->name, fsname)) { + return curr; + } + } + + return NULL; +} + +static const struct FilesystemMap *cbm_get_fstype(const char *boot_device) +{ + autofree(char) *fsname = NULL; + const struct FilesystemMap *fs; /* Test suite will set the CBM_TEST_FSTYPE env var and inform the wanted fstype */ - char *test_mode_fs_type_env = getenv("CBM_TEST_FSTYPE"); - if (test_mode_fs_type_env && !strncmp(test_mode_fs_type_env, "EXTFS", 5)) { - return BOOTLOADER_CAP_EXTFS; - } else if (test_mode_fs_type_env && !strncmp(test_mode_fs_type_env, "FATFS", 5)) { + fsname = getenv("CBM_TEST_FSTYPE"); + if (fsname) { + fsname = strdup(fsname); + } else { + int rc; + blkid_probe pr; + const char *tmp; + + pr = blkid_new_probe_from_filename(boot_device); + if (!pr) { + LOG_ERROR("%s: failed to create a new libblkid probe", + boot_device); + exit(EXIT_FAILURE); + } + + blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_TYPE); + rc = blkid_do_safeprobe(pr); + if (rc != 0) { + LOG_ERROR("%s: blkid_do_safeprobe() failed", boot_device); + exit(EXIT_FAILURE); + } + + rc = blkid_probe_lookup_value(pr, "TYPE", &tmp, NULL); + if (rc != 0 || tmp == NULL || strlen(tmp) == 0) { + LOG_ERROR("%s: blkid_probe_lookup_value() failed", boot_device); + exit(EXIT_FAILURE); + } + + fsname = strdup(tmp); + if (fsname == NULL) { + DECLARE_OOM(); + exit(EXIT_FAILURE); + } + + blkid_free_probe(pr); + } + + fs = cbm_find_fstype(fsname); + CHECK_DBG_RET_VAL(!fs, NULL, "Failed to find fstype for: %s(%s)", boot_device, fsname); + + return fs; +} + +const char *cbm_get_fstype_name(const char *boot_device) +{ + const struct FilesystemMap *fs = cbm_get_fstype(boot_device); + CHECK_DBG_RET_VAL(!fs, NULL, "Unknown Filesystem of: %s", boot_device); + return fs->name; +} + +int cbm_get_filesystem_cap(const char *boot_device) +{ + const struct FilesystemMap *fs = NULL; + + fs = cbm_get_fstype(boot_device); + CHECK_DBG_RET_VAL(!fs, 0, "Could not find filesystem map for: %s", boot_device); + + switch (fs->id) { + case FSTYPE_VFAT: return BOOTLOADER_CAP_FATFS; + case FSTYPE_EXT2: + case FSTYPE_EXT3: + case FSTYPE_EXT4: + return BOOTLOADER_CAP_EXTFS; + default: + return 0; } - - pr = blkid_new_probe_from_filename(boot_device); - if (!pr) { - LOG_ERROR("%s: failed to create a new libblkid probe", - boot_device); - exit(EXIT_FAILURE); - } - - blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_TYPE); - rc = blkid_do_safeprobe(pr); - if (rc != 0) { - LOG_ERROR("%s: blkid_do_safeprobe() failed", boot_device); - exit(EXIT_FAILURE); - } - - rc = blkid_probe_lookup_value(pr, "TYPE", &data, NULL); - if (rc != 0) { - LOG_ERROR("%s: blkid_probe_lookup_value() failed", boot_device); - exit(EXIT_FAILURE); - } - - if ((strcmp(data, "ext2") == 0) || - (strcmp(data, "ext3") == 0) || - (strcmp(data, "ext4") == 0)) - ret = BOOTLOADER_CAP_EXTFS; - else if (strcmp(data, "vfat") == 0) - ret = BOOTLOADER_CAP_FATFS; - - blkid_free_probe(pr); - - return ret; } static void cmb_inspect_root_native(SystemConfig *c, char *realp) { @@ -189,7 +256,7 @@ SystemConfig *cbm_inspect_root(const char *path, bool image_mode) c->wanted_boot_mask |= BOOTLOADER_CAP_GPT; /* determine fstype of the boot_device */ - c->wanted_boot_mask |= cbm_get_fstype(c->boot_device); + c->wanted_boot_mask |= cbm_get_filesystem_cap(c->boot_device); } c->root_device = cbm_probe_path(realp); diff --git a/tests/check-core.c b/tests/check-core.c index 4e304d6..0d98b33 100644 --- a/tests/check-core.c +++ b/tests/check-core.c @@ -434,7 +434,7 @@ int main(void) setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1); /* Force detection of `fat` filesystem. */ - setenv("CBM_TEST_FSTYPE", "FATFS", 1); + setenv("CBM_TEST_FSTYPE", "vfat", 1); cbm_blkid_set_vtable(&BlkidTestOps); cbm_system_set_vtable(&SystemTestOps); diff --git a/tests/check-grub2.c b/tests/check-grub2.c index f83bd7e..d62abaa 100644 --- a/tests/check-grub2.c +++ b/tests/check-grub2.c @@ -265,7 +265,7 @@ int main(void) setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1); /* Force detection of `ext` filesystem. */ - setenv("CBM_TEST_FSTYPE", "EXTFS", 1); + setenv("CBM_TEST_FSTYPE", "ext4", 1); cbm_blkid_set_vtable(&blkid_ops); cbm_system_set_vtable(&SystemTestOps); diff --git a/tests/check-legacy.c b/tests/check-legacy.c index 5da7a34..07f10dd 100644 --- a/tests/check-legacy.c +++ b/tests/check-legacy.c @@ -304,7 +304,7 @@ int main(void) setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1); /* Force detection of `ext` filesystem. */ - setenv("CBM_TEST_FSTYPE", "EXTFS", 1); + setenv("CBM_TEST_FSTYPE", "ext4", 1); cbm_blkid_set_vtable(&blkid_ops); cbm_system_set_vtable(&SystemTestOps); diff --git a/tests/check-probe.c b/tests/check-probe.c index e3c2a4a..321ab6d 100644 --- a/tests/check-probe.c +++ b/tests/check-probe.c @@ -245,7 +245,7 @@ int main(void) setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1); /* Force detection of `fat` filesystem. */ - setenv("CBM_TEST_FSTYPE", "FATFS", 1); + setenv("CBM_TEST_FSTYPE", "vfat", 1); s = core_suite(); sr = srunner_create(s); diff --git a/tests/check-select-bootloader.c b/tests/check-select-bootloader.c index f88485c..6c13c2a 100644 --- a/tests/check-select-bootloader.c +++ b/tests/check-select-bootloader.c @@ -104,7 +104,7 @@ static void nuke_boot_device(struct PlaygroundConfig *config) START_TEST(bootman_select_uefi_native_with_boot) { static PlaygroundConfig config = { "4.2.1-121.kvm", NULL, 0, .uefi = true }; - setenv("CBM_TEST_FSTYPE", "FATFS", 1); + setenv("CBM_TEST_FSTYPE", "vfat", 1); autofree(BootManager) *m = NULL; bootman_select_set_default_vtables(); @@ -119,7 +119,7 @@ END_TEST START_TEST(bootman_select_uefi_native_without_boot) { static PlaygroundConfig config = { "4.2.1-121.kvm", NULL, 0, .uefi = true }; - setenv("CBM_TEST_FSTYPE", "FATFS", 1); + setenv("CBM_TEST_FSTYPE", "vfat", 1); autofree(BootManager) *m = NULL; bootman_select_set_default_vtables(); @@ -138,7 +138,7 @@ END_TEST START_TEST(bootman_select_uefi_image_with_boot) { static PlaygroundConfig config = { "4.2.1-121.kvm", NULL, 0, .uefi = true }; - setenv("CBM_TEST_FSTYPE", "FATFS", 1); + setenv("CBM_TEST_FSTYPE", "vfat", 1); autofree(BootManager) *m = NULL; bootman_select_set_default_vtables(); @@ -156,7 +156,7 @@ END_TEST START_TEST(bootman_select_uefi_image_without_boot) { static PlaygroundConfig config = { "4.2.1-121.kvm", NULL, 0, .uefi = true }; - setenv("CBM_TEST_FSTYPE", "FATFS", 1); + setenv("CBM_TEST_FSTYPE", "vfat", 1); autofree(BootManager) *m = NULL; bootman_select_set_default_vtables(); @@ -240,7 +240,7 @@ static void bootman_select_set_legacy_vtables(void) START_TEST(bootman_select_extlinux_native_with_boot) { PlaygroundConfig config = { "4.2.1-121.kvm", NULL, 0, .uefi = false }; - setenv("CBM_TEST_FSTYPE", "EXTFS", 1); + setenv("CBM_TEST_FSTYPE", "ext4", 1); autofree(BootManager) *m = NULL; bootman_select_set_legacy_vtables(); @@ -255,7 +255,7 @@ END_TEST START_TEST(bootman_select_extlinux_image_with_boot) { PlaygroundConfig config = { "4.2.1-121.kvm", NULL, 0, .uefi = false }; - setenv("CBM_TEST_FSTYPE", "EXTFS", 1); + setenv("CBM_TEST_FSTYPE", "ext4", 1); autofree(BootManager) *m = NULL; bootman_select_set_legacy_vtables(); @@ -330,7 +330,7 @@ static void bootman_select_set_grub2_vtables(void) START_TEST(bootman_select_grub2_native_without_boot) { static PlaygroundConfig config = { "4.2.1-121.kvm", NULL, 0, .uefi = false }; - setenv("CBM_TEST_FSTYPE", "EXTFS", 1); + setenv("CBM_TEST_FSTYPE", "ext4", 1); autofree(BootManager) *m = NULL; bootman_select_set_grub2_vtables(); @@ -355,7 +355,7 @@ END_TEST START_TEST(bootman_select_edge_uefi_with_legacy_part_native) { static PlaygroundConfig config = { "4.2.1-121.kvm", NULL, 0, .uefi = false }; - setenv("CBM_TEST_FSTYPE", "EXTFS", 1); + setenv("CBM_TEST_FSTYPE", "ext4", 1); autofree(BootManager) *m = NULL; bootman_select_set_legacy_vtables(); @@ -378,7 +378,7 @@ END_TEST START_TEST(bootman_select_edge_uefi_with_legacy_part_image) { static PlaygroundConfig config = { "4.2.1-121.kvm", NULL, 0, .uefi = false }; - setenv("CBM_TEST_FSTYPE", "EXTFS", 1); + setenv("CBM_TEST_FSTYPE", "ext4", 1); autofree(BootManager) *m = NULL; bootman_select_set_legacy_vtables(); diff --git a/tests/check-syslinux.c b/tests/check-syslinux.c index e6c917e..80c81e1 100644 --- a/tests/check-syslinux.c +++ b/tests/check-syslinux.c @@ -304,7 +304,7 @@ int main(void) setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1); /* Force detection of `ext` filesystem. */ - setenv("CBM_TEST_FSTYPE", "EXTFS", 1); + setenv("CBM_TEST_FSTYPE", "ext4", 1); cbm_blkid_set_vtable(&blkid_ops); cbm_system_set_vtable(&SystemTestOps); diff --git a/tests/check-uefi.c b/tests/check-uefi.c index 90ac9f7..04a3f8e 100644 --- a/tests/check-uefi.c +++ b/tests/check-uefi.c @@ -638,7 +638,7 @@ int main(void) setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1); /* Force detection of `fat` filesystem. */ - setenv("CBM_TEST_FSTYPE", "FATFS", 1); + setenv("CBM_TEST_FSTYPE", "vfat", 1); cbm_blkid_set_vtable(&BlkidTestOps); cbm_system_set_vtable(&SystemTestOps);