2022-03-30 17:56:27 +08:00
|
|
|
|
#include <getopt.h>
|
|
|
|
|
#include <grp.h>
|
|
|
|
|
#include <pwd.h>
|
|
|
|
|
#include <sched.h>
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <sys/prctl.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/un.h>
|
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
#include <filesystem>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <thread>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
2022-05-25 11:46:28 +08:00
|
|
|
|
#include <QString>
|
|
|
|
|
#include <QProcess>
|
|
|
|
|
#include <QDir>
|
|
|
|
|
|
2022-03-30 17:56:27 +08:00
|
|
|
|
#include "../modules/methods/basic.h"
|
|
|
|
|
#include "../modules/methods/instance.hpp"
|
2022-06-15 14:14:43 +08:00
|
|
|
|
#include "../modules/methods/process_status.hpp"
|
2022-03-30 17:56:27 +08:00
|
|
|
|
#include "../modules/methods/registe.hpp"
|
|
|
|
|
#include "../modules/methods/task.hpp"
|
|
|
|
|
#include "../modules/socket/client.h"
|
|
|
|
|
#include "../modules/tools/desktop_deconstruction.hpp"
|
|
|
|
|
#include "../modules/util/oci_runtime.h"
|
|
|
|
|
|
|
|
|
|
extern char** environ;
|
|
|
|
|
|
|
|
|
|
// from linglong
|
|
|
|
|
#define LINGLONG 118
|
|
|
|
|
#define LL_VAL(str) #str
|
|
|
|
|
#define LL_TOSTRING(str) LL_VAL(str)
|
|
|
|
|
|
|
|
|
|
struct App {
|
|
|
|
|
std::string type;
|
|
|
|
|
std::string prefix;
|
|
|
|
|
std::string id;
|
|
|
|
|
};
|
|
|
|
|
|
2022-05-25 11:46:28 +08:00
|
|
|
|
static App parseApp(const QString& app)
|
2022-03-30 17:56:27 +08:00
|
|
|
|
{
|
2022-05-25 11:46:28 +08:00
|
|
|
|
QStringList values = app.split('/', QString::SkipEmptyParts);
|
|
|
|
|
qInfo() << "app:" << app << ", values size:" << values.size();
|
2022-03-30 17:56:27 +08:00
|
|
|
|
App result;
|
2022-05-25 11:46:28 +08:00
|
|
|
|
if (values.size() == 3) {
|
|
|
|
|
result.prefix = values.at(0).toStdString();
|
|
|
|
|
result.type = values.at(1).toStdString();
|
|
|
|
|
result.id = values.at(2).toStdString();
|
2022-05-19 13:13:55 +08:00
|
|
|
|
}
|
2022-03-30 17:56:27 +08:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void quit() {}
|
|
|
|
|
|
|
|
|
|
void sig_handler(int num)
|
|
|
|
|
{
|
|
|
|
|
int status;
|
|
|
|
|
pid_t pid;
|
|
|
|
|
/* 由于该信号不能叠加,所以可能同时有多个子进程已经结束 所以循环wait */
|
|
|
|
|
while ((pid = waitpid(0, &status, WNOHANG)) > 0) {
|
|
|
|
|
if (WIFEXITED(status)) // 判断子进程的退出状态 是否是正常退出
|
|
|
|
|
printf("-----child %d exit with %d\n", pid, WEXITSTATUS(status));
|
|
|
|
|
else if (WIFSIGNALED(status)) // 判断子进程是否是 通过信号退出
|
|
|
|
|
printf("child %d killed by the %dth signal\n", pid, WTERMSIG(status));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-25 11:46:28 +08:00
|
|
|
|
// TODO: startManager合并流程?
|
|
|
|
|
int childFreedesktop(Methods::Task* task, std::string path)
|
2022-03-30 17:56:27 +08:00
|
|
|
|
{
|
2022-05-25 11:46:28 +08:00
|
|
|
|
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
|
|
|
|
prctl(PR_SET_PDEATHSIG, SIGTERM);
|
|
|
|
|
prctl(PR_SET_PDEATHSIG, SIGHUP);
|
|
|
|
|
|
|
|
|
|
DesktopDeconstruction dd(path);
|
|
|
|
|
dd.beginGroup("Desktop Entry");
|
|
|
|
|
std::cout << dd.value<std::string>("Exec") << std::endl;
|
|
|
|
|
|
|
|
|
|
QStringList envs;
|
|
|
|
|
for (auto it = task->environments.begin(); it != task->environments.end(); ++it) {
|
|
|
|
|
envs.append(it.key() + "=" + it.value());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList exeArgs;
|
|
|
|
|
exeArgs << QString::fromStdString(dd.value<std::string>("Exec")).split(" ");
|
|
|
|
|
|
|
|
|
|
QString exec = exeArgs[0];
|
|
|
|
|
exeArgs.removeAt(0);
|
|
|
|
|
|
|
|
|
|
pid_t pid = fork();
|
|
|
|
|
if (pid == -1) {
|
|
|
|
|
perror("fork()");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pid == 0) {
|
|
|
|
|
// 子进程
|
|
|
|
|
QProcess process;
|
|
|
|
|
qInfo() << "exec:" << exec;
|
|
|
|
|
qInfo() << "exeArgs:" << exeArgs;
|
|
|
|
|
process.setWorkingDirectory(QDir::homePath());
|
|
|
|
|
process.setEnvironment(envs);
|
|
|
|
|
process.start(exec, exeArgs);
|
|
|
|
|
process.waitForFinished(-1);
|
|
|
|
|
process.close();
|
|
|
|
|
qInfo() << "process finish";
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
return pid;
|
2022-03-30 17:56:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-25 11:46:28 +08:00
|
|
|
|
int childLinglong(Methods::Task* task, std::string path)
|
2022-03-30 17:56:27 +08:00
|
|
|
|
{
|
|
|
|
|
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
|
|
|
|
prctl(PR_SET_PDEATHSIG, SIGTERM);
|
|
|
|
|
prctl(PR_SET_PDEATHSIG, SIGHUP);
|
|
|
|
|
|
|
|
|
|
DesktopDeconstruction dd(path);
|
|
|
|
|
dd.beginGroup("Desktop Entry");
|
|
|
|
|
std::cout << dd.value<std::string>("Exec") << std::endl;
|
|
|
|
|
|
|
|
|
|
linglong::Runtime runtime;
|
|
|
|
|
linglong::Annotations annotations;
|
|
|
|
|
linglong::Root root;
|
|
|
|
|
linglong::Mount mount;
|
|
|
|
|
annotations.container_root_path = "/run/user/1000/DAM/" + task->id;
|
|
|
|
|
annotations.native = { { mount } };
|
|
|
|
|
root.path = annotations.container_root_path + "/root";
|
|
|
|
|
mount.destination = "/";
|
|
|
|
|
mount.source = "/";
|
|
|
|
|
mount.type = "bind";
|
|
|
|
|
mount.data = { "ro" };
|
|
|
|
|
runtime.hostname = "hostname";
|
|
|
|
|
runtime.process.cwd = "/";
|
2022-04-24 14:52:13 +08:00
|
|
|
|
std::filesystem::path container_root_path(annotations.container_root_path.toStdString());
|
2022-03-30 17:56:27 +08:00
|
|
|
|
if (!std::filesystem::exists(container_root_path)) {
|
|
|
|
|
if (!std::filesystem::create_directories(container_root_path)) {
|
2022-05-19 13:13:55 +08:00
|
|
|
|
std::cout << "[Loader] [Warning] cannot create container root path." << std::endl;
|
|
|
|
|
return -1;
|
2022-03-30 17:56:27 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
|
|
for (auto it = task->environments.begin(); it != task->environments.end(); ++it) {
|
|
|
|
|
runtime.process.env.append(it.key() + "=" + it.value());
|
|
|
|
|
}
|
2022-03-30 17:56:27 +08:00
|
|
|
|
|
|
|
|
|
std::istringstream stream(dd.value<std::string>("Exec"));
|
|
|
|
|
std::string s;
|
|
|
|
|
while (getline(stream, s, ' ')) {
|
|
|
|
|
if (s.empty()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: %U
|
|
|
|
|
if (s.length() == 2 && s[0] == '%') {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
|
runtime.process.args.push_back(QString::fromStdString(s));
|
2022-03-30 17:56:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-19 13:13:55 +08:00
|
|
|
|
// 应用运行信息
|
2022-04-24 14:52:13 +08:00
|
|
|
|
QByteArray runtimeArray;
|
|
|
|
|
toJson(runtimeArray, runtime);
|
|
|
|
|
qWarning() << "runtimeArray: " << runtimeArray;
|
2022-03-30 17:56:27 +08:00
|
|
|
|
|
2022-05-19 13:13:55 +08:00
|
|
|
|
// 使用Pipe进行父子进程通信
|
2022-03-30 17:56:27 +08:00
|
|
|
|
int pipeEnds[2];
|
|
|
|
|
if (pipe(pipeEnds) != 0) {
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pid_t pid = fork();
|
|
|
|
|
if (pid == -1) {
|
|
|
|
|
perror("fork()");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pid == 0) {
|
2022-05-19 13:13:55 +08:00
|
|
|
|
// 子进程
|
2022-03-30 17:56:27 +08:00
|
|
|
|
(void) close(pipeEnds[1]);
|
2022-05-19 13:13:55 +08:00
|
|
|
|
|
|
|
|
|
// 重定向到LINGLONG
|
2022-03-30 17:56:27 +08:00
|
|
|
|
if (dup2(pipeEnds[0], LINGLONG) == -1) {
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
(void) close(pipeEnds[0]);
|
2022-05-19 13:13:55 +08:00
|
|
|
|
|
|
|
|
|
// 初始化运行命令和参数,并执行
|
2022-03-30 17:56:27 +08:00
|
|
|
|
char const* const args[] = { "/usr/bin/ll-box", LL_TOSTRING(LINGLONG), nullptr };
|
|
|
|
|
int ret = execvp(args[0], (char**) args);
|
|
|
|
|
std::cout << "[Loader] [Fork] " << ret << std::endl;
|
|
|
|
|
//std::filesystem::remove(container_root_path);
|
|
|
|
|
exit(ret);
|
2022-05-19 13:13:55 +08:00
|
|
|
|
} else {
|
|
|
|
|
// 父进程
|
2022-04-24 14:52:13 +08:00
|
|
|
|
QByteArray runtimeArray;
|
|
|
|
|
linglong::toJson(runtimeArray, runtime);
|
|
|
|
|
const std::string data = runtimeArray.data();
|
2022-03-30 17:56:27 +08:00
|
|
|
|
close(pipeEnds[0]);
|
2022-05-19 13:13:55 +08:00
|
|
|
|
|
|
|
|
|
// 将运行时信息通过pipe传递给子进程
|
2022-03-30 17:56:27 +08:00
|
|
|
|
write(pipeEnds[1], data.c_str(), data.size());
|
|
|
|
|
close(pipeEnds[1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return pid;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-25 11:46:28 +08:00
|
|
|
|
int childAndroid(Methods::Task* task, std::string path)
|
|
|
|
|
{
|
|
|
|
|
// TODO
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-30 17:56:27 +08:00
|
|
|
|
#define DAM_TASK_HASH "DAM_TASK_HASH"
|
|
|
|
|
#define DAM_TASK_TYPE "DAM_TASK_TYPE"
|
|
|
|
|
|
|
|
|
|
int main(int argc, char* argv[])
|
|
|
|
|
{
|
|
|
|
|
const char* dam_task_hash = getenv(DAM_TASK_HASH);
|
|
|
|
|
if (!dam_task_hash) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
const char* dam_task_type = getenv(DAM_TASK_TYPE);
|
|
|
|
|
if (!dam_task_type) {
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-19 13:13:55 +08:00
|
|
|
|
char socketPath[50];
|
|
|
|
|
sprintf(socketPath, "/run/user/%d/deepin-application-manager.socket", getuid());
|
2022-03-30 17:56:27 +08:00
|
|
|
|
|
|
|
|
|
// register client and run quitConnect
|
|
|
|
|
Socket::Client client;
|
|
|
|
|
client.connect(socketPath);
|
|
|
|
|
|
2022-05-19 13:13:55 +08:00
|
|
|
|
// 初始化应用注册信息
|
2022-04-24 14:52:13 +08:00
|
|
|
|
QByteArray registerArray;
|
2022-03-30 17:56:27 +08:00
|
|
|
|
Methods::Registe registe;
|
2022-05-25 11:46:28 +08:00
|
|
|
|
registe.id = dam_task_type;
|
2022-03-30 17:56:27 +08:00
|
|
|
|
registe.hash = dam_task_hash;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
Methods::toJson(registerArray, registe);
|
2022-03-30 17:56:27 +08:00
|
|
|
|
|
2022-05-19 13:13:55 +08:00
|
|
|
|
// 向AM注册应用信息进行校验
|
2022-03-30 17:56:27 +08:00
|
|
|
|
Methods::Registe registe_result;
|
|
|
|
|
registe_result.state = false;
|
2022-05-25 11:46:28 +08:00
|
|
|
|
QByteArray result = client.get(registerArray);
|
2022-04-24 14:52:13 +08:00
|
|
|
|
if (!result.isEmpty()) {
|
|
|
|
|
Methods::fromJson(result, registe_result);
|
2022-03-30 17:56:27 +08:00
|
|
|
|
}
|
|
|
|
|
if (!registe_result.state) {
|
|
|
|
|
return -3;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-19 13:13:55 +08:00
|
|
|
|
// 初始化应用实例信息
|
2022-03-30 17:56:27 +08:00
|
|
|
|
Methods::Instance instance;
|
|
|
|
|
instance.hash = registe_result.hash;
|
2022-04-24 14:52:13 +08:00
|
|
|
|
QByteArray instanceArray;
|
|
|
|
|
Methods::toJson(instanceArray, instance);
|
2022-05-19 13:13:55 +08:00
|
|
|
|
|
|
|
|
|
// 向AM注册应用实例信息进行校验
|
2022-04-24 14:52:13 +08:00
|
|
|
|
result = client.get(instanceArray);
|
|
|
|
|
Methods::Task task;
|
2022-05-19 13:13:55 +08:00
|
|
|
|
Methods::fromJson(result, task); // fromJson TODO 数据解析异常
|
2022-05-25 11:46:28 +08:00
|
|
|
|
qInfo() << "[Task] " << result;
|
2022-03-30 17:56:27 +08:00
|
|
|
|
|
2022-05-19 13:13:55 +08:00
|
|
|
|
// 校验task内容
|
2022-05-25 11:46:28 +08:00
|
|
|
|
App app = parseApp(task.runId);
|
|
|
|
|
qInfo() << "[App] "
|
|
|
|
|
<< "prefix:" << QString::fromStdString(app.prefix)
|
|
|
|
|
<< "type:" << QString::fromStdString(app.type)
|
|
|
|
|
<< "id:" << QString::fromStdString(app.id);
|
2022-05-19 13:13:55 +08:00
|
|
|
|
if (task.id.isEmpty() || app.id.empty() || app.type.empty() || app.prefix.empty()) {
|
|
|
|
|
std::cout << "get task error" << std::endl;
|
|
|
|
|
return -4;
|
|
|
|
|
}
|
2022-05-25 11:46:28 +08:00
|
|
|
|
if (app.prefix != "freedesktop"
|
|
|
|
|
&& app.prefix != "linglong"
|
|
|
|
|
&& app.prefix != "android") {
|
|
|
|
|
qWarning() << "error app prefix :" << QString::fromStdString(app.type);
|
|
|
|
|
return -1;
|
2022-05-19 13:13:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-30 17:56:27 +08:00
|
|
|
|
pthread_attr_t attr;
|
2022-05-25 11:46:28 +08:00
|
|
|
|
size_t stack_size;
|
2022-03-30 17:56:27 +08:00
|
|
|
|
pthread_attr_init(&attr);
|
|
|
|
|
pthread_attr_getstacksize(&attr, &stack_size);
|
|
|
|
|
pthread_attr_destroy(&attr);
|
|
|
|
|
|
|
|
|
|
/* 先将SIGCHLD信号阻塞 保证在子进程结束前设置父进程的捕捉函数 */
|
|
|
|
|
sigset_t nmask, omask;
|
2022-05-25 11:46:28 +08:00
|
|
|
|
// sigemptyset(&nmask);
|
|
|
|
|
// sigaddset(&nmask, SIGCHLD);
|
|
|
|
|
// sigprocmask(SIG_BLOCK, &nmask, &omask);
|
2022-03-30 17:56:27 +08:00
|
|
|
|
|
|
|
|
|
//char* stack = (char*) malloc(stack_size);
|
|
|
|
|
//pid_t pid = clone(child, stack + stack_size, CLONE_NEWPID | SIGCHLD, static_cast<void*>(&task));
|
2022-05-25 11:46:28 +08:00
|
|
|
|
pid_t pid = -1;
|
|
|
|
|
if (app.prefix == "freedesktop") {
|
|
|
|
|
pid = childFreedesktop(&task, task.filePath.toStdString());
|
|
|
|
|
} else if (app.prefix == "linglong") {
|
|
|
|
|
pid = childLinglong(&task, task.filePath.toStdString());
|
|
|
|
|
} else if (app.prefix == "android") {
|
|
|
|
|
pid = childAndroid(&task, task.filePath.toStdString());
|
|
|
|
|
} else {
|
|
|
|
|
qWarning() << "error app prefix:" << QString::fromStdString(app.prefix);
|
|
|
|
|
}
|
2022-06-15 14:14:43 +08:00
|
|
|
|
|
|
|
|
|
if(pid != -1)
|
|
|
|
|
{
|
|
|
|
|
Methods::ProcessStatus processSuccess;
|
|
|
|
|
processSuccess.code = 0;
|
|
|
|
|
processSuccess.id = task.id;
|
|
|
|
|
processSuccess.type = "success";
|
|
|
|
|
processSuccess.data = QString::number(pid);
|
|
|
|
|
QByteArray processArray;
|
|
|
|
|
Methods::toJson(processArray, processSuccess);
|
|
|
|
|
client.send(processArray);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-30 17:56:27 +08:00
|
|
|
|
// TODO: 启动线程,创建新的连接去接受服务器的消息
|
|
|
|
|
|
2022-05-25 11:46:28 +08:00
|
|
|
|
// TODO:信号处理有问题
|
2022-03-30 17:56:27 +08:00
|
|
|
|
/* 设置捕捉函数 */
|
2022-05-25 11:46:28 +08:00
|
|
|
|
// struct sigaction sig;
|
|
|
|
|
// sig.sa_handler = sig_handler;
|
|
|
|
|
// sigemptyset(&sig.sa_mask);
|
|
|
|
|
// sig.sa_flags = 0;
|
|
|
|
|
// sigaction(SIGCHLD, &sig, NULL);
|
2022-03-30 17:56:27 +08:00
|
|
|
|
/* 然后再unblock */
|
2022-05-25 11:46:28 +08:00
|
|
|
|
// sigdelset(&omask, SIGCHLD);
|
|
|
|
|
// sigprocmask(SIG_SETMASK, &omask, NULL);
|
2022-03-30 17:56:27 +08:00
|
|
|
|
|
|
|
|
|
int exitCode;
|
|
|
|
|
waitpid(pid, &exitCode, 0);
|
2022-05-25 11:46:28 +08:00
|
|
|
|
qInfo() << "app exitCode:" << exitCode;
|
2022-03-30 17:56:27 +08:00
|
|
|
|
|
2022-06-15 14:14:43 +08:00
|
|
|
|
Methods::ProcessStatus quit;
|
2022-03-30 17:56:27 +08:00
|
|
|
|
quit.code = exitCode;
|
|
|
|
|
quit.id = task.id;
|
2022-06-15 14:14:43 +08:00
|
|
|
|
quit.type = "quit";
|
2022-04-24 14:52:13 +08:00
|
|
|
|
QByteArray quitArray;
|
|
|
|
|
Methods::toJson(quitArray, quit);
|
|
|
|
|
client.send(quitArray);
|
2022-03-30 17:56:27 +08:00
|
|
|
|
|
|
|
|
|
return exitCode;
|
|
|
|
|
}
|