#!/bin/sh

# This is executed as "sysinit" level, before all /etc/init.d/rcS/S* scripts.

# Warning: this file (and only this one) is executed in initramfs
# *before* /etc is copied from flash, so you can't edit this on
# flash, as it won't work. This can only be modified at build time.
# Don't run/access anything from /usr, because it is not mounted until
# the end of this file.

echo "$0: Running"

# This allows me to pass WRS_VERBOSE=y on the command line...
if [ -n "$WRS_VERBOSE" ]; then
    set -x
fi

# This used to be S01modules
insmod /lib/modules/`uname -r`/kernel/libcomposite.ko

insmod /lib/modules/`uname -r`/kernel/u_serial.ko
insmod /lib/modules/`uname -r`/kernel/usb_f_acm.ko
insmod /lib/modules/`uname -r`/kernel/g_serial.ko
rmmod g_serial
insmod /lib/modules/`uname -r`/kernel/g_serial.ko

/bin/mkdir -p /dev/pts
/bin/mkdir -p /dev/shm

# See fstab:  /dev/pts, /tmp, /sys
/bin/mount -a;

# Allow me to have a shell at this point in time,
# by passing WRS_INTERACTIVE=y in the command line.
#echo "WRS_INTERACTIVE: \"$WRS_INTERACTIVE\""
if [ -n "$WRS_INTERACTIVE" ]; then sh; fi


# At installation time, we have WRS_INSTALLING=y
if [ -n "$WRS_INSTALLING" ]; then install=true; else install=false; fi

# All special file names are factorized here. All "old" copies use
# "current-" as a prefix. And we support "previous-" too.
WRS_FW="wrs-firmware.tar"
WRS_USR="wrs-usr.tar.gz"
WRS_KER="zImage"
WRS_RAMFS="wrs-initramfs.gz"
WRS_BB="barebox.bin"

# This is an old name we need to remove so users are not confused
OLD_FW_OLDNAME="wrs-firmware-old.tar"


# This helps create the devices that we need over time (and are dynamic)
mkdev_sh () {
    f="$1/dev"
    name=$(busybox basename $1)
    maj=$(busybox awk -F: '{print $1}' $f)
    min=$(busybox awk -F: '{print $2}' $f)
    rm -f /dev/$name
    mknod /dev/$name c $maj $min
}

# Create ubi_ctrl in any case
mkdev_sh "/sys/devices/virtual/misc/ubi_ctrl"


TEE="/bin/nbtee"; # often used. And non-blocking, in case ttyGS0 is unplugged

# Installing is like updating, but there are more steps to do initially
if $install; then

    # keep /dev/ttyGS0 open, to prevent EOF being seen from the PC
    sleep 99999 > /dev/ttyGS0 &
    sleep 1; # extra delay, so sleep above opens device before echo below

    # format the ubi device and create volumes
    echo -n "Formatting UBI device..." | $TEE /dev/ttyGS0
    ubiformat -y -q /dev/mtd1; # This takes up to 40s if flash is dirty
    echo " done" | $TEE /dev/ttyGS0

    ubiattach -p /dev/mtd1
    mkdev_sh "/sys/devices/virtual/ubi/ubi0"
    ubimkvol /dev/ubi0 -s  32MiB -N boot
    ubimkvol /dev/ubi0 -s 150MiB -N usr
    ubimkvol /dev/ubi0 -s 150MiB -N update

    # be able to access them in /dev
    mkdev_sh "/sys/devices/virtual/ubi/ubi0/ubi0_0"
    mkdev_sh "/sys/devices/virtual/ubi/ubi0/ubi0_1"
    mkdev_sh "/sys/devices/virtual/ubi/ubi0/ubi0_2"

    # mount the "update" directory, and download stuff in there
    mkdir -p /update
    mount -t ubifs ubi0:update /update

    # Eth0 is already up, thanks to ip= passed by bootloader
    cd /update
    echo -n "Getting tftp://$SERVERIP/$WRS_FW ..." | $TEE /dev/ttyGS0
    busybox tftp -g -r $WRS_FW -l $WRS_FW $SERVERIP 2>&1 | $TEE /dev/ttyGS0
    while [ ! -f $WRS_FW ]; do
	echo "Downloading tftp://$SERVERIP/$WRS_FW failed" | \
		$TEE /dev/ttyGS0
	# this loops forever
	sleep 5
	busybox tftp -g -r $WRS_FW -l $WRS_FW $SERVERIP 2>&1 | $TEE /dev/ttyGS0
    done


    cd /; umount /update
    echo " done" | $TEE /dev/ttyGS0
    
else
    # Not installing, access existing UBI volumes
    ubiattach -p /dev/mtd1
    mkdev_sh "/sys/devices/virtual/ubi/ubi0"
    mkdev_sh "/sys/devices/virtual/ubi/ubi0/ubi0_0"
    mkdev_sh "/sys/devices/virtual/ubi/ubi0/ubi0_1"
    mkdev_sh "/sys/devices/virtual/ubi/ubi0/ubi0_2"
fi

# Now, whether installing or not, mount /update and check what is there
mkdir -p /update
mount -t ubifs ubi0:update /update
# Mount /boot too, as we check for files in there, later
mkdir -p /boot
mount -t ubifs ubi0:boot /boot

# Some steps later set reboot=true; prepare a sane default.
reboot=false

#whether to change date of last update
change_update_date=false

checksum_error=false

# commands below are links to the busybox from /usr, which is not mounted yet
# at this moment
md5sum_bin="/bin/busybox md5sum"
cut_bin="/bin/busybox cut"

# check checksums, but only if we have $WRS_FW archive
if [ -f /update/$WRS_FW  ]; then
    tar -xOf /update/$WRS_FW checksums.md5 &>/dev/null
    if [ $? != 0 ]; then
	echo -e "\nWarning: File with checksums for the new firmware not found\n" | $TEE /dev/ttyGS0
    else
	echo "Verifying checksums of the new firmware" | $TEE /dev/ttyGS0
	for file in `tar -tf /update/$WRS_FW`; do
	    if [ x"$file" = x"checksums.md5" ]; then
		continue;
	    fi
	    echo -n "Checking $file ... " | $TEE /dev/ttyGS0
	    sum=`tar -xOf /update/$WRS_FW $file | $md5sum_bin  | $cut_bin -f 1 -d " "`
	    expected_sum=`tar -xOf /update/$WRS_FW checksums.md5 | grep "$file" | $cut_bin -f 1 -d " "`
	    if [ x"$expected_sum" = x"" ]; then
		echo "Error no checksum found for file $file" | $TEE /dev/ttyGS0
		checksum_error=true
	    else
		echo "$expected_sum" | grep "$sum" > /dev/null
		if [ $? != 0 ]; then
		    echo "Checksum error! Expected $expected_sum, calculated $sum" | $TEE /dev/ttyGS0
		    checksum_error=true
		else
		    echo "OK" | $TEE /dev/ttyGS0
		fi
	    fi
	done
	if [ $checksum_error = true ]; then
	    echo -e "\nChecksum error! skip firmware update!\n" | $TEE /dev/ttyGS0
	    mv /update/"$WRS_FW" /update/"$WRS_FW".checksum_error
	else
	    if [ -f /update/"$WRS_FW".checksum_error ]; then
		echo "Remove file /update/"$WRS_FW".checksum_error" | $TEE /dev/ttyGS0
		rm -f /update/"$WRS_FW".checksum_error
	    fi
	fi
    fi

fi


# First: update usr: we may have the whole thing, or just wrs-usr.tar.gz
if [ -f /update/$WRS_FW -o -f /update/$WRS_USR ]; then
    # FIXME: save configuration somewhere, and recover it later
    echo -n "Extracting filesystem..." | $TEE /dev/ttyGS0
    # since we are upgrading, we'd better remove and recreate the volume
    ubirmvol /dev/ubi0 --name=usr
    ubimkvol /dev/ubi0 -s 150MiB -N usr
    # So, it's new: mount and untar, from whole-tar or usr only
    mount -t ubifs ubi0:usr /usr
    cd /usr
    if [ -f /update/$WRS_FW ]; then
	tar -xOf /update/$WRS_FW $WRS_USR | zcat | tar xf -
    else
	tar xzf /update/$WRS_USR
    fi

    sync; cd /; umount /usr
    echo " done" | $TEE /dev/ttyGS0

    # check if we have an initramfs and/or kernel too
    # FIXME: should rather check first and save a backup
    cd /boot

    if [ -f /update/$WRS_FW ]; then
	# The commands may fail because we miss wrs-firmware.tar or the content
	for file in $WRS_KER $WRS_RAMFS; do
	
	    echo -n "Trying to extract $file..." | $TEE /dev/ttyGS0
	    tar -xf /update/$WRS_FW $file &> /dev/null
	    ret=$?
	    if [ $ret = 0 ]; then
		echo " done" | $TEE /dev/ttyGS0
		reboot=true
	    else
		echo " not present in anchive" | $TEE /dev/ttyGS0
	    fi
	done
    fi
    # Do the same for barebox.bin, so we can upgrade it all in a step
    cd /tmp
    tar -xf /update/$WRS_FW $WRS_BB
    if [ -f $WRS_BB ]; then
	echo -n "Updating barebox..." | $TEE /dev/ttyGS0
	cat $WRS_BB > /dev/mtd3
	rm $WRS_BB
	echo " done" | $TEE /dev/ttyGS0
    fi

    # done: rename the firmware file (whole or usr, whatever is there)
    if [ -f /update/$WRS_FW ]; then
	mv /update/current-$WRS_FW /update/previous-$WRS_FW 2> /dev/null
	mv /update/$WRS_FW /update/current-$WRS_FW
    else
	mv /update/current-$WRS_USR  /update/previous-$WRS_USR 2> /dev/null
	mv /update/$WRS_USR  /update/current-$WRS_USR
    fi
    # And, to be sure, remove a file that may exist from a 4.0 install
    rm -f /update/$OLD_FW_OLDNAME
    change_update_date=true
fi

# Allow replacing the kernel or initramfs alone (new in v4.1 of wr-switch-sw)
for file in $WRS_KER $WRS_RAMFS; do
    if [ -f /update/$file ]; then
	echo -n "Replacing $file..." | $TEE /dev/ttyGS0
	cp /update/$file /boot; sync
	mv /update/current-$file /update/previous-${file} 2> /dev/null
	mv /update/$file /update/current-$file
	reboot=true
	echo " done" | $TEE /dev/ttyGS0
    fi
done

# Allow changing the boot loader (new in v4.1 of wr-switch-sw)
if [ -f /update/$WRS_BB ]; then
    echo -n "Updating barebox..." | $TEE /dev/ttyGS0
    cat /update/$WRS_BB > /dev/mtd3
    mv /update/current-$WRS_BB /update/previous-$WRS_BB
    mv /update/$WRS_BB /update/current-$WRS_BB
    reboot=true
    change_update_date=true
    echo " done" | $TEE /dev/ttyGS0
fi

if $change_update_date; then
    cp /update/saved_date /update/last_update > /dev/null 2>&1
fi
# If we changed bloader or kernel or initramfs, we reboot. Otherwise proceed.
if $reboot; then
    cd /
    umount /update
    umount /boot
    echo "Gentle reboot"
    reboot
    sleep 2
    # If init ignores signals before all sysinit entires from inittab are done,
    # we have to force the reboot.
    echo "Force reboot"
    # Firstly, remount / in case we use nfs
    /bin/mount -o remount,ro /
    # umount what is left
    /bin/umount -a -r
    # force reboot
    reboot -f
    # wait forever
    while true; do sleep 1; done
fi

# Here we are: boot normally: if initrd, mount /usr and copy /etc
# Otherwise do not do that, because we likely are nfs-root
if grep -q initrd= /proc/cmdline; then
    mount -t ubifs ubi0:usr /usr
    # Remove this script: avoid overwriting an open file
    rm /etc/init.d/wrs-boot-procedure;
    cp -a /usr/etc/* /etc
fi

# create dir for home dirs
mkdir -p /tmp/home
