Files
s390-tools/netboot/mk-s390image
Marc Hartmayer 419f042f55 netboot: Improve error reporting in mk-s390image
If an input file is not readable return a proper error message indicating
this.

Before:

$ mk-s390image /var/lib/libvirt/images/hades/vmlinux-s390x out.img
mk-s390image: Unrecognized file format for /var/lib/libvirt/images/hades/vmlinux-s390x

After:

$ mk-s390image /var/lib/libvirt/images/hades/vmlinux-s390x out.img
mk-s390image: File /var/lib/libvirt/images/hades/vmlinux-s390x cannot be read, no read permission

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2025-12-01 13:45:36 +01:00

214 lines
4.7 KiB
Bash
Executable File

#!/bin/bash
#
# netboot - PXE-style boot for KVM on s390
#
# Sample script to build a single s390 boot image consisting of
# kernel, an initial ramdisk and kernel parameters from
# individual components. Note that bash is required to run this script!
#
# Sample invocation:
#
# ./mk-s390image /boot/image -r /boot/initrd image
#
# The resulting image can be used to build a bootable
# ISO or as firmware image for KVM.
#
# Copyright IBM Corp. 2017
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
# Offsets
OFFS_INITRD_START_BYTES=66568
OFFS_INITRD_SIZE_BYTES=66576
OFFS_COMMANDLINE_MAX_SIZE_BYTES=66608
OFFS_COMMANDLINE_BYTES=66688
LEGACY_MAX_PARMFILE_SIZE=896
# Variables
cmd=$(basename -- "$0")
kernel=
ramdisk=
parmfile=
image=
binval=
success=no
# Cleanup on exit
# shellcheck disable=SC2317
cleanup()
{
if [ -n "$binval" ]
then
rm -f -- "$binval"
fi
if [ -n "$image" ] && [ "$success" = no ]
then
rm -- "$image"
fi
}
trap cleanup EXIT
# Usage
usage()
{
cat <<-EOF
Usage: $cmd KERNEL BOOT_IMAGE [-r RAMDISK] [-p PARMFILE]
Build an s390 image BOOT_IMAGE suitable for CD/tape/network boot or as a
KVM firmware image using a stripped Linux kernel file KERNEL.
OPTIONS
-p Use PARMFILE with kernel parameters in the image
-r Include RAMDISK in the image
-h Print this help, then exit
-v Print version information, then exit
EOF
}
printversion()
{
cat <<-EOD
$cmd: version %S390_TOOLS_VERSION%
Copyright IBM Corp. 2017
EOD
}
# Convert decimal number to big endian doubleword
dec2be64()
{
local num=$1
local b
local i
for i in $(seq 1 8)
do
b="\\x$(printf '%x' "$((num % 256))")$b"
num=$((num / 256)) || true
done
printf '%b' "$b"
}
max_kernel_cmdline_size()
{
local __kernel=$1 size v
size_be="$(od -A n -j "${OFFS_COMMANDLINE_MAX_SIZE_BYTES}" -N 8 -t uL -- "$__kernel")"
# If little endian then swap bytes
if (("$(printf '\1' | od -dAn)" == 1)); then
v="$(printf '%016x0' "$size_be")"
size="0x${v:14:2}${v:12:2}${v:10:2}${v:8:2}${v:6:2}${v:4:2}${v:2:2}${v:0:2}"
else
size="$size_be"
fi
if ((size == 0)); then
size="${LEGACY_MAX_PARMFILE_SIZE}"
fi
# Use arithmetic expression to remove leading and trailing whitespace.
printf '%s' "$((size))"
}
# Do the image build
dobuild()
{
local i
local kernel_size
local ramdisk_size
local ramdisk_offset
local parmfile_size
# check whether all specified files exist
for i in $kernel $ramdisk $parmfile
do
if [ ! -f "$i" ]
then
echo "$cmd: File $i not found" >&2
return 1
fi
if [ ! -r "$i" ]
then
echo "$cmd: File $i cannot be read, no read permission" >&2
return 1
fi
done
if ! file -b -- "$(readlink -f -- "$kernel")" | grep "Linux S390" > /dev/null
then
echo "$cmd: Unrecognized file format for $kernel" >&2
return 1
fi
# from now on we SHOULD only fail on disk shortage
# or file permissions, let the shell handle that
set -e
# copy over kernel padded with zeroes to page boundary
dd if="$kernel" of="$image" bs=4096 conv=sync status=none
# append ramdisk if specified
if [ "$ramdisk" != "" ]
then
ramdisk_size=$(du -b -L -- "$ramdisk" | cut -f1)
# shellcheck disable=SC2034
kernel_size=$(du -b -L -- "$kernel" | cut -f1)
ramdisk_offset=$(du -b -L -- "$image" | cut -f1)
cat -- "$ramdisk" >> "$image"
binval=$(mktemp)
dec2be64 "$ramdisk_offset" > "$binval"
dd seek=$OFFS_INITRD_START_BYTES if="$binval" of="$image" bs=1 \
count=8 conv=notrunc status=none
dec2be64 "$ramdisk_size" > "$binval"
dd seek=$OFFS_INITRD_SIZE_BYTES if="$binval" of="$image" bs=1 \
count=8 conv=notrunc status=none
fi
# set cmdline
if [ "$parmfile" != "" ]
then
max_parmfile_size=$(max_kernel_cmdline_size "$kernel")
parmfile_size=$(du -b -L -- "$parmfile" | cut -f1)
if (( parmfile_size <= max_parmfile_size ));
then
# Clear any previous parameters
dd seek=$OFFS_COMMANDLINE_BYTES bs=1 count="$max_parmfile_size" \
if=/dev/zero of="$image" conv=notrunc status=none
dd seek=$OFFS_COMMANDLINE_BYTES bs=1 count="$parmfile_size" \
if="$parmfile" of="$image" conv=notrunc status=none
else
echo "$cmd: Size $parmfile_size of $parmfile exceeds command line limit of $max_parmfile_size bytes" >&2
return 1
fi
fi
# we've done it
success=yes
}
# check args and build
# shellcheck disable=SC2086,SC2048
if args=$(getopt "r:p:hv" $*)
then
# shellcheck disable=SC2086
set -- $args
while [ "$1" != "" ]
do
case $1 in
-r) ramdisk=$2; shift 2;;
-p) parmfile=$2; shift 2;;
-h) usage; exit 0;;
-v) printversion; exit 0;;
--) shift; break;;
*) echo "$cmd: Unexpected argument $1, exiting..." >&2; exit 1;;
esac
done
fi
if [ $# = 2 ]
then
kernel=$1
image=$2
dobuild
exit 0
fi
# something wasn't right
usage >&2
exit 1