我想设置新启动的进程的父进程,可以吗?
例如,假设我们通过登录管理器启动一个新的桌面环境会话,因此我们的进程树将如下所示:
init
\- login-manager
\- de-session
现在我确实有一个脚本来启动我最重要的应用程序,这些应用程序应该从会话开始,出于各种原因,我想将它们保留为脚本,而不是将它们迁移到任何 DE 的自动启动管理器。它看起来像这样:
#!/usr/bin/env
application1 &
application2 &
application3 &
在会话开始时自动运行此命令后,我们的进程树如下所示:
init
|- application1
|- application2
|- application3
\- login-manager
\- de-session
但我实际上想要的是在会话下“重新定义”这些进程,如下所示:
init
\- login-manager
\- de-session
|- application1
|- application2
\- application3
那么,有没有办法在另一个进程下“重新设置父进程”呢?
答案1
在一些系统上,您可以将进程标记为儿童副收割者,这使得它承担init
起为其所有后代收养孤儿进程的角色。
在 Linux 上,这是通过PR_SET_CHILD_SUBREAPER
prctl()
.
因此,您可以启动de-session
as (此处对 Linux 的值进行硬编码PR_SET_CHILD_SUBREAPER
):
perl -e 'require "syscall.ph";
syscall(&SYS_prctl,36,1) >= 0 or die "cannot set subreaper: $!";
exec("de-session");'
但当de-session
它收到从未生成的进程的 SIGCHLD 信号时,可能会感到困惑。您的init
设计目的是处理这些问题,但可能不是您的de-session
,因此您可能会发现您得到了一支僵尸大军,因为它们de-session
从不承认那些它不想继承的进程的死亡。
答案2
事实上,就在不到一年前,我用 TrueOS(以前称为 PC-BSD)做到了这一点。
普通 TrueOS
在普通 TrueOS 上,该pcdm
服务运行图形用户界面。
- Mewburn
rc
系统运行该/usr/local/etc/rc.d/pcdm
脚本,该脚本的生命周期不长。 PCDMd
一个名为Spawn的无限循环且相当复杂的 shell 脚本xinit
告诉它运行一个名为 的程序PCDM-session
。PCDM-session
是一个桌面选择器和登录程序,它以/tmp
.它产生/usr/local/share/PCDM/pcdm-session
。dbus-daemon
如果没有传递有关要与之通信的桌面总线的信息,它还会在侧面剥离并孤立一个以超级用户身份运行的 。/usr/local/share/PCDM/pcdm-session
链接到之前写出的脚本。sh /tmp/PCDM-session.blah
- 所述 shell 脚本依次运行 中的所有内容
$HOME/.xprofile
,这是所有诸如此类的内容被分叉的地方,并最终通过(以登录用户身份运行并分离另一个进程)gpg-agent
运行所选桌面的会话。dbus-launch
dbus-daemon
这会导致相当混乱的进程树,无论是对于由 分叉出来的任何东西$HOME/.xprofile
(从 运行所有内容/usr/local/share/pcbsd/xstartup/
),还是对于在桌面会话进程下启动并后来通过 fork-and-exit-parent 孤立的任何东西(例如,唉,thunderbird
)。所有 D-Bus 经纪人也都不是很漂亮;很多东西最终都会以进程 #1 作为其父进程 ID。命名也无助于使事情变得简单。 pcdm
调用PCDMd
调用调用PCDM-session
调用pcdm-session
调用。PCDM-session.blah
(我试图让 TrueOS 的人们知道这是不必要的复杂,特别是程序中完全不必要的隐藏的额外的、损坏的服务管理器,PCDM-session
我在上面的描述中省略了。)
local-reaper
以及userenv
来自 nosh 工具集
在诺什工具集有一个名为 的小链加载实用程序local-reaper
。它的唯一任务是将自己标记(或取消标记)为副收割者然后在同一进程中链式加载另一个程序映像。
没有任何 Linux 特有的东西,子收割机机制可在多个操作系统上使用。它可以在 Linux 和 FreeBSD/TrueOS/DragonFlySBD 上运行,并且没有硬连线的系统调用号或任何类似的东西。 ☺
nosh 工具集中还有userenv
和setuidgid
工具。这些实际上做到了一切TrueOSpcdm-session
程序所做的事情,以及更多,包括设置DBUS_SESSION_BUS_ADDRESS
变量以指向每用户桌面总线代理。整个 TrueOSpcdm-session
程序实际上可以替换为
#!/bin/sh - 执行 >>"$5" 2>&1 chown -v -h -- "$1" "${XAUTHORITY}" 执行\ 本地收割者 true \ setuidgid --补充“$1”\ userenv --set-path --set-other --set-tools --set-timezone --set-locale --set-xdg \ 嘘“4美元”
投入local-reaper
使用
要使用它,我必须找到满足三个条件的进程:
- 它们必须是孤立进程的间接父进程。
- 他们必须长寿。
- 他们必须能够适应突然获得他们没有预料到的子进程。
并非所有流程都适合。我实际上发现了 TrueOS 程序中的一个错误,它在诊断进程是否适合作为子收割者PCDM-session
的同时等待错误的进程 ID 。PCDM-session
(我也向 TrueOS 人员讲述了这个错误。 它实际上是一个一个字符输入错误。)
幸运的是,shell 程序几乎总是是适合做收割者,而且这棵树上有几个shell进程。事实证明,也是如此xinit
。
改进的进程树
那么会发生什么现在是;
- 我在适当的服务经理的领导下管理事务。服务器管理器进程是本身副收割者。
- 服务管理生成了一个明显更短的 shell 脚本
local-reaper true xinit …
,从而使该xinit
进程也成为子收割者。 xinit
被告知要跑local-reaper true helper-script
,使 shell 解释器进行解释帮助脚本第三个副收割者。- 帮助脚本运行
dbus-launch --exit-with-session PCDM-session
。它会一直运行,运行 shell 解释器,等待PCDM-session
进程完成。dbus-launch
剥离它所孤立的两个副进程。 PCDM-session
无法成为副收割者。它的行为没有改变:它在/tmp
并生成中写出一个随机数 shell 脚本/usr/local/share/PCDM/pcdm-session
。但桌面总线侧处理的分拆已经完成。- 修订后的版本
/usr/local/share/PCDM/pcdm-session
将自己标记为 subreaper 并链接到之前编写的脚本。sh /tmp/PCDM-session.blah
- 所述 shell 脚本仍然运行 中的所有内容
$HOME/.xprofile
,从而运行 中的所有内容/usr/local/share/pcbsd/xstartup/
,最后运行所选桌面的会话,但直接运行,不再通过dbus-launch
。它会一直运行,运行 shell 解释器,等待桌面会话进程完成。
其效果如下:
- 从 中的任何脚本分叉出来的内容都
/usr/local/share/pcbsd/xstartup/
将重新设置为正在运行的进程的父级。sh /tmp/PCDM-session.blah
- 诸如
thunderbird
通过 fork-and-exit-parent 作为桌面会话进程的孙子运行的桌面应用程序将重新设置为正在运行的进程的父级。sh /tmp/PCDM-session.blah
- 由其分叉和孤立的副进程
dbus-launch
将重新成为该helper-script
进程的父进程。 - 没有
dbus-daemon
分叉出用户端进程;因为一切都指向在进程树的另一部分中运行的每用户桌面总线代理,作为正确服务管理下的用户级服务。 - 没有什么比重新设置父级到 更远的了
xinit
。事实证明,让它成为副收割机是没有必要的。
进程树从进程 #1 开始,如下所示:
/sbin/系统管理器 -- |-- cyclog --最大文件大小 262144 --最大总大小 1048576 。 (系统管理员) `-- 服务管理器(系统管理器) …… |-- 每用户管理器 | |-- cyclog --最大文件大小 262144 --最大总大小 1048576 。 | `--服务经理 | |-- cyclog JdeBP/socket-servers/ | |-- cyclog JdeBP/dbus-servers/ | |-- dbus-daemon --config-file ./per-user.conf --nofork --address=unix:path=/run/user/JdeBP//bus …… |-- /bin/sh - ./helper 运行 `-- xinit /bin/exec local-reaper true ./helper session -- :0 -auth -retro |-- X :0 -auth -retro (Xorg) `-- /bin/sh - ./helper 会话 |-- PCDM-会话-一次 | `-- PCDM-会话-一次 | `-- sh /tmp/PCDM-session.ca1015 | |-- /usr/local/bin/gpg-agent … | | `-- scdaemon --多服务器 | |-- /usr/local/bin/lxsession -s LXDE | | |-- openbox --配置文件 … | | |-- lxpanel --profile LXDE | | |-- pcmanfm --desktop --profile LXDE | | `-- xscreensaver -无飞溅 | |-- /usr/local/bin/python2.7 /usr/local/share/system-config-printer/applet.py | |-- 救生盘 | |-- /usr/local/bin/pc-systemupdatertray | |-- 时代精神数据中心 | |-- 电脑调音台 | |-- pc-安装托盘 | |-- /usr/local/libexec/menu-cache/menu-cached … | `——雷鸟 |-- dbus-launch --exit-with-session PCDM-session-once `-- /usr/local/bin/dbus-daemon --fork … --session