#!/bin/bash

# 文件放在 /usr/share/initramfs-tools/scripts/local-bottom/ 目录下
# 权限为 0755，执行 update-initramfs -u

PREREQ=""

prereqs()
{
    echo "$PREREQ"
}

case $1 in
    prereqs)
        prereqs
        exit 0
        ;;
esac

. /scripts/local-bottom/recovery-utils

NEED_BACKUP=
NEED_RESTORE=
NEED_ROLLBACK=
FACTORY_RESTORE=
RECOVERY_TYPE=

ROOT_UUID=
RESTORE_UUID=
RESTORE_UUID_MOUNT_POINT=
FSTABLE_PATH=
LOG_FILE=
RESTORE_POINT=
V20RESTORE_PATH=
V20RESTORE_LIST=
V20RESTORE_TAR=
V20_BACKUP_LIVE=
GRUB_BACKUP_SCHEME=

V20TARGETDATAPATH="/targetdata"

unset_global_var()
{
    unset NEED_BACKUP
    unset NEED_RESTORE
    unset NEED_ROLLBACK
    unset FACTORY_RESTORE
    unset RECOVERY_TYPE

    unset ROOT_UUID
    unset RESTORE_UUID
    unset RESTORE_UUID_MOUNT_POINT
    unset FSTABLE_PATH
    unset LOG_FILE
    unset RESTORE_POINT
    unset V20RESTORE_PATH
    unset V20RESTORE_LIST
    unset V20_BACKUP_LIVE
    unset GRUB_BACKUP_SCHEME
}

# 根据传入的UUID，挂载指定的分区
mount_backup()
{
    local rootpath=${rootmnt}
    local fstable_path=$FSTABLE_PATH
    local logfile=$LOG_FILE
    local errcode=err_uuid_not_exist

    while read fstabline; do
        # eg: UUID=bfc917ad-6f18-462b-af29-9bc823fd726d       /    ext4    rw,relatime    0 1
        if [ "${fstabline:0:5}" != "UUID=" ]; then
            continue
        fi

        uuid=$(echo "$fstabline" | awk '{print $1}')
        if echo $uuid | grep -E -q "^UUID="; then
            uuid=$(echo "$uuid" | awk -F '=' '{print $2}')
        fi

        if [ $RESTORE_UUID != $uuid ]; then
            continue
        fi

        errcode=0  # match RESTORE_UUID
        mountpoint=$(echo "$fstabline" | awk '{print $2}')
        if [ $mountpoint = "/" ]; then
            continue
        fi

        # 设置需要还原的备份文件所在的挂载点
        RESTORE_UUID_MOUNT_POINT=$rootpath$mountpoint
        write_log "mount_backup: mountpoint = $mountpoint, uuid = $uuid"

        if [ ! -e $RESTORE_UUID_MOUNT_POINT ]; then
            write_log " Warnning! mount_backup $RESTORE_UUID_MOUNT_POINT not exit, create it "
            mkdir -p $RESTORE_UUID_MOUNT_POINT
        fi

        mount -U $uuid $RESTORE_UUID_MOUNT_POINT &>>$logfile
        if [ $? -ne 0 ]; then
            write_log " mount_backup mount error !, exit "
            return $err_mount_failed
        fi
    done < "$fstable_path"

    return $errcode
}

rsync_restore()
{
    local rootpath=${rootmnt}
    local logfile=$LOG_FILE

    write_log "rsync_restore call is_fstab_exist"
    is_fstab_exist
    local errcode=$?
    if [ $errcode -ne 0 ]; then
        write_log " rsync_restore: is_fstab_exist error, rootpath = $rootpath, errcode = $errcode"
        return $errcode
    fi

    write_log "rsync_restore call mount_fstab"
    mount_fstab
    errcode=$?
    if [ $errcode -ne 0 ]; then
        write_log " rsync_restore call mount_type=$mount_type error !, errcode = $errcode "
        return $errcode
    fi

    RESTORE_UUID_MOUNT_POINT=$(echo $(lsblk --output UUID,MOUNTPOINT | grep $RESTORE_UUID) | awk '{print $2}')
    if [ -z "$RESTORE_UUID_MOUNT_POINT" ]; then
        write_log "rsync_restore get restore mount point failed"
        return 1
    fi

    write_log "rsync_restore RESTORE_UUID_MOUNT_POINT=$RESTORE_UUID_MOUNT_POINT"
#    local latest_backup=${RESTORE_UUID_MOUNT_POINT}"/backup/system/snapshots/last"
    local latest_backup=${RESTORE_UUID_MOUNT_POINT}$RESTORE_POINT
    write_log "latest_backup=$latest_backup"
    write_log "`lsblk -f`"
    write_log "`ls -l $latest_backup`"
#    local restore_src=${rootpath}`readlink $latest_backup`"/"
    local restore_src=$latest_backup"/"
    local restore_dest=${rootpath}
    write_log "rsync_restore restore_src=$restore_src"
    write_log "`ls -l $restore_src`"

    exclude_file=${restore_src}"/../exclude.list"
    write_log "exclude_file: begin"
    write_log "`cat $exclude_file`"
    write_log "exclude_file: end"

    write_log "call rsync_restore begin, exclude_file=$exclude_file, rootpath=$rootpath, logfile=$logfile"
#    plymouth_output "call rsync_restore begin, exclude_file=$exclude_file, rootpath=$rootpath, logfile=$logfile"

    write_log "rsync_restore call rsync begin ..."
#    plymouth_output "rsync_restore call rsync begin ..."
    write_log "latest_backup=$latest_backup --> restore_src=$restore_src"
    # Run rsync to restore snapshot
    local rsyncArgs="-avAXHr --no-inc-recursive --ignore-missing-args --delete --info=progress2 --force"
    rsync $rsyncArgs --exclude-from $exclude_file $restore_src $restore_dest &>>$logfile
    errcode=$?
    if [ $errcode -eq 24 ]; then
        write_log "rsync file has vanished , ignore errcode=$errcode"
        errcode=0
    fi

    if [ $errcode -eq 23 ]; then
        write_log "rsync Operation not supported , ignore errcode=$errcode"
        errcode=0
    fi

    if [ $errcode -ne 0 ]; then
        write_log " rsync restore error !, errcode = $errcode "
        # 需要在umount前先备份日志到真实系统
        return $err_rsync_failed
    fi

    write_log "rsync_restore end ..."
#    plymouth_output "rsync_restore call rsync end ..."
    return 0
}

rsync_v20_restore()
{
    local logfile=$LOG_FILE
    write_log "****** rsync_v20_restore call start ..."
    local restore_src="/V20SRCLOOPPATH";
    local restore_dest="/V20TARGETPATH"
    local restore_args=$1
    # 解析镜像文件路径和分区挂载对应关系
    local imgFilePath=${restore_args%%[*}
    local partMountKeyValue=${restore_args#*[}
    write_log "****** imgFilePath is : ${imgFilePath}"
    write_log "****** partMountKeyValue : ${partMountKeyValue}"

    mkdir ${restore_src}
    mkdir ${restore_dest}

    # mount镜像文件
    mount -t squashfs ${V20TARGETDATAPATH}${imgFilePath} ${restore_src} &>>$logfile
    write_log "****** done *** mount -t squashfs ${V20TARGETDATAPATH}${imgFilePath} ${restore_src}"

    write_log "****** lsblk info : "
    write_log "`lsblk -f`"

    # 处理挂载
    local keyValues=${partMountKeyValue//[/ }
    for i in ${keyValues}; do
        local v20MountSrcItem=""
        while [ x"${v20MountSrcItem}" = x ] ; do
            v20MountSrcItem=$(lsblk -pln -o NAME,UUID | grep ${i%:*} | awk '{print $1}')
        done
        local v20MountDestItem=${i#*:}
        write_log "****** mount source : ${v20MountSrcItem} mount dest : ${v20MountDestItem}"

        # 挂载目标分区，并清理数据
        mkdir -p ${restore_dest}${v20MountDestItem}
        mount ${v20MountSrcItem} ${restore_dest}${v20MountDestItem} &>>$logfile
        write_log "****** done *** mount ${v20MountSrcItem} ${restore_dest}${v20MountDestItem}"
        rm -rf ${restore_dest}${v20MountDestItem}/* &>>$logfile
        write_log "****** done *** rm -rf ${restore_dest}${v20MountDestItem}/*"
    done

    write_log "****** lsblk info : "
    write_log "`lsblk -f`"

    local rsyncArgs="-aAXHi --verbose --delete --force --sparse --stats --delete-excluded --no-inc-recursive  --info=progress2 --ignore-missing-args"
    write_log "****** rsync arg is : $rsyncArgs"

    # 开始对拷还原 
    echo "start restore, wait..."
    rsync ${rsyncArgs} ${restore_src}/* ${restore_dest} >/dev/null 2>>$logfile

    # 异常处理
    errcode=$?
    if [ $errcode -eq 24 ]; then
        write_log "rsync_v20_restore file has vanished , ignore errcode=$errcode"
        errcode=0
    fi

    if [ $errcode -eq 23 ]; then
        write_log "rsync_v20_restore Operation not supported , ignore errcode=$errcode"
        errcode=0
    fi

    if [ $errcode -ne 0 ]; then
        write_log "****** rsync restore error !, errcode = $errcode "
        return $err_rsync_failed
    fi
    write_log "****** done *** rsync ${rsyncArgs} ${restore_src} ${restore_dest}"

    # 卸载并清理挂载的目录
    local partUnMountKeyValue="[${partMountKeyValue}"
    while [ x"${partUnMountKeyValue}" != x ] ; do
        local v20UmountDestItem=${partUnMountKeyValue##*[}
        partUnMountKeyValue=${partUnMountKeyValue%[*}
        umount ${restore_dest}${v20UmountDestItem#*:} &>>$logfile
        write_log "****** done *** umount ${restore_dest}${v20UmountDestItem#*:}"
    done

    umount ${restore_src} &>>$logfile
    umount ${restore_dest} &>>$logfile
    write_log "****** done *** umount ${restore_src} and ${restore_dest}"

    rm -rf ${restore_src} &>>$logfile
    rm -rf ${restore_dest} &>>$logfile
    write_log "****** done *** rm -rf ${restore_src} and ${restore_dest}"

    write_log "****** rsync_restore call end ..."
}

read_uos_recovery_conf()
{
    local uos_recovery_conf=${rootmnt}"/etc/uos-recovery/uos-recovery.ini"
    if [ ! -e "$uos_recovery_conf" ]; then
        write_log "read_uos_recovery_conf: uos-recovery.ini file not exist!"
        return $err_uos_recovery_ini_not_exist
    fi

    local restore_section="restore"
    local do_restore_key="do_restore"

    local do_restore_val=$(ini_get $uos_recovery_conf $restore_section $do_restore_key)
    if [ "$do_restore_val" = "true" ]; then
        NEED_RESTORE="yes"
    else
        NEED_RESTORE="no"
        return 0
    fi
    write_log "read_uos_recovery_conf do_restore_val=$do_restore_val, NEED_RESTORE=$NEED_RESTORE"

    local recovery_type_key="recovery_type"
    local recovery_type_val=$(ini_get $uos_recovery_conf $restore_section $recovery_type_key)
    write_log "read_uos_recovery_conf recovery_type_val=$recovery_type_val"
    if [ "$recovery_type_val" = "0" ]; then
        RECOVERY_TYPE="Rsync"
    elif [ "$recovery_type_val" = "1" ]; then
        RECOVERY_TYPE="OSTree"
    elif [ "$recovery_type_val" = "2" ]; then
        RECOVERY_TYPE="BtrfsSnapshot"
    elif [ "$recovery_type_val" = "3" ]; then
        RECOVERY_TYPE="LvmSnapshot"
    elif [ "$recovery_type_val" = "4" ]; then
        #参考RecoveryType中的RsyncV20类型的值
        RECOVERY_TYPE="RsyncV20"
    else
        RECOVERY_TYPE=""
    fi

    local backup_uuid_key="backup_device_uuid"
    RESTORE_UUID=$(ini_get $uos_recovery_conf $restore_section $backup_uuid_key)
    write_log "read_uos_recovery_conf RESTORE_UUID=$RESTORE_UUID"
    if [ -z "$RESTORE_UUID" ]; then
        write_log "error: read_uos_recovery_conf RESTORE_UUID=$RESTORE_UUID"
        return 1;
    fi

    local backup_point_key="backup_point"
    RESTORE_POINT=$(ini_get $uos_recovery_conf $restore_section $backup_point_key)
    write_log "read_uos_recovery_conf RESTORE_POINT=$RESTORE_POINT"
    if [ -z "$RESTORE_POINT" ]; then
        write_log "error: read_uos_recovery_conf RESTORE_POINT=$RESTORE_POINT"
        return 1;
    fi

    V20RESTORE_PATH=$(ini_get $uos_recovery_conf $restore_section "v20_restore_path")
    V20RESTORE_PATH=`echo $V20RESTORE_PATH | sed -e 's/^[ \"]*//g' -e 's/[ \"]*$//g'`
    write_log "read_uos_recovery_conf, V20RESTORE_PATH = $V20RESTORE_PATH"
    V20RESTORE_LIST=$(ini_get $uos_recovery_conf $restore_section "v20_restore_list")
    V20RESTORE_LIST=`echo $V20RESTORE_LIST | sed -e 's/^[ \"]*//g' -e 's/[ \"]*$//g'`
    write_log "read_uos_recovery_conf, V20RESTORE_LIST = $V20RESTORE_LIST"
    V20RESTORE_TAR=$(ini_get $uos_recovery_conf $restore_section "v20_restore_tar")
    V20RESTORE_TAR=`echo $V20RESTORE_TAR | sed -e 's/^[ \"]*//g' -e 's/[ \"]*$//g'`
    write_log "read_uos_recovery_conf, V20RESTORE_TAR = $V20RESTORE_TAR"

    write_log "read_uos_recovery_conf, RECOVERY_TYPE = $RECOVERY_TYPE, NEED_RESTORE = $NEED_RESTORE"

    return 0
}

reset_do_restore()
{
    local uos_recovery_conf=${rootmnt}"/etc/uos-recovery/uos-recovery.ini"
    local restore_section="restore"
    local auto_restore_key="auto_restore"
    local do_restore_key="do_restore"
    local auto_restore_val=$(ini_get $uos_recovery_conf $restore_section $auto_restore_key)
    write_log "read_uos_recovery_conf auto_restore_val=$auto_restore_val"
    if [ "$auto_restore_val" = "true" ]; then
        ini_set $uos_recovery_conf $do_restore_key "true"
    else
        ini_set $uos_recovery_conf $do_restore_key "false"
    fi
}

main()
{
    for x in $LIVE_BOOT_CMDLINE; do
        case $x in
            back_scheme=*)
                GRUB_BACKUP_SCHEME=${x#back_scheme=}
                ;;
            live-media-path=*)
                V20_BACKUP_LIVE=${x#live-media-path=}
                ;;
        esac
    done

    if [ "$V20_BACKUP_LIVE" = "usr/doppel" ] || [ "$GRUB_BACKUP_SCHEME" = "recovery" ]; then
        #echo "nothing need to do here"
        exit 0
    fi

    init_log

    read_uos_recovery_conf
    local errcode=$?
    if [ $errcode -ne 0 ]; then
        write_log " main read_uos_recovery_conf error !, errcode = $errcode"
        copy_log
        if [ $errcode = $err_uos_recovery_ini_not_exist ]; then
            #echo "read_uos_recovery_conf error, return, do nothing"
            exit 0
        fi
        exit $errcode
    fi

    write_log "main call read_uos_recovery_conf end ... "

    if [ "$NEED_RESTORE" = "yes" ]; then
        mount -o remount,rw ${rootmnt}
        if [ $? -ne 0 ]; then
            write_log "call remount error, exit ..."
            exit $err_mount_failed
        fi

        write_log "main need restore ... "
        if [ "$RECOVERY_TYPE" = "Rsync" ]; then
            write_log "main call rsync_restore begin ... "
            rsync_restore
            errcode=$?
            if [ $errcode -ne 0 ]; then
                write_log "main rsync_restore error!, RECOVERY_TYPE = $RECOVERY_TYPE, errcode = $errcode"
                dump_log
            else
                write_log "main call rsync_restore success  ... "
            fi

            reset_do_restore
            copy_log
            umount_fstab
            errcode=$?
            if [ $errcode -ne 0 ]; then
                write_log "main umount_fstab error !, errcode = $errcode "
                #display_result $errcode
                # umount 失败，这里需要重启，不然无法正常进入系统
                reboot -f
            fi
            return 0
        elif [ "$RECOVERY_TYPE" = "RsyncV20" ]; then
            # 卸载已经挂载的root
            umount ${rootmnt}
            write_log "****** done *** umount ${rootmnt}"

            #激活loop环境
            mknod /dev/loop0 b 7 1 &>>$LOG_FILE
            write_log "****** done *** mknod /dev/loop0 b 7 1"

            # 挂载备份文件所在的分区
            mkdir -p ${V20TARGETDATAPATH} &>>$LOG_FILE
            local sourceFilePath=""
            while [ x"${sourceFilePath}" = x ] ; do
              sourceFilePath=$(lsblk -pln -o NAME,UUID | grep ${V20RESTORE_PATH%;*} | awk '{print $1}')
            done
            mount ${sourceFilePath} ${V20TARGETDATAPATH} &>>$LOG_FILE
            write_log "****** done *** mount ${sourceFilePath} ${V20TARGETDATAPATH}"

            write_log "****** lsblk info : "
            write_log "`lsblk -f`"

            local log_dest_path=${V20TARGETDATAPATH}/uos-recovery/v20restore/
            #根据V20RESTORE_LIST遍历执行rsync操作
            local restore_array=${V20RESTORE_LIST//;/ }
            for i in ${restore_array}; do
                write_log "****** rsync_v20_restore args is : ${i}"
                rsync_v20_restore ${i}
                errcode=$?
                if [ $errcode -ne 0 ]; then
                    write_log " main rsync_v20_restore error!, RECOVERY_TYPE = $RECOVERY_TYPE, errcode = $errcode"
                    copy_log $log_dest_path
                    echo "v20 backup file restore failed, RECOVERY_TYPE = $RECOVERY_TYPE, errcode = $errcode"
                    dump_log
                    return 1
                fi
            done

            # 处理tar压缩包里文件
            local tarFileList=${V20RESTORE_TAR//;/ }
            for i in ${tarFileList}; do
                write_log "****** tarFileList item value is : ${i}"
                local tarFilePath=${i#*[}
                local uTarFileDevDirPath=${i%[*}
                local uTarFileDevPath=""
                while [ x"${uTarFileDevPath}" = x ] ; do
                    uTarFileDevPath=$(lsblk -pln -o NAME,UUID | grep ${uTarFileDevDirPath%:*} | awk '{print $1}')
                done
                local uTarFileDirPath=${uTarFileDevDirPath#*:}
                local uTarFileDevPathMountPoint=$(lsblk -ln ${uTarFileDevPath} -o MOUNTPOINT)
                write_log "****** done *** tarFilePath : ${tarFilePath}, uTarFileDevDirPath : ${uTarFileDevDirPath}, uTarFileDevPath : ${uTarFileDevPath}, uTarFileDirPath : ${uTarFileDirPath}, uTarFileDevPathMountPoint : ${uTarFileDevPathMountPoint}"
                if [ x"${uTarFileDevPathMountPoint}" = x ]; then
                    uTarFileDevPathMountPoint="V20TARFILETO"
                    mkdir -p ${uTarFileDevPathMountPoint} &>>$LOG_FILE
                    mount ${uTarFileDevPath} ${uTarFileDevPathMountPoint} &>>$LOG_FILE
                fi

                # 删除原来的目录
                rm -rf ${uTarFileDevPathMountPoint}/${uTarFileDirPath} &>>$LOG_FILE
                write_log "****** done *** rm -rf ${uTarFileDevPathMountPoint}/${uTarFileDirPath}"

                # 解压tar文件到目标目录
                tar --xattrs --xattrs-include=* -xvf ${V20TARGETDATAPATH}${V20RESTORE_PATH#*;}/${tarFilePath} -C ${uTarFileDevPathMountPoint} ${uTarFileDirPath}
                write_log "****** done *** tar --xattrs --xattrs-include=* -xvf ${V20TARGETDATAPATH}${V20RESTORE_PATH#*;}/${tarFilePath} -C ${uTarFileDevPathMountPoint} ${uTarFileDirPath}"
            done

            if [ x"${uTarFileDevPathMountPoint}" = xV20TARFILETO ]; then
                umount ${uTarFileDevPathMountPoint} &>>$LOG_FILE
                rm -rf ${uTarFileDevPathMountPoint} &>>$LOG_FILE
            fi

            # 清理还原过程中生成img中间文件
            write_log "****** do *** rm dir : ${V20RESTORE_PATH#*;}"
            write_log "`rm -rf ${V20TARGETDATAPATH}${V20RESTORE_PATH#*;}`"

            copy_log $log_dest_path

            umount ${V20TARGETDATAPATH} &>>$LOG_FILE
            rm -rf ${V20TARGETDATAPATH} &>>$LOG_FILE
            echo "v20 backup file restore success"
            write_log "****** done *** umount ${V20TARGETDATAPATH}"
            if [ $errcode -eq 0 ]; then
                echo "****** reboot system to grub"
                reboot -f
            fi
        fi
        unset_global_var
    fi
}

main

exit 0
