#!/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 "" >$m_backuplistPath #echo "" >>$m_backuplistPath #echo "" >>$m_backuplistPath echo "" >>$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" =~ "" ]]; then if [ $xxx = "${m_comment}" ]; then foundComment=1 #当前comment是要修改的mycomment else foundComment=0 #当前comment不是要修改的mycomment fi fi if [[ "$xxx" =~ "" ]]; then if [[ $foundComment -eq 1 ]]; then line=" ${newSize}" fi fi if [[ "$xxx" =~ "" ]]; then if [ $foundComment -eq 1 ]; then line=" ${m_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" =~ "" ]]; then comment0=`echo $xxx | awk -F "" '{print $2}' |awk -F "" '{print $1}' | tr -d "\n"` fi if [[ "$xxx" =~ "" ]]; then if [ $xxx = "${local_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" =~ "" ]]; then backupPointTmp=$i fi if [[ "$xxx" =~ "" ]]; then if [ $xxx = "$local_comment" ]; then foundComment=1 #当前comment是要修改的mycomment ii=$backupPointTmp #echo "delete foundComment = 1" else foundComment=0 #当前comment不是要修改的mycomment fi fi if [[ "$xxx" =~ "" ]]; 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 #有头吗"" #如果不定义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" =~ "" ]]; then hasHead=true fi if [[ "$xxx" =~ "" ]]; then xxx="" #与图形界面一致 line="" fi #插入新的记录 if [ $xxx = "" ]; then if [ "$hasHead" = false ]; then echo "" >>$tmpFile hasHead=true fi echo " " >>$tmpFile echo " $m_comment" >>$tmpFile echo " " >>$tmpFile echo " $m_uuid" >>$tmpFile echo " $newSize" >>$tmpFile echo " $state" >>$tmpFile echo " 0" >>$tmpFile echo " " >>$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" =~ "" ]]; then lastbackupname=$xxx fi if [[ "$xxx" =~ "" ]]; then currentUuid=$xxx currentState=false currentType=true fi if [[ "$xxx" =~ "backup finished" ]]; then #lastUsefulBackupPointUuid=$currentUuid currentState=true fi if [[ "$xxx" =~ "2" ]]; then currentType=false fi if [[ "$xxx" =~ "3" ]]; then currentType=false fi if [[ "$xxx" =~ "3" ]]; then currentType=false fi if [[ "$xxx" =~ "" ]]; 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:::' | tr -d "\n") lastUsefulBackupPointUuid=$(echo $lastUsefulBackupPointUuid | sed 's:.*::' | tr -d "\n") #echo "lastUsefulBackupPointUuid=$lastUsefulBackupPointUuid" lastbackupname=$(echo $lastbackupname | sed 's:::' | tr -d "\n") lastbackupname=$(echo $lastbackupname | sed 's:.*::' | 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