#!/bin/sh

unset $(env | grep CONFIG_ | cut -f1 -d'=')

export PATH=/sbin:/bin:/usr/bin:/usr/sbin:/lib/udev:/usr/local/sbin:/usr/local/bin
export SHELL=/bin/sh

. /cnvres-code.sh

# ugly fix for wrong values of *_SIZE in /etc/default/tmpfs in versions < beta 1.2
RUN_SIZE=0
[ ! -e /etc/default/tmpfs ] || . /etc/default/tmpfs
case $RUN_SIZE in
    *%*)
        ;;
    *)
        [ "$RUN_SIZE" -le 10000000 ] && RUN_SIZE='10%'
        ;;
esac

/bin/mount -t sysfs -o nodev,noexec,nosuid,noatime sysfs /sys
/bin/mount -t proc -o nodev,noexec,nosuid,noatime proc /proc
echo -e "To dropdown to shell, press and hold shift on usb attached keyboard...\n"

/bin/mount -t devtmpfs -o size=262144,mode=0755 udev /dev && mkdir /dev/.udev && mkdir /dev/pts
/bin/mount -t devpts -o noexec,nosuid,gid=5,mode=0620 devpts /dev/pts
/bin/mount -t tmpfs -o rw,nosuid,noexec,noatime,size=$RUN_SIZE,mode=755 tmpfs /run && touch /run/.tmpfs && mkdir /run/initramfs && ln -s /run/initramfs /dev/.initramfs && mkdir /run/sendsigs.omit.d && mkdir /run/lock
up "/run";  chmod 666 /run/uptime-init.log

#mkdir -p /var/log
#ln -s /run/splash-daemon.log /var/log/splash-daemon.log  

[ ! -e /etc/udev/udev.conf ] || . /etc/udev/udev.conf
echo > /sys/kernel/uevent_helper
[ -x /sbin/udevd ] && udevd --daemon --resolve-names=never 2>/dev/null || /lib/systemd/systemd-udevd --daemon --resolve-names=never 2>/dev/null
udevadm trigger --action=add
up "started udev"

load_modules 2>/dev/null
up "after modprobe"

INITIALBOOT="0"
RESIZEERROR="0"
RESIZEERROR_NONFATAL="0"

export CONFIG_rootfstype="btrfs"
export CONFIG_root="LABEL=xbian-root-btrfs"
export CONFIG_init='switch_root'
export CONFIG_rootwait='10'
export CONFIG_noresizesd='0'
export CONFIG_convertfs='0'
export CONFIG_newroot="/rootfs"
export CONFIG_console="tty1"
export CONFIG_rooton='local'

export CMDLINE="$(cat /proc/cmdline)"
for OPTION in ${CMDLINE}; do
	if [ -z "$nextVal" ]; then
		OPTIONNAME=${OPTION%%=*}
		[ -z "${OPTIONNAME##*-*}" ] && { nextVal=1; OPTIONNAME=${OPTIONNAME//-/}; continue; }
		[ -z "${OPTIONNAME##*\.*}" ] && continue
	fi
	VALUE=${OPTION#*=}
	test "$VALUE" = "$OPTIONNAME" && VALUE='1'
	export CONFIG_"$OPTIONNAME"="$VALUE"
	nextVal=
done
test ! -x /usr/bin/splash && unset CONFIG_splash
up "after get cmdline"

if [ -n "$CONFIG_debug" ]; then
	unset CONFIG_rescue
	unset CONFIG_rescue_early
	unset CONFIG_rescue_late
	unset CONFIG_splash
	set -x
fi

if [ -n "$CONFIG_bootmenu" ]; then
    unset CONFIG_splash
    unset CONFIG_vnc
    udevadm settle --timeout=15
    up "dev settle"
fi

if [ -z "$CONFIG_splash" -o "$CONFIG_init" != switch_root ]; then
    unset CONFIG_splash
    touch /run/nosplash
fi

    NP=/run/$$.pipe
    mknod $NP p
    tee <$NP -a /run/initramfs/initramfs.debug & pids2kill="$pids2kill $!"
    exec 1>$NP 2>&1

trap "{ [ -e /run/do_drop ] && . /run/do_drop; [ ! -e /run/no_debug ] && [ -e /run/do_debug ] && set -x; }" USR1

test -e /howto.txt && sed -i s%\$CONFIG_newroot%$CONFIG_newroot% ./howto.txt
### hack to allow faster FEC initialisation on iMX6
grep -q 'Freescale i.MX6' /proc/cpuinfo && ip link set eth0 up &

test -n "$CONFIG_vnc" && vncrun
test -n "$CONFIG_telnet" && telnetrun

ifconfig lo inet 127.0.0.1

if [ -z "$CONFIG_norescuekbd" ]; then
    echo -e "\nLooking for keyboards ..."
    { X=0; while test ! -d /dev/input && test $X -le '7'; do sleep 0.2; X=$(($X+1)); done; }
    while true; do if test -e /dev/input/event0; then echo "Keyboard ready ..."; nice -n -10 /usr/sbin/thd --daemon --triggers /trigg.shift $(find /dev/input ! -type d) 2>/dev/null; break; else sleep 0.2; fi; done & pids2kill="$pids2kill $!"
    up "dev keyb"
fi

if [ -n "$CONFIG_splash" ]; then
    [ -n "$CONFIG_cnet" ] && m="init: starting network..." || m="init: starting..."
    sleep 0.5
    splash --infinitebar --msgtxt="$m"
fi

if [ -n "$CONFIG_cnet" ]; then
    up "before ipconfig"
    # FIXME: Network does not initialize properly if we post another splash message
    #        Running a RPi3, onboard wlan device does not work
    #        No idea atm what's causing the problem
    mkdir -p /run/network /var/lib/dhcp /etc/network/interfaces.d

    iff=/etc/network/interfaces
    echo -e "# interfaces(5) file used by ifup(8) and ifdown(8)\n# generated by initramfs. Do not modify until...\n" > $iff
    echo -e "source-directory /etc/network/interfaces.d\n\nauto lo\niface lo inet loopback\n" >> $iff

    # client-ip:[server-ip]:[gw-ip]:[netmask]:[hostname]:[device][:autoconf]
    cip=$(echo $CONFIG_cnet | cut -f1 -d ':')
    case "$cip" in
        dhcp|auto|on)
            cip=; cnf=dhcp
        ;;
        eth*|wlan*|ra*|br*|bond*)
            dev=$cip; cip=; cnf=dhcp
        ;;
        *)
            gip=$(echo $CONFIG_cnet | cut -f3 -d ':')
            msk=$(echo $CONFIG_cnet | cut -f4 -d ':')
            dev=$(echo $CONFIG_cnet | cut -f6 -d ':')
            cnf=$(echo $CONFIG_cnet | cut -f7 -d ':')
            [ -z "$cnf" ] || [ "$cnf" = auto ] || [ "$cnf" = on ] && cnf=dhcp
            [ -n "$msk" ] || msk=$(ipcalc -m $cip | awk -F= '{print $2}')
        ;;
    esac
    sleep 0.5
    if [ -z "$dev" ] && [ "$cnf" = dhcp ]; then
        for dev in $(ls -L /sys/class/net); do devs="$devs $dev"; done
        echo $devs | grep -q eth0 || devs="$devs eth0"
    else
        [ -z "$dev" ] && dev=eth0
        devs=$dev
    fi
    if echo $dev | grep -qE ^bond; then
        bmo=$(grep -wos mode=[0-9] /etc/modprobe.d/bonding.conf | awk -F= '{print $2}'); bmo=${bmo:-1}
        bm2=$(grep -wos miimon=[0-9]* /etc/modprobe.d/bonding.conf | awk -F= '{print $2}'); bm2=${bm2:-100}
        bud=$(grep -wos updelay=[0-9]* /etc/modprobe.d/bonding.conf | awk -F= '{print $2}'); bud=${bud:-200}
        bdd=$(grep -wos downdelay=[0-9]* /etc/modprobe.d/bonding.conf | awk -F= '{print $2}'); bdd=${bdd:-200}
        for d in $(ls -L /sys/class/net); do echo $d | grep -qE "ra[0-9]|wlan[0-9]|eth[0-9]" && bdevs="$bdevs $d"; done
        echo $bdevs | grep -q eth0 || bdevs=" eth0$bdevs"
    fi
    ifup_devs() {
        nd='-a'; [ -z "$1" ] || nd=$1
        to=30; [ -z "$2" ] || to=$2
        for r in $(seq 1 3); do
            ifup $nd &
            for j in $(seq 1 $to); do
                sleep 0.5
                if ! pgrep ifup >/dev/null; then
                    touch /run/network/ifup.$dev
                    echo "$dev" > /run/network/ifstate.$dev
                    for d in $bdevs; do
                        if ! ip a | grep -q "$d.*UP,"; then
                            ifdown -f $d && sleep 1 && ifup -f $d
                        fi
                    done
                    return 0
                fi
            done
            pkill ifup >/dev/null 2>&1
            for d in $(grep ^auto /etc/network/interfaces | grep -E "wlan|ra" | awk '{print $2}'); do
                pkill wpa_supplicant >/dev/null 2>&1
                ifdown -f $nd >/dev/null 2>&1
                module=$(readlink -f /sys/class/net/$d/device/driver/module); module=${module##*/}
                if [ -n "$module" ] && grep -q ^$module /proc/modules; then
                    echo "Restart $module ..."
                    rmmod $module
                    modprobe $module
                    sleep 1
                fi
            done
        done
        return 1
    }
    add_bdevs() {
        for d in $bdevs; do
            case $d in
                wlan*|ra*) echo -e "allow-hotplug $d\nauto $d\niface $d inet manual\n  bond-master $dev\n  bond-mode $bmo" >> $iff
                           echo -e "  bond-give-a-chance 10\n  wpa-bridge $dev\n  wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf\n  wireless-power off\n" >> $iff
                ;;
                eth*)      echo -e "auto $d\niface $d inet manual\n  bond-master $dev\n  bond-mode $bmo" >> $iff
                           echo -e "  pre-up ethtool -K $d tx off\n" >> $iff
                ;;
                *)         echo -e "auto $d\niface $d inet manual\n  bond-master $dev\n  bond-mode $bmo" >> $iff
                           echo "" >> $iff
                ;;
            esac
            # Somehow device state will not be stored in /run/network. So let's do it manually
            touch /run/network/ifup.$d && echo "$d" > /run/network/ifstate.$d
        done
    }
    add_bridge() {
        echo -e "  bridge_ports $@" >> $iff
        # Somehow brctl busybox applet does not work correctly here. So let's do it manually
        brctl addbr $dev
        for d in $@; do
            grep -q "auto $d" $iff || echo -e "\nauto $d\niface $d inet manual\n" >> $iff
            brctl addif $dev $d
            ifconfig $d up && touch /run/network/ifup.$d && echo "$d" > /run/network/ifstate.$d
        done
    }
    case "$cnf" in
        dhcp)
            for dev in $devs; do
                echo "Configuring $dev ($cnf) ..."
                for i in $(seq 1 5); do
                    if [ -e /sys/class/net/$dev ] || echo $dev | grep -qE ^"(br|bond)" && [ -e /sys/class/net/eth0 ]; then
                        case "$dev" in
                            wlan*|ra*|eth*|br*|bond*)
                                dhcp_ifup() {
                                    if echo "$dev" | grep -q ^bond; then
                                        add_bdevs
                                        echo -e "auto $dev\niface $dev inet dhcp\n  bond-slaves$bdevs\n  bond-primary eth0\n  bond-miimon $bm2\n  bond-downdelay $bdd\n  bond-updelay $bud\n" >> $iff
                                    else
                                        echo -e "auto $dev\niface $dev inet dhcp" >> $iff
                                        if echo "$dev" | grep -qE "wlan|ra"; then
                                            echo -e "  wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf\n  wireless-power off\n" >> $iff
                                        elif echo "$dev" | grep -q ^eth; then
                                            echo -e "  pre-up ethtool -K $dev tx off\n" >> $iff
                                        elif echo "$dev" | grep -q ^br; then
                                            add_bridge eth0
                                        fi
                                    fi
                                    ifup_devs $dev 30
                                }
                                dhcp_ipconfig() {
                                    ipconfig $dev &
                                    for j in $(seq 1 10); do
                                        sleep 0.5
                                        pgrep ipconfig >/dev/null || break
                                    done
                                    pkill ipconfig >/dev/null 2>&1
                                }
                                if echo "$dev" | grep -qE ^"eth" && which ipconfig >/dev/null; then
                                    dhcp_ipconfig $dev
                                else
                                    dhcp_ifup $dev
                                fi
                            ;;
                        esac
                        break
                    else
                        sleep 0.5
                    fi
                done
            done
        ;;
        dis|disable)
        ;;
        *)
            echo "Configuring $dev ($cip,$msk,$gip) ..."
            for i in $(seq 1 5); do
                if [ -e /sys/class/net/$dev ] || echo $dev | grep -qE ^"(br|bond)" && [ -e /sys/class/net/eth0 ]; then
                    case "$dev" in
                        wlan*|ra*|eth*|br*|bond*)
                            static_ifup() {
                                if echo "$dev" | grep -q ^bond; then
                                    add_bdevs
                                    echo -e "auto $dev\niface $dev inet static\n  bond-slaves$bdevs\n  bond-primary eth0\n  bond-miimon $bm2\n  bond-downdelay $bdd\n  bond-updelay $bud\n" >> $iff
                                else
                                    echo -e "auto $dev\niface $dev inet static" >> $iff
                                fi
                                echo "  address $cip" >> $iff
                                [ -z $msk ] || echo "  netmask $msk" >> $iff
                                [ -z $gip ] || echo "  gateway $gip" >> $iff
                                if echo "$dev" | grep -qE "wlan|ra"; then
                                    echo -e "  wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf\n  wireless-power off\n" >> $iff
                                elif echo "$dev" | grep -q ^eth; then
                                    echo -e "  pre-up ethtool -K $dev tx off\n" >> $iff
                                elif echo "$dev" | grep -q ^br; then
                                    add_bridge eth0
                                fi
                                ifup_devs $dev 6
                            }
                            static_ipconfig() {
                                ipconfig "$cip::$gip:$msk::$dev:none" &
                                for j in $(seq 1 10); do
                                    sleep 0.5
                                    pgrep ipconfig >/dev/null || break
                                done
                                pkill ipconfig >/dev/null 2>&1
                            }
                            if echo "$dev" | grep -qE ^"eth" && which ipconfig >/dev/null; then
                                static_ipconfig
                            else
                                static_ifup
                            fi
                        ;;
                    esac
                    break
                else
                    sleep 0.5
                fi
            done
        ;;
    esac
    sed -i -e :a -e '/^\n*$/{$d;N;ba' -e '}' $iff
    echo -e "\n# ...here. You can modify and add settings from here to end" >> $iff
    for dev in $(ls -L /sys/class/net | grep -vE "^bond|^tun|^lo"); do
        grep -q "auto $dev" $iff || echo -e "\nauto $dev\niface $dev inet manual" >> $iff
    done
    test -n "$CONFIG_splash" && splash --msgtxt="init: network started..." --percentage=100
    up "after ipconfig"
    export CONFIG_ip=$CONFIG_cnet
fi

[ ! -e /etc/resolv.conf ] && gen_resolv /etc/resolv.conf || gen_resolv /run/resolv.conf

export CONFIG_root=$(echo ${CONFIG_root} | tr -d '"')
[ -n "${CONFIG_rootflags}" ] && export CONFIG_rootfsopts="${CONFIG_rootflags}"

case ${CONFIG_root} in
	/dev/nfs|nfs)
		export CONFIG_rootfstype='nfs'
		export mount_bin="/bin/busybox mount"
		;;
	*)
		export mount_bin="/bin/mount"
		;;
esac
case ${CONFIG_rootfstype} in
	/dev/nfs|nfs)
		export CONFIG_root="${CONFIG_nfsroot%%,*}"
		export CONFIG_rootfstype='nfs'
		export CONFIG_rootfsopts="${CONFIG_nfsroot#*,}"
		echo ${CONFIG_nfsroot#*,} | grep -q vers=4 || export CONFIG_rootfsopts="${CONFIG_rootfsopts},nolock"
		export CONFIG_noresizesd='1'
		export CONFIG_rooton='nfs'
		chmod 777 $CONFIG_newroot
		;;
	*)
		[ -z "$CONFIG_rootfsopts" ] && export CONFIG_rootfsopts="${CONFIG_root#*,}"
		echo $CONFIG_root | grep -q ^'iSCSI=' && export CONFIG_rooton='iscsi' || export CONFIG_root="${CONFIG_root%%,*}"
		;;
esac
if [ "${CONFIG_rootfsopts}" = "${CONFIG_root}" ]; then
	export CONFIG_rootfsopts=""
fi

[ -n "$CONFIG_rescue_early" ] && drop_shell

test -n "$CONFIG_bootmenu" && { setconsole -r; echo "Waiting for block devices" && udevadm settle; /bootmenu; }

test -n "$CONFIG_splash" && splash --infinitebar --msgtxt="init: waiting for root..."

if [ "$CONFIG_rootfstype" != "nfs" ]; then
    [ "$CONFIG_rootwait" -lt 10 ] && export CONFIG_rootwait=10
    while ! get_root; do
        modprobe -q usb_storage
        echo "Waiting for root ($CONFIG_rootwait)..."
        if [ "$CONFIG_rootwait" -le 0 -o -e /run/do_drop ]; then
            [ -e /run/do_drop ] || echo "Root partition ${CONFIG_root} missing"
            drop_shell
            break
        fi
        CONFIG_rootwait=$(($CONFIG_rootwait-1))
        sleep 1
    done

    resize_part

    case "${CONFIG_rootfstype}" in
        zfs)
            resize_zfspool
            export CONFIG_root=${CONFIG_rootfs}
            up "after resize"
        ;;
        *)
            resize_ext4; convert_btrfs
            up "after resize, convert"

            ln -s ${CONFIG_root} /dev/root
            up "root block device set"
        ;;
    esac

    [ "$CONFIG_partswap" = 1 ] && export CONFIG_partswap=250
    [ -n "$CONFIG_partswap" ] && create_swap

else
    if echo $CONFIG_root | grep -q ^"[0-9.]*:/"; then
        export CONFIG_server=${CONFIG_root%%\:*}
    else
        [ -n "$CONFIG_server" ] || export CONFIG_server=$(echo $CONFIG_ip | awk -F: '{print $2}')
        CONFIG_root=$CONFIG_server:$CONFIG_root
    fi
    while ! ping $CONFIG_server -c1 -W1 >/dev/null 2>&1 && [ "$CONFIG_rootwait" -gt 0 ]; do
        echo "Waiting for server $CONFIG_server ($CONFIG_rootwait)..."
        CONFIG_rootwait=$(($CONFIG_rootwait-1))
    done
fi

### LVM
if [ -e /sbin/lvm ]; then
   test -n "$CONFIG_splash" && splash --msgtxt="detecting LVM volumes..."
   modprobe dm-mod
   lvm vgscan --ignorelockingfailure
   lvm vgchange -aly --ignorelockingfailure
fi
### LVM end

[ -n "$CONFIG_rescue" ] && drop_shell

# mount root partition
echo "Mounting root as: mount -t ${CONFIG_rootfstype} -o ${CONFIG_rootfsopts} ${CONFIG_root} $CONFIG_newroot" >&2
if ! $mount_bin -t ${CONFIG_rootfstype} -o noatime,${CONFIG_rootfsopts} ${CONFIG_root} $CONFIG_newroot; then
	if [ "$CONFIG_rootfstype" != btrfs ] || ! btrfs check --clear-space-cache v1 ${CONFIG_root} || ! $mount_bin -t ${CONFIG_rootfstype} -o space_cache=v2,noatime,${CONFIG_rootfsopts} ${CONFIG_root} $CONFIG_newroot; then
		echo "Mounting root partition ${CONFIG_root} failed" >&2
		drop_shell "noumount"
	fi
fi
up "after mount"

set_time
hostname -F ${CONFIG_newroot}/etc/hostname && touch /run/hostname.init

modify_interfaces
up "after net/interfaces file"

[ -n "$CONFIG_rescue" ] && drop_shell

[ "$CONFIG_rootfstype" = btrfs ] && resize_btrfs "fs resize..."
up "after resize_btrfs"

echo "Moving root" >&2
move_root

[ -n "$CONFIG_rescue_late" ] && drop_shell "noumount"

test -n "${CONFIG_splash}" && splash --msgtxt="init: running system..." --percentage=15

pids2kill="$pids2kill $(pidof thd)"

up "switch root"

for rp in udhcpc dhclient wpa_supplicant; do
    pids=$(pgrep $rp)
    for p in $pids; do
        cmd="$(cat /proc/$p/cmdline | tr '\000' ' ')"
        if [ "$rp" != wpa_supplicant ] || ! echo $CONFIG_devinuse | grep -qE "wlan|ra"; then
            echo "Restart $cmd" >&2
            kill $p && chroot $CONFIG_newroot $cmd 2>/dev/null
            sed -i "s/$p/$(pgrep $rp)/" /run/sendsigs.omit.d/*
        fi
    done
done

if test -n "$CONFIG_debug"; then set -- --verbose $@; fi
if test -n "$CONFIG_startupevent"; then set -- --startup-event=$CONFIG_startupevent $@; fi
if test -n "$CONFIG_defaultconsole"; then set -- --default-console=$CONFIG_defaultconsole $@; fi
#unset debug
set +x
up "$@"; rm /dev /proc /sys /run

mkdir /dev
for f in tty console; do
    ln -s /rootfs/dev/$f /dev/$f
done

echo "Switching root" >&2

[ -n "$CONFIG_splash" -o $CONFIG_init != switch_root ] || chvt 7

for p in $pids2kill; do kill $p >/dev/null 2>&1; done
rm -f $CONFIG_newroot$NP $CONFIG_newroot/run/do_drop $CONFIG_newroot/run/do_debug $CONFIG_newroot/run/no_debug

if [ ${CONFIG_init} = switch_root ]; then
	exec $CONFIG_init $CONFIG_newroot /sbin/init "$@" <$CONFIG_newroot/dev/console >$CONFIG_newroot/dev/console
else
	set -- $(echo "$@" | tr ' ' '\n' | grep -vE "telnet|vnc|noswap|partswap|splash|nohdparm|startup-event|mountall" | tr '\n' ' ')
#	exec /sbin/switch_root $CONFIG_newroot ${CONFIG_init} "$@" <$CONFIG_newroot/dev/console >$CONFIG_newroot/dev/console
	exec run-init $CONFIG_newroot ${CONFIG_init} "$@" <$CONFIG_newroot/dev/console >$CONFIG_newroot/dev/console
fi

kill_splash
echo "Failed to switch_root, dropping to a shell" >&2
exec /bin/sh
