#!/bin/bash

BACKUP_NAME="备份"
FACTORY_BACKUP_NAME="工厂备份"
RESTORE_NAME="恢复"
WINDOW_WIDTH=480
WINDOW_HEIGHT=320
LOG_FILE="system_recovery.log"
LOG_MNT=/mnt/log

SYSTEM_MNT=/mnt/sys
BACKUP_MNT=/mnt/bak
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

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

get_sys_disk() {
	BOOT_UUID=`cat /proc/cmdline| tr ' ' '\n' | grep UUID | awk -F'=' '{print $NF}'`
	BACKUP_NUM=`cat /proc/cmdline| tr ' ' '\n' |grep repo |awk -F'*' '{print $NF}'|awk -F':' '{print $1}'`
	DEVICE=$(mount|grep 'install/isodir'|grep xfs|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}3
	ROOT_PAR=${SYS_DISK}3
	BACKUP_PAR=${SYS_DISK}${BACKUP_NUM}
	LOG_PAR=${SYS_DISK}${BACKUP_NUM}
}

main_window() {
	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 \
			--width=$WINDOW_WIDTH --height=$WINDOW_HEIGHT)
	else
		str=$(zenity --list --radiolist --title="备份恢复工具" \
			--text="" --column "选择" --column "功能" \
			True $BACKUP_NAME Fasle $RESTORE_NAME \
			--width=$WINDOW_WIDTH --height=$WINDOW_HEIGHT)
	fi

	main_ret=$?
	SELECTION=$str
	echo $SELECTION
	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
	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
		cd $SYSTEM_MNT
		CMD_BACKUP="tar -cf $BACKUP_DIR/$BACKUP_FILE_NAME * --selinux --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
	#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"
	return $restore_ret
}

restore_progress_window() {
	echo "[`date +%Y%m%d%H%M%S`] 开始还原..." >> $LOG_MNT/$LOG_FILE
	(
	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 /
	mkdir -p /mnt/delete
	rsync --delete-before -d /mnt/delete/ $SYSTEM_MNT
	echo "Image restore"; $CMD_RESTORE >> $LOG_MNT/$LOG_FILE
	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 "Restore passwd"; tar -xlpf $BACKUP_DIR/user-backup.tar.bz2 --selinux --acls --xattrs-include='*' -C $SYSTEM_MNT
	rm -rf $BACKUP_DIR/user-backup.tar.bz2
	echo "Sync data."; sync; sync
	echo "# 恢复完成,请重启系统！";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
	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
	mount $ROOT_PAR $SYSTEM_MNT
	#mount $BOOT_PAR $SYSTEM_MNT/boot
}

system_partition_umount() {
	umount -Rf $SYSTEM_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 -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 ]; 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 ]; 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
