My application is launching under root and I need to be able to unload processes using NSTask and launchctl Here is a code I do:
NSPipe *pipe = [NSPipe pipe];
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath: @"/bin/launchctl"];
[task setCurrentDirectoryPath:@"/"];
[task setStandardError:pipe];
NSLog(@"/bin/launchctl unload %@", plistAutostartLocation);
NSArray *arguments;
arguments = [NSArray arrayWithObjects: enableCommand, plistAutostartLocation, nil];
[task setArguments: arguments];
NSFileHandle * read = [pipe fileHandleForReading];
[task launch];
[task waitUntilExit];
If process need to be unload is launched under "root" then it unloads successfully if not the fails. The question is how to run "launchctl" under specific user (e.g. "myusername")?
Edit: In terminal if I want to run some command under specific user I do next and it works well:
su - myusername -c "ls /Users/myusername"
But when I try to run "launchctl" under specific user it fails:
su - myusername -c "launchctl load /Library/LaunchAgents/com.google.keystone.agent.plist"
It says: "nothing found to load"
The failing of your last command is related to bootstrap namespaces, you are trying to load the agent in the wrong bootstrap namespace. The system is creating two different bootstrap namespaces, excerpt from Apple documentation:
It's worth noting the distinction between GUI and non-GUI per-session bootstrap namespaces. A GUI per-session bootstrap namespace is instantiated by the GUI infrastructure (
loginwindow
andWindowServer
) when a user logs in via the GUI. A non-GUI per-session bootstrap namespace is created when a user logs in via SSH. While there is no fundamental difference between these namespaces, GUI-based services, like the Dock, only register themselves in GUI per-session bootstrap namespaces.
The su
command is not launched in the same bootsrap namespace used by launchd
.
There are two ways to run a command like the ones you want to run in the correct bootstrap namespace:
10.10 and above: use launchctl asuser
. This will run any command as it was launched by the specified <myusername>
. It is worth to mention that you must run this as root, otherwise the command will fail. Your last command should be run like this:
launchctl asuser <myusername> launchctl load "/Library/LaunchAgents/com.google.keystone.agent.plist"
10.10 and below (since 10.11, SIP blocks this method): use launchctl bsexec
. This requires a process id to retrieve the correct namespace in which to run another command. Also, you have to change the UID of the command manually, like this:
launctl bsexec <pid> su -u <myusername> launchctl load "/Library/LaunchAgents/com.google.keystone.agent.plist"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With