从root帐户启动应用程序

时间:2010-11-30 22:10:45

标签: objective-c cocoa launchd

我正在开发一个具有Objective-C守护程序的Cocoa GUI应用程序。守护进程由LaunchDaemon启动,GUI使用loginItems为每个用户启动。

部署更新时,我需要更新守护程序,这很简单,并更新GUI。我希望能够退出GUI,替换应用程序,并在当前运行的每个用户帐户上重新启动它。我想从守护进程中做到这一切,守护进程当然是以root身份运行。

我怎么能: 1)以root身份退出然后在另一个用户界面重新启动应用程序? 2)以root身份退出,然后为当前登录的每个用户重新启动特定的loginItem?

我尝试过搜索,有很多讨论,包括similar question,但似乎没有可行的解决方案。

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:3)

我相信NSDistributedNotificationCenter应该为此工作。请注意,使用NSDistributedNotificationCenter在不同用户帐户中的进程之间进行通信本身并不需要root权限。

为了帮助协调用户帐户,可能有助于区分GUI应用程序和守护程序的哪个实例当前处于活动状态并处于控制状态,以及哪些实例是被动的。您可以使用NSWorkspace的通知(NSWorkspaceSessionDidBecomeActiveNotification,NSWorkspaceSessionDidResignActiveNotification)来确定用户何时在用户帐户之间切换等,并相应地设置您的实例。

假设您的GUI应用程序和守护程序在3个不同的用户帐户中运行实例。例如,如果在活动用户帐户中,您希望开始更新过程,则可以使用NSDistributedNotificationCenter轻松告知所有其他实例立即关闭。为此,您需要定义如下内容。

在.h文件中,声明不同通知的名称:

extern NSString * const MDShouldTerminateImmediatelyNotification;

在(a)实现文件中,创建名称,并将该类设置为对该名称等的分布式通知感兴趣:

NSString * const MDShouldTerminateImmediatelyNotification = @"MDShouldTerminateImmediately";


- (id)init {
   if (self = [super init]) {
       [[NSDistributedNotificationCenter defaultCenter]
       addObserver:self
       selector:@selector(shouldTerminateImmediately:)
       name:MDShouldTerminateImmediatelyNotification
       object:nil];
   }
   return self;
}

- (void)dealloc {
   [[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
   [super dealloc];
}

- (void)shouldTerminateImmediately:(NSNotification *)notification {
   if (ourInstanceIsInControl == NO) {
     [NSApp terminate:nil];
    }
}

在启动更新过程的类中,您可以执行以下操作来发送通知:

- (void)beginUpdate {
   [[NSDistributedNotificationCenter defaultCenter]
    postNotificationName:MDShouldTerminateImmediatelyNotification
       object:[self description] // or just nil
       userInfo:nil
       options:NSNotificationDeliverImmediately | NSNotificationPostToAllSessions];
    // continue

}

至少应该是一个开始合作,我想......

实际上,如果您正在谈论以root身份运行一个守护进程实例来执行所有用户帐户中的所有操作,您可能需要考虑将该部分分解为启动代理类型进程(后台进程,在用户级别运行,每个用户帐户都有自己的实例。

欲了解更多信息:

Technical Note TN2083 Daemons and Agents

Root and Login Sessions

Creating launchd Daemons and Agents

答案 1 :(得分:3)

因此,我使用Apple的支持请求获得最佳答案,并结合一些在线研究。

攻击的基本计划是让守护进程告诉它时每个GUI实例都重新启动。

首先,我让守护进程替换了GUI的bundle(.app文件夹)。您可以在应用仍然运行时做到这一点。这就是Apple支持的帮助。我仍然惊讶于应用程序在运行时可以被替换,但是他们告诉我这样做并且它会没问题。

然后我让守护进程向GUI发出一个DistributedNotification,并显示一条重新启动的消息。为了让GUI正确响应,我创建了重启器类,它将获取它自己的pid和bundle路径,然后我在内存中构建了一个shell脚本,杀死了pid,等了10秒然后执行了一个shell“open bundlepath.app”and it重新启动。

我使用NSTask来调用“内存”shell脚本,它实际上只是一个@“kill%@; sleep 10; open%@”,pid,bundlePath ....

工作惊人!

感谢您的建议!

答案 2 :(得分:0)

在Apple的文档中查找“授权服务”。