#!/bin/bash

BACKUP_NAME="系统备份"
FACTORY_BACKUP_NAME="工厂备份"
RESTORE_NAME="系统恢复"
BACKUP_OTHER="分区数据备份" 
RESTORE_OTHER="分区数据还原" 
WINDOW_WIDTH=480
WINDOW_HEIGHT=320
LOG_FILE="system_recovery.log"
LOG_MNT=/mnt/log

SYSTEM_MNT=/mnt/sys
BACKUP_MNT=/mnt/bak
BOOT_MNT=/mnt/sys/boot
BOOT_EFI_MNT=/mnt/sys/boot/efi
BACKUP_DIR=$BACKUP_MNT/backup

BACKUP_FILE_NAME=""
RESTORE_FILE_NAME=""
CMD_BACKUP=""
CMD_RESTORE=""
SELECTION=""
SYS_DISK=""
FACTORY_NODE_REMOVABLE=false
EXIST_BACKUP_FILE=true
ERROR=0











#mount -o remount,rw /run/initramfs/isoscan




get_sys_disk() {

SYS_DIR="/sys/block"
ROOT_DEVICE=""
BOOT_DEV=""
BOOT_EFI_DEV=""

LVM_DEVICE=`blkid |grep LVM2_member|awk -F: '{print $1}'|head -1`
if [ -n "$LVM_DEVICE" ];then
BOOT_DEV=${LVM_DEVICE%?}2
BOOT_EFI_DEV=${LVM_DEVICE%?}1
for dir in `lvscan |awk -F " " '{print $2}' | sed  s/\'//g`
do
    partiton_dir=${dir##*/}
    if [ $partiton_dir = "root" ];then
	ROOT_DEV=$dir
    elif [ $partiton_dir = "backup" ];then
	BACKUP_DEV=$dir
    else
	continue
    fi
done
else 
##set the partition for standard partition  
   echo "cannot get the lvm_device"  >>/tmp/$LOG_FILE
   for dev in $SYS_DIR/nvme*?  $SYS_DIR/sd? $SYS_DIR/hd? $SYS_DIR/vd?
do
    SYSTEM_DEVICE=${dev##*/}
    if [ $SYSTEM_DEVICE = "nvme0n1" ]; then
        ROOT_DEVICE=$dev
        BOOT_DEV="/dev/${SYSTEM_DEVICE}p2"
        BOOT_EFI_DEV="/dev/${SYSTEM_DEVICE}p1"
 	ROOT_DEV="/dev/${SYSTEM_DEVICE}p4"
	BACKUP_DEV="/dev/${SYSTEM_DEVICE}p5"
        break
    elif [ $SYSTEM_DEVICE = "sda" ]; then
        ROOT_DEVICE=$dev
        BOOT_DEV="/dev/${SYSTEM_DEVICE}2"
        BOOT_EFI_DEV="/dev/${SYSTEM_DEVICE}1"
 	ROOT_DEV="/dev/${SYSTEM_DEVICE}4"
	BACKUP_DEV="/dev/${SYSTEM_DEVICE}5"
        break
   else
        continue
    fi
        echo "cannot find the  device " >>/tmp/$LOG_FILE
done
 		
fi

##ROOT_UUID=`/usr/sbin/grub2-probe  --target=device  /  --target=fs_uuid`
#	BOOT_UUID=`cat /proc/cmdline| tr ' ' '\n' | grep UUID | awk -F'=' '{print $NF}'`
#	DEVICE=$(mount|grep 'install/isodir'|grep ext|sed -n 1p|awk '{print $1}'|sed 's/[0-9]//')
#	if [ $BOOT_UUID != "" ];then
#		SYS_DISK=`blkid | grep $BOOT_UUID | cut -c1-8`
#	elif [ -n "$DEVICE" ];then
#		SYS_DISK="$DEVICE"
#	else
#		SYS_DISK=/dev/sda
#	fi
#
	#BOOT_PAR=${SYS_DISK}1
	ROOT_PAR=$ROOT_DEV
	BACKUP_PAR=$BACKUP_DEV
	LOG_PAR=$BACKUP_DEV
	BOOT_PAR=$BOOT_DEV
        BOOT_EFI_PAR=$BOOT_EFI_DEV


}

#mount the disks in fstab
mount_other_disk() {

for dev in `cat $SYSTEM_MNT/etc/fstab  |sed  '/#/d' |sed '/^$/d' |awk '{print $1}'` 
        do
                MOUNT_POINT=`cat $SYSTEM_MNT/etc/fstab |grep $dev |awk -F ' ' '{print $2}'`
		if [ $MOUNT_POINT = "/backup" -o $MOUNT_POINT = "/" -o $MOUNT_POINT = "/boot" \
                        -o $MOUNT_POINT = "/boot/efi" -o $MOUNT_POINT = "none" ];then
                        continue
                fi
                if [ `echo $dev |awk -F= '{print $1}'` = "UUID" ];then
                       MOUNT_UUID=`echo $dev |awk -F= '{print $2}'`
                       mount /dev/disk/by-uuid/$MOUNT_UUID $SYSTEM_MNT/${MOUNT_POINT#*/}
                else
                       mount $dev $SYSTEM_MNT/${MOUNT_POINT#*/}
                fi
        done

}

zenity --info     --text="正在进入备份还原界面，请确认！"  --width=320 --height=200
main_window() {
main_ret=""
while true
do
	if [[ $FACTORY_NODE_REMOVABLE = true && $EXIST_BACKUP_FILE = false ]]; then
		str=$(zenity --list --radiolist --title="备份恢复工具" \
			--text="" --column "选择" --column "功能" \
			True $BACKUP_NAME Fasle $RESTORE_NAME Fasle $FACTORY_BACKUP_NAME \
			Fasle  $BACKUP_OTHER  Fasle $RESTORE_OTHER \
			--width=$WINDOW_WIDTH --height=$WINDOW_HEIGHT)
	else
		str=$(zenity --list --radiolist --title="备份恢复工具" \
			--text="" --column "选择" --column "功能" \
			True $BACKUP_NAME Fasle $RESTORE_NAME \
			Fasle  $BACKUP_OTHER  Fasle $RESTORE_OTHER \
			--width=$WINDOW_WIDTH --height=$WINDOW_HEIGHT)
	fi

	main_ret=$?
	SELECTION=$str
 	if [ "$SELECTION" = "$BACKUP_OTHER" ]; then
		MANUAL_DIR=$(zenity --entry    --title=$BACKUP_OTHER  --text="输入需要备份的数据分区目录，多个目录请以空格区分:"  --width=$WINDOW_WIDTH --height=$WINDOW_HEIGHT)
		if [ $? -eq 1 ];then
			continue
		fi
	fi
	break
done
	return $main_ret
}

factory_node_update_window() {
	echo "[`date +%Y%m%d%H%M%S`] 进入工厂备份选项" >> $LOG_MNT/$LOG_FILE
	BACKUP_FILE_NAME=backup_factory.tar
	factory_ret=0

	while [ $factory_ret -eq 0 ]
	do
		zenity --question --title="风险提示" \
		--text "<span color=\"red\"><b>\n\n提示：此工厂备份功能仅可进行一次工厂备份操作，本次 \
			\n\n创建的备份点将无法被删除或覆盖，请谨慎操作！</b></span>" \
		--width=$WINDOW_WIDTH --height=$WINDOW_HEIGHT

		factory_ret=$?
		if [ $factory_ret -eq 0 ]; then
			rm -f $BACKUP_DIR/backup_factory.tar
			rm -f $BACKUP_MNT/.factory_node_removable
			#CMD_BACKUP="fsarchiver -j4 -o savefs $BACKUP_DIR/$BACKUP_FILE_NAME ${BOOT_PAR} ${ROOT_PAR}"
			CMD_BACKUP="fsarchiver -j4 -o savefs $BACKUP_DIR/$BACKUP_FILE_NAME ${ROOT_PAR}"
			break
		fi
	done

	return $factory_ret
}

backup_window() {
	echo "[`date +%Y%m%d%H%M%S`] 进入备份选项" >> $LOG_MNT/$LOG_FILE
	system_partition_mount
	mount_other_disk
	BACKUP_FILE_NAME=backup_$(date +%Y%m%d%H%M%S).tar
	name_str=$(zenity --entry \
		--title="备份" \
		--text="备份命名:" \
		--width=$WINDOW_WIDTH --height=$WINDOW_HEIGHT \
		--entry-text $BACKUP_FILE_NAME)
	backup_ret=$?
	if [ $backup_ret -eq 0 ];then
		while [[ "$name_str" = "backup_factory.tar" ]] || [ -e $BACKUP_DIR/$name_str ] || [ -e $BACKUP_DIR/"${name_str}.tar" ]
		do
			if [[ "$name_str" = "backup_factory.tar" ]]; then
				zenity --warning --title="警告" --text "<span color=\"red\"><b>\n\n \n\n警告：此备份还原点用于出厂恢复，用户\n \n \n无法进行覆盖操作，请重新命名！</b></span>" --width=$WINDOW_WIDTH --height=$WINDOW_HEIGHT
				if [ $? -eq 0 ]; then
					BACKUP_FILE_NAME=backup_$(date +%Y%m%d%H%M%S).tar
					name_str=$(zenity --entry \
						--title="备份" \
						--text="备份命名:" \
						--width=$WINDOW_WIDTH --height=$WINDOW_HEIGHT \
						--entry-text $BACKUP_FILE_NAME)
					backup_ret=$?
					if [ ! $backup_ret -eq 0 ]; then
						break
					fi
				fi
			else
				zenity --question --title="警告" --text "<span color=\"red\"><b>\n\n \n\n警告：此备份还原文件已经存在，\n \n \n 是否进行覆盖操作?</b></span>" --width=$WINDOW_WIDTH --height=$WINDOW_HEIGHT
				if [ $? -eq 0 ]; then
					backup_ret=$?
					break
				else
					BACKUP_FILE_NAME=backup_$(date +%Y%m%d%H%M%S).tar
					name_str=$(zenity --entry \
						--title="备份" \
						--text="备份命名:" \
						--width=$WINDOW_WIDTH --height=$WINDOW_HEIGHT \
						--entry-text $BACKUP_FILE_NAME)
					backup_ret=$?
					if [ ! $backup_ret -eq 0 ]; then
						break
					fi
				fi
			fi
		done

		BACKUP_FILE_NAME=$name_str

		#CMD_BACKUP="fsarchiver -j4 -o savefs $BACKUP_DIR/$BACKUP_FILE_NAME ${BOOT_PAR} ${ROOT_PAR}"
		#CMD_BACKUP="fsarchiver -j4 -o savefs $BACKUP_DIR/$BACKUP_FILE_NAME ${ROOT_PAR}"
		system_partition_mount
		mount_other_disk
		cd $SYSTEM_MNT
		#CMD_BACKUP="tar -cf $BACKUP_DIR/$BACKUP_FILE_NAME * --selinux --acls --xattrs --atime-preserve"
		CMD_BACKUP="tar -cf $BACKUP_DIR/$BACKUP_FILE_NAME *  --acls --xattrs --atime-preserve"
	fi

	return $backup_ret
}

backup_progress_window() {
	echo "[`date +%Y%m%d%H%M%S`] 开始备份..." >> $LOG_MNT/$LOG_FILE
	(
	echo "System backup"; $CMD_BACKUP >> $LOG_MNT/$LOG_FILE 2>&1
	if [ $? -eq 0 ]; then
		echo "[`date +%Y%m%d%H%M%S`] 备份完成。" >> $LOG_MNT/$LOG_FILE
	else
		echo "[`date +%Y%m%d%H%M%S`] 备份异常。" >> $LOG_MNT/$LOG_FILE
	fi
	echo "Sync data."; sync; sync
	echo "# 备份完成"
	) |
	zenity --progress --title="备份" \
		--text="正在备份..." --pulsate --no-cancel \
		--width=$WINDOW_WIDTH --height=$WINDOW_HEIGHT
	ret=$?
	return $ret
}

restore_window() {
	echo "[`date +%Y%m%d%H%M%S`] 进入还原选项" >> $LOG_MNT/$LOG_FILE
	file_list=$(ls $BACKUP_DIR)
	RESTORE_FILE_NAME=$(zenity --list \
				--title="恢复" \
				--width=$WINDOW_WIDTH --height=$WINDOW_HEIGHT \
				--column="备份节点" \
				$file_list)
	restore_ret=$?
	if [ $restore_ret -eq 0 ] && [ "x$RESTORE_FILE_NAME" = "x" ]; then
		zenity --error --text="请选择一个备份文件"
		restore_window
	fi

	#CMD_RESTORE="fsarchiver -j4 restfs $BACKUP_DIR/$RESTORE_FILE_NAME id=0,dest=${BOOT_PAR} id=1,dest=${ROOT_PAR}"
	#CMD_RESTORE="fsarchiver -j4 restfs $BACKUP_DIR/$RESTORE_FILE_NAME id=0,dest=${ROOT_PAR}"
	system_partition_mount
	mount_other_disk
	#CMD_RESTORE="/usr/bin/pigz -d -c -p 4 $BACKUP_DIR/$RESTORE_FILE_NAME | tar -xp --selinux --acls --xattrs-include='*' -C $SYSTEM_MNT"
	#CMD_RESTORE="tar -xlpf $BACKUP_DIR/$RESTORE_FILE_NAME --selinux --acls --xattrs-include='*' -C $SYSTEM_MNT"
	#CMD_RESTORE="tar -xlpf $BACKUP_DIR/${RESTORE_FILE_NAME#*|} --selinux --acls --xattrs-include='*' -C $SYSTEM_MNT"
	CMD_RESTORE="tar -xlpf $BACKUP_DIR/${RESTORE_FILE_NAME#*|}  --acls --xattrs-include='*' -C $SYSTEM_MNT"
	return $restore_ret
}

restore_progress_window() {
	echo "[`date +%Y%m%d%H%M%S`] 开始还原..." >> $LOG_MNT/$LOG_FILE
	(
	if [ $RETRY_TIMES -eq 0 ];then
	    cd $SYSTEM_MNT
	    tar -cf $BACKUP_DIR/user-backup.tar.bz2 etc/passwd etc/group etc/shadow etc/gshadow --selinux --acls --xattrs --atime-preserve
	    cd /
	fi
	mkdir -p /mnt/delete
	rsync --delete-before -d /mnt/delete/ $SYSTEM_MNT
	echo "Image restore"
	echo "#!/bin/bash
	$CMD_RESTORE >> $LOG_MNT/$LOG_FILE
	" >/tmp/run.sh
	chmod 777 /tmp/run.sh
	sh /tmp/run.sh
	if [ $? -eq 0 ]; then
		echo "[`date +%Y%m%d%H%M%S`] 还原完成。" >> $LOG_MNT/$LOG_FILE
	else
		echo "[`date +%Y%m%d%H%M%S`] 还原异常。" >> $LOG_MNT/$LOG_FILE
		ERROR=1
	fi
	sync
	rm -rf $BACKUP_DIR/user-backup.tar.bz2
	echo "Restore passwd"; tar -xlpf $BACKUP_DIR/user-backup.tar.bz2 --selinux --acls --xattrs-include='*' -C $SYSTEM_MNT
	echo "Sync data."; sync; sync
	if [ $ERROR -eq 0 ];then
		MES="# 恢复完成,请重启系统！"
	else
		MES="# 恢复失败，请重新进行恢复！"
	fi
	echo $MES;system_partition_mount;touch $SYSTEM_MNT/.autorelabel;sync;sync;system_partition_umount
	) |
	zenity --progress --title="恢复" \
		--text="正在恢复..." --pulsate --no-cancel \
		--width=$WINDOW_WIDTH --height=$WINDOW_HEIGHT
	ret=$?
	return $ret
}

destroy_backup_image_window() {
	lists=$(du -sh $BACKUP_DIR/* | grep -v backup_factory.tar | awk '{ gsub("'$BACKUP_DIR'/", "", $2); print "FALSE " $2 " " $1}')
	selected=$(zenity --list --checklist --title="备份空间不足，请删除备份节点"\
			--width=$WINDOW_WIDTH --height=$WINDOW_HEIGHT \
			--column="删除" --column="备份文件" --column="大小"\
			$lists)
	ret=$?
	if [ $ret -eq 0 ]; then
		echo $selected | awk -F '|' '{for(i=1;i<=NF;i++) {system("rm -f '$BACKUP_DIR'/"$i)}}'
	else
		return $ret
	fi
}

backup_size_not_enough() {
	system_partition_mount
	mount_other_disk
	root_size=$(echo `df --output=used $SYSTEM_MNT` | cut -f2 --delimiter=' ')
	#boot_size=$(echo `df --output=used $SYSTEM_MNT/boot` | cut -f2 --delimiter=' ')
	boot_size=0
	need=$((root_size + boot_size))
	system_partition_umount
	available=$(df --output=avail $BACKUP_MNT | cut -f2 --delimiter=' ')
	echo "[`date +%Y%m%d%H%M%S`] 备份需要的空间大小:$need KB, 可用的备份分区空间大小:$available KB" >> $LOG_MNT/$LOG_FILE
	if [ $need -gt $available ]; then
		return 0
	else
		return 1
	fi
}

system_partition_mount() {
	mkdir -p $SYSTEM_MNT
	mkdir -p $BOOT_MNT
        mkdir -p $BOOT_EFI_MNT
	mount $ROOT_PAR $SYSTEM_MNT
	mount $BOOT_PAR $BOOT_MNT
	mount $BOOT_EFI_PAR  $BOOT_EFI_MNT
	chroot $SYSTEM_MNT tppunlf $(md5sum /usr/bin/tpplf |awk '{print $1}')
	#mount $BOOT_PAR $SYSTEM_MNT/boot
}

system_partition_umount() {
	chroot $SYSTEM_MNT tpplf $(md5sum /usr/bin/tppunlf |awk '{print $1}')
	umount -Rf $SYSTEM_MNT
	umount -Rf $BOOT_MNT
	umount -Rf $BOOT_EFI_MNT
}

backup_partition_mount() {
	mkdir -p $BACKUP_MNT
	mount $BACKUP_PAR $BACKUP_MNT
}

log_partition_mount() {
	mkdir -p $LOG_MNT
	mount $LOG_PAR $LOG_MNT
}

set_backup_restore_status() {
	if [ -e $BACKUP_MNT/.factory_node_removable ]; then
		FACTORY_NODE_REMOVABLE=true
	else
		FACTORY_NODE_REMOVABLE=false
	fi

	ls $BACKUP_DIR | grep -v "backup_factory.tar" | grep -E "backup_.*fsa$"
	if [[ "x$?" = "x0" ]]; then
		EXIST_BACKUP_FILE=true
	else
		EXIST_BACKUP_FILE=false
	fi
}

umount_all() {
	#umount $SYSTEM_MNT
	umount -Rf $BACKUP_MNT
	echo "[`date +%Y%m%d%H%M%S`] 系统重启" >> $LOG_MNT/$LOG_FILE
	umount -f $LOG_MNT
	systemctl --no-wall reboot
}

grub2_install() {
	system_partition_mount
	mount_other_disk
	mount -o bind /dev $SYSTEM_MNT/dev
	mount -o bind /proc $SYSTEM_MNT/proc
	chroot $SYSTEM_MNT grub2-install ${SYS_DISK}
	umount -Rf $SYSTEM_MNT/dev
	umount -Rf $SYSTEM_MNT/proc
	system_partition_umount
}

run() {
	while true
	do
		main_window
		if [ $? -eq 0 ]; then
			if [ "$SELECTION" = "$BACKUP_NAME" -o "$SELECTION" = "$BACKUP_OTHER" ]; then
				del_ret=0
				while backup_size_not_enough ;
				do
					destroy_backup_image_window
					del_ret=$?
					if [ ! $del_ret -eq 0 ]; then
						break
					fi
				done
				if [ ! $del_ret -eq 0 ]; then
					continue
				fi

				backup_window
				if [ $? -eq 0 ]; then
					backup_progress_window
					break
				fi
			elif [ "$SELECTION" = "$RESTORE_NAME" -o "$SELECTION" = "$RESTORE_OTHER" ]; then
				restore_window
				if [ $? -eq 0 ]; then
					restore_progress_window
					break
				fi
			elif [ $SELECTION = $FACTORY_BACKUP_NAME ]; then
				factory_node_update_window
				if [ $? -eq 0 ]; then
					backup_progress_window
					break
				fi
			fi
		else
			break
		fi
	done

	umount_all
	exit 1
}

get_sys_disk
log_partition_mount
backup_partition_mount

if [ ! -e $BACKUP_DIR ]; then
	mkdir -p $BACKUP_DIR
fi

set_backup_restore_status

run
