yhkylin-backup-tools/backup-daemon/customizesystemrestoreproxy...

316 lines
9.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "customizesystemrestoreproxy.h"
#include <QDateTime>
#include <QDir>
#include <QDebug>
#include <unistd.h>
#include <sys/reboot.h>
#include "../common/utils.h"
#include "mymountproxy.h"
IMPLEMENT_DYNCREATE(CustomizeSystemRestoreProxy)
/**
* @brief 构造函数
*/
CustomizeSystemRestoreProxy::CustomizeSystemRestoreProxy()
{
m_bSuccess = false;
m_p = nullptr;
}
/**
* @brief 析构函数
*/
CustomizeSystemRestoreProxy::~CustomizeSystemRestoreProxy()
{
delete m_p;
}
/**
* @brief 环境检测
* @return false,检测失败;true,检测成功
*/
bool CustomizeSystemRestoreProxy::checkEnvEx()
{
qDebug() << "CustomizeSystemRestoreProxy::checkEnvEx invoke begin";
// 1、检测xml中的还原点是否还存在
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
xmlPath.replace("//", "/");
ParseBackupList parse(xmlPath);
m_backupPoint = parse.findBackupPointByUuid(m_backupWrapper.m_uuid);
if (m_backupPoint.m_uuid.isEmpty()) {
qCritical("xml中还原点不存在");
emit checkResult(int(BackupResult::INC_NOT_FOUND_DIR));
return false;
}
// 2、检测.user.txt是否存在
m_userFile = m_backupPoint.m_path + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/" + PATHS_USER_FILE;
m_userFile.replace("//", "/");
if (!Utils::filsExists(m_userFile)) {
qCritical(".user.txt文件不存在");
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
return false;
}
// 3、检测.exclude.user.txt是否存在
m_excludeUserFile = m_backupPoint.m_path + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/" + EXCLUDE_PATHS_USER_FILE;
m_excludeUserFile.replace("//", "/");
if (!Utils::filsExists(m_excludeUserFile)) {
qCritical(".exclude.user.txt文件不存在");
emit checkResult(int(BackupResult::WRITE_EXCLUDE_BACKUP_PATHS_TO_USER_FAILED));
return false;
}
// 4、检测还原点是否存在
m_backupPath = m_backupPoint.m_path + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
m_backupPath.replace("//", "/");
if (Utils::isDirEmpty(m_backupPath)) {
qCritical("还原点{uuid}/data目录不存在");
emit checkResult(int(BackupResult::INC_NOT_FOUND_DIR));
return false;
}
m_imgFileName = m_backupPath + "/" + UDISK_MKSQUASHFS_IMG_NAME;
if (!Utils::filsExists(m_imgFileName)) {
qCritical("还原点{uuid}/data/dst.img文件不存在");
emit checkResult(int(BackupResult::INC_NOT_FOUND_DIR));
return false;
}
m_curUuid = m_backupWrapper.m_uuid;
emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS));
qDebug() << "CustomizeSystemRestoreProxy::checkEnvEx invoke end";
return true;
}
/**
* @brief 执行还原逻辑
*/
void CustomizeSystemRestoreProxy::doWorkEx()
{
qDebug() << "CustomizeSystemRestoreProxy::doWorkEx invoke begin";
// 1、校验
if (!checkEnvEx())
return ;
// 2、还原系统
restoreSystem();
qDebug() << "CustomizeSystemRestoreProxy::doWorkEx invoke end";
}
/**
* @brief 备份准备
* @return true,准备成功false准备失败
*/
bool CustomizeSystemRestoreProxy::doPrepare()
{
qDebug() << "CustomizeSystemRestoreProxy::doPrepare invoke begin";
// 1、dst.img文件需要挂载到目录
if (!mountImg())
return false;
// 2、停止安全防护
QProcess::execute("systemctl stop kysec-init.service");
// 3、以读写方式重新挂载boot分区因为有的机器默认以只读挂载
remountBoot();
// 4、是否有/boot/efi目录有则认为有efi分区需重新rw挂载
QString efiPath = Utils::getSysRootPath() + "/boot/efi";
efiPath.replace("//", "/");
if (!Utils::isDirEmpty(efiPath)) {
// 重新rw读写挂载
remountEfi();
}
qDebug() << "CustomizeSystemRestoreProxy::doPrepare invoke end";
return true;
}
/**
* @brief 将dst.img文件挂载到/backup/imgbackup目录
* @return
*/
bool CustomizeSystemRestoreProxy::mountImg()
{
// 自定义路径系统备份需要先将dst.img文件挂载到/backup/imgbackup目录
// 1、检测目录/backup/imgbackup是否存在不存在则创建此目录
QString dstImgMountPath = Utils::getSysRootPath() + BACKUP_IMGBACKUP_PATH;
dstImgMountPath.replace("//", "/");
Utils::mkpath(dstImgMountPath);
// 2、先卸载/backup/imgbackup上的mount
MountBackupProcess *processMount = new MountBackupProcess(this);
processMount->umount(dstImgMountPath);
// 3、将img文件挂载到/backup/imgbackup上
if (!processMount->mount(m_imgFileName, dstImgMountPath)) {
emit checkResult(int(BackupResult::RESTOREDIR_PREPARE_FAILED));
return false;
}
m_srcPath = dstImgMountPath;
return true;
}
/**
* @brief 重新rw读写挂载efi分区
*/
void CustomizeSystemRestoreProxy::remountEfi()
{
QString mountPath = Utils::getSysRootPath() + "/boot/efi";
mountPath.replace("//", "/");
QStringList args;
args << "-o"
<< "rw,remount"
<< mountPath;
QProcess::execute("mount", args);
}
/**
* @brief 重新rw读写挂载boot分区
*/
void CustomizeSystemRestoreProxy::remountBoot()
{
QString mountPath = Utils::getSysRootPath() + "/boot";
mountPath.replace("//", "/");
QStringList args;
args << "-o"
<< "rw,remount"
<< mountPath;
QProcess::execute("mount", args);
}
/**
* @brief 根据场景获取rsync命令参数
* @param scene场景
* @return 组装好的rsync的参数信息
*/
QStringList CustomizeSystemRestoreProxy::getRsyncArgs(CustomizeSystemRestoreScene scene)
{
QStringList args;
args << "-avAHXr";
args << "--info=progress2";
args << "--no-inc-recursive";
args << "--ignore-missing-args";
args << "--delete";
QStringList excludes;
// 自定义备份的路径也需要跳过,不进行还原
Utils::excludeCustomizePath(excludes);
switch (scene) {
case CustomizeSystemRestoreScene::RESTORE_SYSTEM_WITH_DATA :
args << "--exclude=/home";
args << "--exclude=/root";
if (Utils::isHuawei990()) {
args << "--exclude=/data";
} else {
args << "--exclude=/data/usershare";
}
// 保留指纹数据,用户密码、角色、权限、生物识别等信息不需要改变
args << "--exclude=/var/lib/biometric-auth";
args << "--exclude=/data/sec_storage_data";
args << "--exclude=/etc/passwd";
args << "--exclude=/etc/shadow";
args << "--exclude=/etc/group";
args << "--exclude=/etc/gshadow";
args << "--exclude=/etc/sudoers";
args << "--exclude=/data/home";
args << "--exclude=/data/root";
// 云桌面背景路径属于用户数据
args << "--exclude=/var/lib/AccountsService";
// 此处不要break因为还需要排除SYSTEM_RESTORE中的项
case CustomizeSystemRestoreScene::SYSTEM_RESTORE :
// 还原工具不还原自身
args << "--exclude=/usr/bin/backup-daemon";
args << "--exclude=/usr/bin/kybackup";
args << "--exclude=/usr/bin/mount_fstab_efi";
args << "--exclude=/usr/bin/backup-auto-efi";
args << "--exclude=/usr/bin/backup-auto";
args << "--exclude=/usr/bin/rsync";
args << "--exclude=/usr/share/rsync";
args << "--exclude=/usr/share/initramfs-tools/hooks/kybackup-hooks";
args << "--exclude=/usr/share/initramfs-tools/scripts/local-bottom/kybackup";
for (const QString& item : excludes) {
args << QString("--exclude=") + item;
}
args << "--exclude-from" << m_excludeUserFile;
args << "--files-from" << m_userFile;
break ;
default:
return args;
}
return args;
}
/**
* @brief 系统还原
*/
void CustomizeSystemRestoreProxy::restoreSystem()
{
// 还原前准备
doPrepare();
QString destPath = Utils::getSysRootPath();
QStringList args;
// 保留用户数据还原
if ( m_backupWrapper.m_type == BackupType::RESTORE_SYSTEM_WITH_DATA) {
args = getRsyncArgs(CustomizeSystemRestoreScene::RESTORE_SYSTEM_WITH_DATA);
} else {
args = getRsyncArgs(CustomizeSystemRestoreScene::SYSTEM_RESTORE);
}
args << m_srcPath + "/";
destPath += "/";
destPath.replace("//", "/");
args << destPath;
m_p = new RsyncPathToDirProcess(this);
connect(m_p, &RsyncPathToDirProcess::progress, this, &CustomizeSystemRestoreProxy::progress);
connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool result) {
if (result) {
QString time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
// Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ",,," + QString::number(m_backupWrapper.m_frontUid));
Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ",,,," + m_backupPoint.m_backupName);
Utils::updateSyncFile();
QString fileIfSync = Utils::getSysRootPath() + FILE_IF_SYNC;
fileIfSync.replace("//", "/");
QFileInfo file(fileIfSync);
QDateTime beginTime = file.fileTime(QFileDevice::FileModificationTime);
Utils::wait(10);
Utils::updateSyncFile();
while (1) {
Utils::wait(2);
QFileInfo file1(fileIfSync);
QDateTime UpdateTime = file1.fileTime(QFileDevice::FileModificationTime);
if (UpdateTime > beginTime)
break;
}
emit this->workResult(result);
Utils::wait(2);
reboot(RB_AUTOBOOT);
}
emit this->workResult(result);
});
m_p->start(args, false);
}