#!/bin/sh

type getarg > /dev/null 2>&1 || . /lib/dracut-lib.sh

if getargbool 0 rd.live.debug -n -y rdlivedebug; then
    exec > /tmp/create-overlay.$$.out
    exec 2>> /tmp/create-overlay.$$.out
    set -x
fi

gatherData() {
    overlay=$(getarg rd.live.overlay)
    if [ -z "$overlay" ]; then
        info "Skipping overlay creation: kernel command line parameter 'rd.live.overlay' is not set"
        exit 0
    fi
    # shellcheck disable=SC2086
    if ! str_starts ${overlay} LABEL=; then
        die "Overlay creation failed: the partition must be set by LABEL in the 'rd.live.overlay' kernel parameter"
    fi

    overlayLabel=${overlay#LABEL=}
    # shellcheck disable=SC2086
    if [ -b /dev/disk/by-label/${overlayLabel} ]; then
        info "Skipping overlay creation: overlay already exists"
        exit 0
    fi

    filesystem=$(getarg rd.live.overlay.cowfs)
    [ -z "$filesystem" ] && filesystem="ext4"
    if [ "$filesystem" != "ext4" ] && [ "$filesystem" != "xfs" ] && [ "$filesystem" != "btrfs" ]; then
        die "Overlay creation failed: only ext4, xfs, and btrfs are supported in the 'rd.live.overlay.cowfs' kernel parameter"
    fi

    live_dir=$(getarg rd.live.dir)
    [ -z "$live_dir" ] && live_dir="LiveOS"

    [ -z "$1" ] && exit 1
    rootDevice=$1

    # The kernel command line's 'root=' parameter was parsed into the $root variable by the dmsquash-live module.
    # $root contains the path to a symlink within /dev/disk/by-label, which points to a partition.
    # This script needs that partition's parent block device.
    # shellcheck disable=SC2046
    # shellcheck disable=SC2086
    rootDeviceAbsolutePath=$(readlink -f ${rootDevice})
    rootDeviceSysfsPath=/sys/class/block/${rootDeviceAbsolutePath##*/}
    if [ -f "${rootDeviceSysfsPath}/partition" ]; then
        # shellcheck disable=SC2086
        read -r partition < ${rootDeviceSysfsPath}/partition
    else
        partition=0
    fi
    # shellcheck disable=SC2086
    read -r readonly < ${rootDeviceSysfsPath}/ro
    # shellcheck disable=SC2086
    if [ "$partition" != "1" ] || [ "$readonly" != "0" ]; then
        info "Skipping overlay creation: unpartitioned or read-only media detected"
        exit 0
    fi
    # shellcheck disable=SC2046
    # shellcheck disable=SC2086
    fullDriveSysfsPath=$(readlink -f ${rootDeviceSysfsPath}/..)
    blockDevice=/dev/${fullDriveSysfsPath##*/}
    currentPartitionCount=$(grep --count -E "${blockDevice#/dev/}[0-9]+" /proc/partitions)

    # shellcheck disable=SC2086
    freeSpaceStart=$(parted --script ${blockDevice} unit % print free \
        | awk -v x=${currentPartitionCount} '$1 == x {getline; print $1}')
    if [ -z "$freeSpaceStart" ]; then
        info "Skipping overlay creation: there is no free space after the last partition"
        exit 0
    fi
    partitionStart=$((${freeSpaceStart%.*} + 1))
    if [ $partitionStart -eq 100 ]; then
        info "Skipping overlay creation: there is not enough free space after the last partition"
        exit 0
    fi

    overlayPartition=${blockDevice}$((currentPartitionCount + 1))

    label=$(blkid --match-tag LABEL --output value "$rootDevice")
    uuid=$(blkid --match-tag UUID --output value "$rootDevice")
    if [ -z "$label" ] || [ -z "$uuid" ]; then
        die "Overlay creation failed: failed to look up root device label and UUID"
    fi
}

createPartition() {
    # shellcheck disable=SC2086
    parted --script --align optimal ${blockDevice} mkpart primary ${partitionStart}% 100%
}

createFilesystem() {
    # shellcheck disable=SC2086
    mkfs.${filesystem} -L ${overlayLabel} ${overlayPartition}

    baseDir=/run/initramfs/create-overlayfs
    mkdir -p ${baseDir}
    # shellcheck disable=SC2086
    mount -t ${filesystem} ${overlayPartition} ${baseDir}

    mkdir -p ${baseDir}/${live_dir}/ovlwork
    # shellcheck disable=SC2086
    mkdir ${baseDir}/${live_dir}/overlay-${label}-${uuid}

    umount ${baseDir}
    rm -r ${baseDir}
}

main() {
    gatherData "$1"
    createPartition
    udevsettle
    createFilesystem
    udevsettle
}

main "$1"
