#!/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)

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

mnt_pseudofs() {
    mount -t proc none /proc
    mount -t sysfs none /sys
    mount -t devtmpfs none /dev
    mount -t tmpfs none /tmp
}

setup_mdev() {
    # setup hotplugger
    if [ -e /proc/sys/kernel/hotplug ]; then
        printf /sbin/mdev > /proc/sys/kernel/hotplug
    else
        uevent mdev &
    fi

    # trigger mdev
    mdev -s

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

    # load drivers
    find /sys -name modalias -type f -exec sort -u "{}" "+" | xargs modprobe -qba
}

setup_mdevd() {
    # setup daemon
    mdevd &
    # trigger uevents
    mdevd-coldplug
}

setup_udev() {
    udevd --daemon
    udevadm trigger --action=add --type=subsystems
    udevadm trigger --action=add --type=devices
    udevadm settle
}

findfs_sh() {
    case "${1%%=*}" in
        LABEL)    device="/dev/disk/by-label/${1##*=}" ;;
        UUID)     device="/dev/disk/by-uuid/${1##*=}" ;;
        PARTUUID) device="/dev/disk/by-partuuid/${1##*=}" ;;
        /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 --quiet --sysinit -a y "${lvm_group}/${lvm_name}" > /dev/null
    elif [ "$lvm_group" ]; then
        lvm vgchange $lvm_args --quiet --sysinit -a y "$lvm_group" > /dev/null
    else
        lvm vgchange $lvm_args --quiet --sysinit -a y > /dev/null
    fi
}

mnt_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
        mdev)  { printf "" > /proc/sys/kernel/hotplug || killall uevent; } > /dev/null 2>&1 ;;
        mdevd) killall mdevd ;;
        udev)  udevadm control --exit ;;
    esac

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

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"

mnt_pseudofs
parse_cmdline

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

case "$devmgr" in
    mdev)  setup_mdev ;;
    mdevd) setup_mdevd ;;
    udev)  setup_udev ;;
    *)     panic "devmgr option broken" ;;
esac

# TODO handle situations when LUKS on LVM
[ "$luks" =  1 ] && [ -x "$(command -v cryptsetup)" ] && unlock_luks
[ "$lvm"  =  1 ] && [ -x "$(command -v lvm)"        ] && trigger_lvm
mnt_rootfs
[ "$debug" = 1 ] && panic "dropping to shell"
cleanup
boot_system