当您的代码作为 LaunchDaemon 运行时,如何在不重新启动的情况下首次启动 LaunchAgent?
我有一个 LaunchDaemon。当它运行时,它会检查 SIMBL 是否已安装。如果未安装 SIMBL,它将使用 NSTask 在 SIMBL.pkg 上运行 /usr/sbin/installer。
然后,SIMBL 的 postflight 脚本尝试运行 launchctl load 命令以立即启动 SIMBL 的 LaunchAgent:
sudo -u "$USER" -- /bin/launchctl load -F -S Aqua -D user "${LAUNCHD_PLIST}"
这会失败,因为我的 LaunchDaemon 的 NSTask 环境没有设置 $USER。
如果我让我的守护进程使用系统配置框架检测当前用户,并使用 setEnvironment 将其传递给 NSTask,则 launchctl 会出现错误:
Bug: launchctl.c:2325 (23930):13: (dbfd = open(g_job_overrides_db_path, O_RDONLY | O_EXLOCK | O_CREAT, S_IRUSR | S_IWUSR)) != -1
根据定义,我意识到守护进程不应在用户会话中运行。出于同样的原因,Apple 似乎推荐 LaunchAgents 作为 LaunchDaemons 的辅助对象,以完成用户会话工作。有没有办法让这样的代理立即启动并运行?
我将所有 .plist 放在正确的位置(它们在重新启动后开始运行,下次 launchctl 进行常规加载时),所以我的第一个想法是告诉 launchctl 重新加载。但是 所有执行此操作的代码都已注释在 launchctl.c 中:
// { "reload", reload_cmd, "Reload configuration files and/or directories" },
...
* In later versions of launchd, I hope to load everything in the first pass,
* then do the Bonjour magic on the jobs that need it, and reload them, but for now,
* I haven't thought through the various complexities of reloading jobs, and therefore
* launchd doesn't have reload support right now.
I have a LaunchDaemon. When it runs, it checks if SIMBL is installed. If SIMBL is not installed, it uses NSTask to run /usr/sbin/installer on the SIMBL.pkg.
SIMBL's postflight script then tries to run a launchctl load command to start SIMBL's LaunchAgent immediately:
sudo -u "$USER" -- /bin/launchctl load -F -S Aqua -D user "${LAUNCHD_PLIST}"
This fails, because my LaunchDaemon's NSTask environment doesn't have $USER set.
If I have my daemon detect the current user with the System Configuration framework and pass it to NSTask with setEnvironment, launchctl bugs out on me:
Bug: launchctl.c:2325 (23930):13: (dbfd = open(g_job_overrides_db_path, O_RDONLY | O_EXLOCK | O_CREAT, S_IRUSR | S_IWUSR)) != -1
I realize a daemon, by definition, should not operate in a user session. By the same token, Apple seems to recommend LaunchAgents as helper objects for LaunchDaemons, to do that user session work. Is there any way to get such an agent up and running immediately?
I have all the .plists in the right places (they start running after a reboot, the next time launchctl does its regular loading) so my first thought was to just tell launchctl to reload. But all the code to do that is commented out in launchctl.c:
// { "reload", reload_cmd, "Reload configuration files and/or directories" },
...
* In later versions of launchd, I hope to load everything in the first pass,
* then do the Bonjour magic on the jobs that need it, and reload them, but for now,
* I haven't thought through the various complexities of reloading jobs, and therefore
* launchd doesn't have reload support right now.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
哦,
launchd
让我发疯了......言归正传,经过大量研究和实验,我在 10.5+ 上是这样做的:
我发现没有办法直接在 10.4 上实现这一点。我在 10.4 上作弊,只运行 LaunchAgent 会运行的东西,即使它有 GUI,而且你不应该能够这样做(在 10.4-10.6 中无论如何你都可以;在 10.7 中你不能)。在 10.4 上,LaunchAgent 在下次重新启动后可以正常工作。
上面的代码查找
loginwindow
进程并使用bsexec
在这些上下文中运行命令。请记住,通过快速用户切换,可以有多个上下文。一些有用的链接:
launchd
深渊的人来说,这是福音和必读的内容。在我看来,
launchd
是苹果公司有史以来部署的最糟糕的“好主意”之一。这个想法非常有用,但是 API 很糟糕。Oh how
launchd
drives me crazy....To cut to the chase, after much study and experimentation, this is how I do it on 10.5+:
I have found no way to achieve this directly on 10.4. I cheat on 10.4 and just run the thing the LaunchAgent would have run, even though it has a GUI and you're not supposed to be able to do that (you can anyway in 10.4-10.6; you can't in 10.7). On 10.4, the LaunchAgent works correct after the next reboot.
The above code looks for
loginwindow
processes and usesbsexec
to run commands in those contexts. Keep in mind that with Fast User Switching, there can be multiple contexts.Some useful links:
launchd
.IMO,
launchd
is one of the worst "great ideas" Apple has ever deployed. The idea is very useful, but the API is horrible.