#!/sbin/busybox sh
#
# tiny init script

panic() {
    printf "panic >> %s\n" "$1"

    # TODO fix job control
    sh -l
}

parse_cmdline() {
    # turn output into list
    set -- $(cat /proc/cmdline)

    for line in "$@"; do
        value="${line##*=}"

        case "${line%%=*}" in
            debug)        debug="$value"        ;;
            init)         init="$value"         ;;
            root)         root="$value"         ;;
            root.type)    root_type="$value"    ;;
            root.opts)    root_opts="$value"    ;;
            lvm)          lvm="$value"          ;;
            lvm.name)     lvm_name="$value"     ;;
            lvm.group)    lvm_group="$value"    ;;
            lvm.args)     lvm_args="$value"     ;;
            luks)         luks="$value"         ;;
            luks.root)    luks_root="$value"    ;;
            luks.name)    luks_name="$value"    ;;
            luks.discard) luks_discard="$value" ;;
            luks.args)    luks_args="$value"    ;;
            # TODO implement
            #lvm.discard) ;;
            #lvm.conf) ;;
            #luks_header) ;;
            #luks_keyfile) ;;
        esac
    done
}

mount_pseudofs() {
    mount -t proc     none /proc
    mount -t sysfs    none /sys
    mount -t devtmpfs none /dev
}

setup_devmgr() {
    case "$devmgr" in
        udev)
            udevd -d
            udevadm trigger -c add -t subsystems
            udevadm trigger -c add -t devices
            udevadm settle
            ;;
        mdev)
            uevent mdev &
            mdev -s

            for device in /sys/bus/usb/devices/*; do
                case "${device##*/}" in [0-9]*-[0-9]*)
                    printf add > "${device}/uevent" ;;
                esac
            done

            find /sys -name modalias -type f -exec sort -u {} + |
                xargs modprobe -b > /dev/null 2>&1
            ;;
        mdevd)
            mdevd &
            mdevd-coldplug
            ;;
        *)
            panic "devmgr option broken"
            ;;
    esac
}

findfs_sh() {
    value="${1##*=}"

    case "${1%%=*}" in
        LABEL)    device="/dev/disk/by-label/${value}"    ;;
        UUID)     device="/dev/disk/by-uuid/${value}"     ;;
        PARTUUID) device="/dev/disk/by-partuuid/${value}" ;;
        /dev/*)   device="$1"                             ;;
        *)        panic "findfs option broken"            ;;
    esac

    # avoid race condition
    while [ ! -e "$device" ]; do
        sleep 0.5
        [ "$increment" ] || increment=0
        increment=$(( increment + 1 ))
        [ "$increment" = 10 ] &&
            panic "failed to lookup partition"
    done

    printf "%s\n" "$device"
}

unlock_luks() {
    [ "$luks_discard" = 1 ] &&
        luks_args="--allow-discards $luks_args"

    cryptsetup $luks_args luksOpen $(findfs_sh "$luks_root") ${luks_name:-luks_root} ||
        panic "failed to unlock luks container"
}

trigger_lvm() {
    if [ "$lvm_group" ] && [ "$lvm_name" ]; then
        lvm lvchange $lvm_args --sysinit -q -a y "${lvm_group}/${lvm_name}" > /dev/null
    elif [ "$lvm_group" ]; then
        lvm vgchange $lvm_args --sysinit -q -a y "$lvm_group" > /dev/null
    else
        lvm vgchange $lvm_args --sysinit -q -a y > /dev/null
    fi
}

mount_rootfs() {
    mount ${root_type:+-t $root_type} ${root_opts:+-o $root_opts} $(findfs_sh "$root") /mnt/root ||
        panic "failed to mount rootfs"
}

cleanup() {
    case "$devmgr" in
        udev)  udevadm control -e ;;
        mdev)  killall uevent     ;;
        mdevd) killall mdevd      ;;
    esac

    # unmount pseudofs's
    umount /dev /sys /proc
}

boot_system() {
    exec switch_root /mnt/root ${init:-/sbin/init} ||
        panic "failed to boot system"
}

/sbin/busybox --install -s

. /config ||
    panic "failed to source config"

mount_pseudofs
parse_cmdline

[ "$debug" = 1 ] && set -x

setup_devmgr

# TODO handle situations when LUKS on LVM
[ "$luks" =  1 ] && command -v cryptsetup > /dev/null 2>&1 &&
    unlock_luks

[ "$lvm"  =  1 ] && command -v lvm        > /dev/null 2>&1 &&
    trigger_lvm

mount_rootfs

[ "$debug" = 1 ] &&
    panic "dropping to shell"

cleanup
boot_system