From 6a20a9d2862d27bb91424419c641acc3f1cd5667 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 6 Nov 2023 11:33:51 +0100 Subject: [PATCH 1/8] string-util: add strdup_or_null() helper --- src/basic/string-util.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 6b6a5746fe..b6d8be3083 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -301,3 +301,24 @@ bool version_is_valid(const char *s); bool version_is_valid_versionspec(const char *s); ssize_t strlevenshtein(const char *x, const char *y); + +static inline int strdup_or_null(const char *s, char **ret) { + char *c; + + assert(ret); + + /* This is a lot like strdup(), but is happy with NULL strings, and does not treat that as error, but + * copies the NULL value. */ + + if (!s) { + *ret = NULL; + return 0; + } + + c = strdup(s); + if (!c) + return -ENOMEM; + + *ret = c; + return 1; +} From 658e6cc4ae50d6eccb665e42a15f4f2d20e88cf1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 6 Nov 2023 10:30:58 +0100 Subject: [PATCH 2/8] kernel-install: add command to list installed kernels This simply dumps the dirs in /usr/lib/modules/ and whether they contain a vmlinuz binary. --- man/kernel-install.xml | 15 +++++ src/kernel-install/kernel-install.c | 91 ++++++++++++++++++++++++++--- 2 files changed, 98 insertions(+), 8 deletions(-) diff --git a/man/kernel-install.xml b/man/kernel-install.xml index f7a5d8a76b..fd96510d07 100644 --- a/man/kernel-install.xml +++ b/man/kernel-install.xml @@ -44,6 +44,11 @@ KERNEL-IMAGE INITRD-FILE + + kernel-install + OPTIONS + list + @@ -190,6 +195,15 @@ + + list + + Shows the various installed kernels. This enumerates the subdirectories of + /usr/lib/modules/, and shows whether a kernel image is installed there. + + + + @@ -332,6 +346,7 @@ + diff --git a/src/kernel-install/kernel-install.c b/src/kernel-install/kernel-install.c index cae93362b6..aaafe098b7 100644 --- a/src/kernel-install/kernel-install.c +++ b/src/kernel-install/kernel-install.c @@ -3,10 +3,11 @@ #include #include -#include "build.h" #include "boot-entry.h" +#include "build.h" #include "chase.h" #include "conf-files.h" +#include "dirent-util.h" #include "env-file.h" #include "env-util.h" #include "exec-util.h" @@ -23,6 +24,7 @@ #include "parse-argument.h" #include "path-util.h" #include "pretty-print.h" +#include "recurse-dir.h" #include "rm-rf.h" #include "stat-util.h" #include "string-table.h" @@ -40,6 +42,7 @@ static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF; static char *arg_root = NULL; static char *arg_image = NULL; static ImagePolicy *arg_image_policy = NULL; +static bool arg_legend = true; STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep); STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep); @@ -1183,6 +1186,68 @@ static int verb_inspect(int argc, char *argv[], void *userdata) { return table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, /* show_header= */ false); } +static int verb_list(int argc, char *argv[], void *userdata) { + _cleanup_close_ int fd = -EBADF; + int r; + + fd = open("/usr/lib/modules", O_DIRECTORY|O_RDONLY|O_CLOEXEC); + if (fd < 0) + return log_error_errno(fd, "Failed to open /usr/lib/modules/: %m"); + + _cleanup_free_ DirectoryEntries *de = NULL; + r = readdir_all(fd, RECURSE_DIR_SORT|RECURSE_DIR_IGNORE_DOT, &de); + if (r < 0) + return log_error_errno(r, "Failed to numerate /usr/lib/modules/ contents: %m"); + + _cleanup_(table_unrefp) Table *table = NULL; + table = table_new("version", "has kernel", "path"); + if (!table) + return log_oom(); + + table_set_ersatz_string(table, TABLE_ERSATZ_DASH); + table_set_align_percent(table, table_get_cell(table, 0, 1), 100); + + FOREACH_ARRAY(d, de->entries, de->n_entries) { + + _cleanup_free_ char *j = path_join("/usr/lib/modules/", (*d)->d_name); + if (!j) + return log_oom(); + + r = dirent_ensure_type(fd, *d); + if (r < 0) { + if (r != -ENOENT) /* don't log if just gone by now */ + log_debug_errno(r, "Failed to check if '%s' is a directory, ignoring: %m", j); + continue; + } + + if ((*d)->d_type != DT_DIR) + continue; + + _cleanup_free_ char *fn = path_join((*d)->d_name, "vmlinuz"); + if (!fn) + return log_oom(); + + bool exists; + if (faccessat(fd, fn, F_OK, AT_SYMLINK_NOFOLLOW) < 0) { + if (errno != ENOENT) + log_debug_errno(errno, "Failed to check if '/usr/lib/modules/%s/vmlinuz' exists, ignoring: %m", (*d)->d_name); + + exists = false; + } else + exists = true; + + r = table_add_many(table, + TABLE_STRING, (*d)->d_name, + TABLE_BOOLEAN_CHECKMARK, exists, + TABLE_SET_COLOR, ansi_highlight_green_red(exists), + TABLE_PATH, j); + if (r < 0) + return table_log_add_error(r); + } + + return table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend); +} + static int help(void) { _cleanup_free_ char *link = NULL; int r; @@ -1192,13 +1257,13 @@ static int help(void) { return log_oom(); printf("%1$s [OPTIONS...] COMMAND ...\n\n" - "%2$sAdd and remove kernel and initrd images to and from /boot%3$s\n" - "\nUsage:\n" + "%5$sAdd and remove kernel and initrd images to and from /boot/%6$s\n" + "\n%3$sUsage:%4$s\n" " kernel-install [OPTIONS...] add KERNEL-VERSION KERNEL-IMAGE [INITRD ...]\n" " kernel-install [OPTIONS...] remove KERNEL-VERSION\n" " kernel-install [OPTIONS...] inspect [KERNEL-VERSION] KERNEL-IMAGE [INITRD ...]\n" - "\n" - "Options:\n" + " kernel-install [OPTIONS...] list\n" + "\n%3$sOptions:%4$s\n" " -h --help Show this help\n" " --version Show package version\n" " -v --verbose Increase verbosity\n" @@ -1210,6 +1275,7 @@ static int help(void) { " Entry token to use for this installation\n" " --no-pager Do not pipe inspect output into a pager\n" " --json=pretty|short|off Generate JSON output\n" + " --no-legend Do not show the headers and footers\n" " --root=PATH Operate on an alternate filesystem root\n" " --image=PATH Operate on disk image as filesystem root\n" " --image-policy=POLICY Specify disk image dissection policy\n" @@ -1218,11 +1284,13 @@ static int help(void) { " installkernel [OPTIONS...] VERSION VMLINUZ [MAP] [INSTALLATION-DIR]\n" "(The optional arguments are passed by kernel build system, but ignored.)\n" "\n" - "See the %4$s for details.\n", + "See the %2$s for details.\n", program_invocation_short_name, - ansi_highlight(), + link, + ansi_underline(), ansi_normal(), - link); + ansi_highlight(), + ansi_normal()); return 0; } @@ -1230,6 +1298,7 @@ static int help(void) { static int parse_argv(int argc, char *argv[], Context *c) { enum { ARG_VERSION = 0x100, + ARG_NO_LEGEND, ARG_ESP_PATH, ARG_BOOT_PATH, ARG_MAKE_ENTRY_DIRECTORY, @@ -1253,6 +1322,7 @@ static int parse_argv(int argc, char *argv[], Context *c) { { "root", required_argument, NULL, ARG_ROOT }, { "image", required_argument, NULL, ARG_IMAGE }, { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, {} }; int t, r; @@ -1269,6 +1339,10 @@ static int parse_argv(int argc, char *argv[], Context *c) { case ARG_VERSION: return version(); + case ARG_NO_LEGEND: + arg_legend = false; + break; + case 'v': log_set_max_level(LOG_DEBUG); arg_verbose = true; @@ -1350,6 +1424,7 @@ static int run(int argc, char* argv[]) { { "add", 3, VERB_ANY, 0, verb_add }, { "remove", 2, VERB_ANY, 0, verb_remove }, { "inspect", 1, VERB_ANY, VERB_DEFAULT, verb_inspect }, + { "list", 1, 1, 0, verb_list }, {} }; _cleanup_(context_done) Context c = { From 9d9e99a8f0b6db433e2c42228cdba2d13ff9b537 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 6 Nov 2023 10:47:10 +0100 Subject: [PATCH 3/8] kernel-install: make version/kernel image parameters optional for "add" Let's make kernel-install a bit easier to use: If the kernel version is not specified, let's imply "uname -r", so that we regnerate the entries for the current kernel. If the kernel image is not specified let's imply using /usr/lib/modules/$version/vmlinuz, i.e. the location distros like Fedora drop the kernel into, which we generally recommend people to use. If the kernel is not found there, don't try to automatically pick the kernel path, and fail, as before. --- man/kernel-install.xml | 14 ++++---- src/kernel-install/kernel-install.c | 50 +++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/man/kernel-install.xml b/man/kernel-install.xml index fd96510d07..8130bc09a4 100644 --- a/man/kernel-install.xml +++ b/man/kernel-install.xml @@ -86,15 +86,17 @@ - add - KERNEL-VERSION - KERNEL-IMAGE [INITRD-FILE ...] + add [[[KERNEL-VERSION] KERNEL-IMAGE] [INITRD-FILE ...]] - This command expects a kernel version string and a path to a kernel image file as arguments. - Optionally, one or more initrd images may be specified as well (note that plugins might generate - additional ones). + This command takes a kernel version string and a path to a kernel image file as arguments. If + the former is omitted, specified as an empty string or as "-" it defaults to the current kernel + version, i.e. the same string uname -r returns. If the latter is omitted, + specified as an empty string or as "-" defaults to + /usr/lib/modules/KERNEL_VERSION/vmlinuz. Optionally, + one or more initrd images may be specified as well (note that plugins might generate additional + ones). The executable files from /usr/lib/kernel/install.d/*.install and /etc/kernel/install.d/*.install (i.e. the plugins) are called with the diff --git a/src/kernel-install/kernel-install.c b/src/kernel-install/kernel-install.c index aaafe098b7..35e7c422b6 100644 --- a/src/kernel-install/kernel-install.c +++ b/src/kernel-install/kernel-install.c @@ -2,6 +2,7 @@ #include #include +#include #include "boot-entry.h" #include "build.h" @@ -15,6 +16,7 @@ #include "fileio.h" #include "find-esp.h" #include "format-table.h" +#include "fs-util.h" #include "id128-util.h" #include "image-policy.h" #include "kernel-image.h" @@ -1024,9 +1026,12 @@ static bool bypass(void) { static int verb_add(int argc, char *argv[], void *userdata) { Context *c = ASSERT_PTR(userdata); + _cleanup_free_ char *vmlinuz = NULL; + const char *version, *kernel; + char **initrds; + struct utsname un; int r; - assert(argc >= 3); assert(argv); if (arg_root) @@ -1037,15 +1042,44 @@ static int verb_add(int argc, char *argv[], void *userdata) { c->action = ACTION_ADD; - r = context_set_version(c, argv[1]); + /* We use the same order of arguments that "inspect" introduced, i.e. if only on argument is + * specified we take it as the kernel path, not the version, i.e. it's the first argument that is + * optional, not the 2nd. */ + version = argc > 2 ? empty_or_dash_to_null(argv[1]) : NULL; + kernel = argc > 2 ? empty_or_dash_to_null(argv[2]) : + (argc > 1 ? empty_or_dash_to_null(argv[1]) : NULL); + initrds = strv_skip(argv, 3); + + if (!version) { + assert_se(uname(&un) >= 0); + version = un.release; + } + + if (!kernel) { + vmlinuz = path_join("/usr/lib/modules/", version, "/vmlinuz"); + if (!vmlinuz) + return log_oom(); + + r = laccess(vmlinuz, F_OK); + if (r < 0) { + if (r == -ENOENT) + return log_error_errno(r, "Kernel image not installed to '%s', requiring manual kernel image path specification.", vmlinuz); + + return log_error_errno(r, "Failed to determin if kernel image is installed to '%s': %m", vmlinuz); + } + + kernel = vmlinuz; + } + + r = context_set_version(c, version); if (r < 0) return r; - r = context_set_kernel(c, argv[2]); + r = context_set_kernel(c, kernel); if (r < 0) return r; - r = context_set_initrds(c, strv_skip(argv, 3)); + r = context_set_initrds(c, initrds); if (r < 0) return r; @@ -1085,6 +1119,10 @@ static int verb_remove(int argc, char *argv[], void *userdata) { c->action = ACTION_REMOVE; + /* Note, we do not automatically derive the kernel version to remove from uname() here (unlike we do + * it for the "add" verb), since we don't want to make it too easy to uninstall your running + * kernel, as a safety precaution */ + r = context_set_version(c, argv[1]); if (r < 0) return r; @@ -1259,7 +1297,7 @@ static int help(void) { printf("%1$s [OPTIONS...] COMMAND ...\n\n" "%5$sAdd and remove kernel and initrd images to and from /boot/%6$s\n" "\n%3$sUsage:%4$s\n" - " kernel-install [OPTIONS...] add KERNEL-VERSION KERNEL-IMAGE [INITRD ...]\n" + " kernel-install [OPTIONS...] add [[[KERNEL-VERSION] KERNEL-IMAGE] [INITRD ...]]\n" " kernel-install [OPTIONS...] remove KERNEL-VERSION\n" " kernel-install [OPTIONS...] inspect [KERNEL-VERSION] KERNEL-IMAGE [INITRD ...]\n" " kernel-install [OPTIONS...] list\n" @@ -1421,7 +1459,7 @@ static int parse_argv(int argc, char *argv[], Context *c) { static int run(int argc, char* argv[]) { static const Verb verbs[] = { - { "add", 3, VERB_ANY, 0, verb_add }, + { "add", 1, VERB_ANY, 0, verb_add }, { "remove", 2, VERB_ANY, 0, verb_remove }, { "inspect", 1, VERB_ANY, VERB_DEFAULT, verb_inspect }, { "list", 1, 1, 0, verb_list }, From ec1399f567163efe490ec56c1ffcf0dfef3c609c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 6 Nov 2023 11:34:11 +0100 Subject: [PATCH 4/8] kernel-install: add add-all verb --- man/kernel-install.xml | 14 ++ src/kernel-install/kernel-install.c | 192 ++++++++++++++++++++++++++-- 2 files changed, 193 insertions(+), 13 deletions(-) diff --git a/man/kernel-install.xml b/man/kernel-install.xml index 8130bc09a4..625658becf 100644 --- a/man/kernel-install.xml +++ b/man/kernel-install.xml @@ -151,6 +151,20 @@ + + + add-all + + + + This is the same as add (see above), but invokes the operation iteratively + for every installed kernel in /usr/lib/modules/. This operation is only + supported on systems where the kernel image is installed in + /usr/lib/modules/KERNEL-VERSION/vmlinuz. + + + + remove KERNEL-VERSION diff --git a/src/kernel-install/kernel-install.c b/src/kernel-install/kernel-install.c index 35e7c422b6..1940ae2bb6 100644 --- a/src/kernel-install/kernel-install.c +++ b/src/kernel-install/kernel-install.c @@ -101,6 +101,8 @@ typedef struct Context { char **envp; } Context; +#define CONTEXT_NULL (Context) { .rfd = -EBADF } + static void context_done(Context *c) { assert(c); @@ -125,6 +127,75 @@ static void context_done(Context *c) { safe_close(c->rfd); } +static int context_copy(const Context *source, Context *ret) { + int r; + + assert(source); + assert(ret); + + _cleanup_(context_done) Context copy = (Context) { + .rfd = -EBADF, + .action = source->action, + .machine_id = source->machine_id, + .machine_id_is_random = source->machine_id_is_random, + .kernel_image_type = source->kernel_image_type, + .layout = source->layout, + .entry_token_type = source->entry_token_type, + }; + + copy.rfd = fd_reopen(source->rfd, O_CLOEXEC|O_DIRECTORY|O_PATH); + if (copy.rfd < 0) + return copy.rfd; + + r = strdup_or_null(source->layout_other, ©.layout_other); + if (r < 0) + return r; + r = strdup_or_null(source->conf_root, ©.conf_root); + if (r < 0) + return r; + r = strdup_or_null(source->boot_root, ©.boot_root); + if (r < 0) + return r; + r = strdup_or_null(source->entry_token, ©.entry_token); + if (r < 0) + return r; + r = strdup_or_null(source->entry_dir, ©.entry_dir); + if (r < 0) + return r; + r = strdup_or_null(source->version, ©.version); + if (r < 0) + return r; + r = strdup_or_null(source->kernel, ©.kernel); + if (r < 0) + return r; + copy.initrds = strv_copy(source->initrds); + if (!copy.initrds) + return -ENOMEM; + r = strdup_or_null(source->initrd_generator, ©.initrd_generator); + if (r < 0) + return r; + r = strdup_or_null(source->uki_generator, ©.uki_generator); + if (r < 0) + return r; + r = strdup_or_null(source->staging_area, ©.staging_area); + if (r < 0) + return r; + copy.plugins = strv_copy(source->plugins); + if (!copy.plugins) + return -ENOMEM; + copy.argv = strv_copy(source->argv); + if (!copy.argv) + return -ENOMEM; + copy.envp = strv_copy(source->envp); + if (!copy.envp) + return -ENOMEM; + + *ret = copy; + copy = CONTEXT_NULL; + + return 0; +} + static int context_open_root(Context *c) { assert(c); assert(c->rfd < 0); @@ -1024,6 +1095,37 @@ static bool bypass(void) { return true; } +static int do_add( + Context *c, + const char *version, + const char *kernel, + char **initrds) { + + int r; + + assert(c); + assert(version); + assert(kernel); + + r = context_set_version(c, version); + if (r < 0) + return r; + + r = context_set_kernel(c, kernel); + if (r < 0) + return r; + + r = context_set_initrds(c, initrds); + if (r < 0) + return r; + + r = context_prepare_execution(c); + if (r < 0) + return r; + + return context_execute(c); +} + static int verb_add(int argc, char *argv[], void *userdata) { Context *c = ASSERT_PTR(userdata); _cleanup_free_ char *vmlinuz = NULL; @@ -1071,23 +1173,85 @@ static int verb_add(int argc, char *argv[], void *userdata) { kernel = vmlinuz; } - r = context_set_version(c, version); - if (r < 0) - return r; + return do_add(c, version, kernel, initrds); +} - r = context_set_kernel(c, kernel); - if (r < 0) - return r; +static int verb_add_all(int argc, char *argv[], void *userdata) { + Context *c = ASSERT_PTR(userdata); + _cleanup_close_ int fd = -EBADF; + size_t n = 0; + int ret = 0, r; - r = context_set_initrds(c, initrds); - if (r < 0) - return r; + assert(argv); - r = context_prepare_execution(c); - if (r < 0) - return r; + if (bypass()) + return 0; - return context_execute(c); + c->action = ACTION_ADD; + + fd = open("/usr/lib/modules", O_DIRECTORY|O_RDONLY|O_CLOEXEC); + if (fd < 0) + return log_error_errno(fd, "Failed to open /usr/lib/modules/: %m"); + + _cleanup_free_ DirectoryEntries *de = NULL; + r = readdir_all(fd, RECURSE_DIR_SORT|RECURSE_DIR_IGNORE_DOT, &de); + if (r < 0) + return log_error_errno(r, "Failed to numerate /usr/lib/modules/ contents: %m"); + + FOREACH_ARRAY(d, de->entries, de->n_entries) { + + _cleanup_free_ char *j = path_join("/usr/lib/modules/", (*d)->d_name); + if (!j) + return log_oom(); + + r = dirent_ensure_type(fd, *d); + if (r < 0) { + if (r != -ENOENT) /* don't log if just gone by now */ + log_debug_errno(r, "Failed to check if '%s' is a directory, ignoring: %m", j); + continue; + } + + if ((*d)->d_type != DT_DIR) + continue; + + _cleanup_free_ char *fn = path_join((*d)->d_name, "vmlinuz"); + if (!fn) + return log_oom(); + + if (faccessat(fd, fn, F_OK, AT_SYMLINK_NOFOLLOW) < 0) { + if (errno != ENOENT) + log_debug_errno(errno, "Failed to check if '/usr/lib/modules/%s/vmlinuz' exists, ignoring: %m", (*d)->d_name); + + log_notice("Not adding version '%s', because kernel image not found.", (*d)->d_name); + continue; + } + + _cleanup_(context_done) Context copy = CONTEXT_NULL; + + r = context_copy(c, ©); + if (r < 0) + return log_error_errno(r, "Failed to copy execution context: %m"); + + _cleanup_free_ char *full = path_join("/usr/lib/modules/", fn); + if (!full) + return log_oom(); + + r = do_add(©, + /* version= */ (*d)->d_name, + /* kernel= */ full, + /* initrds= */ NULL); + RET_GATHER(ret, r); + + if (r >= 0) + n++; + } + + if (n > 0) + log_info("Installed %zu kernels.", n); + else if (ret == 0) + ret = log_error_errno(SYNTHETIC_ERRNO(ENOENT), "No kernels to install found."); + + return ret; } static int run_as_installkernel(int argc, char *argv[], Context *c) { @@ -1298,6 +1462,7 @@ static int help(void) { "%5$sAdd and remove kernel and initrd images to and from /boot/%6$s\n" "\n%3$sUsage:%4$s\n" " kernel-install [OPTIONS...] add [[[KERNEL-VERSION] KERNEL-IMAGE] [INITRD ...]]\n" + " kernel-install [OPTIONS...] add-all\n" " kernel-install [OPTIONS...] remove KERNEL-VERSION\n" " kernel-install [OPTIONS...] inspect [KERNEL-VERSION] KERNEL-IMAGE [INITRD ...]\n" " kernel-install [OPTIONS...] list\n" @@ -1460,6 +1625,7 @@ static int parse_argv(int argc, char *argv[], Context *c) { static int run(int argc, char* argv[]) { static const Verb verbs[] = { { "add", 1, VERB_ANY, 0, verb_add }, + { "add-all", 1, 1, 0, verb_add_all }, { "remove", 2, VERB_ANY, 0, verb_remove }, { "inspect", 1, VERB_ANY, VERB_DEFAULT, verb_inspect }, { "list", 1, 1, 0, verb_list }, From 758d14767d59dd5444dde9fe74fbb669b18a6572 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 6 Nov 2023 18:25:46 +0100 Subject: [PATCH 5/8] kernel-install: make "inspect" work more like "add" regarding omission of parameters This makes "kernel-install inspect" work more "kernel-install add": if the version or kernel image is specified as "-" or omitted we'll make it up. --- man/kernel-install.xml | 10 ++-- src/kernel-install/kernel-install.c | 90 ++++++++++++++++++++--------- 2 files changed, 69 insertions(+), 31 deletions(-) diff --git a/man/kernel-install.xml b/man/kernel-install.xml index 625658becf..0223b561f1 100644 --- a/man/kernel-install.xml +++ b/man/kernel-install.xml @@ -200,13 +200,15 @@ - inspect [[KERNEL-VERSION] KERNEL-IMAGE] [INITRD-FILE ...] + inspect [[[KERNEL-VERSION] KERNEL-IMAGE] [INITRD-FILE ...]] + Takes the same parameters as add. + Shows the various paths and parameters configured or auto-detected. In particular shows the - values of the various $KERNEL_INSTALL_* environment variables listed - below. The option can be used to get the output of this verb as a JSON - object. + values of the various $KERNEL_INSTALL_* environment variables listed below, as + they would be passed to plugins. The option can be used to get the output + of this verb as a JSON object. diff --git a/src/kernel-install/kernel-install.c b/src/kernel-install/kernel-install.c index 1940ae2bb6..6631054d07 100644 --- a/src/kernel-install/kernel-install.c +++ b/src/kernel-install/kernel-install.c @@ -1126,6 +1126,28 @@ static int do_add( return context_execute(c); } +static int kernel_from_version(const char *version, char **ret_kernel) { + _cleanup_free_ char *vmlinuz = NULL; + int r; + + assert(version); + + vmlinuz = path_join("/usr/lib/modules/", version, "/vmlinuz"); + if (!vmlinuz) + return log_oom(); + + r = laccess(vmlinuz, F_OK); + if (r < 0) { + if (r == -ENOENT) + return log_error_errno(r, "Kernel image not installed to '%s', requiring manual kernel image path specification.", vmlinuz); + + return log_error_errno(r, "Failed to determin if kernel image is installed to '%s': %m", vmlinuz); + } + + *ret_kernel = TAKE_PTR(vmlinuz); + return 0; +} + static int verb_add(int argc, char *argv[], void *userdata) { Context *c = ASSERT_PTR(userdata); _cleanup_free_ char *vmlinuz = NULL; @@ -1158,17 +1180,9 @@ static int verb_add(int argc, char *argv[], void *userdata) { } if (!kernel) { - vmlinuz = path_join("/usr/lib/modules/", version, "/vmlinuz"); - if (!vmlinuz) - return log_oom(); - - r = laccess(vmlinuz, F_OK); - if (r < 0) { - if (r == -ENOENT) - return log_error_errno(r, "Kernel image not installed to '%s', requiring manual kernel image path specification.", vmlinuz); - - return log_error_errno(r, "Failed to determin if kernel image is installed to '%s': %m", vmlinuz); - } + r = kernel_from_version(version, &vmlinuz); + if (r < 0) + return r; kernel = vmlinuz; } @@ -1301,28 +1315,49 @@ static int verb_remove(int argc, char *argv[], void *userdata) { static int verb_inspect(int argc, char *argv[], void *userdata) { Context *c = ASSERT_PTR(userdata); _cleanup_(table_unrefp) Table *t = NULL; + _cleanup_free_ char *vmlinuz = NULL; + const char *version, *kernel; + char **initrds; + struct utsname un; int r; c->action = ACTION_INSPECT; - if (argc == 2) { - r = context_set_kernel(c, argv[1]); - if (r < 0) - return r; - } else if (argc >= 3) { - r = context_set_version(c, argv[1]); - if (r < 0) - return r; + /* When only a single parameter is specified 'inspect' it's the kernel image path, and not the kernel + * version. i.e. it's the first argument that is optional, not the 2nd. That's a bit unfortunate, but + * we keep the behaviour for compatibility. If users want to specify only the version (and have the + * kernel image path derived automatically), then they may specify an empty string or "dash" as + * kernel image path. */ + version = argc > 2 ? empty_or_dash_to_null(argv[1]) : NULL; + kernel = argc > 2 ? empty_or_dash_to_null(argv[2]) : + (argc > 1 ? empty_or_dash_to_null(argv[1]) : NULL); + initrds = strv_skip(argv, 3); - r = context_set_kernel(c, argv[2]); - if (r < 0) - return r; - - r = context_set_initrds(c, strv_skip(argv, 3)); - if (r < 0) - return r; + if (!version) { + assert_se(uname(&un) >= 0); + version = un.release; } + if (!kernel) { + r = kernel_from_version(version, &vmlinuz); + if (r < 0) + return r; + + kernel = vmlinuz; + } + + r = context_set_version(c, version); + if (r < 0) + return r; + + r = context_set_kernel(c, kernel); + if (r < 0) + return r; + + r = context_set_initrds(c, initrds); + if (r < 0) + return r; + r = context_prepare_execution(c); if (r < 0) return r; @@ -1464,7 +1499,8 @@ static int help(void) { " kernel-install [OPTIONS...] add [[[KERNEL-VERSION] KERNEL-IMAGE] [INITRD ...]]\n" " kernel-install [OPTIONS...] add-all\n" " kernel-install [OPTIONS...] remove KERNEL-VERSION\n" - " kernel-install [OPTIONS...] inspect [KERNEL-VERSION] KERNEL-IMAGE [INITRD ...]\n" + " kernel-install [OPTIONS...] inspect [[[KERNEL-VERSION] KERNEL-IMAGE]\n" + " [INITRD ...]]\n" " kernel-install [OPTIONS...] list\n" "\n%3$sOptions:%4$s\n" " -h --help Show this help\n" From 35f58f8c36f9fe27c07ed4d35a4effcad504cdb3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 6 Nov 2023 12:03:03 +0100 Subject: [PATCH 6/8] man: document /usr/lib/modules/ paths as recommend copy source for kernel-install --- man/kernel-install.xml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/man/kernel-install.xml b/man/kernel-install.xml index 0223b561f1..ee8c0069df 100644 --- a/man/kernel-install.xml +++ b/man/kernel-install.xml @@ -674,6 +674,31 @@ + + + /usr/lib/modules/KERNEL-VERSION/ + + + Location for installed kernel modules and other kernel related resources. For each locally + installed kernel a directory named after the kernel version (uname -r) is + kept. + + + + + + + /usr/lib/modules/KERNEL-VERSION/vmlinuz + + + Location for installed kernel images. This is the recommended location for OS package + managers to install kernel images into (as applicable), from which kernel-install + add then copies it into the final boot partition. + + + + + For various cases listed above, if the $KERNEL_INSTALL_CONF_ROOT environment From a6906aa579a0312a65a7de095e02a4e5ee49ed46 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Nov 2023 12:14:30 +0100 Subject: [PATCH 7/8] update TODO --- TODO | 3 --- 1 file changed, 3 deletions(-) diff --git a/TODO b/TODO index 216ed7e58d..25165de973 100644 --- a/TODO +++ b/TODO @@ -1086,9 +1086,6 @@ Features: uses RootDirectory= or RootImage=. (Might also over-mount /sys/class/dmi/id/*{uuid,serial} with /dev/null). -* kernel-install: - - add --all switch for rerunning kernel-install for all installed kernels - * doc: prep a document explaining resolved's internal objects, i.e. Query vs. Question vs. Transaction vs. Stream and so on. From 8353229e10f916fd2f54a88eef0ef6e16955d0ac Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Nov 2023 15:58:32 +0100 Subject: [PATCH 8/8] update CI --- src/kernel-install/test-kernel-install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel-install/test-kernel-install.sh b/src/kernel-install/test-kernel-install.sh index 931fae5372..db412ec524 100755 --- a/src/kernel-install/test-kernel-install.sh +++ b/src/kernel-install/test-kernel-install.sh @@ -71,7 +71,7 @@ grep -qE 'image' "$BOOT_ROOT/the-token/1.1.1/linux" grep -qE 'initrd' "$BOOT_ROOT/the-token/1.1.1/initrd" grep -qE 'DTBDTB' "$BOOT_ROOT/the-token/1.1.1/whatever.dtb" -"$kernel_install" inspect +test -f /usr/lib/modules/"$(uname -r)"/vmlinuz && "$kernel_install" inspect "$kernel_install" inspect "$D/sources/linux" "$kernel_install" -v remove 1.1.1