Files
Leandro Dorileo 486486e19a 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 <leandro.maciel.dorileo@intel.com>
2019-09-17 15:08:18 -07:00

298 lines
10 KiB
C

/*
* This file is part of clr-boot-manager.
*
* Copyright © 2016-2018 Intel Corporation
*
* clr-boot-manager is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*/
#define _GNU_SOURCE
#include <check.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "bootman.h"
#include "config.h"
#include "files.h"
#include "log.h"
#include "nica/array.h"
#include "nica/files.h"
#include "util.h"
#include "writer.h"
#include "blkid-harness.h"
#include "harness.h"
#include "system-harness.h"
#define PLAYGROUND_ROOT TOP_BUILD_DIR "/tests/update_playground"
#define BOOT_FULL PLAYGROUND_ROOT "/" BOOT_DIRECTORY
/**
* We only permit UUID in our tests.
*/
static int grub2_blkid_probe_lookup_value(__cbm_unused__ blkid_probe pr, const char *name,
const char **data, size_t *len)
{
if (!name || !data) {
return -1;
}
if (streq(name, "UUID")) {
*data = DEFAULT_UUID;
} else {
return -1;
}
if (!*data) {
abort();
}
if (len) {
*len = strlen(*data);
}
return 0;
}
static PlaygroundKernel grub2_kernels[] = { { "4.2.1", "kvm", 121, false, true },
{ "4.2.3", "kvm", 124, true, true },
{ "4.2.1", "native", 137, false, true },
{ "4.2.3", "native", 138, true, true } };
static PlaygroundConfig grub2_config = { "4.2.1-121.kvm",
grub2_kernels,
ARRAY_SIZE(grub2_kernels),
.uefi = false };
#define PLAYGROUND_ROOT TOP_BUILD_DIR "/tests/update_playground"
START_TEST(bootman_grub2_get_boot_device)
{
autofree(char) *boot_device = NULL;
autofree(BootManager) *m = NULL;
autofree(char) *exp = NULL;
/* Ensure cleanup */
m = prepare_playground(&grub2_config);
boot_device = get_boot_device();
fail_if(boot_device != NULL, "Found incorrect device for Legacy (GRUB2) Boot");
}
END_TEST
START_TEST(bootman_grub2_image)
{
autofree(BootManager) *m = NULL;
m = prepare_playground(&grub2_config);
fail_if(!m, "Failed to prepare update playground");
/* Validate image install */
boot_manager_set_image_mode(m, true);
fail_if(!boot_manager_update(m), "Failed to update image");
}
END_TEST
START_TEST(bootman_grub2_native)
{
autofree(BootManager) *m = NULL;
m = prepare_playground(&grub2_config);
fail_if(!m, "Failed to prepare update playground");
boot_manager_set_image_mode(m, false);
fail_if(!set_kernel_booted(&grub2_kernels[1], true), "Failed to set kernel as booted");
fail_if(!boot_manager_update(m), "Failed to update in native mode");
/* Latest kernel for us */
fail_if(!confirm_kernel_installed(m, &grub2_config, &(grub2_kernels[0])),
"Newest kernel not installed");
/* Running kernel */
fail_if(!confirm_kernel_installed(m, &grub2_config, &(grub2_kernels[1])),
"Newest kernel not installed");
/* This guy isn't supposed to be kept around now */
fail_if(!confirm_kernel_uninstalled(m, &(grub2_kernels[2])),
"Uninteresting kernel shouldn't be kept around.");
}
END_TEST
/**
* This test is designed to perform a system update to a new kernel, when the
* current kernel cannot be detected. This ensures we can perform a transition
* from a non cbm-managed distro to a cbm-managed one.
*
* Scenario:
*
* - Unknown running kernel
* - One initial new kernel from the first update. Has never rebooted.
* - Update: New kernel should be installed
* - "Reboot", then verify running = only kernel on system
*/
START_TEST(bootman_grub2_update_from_unknown)
{
autofree(BootManager) *m = NULL;
PlaygroundKernel kernels[] = { { "4.2.1", "kvm", 121, true, true } };
PlaygroundConfig config = { "4.2.1-121.kvm", kernels, 1, false };
autofree(KernelArray) *pre_kernels = NULL;
autofree(KernelArray) *post_kernels = NULL;
Kernel *running_kernel = NULL;
m = prepare_playground(&config);
fail_if(!m, "Failed to prepare update playground");
boot_manager_set_image_mode(m, false);
/* Hax the uname */
boot_manager_set_uname(m, "unknown-uname");
/* Make sure pre kernels are found */
pre_kernels = boot_manager_get_kernels(m);
fail_if(!pre_kernels, "Failed to find kernels");
fail_if(pre_kernels->len != 1, "Available kernels != 1");
/* Ensure it's not booting */
fail_if(boot_manager_get_running_kernel(m, pre_kernels) != NULL,
"Should not find a running kernel at this point");
/* Attempt update in this configuration */
fail_if(!boot_manager_update(m), "Failed to update single kernel system");
/* Now "reboot" */
fail_if(!boot_manager_set_uname(m, "4.2.1-121.kvm"), "Failed to simulate reboot");
/* Grab new kernels */
post_kernels = boot_manager_get_kernels(m);
fail_if(!post_kernels, "Failed to find kernels after update");
fail_if(post_kernels->len != 1, "Available post kernels != 1");
/* Check running kernel */
running_kernel = boot_manager_get_running_kernel(m, post_kernels);
fail_if(!running_kernel, "Failed to find kernel post reboot");
fail_if(!streq(running_kernel->meta.version, "4.2.1"), "Running kernel is invalid");
}
END_TEST
START_TEST(bootman_grub2_namespace_migration)
{
autofree(BootManager) *m = NULL;
PlaygroundKernel kernels[] = { { "4.2.1", "kvm", 121, false, false },
{ "4.2.3", "kvm", 124, true, false },
{ "4.2.1", "native", 137, false, false },
{ "4.2.3", "native", 138, true, false } };
PlaygroundConfig config = { "4.2.1-121.kvm", kernels, ARRAY_SIZE(kernels), .uefi = false };
m = prepare_playground(&config);
fail_if(!nc_mkdir_p(PLAYGROUND_ROOT "/etc/grub.d", 00755), "Failed to create GRUB dir");
fail_if(!nc_mkdir_p(BOOT_FULL, 00755), "Failed to create boot dir");
/* Manually install a bunch of kernels using their legacy paths */
for (size_t i = 0; i < config.n_kernels; i++) {
PlaygroundKernel *k = &(kernels[i]);
autofree(char) *tgt_path_config = NULL;
tgt_path_config = string_printf("%s/etc/grub.d/10_%s_%s-%d.%s",
PLAYGROUND_ROOT,
boot_manager_get_os_id(m),
k->version,
k->release,
k->ktype);
fail_if(!file_set_text(tgt_path_config, "Placeholder config"),
"Failed to write legacy GRUB2 config file");
}
/* Upgrade will put new kernels in place, and wipe old ones */
fail_if(!boot_manager_update(m), "Failed to migrate namespace on update");
/* Iterate again, make sure new ones are valid, and old ones are gone
* Not all kernels are retained during upgrade */
for (size_t i = 0; i < config.n_kernels; i++) {
PlaygroundKernel *k = &(kernels[i]);
autofree(char) *tgt_path_config = NULL;
tgt_path_config = string_printf("%s/etc/grub.d/10_%s_%s-%d.%s",
PLAYGROUND_ROOT,
boot_manager_get_os_id(m),
k->version,
k->release,
k->ktype);
fail_if(nc_file_exists(tgt_path_config),
"Old GRUB2 path not removed: %s",
tgt_path_config);
}
fail_if(!nc_file_exists(PLAYGROUND_ROOT "/etc/grub.d/10_" KERNEL_NAMESPACE),
"GRUB2 configuration not written");
}
END_TEST
static Suite *core_suite(void)
{
Suite *s = NULL;
TCase *tc = NULL;
s = suite_create("bootman_grub2");
tc = tcase_create("bootman_grub2_functions");
tcase_add_test(tc, bootman_grub2_get_boot_device);
tcase_add_test(tc, bootman_grub2_image);
tcase_add_test(tc, bootman_grub2_native);
tcase_add_test(tc, bootman_grub2_update_from_unknown);
tcase_add_test(tc, bootman_grub2_namespace_migration);
suite_add_tcase(s, tc);
return s;
}
int main(void)
{
Suite *s;
SRunner *sr;
int fail;
/* override test ops for legacy grub2 testing */
CbmBlkidOps blkid_ops = BlkidTestOps;
blkid_ops.probe_lookup_value = grub2_blkid_probe_lookup_value;
/* syncing can be problematic during test suite runs */
cbm_set_sync_filesystems(false);
/* Ensure that logging is set up properly. */
setenv("CBM_DEBUG", "1", 1);
cbm_log_init(stderr);
/* Turn off the EFI variable manipulation. */
setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1);
/* Force detection of `ext` filesystem. */
setenv("CBM_TEST_FSTYPE", "ext4", 1);
cbm_blkid_set_vtable(&blkid_ops);
cbm_system_set_vtable(&SystemTestOps);
s = core_suite();
sr = srunner_create(s);
srunner_run_all(sr, CK_VERBOSE);
fail = srunner_ntests_failed(sr);
srunner_free(sr);
if (fail > 0) {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=8 tabstop=8 expandtab:
* :indentSize=8:tabSize=8:noTabs=true:
*/