diff --git a/zipl/dracut/Makefile b/zipl/dracut/Makefile index a826e9c5..16634fda 100644 --- a/zipl/dracut/Makefile +++ b/zipl/dracut/Makefile @@ -15,6 +15,8 @@ NGDUMPDIR := 99ngdump # ifeq ($(HAVE_DRACUT),1) install: + $(INSTALL) -m 755 zipl_helper.prepare-ngdump \ + $(DESTDIR)$(TOOLS_LIBDIR) $(INSTALL) -m 755 -d $(DESTDIR)$(MODULESDIR) $(INSTALL) -m 755 -d $(DESTDIR)$(MODULESDIR)/$(NGDUMPDIR) $(INSTALL) -m 755 $(NGDUMPDIR)/module-setup.sh \ diff --git a/zipl/dracut/zipl_helper.prepare-ngdump b/zipl/dracut/zipl_helper.prepare-ngdump new file mode 100755 index 00000000..7f774876 --- /dev/null +++ b/zipl/dracut/zipl_helper.prepare-ngdump @@ -0,0 +1,93 @@ +#!/bin/bash +# +# Copyright IBM Corp. 2021 +# +# s390-tools is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. +# + +set -u + +DRACUT_OMIT_MODULES=( + nfs network network-manager + dbus dbus-broker dbus-daemon plymouth + znet dash resume ifcfg earlykdump + kdumpcore i18n lvm mdraid memstrack + systemd-timedated systemd-timesyncd + systemd-networkd systemd-network-manager systemd-coredump) + +[ $# -gt 0 ] || { echo "Usage: $0 " >&2; exit 1; } + +# +# Retrieve partition UUID +# +# We use PARTUUID because zipl re-formats the given partition after +# calling us, therefore, a UUID will change. +# +device=$(readlink -f $1) +disk_path=/dev/disk/by-partuuid/$(blkid -o value -s PARTUUID "$device") + +[ -e "$disk_path" ] || { echo "Couldn't find disk by PARTUUID." >&2; exit 1; } + +function get_kernel_version() +{ + local version=$(uname -r) + + echo $version +} + +function get_kernel_image() +{ + local version=$1 + + if [ -e "/boot/image-$version" ]; then + # SLES kernel image + echo "/boot/image-$version" + else + # Fedora/RHEL kernel image + echo "/boot/vmlinuz-$version" + fi +} + +# +# dracut is the standard tool for building initramfs images +# on Fedora, RHEL, and SLES. +# +function create_initrd() +{ + local disk=$1 + local kver=$2 + local initrd=$3 + local omit_modules=$(echo ${DRACUT_OMIT_MODULES[@]}) + + command -v dracut >/dev/null || + { echo "Please install dracut." >&2; return 1; } + + dracut -v --hostonly --no-hostonly-cmdline --hostonly-i18n \ + -o "$omit_modules" --add ngdump \ + --mount "$disk /ngdump ext4 defaults" \ + --kver "$kver" -f "$initrd" 2>&1 +} + +kernel_version=$(get_kernel_version) +kernel=$(get_kernel_image "$kernel_version") +[ -e "$kernel" ] || { echo "Couldn't find kernel image." >&2; exit 1; } + +initrd=$(mktemp) +create_initrd "$disk_path" "$kernel_version" "$initrd" +[ $? -eq 0 ] || { echo "Failed to create initramfs image" >&2; exit 1; } + +# +# zipl expects this script to output three variables to stdout: +# * kernel: path to bzImage file of Linux kernel +# * initrd: path to dumper initramfs image +# * cmdline: command-line for dumper's kernel +# +# The output order is irrelevant. +# + +echo "kernel=$kernel" +echo "initrd=$initrd" +echo "cmdline=reset_devices cgroup_disable=memory nokaslr numa=off irqpoll nr_cpus=1" + +exit 0 diff --git a/zipl/include/job.h b/zipl/include/job.h index 0090c652..a3d5a2a6 100644 --- a/zipl/include/job.h +++ b/zipl/include/job.h @@ -135,5 +135,6 @@ int job_get(int argc, char* argv[], struct job_data** data); void job_free(struct job_data* job); int type_from_target(char *target, disk_type_t *type); int check_job_dump_images(struct job_dump_data* dump, char* name); +int check_job_images_ngdump(struct job_dump_data* dump, char* name); #endif /* not JOB_H */ diff --git a/zipl/initramfs-tools/Makefile b/zipl/initramfs-tools/Makefile index aa65fce8..e5d0f2ef 100644 --- a/zipl/initramfs-tools/Makefile +++ b/zipl/initramfs-tools/Makefile @@ -16,6 +16,8 @@ INITPREMOUNTDIR := $(INITRAMFSTOOLSDIR)/scripts/init-premount # ifeq ($(HAVE_INITRAMFS),1) install: + $(INSTALL) -m 755 zipl_helper.prepare-ngdump \ + $(DESTDIR)$(TOOLS_LIBDIR) $(INSTALL) -m 755 -d $(DESTDIR)$(HOOKSDIR) $(INSTALL) -m 755 -d $(DESTDIR)$(INITPREMOUNTDIR) $(INSTALL) -m 755 hooks/ngdump $(DESTDIR)$(HOOKSDIR)/ diff --git a/zipl/initramfs-tools/zipl_helper.prepare-ngdump b/zipl/initramfs-tools/zipl_helper.prepare-ngdump new file mode 100755 index 00000000..5727474b --- /dev/null +++ b/zipl/initramfs-tools/zipl_helper.prepare-ngdump @@ -0,0 +1,73 @@ +#!/bin/bash +# +# Copyright IBM Corp. 2021 +# +# s390-tools is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. +# + +[ $# -gt 0 ] || { echo "Usage: $0 " >&2; exit 1; } + +# +# Retrieve partition UUID +# +# We use PARTUUID because zipl re-formats the given partition after +# calling us, therefore, a UUID will change. +# +device=$(readlink -f $1) +disk_path=/dev/disk/by-partuuid/$(blkid -o value -s PARTUUID "$device") + +[ -e "$disk_path" ] || { echo "Couldn't find disk by PARTUUID." >&2; exit 1; } + +function get_kernel_version() +{ + local version=$(uname -r) + + echo $version +} + +function get_kernel_image() +{ + local version=$1 + + echo "/boot/vmlinuz-$version" +} + +# +# initramfs-tools is the standard tool for building initramfs images +# on Ubuntu and Debian. +# +function create_initrd() +{ + local disk=$1 + local kver=$2 + local initrd=$3 + + command -v mkinitramfs >/dev/null || + { echo "Please install mkinitramfs." >&2; return 1; } + + NGDUMP=y NGDUMP_DEVICE="$disk" mkinitramfs -o "$initrd" "$kver" 2>&1 +} + +kernel_version=$(get_kernel_version) +kernel=$(get_kernel_image "$kernel_version") +[ -e "$kernel" ] || { echo "Couldn't find kernel image." >&2; exit 1; } + +initrd=$(mktemp) +create_initrd "$disk_path" "$kernel_version" "$initrd" +[ $? -eq 0 ] || { echo "Failed to create initramfs image" >&2; exit 1; } + +# +# zipl expects this script to output three variables to stdout: +# * kernel: path to bzImage file of Linux kernel +# * initrd: path to dumper initramfs image +# * cmdline: command-line for dumper's kernel +# +# The output order is irrelevant. +# + +echo "kernel=$kernel" +echo "initrd=$initrd" +echo "cmdline=reset_devices cgroup_disable=memory nokaslr numa=off irqpoll nr_cpus=1" + +exit 0 diff --git a/zipl/src/job.c b/zipl/src/job.c index 4e405d2b..ecac40d9 100644 --- a/zipl/src/job.c +++ b/zipl/src/job.c @@ -896,6 +896,92 @@ check_job_dump_images(struct job_dump_data* dump, char* name) } +int +check_job_images_ngdump(struct job_dump_data* dump, char *name) +{ + const char *helper = TOOLS_LIBDIR "/zipl_helper.prepare-ngdump"; + char *ppn_cmd = NULL; + char *line = NULL; + FILE *fp; + int rc; + + misc_asprintf(&ppn_cmd, "%s %s", helper, dump->device); + printf("Run %s\n", ppn_cmd); + + fp = popen(ppn_cmd, "r"); + if (fp == NULL) { + error_reason("Failed to run popen(%s,\"r\",)"); + free(ppn_cmd); + return -1; + } + free(ppn_cmd); + + while (fscanf(fp, "%m[^\n]\n", &line) != EOF) { + char *param = NULL; + char *value = NULL; + + int n = sscanf(line, "%m[^=]=%m[^\n]\n", ¶m, &value); + + if (n != 2) { + if (verbose) + printf("%s\n", line); + free(line); + free(param); + free(value); + continue; + } + + if (strcmp(param, "kernel") == 0) { + dump->common.image = value; + value = NULL; + } else if (strcmp(param, "initrd") == 0) { + dump->common.ramdisk = value; + value = NULL; + } else if (strcmp(param, "cmdline") == 0) { + dump->common.parmline = value; + value = NULL; + } else { + printf("%s\n", line); + } + + free(line); + free(param); + free(value); + } + + switch (pclose(fp)) { + case 0: + /* success */ + break; + case -1: + error_reason("Failed to run pclose"); + return -1; + default: + error_reason("Script could not determine dump parameters"); + return -1; + } + + rc = misc_check_readable_file(dump->common.image); + if (rc) { + error_text("Need external file '%s' for dump", + dump->common.image); + return rc; + } + dump->common.image_addr = IMAGE_LOAD_ADDRESS; + + rc = misc_check_readable_file(dump->common.ramdisk); + if (rc) { + error_text("Need external file '%s' for dump", + dump->common.ramdisk); + return rc; + } + dump->common.ramdisk_addr = UNSPECIFIED_ADDRESS; + + dump->common.parm_addr = UNSPECIFIED_ADDRESS; + return finalize_common_address_data(&dump->common, name); +} + + static int check_job_menu_data(struct job_menu_data *menu, struct job_envblk_data *envblk) {