1232 lines
40 KiB
Plaintext
1232 lines
40 KiB
Plaintext
|
#!/bin/bash
|
|||
|
#Author Buquan Liu, liubuquan@kylinos.cn, walt_lbq@163.com
|
|||
|
#本程序本质上是对backup-auto/autobackup.cpp的重写.
|
|||
|
#因为采用Qt程序则打包进入内核,相应的库会导致内核超过16M,故改为shell程序.
|
|||
|
|
|||
|
#backup-auto --autobackup ${rootpath} /backup
|
|||
|
#backup-auto --autorestore ${rootpath} /backup
|
|||
|
|
|||
|
#xgs备份还原要保留更多的文件或目录:
|
|||
|
#kybackup/maindialog.cpp, backup-daemon/mountpoint.cpp, backup-daemon/data/backup-auto-efi
|
|||
|
XGS=false
|
|||
|
|
|||
|
INFO="/etc/.bootinfo"
|
|||
|
METAINFO=".METAINFO"
|
|||
|
KB=1024
|
|||
|
MB=1048576
|
|||
|
GB=1073741824
|
|||
|
|
|||
|
if [ $# -lt 3 ]; then
|
|||
|
exit 18
|
|||
|
fi
|
|||
|
|
|||
|
#是否有/data数据分区
|
|||
|
hasDataPartition=0
|
|||
|
backupORrestore=$1
|
|||
|
rootpath=$2
|
|||
|
m_mountPath=$3
|
|||
|
m_default_uuid=$4
|
|||
|
|
|||
|
BACKUP=
|
|||
|
if [[ -e "${rootpath}/backup/BACKUP/snapshots" ]]; then
|
|||
|
BACKUP="/BACKUP"
|
|||
|
fi
|
|||
|
|
|||
|
m_backuplistPath=${m_mountPath}${BACKUP}"/snapshots/backuplist.xml"
|
|||
|
EXCLUDEFILE=${m_mountPath}${BACKUP}"/snapshots/.exclude"
|
|||
|
PLOGFILEDIR="${m_mountPath}${BACKUP}/log"
|
|||
|
PLOGFILE="$PLOGFILEDIR/log-$(date +%Y%m%d%H%M)"
|
|||
|
LOGFILE="${m_mountPath}${BACKUP}/log.txt" #LOGFILE="/tmp/log.txt"
|
|||
|
|
|||
|
#是否是出厂备份
|
|||
|
m_isFactory=false
|
|||
|
factory_uuid="00000000-0000-0000-0000-000000000000"
|
|||
|
auto_uuid="01234567-0123-0123-0123-0123456789ab"
|
|||
|
PERSONAL_EXCLUDEFILE=".exclude.user.txt"
|
|||
|
PERSONAL_BACKUPFILE=".user.txt"
|
|||
|
m_isRetainUserData=false
|
|||
|
|
|||
|
#如果/backup不存在,则创建该目录
|
|||
|
mkdir -p ${m_mountPath}${BACKUP}
|
|||
|
if [ $? -ne 0 ]; then
|
|||
|
echo "Could not create /backup in initrd!"
|
|||
|
exit 20
|
|||
|
fi
|
|||
|
m_restoreUuid=""
|
|||
|
m_enabled=""
|
|||
|
global_system_usedDisk=0
|
|||
|
m_size=0
|
|||
|
newSize=0
|
|||
|
|
|||
|
#-----------------------------------------------------------------
|
|||
|
get_is_990_9a0() {
|
|||
|
local ret=false
|
|||
|
# 匹配 kirin 990 5g, kirin990, kirin 9006c
|
|||
|
if egrep -qi 'kirin.?9[09]0' /proc/cpuinfo; then
|
|||
|
ret=true
|
|||
|
elif egrep -qi 'PANGU' /proc/cpuinfo; then
|
|||
|
ret=true
|
|||
|
|
|||
|
fi
|
|||
|
echo $ret
|
|||
|
}
|
|||
|
is_990_9a0=$(get_is_990_9a0)
|
|||
|
#see backup-auto/autobackup.cpp
|
|||
|
getBackupInfo() {
|
|||
|
if [ "$rootpath" = "/" ]; then
|
|||
|
bootinfo=$INFO
|
|||
|
else
|
|||
|
bootinfo=${rootpath}${INFO}
|
|||
|
fi
|
|||
|
|
|||
|
if [ ! -e "$bootinfo" ]; then
|
|||
|
# 系统崩坏,如操作失误删除了/etc目录
|
|||
|
if [ -e $INFO ]; then
|
|||
|
bootinfo=$INFO
|
|||
|
else
|
|||
|
echo "$bootinfo file not exist!"
|
|||
|
exit 1
|
|||
|
fi
|
|||
|
fi
|
|||
|
|
|||
|
which_line=0
|
|||
|
content=$(cat "$bootinfo" | grep -Ev "^#" | grep "=" | awk '{print $1}')
|
|||
|
for line in $content;
|
|||
|
do
|
|||
|
#parse_device "$device"
|
|||
|
#只读第1行:RECOVERY_DEV_UUID=c965e712-9903-4139-b8da-c6e1eef0af6a
|
|||
|
if [ $which_line -eq 0 ]; then
|
|||
|
m_restoreUuid=$(echo $line | sed 's:.*=::' | tr -d "\n")
|
|||
|
which_line=$(expr $which_line + 1)
|
|||
|
else
|
|||
|
m_enabled=$(echo $line | sed 's:.*=::' | tr -d "\n")
|
|||
|
which_line=$(expr $which_line + 1)
|
|||
|
fi
|
|||
|
done
|
|||
|
}
|
|||
|
|
|||
|
#-----------------------------------------------------------------
|
|||
|
|
|||
|
#该函数是对backup-daemon/parsebackuplist.cpp中相应函数的替换
|
|||
|
createBackupList() {
|
|||
|
local backuplistDir=${m_mountPath}${BACKUP}"/snapshots/"
|
|||
|
|
|||
|
if [ ! -e "$backuplistDir" ]; then
|
|||
|
mkdir -p $backuplistDir
|
|||
|
fi
|
|||
|
|
|||
|
if [ ! -e "$m_backuplistPath" ]; then
|
|||
|
#echo "$m_backuplistPath file not exist!"
|
|||
|
|
|||
|
#第1行'>'会清空后写文件
|
|||
|
echo "<?xml version='1.0'?>" >$m_backuplistPath
|
|||
|
#echo "<backupList>" >>$m_backuplistPath
|
|||
|
#echo "</backupList>" >>$m_backuplistPath
|
|||
|
echo "<backupList/>" >>$m_backuplistPath #QDomDocument在节点为空时如此生成根节点
|
|||
|
fi
|
|||
|
}
|
|||
|
|
|||
|
#-----------------------------------------------------------------
|
|||
|
#see backup-auto/autobackup.cpp
|
|||
|
mountBackup() {
|
|||
|
local myuuid="/dev/disk/by-uuid/"$m_restoreUuid
|
|||
|
#echo "myuuid: $myuuid"
|
|||
|
|
|||
|
#support lvm by zhangze
|
|||
|
tmp_root_dev=$(mount | grep " /root " | cut -d ' ' -f 1)
|
|||
|
case "$tmp_root_dev" in
|
|||
|
/dev/mapper/*)
|
|||
|
eval $(dmsetup splitname --nameprefixes --noheadings --rows "${tmp_root_dev#/dev/mapper/}")
|
|||
|
if [ "$DM_VG_NAME" ] && [ "$DM_LV_NAME" ]; then
|
|||
|
lvm lvchange -aay -y --sysinit --ignoreskippedcluster "$DM_VG_NAME"
|
|||
|
fi
|
|||
|
;;
|
|||
|
esac
|
|||
|
|
|||
|
#mount $myuuid $m_mountPath
|
|||
|
mount -o defaults,rw -U $m_restoreUuid $m_mountPath
|
|||
|
if [ $? -ne 0 ]; then
|
|||
|
echo "Mount backup failed!"
|
|||
|
exit 21
|
|||
|
fi
|
|||
|
|
|||
|
mkdir -p $PLOGFILEDIR
|
|||
|
if [ $? -ne 0 ]; then
|
|||
|
echo "Could not create log directory in /backup"
|
|||
|
exit 22
|
|||
|
fi
|
|||
|
|
|||
|
touch $PLOGFILE
|
|||
|
if [ $? -ne 0 ]; then
|
|||
|
echo "Could not create log file"
|
|||
|
exit 23
|
|||
|
fi
|
|||
|
echo "Log for backuping and restoring...." >$PLOGFILE
|
|||
|
createBackupList #创建备份信息
|
|||
|
}
|
|||
|
|
|||
|
#-----------------------------------------------------------------
|
|||
|
#see backup-auto/autobackup.cpp
|
|||
|
umountBackup() {
|
|||
|
umount $m_mountPath
|
|||
|
}
|
|||
|
|
|||
|
#-----------------------------------------------------------------
|
|||
|
#see backup-auto/backupcommon.cpp
|
|||
|
#在grub时,根分区为/root;在进入系统后,根分区为/
|
|||
|
#parameters: rootDiskName
|
|||
|
#返回值 elements=( $totalSize $freeDisk $usedDisk )
|
|||
|
caculateDiskSize() {
|
|||
|
local origalParas
|
|||
|
|
|||
|
origalParas=($(echo "$@"))
|
|||
|
num=$(($#))
|
|||
|
|
|||
|
#if [ $# -ne 2 ]; then
|
|||
|
if [ $num -ne 2 ]; then
|
|||
|
echo "You shoud input the rootDiskName and disk"
|
|||
|
exit 19
|
|||
|
fi
|
|||
|
|
|||
|
local fullDiskName
|
|||
|
local totalSize
|
|||
|
local freeDisk
|
|||
|
local usedDisk
|
|||
|
|
|||
|
if [ "${origalParas[1]}" = "/" ]; then
|
|||
|
fullDiskName=${origalParas[0]}
|
|||
|
else
|
|||
|
fullDiskName=${origalParas[0]}${origalParas[1]}
|
|||
|
fi
|
|||
|
|
|||
|
if [ ! -e "$fullDiskName" ]; then
|
|||
|
##因为要返回数组,所以下面的echo没有上面用,不会显示,只会作为返回值
|
|||
|
#echo "$fullDiskName not exist!"
|
|||
|
elements=(0 0 0)
|
|||
|
echo ${elements[*]}
|
|||
|
return
|
|||
|
fi
|
|||
|
|
|||
|
##因为要返回数组,这里不能echo "fullDiskName: $fullDiskName"
|
|||
|
sss=$(df -k $fullDiskName | sed '1d' | tr -d "\n")
|
|||
|
freeDisk=$(echo $sss | awk '{print $4}')
|
|||
|
freeDisk=$(expr 1024 \* $freeDisk)
|
|||
|
usedDisk=$(echo $sss | awk '{print $3}')
|
|||
|
usedDisk=$(expr 1024 \* $usedDisk)
|
|||
|
|
|||
|
#totalSize没有从df命令的第2列来取,该值比下面2个的和还要大
|
|||
|
totalSize=$(expr $usedDisk + $freeDisk)
|
|||
|
|
|||
|
##因为要返回数组,这里不能echo "freeDisk=$freeDisk"
|
|||
|
##因为要返回数组,这里不能echo "usedDisk=$usedDisk"
|
|||
|
##因为要返回数组,这里不能echo "totalSize=$totalSize"
|
|||
|
|
|||
|
#local elements
|
|||
|
elements=($totalSize $freeDisk $usedDisk)
|
|||
|
echo ${elements[*]}
|
|||
|
}
|
|||
|
|
|||
|
parse_device() {
|
|||
|
device=$1
|
|||
|
if echo $device | grep -E -q "^UUID="; then
|
|||
|
echo $device | sed 's:^UUID=:/dev/disk/by-uuid/:' | tr -d "\n"
|
|||
|
elif echo $device | grep -E -q "^LABEL="; then
|
|||
|
echo $device | sed 's:^LABEL=:/dev/disk/by-label/:' | tr -d "\n"
|
|||
|
else
|
|||
|
echo $device | tr -d "\n"
|
|||
|
fi
|
|||
|
}
|
|||
|
|
|||
|
is_remote() {
|
|||
|
fstype=$1
|
|||
|
if [ nfs = "$fstype" ] || [ nfs4 = "$fstype" ] || [ smbfs = "$fstype" ] || [ cifs = "$fstype" ] || [ coda = "$fstype" ] || [ ncp = "$fstype" ]; then
|
|||
|
echo yes
|
|||
|
elif [ ncpfs = "$fstype" ] || [ ocfs2 = "$fstype" ] || [ gfs = "$fstype" ] || [ gfs2 = "$fstype" ] || [ ceph = "$fstype" ]; then
|
|||
|
echo yes
|
|||
|
else
|
|||
|
echo no
|
|||
|
fi
|
|||
|
}
|
|||
|
|
|||
|
function caculateDirSize() {
|
|||
|
mkdir -p /backup/snapshots/check/data
|
|||
|
local total_file_size=$(rsync -aAHXrn --stats --ignore-missing-args --exclude=/backup --exclude=/cdrom --exclude=/dev --exclude=/efi --exclude=/etc/uid_list --exclude=/data/ghost --exclude=/ghost --exclude=/lost+found --exclude=/media --exclude=/mnt --exclude=/proc --exclude=/run --exclude=/swap_file --exclude=/sys --exclude=/tmp --exclude=/var/lib/docker/overlay2 --exclude=/var/lib/kmre/data --exclude=/var/lib/kmre/kmre-*-*/data/media/0/0-麒麟* --exclude=/var/lib/udisks2 --exclude=/var/log --exclude=*/backup/snapshots --exclude=/data/home --exclude=/data/root "${rootpath}/" /backup/snapshots/check/data/ | grep "Total file size:" | awk '{print $4}' | sed 's/,//g')
|
|||
|
total_file_size=$(expr ${total_file_size} + 200000000)
|
|||
|
echo "备份所需空间大小:${total_file_size}" >>$PLOGFILE
|
|||
|
echo "${total_file_size}"
|
|||
|
}
|
|||
|
|
|||
|
#parameters: 无
|
|||
|
#返回值:(system_totalSize system_freeDisk system_usedDisk)
|
|||
|
caculateSystemSize() {
|
|||
|
local root_totalSize root_freeDisk root_usedDisk
|
|||
|
local system_totalSize system_freeDisk system_usedDisk
|
|||
|
local origalParas
|
|||
|
local found item result
|
|||
|
local device mntdir fstype options dump passno
|
|||
|
#local -a alreadyDisks #数组,已经分析过的磁盘目录
|
|||
|
local -a elements #存放返回值
|
|||
|
|
|||
|
#alreadyDisks=(${alreadyDisks[*]} "/boot") #插入一个元素"/boot"
|
|||
|
|
|||
|
#result=(`caculateDiskSize "$rootpath" "$rootpath"`)
|
|||
|
#origalParas=($rootpath "/")
|
|||
|
#arg1=$(echo ${origalParas[*]})
|
|||
|
|
|||
|
#result=($(caculateDiskSize $arg1))
|
|||
|
#root_totalSize=${result[0]}
|
|||
|
#root_freeDisk=${result[1]}
|
|||
|
#root_usedDisk=${result[2]}
|
|||
|
|
|||
|
#system_totalSize=$root_totalSize
|
|||
|
#system_freeDisk=$root_freeDisk
|
|||
|
#system_usedDisk=$root_usedDisk
|
|||
|
|
|||
|
#echo "system_totalSize="$system_totalSize
|
|||
|
#echo "system_freeDisk="$system_freeDisk
|
|||
|
#echo "system_usedDisk="$system_usedDisk
|
|||
|
|
|||
|
##############3#caculateDiskSize / /backup
|
|||
|
fstab_path=${rootpath}/etc/fstab
|
|||
|
|
|||
|
if [ ! -e "$fstab_path" ]; then
|
|||
|
fstab_path=/etc/fstab-backup
|
|||
|
if [ ! -e "$fstab_path" ]; then
|
|||
|
echo "$fstab_path file not exist!"
|
|||
|
exit 16
|
|||
|
fi
|
|||
|
fi
|
|||
|
|
|||
|
system_totalSize=0
|
|||
|
system_freeDisk=0
|
|||
|
system_usedDisk=0
|
|||
|
while read line; do
|
|||
|
#取第1个字符
|
|||
|
if [ "${line:0:1}" = "#" ]; then
|
|||
|
continue
|
|||
|
fi
|
|||
|
|
|||
|
echo $line
|
|||
|
echo $line >>$PLOGFILE
|
|||
|
|
|||
|
device=$(echo "$line" | awk '{print $1}')
|
|||
|
mntdir=$(echo "$line" | awk '{print $2}')
|
|||
|
fstype=$(echo "$line" | awk '{print $3}')
|
|||
|
options=$(echo "$line" | awk '{print $4}')
|
|||
|
dump=$(echo "$line" | awk '{print $5}')
|
|||
|
passno=$(echo "$line" | awk '{print $6}')
|
|||
|
|
|||
|
device=$(parse_device $device)
|
|||
|
|
|||
|
if [[ $options =~ "bind" ]]; then
|
|||
|
continue
|
|||
|
fi
|
|||
|
|
|||
|
# nodev filesystems
|
|||
|
(cat /proc/filesystems | grep "$fstype" | grep -q nodev) && continue
|
|||
|
|
|||
|
# virtual or network filesystems
|
|||
|
[ none = "$mntdir" ] || [ yes = $(is_remote $fstype) ] && continue
|
|||
|
|
|||
|
# swap or rootfs
|
|||
|
[ swap = "$fstype" ] && continue
|
|||
|
#[ swap = "$fstype" ] || [ / = "$mntdir" ] || [ /home = "$mntdir" ] || [ /var/log = "$mntdir" ]&& continue
|
|||
|
|
|||
|
#取第1个字符
|
|||
|
if [ "${mntdir:0:1}" != "/" ]; then
|
|||
|
continue
|
|||
|
fi
|
|||
|
|
|||
|
if [ $mntdir = "/backup" ]; then #没有写成$m_mountPath,看下面if
|
|||
|
continue
|
|||
|
fi
|
|||
|
|
|||
|
if [ $mntdir = $m_mountPath ]; then #没有写成$m_mountPath
|
|||
|
continue
|
|||
|
fi
|
|||
|
|
|||
|
#注意: 没有备份数据分区
|
|||
|
if [ $mntdir = "/data" ]; then
|
|||
|
hasDataPartition=1
|
|||
|
fi
|
|||
|
|
|||
|
#echo "1: " $device
|
|||
|
#echo "2: " $mntdir
|
|||
|
#echo "3: " $fstype
|
|||
|
#echo "4: " $options
|
|||
|
#echo "5: " $dump
|
|||
|
#echo "6: " $passno
|
|||
|
|
|||
|
# not system partition
|
|||
|
# [ no = $(is_system_partition $mntdir) ] && continue
|
|||
|
|
|||
|
################计算df $target_mntdir的各项值
|
|||
|
origalParas=($rootpath $mntdir)
|
|||
|
arg1=$(echo ${origalParas[*]})
|
|||
|
|
|||
|
result=($(caculateDiskSize $arg1))
|
|||
|
disk_totalSize=${result[0]}
|
|||
|
disk_freeDisk=${result[1]}
|
|||
|
disk_usedDisk=${result[2]}
|
|||
|
|
|||
|
#echo "disk_totalSize="$disk_totalSize
|
|||
|
#echo "disk_freeDisk="$disk_freeDisk
|
|||
|
#echo "disk_usedDisk="$disk_usedDisk
|
|||
|
|
|||
|
system_totalSize=$(expr $system_totalSize + $disk_totalSize)
|
|||
|
system_freeDisk=$(expr $system_freeDisk + $disk_freeDisk)
|
|||
|
system_usedDisk=$(expr $system_usedDisk + $disk_usedDisk)
|
|||
|
|
|||
|
#echo "system_totalSize="$system_totalSize
|
|||
|
#echo "system_freeDisk="$system_freeDisk
|
|||
|
#echo "system_usedDisk="$system_usedDisk
|
|||
|
|
|||
|
done <"$fstab_path"
|
|||
|
|
|||
|
#echo "system_totalSize="$system_totalSize
|
|||
|
#echo "system_freeDisk="$system_freeDisk
|
|||
|
#echo "system_usedDisk="$system_usedDisk
|
|||
|
|
|||
|
#local elements
|
|||
|
elements=($system_totalSize $system_freeDisk $system_usedDisk)
|
|||
|
echo ${elements[*]}
|
|||
|
}
|
|||
|
|
|||
|
#-----------------------------------------------------------------
|
|||
|
#//检查备份还原分区/backup剩余空间是否满足备份需求
|
|||
|
#see backup-auto/backupcommon.cpp
|
|||
|
#返回值: 0表示/backup剩余容量不能够满足备份需求;1表示满足
|
|||
|
checkBackupCapacity() { #(m_rootPath.toStdString().c_str(), retstatus))
|
|||
|
local origalParas
|
|||
|
local root_totalSize root_freeDisk root_usedDisk
|
|||
|
local backup_totalSize backup_freeDisk backup_usedDisk
|
|||
|
local system_totalSize system_freeDisk system_usedDisk
|
|||
|
###which_line=`expr $which_line + 1`
|
|||
|
|
|||
|
#从函数caculateSystemSize取返回值
|
|||
|
result=($(caculateSystemSize))
|
|||
|
system_totalSize=${result[0]}
|
|||
|
system_freeDisk=${result[1]}
|
|||
|
system_usedDisk=${result[2]}
|
|||
|
|
|||
|
#global_system_usedDisk=$system_usedDisk
|
|||
|
global_system_usedDisk=$(caculateDirSize)
|
|||
|
|
|||
|
#echo "--system_totalSize="$system_totalSize
|
|||
|
#echo "--system_freeDisk="$system_freeDisk
|
|||
|
#echo "--system_usedDisk="$system_usedDisk
|
|||
|
|
|||
|
#--------------------------------------------------------
|
|||
|
#result=(`caculateDiskSize "$rootpath" "$rootpath"`)
|
|||
|
origalParas=($rootpath "/")
|
|||
|
arg1=$(echo ${origalParas[*]})
|
|||
|
|
|||
|
result=($(caculateDiskSize $arg1))
|
|||
|
root_totalSize=${result[0]}
|
|||
|
root_freeDisk=${result[1]}
|
|||
|
root_usedDisk=${result[2]}
|
|||
|
#echo "--root_totalSize="$root_totalSize
|
|||
|
#echo "--root_freeDisk="$root_freeDisk
|
|||
|
#echo "--root_usedDisk="$root_usedDisk
|
|||
|
|
|||
|
#--------------------------------------------------------
|
|||
|
#caculateDiskSize / /backup
|
|||
|
#origalParas=($rootpath "/backup")
|
|||
|
#origalParas=("/" "/backup") #/backup不会是/root/backup
|
|||
|
origalParas=("/" $m_mountPath) #/backup不会是/root/backup
|
|||
|
arg1=$(echo ${origalParas[*]})
|
|||
|
|
|||
|
result=($(caculateDiskSize $arg1))
|
|||
|
backup_totalSize=${result[0]}
|
|||
|
backup_freeDisk=${result[1]}
|
|||
|
backup_usedDisk=${result[2]}
|
|||
|
|
|||
|
#echo "--backup_totalSize="$backup_totalSize
|
|||
|
#echo "--backup_freeDisk="$backup_freeDisk
|
|||
|
#echo "--backup_usedDisk="$backup_usedDisk
|
|||
|
|
|||
|
if [[ $root_totalSize = $backup_totalSize && $root_freeDisk = $backup_freeDisk && $root_usedDisk = $backup_usedDisk ]]; then #"/backup"是不是一个独立的盘
|
|||
|
echo "Cannot find the /backup disk or not be mounted!"
|
|||
|
exit 12
|
|||
|
fi
|
|||
|
|
|||
|
echo "free size : $backup_freeDisk; sys_size : $global_system_usedDisk"
|
|||
|
echo "free size : $backup_freeDisk; sys_size : $global_system_usedDisk" >>$PLOGFILE
|
|||
|
if [ ${backup_freeDisk} -gt ${global_system_usedDisk} ]; then
|
|||
|
return 1
|
|||
|
else
|
|||
|
return 0
|
|||
|
fi
|
|||
|
}
|
|||
|
|
|||
|
updateStateByComment() {
|
|||
|
tmpFile=${m_backuplistPath}".tmp"
|
|||
|
#echo "tmpFile: $tmpFile"
|
|||
|
is_first_line=1
|
|||
|
|
|||
|
foundComment=0 #是否发现了要修改的comment
|
|||
|
|
|||
|
#如果不定义IFS,则echo $line会去掉前后空格,导致写到文件中去时没有格式
|
|||
|
IFS_old=$IFS
|
|||
|
IFS=$'\n'
|
|||
|
while read line; do
|
|||
|
#去除了前后空格
|
|||
|
xxx=$(echo "$line" | sed "s/^[ \t]*//g" | sed "s/[ \t]*$//g")
|
|||
|
#echo "xxx: $xxx"
|
|||
|
|
|||
|
if [[ "$xxx" =~ "<Comment>" ]]; then
|
|||
|
if [ $xxx = "<Comment>${m_comment}</Comment>" ]; then
|
|||
|
foundComment=1 #当前comment是要修改的mycomment
|
|||
|
else
|
|||
|
foundComment=0 #当前comment不是要修改的mycomment
|
|||
|
fi
|
|||
|
fi
|
|||
|
|
|||
|
if [[ "$xxx" =~ "<Size>" ]]; then
|
|||
|
if [[ $foundComment -eq 1 ]]; then
|
|||
|
line=" <Size>${newSize}</Size>"
|
|||
|
fi
|
|||
|
fi
|
|||
|
|
|||
|
|
|||
|
if [[ "$xxx" =~ "<State>" ]]; then
|
|||
|
if [ $foundComment -eq 1 ]; then
|
|||
|
line=" <State>${m_state}</State>"
|
|||
|
fi
|
|||
|
fi
|
|||
|
|
|||
|
if [ "$is_first_line" -eq 1 ]; then
|
|||
|
echo "$line" >$tmpFile
|
|||
|
else
|
|||
|
echo "$line" >>$tmpFile
|
|||
|
fi
|
|||
|
|
|||
|
is_first_line=0
|
|||
|
|
|||
|
done <"$m_backuplistPath"
|
|||
|
IFS=$IFS_old
|
|||
|
|
|||
|
cp -f $tmpFile ${m_backuplistPath}
|
|||
|
rm -f $tmpFile
|
|||
|
}
|
|||
|
|
|||
|
#参照backup-daemon/backupmanager.cpp, 写日志文件
|
|||
|
writeLogFile() {
|
|||
|
echo $1 >>$LOGFILE
|
|||
|
}
|
|||
|
|
|||
|
#参照backup-daemon/mountpoint.cpp
|
|||
|
bFileExists() {
|
|||
|
local theFile theOldFile
|
|||
|
theOldFile=$1 #必须以"/"开始,但本身是个相对路径,因为没有加rootpath.
|
|||
|
|
|||
|
if [ $rootpath = "/" ]; then
|
|||
|
theFile=$theOldFile
|
|||
|
else
|
|||
|
theFile=$theOldFile
|
|||
|
theFile="$rootpath""$theFile"
|
|||
|
fi
|
|||
|
|
|||
|
if [ -e "$theFile" ]; then
|
|||
|
echo "$theOldFile" >>$EXCLUDEFILE
|
|||
|
fi
|
|||
|
}
|
|||
|
|
|||
|
#参照backup-daemon/mountpoint.cpp
|
|||
|
generateExcludeFile() {
|
|||
|
local backupOrRestore
|
|||
|
backupOrRestore=$1 #0: backup 1:restore
|
|||
|
|
|||
|
#exclude的必须是相对目录,其实在efi启动时为/root/data
|
|||
|
#see backup-daemon/mountpoint.cpp, backup-daemon/data/backup-auto-efi
|
|||
|
#also kybackup: exclude.ui databackupdirs.ui dataincbackupdirs.ui
|
|||
|
#if [ ! -e "$restoreDir" ]; then
|
|||
|
#注意下面的>和>>-----------------------------------------------
|
|||
|
echo "/efi" >$EXCLUDEFILE
|
|||
|
echo "/backup" >>$EXCLUDEFILE
|
|||
|
#echo "/boot/efi" >>$EXCLUDEFILE
|
|||
|
echo "/dev" >>$EXCLUDEFILE
|
|||
|
echo "/ghost" >>$EXCLUDEFILE #ghost镜像文件
|
|||
|
echo "/mnt" >>$EXCLUDEFILE
|
|||
|
echo "/proc" >>$EXCLUDEFILE
|
|||
|
echo "/run" >>$EXCLUDEFILE
|
|||
|
echo "/sys" >>$EXCLUDEFILE
|
|||
|
echo "/media" >>$EXCLUDEFILE
|
|||
|
echo "/tmp" >>$EXCLUDEFILE
|
|||
|
echo "/lost+found" >>$EXCLUDEFILE
|
|||
|
echo "/var/lib/udisks2" >>$EXCLUDEFILE
|
|||
|
#echo "/data/home/*" >>$EXCLUDEFILE
|
|||
|
#echo "/data/root/*" >>$EXCLUDEFILE
|
|||
|
#if [ -e "${rootpath}/data/home" ]; then
|
|||
|
# echo "/home" >>$EXCLUDEFILE
|
|||
|
# echo "/root" >>$EXCLUDEFILE
|
|||
|
#fi
|
|||
|
echo "/cdrom" >>$EXCLUDEFILE
|
|||
|
echo "/swap_file" >>$EXCLUDEFILE
|
|||
|
echo "/var/lib/docker/overlay2" >>$EXCLUDEFILE
|
|||
|
echo "*/backup/snapshots" >>$EXCLUDEFILE
|
|||
|
echo "/var/log" >>$EXCLUDEFILE
|
|||
|
|
|||
|
#bind挂载的目录不进行备份或还原
|
|||
|
if [ -z $fstab_path ]; then
|
|||
|
fstab_path=${rootpath}/etc/fstab
|
|||
|
|
|||
|
if [ ! -e "$fstab_path" ]; then
|
|||
|
fstab_path=/etc/fstab-backup
|
|||
|
if [ ! -e "$fstab_path" ]; then
|
|||
|
echo "$fstab_path file not exist!"
|
|||
|
exit 16
|
|||
|
fi
|
|||
|
fi
|
|||
|
fi
|
|||
|
cat $fstab_path | awk '{if($4~/bind/) print $1}' |
|
|||
|
while read excludePath
|
|||
|
do
|
|||
|
echo "$excludePath" >>$EXCLUDEFILE
|
|||
|
done
|
|||
|
|
|||
|
#bFileExists "/etc/.bootinfo"
|
|||
|
#bFileExists "/etc/fpb" #管控,暂时
|
|||
|
#echo "/etc/.bootinfo" >>$EXCLUDEFILE
|
|||
|
|
|||
|
#数据分区是否使用由用户输入,最终放到/backup/snapshots/.excludeuser
|
|||
|
#因为GRUB没有界面,所以是不是先在其他模式下做一次备份,生成这个文件;然后GRUB就可以了。
|
|||
|
#echo "/data/*" >>$EXCLUDEFILE #用户可以把数据放到该分区或者目录
|
|||
|
|
|||
|
#是否覆盖备份还原工具自身,因为grub备份还原使用的工具是initrd.img里面的东西,故不存在时可以还原备份还原工具本身(例如工具被删除的场景)
|
|||
|
#if [ $backupOrRestore -eq 1 ]; then
|
|||
|
# bFileExists "/usr/bin/backup-daemon"
|
|||
|
# bFileExists "/usr/bin/kybackup"
|
|||
|
# bFileExists "/usr/bin/backup-auto"
|
|||
|
# bFileExists "/usr/bin/mount_fstab_efi"
|
|||
|
# bFileExists "/usr/bin/backup-auto-efi"
|
|||
|
# bFileExists "/usr/bin/rsync"
|
|||
|
# bFileExists "/usr/share/rsync"
|
|||
|
# bFileExists "/usr/share/initramfs-tools/hooks/kybackup-hooks"
|
|||
|
# bFileExists "/usr/share/initramfs-tools/scripts/local-bottom/kybackup"
|
|||
|
#fi
|
|||
|
|
|||
|
# 安全模块会将文件/usr/share/kysec-utils/data/readonly_list中的文件列表限制只读,无法修改、备份(包含扩展属性时)、删除等
|
|||
|
# 现在里面仅有/etc/uid_list,先暂时排除掉;等后续安全模块有其它保护方案后再进一步修改
|
|||
|
# 新:用安全保护程序/usr/bin/setstatus可以关闭保护,故不再排除此文件
|
|||
|
# echo "/etc/uid_list" >>$EXCLUDEFILE
|
|||
|
#if [ $backupOrRestore -eq 1 ]; then
|
|||
|
# bFileExists "/usr/bin/backup-daemon" #备份还原
|
|||
|
# bFileExists "/usr/bin/kybackup" #备份还原
|
|||
|
# bFileExists "/usr/bin/mount_fstab" #备份还原
|
|||
|
# bFileExists "/usr/bin/backup-auto" #备份还原
|
|||
|
# bFileExists "/usr/bin/mount_fstab_efi" #备份还原
|
|||
|
# bFileExists "/usr/bin/backup-auto-efi" #备份还原
|
|||
|
#fi
|
|||
|
|
|||
|
#是否使用由用户输入,最终放到/backup/snapshots/.excludeuser
|
|||
|
#if [ "$XGS" = true ]; then
|
|||
|
# echo "/etc/passwd" >>$EXCLUDEFILE
|
|||
|
# echo "/etc/group" >>$EXCLUDEFILE
|
|||
|
# echo "/etc/shadow" >>$EXCLUDEFILE
|
|||
|
# if [ -e "/etc/uid_list" ]; then
|
|||
|
# echo "/etc/uid_list" >>$EXCLUDEFILE
|
|||
|
# fi
|
|||
|
|
|||
|
# echo "/home/*" >>$EXCLUDEFILE
|
|||
|
# echo "/opt/softmanager/log/log_cur.txt" >>$EXCLUDEFILE
|
|||
|
# echo "/opt/softmanager/conf/audit/auditLogCur.txt" >>$EXCLUDEFILE
|
|||
|
# echo "/opt/xgs/Audit/*" >>$EXCLUDEFILE
|
|||
|
# echo "/opt/LinuxKpc/log/*" >>$EXCLUDEFILE
|
|||
|
# echo "/var/log/*" >>$EXCLUDEFILE
|
|||
|
# echo "/var/run/*" >>$EXCLUDEFILE
|
|||
|
# echo "/root/*" >>$EXCLUDEFILE
|
|||
|
# echo "/var/mail/*" >>$EXCLUDEFILE
|
|||
|
# echo "/boot/efi/*" >>$EXCLUDEFILE #xgs出厂还原时会失败
|
|||
|
#fi
|
|||
|
#fi
|
|||
|
}
|
|||
|
|
|||
|
backuping() {
|
|||
|
local src dst
|
|||
|
|
|||
|
src=$1
|
|||
|
dst=$2
|
|||
|
|
|||
|
#0:backup 1:restore
|
|||
|
generateExcludeFile 0
|
|||
|
echo "/" > ${m_mountPath}${BACKUP}/snapshots/$m_uuid/$PERSONAL_BACKUPFILE
|
|||
|
cp $EXCLUDEFILE ${m_mountPath}${BACKUP}/snapshots/$m_uuid/$PERSONAL_EXCLUDEFILE
|
|||
|
|
|||
|
#echo "Begin to backup efi directory..." >>$PLOGFILE
|
|||
|
#echo "Begin to backup efi directory..."
|
|||
|
# /boot/efi不再单独备份
|
|||
|
#if [ -d "${src}/boot/efi" ]; then
|
|||
|
# mkdir -p ${dst}/boot
|
|||
|
# rsync -av --ignore-missing-args ${src}/boot/efi ${dst}/boot >/dev/null 2>>$PLOGFILE
|
|||
|
# if [ $? -ne 0 -a $? -ne 24 -a $? -ne 23 ]; then
|
|||
|
# echo "backup update backuplist.xml failed for updateBackupAutoFinishedState!"
|
|||
|
# echo "backup update backuplist.xml failed for updateBackupAutoFinishedState!" >>$PLOGFILE
|
|||
|
# m_state="backup unfinished"
|
|||
|
# updateStateByComment
|
|||
|
# echo "System backuping failed, please reboot your system!"
|
|||
|
# echo "System backuping failed, please reboot your system!" >>$PLOGFILE
|
|||
|
# exit 14
|
|||
|
# fi
|
|||
|
#fi
|
|||
|
|
|||
|
echo "Begin to backup other directories..." >>$PLOGFILE
|
|||
|
echo "Begin to backup other directories..."
|
|||
|
#是否有数据分区
|
|||
|
if [ $hasDataPartition -eq 0 ]; then
|
|||
|
#exclude的必须是相对目录,其实在efi启动时为/root/data
|
|||
|
#echo rsync -avAXH --ignore-missing-args --exclude-from $EXCLUDEFILE $src $dst
|
|||
|
#rsync -avAXH --ignore-missing-args --exclude-from $EXCLUDEFILE $src $dst
|
|||
|
|
|||
|
#不是目录,也不备份
|
|||
|
echo rsync -avAXH --ignore-missing-args --exclude-from $EXCLUDEFILE $src $dst >/dev/null 2>>$PLOGFILE
|
|||
|
rsync -avAXH --ignore-missing-args --exclude-from $EXCLUDEFILE $src $dst >/dev/null 2>>$PLOGFILE
|
|||
|
else
|
|||
|
#exclude的必须是相对目录,其实在efi启动时为/root/data
|
|||
|
#echo rsync -avAXH --ignore-missing-args --exclude data --exclude-from=$EXCLUDEFILE $src $dst
|
|||
|
#The question is that the 'data' directories can not be copied
|
|||
|
echo rsync -avAXH --ignore-missing-args --exclude-from $EXCLUDEFILE $src $dst >/dev/null 2>>$PLOGFILE
|
|||
|
rsync -avAXH --ignore-missing-args --exclude-from $EXCLUDEFILE $src $dst >/dev/null 2>>$PLOGFILE
|
|||
|
fi
|
|||
|
|
|||
|
if [ $? -eq 0 -o $? -eq 24 -o $? -eq 23 ]; then
|
|||
|
#updateStateByComment $m_comment 0
|
|||
|
sync
|
|||
|
m_state="backup finished"
|
|||
|
touch $dst/.exectl
|
|||
|
#caculateDirSize $dst
|
|||
|
|
|||
|
updateStateByComment
|
|||
|
|
|||
|
else
|
|||
|
#将状态从"backup unfinished"改成"backup failed"
|
|||
|
echo "backup update backuplist.xml failed for updateBackupAutoFinishedState!"
|
|||
|
echo "backup update backuplist.xml failed for updateBackupAutoFinishedState!" >>$PLOGFILE
|
|||
|
m_state="backup unfinished"
|
|||
|
updateStateByComment
|
|||
|
echo "System backuping failed, please reboot your system!"
|
|||
|
echo "System backuping failed, please reboot your system!" >>$PLOGFILE
|
|||
|
exit 14
|
|||
|
fi
|
|||
|
|
|||
|
#写文件
|
|||
|
metainfo_file="${m_mountPath}/snapshots/$m_uuid/$METAINFO"
|
|||
|
#echo "metainfo_file="$metainfo_file
|
|||
|
#第1行清空写
|
|||
|
#这里写的不是xml文件,是一个文本文件,这时候的状态是0或者backup failed
|
|||
|
echo "COMMENT=$m_comment" >$metainfo_file
|
|||
|
echo "TIME=$m_time" >>$metainfo_file
|
|||
|
echo "UUID=$m_uuid" >>$metainfo_file
|
|||
|
echo "SIZE=$m_size" >>$metainfo_file
|
|||
|
echo "STATE=$m_state" >>$metainfo_file
|
|||
|
|
|||
|
#写日志文件
|
|||
|
writeLogFile "${m_time},${m_uuid},0,grub备份,${newSize}" #grub时只有全盘备份,没有增量备份
|
|||
|
sync
|
|||
|
}
|
|||
|
|
|||
|
CreateUuid() {
|
|||
|
local uuid=`cat /proc/sys/kernel/random/uuid|tr -d "\n"`
|
|||
|
while [ "$uuid" = $factory_uuid -o "$uuid" = $auto_uuid ]
|
|||
|
do
|
|||
|
uuid=`cat /proc/sys/kernel/random/uuid|tr -d "\n"`
|
|||
|
done
|
|||
|
echo $uuid
|
|||
|
}
|
|||
|
|
|||
|
findCommentByUuid() {
|
|||
|
|
|||
|
local ret=1
|
|||
|
local local_uuid=$1
|
|||
|
local comment0
|
|||
|
local ret_comment
|
|||
|
|
|||
|
#如果不定义IFS,则echo $line会去掉前后空格,导致写到文件中去时没有格式
|
|||
|
IFS_old=$IFS
|
|||
|
IFS=$'\n'
|
|||
|
while read line;
|
|||
|
do
|
|||
|
#去除了前后空格
|
|||
|
xxx=$( echo "$line" | sed "s/^[ \t]*//g" | sed "s/[ \t]*$//g" )
|
|||
|
#echo "xxx: $xxx"
|
|||
|
|
|||
|
if [[ "$xxx" =~ "<Comment>" ]]; then
|
|||
|
comment0=`echo $xxx | awk -F "<Comment>" '{print $2}' |awk -F "</Comment>" '{print $1}' | tr -d "\n"`
|
|||
|
fi
|
|||
|
|
|||
|
if [[ "$xxx" =~ "<Uuid>" ]]; then
|
|||
|
if [ $xxx = "<Uuid>${local_uuid}</Uuid>" ]; then
|
|||
|
ret=0
|
|||
|
ret_comment=$comment0
|
|||
|
break
|
|||
|
fi
|
|||
|
fi
|
|||
|
done < "$m_backuplistPath";
|
|||
|
IFS=$IFS_old
|
|||
|
|
|||
|
echo $ret_comment
|
|||
|
return $ret
|
|||
|
}
|
|||
|
|
|||
|
deleteItemByComment() {
|
|||
|
local local_comment=$1
|
|||
|
echo "arg local_comment = $local_comment"
|
|||
|
|
|||
|
tmpFile=${m_backuplistPath}".tmp"
|
|||
|
cp -f ${m_backuplistPath} $tmpFile
|
|||
|
# echo "tmpFile: $tmpFile"
|
|||
|
|
|||
|
local foundComment=0 #是否发现了要修改的comment
|
|||
|
local i=0
|
|||
|
local ii=0
|
|||
|
local iii=0
|
|||
|
local backupPointTmp=0
|
|||
|
|
|||
|
#如果不定义IFS,则echo $line会去掉前后空格,导致写到文件中去时没有格式
|
|||
|
IFS_old=$IFS
|
|||
|
IFS=$'\n'
|
|||
|
while read line;
|
|||
|
do
|
|||
|
let i+=1
|
|||
|
#去除了前后空格
|
|||
|
xxx=$( echo "$line" | sed "s/^[ \t]*//g" | sed "s/[ \t]*$//g" )
|
|||
|
#echo "xxx: $xxx"
|
|||
|
|
|||
|
if [[ "$xxx" =~ "<BackupPoint>" ]]; then
|
|||
|
backupPointTmp=$i
|
|||
|
fi
|
|||
|
if [[ "$xxx" =~ "<Comment>" ]]; then
|
|||
|
if [ $xxx = "<Comment>$local_comment</Comment>" ]; then
|
|||
|
foundComment=1 #当前comment是要修改的mycomment
|
|||
|
ii=$backupPointTmp
|
|||
|
#echo "delete foundComment = 1"
|
|||
|
else
|
|||
|
foundComment=0 #当前comment不是要修改的mycomment
|
|||
|
fi
|
|||
|
fi
|
|||
|
if [[ "$xxx" =~ "</BackupPoint>" ]]; then
|
|||
|
if [ $foundComment -eq 1 ]; then
|
|||
|
iii=$i
|
|||
|
break
|
|||
|
fi
|
|||
|
fi
|
|||
|
done < "$tmpFile";
|
|||
|
IFS=$IFS_old
|
|||
|
|
|||
|
# echo "ii: $ii, iii: $iii"
|
|||
|
|
|||
|
if [ $iii -ne 0 ]; then
|
|||
|
sed -i "${ii},${iii}d" $tmpFile
|
|||
|
cp -f $tmpFile ${m_backuplistPath}
|
|||
|
fi
|
|||
|
rm -f $tmpFile
|
|||
|
}
|
|||
|
|
|||
|
DeleteFactoryBackup() {
|
|||
|
if [ -e "/backup${BACKUP}/snapshots/{${factory_uuid}}" ]; then
|
|||
|
rm /backup${BACKUP}/snapshots/{${factory_uuid}} -rf
|
|||
|
fi
|
|||
|
|
|||
|
local comment=$(findCommentByUuid "{${factory_uuid}}")
|
|||
|
# echo "DeleteFactoryBackup comment is $comment"
|
|||
|
if [ $? -eq 0 ]; then
|
|||
|
deleteItemByComment "$comment"
|
|||
|
fi
|
|||
|
}
|
|||
|
|
|||
|
#see backup-auto/autobackup.cpp
|
|||
|
backupAuto() { #备份
|
|||
|
if [ $m_isFactory = true ]; then
|
|||
|
DeleteFactoryBackup
|
|||
|
fi
|
|||
|
|
|||
|
local xxx
|
|||
|
checkBackupCapacity
|
|||
|
ret=$?
|
|||
|
if [ "$ret" -eq 0 ]; then
|
|||
|
echo "The backup disk space is not enough"
|
|||
|
exit 4
|
|||
|
fi
|
|||
|
|
|||
|
#global_system_usedDisk
|
|||
|
#创建一个uuid
|
|||
|
if [ $m_isFactory = false ]; then
|
|||
|
m_uuid=$(CreateUuid)
|
|||
|
else
|
|||
|
m_uuid="$factory_uuid"
|
|||
|
fi
|
|||
|
m_uuid="{"${m_uuid}"}"
|
|||
|
# echo "BYbobbi: m_uuid is $m_uuid"
|
|||
|
m_time=$(date "+%y-%m-%d %H:%M:%S" | tr -d "\n")
|
|||
|
m_comment=$m_time #这个是全局变量
|
|||
|
dst="${m_mountPath}${BACKUP}/snapshots/$m_uuid/data"
|
|||
|
#echo "dst: $dst"
|
|||
|
mkdir -p $dst
|
|||
|
m_size=$global_system_usedDisk
|
|||
|
|
|||
|
#m_size=188248
|
|||
|
newSize1=$(echo "scale=2;$m_size / $GB" | bc)
|
|||
|
newSize2=$(echo "scale=2;$m_size / $MB" | bc)
|
|||
|
newSize3=$(echo "scale=2;$m_size / $KB" | bc)
|
|||
|
|
|||
|
if [ $(echo "$newSize1 > 1.0" | bc) = 1 ]; then
|
|||
|
newSize=$newSize1"GB"
|
|||
|
elif [ $(echo "$newSize2 > 1.0" | bc) = 1 ]; then
|
|||
|
newSize=$newSize2"MB"
|
|||
|
else
|
|||
|
newSize=$newSize3"KB"
|
|||
|
fi
|
|||
|
|
|||
|
state="backup unfinished"
|
|||
|
|
|||
|
#写入文件m_backuplistPath=$m_mountPath"/snapshots/backuplist1.xml"
|
|||
|
#bool AutoBackup::backupAuto()251 if (!m_parse->addItem(m_comment, time, m_uuid, newsize, "backup unfinished")) {
|
|||
|
#
|
|||
|
tmpFile=${m_backuplistPath}".tmp"
|
|||
|
#echo "tmpFile: $tmpFile"
|
|||
|
new_content=""
|
|||
|
is_first_line=1
|
|||
|
|
|||
|
hasHead=false #有头吗"<backupList>"
|
|||
|
|
|||
|
#如果不定义IFS,则echo $line会去掉前后空格,导致写到文件中去时没有格式
|
|||
|
IFS_old=$IFS
|
|||
|
IFS=$'\n'
|
|||
|
|
|||
|
while read line; do
|
|||
|
#去除了前后空格
|
|||
|
xxx=$(echo "$line" | sed "s/^[ \t]*//g" | sed "s/[ \t]*$//g")
|
|||
|
#echo "xxx: $xxx"
|
|||
|
|
|||
|
if [[ "$xxx" =~ "<backupList>" ]]; then
|
|||
|
hasHead=true
|
|||
|
fi
|
|||
|
|
|||
|
if [[ "$xxx" =~ "<backupList/>" ]]; then
|
|||
|
xxx="</backupList>" #与图形界面一致
|
|||
|
line="</backupList>"
|
|||
|
fi
|
|||
|
|
|||
|
#插入新的记录
|
|||
|
if [ $xxx = "</backupList>" ]; then
|
|||
|
if [ "$hasHead" = false ]; then
|
|||
|
echo "<backupList>" >>$tmpFile
|
|||
|
hasHead=true
|
|||
|
fi
|
|||
|
|
|||
|
echo " <BackupPoint>" >>$tmpFile
|
|||
|
echo " <Comment>$m_comment</Comment>" >>$tmpFile
|
|||
|
echo " <Time>$m_time</Time>" >>$tmpFile
|
|||
|
echo " <Uuid>$m_uuid</Uuid>" >>$tmpFile
|
|||
|
echo " <Size>$newSize</Size>" >>$tmpFile
|
|||
|
echo " <State>$state</State>" >>$tmpFile
|
|||
|
echo " <Type>0</Type>" >>$tmpFile
|
|||
|
echo " </BackupPoint>" >>$tmpFile
|
|||
|
fi
|
|||
|
|
|||
|
if [ "$is_first_line" -eq 1 ]; then
|
|||
|
echo "$line" >$tmpFile
|
|||
|
else
|
|||
|
echo "$line" >>$tmpFile
|
|||
|
fi
|
|||
|
|
|||
|
is_first_line=0
|
|||
|
|
|||
|
done <"$m_backuplistPath"
|
|||
|
IFS=$IFS_old$
|
|||
|
|
|||
|
cp -f $tmpFile ${m_backuplistPath}
|
|||
|
rm -f $tmpFile
|
|||
|
|
|||
|
#写文件
|
|||
|
metainfo_file="${m_mountPath}${BACKUP}/snapshots/$m_uuid/$METAINFO"
|
|||
|
#echo "metainfo_file="$metainfo_file
|
|||
|
#第1行清空写
|
|||
|
#这里写的不是xml文件,是一个文本文件,这时候的状态是backup unfinished
|
|||
|
echo "COMMENT=$m_comment" >$metainfo_file
|
|||
|
echo "TIME=$m_time" >>$metainfo_file
|
|||
|
echo "UUID=$m_uuid" >>$metainfo_file
|
|||
|
echo "SIZE=$m_size" >>$metainfo_file
|
|||
|
echo "STATE=$state" >>$metainfo_file
|
|||
|
echo "TYPE=0" >>$metainfo_file
|
|||
|
|
|||
|
backuping ${rootpath}/ $dst
|
|||
|
}
|
|||
|
|
|||
|
#返回值:
|
|||
|
getLastUsefulBackupPointUuid() {
|
|||
|
local xxx currentUuid foundComment
|
|||
|
currentUuid=""
|
|||
|
currentState=false
|
|||
|
currentType=true
|
|||
|
lastUsefulBackupPointUuid=""
|
|||
|
foundComment=0 #是否发现了要修改的comment
|
|||
|
lastbackupname=""
|
|||
|
|
|||
|
#如果不定义IFS,则echo $line会去掉前后空格,导致写到文件中去时没有格式
|
|||
|
IFS_old=$IFS
|
|||
|
IFS=$'\n'
|
|||
|
while read line; do
|
|||
|
#去除了前后空格
|
|||
|
xxx=$(echo "$line" | sed "s/^[ \t]*//g" | sed "s/[ \t]*$//g")
|
|||
|
#echo "xxx: $xxx"
|
|||
|
|
|||
|
if [[ "$xxx" =~ "<Comment>" ]]; then
|
|||
|
lastbackupname=$xxx
|
|||
|
fi
|
|||
|
|
|||
|
if [[ "$xxx" =~ "<Uuid>" ]]; then
|
|||
|
currentUuid=$xxx
|
|||
|
currentState=false
|
|||
|
currentType=true
|
|||
|
fi
|
|||
|
|
|||
|
if [[ "$xxx" =~ "<State>backup finished</State>" ]]; then
|
|||
|
#lastUsefulBackupPointUuid=$currentUuid
|
|||
|
currentState=true
|
|||
|
fi
|
|||
|
|
|||
|
if [[ "$xxx" =~ "<Type>2</Type>" ]]; then
|
|||
|
currentType=false
|
|||
|
fi
|
|||
|
|
|||
|
if [[ "$xxx" =~ "<Type>3</Type>" ]]; then
|
|||
|
currentType=false
|
|||
|
fi
|
|||
|
|
|||
|
if [[ "$xxx" =~ "<Position>3</Position>" ]]; then
|
|||
|
currentType=false
|
|||
|
fi
|
|||
|
|
|||
|
if [[ "$xxx" =~ "</BackupPoint>" ]]; then
|
|||
|
if [ "$currentState" = true -a "$currentType" = true ]; then #"/backup"是不是一个独立的盘
|
|||
|
lastUsefulBackupPointUuid=$currentUuid
|
|||
|
fi
|
|||
|
fi
|
|||
|
done <"$m_backuplistPath"
|
|||
|
IFS=$IFS_old
|
|||
|
|
|||
|
if [ "$lastUsefulBackupPointUuid" = "" ]; then
|
|||
|
echo "can't find a useful backup for restoring"
|
|||
|
exit 6
|
|||
|
fi
|
|||
|
|
|||
|
lastUsefulBackupPointUuid=$(echo $lastUsefulBackupPointUuid | sed 's:<Uuid>::' | tr -d "\n")
|
|||
|
lastUsefulBackupPointUuid=$(echo $lastUsefulBackupPointUuid | sed 's:</Uuid>.*::' | tr -d "\n")
|
|||
|
#echo "lastUsefulBackupPointUuid=$lastUsefulBackupPointUuid"
|
|||
|
lastbackupname=$(echo $lastbackupname | sed 's:<Comment>::' | tr -d "\n")
|
|||
|
lastbackupname=$(echo $lastbackupname | sed 's:</Comment>.*::' | tr -d "\n")
|
|||
|
}
|
|||
|
|
|||
|
#see backup-auto/autobackup.cpp
|
|||
|
restoreAuto() { #还原
|
|||
|
local xxx
|
|||
|
local uuid
|
|||
|
if [ $m_isFactory = false ]; then
|
|||
|
#echo "lastUsefulBackupPointUuid=$lastUsefulBackupPointUuid"
|
|||
|
if [ x"$m_default_uuid" != x"" ]; then
|
|||
|
#m_default_uuid=$lastUsefulBackupPointUuid
|
|||
|
uuid=$m_default_uuid
|
|||
|
else
|
|||
|
getLastUsefulBackupPointUuid
|
|||
|
uuid=$lastUsefulBackupPointUuid
|
|||
|
fi
|
|||
|
else
|
|||
|
uuid="{${factory_uuid}}"
|
|||
|
fi
|
|||
|
#写日志文件
|
|||
|
local m_time=$(date "+%y-%m-%d %H:%M:%S" | tr -d "\n")
|
|||
|
writeLogFile "${m_time},${uuid},4,grub系统还原,,,${lastbackupname}" #grub时只有一键还原,没有增量还原
|
|||
|
|
|||
|
restoreDir="${m_mountPath}${BACKUP}/snapshots/$uuid"
|
|||
|
|
|||
|
if [ ! -e "$restoreDir" ]; then
|
|||
|
echo "full restore directory not exists!"
|
|||
|
exit 7 #备份文件不存在,不能还原系统
|
|||
|
fi
|
|||
|
|
|||
|
if [ "$uuid" = "{$auto_uuid}" ]; then
|
|||
|
m_isRetainUserData=true
|
|||
|
fi
|
|||
|
|
|||
|
#0:backup 1:restore
|
|||
|
#generateExcludeFile 1
|
|||
|
echo "Begin to restore efi directory..." >>$PLOGFILE
|
|||
|
echo "Begin to restore efi directory..."
|
|||
|
#额外排除目录或文件
|
|||
|
local excludes=
|
|||
|
if [ -d ${restoreDir}/data/efi ]; then
|
|||
|
rsync -avAXHr --no-inc-recursive --ignore-missing-args --delete ${restoreDir}/data/efi ${rootpath}/boot >/dev/null 2>>$PLOGFILE
|
|||
|
if [ $? -ne 0 -a $? -ne 24 -a $? -ne 23 ]; then
|
|||
|
echo "System restoring failed, please reboot your system!"
|
|||
|
echo "System restoring failed, please reboot your system!" >>$PLOGFILE
|
|||
|
exit 9
|
|||
|
fi
|
|||
|
elif [ -d ${restoreDir}/data/boot/efi ]; then
|
|||
|
rsync -avAXHr --no-inc-recursive --ignore-missing-args --delete ${restoreDir}/data/boot/efi ${rootpath}/boot >/dev/null 2>>$PLOGFILE
|
|||
|
if [ $? -ne 0 -a $? -ne 24 -a $? -ne 23 ]; then
|
|||
|
echo "System restoring failed, please reboot your system!"
|
|||
|
echo "System restoring failed, please reboot your system!" >>$PLOGFILE
|
|||
|
exit 9
|
|||
|
fi
|
|||
|
fi
|
|||
|
|
|||
|
echo "Begin to restore other directories..."
|
|||
|
echo "Begin to restore other directories..." >>$PLOGFILE
|
|||
|
#保留用户数据还原
|
|||
|
if [[ x${m_isRetainUserData} = x"true" ]]; then
|
|||
|
# 用户数据目录或文件
|
|||
|
if [ -e "${rootpath}/var/lib/biometric-auth" ]; then
|
|||
|
excludes="${excludes} --exclude=/var/lib/biometric-auth"
|
|||
|
fi
|
|||
|
if [ -e "${rootpath}/data/sec_storage_data" ]; then
|
|||
|
excludes="${excludes} --exclude=/data/sec_storage_data"
|
|||
|
fi
|
|||
|
if [ -e "${rootpath}/etc/passwd" ]; then
|
|||
|
excludes="${excludes} --exclude=/etc/passwd"
|
|||
|
fi
|
|||
|
if [ -e "${rootpath}/etc/shadow" ]; then
|
|||
|
excludes="${excludes} --exclude=/etc/shadow"
|
|||
|
fi
|
|||
|
if [ -e "${rootpath}/etc/group" ]; then
|
|||
|
excludes="${excludes} --exclude=/etc/group"
|
|||
|
fi
|
|||
|
if [ -e "${rootpath}/etc/gshadow" ]; then
|
|||
|
excludes="${excludes} --exclude=/etc/gshadow"
|
|||
|
fi
|
|||
|
if [ -e "${rootpath}/etc/sudoers" ]; then
|
|||
|
excludes="${excludes} --exclude=/etc/sudoers"
|
|||
|
fi
|
|||
|
excludes="${excludes} --exclude=/home --exclude=/root --exclude=/data/home --exclude=/data/root --exclude=/var/lib/AccountsService"
|
|||
|
#下面是域用户相关信息,保留用户数据还原后不退域
|
|||
|
excludes="${excludes} --exclude=/etc/sssd --exclude=/var/lib/sss --exclude=/usr/share/sssd --exclude=/etc/ipa --exclude=/etc/krb5.keytab"
|
|||
|
excludes="${excludes} --exclude=/etc/krb5.conf --exclude=/var/lib/ipa-client --exclude=/etc/nsswitch.conf --exclude=/etc/pam.d --exclude=/etc/hosts"
|
|||
|
excludes="${excludes} --exclude=/etc/hostname --exclude=/etc/hedron --exclude=/etc/kcm --exclude=/usr/hedron/hedronagent --exclude=/etc/.kyinfo --exclude=/etc/LICENSE"
|
|||
|
excludes="${excludes} --exclude=/etc/ssl/certs --exclude=/usr/share/ca-certificates --exclude=/etc/NetworkManager"
|
|||
|
|
|||
|
#如果是990,排除/data;否则,排除/data/usershare
|
|||
|
if [ x${is_990_9a0} == x"true" ]; then
|
|||
|
excludes="${excludes} --exclude=/data"
|
|||
|
else
|
|||
|
excludes="${excludes} --exclude=/data/usershare"
|
|||
|
fi
|
|||
|
#如果是出厂备份的还原,还需要保留语言和时区配置
|
|||
|
if [[ ${uuid} = "{${factory_uuid}}" && x${is_990_9a0} != x"true" ]]; then
|
|||
|
if [ -e "${rootpath}/etc/localtime" ]; then
|
|||
|
excludes="${excludes} --exclude=/etc/localtime"
|
|||
|
fi
|
|||
|
if [ -e "${rootpath}/usr/share/zoneinfo" ]; then
|
|||
|
excludes="${excludes} --exclude=/usr/share/zoneinfo"
|
|||
|
fi
|
|||
|
if [ -e "${rootpath}/etc/default/locale" ]; then
|
|||
|
excludes="${excludes} --exclude=/etc/default/locale"
|
|||
|
fi
|
|||
|
if [ -e "${rootpath}/usr/share/i18n" ]; then
|
|||
|
excludes="${excludes} --exclude=/usr/share/i18n"
|
|||
|
fi
|
|||
|
fi
|
|||
|
fi
|
|||
|
# 兼容以前的老备份数据,后面可以尝试去掉此条件的逻辑
|
|||
|
if [ ! -e "${restoreDir}/data/etc/uid_list" ]; then
|
|||
|
excludes="${excludes} --exclude=/etc/uid_list"
|
|||
|
fi
|
|||
|
if [ ! -e "${restoreDir}/data/boot/efi" ]; then
|
|||
|
excludes="${excludes} --exclude=/boot/efi"
|
|||
|
fi
|
|||
|
excludes="${excludes} --exclude=/var/log"
|
|||
|
excludes="${excludes} --exclude=*/backup/snapshots"
|
|||
|
#yi jian huan yuan
|
|||
|
if [ ! -e "${restoreDir}/data/data" ]; then
|
|||
|
#这两行要一致
|
|||
|
echo "rsync -avAXHr --no-inc-recursive --ignore-missing-args --delete --exclude=/data ${excludes} --exclude-from $restoreDir/$PERSONAL_EXCLUDEFILE $restoreDir/data/ $rootpath" >>$PLOGFILE
|
|||
|
rsync -avAXHr --no-inc-recursive --ignore-missing-args --delete --exclude=/data ${excludes} --exclude-from $restoreDir/$PERSONAL_EXCLUDEFILE $restoreDir/data/ $rootpath >/dev/null 2>>$PLOGFILE
|
|||
|
else
|
|||
|
#这两行要一致
|
|||
|
echo "rsync -avAXHr --no-inc-recursive --ignore-missing-args --delete ${excludes} --exclude-from $restoreDir/$PERSONAL_EXCLUDEFILE $restoreDir/data/ $rootpath" >>$PLOGFILE
|
|||
|
rsync -avAXHr --no-inc-recursive --ignore-missing-args --delete ${excludes} --exclude-from $restoreDir/$PERSONAL_EXCLUDEFILE $restoreDir/data/ $rootpath >/dev/null 2>>$PLOGFILE
|
|||
|
fi
|
|||
|
|
|||
|
if [ $? -ne 0 -a $? -ne 24 -a $? -ne 23 ]; then
|
|||
|
echo "System restoring failed, please reboot your system!"
|
|||
|
echo "System restoring failed, please reboot your system!" >>$PLOGFILE
|
|||
|
exit 9
|
|||
|
fi
|
|||
|
|
|||
|
echo "restore other directories end"
|
|||
|
echo "restore other directories end" >>$PLOGFILE
|
|||
|
sync
|
|||
|
#还原时清空目录
|
|||
|
#if [ -e "$rootpath/home/data" ]; then
|
|||
|
# rm -r "$rootpath/home/data" ]
|
|||
|
#fi
|
|||
|
#mkdir -p "$rootpath/home/data" ]
|
|||
|
}
|
|||
|
|
|||
|
#-----------------------------------------------------------------
|
|||
|
#see backup-auto/autobackup.cpp
|
|||
|
updateBackupAutoFinishedState() {
|
|||
|
echo "this is updateBackupAutoFinishedState"
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#-----------------------------------------------------------------
|
|||
|
#--------主程序从这里开始-----------------------------------------
|
|||
|
|
|||
|
if [ "${rootpath}" = "/" ]; then
|
|||
|
echo "This program is used in boot time"
|
|||
|
# exit
|
|||
|
fi
|
|||
|
|
|||
|
getBackupInfo
|
|||
|
#echo "m_restoreUuid="$m_restoreUuid
|
|||
|
#echo "m_enabled="$m_enabled
|
|||
|
#不加引号报错
|
|||
|
if [ "$m_restoreUuid" = "" ] || [ "$m_enabled" = "" ]; then
|
|||
|
echo "bootinfo file is not correct!"
|
|||
|
exit 3
|
|||
|
fi
|
|||
|
|
|||
|
if [ $backupORrestore = "--autobackup" ]; then
|
|||
|
mountBackup
|
|||
|
mount >>$PLOGFILE
|
|||
|
backupAuto #备份, grub时只有全盘备份,没有增量备份
|
|||
|
updateBackupAutoFinishedState
|
|||
|
#umountBackup
|
|||
|
|
|||
|
echo "This is autobackup"
|
|||
|
|
|||
|
elif [ $backupORrestore = "--autorestore" ]; then
|
|||
|
mountBackup
|
|||
|
mount >>$PLOGFILE
|
|||
|
restoreAuto #还原, grub时只有一键还原,没有增量还原
|
|||
|
#umountBackup
|
|||
|
echo "This is autorestore"
|
|||
|
|
|||
|
elif [ $backupORrestore = "--factorybackup" ]; then
|
|||
|
m_isFactory=true
|
|||
|
mountBackup
|
|||
|
backupAuto #备份, grub时只有全盘备份,没有增量备份
|
|||
|
updateBackupAutoFinishedState
|
|||
|
#umountBackup
|
|||
|
elif [ $backupORrestore = "--restoreretainuserdata" ]; then
|
|||
|
m_isRetainUserData=true
|
|||
|
mountBackup
|
|||
|
mount >>$PLOGFILE
|
|||
|
restoreAuto
|
|||
|
elif [ $backupORrestore = "--factoryrestore" ]; then
|
|||
|
m_isFactory=true
|
|||
|
mountBackup
|
|||
|
mount >>$PLOGFILE
|
|||
|
restoreAuto #还原, grub时只有一键还原,没有增量还原
|
|||
|
#umountBackup
|
|||
|
|
|||
|
echo "This is factorybackup"
|
|||
|
else
|
|||
|
echo "Not correct command"
|
|||
|
exit 18
|
|||
|
fi
|
|||
|
|
|||
|
sync
|
|||
|
|
|||
|
exit 0
|