Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Launching app from root account

I am developing a Cocoa GUI app that has an Objective-C daemon. The daemon is launched by LaunchDaemon, the GUI is launched using loginItems for each user.

When an update is deployed I need to update the daemon, which is simple, and update the GUI. I would like to be able to exit the GUI, replace the app, and relaunch it on each user account that it is currently running on. I would like to do all this from the daemon which of course is running as root.

How can I either: 1) as root, quit and then re-launch an app in another user's interface? 2) as root, quit and then re-launch a particular loginItem for each user currently logged it?

I have tried searching and there are lots of discussions including this similar question, but there doesn't appear to be a working solution available.

Any help is greatly appreciated.

like image 280
Dave Avatar asked Dec 14 '25 22:12

Dave


1 Answers

I believe NSDistributedNotificationCenter should work for this. Note that using NSDistributedNotificationCenter to communicate between processes in different user accounts does not, in and of itself, require root privileges.

To help with coordination between user accounts, it might help to distinguish which instance of the GUI app and daemon are currently active and in control, and which instances are passive. You can use NSWorkspace's notifications (NSWorkspaceSessionDidBecomeActiveNotification, NSWorkspaceSessionDidResignActiveNotification) to determine when a user switches between user accounts, etc. and have your instances set themselves accordingly.

Say your GUI app and daemon have instances running in 3 different user accounts. If in the active user account, you want to begin the update process, you could use NSDistributedNotificationCenter to easily tell all other instances to shutdown immediately, for example. To do that, you'd define something like the following.

In an .h file, declare the names of your different notifications:

extern NSString * const MDShouldTerminateImmediatelyNotification;

in (an) implementation file, create the names, and set the class up to be interested in a distributed notification by that name, etc.:

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];
    }
}

In the class that would initiate the update process, you'd do something like this to send the notification:

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

}

That should at least be a beginning to work with, I'd think....

Actually, if you are talking about having one single daemon instance running as root that does everything in all user accounts, you may need to consider factoring that part out into a Launchd Agent type process (background process, runs at user level, each user account would have its own instance).

For more info:

Technical Note TN2083 Daemons and Agents

Root and Login Sessions

Creating launchd Daemons and Agents

like image 196
NSGod Avatar answered Dec 16 '25 22:12

NSGod



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!