mirror of
https://github.com/systemd/systemd.git
synced 2024-11-27 04:03:36 +08:00
bootctl: unlink and cleanup functions
The unlink command removes an entry from the ESP including referenced files that are not referenced in other entries. That is useful eg to have multiple entries that use the same kernel with different options. The cleanup command removes all files that are not referenced by any entry.
This commit is contained in:
parent
1132fd73b3
commit
8702496bfb
@ -153,6 +153,21 @@
|
||||
disables the timeout while always showing the menu. When an empty string ("") is specified the
|
||||
bootloader will revert to its default menu timeout.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>unlink</option> <replaceable>ID</replaceable></term>
|
||||
|
||||
<listitem><para>Removes a boot loader entry including the files it refers to. Takes a single boot
|
||||
loader entry ID string or a glob pattern as argument. Referenced files such as kernel or initrd are
|
||||
only removed if no other entry refers to them.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>cleanup</option></term>
|
||||
|
||||
<listitem><para>Removes files from the ESP and XBOOTLDR partitions that belong to the entry token but
|
||||
are not referenced in any boot loader entries.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
@ -409,6 +424,14 @@
|
||||
the firmware's boot option menu.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--dry-run</option></term>
|
||||
<listitem><para>Dry run for <option>--unlink</option> and <option>--cleanup</option>.</para>
|
||||
|
||||
<para>In dry run mode, the unlink and cleanup operations only print the files that would get deleted
|
||||
without actually deleting them.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="no-pager"/>
|
||||
<xi:include href="standard-options.xml" xpointer="json" />
|
||||
<xi:include href="standard-options.xml" xpointer="help"/>
|
||||
|
@ -4051,6 +4051,7 @@ public_programs += exe
|
||||
if want_tests != 'false' and want_kernel_install
|
||||
test('test-kernel-install',
|
||||
test_kernel_install_sh,
|
||||
env : test_env,
|
||||
args : [exe.full_path(), loaderentry_install])
|
||||
endif
|
||||
|
||||
|
@ -31,7 +31,7 @@ _bootctl() {
|
||||
local i verb comps
|
||||
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
local -A OPTS=(
|
||||
[STANDALONE]='-h --help -p --print-esp-path -x --print-boot-path --version --no-variables --no-pager --graceful'
|
||||
[STANDALONE]='-h --help -p --print-esp-path -x --print-boot-path --version --no-variables --no-pager --graceful --dry-run'
|
||||
[ARG]='--esp-path --boot-path --make-machine-id-directory --root --image --install-source'
|
||||
)
|
||||
|
||||
@ -67,8 +67,8 @@ _bootctl() {
|
||||
|
||||
local -A VERBS=(
|
||||
# systemd-efi-options takes an argument, but it is free-form, so we cannot complete it
|
||||
[STANDALONE]='help status install update remove is-installed random-seed systemd-efi-options list set-timeout set-timeout-oneshot'
|
||||
[BOOTENTRY]='set-default set-oneshot'
|
||||
[STANDALONE]='help status install update remove is-installed random-seed systemd-efi-options list set-timeout set-timeout-oneshot cleanup'
|
||||
[BOOTENTRY]='set-default set-oneshot unlink'
|
||||
[BOOLEAN]='reboot-to-firmware'
|
||||
)
|
||||
|
||||
|
@ -24,6 +24,10 @@ _bootctl_set-oneshot() {
|
||||
_bootctl_comp_ids
|
||||
}
|
||||
|
||||
_bootctl_unlink() {
|
||||
_bootctl_comp_ids
|
||||
}
|
||||
|
||||
_bootctl_reboot-to-firmware() {
|
||||
local -a _completions
|
||||
_completions=( yes no )
|
||||
@ -48,6 +52,8 @@ _bootctl_reboot-to-firmware() {
|
||||
"set-oneshot:Set the default boot loader entry only for the next boot"
|
||||
"set-timeout:Set the menu timeout"
|
||||
"set-timeout-oneshot:Set the menu timeout for the next boot only"
|
||||
"unlink:Remove boot loader entry"
|
||||
"cleanup:Remove files in ESP not referenced in any boot entry"
|
||||
)
|
||||
if (( CURRENT == 1 )); then
|
||||
_describe -t commands 'bootctl command' _bootctl_cmds || compadd "$@"
|
||||
@ -73,6 +79,7 @@ _arguments \
|
||||
'--no-variables[Do not touch EFI variables]' \
|
||||
'--no-pager[Do not pipe output into a pager]' \
|
||||
'--graceful[Do not fail when locating ESP or writing fails]' \
|
||||
'--dry-run[Dry run (unlink and cleanup)]' \
|
||||
'--root=[Operate under the specified directory]:PATH' \
|
||||
'--image=[Operate on the specified image]:PATH' \
|
||||
'--install-source[Where to pick files when using --root=/--image=]:options:(image host auto)' \
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "find-esp.h"
|
||||
#include "path-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "recurse-dir.h"
|
||||
#include "terminal-util.h"
|
||||
#include "tpm2-util.h"
|
||||
|
||||
@ -503,6 +504,250 @@ int verb_status(int argc, char *argv[], void *userdata) {
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ref_file(Hashmap *known_files, const char *fn, int increment) {
|
||||
char *k = NULL;
|
||||
int n, r;
|
||||
|
||||
assert(known_files);
|
||||
|
||||
/* just gracefully ignore this. This way the caller doesn't
|
||||
have to verify whether the bootloader entry is relevant */
|
||||
if (!fn)
|
||||
return 0;
|
||||
|
||||
n = PTR_TO_INT(hashmap_get2(known_files, fn, (void**)&k));
|
||||
n += increment;
|
||||
|
||||
assert(n >= 0);
|
||||
|
||||
if (n == 0) {
|
||||
(void) hashmap_remove(known_files, fn);
|
||||
free(k);
|
||||
} else if (!k) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
t = strdup(fn);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
r = hashmap_put(known_files, t, INT_TO_PTR(n));
|
||||
if (r < 0)
|
||||
return r;
|
||||
TAKE_PTR(t);
|
||||
} else {
|
||||
r = hashmap_update(known_files, fn, INT_TO_PTR(n));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static void deref_unlink_file(Hashmap *known_files, const char *fn, const char *root) {
|
||||
_cleanup_free_ char *path = NULL;
|
||||
int r;
|
||||
|
||||
/* just gracefully ignore this. This way the caller doesn't
|
||||
have to verify whether the bootloader entry is relevant */
|
||||
if (!fn || !root)
|
||||
return;
|
||||
|
||||
r = ref_file(known_files, fn, -1);
|
||||
if (r < 0)
|
||||
return (void) log_warning_errno(r, "Failed to deref \"%s\", ignoring: %m", fn);
|
||||
if (r > 0)
|
||||
return;
|
||||
|
||||
if (arg_dry_run) {
|
||||
r = chase_symlinks_and_access(fn, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, &path, NULL);
|
||||
if (r < 0)
|
||||
log_info("Unable to determine whether \"%s\" exists, ignoring: %m", fn);
|
||||
else
|
||||
log_info("Would remove %s", path);
|
||||
return;
|
||||
}
|
||||
|
||||
r = chase_symlinks_and_unlink(fn, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, 0, &path);
|
||||
if (r >= 0)
|
||||
log_info("Removed %s", path);
|
||||
else if (r != -ENOENT)
|
||||
return (void) log_warning_errno(r, "Failed to remove \"%s\", ignoring: %m", path ?: fn);
|
||||
|
||||
_cleanup_free_ char *d = NULL;
|
||||
if (path_extract_directory(fn, &d) >= 0 && !path_equal(d, "/")) {
|
||||
r = chase_symlinks_and_unlink(d, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, AT_REMOVEDIR, NULL);
|
||||
if (r < 0 && !IN_SET(r, -ENOTEMPTY, -ENOENT))
|
||||
log_warning_errno(r, "Failed to remove directoy \"%s\", ignoring: %m", d);
|
||||
}
|
||||
}
|
||||
|
||||
static int count_known_files(const BootConfig *config, const char* root, Hashmap **ret_known_files) {
|
||||
_cleanup_(hashmap_free_free_keyp) Hashmap *known_files = NULL;
|
||||
int r = 0;
|
||||
|
||||
assert(config);
|
||||
assert(ret_known_files);
|
||||
|
||||
known_files = hashmap_new(&path_hash_ops);
|
||||
if (!known_files)
|
||||
return -ENOMEM;
|
||||
|
||||
for (size_t i = 0; i < config->n_entries; i++) {
|
||||
const BootEntry *e = config->entries + i;
|
||||
|
||||
if (!path_equal(e->root, root))
|
||||
continue;
|
||||
|
||||
r = ref_file(known_files, e->kernel, +1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = ref_file(known_files, e->efi, +1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
STRV_FOREACH(s, e->initrd) {
|
||||
r = ref_file(known_files, *s, +1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
r = ref_file(known_files, e->device_tree, +1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
STRV_FOREACH(s, e->device_tree_overlay) {
|
||||
r = ref_file(known_files, *s, +1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
*ret_known_files = TAKE_PTR(known_files);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int boot_config_find_in(const BootConfig *config, const char *root, const char *id) {
|
||||
assert(config);
|
||||
|
||||
if (!root || !id)
|
||||
return -1;
|
||||
|
||||
for (size_t i = 0; i < config->n_entries; i++)
|
||||
if (path_equal(config->entries[i].root, root)
|
||||
&& fnmatch(id, config->entries[i].id, FNM_CASEFOLD) == 0)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int unlink_entry(const BootConfig *config, const char *root, const char *id) {
|
||||
_cleanup_(hashmap_free_free_keyp) Hashmap *known_files = NULL;
|
||||
const BootEntry *e = NULL;
|
||||
int r;
|
||||
|
||||
assert(config);
|
||||
|
||||
r = count_known_files(config, root, &known_files);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to count files in %s: %m", root);
|
||||
|
||||
r = boot_config_find_in(config, root, id);
|
||||
if (r < 0)
|
||||
return -ENOENT;
|
||||
|
||||
if (r == config->default_entry)
|
||||
log_warning("%s is the default boot entry", id);
|
||||
if (r == config->selected_entry)
|
||||
log_warning("%s is the selected boot entry", id);
|
||||
|
||||
e = &config->entries[r];
|
||||
|
||||
deref_unlink_file(known_files, e->kernel, e->root);
|
||||
deref_unlink_file(known_files, e->efi, e->root);
|
||||
STRV_FOREACH(s, e->initrd)
|
||||
deref_unlink_file(known_files, *s, e->root);
|
||||
deref_unlink_file(known_files, e->device_tree, e->root);
|
||||
STRV_FOREACH(s, e->device_tree_overlay)
|
||||
deref_unlink_file(known_files, *s, e->root);
|
||||
|
||||
if (arg_dry_run)
|
||||
log_info("Would remove %s", e->path);
|
||||
else {
|
||||
r = chase_symlinks_and_unlink(e->path, root, CHASE_PROHIBIT_SYMLINKS, 0, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to remove \"%s\": %m", e->path);
|
||||
|
||||
log_info("Removed %s", e->path);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int list_remove_orphaned_file(
|
||||
RecurseDirEvent event,
|
||||
const char *path,
|
||||
int dir_fd,
|
||||
int inode_fd,
|
||||
const struct dirent *de,
|
||||
const struct statx *sx,
|
||||
void *userdata) {
|
||||
Hashmap *known_files = userdata;
|
||||
|
||||
assert(path);
|
||||
assert(known_files);
|
||||
|
||||
if (event != RECURSE_DIR_ENTRY)
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
|
||||
if (hashmap_get(known_files, path))
|
||||
return RECURSE_DIR_CONTINUE; /* keep! */
|
||||
|
||||
if (arg_dry_run)
|
||||
log_info("Would remove %s", path);
|
||||
else if (unlinkat(dir_fd, de->d_name, 0) < 0)
|
||||
log_warning_errno(errno, "Failed to remove \"%s\", ignoring: %m", path);
|
||||
else
|
||||
log_info("Removed %s", path);
|
||||
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
}
|
||||
|
||||
static int cleanup_orphaned_files(
|
||||
const BootConfig *config,
|
||||
const char *root) {
|
||||
_cleanup_(hashmap_free_free_keyp) Hashmap *known_files = NULL;
|
||||
_cleanup_free_ char *full = NULL, *p = NULL;
|
||||
_cleanup_close_ int dir_fd = -1;
|
||||
int r = -1;
|
||||
|
||||
assert(config);
|
||||
assert(root);
|
||||
|
||||
log_info("Cleaning %s", root);
|
||||
|
||||
r = settle_entry_token();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = count_known_files(config, root, &known_files);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to count files in %s: %m", root);
|
||||
|
||||
dir_fd = chase_symlinks_and_open(arg_entry_token, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS,
|
||||
O_DIRECTORY|O_CLOEXEC, &full);
|
||||
if (dir_fd == -ENOENT)
|
||||
return 0;
|
||||
if (dir_fd < 0)
|
||||
return log_error_errno(dir_fd, "Failed to open '%s/%s': %m", root, arg_entry_token);
|
||||
|
||||
p = path_join("/", arg_entry_token);
|
||||
if (!p)
|
||||
return log_oom();
|
||||
|
||||
r = recurse_dir(dir_fd, p, 0, UINT_MAX, RECURSE_DIR_SORT, list_remove_orphaned_file, known_files);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to cleanup %s: %m", full);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int verb_list(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(boot_config_free) BootConfig config = BOOT_CONFIG_NULL;
|
||||
dev_t esp_devid = 0, xbootldr_devid = 0;
|
||||
@ -534,6 +779,24 @@ int verb_list(int argc, char *argv[], void *userdata) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pager_open(arg_pager_flags);
|
||||
return show_boot_entries(&config, arg_json_format_flags);
|
||||
if (streq(argv[0], "list")) {
|
||||
pager_open(arg_pager_flags);
|
||||
return show_boot_entries(&config, arg_json_format_flags);
|
||||
} else if (streq(argv[0], "cleanup")) {
|
||||
if (arg_xbootldr_path && xbootldr_devid != esp_devid)
|
||||
cleanup_orphaned_files(&config, arg_xbootldr_path);
|
||||
return cleanup_orphaned_files(&config, arg_esp_path);
|
||||
} else {
|
||||
assert(streq(argv[0], "unlink"));
|
||||
if (arg_xbootldr_path && xbootldr_devid != esp_devid) {
|
||||
r = unlink_entry(&config, arg_xbootldr_path, argv[1]);
|
||||
if (r == 0 || r != -ENOENT)
|
||||
return r;
|
||||
}
|
||||
return unlink_entry(&config, arg_esp_path, argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
int verb_unlink(int argc, char *argv[], void *userdata) {
|
||||
return verb_list(argc, argv, userdata);
|
||||
}
|
||||
|
@ -2,3 +2,4 @@
|
||||
|
||||
int verb_status(int argc, char *argv[], void *userdata);
|
||||
int verb_list(int argc, char *argv[], void *userdata);
|
||||
int verb_unlink(int argc, char *argv[], void *userdata);
|
||||
|
@ -48,6 +48,7 @@ char *arg_root = NULL;
|
||||
char *arg_image = NULL;
|
||||
InstallSource arg_install_source = ARG_INSTALL_SOURCE_AUTO;
|
||||
char *arg_efi_boot_option_description = NULL;
|
||||
bool arg_dry_run = false;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
|
||||
@ -145,6 +146,8 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||
" set-timeout SECONDS Set the menu timeout\n"
|
||||
" set-timeout-oneshot SECONDS\n"
|
||||
" Set the menu timeout for the next boot only\n"
|
||||
" unlink ID Remove boot loader entry\n"
|
||||
" cleanup Remove files in ESP not referenced in any boot entry\n"
|
||||
"\n%3$ssystemd-boot Commands:%4$s\n"
|
||||
" install Install systemd-boot to the ESP and EFI variables\n"
|
||||
" update Update systemd-boot in the ESP and EFI variables\n"
|
||||
@ -179,6 +182,7 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||
" Install all supported EFI architectures\n"
|
||||
" --efi-boot-option-description=DESCRIPTION\n"
|
||||
" Description of the entry in the boot option list\n"
|
||||
" --dry-run Dry run (unlink and cleanup)\n"
|
||||
"\nSee the %2$s for details.\n",
|
||||
program_invocation_short_name,
|
||||
link,
|
||||
@ -206,6 +210,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_JSON,
|
||||
ARG_ARCH_ALL,
|
||||
ARG_EFI_BOOT_OPTION_DESCRIPTION,
|
||||
ARG_DRY_RUN,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@ -230,6 +235,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "json", required_argument, NULL, ARG_JSON },
|
||||
{ "all-architectures", no_argument, NULL, ARG_ARCH_ALL },
|
||||
{ "efi-boot-option-description", required_argument, NULL, ARG_EFI_BOOT_OPTION_DESCRIPTION },
|
||||
{ "dry-run", no_argument, NULL, ARG_DRY_RUN },
|
||||
{}
|
||||
};
|
||||
|
||||
@ -379,6 +385,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return r;
|
||||
break;
|
||||
|
||||
case ARG_DRY_RUN:
|
||||
arg_dry_run = true;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
@ -387,7 +397,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
if ((arg_root || arg_image) && argv[optind] && !STR_IN_SET(argv[optind], "status", "list",
|
||||
"install", "update", "remove", "is-installed", "random-seed"))
|
||||
"install", "update", "remove", "is-installed", "random-seed", "unlink", "cleanup"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Options --root= and --image= are not supported with verb %s.",
|
||||
argv[optind]);
|
||||
@ -398,6 +408,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (arg_install_source != ARG_INSTALL_SOURCE_AUTO && !arg_root && !arg_image)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--install-from-host is only supported with --root= or --image=.");
|
||||
|
||||
if (arg_dry_run && argv[optind] && !STR_IN_SET(argv[optind], "unlink", "cleanup"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--dry is only supported with --unlink or --cleanup");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -412,6 +425,8 @@ static int bootctl_main(int argc, char *argv[]) {
|
||||
{ "kernel-identify", 2, 2, 0, verb_kernel_identify },
|
||||
{ "kernel-inspect", 2, 2, 0, verb_kernel_inspect },
|
||||
{ "list", VERB_ANY, 1, 0, verb_list },
|
||||
{ "unlink", 2, 2, 0, verb_unlink },
|
||||
{ "cleanup", VERB_ANY, 1, 0, verb_list },
|
||||
{ "set-default", 2, 2, 0, verb_set_efivar },
|
||||
{ "set-oneshot", 2, 2, 0, verb_set_efivar },
|
||||
{ "set-timeout", 2, 2, 0, verb_set_efivar },
|
||||
|
@ -39,6 +39,7 @@ extern char *arg_root;
|
||||
extern char *arg_image;
|
||||
extern InstallSource arg_install_source;
|
||||
extern char *arg_efi_boot_option_description;
|
||||
extern bool arg_dry_run;
|
||||
|
||||
static inline const char *arg_dollar_boot_path(void) {
|
||||
/* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */
|
||||
|
@ -32,7 +32,7 @@ MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID"
|
||||
ENTRY_TOKEN="$KERNEL_INSTALL_ENTRY_TOKEN"
|
||||
BOOT_ROOT="$KERNEL_INSTALL_BOOT_ROOT"
|
||||
|
||||
BOOT_MNT="$(stat -c %m "$BOOT_ROOT")"
|
||||
[ -n "$BOOT_MNT" ] || BOOT_MNT="$(stat -c %m "$BOOT_ROOT")"
|
||||
if [ "$BOOT_MNT" = '/' ]; then
|
||||
ENTRY_DIR="$ENTRY_DIR_ABS"
|
||||
else
|
||||
|
@ -9,6 +9,8 @@ plugin="${2:?}"
|
||||
|
||||
D="$(mktemp --tmpdir --directory "test-kernel-install.XXXXXXXXXX")"
|
||||
|
||||
export _KERNEL_INSTALL_BOOTCTL="$PROJECT_BUILD_ROOT/bootctl"
|
||||
|
||||
# shellcheck disable=SC2064
|
||||
trap "rm -rf '$D'" EXIT INT QUIT PIPE
|
||||
mkdir -p "$D/boot"
|
||||
@ -31,6 +33,7 @@ EOF
|
||||
export KERNEL_INSTALL_CONF_ROOT="$D/sources"
|
||||
export KERNEL_INSTALL_PLUGINS="$plugin"
|
||||
export BOOT_ROOT="$D/boot"
|
||||
export BOOT_MNT="$D/boot"
|
||||
export MACHINE_ID='3e0484f3634a418b8e6a39e8828b03e3'
|
||||
|
||||
"$kernel_install" -v add 1.1.1 "$D/sources/linux" "$D/sources/initrd"
|
||||
@ -82,3 +85,32 @@ grep -qE '^initrd .*/the-token/1.1.1/initrd' "$entry"
|
||||
|
||||
grep -qE 'image' "$BOOT_ROOT/the-token/1.1.1/linux"
|
||||
grep -qE 'initrd' "$BOOT_ROOT/the-token/1.1.1/initrd"
|
||||
|
||||
if test -x "$_KERNEL_INSTALL_BOOTCTL"; then
|
||||
echo "Testing bootctl"
|
||||
e2="${entry%+*}_2.conf"
|
||||
cp "$entry" "$e2"
|
||||
export SYSTEMD_ESP_PATH=/
|
||||
|
||||
# create file that is not referenced. Check if cleanup removes
|
||||
# it but leaves the rest alone
|
||||
:> "$BOOT_ROOT/the-token/1.1.2/initrd"
|
||||
"$_KERNEL_INSTALL_BOOTCTL" --root="$BOOT_ROOT" cleanup
|
||||
test ! -e "$BOOT_ROOT/the-token/1.1.2/initrd"
|
||||
test -e "$BOOT_ROOT/the-token/1.1.2/linux"
|
||||
test -e "$BOOT_ROOT/the-token/1.1.1/linux"
|
||||
test -e "$BOOT_ROOT/the-token/1.1.1/initrd"
|
||||
# now remove duplicated entry and make sure files are left over
|
||||
"$_KERNEL_INSTALL_BOOTCTL" --root="$BOOT_ROOT" unlink "${e2##*/}"
|
||||
test -e "$BOOT_ROOT/the-token/1.1.1/linux"
|
||||
test -e "$BOOT_ROOT/the-token/1.1.1/initrd"
|
||||
test -e "$entry"
|
||||
test ! -e "$e2"
|
||||
# remove last entry referencing those files
|
||||
entry_id="${entry##*/}"
|
||||
entry_id="${entry_id%+*}.conf"
|
||||
"$_KERNEL_INSTALL_BOOTCTL" --root="$BOOT_ROOT" unlink "$entry_id"
|
||||
test ! -e "$entry"
|
||||
test ! -e "$BOOT_ROOT/the-token/1.1.1/linux"
|
||||
test ! -e "$BOOT_ROOT/the-token/1.1.1/initrd"
|
||||
fi
|
||||
|
@ -15,6 +15,7 @@ path = run_command(sh, '-c', 'echo "$PATH"', check: true).stdout().strip()
|
||||
test_env = environment()
|
||||
test_env.set('SYSTEMD_LANGUAGE_FALLBACK_MAP', language_fallback_map)
|
||||
test_env.set('PATH', project_build_root + ':' + path)
|
||||
test_env.set('PROJECT_BUILD_ROOT', project_build_root)
|
||||
|
||||
############################################################
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user