summaryrefslogtreecommitdiff
path: root/src/boot/bootctl-uki.c
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2023-01-17 22:06:06 +0100
committerGerd Hoffmann <kraxel@redhat.com>2023-01-18 14:32:14 +0100
commita05255981ba5b04f1cf54ea656fbce1dfd9c3a68 (patch)
treeb0b29f717ae55d538bc328c4c1236d7af968b517 /src/boot/bootctl-uki.c
parent53c368d71ba43da7414ac86c58291a11da05ba84 (diff)
downloadsystemd-a05255981ba5b04f1cf54ea656fbce1dfd9c3a68.tar.gz
bootctl: add kernel-inspect command
Takes a kernel image as argument. Prints details about the kernel. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'src/boot/bootctl-uki.c')
-rw-r--r--src/boot/bootctl-uki.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/src/boot/bootctl-uki.c b/src/boot/bootctl-uki.c
index 1a439afaae..aa2868fb11 100644
--- a/src/boot/bootctl-uki.c
+++ b/src/boot/bootctl-uki.c
@@ -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;
+}