我对 OS X 上的 launchd 并不陌生。过去我创建过几个守护进程,最近一次是与 Mountain Lion Mavericks 一起创建的。
但是,我似乎很难让最简单的 plist 在 Mavericks 和 El Capitan 上运行。最初,我复制了运行 Tomcat 的 plist,并对其进行了修改,以使 WebSphere Liberty Profile 在启动时运行。看到一些错误后,我决定尝试 Apple 自己的 [site][1] 中的以下示例 plist。以下内容甚至无法运行:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.example.hello</string>
<key>ProgramArguments</key>
<array>
<string>hello</string>
<string>world</string>
</array>
<key>KeepAlive</key>
<true/>
</dict>
每当我将 plist 文件放在 /Library/LaunchDaemons 然后加载 plist 时,我都会在控制台中看到以下错误:
2015 年 10 月 5 日 上午 11:52:44.868 com.apple.xpc.launchd[1]: (com.example.hello) 此服务被定义为持续运行,本质上效率低下。
2015 年 10 月 5 日 上午 11:52:44.869 com.apple.xpc.launchd[1]:(com.example.hello[66956])服务无法初始化:15A284:xpcproxy + 12644 [1472][19011403-4854-3CCD-9FCF-49C36302EB40]:0x2
2015 年 10 月 5 日 上午 11:52:44.870 com.apple.xpc.launchd[1]: (com.example.hello) 服务仅运行了 0 秒。重生时间推迟了 10 秒。
就输出而言就是这样。我尝试写入 StandardOutput 和 StandardError 日志,但日志文件是空的。
当我看到这种情况发生在优胜美地和酋长岩上时,我认为这一定是与权限有关的事情:
-rw-r--r-- 1 根轮 418 十月 5 11:52 helloworld.plist
但是,我尝试将权限设置为 644 和 755 来运行守护进程,但仍然看到相同的控制台错误。
我是否忽略了什么?
答案1
正如我所看到的,<key>KeepAlive</key>
正在输出com.apple.xpc.launchd[1]: (com.example.hello) This service is defined to be constantly running and is inherently inefficient.
然后它告诉自己在 10 秒后重新启动该过程<key>
。
我不能 100% 确定它com.apple.xpc.launchd[1]: (com.example.hello[66956]) Service could not initialize: 15A284: xpcproxy + 12644 [1472][19011403-4854-3CCD-9FCF-49C36302EB40]: 0x2
在说什么,因为我没有该事件的日志,但它似乎在抗议原始事件,<key>
因为它没有执行任何其他操作。也许尝试删除<key>
或将其更改为其他内容?可能:
<key>Label</key>
<string>com.example.hello</string>
<key>ProgramArguments</key>
<array>
<string>hello</string>
<string>world</string>
</array>
<key>KeepAlive</key>
<false/>
或者
<key>Label</key>
<string>com.example.hello</string>
<key>ProgramArguments</key>
<array>
<string>hello</string>
<string>world</string>
</array>
再次强调,我对此不是 100% 确定,但我建议尝试类似的东西。操作系统抗议不需要 keepAlive 节点,所以祝你好运。
答案2
我能够在@Dooley_labs 和@Spiff 的帮助下创建一个工作示例(谢谢)。
以下示例将每 10 秒将 Hello World 回显到指定的日志文件。控制台不显示任何输出,但当我查看日志文件的内容时,我看到 Hello World 被重复写入其中。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.example.hello</string>
<key>ProgramArguments</key>
<array>
<string>echo</string>
<string>Hello World</string>
</array>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/var/log/helloworld.log</string>
</dict>
</plist>
答案3
当您读到这篇文章时,您会打自己一巴掌,但是,您并没有告诉 launchctl 要运行什么可执行文件!
第一个答案正确地将“echo”作为第一个“ProgramArguments”,但并没有说这就是问题所在。
我相信您也可以使用“Program”键来完成此操作,但我不确定您是否必须在“ProgramArguments”键中重复此操作,我相信这是传递给可执行文件的 arg[] 数组。
要注意的另一件事是始终列出可执行文件的完整路径。launchd/launchctl 非常严格,但是,Bad Guy™ 仍然可以将恶意的“echo”可执行文件放在默认 $PATH 的某个地方,然后等待 launchctl 重新解析 LaunchDaemon plist。