我在 Linux 上有一个服务。该服务需要启动不同的进程。例如,在某些条件下,例如网络事件时,服务应启动具有 GUI 的进程。 为此,我使用了 fork() 和 execvp()。 此外,我还通过根据我想要运行该进程的用户设置 uid 和 gid 来删除 root 权限。 然后,我相应地设置了 DISPLAY 和 XAUTHORITY 环境变量。
这有点效果。我的进程确实正在运行并且 GUI 已显示。然而值得注意的是,该进程并没有真正与服务分离。 例如:pkexec 不起作用。它总是尝试启动终端版本并失败。 另外,我不希望服务停止后我的进程就被终止。
我读到为此我应该使用 dbus 并使用它与 systemd 进行通信,并且 1)通过 systemd 启动进程或 2)让 systemd 以某种方式从服务中分离我的进程。
现在我不知道这是如何运作的。我可以打开总线,我也应该能够调用方法,但是我不知道哪种方法以及我想要做什么。
有人可以指导我正确的方向,我应该在 systemd 上调用哪种方法来在用户会话中启动进程或从我的服务中分离进程。
免责声明:设置 KillMode=none 可以解决进程终止问题,但据我所知,不建议这样做,也不能解决 pkexec 问题。
以我的热门评论开头......
fork
setsid
做setpgrp
做我创建了一个似乎有效的诊断程序。我没有对其进行过广泛测试。它没有设置任何环境,所以我不知道这会如何影响事情。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
void
launch_top(int argc,char **argv)
{
pid_t top = getpid();
// parent launching child
pid_t pcld = fork();
if (pcld != 0) {
waitpid(pcld,NULL,0);
sleep(2);
printf("launch_top: killing self %d\n",top);
kill(top,SIGTERM);
exit(0);
}
// child launching grandchild
pid_t gcld = fork();
if (gcld != 0)
exit(0);
// grandchild launching target
setsid();
setpgrp();
fclose(stdin);
fclose(stdout);
fclose(stderr);
char *av[3];
av[0] = argv[0];
av[1] = "forever";
av[2] = NULL;
execvp(av[0],av);
perror("launch_top/execvp");
exit(9);
}
void
stay_alive(int argc,char **argv)
{
FILE *xflog = fopen("stay.log","w");
setlinebuf(xflog);
for (int loop = 0; loop < 10; ++loop) {
fprintf(xflog,"stay_alive: %d\n",loop);
sleep(1);
}
fprintf(xflog,"stay_alive: success\n");
fclose(xflog);
exit(0);
}
int
main(int argc,char **argv)
{
setlinebuf(stdout);
// ultimate program that should stay alive
if (argc > 1)
stay_alive(argc,argv);
// launcher service
else
launch_top(argc,argv);
return 0;
}
这是父级的
stdout
输出:
launch_top: killing self 2564383
这是目标程序的示例输出日志
stay.log
,该程序应该保持活动状态并在原始/父进程被杀死的情况下幸存下来:
stay_alive: 0
stay_alive: 1
stay_alive: 2
stay_alive: 3
stay_alive: 4
stay_alive: 5
stay_alive: 6
stay_alive: 7
stay_alive: 8
stay_alive: 9
stay_alive: success