From 2f9e522caf8dd029d80f1f9e0cccefeb8778e584 Mon Sep 17 00:00:00 2001 From: Jonathan Bauer Date: Wed, 31 Jul 2019 10:28:20 +0200 Subject: [slx-partitioner] renamed to slx-dmsetup --- builder/modules.d/dnbd3-rootfs/module-setup.sh | 2 +- builder/modules.d/slx-dmsetup/module-setup.sh | 17 + .../slx-dmsetup/scripts/dmsetup-slx-device | 435 +++++++++++++++++++++ .../slx-dmsetup/scripts/gen-fstab-persistent | 52 +++ .../scripts/generate-fstab-persistent.sh | 52 +++ .../slx-dmsetup/scripts/generate-fstab-swap.sh | 33 ++ .../slx-dmsetup/scripts/get-partitions-by-id | 60 +++ builder/modules.d/slx-partitioner/module-setup.sh | 17 - .../slx-partitioner/scripts/dmsetup-slx-device | 435 --------------------- .../slx-partitioner/scripts/gen-fstab-persistent | 52 --- .../scripts/generate-fstab-persistent.sh | 52 --- .../slx-partitioner/scripts/generate-fstab-swap.sh | 33 -- .../slx-partitioner/scripts/get-partitions-by-id | 60 --- 13 files changed, 650 insertions(+), 650 deletions(-) create mode 100755 builder/modules.d/slx-dmsetup/module-setup.sh create mode 100755 builder/modules.d/slx-dmsetup/scripts/dmsetup-slx-device create mode 100644 builder/modules.d/slx-dmsetup/scripts/gen-fstab-persistent create mode 100644 builder/modules.d/slx-dmsetup/scripts/generate-fstab-persistent.sh create mode 100644 builder/modules.d/slx-dmsetup/scripts/generate-fstab-swap.sh create mode 100755 builder/modules.d/slx-dmsetup/scripts/get-partitions-by-id delete mode 100755 builder/modules.d/slx-partitioner/module-setup.sh delete mode 100755 builder/modules.d/slx-partitioner/scripts/dmsetup-slx-device delete mode 100644 builder/modules.d/slx-partitioner/scripts/gen-fstab-persistent delete mode 100644 builder/modules.d/slx-partitioner/scripts/generate-fstab-persistent.sh delete mode 100644 builder/modules.d/slx-partitioner/scripts/generate-fstab-swap.sh delete mode 100755 builder/modules.d/slx-partitioner/scripts/get-partitions-by-id (limited to 'builder/modules.d') diff --git a/builder/modules.d/dnbd3-rootfs/module-setup.sh b/builder/modules.d/dnbd3-rootfs/module-setup.sh index 6d8f8ff3..a2e691c5 100755 --- a/builder/modules.d/dnbd3-rootfs/module-setup.sh +++ b/builder/modules.d/dnbd3-rootfs/module-setup.sh @@ -153,7 +153,7 @@ depends() { ' #local network_module="network" #dracut_module_included "systemd-initrd" && network_module="systemd-networkd-ext" - echo base bash kernel-modules shutdown slx-partitioner slx-tools slx-network # "$network_module" + echo base bash kernel-modules shutdown slx-dmsetup slx-tools slx-network # "$network_module" } installkernel() { local __doc__=' diff --git a/builder/modules.d/slx-dmsetup/module-setup.sh b/builder/modules.d/slx-dmsetup/module-setup.sh new file mode 100755 index 00000000..57a67626 --- /dev/null +++ b/builder/modules.d/slx-dmsetup/module-setup.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +check() { + return 255 +} +depends() { + echo "" +} +install() { + # install helpers + inst "$moddir/scripts/dmsetup-slx-device" "/usr/bin/dmsetup-slx-device" + # install hooks + inst_hook pre-pivot 10 "$moddir/scripts/generate-fstab-swap.sh" + inst_multiple head tail mkfs.ext4 mkfs.xfs fsck.ext4 fsck.xfs blockdev xxd +} +installkernel() { + instmods dm-thin-pool dm-snapshot dm-crypt crc32c ext4 xfs +} diff --git a/builder/modules.d/slx-dmsetup/scripts/dmsetup-slx-device b/builder/modules.d/slx-dmsetup/scripts/dmsetup-slx-device new file mode 100755 index 00000000..740445bb --- /dev/null +++ b/builder/modules.d/slx-dmsetup/scripts/dmsetup-slx-device @@ -0,0 +1,435 @@ +#!/usr/bin/env bash +# +# Script to back given read-only device using the block device +# specified by SLX_WRITABLE_DEVICE_IDENTIFIER in the SLX config. +# If SLX_WRITABLE_DEVICE_PARTITION_TABLE is sepcified, it will +# further create device mapper devices accordingly. +# +# Example partition config: +# +# thin-snapshot root 10G 1 +# thin-volume tmp 20G 0 +# linear data0 5-10G 1 +# linear data1 1-50% 1 +# +# NOTE: Encrypting thin-snapshot will actually encrypt the +# entire pool data device used for the pool. +# TODO: Support external keys + +type -p emergency_shell || . /lib/dracut-lib.sh + +# for debugging purposes +set -x +exec &> /run/openslx/dmsetup.log + +# read-only device to prepare for CoW +[ -z "$1" ] && emergency_shell "Read-only device was not given!" +declare -rg read_only_device="$1" +declare -rg read_only_device_size="$(blockdev --getsz $1)" + +# global array variables storing the configuration of the partitions +declare -ag linear snapshot thin_snapshot thin_volume +parse_config() { + [ -z "$1" ] && return 1 + while IFS= read -r line; do + [ -z "$line" ] && continue + read -r type name range crypt ignore <<< "$line" + type=${type//-/_} # to use the type as variable in eval + if ! [[ "$type" =~ \ + ^(linear|snapshot|thin_snapshot|thin_volume)$ ]]; then + echo "$0: Ignoring invalid type: $line" + continue + fi + if [[ -z "$name" ]]; then + echo "$0: Ignoring nameless entry: $line" + continue + fi + unset unit min max + # ranges can be like: 40G, 40-80G, 10-20% + if ! [[ $range =~ ^([0-9]+-)*([0-9])+[GgMmKkBb%]$ ]]; then + echo "$0: Ignoring invalid range: $line" + continue + fi + # process ranges: convert percentages (of read_only_device!) + # to actual sizes (in sectors!) before saving them + local unit=${range: -1} + local min="$(cut -d'-' -f1 <<< "${range%?}" )" + local max="$(cut -d'-' -f2 <<< "${range%?}" )" + if [ "$min" -gt "$max" ]; then + echo "$0: Ignoring invalid range: $line" + continue + fi + # default for bytes + local -i potency=0 + case "$unit" in + [%]) + if [ "$max" -gt 100 ]; then + echo "Ignoring invalid percentages: $min/$max" + continue + fi + min=$(( $writable_device_size * $min / 100 )) + max=$(( $writable_device_size * $max / 100 )) + ;; + [Kk]) potency=1 ;;& + [Mm]) potency=2 ;;& + [Gg]) potency=3 ;;& + *) + # => 1024 ** potency for G, M, K, etc results in bytes + # => bytes / 512 = sectors + min=$(( $min * ( 1024 ** $potency) / 512 )) + max=$(( $max * ( 1024 ** $potency) / 512 )) + ;; + esac + if ! [[ "$crypt" =~ ^[01]$ ]]; then + echo "$0: Disabling encryption due to invalid crypt argument: $line" + crypt=0 + fi + # finally save it to the global array for this type + eval "${type}"'+=("'${name} ${crypt} ${min} ${max}'")' + done <<< "$1" +} + +# Helper to call 'dmsetup setup' without syncing with udev +# and then actively create the devices with the mknodes command. +# dmsetup_create_noudevsync +dmsetup_create_noudevsync() { + ( + set -o errexit + dmsetup create "$1" --noudevsync --table "$2" + dmsetup mknodes --noudevsync "$1" + ) + local ret=$? + [ $ret -ne 0 ] && dmsetup remove --noudevsync "$1" + return $ret +} + +# encrypt_device [] +encrypt_device() { + modprobe dm-crypt || echo "$0: dm-crypt loading failed, maybe builtin?" + [ -b "$1" ] || return 1 + [ -n "$2" ] || return 1 + [ -z "$3" ] && local size="$(blockdev --getsz $1)" + local key="$(head -c32 /dev/random | xxd -p | tr -d '\n')" + if ! dmsetup_create_noudevsync "$2" \ + "0 ${3:-${size}} crypt aes-xts-plain64 $key 0 $1 0 1 allow_discards"; then + echo "$0: Failed to encrypt $1." + return 1 + fi + return 0 +} +# create_snapshot " " +create_snapshot() { + modprobe dm-snapshot || echo "$0: dm-snapshot loading failed, maybe builtin?" + read -r name persist ignore <<< "$1" + if ! dmsetup_create_noudevsync "$name" \ + "0 $read_only_device_size snapshot $read_only_device $writable_device ${persist:-N} 8"; then + echo "$0: Failed to create snapshot on '$writable_device' for '$read_only_device'." + return 1 + fi + return 0 +} + +# Call this to fallback to a RAMdisk stored under /run/openslx +# This will call terminate the whole script by calling finish_setup, if successful +ramdisk_fallback() { + echo "$0: Falling back to regular dm-snapshot on a RAMdisk." + local file="$(mktemp -u -p /run/openslx dnbd_cow.XXX)" + local size="$SLX_RAMDISK_SIZE_IN_MB" + [ -z "$size" ] && size="$(awk '/MemTotal/ {printf("%d\n", $2 / 2 / 1024 )}' /proc/meminfo)" + dd of="$file" seek="$size" bs=1M count=0 &> /dev/null + writable_device="$(losetup --show --find "$file")" + cow_device_candidate="root" + while [ -b "/dev/mapper/$cow_device_candidate" ]; do + cow_device_candidate="root.$RANDOM" + done + if [ -z "$writable_device" ] || ! create_snapshot "$cow_device_candidate N"; then + emergency_shell "CRITICAL: failed to setup RAMdisk fallback." + exit 1 + fi + finish_setup "$cow_device_candidate" "0" "$size" +} + +# finish_setup [] +# is the device name only, /dev/mapper will be prepended automatically. +# denotes if the created device lies in a RAMdisk (0) or is backed by a disk (1). +# is given in sectors. +finish_setup() { + if [ -z "$1" ] || [ ! -b "/dev/mapper/$1" ]; then + emergency_shell "'/dev/mapper/$1' not a block device. Failed to setup CoW layer." + exit 1 + fi + if ! [[ "$2" =~ ^[0-9]$ ]]; then + emergency_shell "'$2' not a valid type, 0 or 1 expected." + fi + # optional? + ( + echo "# Generated by '$0'." + echo "SLX_DNBD3_DEVICE_COW=/dev/mapper/$1" + ) >> /etc/openslx + save_partition_info "$1" "/" "$2" "$3" + exit 0 +} + +# path to save the achieved setup to +declare -rg partitions_config="/run/openslx/dmsetup.state" +cat <<-EOF > "$partitions_config" +# Generated by '$0'. +# Format: +# Options can be: +# * type -> CoW layer type: 0 is RAMdisk, 1 is disk, 2 is network +# * size -> in 512 byte sectors +EOF + +# save_partition_info [] +save_partition_info() { + [ -b "/dev/mapper/$1" ] || return 1 + [ -n "$2" ] || return 1 + [[ "$3" =~ ^[0-9]$ ]] || return 1 + local opts="type=$3" + # plain size given + [[ "$4" =~ ^[0-9]+$ ]] && opts="$opts,physical_size=$4" + # - + [[ "$4" =~ ^[0-9]+-[0-9]+$ ]] && opts="$opts,shared_physical_size=${4%-*},virtual_size=${4#*-}" + echo "/dev/mapper/$1 $2 ${opts}" >> "$partitions_config" +} + +### +## MAIN +### + +. /etc/openslx +# This is the main variable driving this script +declare -g writable_device= +if [ -n "$SLX_WRITABLE_DEVICE_IDENTIFIER" ]; then + # only first one for now TODO create linear devices of all ID44s + writable_device="$(slx-tools dev_find_partitions "$SLX_WRITABLE_DEVICE_IDENTIFIER" | head -n 1)" +fi +if [ -z "$writable_device" ]; then + echo "$0: Could not find writable device with id '$SLX_WRITABLE_DEVICE_IDENTIFIER'." + ramdisk_fallback +fi + +# NOTE: from here on out, every value related to size is in 512 bytes sectors! +declare -g writable_device_size="$(blockdev --getsz $writable_device)" + +# If SLX_WRITABLE_DEVICE_PARTITION_TABLE is not set, just do +# regular thin-snapshot for the CoW layer, else parse it. +if [ -n "$SLX_WRITABLE_DEVICE_PARTITION_TABLE" ]; then + parse_config "$SLX_WRITABLE_DEVICE_PARTITION_TABLE" +fi +# Default to thin-snapshot, if none were configured +if [ -z "$snapshot" ] && [ -z "$thin_snapshot" ]; then + parse_config "thin-snapshot root 100% 0" +fi + +# Sanity checks for weird configurations +if [ "${#snapshot[@]}" -gt 1 ]; then + echo "Multiple snapshots specified, using first one: ${snapshot[0]}" + snapshot="${snapshot[0]}" +fi +if [ "${#thin_snapshot[@]}" -gt 1 ]; then + echo "Multiple thin-snapshots specified, using first one: ${thin_snapshot[0]}" + thin_snapshot="${thin_snapshot[0]}" +fi +if [ -n "$snapshot" ] && [ -n "$thin_snapshot" ]; then + echo "$0: Both snapshot and thin-snapshot specified, prefering thin-snapshot." + snapshot= +fi + +### +## LINEAR SLICES +### + +# start allocating spaces to the configured devices +declare -g writable_device_allocated=0 +# reserve the space for the snapshot (of either type)... +read -r name crypt min max ignore <<< "${thin_snapshot:-${snapshot}}" + +declare -g scratch_device_size=0 +if (( $min <= $writable_device_size )); then + scratch_device_size=$max + while (( $scratch_device_size >= 0 )) && (( $scratch_device_size > $writable_device_size )); do + (( scratch_device_size -= 2097152 )) # 1G steps => 2097152 sectors + done + (( $scratch_device_size < $min )) && scratch_device_size="$min" +else + # minimum snapshot size is bigger than physical device size + echo "$0: Minimum snapshot size is too big for the scratch partition." + echo "$0: You probably need to use a more conservative value." + echo "$0: Using this client maximum scratch space ($writable_device_size sectors)." + scratch_device_size="$writable_device_size" +fi + +# ... and slice it from the start of the writable device (for performance). +declare -g scratch_device="/dev/mapper/scratch" +if ! dmsetup_create_noudevsync "${scratch_device##*/}" \ + "0 $scratch_device_size linear $writable_device $writable_device_allocated"; then + echo "$0: Failed to create scratch space for the CoW layer." + # TODO do not bail directly, but try to to create the linear devices at least? + ramdisk_fallback +fi +save_partition_info "${scratch_device##*/}" "*" "1" "$scratch_device_size" + +# encrypt the scratch device, if configured +if [ "$crypt" -ne 0 ] && encrypt_device \ + "$scratch_device" "${scratch_device##*/}-crypt" "$scratch_device_size"; then + scratch_device="${scratch_device##*/}-crypt" +fi + +writable_device_allocated="$scratch_device_size" + +# first setup linear slices of the writable device +for i in ${!linear[@]}; do + [ -z "${linear[$i]}" ] && continue + read -r name crypt min max ignore <<< "${linear[$i]}" + free_space=$(( $writable_device_size - $writable_device_allocated )) + if [ "$min" -gt "$free_space" ]; then + echo "$0: Not enough space left for linear devices: ${linear[$i]}" + break + fi + # allocate its max if it fits within the free space, otherwise use the space left. + to_allocate="$max" + [ "$to_allocate" -gt "$free_space" ] && to_allocate="$free_space" + + if ! dmsetup_create_noudevsync "$name" "0 $to_allocate linear $writable_device $writable_device_allocated"; then + echo "$0: Failed to create linear device: ${linear[$i]}" + continue + fi + # TODO sane? + save_partition_info "$name" "*" "1" "$to_allocate" + if [ "$crypt" -ne 0 ] && \ + ! encrypt_device "/dev/mapper/$name" "${name}-crypt" "$to_allocate"; then + echo "$0: Failed to encrypt '$name'." + fi + writable_device_allocated=$(( $to_allocate + $writable_device_allocated )) +done + +# we are done with the physical device, use the scratch space from now on +writable_device="$scratch_device" +writable_device_size="$scratch_device_size" + +### +## THIN-PROVISIONING +### +declare -rg pool_metadata_dev="/dev/mapper/pool-metadata" +declare -rg pool_data_dev="/dev/mapper/pool-data" +declare -rg pool_dev="/dev/mapper/pool" +create_pool() { + # create external snapshot for read-only device + # create remaining thin volumes + modprobe dm-thin-pool || echo "$0: dm-thin-pool load failed, maybe builtin?" + # create temporary metadata device + data_block_size=128 + # calculate number of sectors needed and check boundaries: + metadata_dev_size="$(( 48 * $writable_device_size / $data_block_size / 512 ))" + # Min 2MB -> 4096 sectors, max 16GB -> 33554432 sectors + [ "$metadata_dev_size" -lt 4096 ] && metadata_dev_size="4096" + # TODO handle the exotic case of a too large metadata device to fit within RAM. + [ "$metadata_dev_size" -gt 33554432 ] && metadata_dev_size="33554432" + # TODO handle persistent metadata device on disk + # create RAMdisk in /run for metadata device + metadata_dev="$(mktemp -p /run/openslx .pool-metadata.XXX)" + dd of="$metadata_dev" bs=512 seek="$metadata_dev_size" &> /dev/null + metadata_dev="$(losetup --show --find $metadata_dev)" + if ! dmsetup_create_noudevsync "${pool_metadata_dev##*/}" \ + "0 $metadata_dev_size linear $metadata_dev 0"; then + echo "$0: Failed to create pool metadata device on '$writable_device'." + return 1 + fi + # For persistent metadata device we will need to cut that space off first: + # writable_device_size=$(( $writable_device_size - $metadata_dev_size )) + + if ! dmsetup_create_noudevsync "${pool_data_dev##*/}" \ + "0 $writable_device_size linear $writable_device 0"; then + echo "$0: Failed to create pool data device on '$writable_device'." + return 1 + fi + low_water_mark=32 + if ! dmsetup_create_noudevsync "${pool_dev##*/}" \ + "0 $writable_device_size thin-pool $pool_metadata_dev $pool_data_dev $data_block_size $low_water_mark"; then + echo "$0: Failed to create thin-pool device on '$writable_device'." + return 1 + fi + return 0 +} + +# create_volume " " +create_volume() { + if [ -z "$pool_dev" -o ! -b "$pool_dev" ]; then + echo "$0: Global pool device not set or present." + return 1 + fi + if [ $# -ne 1 -o -z "$1" ]; then + echo "$0: create_volume requires one non-empty argument." + return 1 + fi + local name id size backing_dev ignore + read -r name id size backing_dev ignore <<< "$1" + + if ! dmsetup message "$pool_dev" 0 "create_thin $id"; then + echo "$0: Failed to create thin volume with id '$id' in pool '$pool_dev'." + echo "$0: It might already exists, trying anyway..." + fi + if ! dmsetup_create_noudevsync "$name" "0 $size thin $pool_dev $id $backing_dev"; then + echo "$0: Failed to create external snapshot named '$name':" + echo " Size: $size" + echo " Backing device: $backing_dev" + echo " Thin volume id: $id" + return 1 + fi + return 0 +} +if [ -n "$thin_snapshot" ] || [ -n "$thin_volume" ]; then + if ! create_pool ; then + echo "Failed to create thin pool. Will ignore:" + echo -e "\tThin snapshot: $(declare -p thin_snapshot)" + echo -e "\tThin volumes: $(declare -p thin_volume)" + ramdisk_fallback + fi + # the order in which pool devices are created does not matter + # so start with thin volumes starting with id 2 and end with + # the thin-snapshot with id 1 which needs to call finish_setup. + volume_id=2 + # go over thin-volumes + for i in ${!thin_volume[@]}; do + [ -z "${thin_volume[$i]}" ] && continue + read -r name crypt min max ignore <<< "${thin_volume[$i]}" + # thin-volume can be safely created with max size, + # since they are overprovisioned anyway. + if ! create_volume "$name $(( volume_id++ )) $max"; then + echo "Failed to create thin volume '$name'." + fi + save_partition_info "$name" "*" "1" "${writable_device_size}-${max}" + if [ "$crypt" -ne 0 ] && ! encrypt_device \ + "/dev/mapper/$name" "$name-crypt" "$max"; then + echo "Failed to encrypt thin volume '$name'." + fi + done + + if [ -n "$thin_snapshot" ]; then + # create thin-snapshot, use first one + read -r name crypt min max ignore <<< "$thin_snapshot" + # min/max was used for the pool data device, ignore it here! + if ! create_volume "$name 1 $read_only_device_size $read_only_device"; then + echo "Failed to create external snapshot for '$read_only_device'." + ramdisk_fallback + fi + finish_setup "$name" "1" "$writable_device_size" + fi +fi + +### +## SNAPSHOT (OLD FUNCTIONALITY) +### +if [ -n "$snapshot" ]; then + read -r name crypt min max ignore <<< "$snapshot" + if ! create_snapshot "$name $persist"; then + echo "Failed to create regular snapshot for '$read_only_device' on '$writable_device'." + ramdisk_fallback + fi + finish_setup "$name" "1" "$writable_device_size" +fi + +# ultimate fallback +ramdisk_fallback +exit 1 diff --git a/builder/modules.d/slx-dmsetup/scripts/gen-fstab-persistent b/builder/modules.d/slx-dmsetup/scripts/gen-fstab-persistent new file mode 100644 index 00000000..ed00b5de --- /dev/null +++ b/builder/modules.d/slx-dmsetup/scripts/gen-fstab-persistent @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# +# Hook to generate stage4's fstab entries for persistent partitions +# +# Persistent identifiers (MBR types, GPT partition labels) +# are expected to be specified in the OpenSLX config +# as 'SLX_PERSISTENT_DEVICE_IDENTIFIER' and their filesystem +# as 'SLX_PERSISTENT_DEVICE_FILESYSTEM', e.g ext4 or xfs. +# If not specified, will default to 'auto' but will not +# active systemd's features 'x-systemd.makefs' and 'x-systemd.growfs' + +. /etc/openslx + +type -p emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh + +# NOTE: systemd makes the mount point path automatically. +# if multiple exists, take the biggest one (first in the list) +if [ -n "$SLX_PERSISTENT_DEVICE_IDENTIFIER" ]; then + declare -a persistent_dev_list + for persistent_dev in \ + $(get_partitions_by_id ${SLX_PERSISTENT_DEVICE_IDENTIFIER//,/ /}); do + [ -z "$persistent_dev" ] && continue + persistent_dev_list+=("$persistent_dev") + done + if [ "${#persistent_dev[@]}" -gt 0 ]; then + if [ "${#persistent_dev[@]}" -gt 1 ]; then + warn "$0: More than one persistent device found." + warn "$0: Will use the biggest one: ${persistent_dev[0]}" + fi + persistent_dev_systemd_name="$( tr '/' '-' <<< ${persistent_dev[0]:1})" + persistent_mount_opts="nofail" + if [ -n "$SLX_PERSISTENT_DEVICE_FILESYSTEM" ]; then + #persistent_mount_opts+=",x-systemd.requires=ensure-fs@${persistent_dev_systemd_name}" + persistent_mount_opts+=",x-systemd.after=ensure-fs@${persistent_dev_systemd_name}" + fi + ( + echo -ne "${persistent_dev[0]}\t" + echo -ne "${SLX_PERSISTENT_DEVICE_MOUNT_POINT:-/opt/openslx/persistent}\t" + echo -ne "${SLX_PERSISTENT_DEVICE_FILESYSTEM:-auto}\t" + echo -ne "${persistent_mount_opts}\t0\t2" + ) >> "$NEWROOT/etc/fstab" + + # drop-in to create filesystem if needed and + #persistent_dev_systemd_name="$( tr '/' '-' <<< ${persistent_dev[0]:1})" + #mkdir -p "$NEWROOT/etc/systemd/system/${persistent_dev_systemd_name}" + #cat <<- EOF > "$NEWROOT" + #EOF + else + warn "$0: No device with ID '$SLX_PERSISTENT_DEVICE_IDENTIFIER' found." + fi +fi +true diff --git a/builder/modules.d/slx-dmsetup/scripts/generate-fstab-persistent.sh b/builder/modules.d/slx-dmsetup/scripts/generate-fstab-persistent.sh new file mode 100644 index 00000000..5c6f2b82 --- /dev/null +++ b/builder/modules.d/slx-dmsetup/scripts/generate-fstab-persistent.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# +# Hook to generate stage4's fstab entries for persistent partitions +# +# Persistent identifiers (MBR types, GPT partition labels) +# are expected to be specified in the OpenSLX config +# as 'SLX_PERSISTENT_DEVICE_IDENTIFIER' and their filesystem +# as 'SLX_PERSISTENT_DEVICE_FILESYSTEM', e.g ext4 or xfs. +# If not specified, will default to 'auto' but will not +# active systemd's features 'x-systemd.makefs' and 'x-systemd.growfs' + +. /etc/openslx + +type -p emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh + +# NOTE: systemd makes the mount point path automatically. +# if multiple exists, take the biggest one (first in the list) +if [ -n "$SLX_PERSISTENT_DEVICE_IDENTIFIER" ]; then + declare -a persistent_dev_list + for persistent_dev in \ + $(get-partitions-by-id ${SLX_PERSISTENT_DEVICE_IDENTIFIER//,/ /}); do + [ -z "$persistent_dev" ] && continue + persistent_dev_list+=("$persistent_dev") + done + if [ "${#persistent_dev[@]}" -gt 0 ]; then + if [ "${#persistent_dev[@]}" -gt 1 ]; then + warn "$0: More than one persistent device found." + warn "$0: Will use the biggest one: ${persistent_dev[0]}" + fi + persistent_dev_systemd_name="$( tr '/' '-' <<< ${persistent_dev[0]:1})" + persistent_mount_opts="nofail" + if [ -n "$SLX_PERSISTENT_DEVICE_FILESYSTEM" ]; then + #persistent_mount_opts+=",x-systemd.requires=ensure-fs@${persistent_dev_systemd_name}" + persistent_mount_opts+=",x-systemd.after=ensure-fs@${persistent_dev_systemd_name}" + fi + ( + echo -ne "${persistent_dev[0]}\t" + echo -ne "${SLX_PERSISTENT_DEVICE_MOUNT_POINT:-/opt/openslx/persistent}\t" + echo -ne "${SLX_PERSISTENT_DEVICE_FILESYSTEM:-auto}\t" + echo -ne "${persistent_mount_opts}\t0\t2" + ) >> "$NEWROOT/etc/fstab" + + # drop-in to create filesystem if needed and + #persistent_dev_systemd_name="$( tr '/' '-' <<< ${persistent_dev[0]:1})" + #mkdir -p "$NEWROOT/etc/systemd/system/${persistent_dev_systemd_name}" + #cat <<- EOF > "$NEWROOT" + #EOF + else + warn "$0: No device with ID '$SLX_PERSISTENT_DEVICE_IDENTIFIER' found." + fi +fi +true diff --git a/builder/modules.d/slx-dmsetup/scripts/generate-fstab-swap.sh b/builder/modules.d/slx-dmsetup/scripts/generate-fstab-swap.sh new file mode 100644 index 00000000..bb37d6cf --- /dev/null +++ b/builder/modules.d/slx-dmsetup/scripts/generate-fstab-swap.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# +# Script to create stage4's fstab entry for swap devices +# +# Will use swap partitions of MBR's type '82' or +# GPT UUID '0657fd6d-a4ab-43c4-84e5-0933c84b4f4f' +# +. /etc/openslx + +for swap_dev in \ + $(slx-tools dev_find_partitions "82" "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f"); do + + [ -z "$swap_dev" ] && continue + + # Generate swap fstab entry for NEWROOT. Use priority 10 to prefer zram + echo -e "$swap_dev\tswap\t\tswap\t\tx-systemd.makefs,pri=10\t0\t0" \ + >> "$NEWROOT/etc/fstab" + + # check if configured not to wipe any existing filesystem + [ "$SLX_WIPE_SWAP_DEVICE" = "yes" ] || continue + + # create a drop-in to wipe the device's filesystem + swap_dev_systemd_escaped="$(tr '/' '-' <<< ${swap_dev:1})" + base_dir="$NEWROOT/etc/systemd/system" + dropin_dir="$base_dir/systemd-mkswap@${swap_dev_systemd_escaped}.service.d" + mkdir -p "$dropin_dir" + cat <<- EOF > "$dropin_dir/wipefs.conf" + [Service] + ExecStartPre=/sbin/wipefs -a %f + EOF +done + +true diff --git a/builder/modules.d/slx-dmsetup/scripts/get-partitions-by-id b/builder/modules.d/slx-dmsetup/scripts/get-partitions-by-id new file mode 100755 index 00000000..2fe5ce7a --- /dev/null +++ b/builder/modules.d/slx-dmsetup/scripts/get-partitions-by-id @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# +# Get all partitions with given ids (list of /dev/sdXX) +# Examples of supported ID types: +# * MBR's type: 44 +# * GPT's UUID: 0657fd6d-a4ab-43c4-84e5-0933c84b4f4f (swap) +# * GPT's Name: OpenSLX-ID44 +# +# First argument can be a block device to limit the search to +# partitions thereof, e.g. for /dev/loop0 to look for /dev/loop0pX +# +# NOTE: for compatibility reasons, MBR's type will also +# be matched against part name 'OpenSLX-ID'. +# The output will be a list of matching devices, +# sorted from largest to smallest. +get_partitions_by_id () { + local ID dev exp target + exp= + # target for the scan, defaults to /dev to check everything + target=/dev + if [ -b "$1" ]; then + target="$1"'*' + shift + fi + # support commas and pipes to separate identifiers + local args=$@ + set -- ${args//[,|]/ } + while [ $# -gt 0 ]; do + ID=$1 + shift + [ -z "$ID" ] && continue + # if single digit, e.g. 7, look for 0x7 and 0x07 + [[ $ID =~ ^[0-9]$ ]] && ID="0?$ID" + if [[ $ID =~ ^[0-9]{2}$ ]]; then + # if double digit look for MBR types and OpenSLX-ID$ID GPT labels + exp="$exp|ID_PART_ENTRY_(NAME=OpenSLX-ID|TYPE=0x)$ID" + elif [[ $ID =~ ^(0x[0-9]{2}|[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12})$ ]]; then + # if full MBR type (e.g. 0x44) or UUID look for TYPE + exp="$exp|ID_PART_ENTRY_TYPE=$ID" + else + # something else, look for names of partitions / filesystems + exp="$exp|ID_(PART_ENTRY_NAME|FS_LABEL)=$ID" + fi + done + exp=${exp:1} + #echo "Partition find is '$exp'" >&2 + for dev in $(find $target -type b); do + udevadm info --name="$dev" | grep -iqE "($exp)\$" \ + && echo "$(blockdev --getsize64 "$dev") $dev" + done | sort -n -k1 -r | cut -d' ' -f2 +} + +## MAIN +if [ $# -eq 0 ]; then + echo "$0 needs at least one argument." + exit 1 +fi + +get_partitions_by_id $@ + diff --git a/builder/modules.d/slx-partitioner/module-setup.sh b/builder/modules.d/slx-partitioner/module-setup.sh deleted file mode 100755 index 57a67626..00000000 --- a/builder/modules.d/slx-partitioner/module-setup.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash -check() { - return 255 -} -depends() { - echo "" -} -install() { - # install helpers - inst "$moddir/scripts/dmsetup-slx-device" "/usr/bin/dmsetup-slx-device" - # install hooks - inst_hook pre-pivot 10 "$moddir/scripts/generate-fstab-swap.sh" - inst_multiple head tail mkfs.ext4 mkfs.xfs fsck.ext4 fsck.xfs blockdev xxd -} -installkernel() { - instmods dm-thin-pool dm-snapshot dm-crypt crc32c ext4 xfs -} diff --git a/builder/modules.d/slx-partitioner/scripts/dmsetup-slx-device b/builder/modules.d/slx-partitioner/scripts/dmsetup-slx-device deleted file mode 100755 index 740445bb..00000000 --- a/builder/modules.d/slx-partitioner/scripts/dmsetup-slx-device +++ /dev/null @@ -1,435 +0,0 @@ -#!/usr/bin/env bash -# -# Script to back given read-only device using the block device -# specified by SLX_WRITABLE_DEVICE_IDENTIFIER in the SLX config. -# If SLX_WRITABLE_DEVICE_PARTITION_TABLE is sepcified, it will -# further create device mapper devices accordingly. -# -# Example partition config: -# -# thin-snapshot root 10G 1 -# thin-volume tmp 20G 0 -# linear data0 5-10G 1 -# linear data1 1-50% 1 -# -# NOTE: Encrypting thin-snapshot will actually encrypt the -# entire pool data device used for the pool. -# TODO: Support external keys - -type -p emergency_shell || . /lib/dracut-lib.sh - -# for debugging purposes -set -x -exec &> /run/openslx/dmsetup.log - -# read-only device to prepare for CoW -[ -z "$1" ] && emergency_shell "Read-only device was not given!" -declare -rg read_only_device="$1" -declare -rg read_only_device_size="$(blockdev --getsz $1)" - -# global array variables storing the configuration of the partitions -declare -ag linear snapshot thin_snapshot thin_volume -parse_config() { - [ -z "$1" ] && return 1 - while IFS= read -r line; do - [ -z "$line" ] && continue - read -r type name range crypt ignore <<< "$line" - type=${type//-/_} # to use the type as variable in eval - if ! [[ "$type" =~ \ - ^(linear|snapshot|thin_snapshot|thin_volume)$ ]]; then - echo "$0: Ignoring invalid type: $line" - continue - fi - if [[ -z "$name" ]]; then - echo "$0: Ignoring nameless entry: $line" - continue - fi - unset unit min max - # ranges can be like: 40G, 40-80G, 10-20% - if ! [[ $range =~ ^([0-9]+-)*([0-9])+[GgMmKkBb%]$ ]]; then - echo "$0: Ignoring invalid range: $line" - continue - fi - # process ranges: convert percentages (of read_only_device!) - # to actual sizes (in sectors!) before saving them - local unit=${range: -1} - local min="$(cut -d'-' -f1 <<< "${range%?}" )" - local max="$(cut -d'-' -f2 <<< "${range%?}" )" - if [ "$min" -gt "$max" ]; then - echo "$0: Ignoring invalid range: $line" - continue - fi - # default for bytes - local -i potency=0 - case "$unit" in - [%]) - if [ "$max" -gt 100 ]; then - echo "Ignoring invalid percentages: $min/$max" - continue - fi - min=$(( $writable_device_size * $min / 100 )) - max=$(( $writable_device_size * $max / 100 )) - ;; - [Kk]) potency=1 ;;& - [Mm]) potency=2 ;;& - [Gg]) potency=3 ;;& - *) - # => 1024 ** potency for G, M, K, etc results in bytes - # => bytes / 512 = sectors - min=$(( $min * ( 1024 ** $potency) / 512 )) - max=$(( $max * ( 1024 ** $potency) / 512 )) - ;; - esac - if ! [[ "$crypt" =~ ^[01]$ ]]; then - echo "$0: Disabling encryption due to invalid crypt argument: $line" - crypt=0 - fi - # finally save it to the global array for this type - eval "${type}"'+=("'${name} ${crypt} ${min} ${max}'")' - done <<< "$1" -} - -# Helper to call 'dmsetup setup' without syncing with udev -# and then actively create the devices with the mknodes command. -# dmsetup_create_noudevsync
-dmsetup_create_noudevsync() { - ( - set -o errexit - dmsetup create "$1" --noudevsync --table "$2" - dmsetup mknodes --noudevsync "$1" - ) - local ret=$? - [ $ret -ne 0 ] && dmsetup remove --noudevsync "$1" - return $ret -} - -# encrypt_device [] -encrypt_device() { - modprobe dm-crypt || echo "$0: dm-crypt loading failed, maybe builtin?" - [ -b "$1" ] || return 1 - [ -n "$2" ] || return 1 - [ -z "$3" ] && local size="$(blockdev --getsz $1)" - local key="$(head -c32 /dev/random | xxd -p | tr -d '\n')" - if ! dmsetup_create_noudevsync "$2" \ - "0 ${3:-${size}} crypt aes-xts-plain64 $key 0 $1 0 1 allow_discards"; then - echo "$0: Failed to encrypt $1." - return 1 - fi - return 0 -} -# create_snapshot " " -create_snapshot() { - modprobe dm-snapshot || echo "$0: dm-snapshot loading failed, maybe builtin?" - read -r name persist ignore <<< "$1" - if ! dmsetup_create_noudevsync "$name" \ - "0 $read_only_device_size snapshot $read_only_device $writable_device ${persist:-N} 8"; then - echo "$0: Failed to create snapshot on '$writable_device' for '$read_only_device'." - return 1 - fi - return 0 -} - -# Call this to fallback to a RAMdisk stored under /run/openslx -# This will call terminate the whole script by calling finish_setup, if successful -ramdisk_fallback() { - echo "$0: Falling back to regular dm-snapshot on a RAMdisk." - local file="$(mktemp -u -p /run/openslx dnbd_cow.XXX)" - local size="$SLX_RAMDISK_SIZE_IN_MB" - [ -z "$size" ] && size="$(awk '/MemTotal/ {printf("%d\n", $2 / 2 / 1024 )}' /proc/meminfo)" - dd of="$file" seek="$size" bs=1M count=0 &> /dev/null - writable_device="$(losetup --show --find "$file")" - cow_device_candidate="root" - while [ -b "/dev/mapper/$cow_device_candidate" ]; do - cow_device_candidate="root.$RANDOM" - done - if [ -z "$writable_device" ] || ! create_snapshot "$cow_device_candidate N"; then - emergency_shell "CRITICAL: failed to setup RAMdisk fallback." - exit 1 - fi - finish_setup "$cow_device_candidate" "0" "$size" -} - -# finish_setup [] -# is the device name only, /dev/mapper will be prepended automatically. -# denotes if the created device lies in a RAMdisk (0) or is backed by a disk (1). -# is given in sectors. -finish_setup() { - if [ -z "$1" ] || [ ! -b "/dev/mapper/$1" ]; then - emergency_shell "'/dev/mapper/$1' not a block device. Failed to setup CoW layer." - exit 1 - fi - if ! [[ "$2" =~ ^[0-9]$ ]]; then - emergency_shell "'$2' not a valid type, 0 or 1 expected." - fi - # optional? - ( - echo "# Generated by '$0'." - echo "SLX_DNBD3_DEVICE_COW=/dev/mapper/$1" - ) >> /etc/openslx - save_partition_info "$1" "/" "$2" "$3" - exit 0 -} - -# path to save the achieved setup to -declare -rg partitions_config="/run/openslx/dmsetup.state" -cat <<-EOF > "$partitions_config" -# Generated by '$0'. -# Format: -# Options can be: -# * type -> CoW layer type: 0 is RAMdisk, 1 is disk, 2 is network -# * size -> in 512 byte sectors -EOF - -# save_partition_info [] -save_partition_info() { - [ -b "/dev/mapper/$1" ] || return 1 - [ -n "$2" ] || return 1 - [[ "$3" =~ ^[0-9]$ ]] || return 1 - local opts="type=$3" - # plain size given - [[ "$4" =~ ^[0-9]+$ ]] && opts="$opts,physical_size=$4" - # - - [[ "$4" =~ ^[0-9]+-[0-9]+$ ]] && opts="$opts,shared_physical_size=${4%-*},virtual_size=${4#*-}" - echo "/dev/mapper/$1 $2 ${opts}" >> "$partitions_config" -} - -### -## MAIN -### - -. /etc/openslx -# This is the main variable driving this script -declare -g writable_device= -if [ -n "$SLX_WRITABLE_DEVICE_IDENTIFIER" ]; then - # only first one for now TODO create linear devices of all ID44s - writable_device="$(slx-tools dev_find_partitions "$SLX_WRITABLE_DEVICE_IDENTIFIER" | head -n 1)" -fi -if [ -z "$writable_device" ]; then - echo "$0: Could not find writable device with id '$SLX_WRITABLE_DEVICE_IDENTIFIER'." - ramdisk_fallback -fi - -# NOTE: from here on out, every value related to size is in 512 bytes sectors! -declare -g writable_device_size="$(blockdev --getsz $writable_device)" - -# If SLX_WRITABLE_DEVICE_PARTITION_TABLE is not set, just do -# regular thin-snapshot for the CoW layer, else parse it. -if [ -n "$SLX_WRITABLE_DEVICE_PARTITION_TABLE" ]; then - parse_config "$SLX_WRITABLE_DEVICE_PARTITION_TABLE" -fi -# Default to thin-snapshot, if none were configured -if [ -z "$snapshot" ] && [ -z "$thin_snapshot" ]; then - parse_config "thin-snapshot root 100% 0" -fi - -# Sanity checks for weird configurations -if [ "${#snapshot[@]}" -gt 1 ]; then - echo "Multiple snapshots specified, using first one: ${snapshot[0]}" - snapshot="${snapshot[0]}" -fi -if [ "${#thin_snapshot[@]}" -gt 1 ]; then - echo "Multiple thin-snapshots specified, using first one: ${thin_snapshot[0]}" - thin_snapshot="${thin_snapshot[0]}" -fi -if [ -n "$snapshot" ] && [ -n "$thin_snapshot" ]; then - echo "$0: Both snapshot and thin-snapshot specified, prefering thin-snapshot." - snapshot= -fi - -### -## LINEAR SLICES -### - -# start allocating spaces to the configured devices -declare -g writable_device_allocated=0 -# reserve the space for the snapshot (of either type)... -read -r name crypt min max ignore <<< "${thin_snapshot:-${snapshot}}" - -declare -g scratch_device_size=0 -if (( $min <= $writable_device_size )); then - scratch_device_size=$max - while (( $scratch_device_size >= 0 )) && (( $scratch_device_size > $writable_device_size )); do - (( scratch_device_size -= 2097152 )) # 1G steps => 2097152 sectors - done - (( $scratch_device_size < $min )) && scratch_device_size="$min" -else - # minimum snapshot size is bigger than physical device size - echo "$0: Minimum snapshot size is too big for the scratch partition." - echo "$0: You probably need to use a more conservative value." - echo "$0: Using this client maximum scratch space ($writable_device_size sectors)." - scratch_device_size="$writable_device_size" -fi - -# ... and slice it from the start of the writable device (for performance). -declare -g scratch_device="/dev/mapper/scratch" -if ! dmsetup_create_noudevsync "${scratch_device##*/}" \ - "0 $scratch_device_size linear $writable_device $writable_device_allocated"; then - echo "$0: Failed to create scratch space for the CoW layer." - # TODO do not bail directly, but try to to create the linear devices at least? - ramdisk_fallback -fi -save_partition_info "${scratch_device##*/}" "*" "1" "$scratch_device_size" - -# encrypt the scratch device, if configured -if [ "$crypt" -ne 0 ] && encrypt_device \ - "$scratch_device" "${scratch_device##*/}-crypt" "$scratch_device_size"; then - scratch_device="${scratch_device##*/}-crypt" -fi - -writable_device_allocated="$scratch_device_size" - -# first setup linear slices of the writable device -for i in ${!linear[@]}; do - [ -z "${linear[$i]}" ] && continue - read -r name crypt min max ignore <<< "${linear[$i]}" - free_space=$(( $writable_device_size - $writable_device_allocated )) - if [ "$min" -gt "$free_space" ]; then - echo "$0: Not enough space left for linear devices: ${linear[$i]}" - break - fi - # allocate its max if it fits within the free space, otherwise use the space left. - to_allocate="$max" - [ "$to_allocate" -gt "$free_space" ] && to_allocate="$free_space" - - if ! dmsetup_create_noudevsync "$name" "0 $to_allocate linear $writable_device $writable_device_allocated"; then - echo "$0: Failed to create linear device: ${linear[$i]}" - continue - fi - # TODO sane? - save_partition_info "$name" "*" "1" "$to_allocate" - if [ "$crypt" -ne 0 ] && \ - ! encrypt_device "/dev/mapper/$name" "${name}-crypt" "$to_allocate"; then - echo "$0: Failed to encrypt '$name'." - fi - writable_device_allocated=$(( $to_allocate + $writable_device_allocated )) -done - -# we are done with the physical device, use the scratch space from now on -writable_device="$scratch_device" -writable_device_size="$scratch_device_size" - -### -## THIN-PROVISIONING -### -declare -rg pool_metadata_dev="/dev/mapper/pool-metadata" -declare -rg pool_data_dev="/dev/mapper/pool-data" -declare -rg pool_dev="/dev/mapper/pool" -create_pool() { - # create external snapshot for read-only device - # create remaining thin volumes - modprobe dm-thin-pool || echo "$0: dm-thin-pool load failed, maybe builtin?" - # create temporary metadata device - data_block_size=128 - # calculate number of sectors needed and check boundaries: - metadata_dev_size="$(( 48 * $writable_device_size / $data_block_size / 512 ))" - # Min 2MB -> 4096 sectors, max 16GB -> 33554432 sectors - [ "$metadata_dev_size" -lt 4096 ] && metadata_dev_size="4096" - # TODO handle the exotic case of a too large metadata device to fit within RAM. - [ "$metadata_dev_size" -gt 33554432 ] && metadata_dev_size="33554432" - # TODO handle persistent metadata device on disk - # create RAMdisk in /run for metadata device - metadata_dev="$(mktemp -p /run/openslx .pool-metadata.XXX)" - dd of="$metadata_dev" bs=512 seek="$metadata_dev_size" &> /dev/null - metadata_dev="$(losetup --show --find $metadata_dev)" - if ! dmsetup_create_noudevsync "${pool_metadata_dev##*/}" \ - "0 $metadata_dev_size linear $metadata_dev 0"; then - echo "$0: Failed to create pool metadata device on '$writable_device'." - return 1 - fi - # For persistent metadata device we will need to cut that space off first: - # writable_device_size=$(( $writable_device_size - $metadata_dev_size )) - - if ! dmsetup_create_noudevsync "${pool_data_dev##*/}" \ - "0 $writable_device_size linear $writable_device 0"; then - echo "$0: Failed to create pool data device on '$writable_device'." - return 1 - fi - low_water_mark=32 - if ! dmsetup_create_noudevsync "${pool_dev##*/}" \ - "0 $writable_device_size thin-pool $pool_metadata_dev $pool_data_dev $data_block_size $low_water_mark"; then - echo "$0: Failed to create thin-pool device on '$writable_device'." - return 1 - fi - return 0 -} - -# create_volume " " -create_volume() { - if [ -z "$pool_dev" -o ! -b "$pool_dev" ]; then - echo "$0: Global pool device not set or present." - return 1 - fi - if [ $# -ne 1 -o -z "$1" ]; then - echo "$0: create_volume requires one non-empty argument." - return 1 - fi - local name id size backing_dev ignore - read -r name id size backing_dev ignore <<< "$1" - - if ! dmsetup message "$pool_dev" 0 "create_thin $id"; then - echo "$0: Failed to create thin volume with id '$id' in pool '$pool_dev'." - echo "$0: It might already exists, trying anyway..." - fi - if ! dmsetup_create_noudevsync "$name" "0 $size thin $pool_dev $id $backing_dev"; then - echo "$0: Failed to create external snapshot named '$name':" - echo " Size: $size" - echo " Backing device: $backing_dev" - echo " Thin volume id: $id" - return 1 - fi - return 0 -} -if [ -n "$thin_snapshot" ] || [ -n "$thin_volume" ]; then - if ! create_pool ; then - echo "Failed to create thin pool. Will ignore:" - echo -e "\tThin snapshot: $(declare -p thin_snapshot)" - echo -e "\tThin volumes: $(declare -p thin_volume)" - ramdisk_fallback - fi - # the order in which pool devices are created does not matter - # so start with thin volumes starting with id 2 and end with - # the thin-snapshot with id 1 which needs to call finish_setup. - volume_id=2 - # go over thin-volumes - for i in ${!thin_volume[@]}; do - [ -z "${thin_volume[$i]}" ] && continue - read -r name crypt min max ignore <<< "${thin_volume[$i]}" - # thin-volume can be safely created with max size, - # since they are overprovisioned anyway. - if ! create_volume "$name $(( volume_id++ )) $max"; then - echo "Failed to create thin volume '$name'." - fi - save_partition_info "$name" "*" "1" "${writable_device_size}-${max}" - if [ "$crypt" -ne 0 ] && ! encrypt_device \ - "/dev/mapper/$name" "$name-crypt" "$max"; then - echo "Failed to encrypt thin volume '$name'." - fi - done - - if [ -n "$thin_snapshot" ]; then - # create thin-snapshot, use first one - read -r name crypt min max ignore <<< "$thin_snapshot" - # min/max was used for the pool data device, ignore it here! - if ! create_volume "$name 1 $read_only_device_size $read_only_device"; then - echo "Failed to create external snapshot for '$read_only_device'." - ramdisk_fallback - fi - finish_setup "$name" "1" "$writable_device_size" - fi -fi - -### -## SNAPSHOT (OLD FUNCTIONALITY) -### -if [ -n "$snapshot" ]; then - read -r name crypt min max ignore <<< "$snapshot" - if ! create_snapshot "$name $persist"; then - echo "Failed to create regular snapshot for '$read_only_device' on '$writable_device'." - ramdisk_fallback - fi - finish_setup "$name" "1" "$writable_device_size" -fi - -# ultimate fallback -ramdisk_fallback -exit 1 diff --git a/builder/modules.d/slx-partitioner/scripts/gen-fstab-persistent b/builder/modules.d/slx-partitioner/scripts/gen-fstab-persistent deleted file mode 100644 index ed00b5de..00000000 --- a/builder/modules.d/slx-partitioner/scripts/gen-fstab-persistent +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env bash -# -# Hook to generate stage4's fstab entries for persistent partitions -# -# Persistent identifiers (MBR types, GPT partition labels) -# are expected to be specified in the OpenSLX config -# as 'SLX_PERSISTENT_DEVICE_IDENTIFIER' and their filesystem -# as 'SLX_PERSISTENT_DEVICE_FILESYSTEM', e.g ext4 or xfs. -# If not specified, will default to 'auto' but will not -# active systemd's features 'x-systemd.makefs' and 'x-systemd.growfs' - -. /etc/openslx - -type -p emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh - -# NOTE: systemd makes the mount point path automatically. -# if multiple exists, take the biggest one (first in the list) -if [ -n "$SLX_PERSISTENT_DEVICE_IDENTIFIER" ]; then - declare -a persistent_dev_list - for persistent_dev in \ - $(get_partitions_by_id ${SLX_PERSISTENT_DEVICE_IDENTIFIER//,/ /}); do - [ -z "$persistent_dev" ] && continue - persistent_dev_list+=("$persistent_dev") - done - if [ "${#persistent_dev[@]}" -gt 0 ]; then - if [ "${#persistent_dev[@]}" -gt 1 ]; then - warn "$0: More than one persistent device found." - warn "$0: Will use the biggest one: ${persistent_dev[0]}" - fi - persistent_dev_systemd_name="$( tr '/' '-' <<< ${persistent_dev[0]:1})" - persistent_mount_opts="nofail" - if [ -n "$SLX_PERSISTENT_DEVICE_FILESYSTEM" ]; then - #persistent_mount_opts+=",x-systemd.requires=ensure-fs@${persistent_dev_systemd_name}" - persistent_mount_opts+=",x-systemd.after=ensure-fs@${persistent_dev_systemd_name}" - fi - ( - echo -ne "${persistent_dev[0]}\t" - echo -ne "${SLX_PERSISTENT_DEVICE_MOUNT_POINT:-/opt/openslx/persistent}\t" - echo -ne "${SLX_PERSISTENT_DEVICE_FILESYSTEM:-auto}\t" - echo -ne "${persistent_mount_opts}\t0\t2" - ) >> "$NEWROOT/etc/fstab" - - # drop-in to create filesystem if needed and - #persistent_dev_systemd_name="$( tr '/' '-' <<< ${persistent_dev[0]:1})" - #mkdir -p "$NEWROOT/etc/systemd/system/${persistent_dev_systemd_name}" - #cat <<- EOF > "$NEWROOT" - #EOF - else - warn "$0: No device with ID '$SLX_PERSISTENT_DEVICE_IDENTIFIER' found." - fi -fi -true diff --git a/builder/modules.d/slx-partitioner/scripts/generate-fstab-persistent.sh b/builder/modules.d/slx-partitioner/scripts/generate-fstab-persistent.sh deleted file mode 100644 index 5c6f2b82..00000000 --- a/builder/modules.d/slx-partitioner/scripts/generate-fstab-persistent.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env bash -# -# Hook to generate stage4's fstab entries for persistent partitions -# -# Persistent identifiers (MBR types, GPT partition labels) -# are expected to be specified in the OpenSLX config -# as 'SLX_PERSISTENT_DEVICE_IDENTIFIER' and their filesystem -# as 'SLX_PERSISTENT_DEVICE_FILESYSTEM', e.g ext4 or xfs. -# If not specified, will default to 'auto' but will not -# active systemd's features 'x-systemd.makefs' and 'x-systemd.growfs' - -. /etc/openslx - -type -p emergency_shell >/dev/null 2>&1 || source /lib/dracut-lib.sh - -# NOTE: systemd makes the mount point path automatically. -# if multiple exists, take the biggest one (first in the list) -if [ -n "$SLX_PERSISTENT_DEVICE_IDENTIFIER" ]; then - declare -a persistent_dev_list - for persistent_dev in \ - $(get-partitions-by-id ${SLX_PERSISTENT_DEVICE_IDENTIFIER//,/ /}); do - [ -z "$persistent_dev" ] && continue - persistent_dev_list+=("$persistent_dev") - done - if [ "${#persistent_dev[@]}" -gt 0 ]; then - if [ "${#persistent_dev[@]}" -gt 1 ]; then - warn "$0: More than one persistent device found." - warn "$0: Will use the biggest one: ${persistent_dev[0]}" - fi - persistent_dev_systemd_name="$( tr '/' '-' <<< ${persistent_dev[0]:1})" - persistent_mount_opts="nofail" - if [ -n "$SLX_PERSISTENT_DEVICE_FILESYSTEM" ]; then - #persistent_mount_opts+=",x-systemd.requires=ensure-fs@${persistent_dev_systemd_name}" - persistent_mount_opts+=",x-systemd.after=ensure-fs@${persistent_dev_systemd_name}" - fi - ( - echo -ne "${persistent_dev[0]}\t" - echo -ne "${SLX_PERSISTENT_DEVICE_MOUNT_POINT:-/opt/openslx/persistent}\t" - echo -ne "${SLX_PERSISTENT_DEVICE_FILESYSTEM:-auto}\t" - echo -ne "${persistent_mount_opts}\t0\t2" - ) >> "$NEWROOT/etc/fstab" - - # drop-in to create filesystem if needed and - #persistent_dev_systemd_name="$( tr '/' '-' <<< ${persistent_dev[0]:1})" - #mkdir -p "$NEWROOT/etc/systemd/system/${persistent_dev_systemd_name}" - #cat <<- EOF > "$NEWROOT" - #EOF - else - warn "$0: No device with ID '$SLX_PERSISTENT_DEVICE_IDENTIFIER' found." - fi -fi -true diff --git a/builder/modules.d/slx-partitioner/scripts/generate-fstab-swap.sh b/builder/modules.d/slx-partitioner/scripts/generate-fstab-swap.sh deleted file mode 100644 index bb37d6cf..00000000 --- a/builder/modules.d/slx-partitioner/scripts/generate-fstab-swap.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash -# -# Script to create stage4's fstab entry for swap devices -# -# Will use swap partitions of MBR's type '82' or -# GPT UUID '0657fd6d-a4ab-43c4-84e5-0933c84b4f4f' -# -. /etc/openslx - -for swap_dev in \ - $(slx-tools dev_find_partitions "82" "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f"); do - - [ -z "$swap_dev" ] && continue - - # Generate swap fstab entry for NEWROOT. Use priority 10 to prefer zram - echo -e "$swap_dev\tswap\t\tswap\t\tx-systemd.makefs,pri=10\t0\t0" \ - >> "$NEWROOT/etc/fstab" - - # check if configured not to wipe any existing filesystem - [ "$SLX_WIPE_SWAP_DEVICE" = "yes" ] || continue - - # create a drop-in to wipe the device's filesystem - swap_dev_systemd_escaped="$(tr '/' '-' <<< ${swap_dev:1})" - base_dir="$NEWROOT/etc/systemd/system" - dropin_dir="$base_dir/systemd-mkswap@${swap_dev_systemd_escaped}.service.d" - mkdir -p "$dropin_dir" - cat <<- EOF > "$dropin_dir/wipefs.conf" - [Service] - ExecStartPre=/sbin/wipefs -a %f - EOF -done - -true diff --git a/builder/modules.d/slx-partitioner/scripts/get-partitions-by-id b/builder/modules.d/slx-partitioner/scripts/get-partitions-by-id deleted file mode 100755 index 2fe5ce7a..00000000 --- a/builder/modules.d/slx-partitioner/scripts/get-partitions-by-id +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env bash -# -# Get all partitions with given ids (list of /dev/sdXX) -# Examples of supported ID types: -# * MBR's type: 44 -# * GPT's UUID: 0657fd6d-a4ab-43c4-84e5-0933c84b4f4f (swap) -# * GPT's Name: OpenSLX-ID44 -# -# First argument can be a block device to limit the search to -# partitions thereof, e.g. for /dev/loop0 to look for /dev/loop0pX -# -# NOTE: for compatibility reasons, MBR's type will also -# be matched against part name 'OpenSLX-ID'. -# The output will be a list of matching devices, -# sorted from largest to smallest. -get_partitions_by_id () { - local ID dev exp target - exp= - # target for the scan, defaults to /dev to check everything - target=/dev - if [ -b "$1" ]; then - target="$1"'*' - shift - fi - # support commas and pipes to separate identifiers - local args=$@ - set -- ${args//[,|]/ } - while [ $# -gt 0 ]; do - ID=$1 - shift - [ -z "$ID" ] && continue - # if single digit, e.g. 7, look for 0x7 and 0x07 - [[ $ID =~ ^[0-9]$ ]] && ID="0?$ID" - if [[ $ID =~ ^[0-9]{2}$ ]]; then - # if double digit look for MBR types and OpenSLX-ID$ID GPT labels - exp="$exp|ID_PART_ENTRY_(NAME=OpenSLX-ID|TYPE=0x)$ID" - elif [[ $ID =~ ^(0x[0-9]{2}|[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12})$ ]]; then - # if full MBR type (e.g. 0x44) or UUID look for TYPE - exp="$exp|ID_PART_ENTRY_TYPE=$ID" - else - # something else, look for names of partitions / filesystems - exp="$exp|ID_(PART_ENTRY_NAME|FS_LABEL)=$ID" - fi - done - exp=${exp:1} - #echo "Partition find is '$exp'" >&2 - for dev in $(find $target -type b); do - udevadm info --name="$dev" | grep -iqE "($exp)\$" \ - && echo "$(blockdev --getsize64 "$dev") $dev" - done | sort -n -k1 -r | cut -d' ' -f2 -} - -## MAIN -if [ $# -eq 0 ]; then - echo "$0 needs at least one argument." - exit 1 -fi - -get_partitions_by_id $@ - -- cgit v1.2.3-55-g7522