]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
kernel-install: add add-all verb
authorLennart Poettering <lennart@poettering.net>
Mon, 6 Nov 2023 10:34:11 +0000 (11:34 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 7 Nov 2023 15:07:55 +0000 (16:07 +0100)
man/kernel-install.xml
src/kernel-install/kernel-install.c

index 8130bc09a401e2dc37187956738c0e0e7c8a2987..625658becfa8216f30a2039f27c22a5946550a4a 100644 (file)
             <xi:include href="version-info.xml" xpointer="v198"/>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term>
+          <command>add-all</command>
+        </term>
+
+        <listitem>
+          <para>This is the same as <command>add</command> (see above), but invokes the operation iteratively
+          for every installed kernel in <filename>/usr/lib/modules/</filename>. This operation is only
+          supported on systems where the kernel image is installed in
+          <filename>/usr/lib/modules/<replaceable>KERNEL-VERSION</replaceable>/vmlinuz</filename>.</para>
+
+          <xi:include href="version-info.xml" xpointer="v255"/>
+        </listitem>
+      </varlistentry>
       <varlistentry>
         <term><command>remove <replaceable>KERNEL-VERSION</replaceable></command></term>
         <listitem>
index 35e7c422b6ec1d00bbe74ab695a732a5d6924954..1940ae2bb6a24eab66102f4c783e776671019e0d 100644 (file)
@@ -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, &copy.layout_other);
+        if (r < 0)
+                return r;
+        r = strdup_or_null(source->conf_root, &copy.conf_root);
+        if (r < 0)
+                return r;
+        r = strdup_or_null(source->boot_root, &copy.boot_root);
+        if (r < 0)
+                return r;
+        r = strdup_or_null(source->entry_token, &copy.entry_token);
+        if (r < 0)
+                return r;
+        r = strdup_or_null(source->entry_dir, &copy.entry_dir);
+        if (r < 0)
+                return r;
+        r = strdup_or_null(source->version, &copy.version);
+        if (r < 0)
+                return r;
+        r = strdup_or_null(source->kernel, &copy.kernel);
+        if (r < 0)
+                return r;
+        copy.initrds = strv_copy(source->initrds);
+        if (!copy.initrds)
+                return -ENOMEM;
+        r = strdup_or_null(source->initrd_generator, &copy.initrd_generator);
+        if (r < 0)
+                return r;
+        r = strdup_or_null(source->uki_generator, &copy.uki_generator);
+        if (r < 0)
+                return r;
+        r = strdup_or_null(source->staging_area, &copy.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 (bypass())
+                return 0;
+
+        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 r;
+                return log_error_errno(r, "Failed to numerate /usr/lib/modules/ contents: %m");
 
-        return context_execute(c);
+        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, &copy);
+                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(&copy,
+                           /* 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           },