]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
bootctl: add kernel-inspect command 26082/head
authorGerd Hoffmann <kraxel@redhat.com>
Tue, 17 Jan 2023 21:06:06 +0000 (22:06 +0100)
committerGerd Hoffmann <kraxel@redhat.com>
Wed, 18 Jan 2023 13:32:14 +0000 (14:32 +0100)
Takes a kernel image as argument. Prints details about the kernel.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
man/bootctl.xml
src/boot/bootctl-uki.c
src/boot/bootctl-uki.h
src/boot/bootctl.c

index 2479d5fcd6b36d202ed0377b1b05aa54edbd6517..0d796bedc192eaf318c876a73734d88ef6573276 100644 (file)
         <listitem><para>Takes a kernel image as argument. Checks what kind of kernel the image is.  Returns
         one of uki, pe or unknown.</para></listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><option>kernel-inspect</option> <replaceable>kernel</replaceable></term>
+
+        <listitem><para>Takes a kernel image as argument. Prints details about the kernel.</para></listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index 1a439afaae83c0dea2023ab853b3947cd1209cf3..aa2868fb11f47bf697806e9e20cc23a18e4d159b 100644 (file)
@@ -14,6 +14,8 @@ static const uint8_t pe_file_magic[4] = "PE\0\0";
 static const uint8_t name_osrel[8] = ".osrel";
 static const uint8_t name_linux[8] = ".linux";
 static const uint8_t name_initrd[8] = ".initrd";
+static const uint8_t name_cmdline[8] = ".cmdline";
+static const uint8_t name_uname[8] = ".uname";
 
 static int pe_sections(FILE *uki, struct PeSectionHeader **ret, size_t *ret_n) {
         _cleanup_free_ struct PeSectionHeader *sections = NULL;
@@ -108,3 +110,80 @@ int verb_kernel_identify(int argc, char *argv[], void *userdata) {
         puts("unknown");
         return EXIT_SUCCESS;
 }
+
+static int read_pe_section(FILE *uki, const struct PeSectionHeader *section,
+                           void **ret, size_t *ret_n) {
+        _cleanup_free_ void *data = NULL;
+        uint32_t size, bytes;
+        uint64_t soff;
+        int rc;
+
+        soff = le32toh(section->PointerToRawData);
+        size = le32toh(section->VirtualSize);
+
+        if (size > 16 * 1024)
+                return log_error_errno(SYNTHETIC_ERRNO(E2BIG), "PE section too big");
+
+        rc = fseek(uki, soff, SEEK_SET);
+        if (rc < 0)
+                return log_error_errno(errno, "seek to PE section");
+
+        data = malloc(size+1);
+        if (!data)
+                return log_oom();
+        ((uint8_t*) data)[size] = 0; /* safety NUL byte */
+
+        bytes = fread(data, 1, size, uki);
+        if (bytes != size)
+                return log_error_errno(SYNTHETIC_ERRNO(EIO), "PE section read error");
+
+        *ret = TAKE_PTR(data);
+        if (ret_n)
+                *ret_n = size;
+        return 0;
+}
+
+static void inspect_uki(FILE *uki, struct PeSectionHeader *sections, size_t scount) {
+        _cleanup_free_ char *cmdline = NULL;
+        _cleanup_free_ char *uname = NULL;
+        size_t idx;
+
+        if (find_pe_section(sections, scount, name_cmdline, sizeof(name_cmdline), &idx))
+                read_pe_section(uki, sections + idx, (void**)&cmdline, NULL);
+
+        if (find_pe_section(sections, scount, name_uname, sizeof(name_uname), &idx))
+                read_pe_section(uki, sections + idx, (void**)&uname, NULL);
+
+        if (cmdline)
+                printf("    Cmdline: %s\n", cmdline);
+        if (uname)
+                printf("    Version: %s\n", uname);
+}
+
+int verb_kernel_inspect(int argc, char *argv[], void *userdata) {
+        _cleanup_fclose_ FILE *uki = NULL;
+        _cleanup_free_ struct PeSectionHeader *sections = NULL;
+        size_t scount;
+        int rc;
+
+        uki = fopen(argv[1], "re");
+        if (!uki)
+                return log_error_errno(errno, "Failed to open UKI file '%s': %m", argv[1]);
+
+        rc = pe_sections(uki, &sections, &scount);
+        if (rc < 0)
+                return EXIT_FAILURE;
+
+        if (sections) {
+                if (is_uki(sections, scount)) {
+                        puts("Kernel Type: uki");
+                        inspect_uki(uki, sections, scount);
+                        return EXIT_SUCCESS;
+                }
+                puts("Kernel Type: pe");
+                return EXIT_SUCCESS;
+        }
+
+        puts("Kernel Type: unknown");
+        return EXIT_SUCCESS;
+}
index 3c1fb5bc6ad60df4efa0f4e19d41d948977519bb..effb984d805f2a54ee450e2275b7f3f340f04ca3 100644 (file)
@@ -1,3 +1,4 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 int verb_kernel_identify(int argc, char *argv[], void *userdata);
+int verb_kernel_inspect(int argc, char *argv[], void *userdata);
index 901533cf096fbc86d002bff6067e3ebcaa980a42..7dd1a2f5f29963e21f816496c58d0e41bc9e56b5 100644 (file)
@@ -410,6 +410,7 @@ static int bootctl_main(int argc, char *argv[]) {
                 { "remove",              VERB_ANY, 1,        0,            verb_remove              },
                 { "is-installed",        VERB_ANY, 1,        0,            verb_is_installed        },
                 { "kernel-identify",     2,        2,        0,            verb_kernel_identify     },
+                { "kernel-inspect",      2,        2,        0,            verb_kernel_inspect      },
                 { "list",                VERB_ANY, 1,        0,            verb_list                },
                 { "set-default",         2,        2,        0,            verb_set_efivar          },
                 { "set-oneshot",         2,        2,        0,            verb_set_efivar          },