#!/bin/sh
set -eu

log() {
    echo "[init] $*" >&2
}

panic() {
    echo "initramfs panic: $*" >&2
    exec sh
}

mount_or_panic() {
    mount "$@" || panic "mount failed: $*"
}

mount_retry() {
    dev="$1"
    target="$2"
    fstype="$3"
    opts="$4"

    i=0
    while :; do
        if mount -o "$opts" -t "$fstype" "$dev" "$target"; then
            return 0
        fi

        i=$((i + 1))
        [ "$i" -ge 50 ] && panic "Timed out mounting $dev on $target"
        sleep 0.2
    done
}

wait_for_path() {
    path="$1"
    i=0
    while [ ! -e "$path" ]; do
        i=$((i + 1))
        [ "$i" -ge 50 ] && panic "Timed out waiting for $path"
        sleep 0.2
    done
}

mkdir -p /dev /proc /sys /run
mount_or_panic -t devtmpfs devtmpfs /dev
mount_or_panic -t proc proc /proc
mount_or_panic -t sysfs sysfs /sys
mount_or_panic -t tmpfs tmpfs /run

echo 1 > /proc/sys/kernel/printk

mkdir -p /dev/pts
mount_or_panic -t devpts devpts /dev/pts

# Optional early fan kick. Do not fail boot if this path is not ready yet.
if [ -w /sys/class/hwmon/hwmon0/pwm1 ]; then
    echo 100 > /sys/class/hwmon/hwmon0/pwm1 || true
fi

log "Booting kernel took $(cut -d' ' -f1 /proc/uptime) seconds."

. /etc/build-info || panic "failed to source /etc/build-info"

ROOT_DEV=""
DATA_DEV=""

for arg in $(cat /proc/cmdline); do
    case "$arg" in
        root=*)
            ROOT_DEV="${arg#root=}"
            ;;
        data=*)
            DATA_DEV="${arg#data=}"
            ;;
    esac
done

[ -n "$ROOT_DEV" ] || {
    log "No root= specified in cmdline"
    exec sh
}

[ -n "$DATA_DEV" ] || {
    log "No data= specified in cmdline"
    exec sh
}

wait_for_path "$DATA_DEV"

e2fsck -p "$DATA_DEV" || {
    echo "Auto fsck failed, forcing repair"
    e2fsck -y "$DATA_DEV" || panic "fsck failed on $DATA_DEV"
}

mkdir -p /newroot
mount_retry "$ROOT_DEV" /newroot ext4 ro
mount_retry "$DATA_DEV" /newroot/data ext4 rw

mount_or_panic --bind /newroot/data/var /newroot/var

mount_or_panic -t overlay overlay \
    -o lowerdir=/newroot/etc,upperdir=/newroot/data/etc-overlay/upper,workdir=/newroot/data/etc-overlay/work \
    /newroot/etc

mount_or_panic --move /dev /newroot/dev
mount_or_panic --move /proc /newroot/proc
mount_or_panic --move /sys /newroot/sys
mount_or_panic --move /run /newroot/run

log "Switching root to $ROOT_DEV"
exec switch_root /newroot /sbin/init

panic "switch_root returned unexpectedly"
