如何在OSX Yosemite 10.10.3+中守护非特权脚本

时间:2015-04-21 17:33:01

标签: macos daemon osx-yosemite launchd mach

多年来,我们已将流程监控/控制脚本作为我们应用程序的一部分。脚本的默认行为是守护自身。通常,非特权用户必须启动脚本。由于我没有详细说明的原因,我们需要同时保留脚本和此行为。

OSX 系统上,我们传统上通过Apple提供的 / usr / libexec / StartupItemContext 启动脚本在后台重启脚本。这将我们的进程放在Mach StartupItem 引导程序上下文中,而不是登录引导程序上下文中。这是必要的,因为如果没有上下文切换,当用户注销时(通常也是必需的),脚本将失去对目录服务,getpwuid(),DNS服务等的访问权限。守护脚本的原始内部行看起来基本上是像这样(在perl中):

my $cmd = "/usr/libexec/StartupItemContext myscript @Commandline > logs/startup 2>&1" ;         
system( "$cmd &") ;
exit 0 ;

OSX Yosemite 出现时, StartupItemContext 脚本消失了,所以我们切换到直接调用 launchctl

my $cmd = "/usr/launchctl bsexec / myscript @Commandline > logs/startup 2>&1" ;         
system( "$cmd &") ;
exit 0 ;

但是,在最近的 OSX 10.10.3 升级中, launchctl bsexec 子命令突然需要root权限:

% launchctl bsexec
This subcommand requires root privileges: bsexec
% 

这为我们创造了一个showstopper问题,即非特权用户无法再让我们的监控/控制脚本进行守护自身。

似乎是Glassfish has encountered this problem并用a patch替换了

来解决它
/bin/launchctl bsexec /

nohup

这可能适用于Glassfish实施,但我不为我们考虑。尽管事实上我并不理解它 - 也就是说为什么简单地阻止SIGHUP会阻止退役登录引导程序中的进程丢失服务 - 它似乎也不适用于我们所有的测试我们需要的系统服务。

从非特权,Mach"登录"开始,在 OSX 上守护进程的新规范方法是什么?引导上下文,当用户注销时不会失去对DNS等关键系统服务的访问权限?

1 个答案:

答案 0 :(得分:3)

"来自非特权,Mach"登录" bootstrap context"不幸的是,不太可能采用规范的方式。"唯一的规范方法是通过launchd按需启动服务。甚至" bsexec"几乎没有得到支持,也很难记录。根据我的经验,不可能跟上OS X的变化,也永远不会重新设计你的发布系统。我重新设计了守护进程系统关于其他每个版本,因为Apple打破了它,并且他们将继续打破它。唯一的答案是继续努力使您的要求更简单。但是,几乎所有想要一直运行而不是按需运行的流程都直接违反了苹果公司声明的意图,因此它往往会破坏。

Apple提供的解决方案是创建一个LaunchDaemon并在你的launchd plist中为它分配一个UserName。您必须启动特权,然后切换到用户(它需要是固定用户,而不是"登录用户"因为那将是LaunchAgent)。您无法以这种方式升级您的访问权限。你不能自己守护(再一次,规范的答案是:不要这样做。请参阅launchd.plist手册页。)

我怀疑Glassfish nohup解决方案只是一个实际上并没有将它们置于Mach环境中的闪避。他们只是试图避免在父shell退出时被杀死。这可能对你没有帮助。

根据我的经验,最强大的解决方案是多部分的。最后一个作为系统LaunchDaemon(使用KeepAlive)运行,另一个作为用户LaunchAgent运行,并让它们通过IPC进行通信,以便您可以访问您需要执行的每个活动所需的上下文。是的,这通常要复杂得多。更简单的解决方案往往不起作用。

当然,你必须经常问自己"是否有任何方式我可以按照Apple要求的方式做到这一点。"这意味着XPC是首选,其次是按需LaunchDaemons和LaunchAgent。如果您构建系统以使用XPC组件,您可能会在更多OS X升级中存活下来。你周围的任何工作都认为不能使用这些碎片可能需要在10.11再次修复。