我有一个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,则startctl会对我产生错误:
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的辅助对象,以进行该用户会话工作。有没有办法让这样的代理人立即投入运行?
我将所有的.plists放在正确的位置(它们在重新启动后开始运行,下次启动时会执行常规加载)所以我的第一个想法是告诉launchctl重新加载。但是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.
答案 0 :(得分:6)
哦launchd
让我疯狂......
经过大量的研究和实验后,这就是我在10.5 +上的表现:
# If possible, tell launchd to start the LaunchAgent. This will fail on 10.4.
# $F[0] is the pid
# $F[1] is the username
# $F[2] is the first word of the command
ps -ww -A -opid,user,command | \
perl -nae 'if($F[2] =~ /\bloginwindow\b/) { system(
qq(launchctl bsexec $F[0] su $F[1] -c "launchctl load -w <your_plist>"))
}'
我发现无法直接在10.4上实现这一点。我在10.4上作弊,只是运行LaunchAgent运行的东西,即使它有一个GUI而且你不应该这样做(无论如何你可以在10.4-10.6中;你不能在10.7中)。在10.4上,LaunchAgent在下次重新启动后工作正常。
上面的代码查找loginwindow
个进程,并使用bsexec
在这些上下文中运行命令。请记住,通过快速用户切换,可以有多个上下文。
一些有用的链接:
launchd
深渊的人来说都是福音和强制性阅读。 IMO,launchd
是Apple有史以来最糟糕的“好主意”之一。这个想法非常有用,但API太可怕了。