Skip to content

Commit

Permalink
Add remove-kernel command
Browse files Browse the repository at this point in the history
In some cases users will want to remove kernels from their systems
outside an update workflow. This is fairly painful to do manually so
add a command to handle the operation which removes both the /boot
data and configuration files as well as the /usr data.

The default symlink for a kernel type will remain as this is something
that the update mechanism should be in control of and figuring out
what would be the fallback is out of cbm's scope.

Signed-off-by: William Douglas <[email protected]>
  • Loading branch information
bryteise committed Jan 4, 2023
1 parent 019f324 commit 8276f49
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 3 deletions.
4 changes: 2 additions & 2 deletions data/completions/bash/clr-boot-manager.in
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ _clr_boot_manager() {

case "$3" in
"$1"|help)
opts="version report-booted help update set-timeout get-timeout set-kernel list-kernels help"
opts="version report-booted help update set-timeout get-timeout set-kernel remove-kernel list-kernels help"
COMPREPLY=($(compgen -W "${opts}" -- "${2}"))
;;
get-timeout|list-kernels|update|set-timeout)
opts="--path --image --no-efi-update"
COMPREPLY=($(compgen -W "${opts}" -- "${2}"))
;;
set-kernel)
set-kernel|remove-kernel)
opts="--path --image --no-efi-update"
COMPREPLY=($(compgen -W "${opts}" -- "${2}"))
COMPREPLY+=($(compgen -G "@KERNEL_DIRECTORY@/@KERNEL_NAMESPACE@*" ))
Expand Down
3 changes: 2 additions & 1 deletion data/completions/zsh/_clr-boot-manager.in
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ local -a subcmds; subcmds=(
"set-timeout:Set the timeout to be used by the bootloader"
"get-timeout:Get the timeout to be used by the bootloader"
"set-kernel:Configure kernel to be used at next boot"
"remove-kernel:Remove kernel from system"
"list-kernels:Display currently selectable kernels to boot"
"help:Display help information on available commands"
)
Expand All @@ -50,7 +51,7 @@ if [[ -n "$state" ]]; then
get-timeout|list-kernels|update)
_arguments $args && ret=0
;;
set-kernel)
set-kernel|remove-kernel)
local -a kernelpath

kernelpath=(${opt_args[--path=]:-${opt_args[-p]}})
Expand Down
9 changes: 9 additions & 0 deletions man/clr-boot-manager.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,15 @@ Configure the default booting kernel.
This command will not prevent the update command from changing the default kernel\&.
.RE

.PP
\fBremove-kernel\fR
.RS 4
Remove a kernel from the system (both /boot and /usr locations).

Warning: This can remove the only kernel from the system, ensure you have a default kernel
set after running this command\&.
.RE

.SH "EXIT STATUS"
.PP
On success, 0 is returned, a non\-zero failure code otherwise\&
Expand Down
41 changes: 41 additions & 0 deletions src/bootman/bootman.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,47 @@ bool boot_manager_install_kernel(BootManager *self, const Kernel *kernel)
return self->bootloader->install_kernel(self, kernel);
}

bool boot_manager_remove_kernel_wrapper(BootManager *self, const Kernel *kernel)
{
assert(self != NULL);
autofree(KernelArray) *kernels = NULL;
autofree(char) *boot_dir = NULL;
int did_mount = -1;
bool matched = false;
bool kernel_removed = false;

CHECK_DBG_RET_VAL(!self->bootloader, false, "Invalid boot loader: null");

CHECK_DBG_RET_VAL(!cbm_is_sysconfig_sane(self->sysconfig), false,
"Sysconfig is not sane");

/* Grab the available kernels */
kernels = boot_manager_get_kernels(self);
CHECK_ERR_RET_VAL(!kernels || kernels->len == 0, false,
"No kernels discovered in %s, bailing", self->kernel_dir);

did_mount = detect_and_mount_boot(self, &boot_dir);
CHECK_DBG_RET_VAL(did_mount < 0, false, "Boot was not mounted");

for (uint16_t i = 0; i < kernels->len; i++) {
const Kernel *k = nc_array_get(kernels, i);
if (streq(kernel->meta.ktype, k->meta.ktype) &&
streq(kernel->meta.version, k->meta.version) &&
kernel->meta.release == k->meta.release) {
matched = true;
kernel_removed = boot_manager_remove_kernel(self, k);
break;
}
}
if (did_mount > 0) {
umount_boot(boot_dir);
}

CHECK_ERR(!matched, "No matching kernel in %s, bailing", self->kernel_dir);

return kernel_removed;
}

bool boot_manager_remove_kernel(BootManager *self, const Kernel *kernel)
{
assert(self != NULL);
Expand Down
10 changes: 10 additions & 0 deletions src/bootman/bootman.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,16 @@ void *boot_manager_get_data(BootManager *manager);
*/
void boot_manager_set_data(BootManager *manager, void *data);

/**
* Wrapping function to remove a kernel that handles sanity checks and /boot mount state
*
* @param kernel A valid kernel instance
*
* @return a boolean value, indicating success or failure
*/

bool boot_manager_remove_kernel_wrapper(BootManager *manager, const Kernel *kernel);

/**
* Attempt to uninstall a previously installed kernel
*
Expand Down
16 changes: 16 additions & 0 deletions src/cli/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ static SubCommand cmd_get_timeout;
static SubCommand cmd_report_booted;
static SubCommand cmd_list_kernels;
static SubCommand cmd_set_kernel;
static SubCommand cmd_remove_kernel;
static char *binary_name = NULL;
static NcHashmap *g_commands = NULL;
static bool explicit_help = false;
Expand Down Expand Up @@ -209,6 +210,21 @@ kernel for the next time the system boots.",
return EXIT_FAILURE;
}

/* Remove kernel */
cmd_remove_kernel = (SubCommand){
.name = "remove-kernel",
.blurb = "Remove the kernel from the system",
.help = "This command will remove a kernel from the system.",
.callback = cbm_command_remove_kernel,
.usage = " [--path=/path/to/filesystem/root]",
.requires_root = true
};

if (!nc_hashmap_put(commands, cmd_remove_kernel.name, &cmd_remove_kernel)) {
DECLARE_OOM();
return EXIT_FAILURE;
}

/* Version */
cmd_version = (SubCommand){
.name = "version",
Expand Down
77 changes: 77 additions & 0 deletions src/cli/ops/kernels.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,83 @@ bool cbm_command_set_kernel(int argc, char **argv)
return true;
}

bool cbm_command_remove_kernel(int argc, char **argv)
{
autofree(char) *root = NULL;
autofree(BootManager) *manager = NULL;
autofree(KernelArray) *kernels = NULL;
bool forced_image = false;
char type[32] = { 0 };
char version[16] = { 0 };
int release = 0;
Kernel kern = { 0 };
bool update_efi_vars = true;

if (!cli_default_args_init(&argc, &argv, &root, &forced_image, &update_efi_vars)) {
return false;
}

manager = boot_manager_new();
if (!manager) {
DECLARE_OOM();
return false;
}

boot_manager_set_update_efi_vars(manager, update_efi_vars);

if (root) {
autofree(char) *realp = NULL;

realp = realpath(root, NULL);
if (!realp) {
LOG_FATAL("Path specified does not exist: %s", root);
return false;
}
/* Anything not / is image mode */
if (!streq(realp, "/")) {
boot_manager_set_image_mode(manager, true);
} else {
boot_manager_set_image_mode(manager, forced_image);
}

/* CBM will check this again, we just needed to check for
* image mode.. */
if (!boot_manager_set_prefix(manager, root)) {
return false;
}
} else {
boot_manager_set_image_mode(manager, forced_image);
/* Default to "/", bail if it doesn't work. */
if (!boot_manager_set_prefix(manager, "/")) {
return false;
}
}

if (argc != 1) {
fprintf(stderr,
"remove-kernel takes a kernel ID of the form %s.TYPE.VERSION-RELEASE\n",
KERNEL_NAMESPACE);
return false;
}

if (sscanf(argv[optind], KERNEL_NAMESPACE ".%31[^.].%15[^-]-%d", type, version, &release) != 3) {
fprintf(stderr,
"remove-kernel takes a kernel ID of the form %s.TYPE.VERSION-RELEASE\n",
KERNEL_NAMESPACE);
return false;
}

kern.meta.ktype = type;
kern.meta.version = version;
kern.meta.release = release;

/* Let CBM take care of the rest */
if (!boot_manager_remove_kernel_wrapper(manager, &kern)) {
return false;
}
return true;
}

/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
Expand Down
1 change: 1 addition & 0 deletions src/cli/ops/kernels.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

bool cbm_command_list_kernels(int argc, char **argv);
bool cbm_command_set_kernel(int argc, char **argv);
bool cbm_command_remove_kernel(int argc, char **argv);

/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
Expand Down

0 comments on commit 8276f49

Please sign in to comment.