You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
AppFlow/FITK_Kernel/FITKAppFramework/FITKAbstractCommandRunner.cpp

260 lines
7.7 KiB
C++

#include "FITKAbstractCommandRunner.h"
#include "FITK_Kernel/FITKCore/FITKThreadPool.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppSettings.h"
#include <QFile>
#include <QDir>
#include <QDebug>
#include <QString>
#ifdef Q_OS_LINUX
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdexcept>
#endif
namespace AppFrame
{
FITKAbstractCommandRunner::FITKAbstractCommandRunner(QObject *parent) : Core::FITKThreadTask(parent) {}
void FITKAbstractCommandRunner::setExecuteCommand(const QString & command)
{
_command = command;
}
qint64 FITKAbstractCommandRunner::getID()
{
return processId;
}
QString FITKAbstractCommandRunner::getOutput()
{
return _output;
}
void FITKAbstractCommandRunner::push2ThreadPool()
{
//直接在线程池运行
Core::FITKThreadPool::getInstance()->execTask(this);
}
void FITKAbstractCommandRunner::run()
{
RunStatus runStatus;
_output = executeCommand(_command, processId, runStatus);
}
void FITKAbstractCommandRunner::changeDirectory(const QString &path)
{
QDir dir(path);
if (!dir.exists())
{
emit commandError("Directory does not exist: " + path);
return;
}
if (!QDir::setCurrent(path))
{
emit commandError("Failed to change directory to: " + path);
}
else
{
emit commandOutput("Changed working directory to:" + path);
}
}
void FITKAbstractCommandRunner::setWorkDirect(const QString &path)
{
_workDirect = path;
changeDirectory(path);
}
bool FITKAbstractCommandRunner::isExistDictionary(const QStringList &dicFilePaths)
{
bool isExist = true;
for (QString filePath : dicFilePaths)
{
// 使用 QFileInfo 判断是否存在
QFileInfo checkFile(filePath);
if (!checkFile.exists())
{
isExist = false;
}
}
return isExist;
}
bool FITKAbstractCommandRunner::isExistDictionary(const QStringList &dicFilePaths, int &indexError)
{
//bool isExist = true;
for (QString filePath : dicFilePaths)
{
// 使用 QFileInfo 判断是否存在
QFileInfo checkFile(filePath);
if (!checkFile.exists())
{
indexError = dicFilePaths.indexOf(filePath);
return false;
//isExist = false;
}
}
return true;
}
FITKLinuxCommandRunner::FITKLinuxCommandRunner(QObject *parent) : FITKAbstractCommandRunner(parent) {}
#ifdef Q_OS_LINUX
QString FITKLinuxCommandRunner::executeCommand(const QString &command, qint64 &pid, RunStatus &runStatus)
{
// 数组用于存储管道的文件描述符
int pipefd[2];
// 创建管道,如果失败则抛出异常
if (pipe(pipefd) == -1)
{
return QString("Failed to create pipe");
//throw std::runtime_error("Failed to create pipe");
}
// 创建子进程
pid_t childPid = fork();
if (childPid == -1)
{
// 如果fork失败则抛出异常
return QString("Failed to fork process");
//throw std::runtime_error("Failed to fork process");
}
runStatus = RunStatus::Run;
// 子进程执行的代码
if (childPid == 0)
{
// 关闭管道的读端
close(pipefd[0]);
// 将标准输出重定向到管道的写端
dup2(pipefd[1], STDOUT_FILENO);
// 将标准错误重定向到管道的写端
dup2(pipefd[1], STDERR_FILENO);
// 关闭管道的写端
close(pipefd[1]);
// 使用/bin/sh来执行命令如果execl返回说明出错退出子进程
execl("/bin/sh", "sh", "-c", command.toStdString().c_str(), (char *) nullptr);
// execl只有在出错时才会返回因此在这里退出子进程返回127表示命令未找到
_exit(127);
}
else // 父进程执行的代码
{
// 关闭管道的写端
close(pipefd[1]);
// 存储子进程的进程ID
pid = childPid;
// 用于存储命令输出
QString output = nullptr;
// 缓冲区用于读取管道的数据
char buffer[256];
// 读取的字节数
ssize_t count;
// 从管道中读取数据,直到读取完毕
while ((count = read(pipefd[0], buffer, sizeof(buffer) - 1)) > 0)
{
// 将缓冲区的最后一个字节设置为字符串结束符
buffer[count] = '\0';
emit commandOutput(QString::fromLocal8Bit(buffer));
// 将缓冲区内容添加到输出字符串
output += QString::fromLocal8Bit(buffer);
}
// 关闭管道的读端
close(pipefd[0]);
// 存储子进程的退出状态
int status;
// 等待子进程结束
waitpid(childPid, &status, 0);
if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
{
runStatus = RunStatus::RunError;
// 检查子进程是否正常退出并且退出状态不为0
//qDebug() << QString("Command failed with exit code %1").arg(WEXITSTATUS(status));
//throw std::runtime_error("Command failed with exit code " + std::to_string(WEXITSTATUS(status)));
}
else if (WIFSIGNALED(status))
{
runStatus = RunStatus::RunError;
// 检查子进程是否被信号终止
//qDebug() << QString("Command killed by signal %1").arg(WEXITSTATUS(status));
//throw std::runtime_error("Command killed by signal " + std::to_string(WTERMSIG(status)));
}
runStatus = RunStatus::Stop;
return output;
}
}
bool FITKLinuxCommandRunner::isProcessRunning(qint64 pid)
{
if (kill(static_cast<pid_t>(pid), 0) == 0)
{
// kill 返回 0表示进程存在
return true;
}
else
{
// kill 返回非零值,表示存在错误
if (errno == EPERM)
{
// 如果错误号是 EPERM表示没有权限检查进程
emit commandError("No permission to check process " + QString::number(pid));
}
else if (errno == ESRCH)
{
// 如果错误号是 ESRCH表示进程不存在
return false;
}
return false;
}
}
bool FITKLinuxCommandRunner::killProcess(qint64 pid)
{
// 发送SIGTERM信号给指定进程
if (kill(static_cast<pid_t>(pid), SIGTERM) == 0)
{
emit commandOutput("Successfully sent SIGTERM to process " + QString::number(pid));
return true;
}
else
{
emit commandError("Error sending SIGTERM");
// 如果需要强制终止可以发送SIGKILL信号
if (kill(static_cast<pid_t>(pid), SIGKILL) == 0)
{
emit commandOutput("Successfully sent SIGKILL to process " + QString::number(pid));
return true;
}
else
{
emit commandError("Error sending SIGKILL");
return false;
}
}
}
#endif
}