blob: e79938f6d7ebd41924c32f7a1ba316f5d5104136 (
plain) (
tree)
|
|
#!/usr/bin/env bash
type emergency_shell > /dev/null 2>&1 || source /lib/dracut-lib.sh
source /etc/openslx
export PATH="/usr/local/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/lib"
# hardcode dnbd device path
declare -rg _dnbd3_dev="/dev/dnbd0"
# all outputs are redirected to stderr, since this functions should
# only echo the path to the unpacked container to stdout.
container_unpack_raw() {
local in_device="$1"
local out_device="$(losetup -f)"
if ! losetup "$out_device" "$in_device" --partscan; then
echo "Failed to attach '$in_device' to '$out_device'."
return 1
fi >&2
udevadm settle >&2
echo "$out_device"
}
container_unpack_xloop() {
local in_device="$1"
local out_device="$(xlosetup -f)"
for kmod in xloop xloop_file_fmt_qcow xloop_file_fmt_raw; do
if ! modprobe "${kmod}"; then
echo "Failed to load kernel module: $kmod"
fi
done >&2
if ! xlosetup -r -t QCOW "$out_device" "$in_device" --partscan; then
echo "Failed to attach '$in_device' to '$out_device'."
return 1
fi >&2
udevadm settle >&2
echo "$out_device"
}
# endregion
# region connect dnbd3 image
# Determine path to dnbd3 image: either on the kcl or via config file
declare -r KCL_DNBD3_IMAGE="$(getarg slx.stage4.path=)"
if [ -n "$KCL_DNBD3_IMAGE" ]; then
SLX_DNBD3_IMAGE="$KCL_DNBD3_IMAGE"
echo "SLX_DNBD3_IMAGE='$SLX_DNBD3_IMAGE'" >> /etc/openslx
fi
if [ -z "$SLX_DNBD3_IMAGE" ]; then
emergency_shell "Failed to determine which DNBD3 image to use." \
"It was neither specified on kernel command line nor in the" \
"configuration file."
fi
declare -r KCL_DNBD3_RID="$(getarg slx.stage4.rid=)"
if [ -n "$KCL_DNBD3_RID" ]; then
# specified on the KCL?
SLX_DNBD3_RID="$KCL_DNBD3_RID"
echo "SLX_DNBD3_RID='$SLX_DNBD3_RID'" >> /etc/openslx
fi
if [ -n "$SLX_DNBD3_RID" ]; then
_dnbd3_client_additional_args=("--rid" "$SLX_DNBD3_RID")
fi
if ! modprobe dnbd3; then
echo "Failed to load kernel module: dnbd3"
fi
for try in {1..5} ""; do
if [ -z "$try" ]; then
emergency_shell "Failed to connect '${SLX_DNBD3_IMAGE}'" \
"(revision: ${SLX_DNBD3_RID:-0})" \
"from one of '$SLX_DNBD3_SERVERS' to '$_dnbd3_dev'." \
"Check if the image exists on one of the servers" \
"and if any is reachable from this client."
fi
echo "Trying hosts '$SLX_DNBD3_SERVERS'."
if dnbd3-client \
--host "$SLX_DNBD3_SERVERS" \
--image "$SLX_DNBD3_IMAGE" \
--device "$_dnbd3_dev" \
"${_dnbd3_client_additional_args[@]}"; then
break
fi
sleep 1
done
# endregion
# region unpack dnbd3 image
if [[ $SLX_QCOW_HANDLER = xmount ]]; then
emergency_shell "xmount support is unmaintained, broken, and has been removed. Consider using xloop"
exit 1
fi
if ! [[ $SLX_QCOW_HANDLER =~ ^(kernel|xloop|raw)?$ ]]; then
emergency_shell "Unsupported image handler: $SLX_QCOW_HANDLER" \
"Use either 'raw' or 'xloop'."
fi
if [ -z "$SLX_QCOW_HANDLER" ]; then
SLX_QCOW_HANDLER="xloop"
echo "SLX_QCOW_HANDLER='$SLX_QCOW_HANDLER'" >> /etc/openslx
fi
if [[ $SLX_QCOW_HANDLER =~ ^(kernel|xloop)$ ]]; then
read_only_device="$(container_unpack_xloop "$_dnbd3_dev")"
fi
if [ -z "$read_only_device" ]; then
read_only_device="$(container_unpack_raw "$_dnbd3_dev")"
fi
# Fail fast if unpacking dnbd3 image failed.
if [ -z "$read_only_device" ]; then
emergency_shell "Failed to unpack the qcow2 image!"
fi
# endregion
# region find system partition within image
if [[ "$SLX_SYSTEM_PARTITION_IDENTIFIER" =~ ^\+[0-9]+$ ]]; then
# Partition number, e.g. +2 for second partition
#
num="${SLX_SYSTEM_PARTITION_IDENTIFIER#+}"
if [ -b "${read_only_device}p${num}" ]; then
read_only_partition="${read_only_device}p${num}"
elif [ -b "${read_only_device}${num}" ]; then
read_only_partition="${read_only_device}${num}"
fi
else
# Find requested root partition by MBRID, GPT label, or GPT type - default to SLX_SYS label
#
declare -a parts
parts=( "${read_only_device}"?* )
if [ -b "${parts[0]}" ]; then
# There is at least one partition on the device, scan
mapfile -t parts < <( slx-tools dev_find_partitions \
"$read_only_device" "${SLX_SYSTEM_PARTITION_IDENTIFIER:-SLX_SYS}" )
if [ "${#parts[@]}" = 1 ]; then
# One match, perfect
read_only_partition="${parts[0]}"
echo "Found read-only partition by identifier: $read_only_partition"
elif [ "${#parts[@]}" = 0 ]; then
# Nothing found, scan all partitions. This will include the device itself.
parts=( "$read_only_device"* )
fi
# If we found 2 or more matching partitions, they'll be probed below
else
# No partitions on device - check if it's a file-system
parts=( "$read_only_device" )
fi
fi
if [ -z "$read_only_partition" ]; then
# Do a scan
echo "Don't know which partition to use, trying all candidates (${parts[*]})"
p="/tmp/mounttest"
mkdir -p "$p"
for part in "${parts[@]}"; do
if mount -v -o ro "$part" "$p"; then
# See if it looks like a system partition
if [ -x "$p/sbin/init" ] || [ -x "$p/lib/systemd/systemd" ]; then
umount -lf "$p"
echo "Found init on $part, will try to boot off of it."
read_only_partition="$part"
break
fi
umount -lf "$p"
fi
done
fi
# endregion
if [ -z "$read_only_partition" ]; then
echo "Failed to find bootable partition"
exit 1
fi
if ! [ -b "$read_only_partition" ]; then
echo "Bootable partition $read_only_partition does not exist, or is not a block device"
exit 1
fi
echo "Using read-only partition: $read_only_partition"
# region add rw layer to dnbd3 image
# don't be fooled to think we are done, the next part is crucial
dmsetup-slx-device "$read_only_partition"
udevadm settle
# endregion
|