#!/bin/bash

export PATH=/usr/bin:/bin:/usr/sbin:/sbin

INFORM_PATH=/mnt/inform
HAL_PATH=/mnt/hal
PARTLABEL_PATH=/dev/disk/by-partlabel
FS_RETRY_COUNT=10

SYNC="/bin/sync"
MKDIR="/bin/mkdir"
MOUNT="/bin/mount"
UMOUNT="/bin/umount"
DIRNAME="/bin/dirname"
REBOOT="/sbin/reboot"
BLKID="/usr/sbin/blkid"
CP="/bin/cp"
LN="/bin/ln"
TR="/usr/bin/tr"
BOW_RESTORE="/sbin/bow-restore"
export SUPERFS=""
export PART_ROOTFS=""
export PART_HAL=""

#------------------------------------------------
#       mount_partitions
#------------------------------------------------
mount_partitions() {
    "$MOUNT" -t proc none /proc
    "$MOUNT" -t sysfs none /sys
    "$MOUNT" -t smackfs smackfs /smack
    "$MOUNT" -t tmpfs tmpfs /run -o rw,nosuid,nodev,mode=755
    "$MOUNT" -t tmpfs tmpfs /tmp -o mode=1777,smackfsroot=*
    "$MOUNT" -t devtmpfs devtmpfs /dev -o nosuid,strictatime,mode=755

    "$MKDIR" /dev/pts
    "$MOUNT" -t devpts devpts /dev/pts
}

#------------------------------------------------
#       create_disk_links
#------------------------------------------------
create_disk_links() {
    "$MKDIR" -p ${PARTLABEL_PATH}
    "$BLKID" -s PARTLABEL | "$TR" -s '":=' '   ' | while read dev p name; do
        "$LN" -s ${dev} ${PARTLABEL_PATH}/${name}
    done
}

#------------------------------------------------
#       mount_inform
#------------------------------------------------
mount_inform() {
    PART_INFORM=$("$BLKID" -L "inform" -o device)
    if [ "z$PART_INFORM" != "z" ]; then
        "$MKDIR" -p ${INFORM_PATH}
        "$MOUNT" -t ext4 ${PART_INFORM} ${INFORM_PATH}
    fi
}

#------------------------------------------------
#       mkdir_p_parent
#------------------------------------------------
mkdir_p_parent() {
    dst_dir=`"$DIRNAME" "$1"`
    if [ ! -d "$dst_dir" -a ! -L "$dst_dir" ]; then
        "$MKDIR" -p "$dst_dir"
    fi
}

#------------------------------------------------
#       map_from_super
#------------------------------------------------
function map_from_super() {
    local part_name="$1"
    local part_table="$2"
    echo -e "$part_table" | /usr/sbin/dmsetup create "$part_name" &>/dev/null
    if [ $? = 0 ]
    then
        /usr/sbin/dmsetup mknodes "$part_name"
        echo "/dev/mapper/$part_name"
        return 0
    else
        echo "WARNING : SUPER FOUND BUT $part_name NOT FOUND" >&2
        return 1
    fi
}

#------------------------------------------------
#       get partition id
#------------------------------------------------
get_partition_id() {
    P_SLOT=$([[ $(</proc/cmdline) =~ partition_ab=([ab]) ]]; echo ${BASH_REMATCH[1]})
    P_SUFFIX=""

    if [ "${P_SLOT}" != "" ]; then
        P_SUFFIX="_${P_SLOT}"
        echo "Using A/B slot: ${P_SLOT}"
    fi

    SUPERFS=`/sbin/blkid -t PARTLABEL=super -o device -l`
    if [ x$SUPERFS = "x" ]
    then
        SUPERFS=`/sbin/blkid -t LABEL=super -o device -l`
    fi

    if [ x$SUPERFS != "x" ]
    then
        PARSE_DYNPARTS=`/usr/sbin/parse-dynparts "$SUPERFS" --list-tables`

        while read -r part_name part_table; do
            if [ "$part_name" = "rootfs${P_SUFFIX}" ]
            then
                PART_ROOTFS=`map_from_super "$part_name" "$part_table"`
            fi

            if [ "$part_name" = "hal${P_SUFFIX}" ]
            then
                PART_HAL=`map_from_super "$part_name" "$part_table"`
            fi
        done <<< "$PARSE_DYNPARTS"
    fi

    if [ x$PART_ROOTFS = "x" ]
    then
        PART_ROOTFS=`/sbin/blkid -t PARTLABEL=rootfs${P_SUFFIX} -o device -l`
    fi
    if [ x$PART_ROOTFS = "x" ]
    then
        PART_ROOTFS=`/sbin/blkid -L rootfs`
    fi

    PART_SYSTEM_DATA=`/sbin/blkid -t PARTLABEL=system-data -o device -l`
    if [ x$PART_SYSTEM_DATA = "x" ]
    then
        PART_SYSTEM_DATA=`/sbin/blkid -L system-data`
    fi

    PART_RAMDISK=`/sbin/blkid -t PARTLABEL=ramdisk${P_SUFFIX} -o device -l`
    if [ x$PART_RAMDISK = "x" ]
    then
        PART_RAMDISK=`/sbin/blkid -L ramdisk`
    fi

    if [ x$PART_HAL = "x" ]
    then
        PART_HAL=`/sbin/blkid -t PARTLABEL=hal${P_SUFFIX} -o device -l`
    fi
    if [ x$PART_HAL = "x" ]
    then
        PART_HAL=`/sbin/blkid -L hal`
    fi

    PART_USER=$("$BLKID" --match-token PARTLABEL=user -o device -l || "$BLKID" --match-token LABEL=user -o device -l)
}

function wait_find_partitions()
{
	for ((I=1;I<=$FS_RETRY_COUNT;I++))
	do
		get_partition_id
		if [ x$PART_ROOTFS != "x" ]
		then
			break
		fi
		echo "Waiting for rootfs block device, try $I of $FS_RETRY_COUNT..."
		sleep .5
	done
}

#------------------------------------------------
#       copy_hal_data
#------------------------------------------------
copy_hal_data() {
    if [ ! -e "/hal/.hal_list" ]; then
        return
    fi

    need_copy=0
    while read file
    do
        dst="/hal/${file}"

        if [ ! -e $dst ]; then
            need_copy=1
            break
        fi
    done < /hal/.hal_list

    if [ "$need_copy" = "1" -a "z$PART_HAL" != "z" ]; then
        #mount hal partition
        "$MKDIR" -p ${HAL_PATH}
        "$MOUNT" ${PART_HAL} ${HAL_PATH} -o ro

        #Load list and copy
        while read file
        do
            src="${HAL_PATH}/$file"
            dst="/hal/${file}"

            if [ -e $src ]; then
                mkdir_p_parent $dst

                "$CP" -f "$src" "$dst"
            else
                echo "No file exits: $file in hal.img"
            fi
        done < /hal/.hal_list

        #Done
        "$UMOUNT" ${HAL_PATH}
    fi
}

#------------------------------------------------
#       do_reboot
#------------------------------------------------
do_reboot() {
    echo "Reboot"
    "$SYNC"
    "$REBOOT"
    while [ 1 ]
    do
        sleep 1
        echo "."
    done
}

#------------------------------------------------
#       restore_checkpoint
#------------------------------------------------
restore_checkpoint() {
    # Any existing checkpoint means that the RW update was unexpectedly
    # aborded, so we must roll back the changes and update again.
    echo "Checkpoint restore"
    PART="${1}"
    FS_TYPE="$(blkid -o value -s TYPE "${PART}")"
    if [ "$FS_TYPE" = "ext4" ]; then
        "$BOW_RESTORE" "${PART}"
    elif [ "$FS_TYPE" = "f2fs" ]; then
        # f2fs does not need a restore - if the data was not commited before
        # the reboot, any changes were discarded
        :
    else
        echo "Checkpoint restore error: unknown filesystem ${FS_TYPE} on ${PART}"
    fi
}

#------------------------------------------------
#       restore_partitions
#------------------------------------------------
restore_partitions() {
    echo "Restore partitions"
    . /usr/libexec/upgrade-support/upgrade-common.inc
    if [[ "${P_SLOT}" == "" ]]
    then
        # We have only one slot, so it is likely that rootfs also has
        # a checkpoint
        restore_checkpoint "${PART_ROOTFS}"
        if [ ! "z${PART_HAL}" = "z" ]; then
            restore_checkpoint "${PART_HAL}"
        fi
    fi
    if [ ! "z${PART_USER}" = "z" ]; then
        restore_checkpoint "${PART_USER}"
    fi
    if [ ! "z${PART_SYSTEM_DATA}" = "z" ]; then
        restore_checkpoint "${PART_SYSTEM_DATA}"
    fi
}

#------------------------------------------------
#       Main Routine Start
#------------------------------------------------
echo "You entered into /sbin/init on initrd"

mount_partitions
wait_find_partitions
create_disk_links
mount_inform
restore_partitions
copy_hal_data

cd /

# Manually parse /proc/cmdline to avoid additional tools on image
read cmdline </proc/cmdline
echo "Kernel command line: $cmdline"
set -- $cmdline
while [ $# -gt 0 ]; do
    key="${1%%=*}"
    if [ "$key" = "bootmode" ]; then
        BOOT_MODE="${1#*=}"
        break;
    fi
    shift
done

if [ "z$BOOT_MODE" = "z" ]; then
    echo "BOOT_MODE was NOT defined!!"
    echo "Do reboot!!"
    do_reboot
fi
echo "BOOTMODE is ${BOOT_MODE}"

if [ -f /sbin/${BOOT_MODE}-init ]; then
    exec "/sbin/${BOOT_MODE}-init"
else
    echo "no ${BOOT_MODE}-init!!"
    echo "Do reboot!!"
    do_reboot
fi
