阶段提交

This commit is contained in:
zhaominyong 2021-12-11 09:49:09 +08:00
parent c2ba01b07e
commit c1e7f440bd
14 changed files with 1019 additions and 86 deletions

View File

@ -43,6 +43,7 @@ HEADERS += \
systembackupproxy.h \
systemrestoreproxy.h \
udisksystembackupproxy.h \
udisksystemrestoreproxy.h \
workerfactory.h
SOURCES += \
@ -65,6 +66,7 @@ SOURCES += \
systembackupproxy.cpp \
systemrestoreproxy.cpp \
udisksystembackupproxy.cpp \
udisksystemrestoreproxy.cpp \
workerfactory.cpp
# Default rules for deployment.

View File

@ -4,24 +4,6 @@
#include "../common/mydefine.h"
#include "backupmanager_adaptor.h"
// test begin
#include <QDebug>
#include "../common/reflect.h"
#include "mymountproxy.h"
#include "parsebackuplist.h"
void testXml()
{
ParseBackupList parse("/backup/snapshots/backuplist.xml");
}
void testLog()
{
Utils::getBackupLogList();
}
// test end
int main(int argc, char *argv[])
{
// 以防客户端传入的参数中的中文信息乱码
@ -37,24 +19,6 @@ int main(int argc, char *argv[])
qInstallMessageHandler(Utils::customMessageHandler);
Utils::initSystemInfo();
// test begin
qDebug() << QString("测试 begin");
// MyMountProxy * proxy = (MyMountProxy*)Reflect::createObject("MyMountProxy");
// proxy->mountBackupPartition();
// BackupWrapper backupWrapper;
// backupWrapper.m_backupName = "赵民勇test";
// backupWrapper.m_backupPaths << "/";
// backupWrapper.m_backupExcludePaths = Utils::getFromExcludePathsFile();
// MyBackupManager manager;
// manager.goBackup(backupWrapper);
testLog();
qDebug() << QString("测试 end");
// test end
MyBackupManager* backup_deamon = new MyBackupManager;
new ManagerAdaptor(backup_deamon);
QDBusConnection conn = QDBusConnection::systemBus();

View File

@ -35,12 +35,12 @@ bool MountBackupProcess::Do(const QString& diskUuid)
m_p->start("mount", arguments);
if (!m_p->waitForStarted()) {
qFatal("mount rw /backup process start failed!");
qCritical("mount rw /backup process start failed!");
return false;
}
if (!m_p->waitForFinished()) {
qFatal("mount rw backup process end failed!");
qCritical("mount rw backup process end failed!");
return false;
}
@ -53,12 +53,55 @@ bool MountBackupProcess::umountBackupPartition()
arguments << QString("/backup");
m_p->start("umount", arguments);
if (!m_p->waitForStarted()) {
qFatal("mount ro backup process start failed!");
qCritical("mount ro backup process start failed!");
return false;
}
if (!m_p->waitForFinished()) {
qFatal("mount ro backup process end failed!");
qCritical("mount ro backup process end failed!");
return false;
}
return true;
}
/**
* @brief
* @param mountPath
* @return
*/
bool MountBackupProcess::umount(const QString& mountPath)
{
if (0 == ::umount(mountPath.toUtf8().data()))
return true;
qCritical() << QString("%1 umount failed, error is %2(%3)").arg(mountPath).arg(strerror(errno)).arg(QString::number(errno));
return false;
}
/**
* @brief
* @param source
* @param target
* @return
*/
bool MountBackupProcess::mount(const QString& source, const QString& target, const QString& options)
{
QStringList arguments;
if (!options.isEmpty())
arguments << options;
arguments << source;
arguments << target;
m_p->start("mount", arguments);
if (!m_p->waitForStarted()) {
qCritical("mount process start failed!");
return false;
}
if (!m_p->waitForFinished()) {
qCritical("mount process end failed!");
return false;
}

View File

@ -2,6 +2,7 @@
#define MOUNTBACKUPPROCESS_H
#include <QProcess>
#include <sys/mount.h>
class MountBackupProcess : public QObject {
Q_OBJECT
@ -12,6 +13,9 @@ public:
bool umountBackupPartition();
static bool umount(const QString& mountPath);
bool mount(const QString& source, const QString& target, const QString& options = "");
private:
QProcess* m_p;

View File

@ -146,6 +146,20 @@ void SystemRestoreProxy::remountEfi()
QProcess::execute("mount", args);
}
/**
* @brief rw读写挂载boot分区
*/
void SystemRestoreProxy::remountBoot()
{
QString mountPath = Utils::getSysRootPath() + "/boot";
mountPath.replace("//", "/");
QStringList args;
args << "-o"
<< "rw,remount"
<< mountPath;
QProcess::execute("mount", args);
}
/**
* @brief efi
*/
@ -292,6 +306,9 @@ void SystemRestoreProxy::restoreSystem()
m_srcPath = m_backupPath;
QString destPath = Utils::getSysRootPath();
// 以读写方式重新挂载boot分区因为有的机器默认以只读挂载
remountBoot();
QStringList args;
// 自动更新的备份还原时保留用户数据
if (m_curUuid == AUTO_BACKUP_UUID || m_backupWrapper.m_type == BackupType::RESTORE_SYSTEM_WITH_DATA) {
@ -316,7 +333,7 @@ void SystemRestoreProxy::restoreSystem()
QFileInfo file(fileIfSync);
QDateTime beginTime = file.fileTime(QFileDevice::FileModificationTime);
if (Utils::isHuawei990() && FACTORY_BACKUP_UUID == m_curUuid && m_backupWrapper.m_type == BackupType::RESTORE_SYSTEM) {
// 出厂还原有的机器上删除/home/xxx有残留故在此再强制删除一下妈的sudo rm -rf命令一遍还删除不了报错无法删除/home/xx/.config:目录非空,应该是删除后又自动生成了),多删除几次还不是非常干净,^_^
// 出厂还原有的机器上删除/home/xxx有残留故在此再强制删除一下sudo rm -rf命令一遍还删除不了报错无法删除/home/xx/.config:目录非空,应该是删除后又自动生成了),多删除几次还不是非常干净,^_^
removeHome(Utils::getSysRootPath() + "/home");
removeHome(Utils::getSysRootPath() + "/data/home");
}

View File

@ -34,6 +34,8 @@ private:
void repairEfi();
// 以读写方式重新挂载efi分区
void remountEfi();
// 以读写方式重新挂载boot分区
void remountBoot();
// 同步efi
bool rsyncEfi();
// 系统还原

View File

@ -0,0 +1,418 @@
#include "udisksystemrestoreproxy.h"
#include <QDateTime>
#include <QDir>
#include <QDebug>
#include <QTimer>
#include <unistd.h>
#include <sys/reboot.h>
#include "../common/utils.h"
#include "mymountproxy.h"
#include "myprocess/mksquashfsprocess.h"
IMPLEMENT_DYNCREATE(UDiskSystemRestoreProxy)
/**
* @brief
*/
UDiskSystemRestoreProxy::UDiskSystemRestoreProxy()
{
m_isFinished = false;
m_p = nullptr;
}
/**
* @brief
*/
UDiskSystemRestoreProxy::~UDiskSystemRestoreProxy()
{
delete m_p;
}
/**
* @brief
* @return false,;true,
*/
bool UDiskSystemRestoreProxy::checkEnvEx()
{
qDebug() << "UDiskSystemRestoreProxy::checkEnvEx invoke begin";
// 1、检测.user.txt是否存在
m_userFile = m_backupWrapper.m_prefixDestPath + 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;
}
// 2、检测.exclude.user.txt是否存在
m_excludeUserFile = m_backupWrapper.m_prefixDestPath + 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;
}
// 3、检测还原点是否存在
m_backupPath = m_backupWrapper.m_prefixDestPath + 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;
}
qDebug() << "UDiskSystemRestoreProxy::checkEnvEx invoke end";
return true;
}
/**
* @brief
*/
void UDiskSystemRestoreProxy::doWorkEx()
{
qDebug() << "UDiskSystemRestoreProxy::doWorkEx invoke begin";
// 1、校验
if (!checkEnvEx())
return ;
// 2、还原efi(兼容旧版本的备份)
if (!restoreEfi()) {
qCritical("/boot/efi目录同步失败");
emit checkResult(int(BackupResult::EFI_RSYNC_FAIL));
return ;
}
// 3、还原系统
if (doPrepare())
restoreSystem();
qDebug() << "UDiskSystemRestoreProxy::doWorkEx invoke end";
}
/**
* @brief efi()
* @return
*/
bool UDiskSystemRestoreProxy::restoreEfi()
{
qDebug() << "UDiskSystemRestoreProxy::restoreEfi invoke begin";
// 是否有/boot/efi目录
QString efiPath = Utils::getSysRootPath() + "/boot/efi";
efiPath.replace("//", "/");
if (!Utils::isDirEmpty(efiPath)) {
// 1、修复源数据
repairEfi();
// 2、重新rw读写挂载
remountEfi();
// 3、同步efi
return rsyncEfi();
}
qDebug() << "UDiskSystemRestoreProxy::restoreEfi invoke end";
return true;
}
/**
* @brief efi目录
*/
void UDiskSystemRestoreProxy::repairEfi()
{
QString qsEfiPath = m_backupPath + "/efi";
if (!Utils::isDirEmpty(qsEfiPath)) {
// 存在/efi说明是老备份数据尽量修正老数据
QStringList args;
args << "-f";
args << qsEfiPath;
QString newPath = m_backupPath + "/boot";
args << newPath;
QProcess::execute("mv", args);
}
}
/**
* @brief rw读写挂载efi分区
*/
void UDiskSystemRestoreProxy::remountEfi()
{
QString mountPath = Utils::getSysRootPath() + "/boot/efi";
mountPath.replace("//", "/");
QStringList args;
args << "-o"
<< "rw,remount"
<< mountPath;
QProcess::execute("mount", args);
}
/**
* @brief rw读写挂载boot分区
*/
void UDiskSystemRestoreProxy::remountBoot()
{
QString mountPath = Utils::getSysRootPath() + "/boot";
mountPath.replace("//", "/");
QStringList args;
args << "-o"
<< "rw,remount"
<< mountPath;
QProcess::execute("mount", args);
}
/**
* @brief efi
*/
bool UDiskSystemRestoreProxy::rsyncEfi()
{
QString efiPath = m_backupPath + "/boot/efi/";
if (Utils::isDirEmpty(efiPath))
efiPath = efiPath = m_backupPath + "/efi/";
if (Utils::isDirEmpty(efiPath))
return true;
QStringList args = getRsyncArgs(SystemRestoreScene::EFI_RESTORE);
QString mountPath = Utils::getSysRootPath() + "/boot/efi/";
mountPath.replace("//", "/");
args << efiPath << mountPath;
m_p = new RsyncPathToDirProcess(this);
bool result = m_p->start(args);
delete m_p;
m_p = nullptr;
return result;
}
/**
* @brief rsync命令参数
* @param scene
* @return rsync的参数信息
*/
QStringList UDiskSystemRestoreProxy::getRsyncArgs(SystemRestoreScene scene)
{
QStringList args;
args << "-avAHXr";
args << "--info=progress2";
args << "--no-inc-recursive";
args << "--ignore-missing-args";
args << "--delete";
QDir dataDir(m_srcPath + "/data");
QFile file(m_srcPath + "/etc/uid_list");
QDir efiDir(m_srcPath + "/boot/efi");
QStringList excludes;
switch (scene) {
case SystemRestoreScene::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";
// 以前的出厂备份和grub备份没有备份/data还原时需要判断/data是否存在如不存在需要屏蔽掉不然会将主机上的/data删除造成问题
// 此为兼容以前备份的老数据而改,等以后老的备份估计不存在了可已去掉
if (!dataDir.exists()) {
args << "--exclude=/data";
}
if (!file.exists()) {
args << "--exclude=/etc/uid_list";
}
// 为兼容以前的老备份数据,增加下面几行
if (efiDir.isEmpty()) {
args << QString("--exclude=/boot/efi");
}
// 系统安装后有的会将/data/home /data/root挂载到的/home /root上实际文件是存放在/data/home /data/root下面
Utils::excludeFstabBindPath(excludes);
for (const QString& item : excludes) {
QDir itemDir(m_srcPath + item);
// 以后统一用/home /root这种路径 兼容老备份数据原来的U盘备份在mksquashfs时排除bind挂载的任意一方时都备份不上
if (item == "/data/home") {
QDir homeDir(m_srcPath + "/home");
if (!homeDir.isEmpty()) {
args << QString("--exclude=/data/home");
} else if (!itemDir.isEmpty()) {
args << QString("--exclude=/home");
} else {
args << QString("--exclude=/data/home");
args << QString("--exclude=/home");
}
continue;
} else if (item == "/data/root") {
QDir homeDir(m_srcPath + "/root");
if (!homeDir.isEmpty()) {
args << QString("--exclude=/data/root");
} else if (!itemDir.isEmpty()) {
args << QString("--exclude=/root");
} else {
args << QString("--exclude=/data/root");
args << QString("--exclude=/root");
}
continue;
}
args << QString("--exclude=") + item;
}
args << "--exclude-from" << m_excludeUserFile;
args << "--files-from" << m_userFile;
break ;
case SystemRestoreScene::EFI_RESTORE :
break ;
default:
return args;
}
return args;
}
/**
* @brief
* @return
*/
bool UDiskSystemRestoreProxy::doPrepare()
{
// 移动设备系统备份如果有img则需要先将img挂载到/backup/imgbackup目录
QString imgPath = m_backupPath + UDISK_MKSQUASHFS_IMG_NAME;
if (Utils::filsExists(imgPath)) {
// 1、检测目录/backup/imgbackup是否存在不存在则创建此目录
QString dstImgMountPath = Utils::getSysRootPath() + BACKUP_IMGBACKUP_PATH;
dstImgMountPath.replace("//", "/");
Utils::mkpath(dstImgMountPath);
// 2、先卸载/backup/imgbackup上的mount
MountBackupProcess::umount(dstImgMountPath);
// 3、将img文件挂载到/backup/imgbackup上
MountBackupProcess *processMount = new MountBackupProcess;
if (processMount->mount(imgPath, dstImgMountPath)) {
emit checkResult(int(BackupResult::RESTOREDIR_PREPARE_FAILED));
return false;
}
m_srcPath = dstImgMountPath;
} else
m_srcPath = m_backupPath;
// 以读写方式重新挂载boot分区因为有的机器默认以只读挂载
remountBoot();
return true;
}
/**
* @brief
*/
void UDiskSystemRestoreProxy::restoreSystem()
{
QString destPath = Utils::getSysRootPath();
QStringList args = getRsyncArgs(SystemRestoreScene::SYSTEM_RESTORE);
args << m_srcPath + "/";
args << destPath + "/";
m_p = new RsyncPathToDirProcess(this);
connect(m_p, &RsyncPathToDirProcess::progress, this, &UDiskSystemRestoreProxy::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::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;
}
if (m_backupWrapper.m_isOtherMachine) {
Utils::wait(20);
updateGrubUUid();
sync();
Utils::wait(5);
}
emit this->workResult(result);
Utils::wait(2);
reboot(RB_AUTOBOOT);
}
if (Utils::isDirEmpty(m_backupPath))
result = false;
emit this->workResult(result);
m_isFinished = true;
});
QTimer::singleShot(1*1000, this, &UDiskSystemRestoreProxy::checkUdiskExists);
m_isFinished = false;
m_p->start(args, false);
}
/**
* @brief grub.cfg中的分区UUID
*/
void UDiskSystemRestoreProxy::updateGrubUUid()
{
QString srcFstab = Utils::getSysRootPath() + BACKUP_IMGBACKUP_PATH;
srcFstab += FSTAB_PATH;
srcFstab.replace("//", "/");
QHash<QString, QString> srcPartToUuid = Utils::getPartUuidMap(srcFstab);
QString destFstab = Utils::getSysRootPath() + FSTAB_PATH;
QHash<QString, QString> destPartToUuid = Utils::getPartUuidMap(destFstab);
QString findGrub = Utils::executeCmd("find /boot -name grub.cfg");
QStringList grubs = findGrub.split("\n");
for (const QString &grub : grubs) {
if (grub.isEmpty())
continue;
QString root = QString("sed -i 's/%1/%2/g' %3").arg(srcPartToUuid.value("/")).arg(destPartToUuid.value("/")).arg(grub);
qDebug() << Utils::executeCmd(root);
QString boot = QString("sed -i 's/%1/%2/g' %3").arg(srcPartToUuid.value("/boot")).arg(destPartToUuid.value("/boot")).arg(grub);
qDebug() << Utils::executeCmd(boot);
QString swap = QString("sed -i 's/%1/%2/g' %3").arg(srcPartToUuid.value("swap")).arg(destPartToUuid.value("swap")).arg(grub);
qDebug() << Utils::executeCmd(swap);
}
}
/**
* @brief
* @return true-false-
*/
bool UDiskSystemRestoreProxy::checkUdiskExists()
{
if (!m_isFinished) {
if (Utils::isDirEmpty(m_backupPath) && m_p != nullptr)
m_p->stop();
else
QTimer::singleShot(1*1000, this, &UDiskSystemRestoreProxy::checkUdiskExists);
}
return true;
}

View File

@ -0,0 +1,76 @@
#ifndef UDISKSYSTEMRESTOREPROXY_H
#define UDISKSYSTEMRESTOREPROXY_H
#include "workerfactory.h"
#include "myprocess/rsyncpathtodirprocess.h"
#include "parsebackuplist.h"
class UDiskSystemRestoreProxy : public Worker
{
Q_OBJECT
DECLARE_DYNCREATE(UDiskSystemRestoreProxy)
public:
// 系统还原的几种场景
enum SystemRestoreScene {
SYSTEM_RESTORE, // 系统还原
EFI_RESTORE, // efi还原
};
explicit UDiskSystemRestoreProxy();
virtual ~UDiskSystemRestoreProxy();
public:
// 环境检测
virtual bool checkEnvEx();
// 任务处理
virtual void doWorkEx();
private slots:
bool checkUdiskExists();
private:
// 还原efi
bool restoreEfi();
// 修复efi目录
void repairEfi();
// 以读写方式重新挂载efi分区
void remountEfi();
// 以读写方式重新挂载boot分区
void remountBoot();
// 同步efi
bool rsyncEfi();
// 系统还原
void restoreSystem();
// 还原前准备
bool doPrepare();
// 异机还原时更新grub.cfg中的分区UUID
void updateGrubUUid();
/**
* @brief rsync命令参数
* @param scene
* @return rsync的参数信息
*/
QStringList getRsyncArgs(SystemRestoreScene scene);
// .user.txt文件路径
QString m_userFile;
// .exclude.user.txt文件路径
QString m_excludeUserFile;
// 备份数据所在的data目录
QString m_backupPath;
// 是否还原结束
bool m_isFinished;
// 当前备份uuid
QString m_curUuid;
// 当前还原源目录
QString m_srcPath;
// 备份进程
RsyncPathToDirProcess *m_p;
// 当前备份节点
ParseBackupList::BackupPoint m_backupPoint;
};
#endif // UDISKSYSTEMRESTOREPROXY_H

View File

@ -8,7 +8,7 @@ QDBusArgument &operator<<(QDBusArgument &argument, const BackupWrapper &backupWr
argument << backupWrapper.m_type << backupWrapper.m_iPosition << backupWrapper.m_comment << backupWrapper.m_backupName
<< backupWrapper.m_uuid << backupWrapper.m_backupPaths << backupWrapper.m_backupExcludePaths << backupWrapper.m_prefixDestPath
<< backupWrapper.m_note << backupWrapper.m_frontUserName << backupWrapper.m_frontUid
<< backupWrapper.m_gid;
<< backupWrapper.m_gid << backupWrapper.m_isOtherMachine;
argument.endStructure();
return argument;
}
@ -20,7 +20,7 @@ const QDBusArgument &operator>>(const QDBusArgument &argument, BackupWrapper &ba
argument >> backupWrapper.m_type >> backupWrapper.m_iPosition >> backupWrapper.m_comment >> backupWrapper.m_backupName
>> backupWrapper.m_uuid >> backupWrapper.m_backupPaths >> backupWrapper.m_backupExcludePaths >> backupWrapper.m_prefixDestPath
>> backupWrapper.m_note >> backupWrapper.m_frontUserName >> backupWrapper.m_frontUid
>> backupWrapper.m_gid;
>> backupWrapper.m_gid >> backupWrapper.m_isOtherMachine;
argument.endStructure();
return argument;
}

View File

@ -31,8 +31,9 @@ void RingsProgressbar::paintEvent(QPaintEvent *)
p.setBrush(QBrush(QColor(COLOR_BLUE)));
//画圆弧
pen.setCapStyle(Qt::RoundCap);
p.setPen(pen);
// pen.setCapStyle(Qt::RoundCap);
// pen.setColor(QColor(COLOR_BLUE));
// p.setPen(pen);
p.drawPie(QRectF(5 , 5, side - 10, side - 10), (90-m_rotateAngle)*16, m_rotateAngle*16);
//画遮罩

View File

@ -96,7 +96,7 @@ void SelectRestorePoint::insertLines(const QList<ParseBackupList::BackupPoint> &
continue;
//hide factory backup
if (backupPoint.m_uuid == FACTORY_BACKUP_UUID)
if (backupPoint.m_uuid == FACTORY_BACKUP_UUID && Utils::isHuawei990())
continue;
//udisk unique

View File

@ -779,6 +779,7 @@ void SystemBackup::initFifthWidget()
labelTip->setGeometry(101, 261, 520, 30);
labelTip->setAlignment(Qt::AlignCenter);
labelTip->setFontWordWrap(true);
// 不要使用电脑,以防数据丢失
labelTip->setDeplayText(tr("Do not use computers in case of data loss"));
connect(this, &SystemBackup::backupWarnning, labelTip, [=](const QString& msg) {
labelTip->setDeplayText(msg);

View File

@ -31,6 +31,8 @@ SystemRestore::SystemRestore(QWidget *parent) :
// 界面手写代码创建,作为练手
initFirstWidget();
initSecondWidget();
initThirdWidget();
initLastWidget();
}
SystemRestore::~SystemRestore()
@ -184,12 +186,6 @@ void SystemRestore::on_next_clicked(bool checked)
*/
void SystemRestore::on_button_beginRestore_clicked(bool checked)
{
on_next_clicked();
emit this->startCheckEnv();
return;
// -------以上为测试代码-------
Q_UNUSED(checked)
// 出厂还原,不用去选择备份点
@ -221,7 +217,7 @@ void SystemRestore::on_button_beginRestore_clicked(bool checked)
}
/**
* @brief
* @brief --
*/
void SystemRestore::initSecondWidget()
{
@ -340,6 +336,7 @@ void SystemRestore::initSecondWidget()
nextStep->setAutoRepeat(true);
connect(nextStep, &MyPushButton::clicked, this, [=](bool checked) {
this->on_next_clicked(checked);
this->startRestore();
});
hlayoutCenterFont5->addWidget(nextStep);
// 重新检测按钮
@ -348,10 +345,6 @@ void SystemRestore::initSecondWidget()
recheck->setText(tr("recheck"));
recheck->setEnabled(true);
recheck->setAutoRepeat(true);
connect(recheck, &MyPushButton::clicked, this, [=](bool checked) {
Q_UNUSED(checked)
emit this->startCheckEnv();
});
hlayoutCenterFont5->addWidget(recheck);
hlayoutCenterFont5->addStretch();
vlayoutCenterFont->addLayout(hlayoutCenterFont5);
@ -449,6 +442,12 @@ void SystemRestore::initSecondWidget()
preStep->setVisible(true);
});
// 重新检查
connect(recheck, &MyPushButton::clicked, this, [=](bool checked) {
Q_UNUSED(checked)
emit this->startCheckEnv();
});
addWidget(second);
}
@ -501,35 +500,29 @@ void SystemRestore::on_checkEnv_end(int result)
// 没有找到相应的处理逻辑
errTip = tr("No processing logic was found in the service");
break;
case int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL):
// 备份分区挂载失败
errMsg = tr("Failed to mount the backup partition");
// 检查是否有备份分区
errTip = tr("Check whether there is a backup partition");
case int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED):
// ".user.txt文件不存在"
errMsg = tr(".user.txt file is not exists");
// 备份点可能被损坏
errTip = tr("Backup points may be corrupted");
break;
case int(BackupResult::UDISK_FILESYSTEM_TYPE_IS_VFAT):
// 移动设备的文件系统是vfat格式
errMsg = tr("The filesystem of device is vfat format");
// 请换成ext4、ntfs等格式
errTip = tr("Please change filesystem format to ext3、ext4 or ntfs");
case int(BackupResult::WRITE_EXCLUDE_BACKUP_PATHS_TO_USER_FAILED):
// .exclude.user.txt文件不存在
errMsg = tr(".exclude.user.txt file is not exists");
// 备份点可能被损坏
errTip = tr("Backup points may be corrupted");
break;
case int(BackupResult::UDISK_FILESYSTEM_IS_READONLY):
// 移动设备是只读的
errMsg = tr("The device is read only");
// 请修改为可读写权限的
errTip = tr("Please chmod to rw");
case int(BackupResult::INC_NOT_FOUND_DIR):
// 备份点数据目录不存在
errMsg = tr("The backup point data directory does not exist");
// 备份点可能被损坏
errTip = tr("Backup points may be corrupted");
break;
case int(BackupResult::BACKUP_CAPACITY_IS_NOT_ENOUGH):
// 备份空间不足
errMsg = tr("The storage for backup is not enough");
// 建议释放空间后重试
errTip = tr("Retry after release space");
break;
case int(BackupResult::OTHER_BACKUP_OR_RESTORE_RUNNING):
// 其它备份还原等操作正在执行
errMsg = tr("Other backup or restore task is being performed");
// 请稍后重试
errTip = tr("Please try again later");
case int(BackupResult::EFI_RSYNC_FAIL):
// 同步/boot/efi失败
errMsg = tr("Failed to rsync /boot/efi");
// 请检查/boot/efi分区挂载方式
errTip = tr("Check the mounting mode of the /boot/efi partition");
break;
default:
bRst = true;
@ -543,4 +536,408 @@ void SystemRestore::on_checkEnv_end(int result)
m_pInterface = nullptr;
}
/**
* @brief -
*/
void SystemRestore::initThirdWidget()
{
QWidget *third = new QWidget;
// 流程进度提示栏
CircleLable *one = new CircleLable("1", third, 24, QColor(COLOR_BLUE));
LineLabel *line1 = new LineLabel(third, QColor(COLOR_BLUE), QSize(200, 24));
CircleLable *two = new CircleLable("2", third, 24, QColor(COLOR_BLUE));
LineLabel *line2 = new LineLabel(third, QColor(COLOR_GRAY), QSize(200, 24));
CircleLable *three = new CircleLable("3", third);
QHBoxLayout *layoutLine1 = new QHBoxLayout;
layoutLine1->addStretch();
layoutLine1->addWidget(one);
layoutLine1->addWidget(line1);
layoutLine1->addWidget(two);
layoutLine1->addWidget(line2);
layoutLine1->addWidget(three);
layoutLine1->addStretch();
MyLabel *label1 = new MyLabel(tr("checking"), third);
label1->setIsOriginal(true);
label1->setFontColor(QColor(COLOR_BLUE));
MyLabel *label2 = new MyLabel(tr("restoring"), third);
label2->setIsOriginal(true);
label2->setFontColor(QColor(COLOR_BLUE));
MyLabel *label3 = new MyLabel(tr("finished"), third);
label3->setIsOriginal(true);
QHBoxLayout *layoutLine2 = new QHBoxLayout;
layoutLine2->addSpacing(100);
layoutLine2->addWidget(label1);
layoutLine2->addStretch();
layoutLine2->addWidget(label2);
layoutLine2->addStretch();
layoutLine2->addWidget(label3);
layoutLine2->addSpacing(100);
// ------------ 中部布局begin-------------
QWidget *centerFont = new QWidget(third);
QVBoxLayout *vlayoutCenterFont = new QVBoxLayout;
// 中部第一行
QHBoxLayout *hlayoutCenterFont1 = new QHBoxLayout;
// 检测等待图标
QLabel *loadingGif = new QLabel(centerFont);
// 环境检测等待动画
QMovie *movie = new QMovie(":/images/loading.gif", QByteArray(), centerFont);
loadingGif->setMovie(movie);
// 进度条
RingsProgressbar *progressBar = new RingsProgressbar(centerFont);
progressBar->setFixedSize(100, 100);
hlayoutCenterFont1->addStretch();
hlayoutCenterFont1->addWidget(loadingGif);
hlayoutCenterFont1->addWidget(progressBar);
hlayoutCenterFont1->addStretch();
// 第二行
QHBoxLayout *hlayoutCenterFont2 = new QHBoxLayout;
// 提醒
MyLabel *labelTip = new MyLabel(centerFont);
labelTip->setAlignment(Qt::AlignCenter);
labelTip->setIsOriginal(true);
labelTip->setFontWordWrap(true);
// 不要使用电脑,以防数据丢失
labelTip->setDeplayText(tr("Do not use computers in case of data loss"));
hlayoutCenterFont2->addStretch();
hlayoutCenterFont2->addWidget(labelTip);
hlayoutCenterFont2->addStretch();
vlayoutCenterFont->addLayout(hlayoutCenterFont1);
vlayoutCenterFont->addLayout(hlayoutCenterFont2);
vlayoutCenterFont->addStretch();
centerFont->setLayout(vlayoutCenterFont);
// ------------ 中部布局end-------------
QHBoxLayout *layoutLine3 = new QHBoxLayout;
layoutLine3->addStretch();
layoutLine3->addSpacing(80);
layoutLine3->addWidget(centerFont);
layoutLine3->addStretch();
// 布局
QVBoxLayout *vlayout = new QVBoxLayout;
vlayout->addSpacing(40);
vlayout->addLayout(layoutLine1);
vlayout->addLayout(layoutLine2);
vlayout->addSpacing(50);
vlayout->addLayout(layoutLine3);
vlayout->addStretch();
third->setLayout(vlayout);
// 开始备份
connect(this, &SystemRestore::startRestore, this, [=] {
progressBar->setPersent(20);
movie->start();
// 开始备份
this->on_restore_start();
});
// 进度
connect(this, &SystemRestore::progress, this, [=](int state, int rate) {
Q_UNUSED(state)
progressBar->setPersent(rate);
});
addWidget(third);
}
/**
* @brief
*/
void SystemRestore::on_restore_start()
{
GlobelBackupInfo::inst().setIsBusy(true);
m_systemRestoreState = SystemRestoreState::RESTORING;
m_pInterface = new ComKylinBackupManagerInterface("com.kylin.backup", "/", QDBusConnection::systemBus(), this);
connect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &SystemRestore::on_checkRestore_end);
connect(m_pInterface, &ComKylinBackupManagerInterface::progress, this, &SystemRestore::progress);
connect(m_pInterface, &ComKylinBackupManagerInterface::sendRestoreResult, this, &SystemRestore::on_restore_end);
// 是否已存在备份、还原等操作
bool isActive = false;
if(int(BackupState::BACKUP_STATE_INIT) != m_pInterface->getBackupState(isActive)){
on_checkEnv_end(int(BackupResult::OTHER_BACKUP_OR_RESTORE_RUNNING));
return;
}
BackupWrapper backupWrapper;
backupWrapper.m_type = m_isRetainUserData ? BackupType::RESTORE_SYSTEM_WITH_DATA : BackupType::RESTORE_SYSTEM;
backupWrapper.m_iPosition = m_devPath.isEmpty() ? BackupPosition::LOCAL : BackupPosition::UDISK;
backupWrapper.m_prefixDestPath = m_devPath;
backupWrapper.m_isOtherMachine = m_isOtherMachine ? 1 : 0;
backupWrapper.m_frontUid = getuid();
backupWrapper.m_gid = getgid();
m_pInterface->goRestore(backupWrapper);
}
/**
* @brief
* @param result
*/
void SystemRestore::on_checkRestore_end(int result)
{
bool bRst = false;
QString errMsg, errTip;
switch (result) {
case int(BackupResult::LOCK_PROGRAM_FAIL):
// 程序锁定失败,请重试
errMsg = tr("Program lock failed, please retry");
// 可能有其它备份/还原等任务在执行
errTip = tr("There may be other backups or restores being performed");
break;
case int(BackupResult::NO_FOUND_DEALCLASS):
// 不支持的任务类型
errMsg = tr("Unsupported task type");
// 没有找到相应的处理逻辑
errTip = tr("No processing logic was found in the service");
break;
case int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED):
// ".user.txt文件不存在"
errMsg = tr("The .user.txt file is not exists");
// 备份点可能被损坏
errTip = tr("Backup points may be corrupted");
break;
case int(BackupResult::WRITE_EXCLUDE_BACKUP_PATHS_TO_USER_FAILED):
// .exclude.user.txt文件不存在
errMsg = tr("The .exclude.user.txt file is not exists");
// 备份点可能被损坏
errTip = tr("Backup points may be corrupted");
break;
case int(BackupResult::INC_NOT_FOUND_DIR):
// 备份点数据目录不存在
errMsg = tr("The backup point data directory does not exist");
// 备份点可能被损坏
errTip = tr("Backup points may be corrupted");
break;
case int(BackupResult::EFI_RSYNC_FAIL):
// 同步/boot/efi失败
errMsg = tr("Failed to rsync /boot/efi");
// 请检查/boot/efi分区挂载方式
errTip = tr("Check the mounting mode of the /boot/efi partition");
break;
case int(BackupResult::RESTOREDIR_PREPARE_FAILED):
// 还原目录准备失败
errMsg = tr("Failed to prepare the restore directory");
// 更多信息请参考日志/var/log/backup.log
errTip = tr("Refer to log :/var/log/backup.log for more information");
break;
default:
bRst = true;
break;
}
if (!bRst) {
GlobelBackupInfo::inst().setIsBusy(false);
m_systemRestoreState = SystemRestoreState::IDEL;
this->on_next_clicked(true);
emit this->checkRestoreResult(bRst, errMsg, errTip);
disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &SystemRestore::on_checkRestore_end);
disconnect(m_pInterface, &ComKylinBackupManagerInterface::progress, this, &SystemRestore::progress);
disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendRestoreResult, this, &SystemRestore::on_restore_end);
delete m_pInterface;
m_pInterface = nullptr;
}
}
/**
* @brief
* @param result-false ; true
*/
void SystemRestore::on_restore_end(bool result)
{
m_systemRestoreState = SystemRestoreState::IDEL;
this->on_next_clicked(true);
if (result) {
emit checkRestoreResult(result);
} else {
// 还原过程中出现错误
QString errMsg = tr("An error occurred during restore");
// 错误信息参考日志文件:/var/log/backup.log
QString errTip = tr("Error messages refer to log file : /var/log/backup.log");
emit checkRestoreResult(result, errMsg, errTip);
}
GlobelBackupInfo::inst().setIsBusy(false);
disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &SystemRestore::on_checkRestore_end);
disconnect(m_pInterface, &ComKylinBackupManagerInterface::progress, this, &SystemRestore::progress);
disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendRestoreResult, this, &SystemRestore::on_restore_end);
delete m_pInterface;
m_pInterface = nullptr;
}
/**
* @brief
*/
void SystemRestore::initLastWidget()
{
QWidget *last = new QWidget;
// 流程进度提示栏
CircleLable *one = new CircleLable("1", last, 24, QColor(COLOR_BLUE));
LineLabel *line1 = new LineLabel(last, QColor(COLOR_BLUE), QSize(200, 24));
CircleLable *two = new CircleLable("2", last, 24, QColor(COLOR_BLUE));
LineLabel *line2 = new LineLabel(last, QColor(COLOR_GRAY), QSize(200, 24));
CircleLable *three = new CircleLable("3", last, 24, QColor(COLOR_BLUE));
QHBoxLayout *layoutLine1 = new QHBoxLayout;
layoutLine1->addStretch();
layoutLine1->addWidget(one);
layoutLine1->addWidget(line1);
layoutLine1->addWidget(two);
layoutLine1->addWidget(line2);
layoutLine1->addWidget(three);
layoutLine1->addStretch();
MyLabel *label1 = new MyLabel(tr("checking"), last);
label1->setIsOriginal(true);
label1->setFontColor(QColor(COLOR_BLUE));
MyLabel *label2 = new MyLabel(tr("restoring"), last);
label2->setIsOriginal(true);
label2->setFontColor(QColor(COLOR_BLUE));
MyLabel *label3 = new MyLabel(tr("finished"), last);
label3->setIsOriginal(true);
label3->setFontColor(QColor(COLOR_BLUE));
QHBoxLayout *layoutLine2 = new QHBoxLayout;
layoutLine2->addSpacing(100);
layoutLine2->addWidget(label1);
layoutLine2->addStretch();
layoutLine2->addWidget(label2);
layoutLine2->addStretch();
layoutLine2->addWidget(label3);
layoutLine2->addSpacing(100);
// ------------ 中部布局begin-------------
QWidget *centerFont = new QWidget(last);
QVBoxLayout *vlayoutCenterFont = new QVBoxLayout;
// 中部第一行
QHBoxLayout *hlayoutCenterFont1 = new QHBoxLayout;
// 备份结果对错图标
QLabel *resultLogo = new QLabel(centerFont);
resultLogo->setFixedSize(20,20);
hlayoutCenterFont1->addWidget(resultLogo);
// 检测中大标题
MyLabel *bigTitle = new MyLabel(centerFont);
bigTitle->setFontSize(24);
bigTitle->setMaximumWidth(700);
hlayoutCenterFont1->addWidget(bigTitle);
hlayoutCenterFont1->addStretch();
vlayoutCenterFont->addLayout(hlayoutCenterFont1);
// 第二行
QHBoxLayout *hlayoutCenterFont2 = new QHBoxLayout;
hlayoutCenterFont2->addSpacing(10);
// 备份结果错误提示:黑点和文字
CircleLable *dot1 = new CircleLable(QString(""), centerFont, 6, Qt::black);
hlayoutCenterFont2->addWidget(dot1);
hlayoutCenterFont2->addSpacing(5);
MyLabel *labelError1 = new MyLabel(centerFont);
labelError1->setMinimumWidth(400);
labelError1->setMaximumWidth(600);
labelError1->setIsOriginal(true);
labelError1->setWordWrap(true);
labelError1->adjustSize();
hlayoutCenterFont2->addWidget(labelError1);
hlayoutCenterFont2->addStretch();
vlayoutCenterFont->addLayout(hlayoutCenterFont2);
// 第三行
QHBoxLayout *hlayoutCenterFont3 = new QHBoxLayout;
hlayoutCenterFont3->addSpacing(10);
// 检测中的记录黑点2和文字2
CircleLable *dot2 = new CircleLable(QString(""), centerFont, 6, Qt::black);
hlayoutCenterFont3->addWidget(dot2);
hlayoutCenterFont3->addSpacing(5);
MyLabel *labelError2 = new MyLabel(centerFont);
//labelError2->setMinimumWidth(400);
//labelError2->setMaximumWidth(600);
labelError2->setIsOriginal(true);
labelError2->setWordWrap(true);
labelError2->adjustSize();
hlayoutCenterFont3->addWidget(labelError2);
hlayoutCenterFont3->addStretch();
vlayoutCenterFont->addLayout(hlayoutCenterFont3);
// 第四行
vlayoutCenterFont->addSpacing(30);
// 第五行
QHBoxLayout *hlayoutCenterFont5 = new QHBoxLayout;
hlayoutCenterFont5->addSpacing(100);
// 再试一次
MyPushButton *retry = new MyPushButton(centerFont);
retry->setFixedSize(97, 36);
retry->setText(tr("retry"));
retry->setEnabled(true);
retry->setAutoRepeat(true);
hlayoutCenterFont5->addWidget(retry);
hlayoutCenterFont5->addStretch();
vlayoutCenterFont->addLayout(hlayoutCenterFont5);
vlayoutCenterFont->addStretch();
centerFont->setLayout(vlayoutCenterFont);
// ------------ 中部布局end-------------
QHBoxLayout *layoutLine3 = new QHBoxLayout;
layoutLine3->addStretch();
layoutLine3->addWidget(centerFont);
layoutLine3->addStretch();
// 布局
QVBoxLayout *vlayout = new QVBoxLayout;
vlayout->addSpacing(40);
vlayout->addLayout(layoutLine1);
vlayout->addLayout(layoutLine2);
vlayout->addSpacing(50);
vlayout->addLayout(layoutLine3);
vlayout->addStretch();
last->setLayout(vlayout);
// 还原检测结果
connect(this, &SystemRestore::checkRestoreResult, this, [=](bool result, const QString &errMsg, const QString &errTip) {
if (result) {
QIcon icon = QIcon::fromTheme("ukui-dialog-success", QIcon(":/symbos/ukui-dialog-success.png"));
resultLogo->setPixmap(icon.pixmap(QSize(20,20)));
resultLogo->setVisible(true);
// 系统还原成功
bigTitle->setDeplayText(tr("Successfully restoring the system"));
dot1->setVisible(true);
dot2->setVisible(false);
labelError1->setVisible(true);
// 系统将自动重启
labelError1->setDeplayText(tr("The system will automatically reboot"));
labelError2->setVisible(false);
retry->setVisible(false);
} else {
QIcon icon = QIcon::fromTheme("dialog-error.png", QIcon(":/symbos/dialog-error.png"));
resultLogo->setPixmap(icon.pixmap(QSize(20,20)));
resultLogo->setVisible(true);
// 系统还原失败
bigTitle->setDeplayText(tr("Restoring the system failed"));
dot1->setVisible(true);
dot2->setVisible(true);
labelError1->setDeplayText(errMsg);
labelError2->setDeplayText(errTip);
retry->setVisible(true);
}
});
// 再试一次
connect(retry, &MyPushButton::clicked, this, [=](bool checked) {
Q_UNUSED(checked)
this->setCurrentIndex(SystemRestorePage::RESTORE_PAGE);
this->startRestore();
});
addWidget(last);
}

View File

@ -13,14 +13,14 @@ public:
{
IDEL = 0, // 空闲
CHECKING, // 环境校验中
BACKUPING // 备份
RESTORING // 还原
};
enum SystemRestorePage
{
HOME_PAGE, // 首页
CHECK_ENV_PAGE, // 环境检测页
BACKUP_PAGE, // 还原中页
RESTORE_PAGE, // 还原中页
LAST_PAGE, // 结束页
};
@ -31,10 +31,15 @@ public:
private:
void initFirstWidget();
void initSecondWidget();
void initThirdWidget();
void initLastWidget();
signals:
void startCheckEnv();
void checkEnvResult(bool result, const QString &errMsg = "", const QString &errTip = "");
void startRestore();
void progress(int state, int rate);
void checkRestoreResult(bool result, const QString &errMsg = "", const QString &errTip = "");
public slots:
void on_pre_clicked(bool checked = false);
@ -42,6 +47,9 @@ public slots:
void on_button_beginRestore_clicked(bool checked = false);
void on_checkEnv_start();
void on_checkEnv_end(int result);
void on_restore_start();
void on_checkRestore_end(int result);
void on_restore_end(bool result);
private:
// 是否保留用户数据
@ -54,7 +62,7 @@ private:
QString m_uuid; // 还原点的UUID
QString m_devPath; // 如果是从移动设备进行还原,此中保存移动设备挂载路径
bool m_isOtherMachine;
bool m_isOtherMachine; // 是否异机备份点还原
// 系统备份状态
int m_systemRestoreState;
};