0

I'm writing an installer for my launch daemon, and for a launch agent, that will run in every logged in user session on macOS. The installer will be running as an admin, and thus I can install and start my launch daemon as such:

launchctl load /Library/LaunchDaemons/com.example.MyDaemon.plist

and stop it as such:

launchctl unload /Library/LaunchDaemons/com.example.MyDaemon.plist

The issue is that I need to run (and stop) my launch agent right after installation (and un-installation) in every logged in user session, as it doesn't seem to happen automatically until I log off and log back in.

I placed my launch agent into:

/Library/LaunchAgents/com.example.MyAgent.plist

But how do I start/stop it from a root user process?

PS. Both plists have RunAtLoad and KeepAlive set to true.

c00000fd
  • 20,994
  • 29
  • 177
  • 400
  • Can you give the list of commands you have run (with which user), and expected results ? Maybe also post the content of plist. – Philippe Feb 26 '23 at 18:00
  • @Philippe I can start my launch agent by running `launchctl load /Library/LaunchAgents/com.example.MyAgent.plist` as a user. But it starts it only for that specific user. Plus, I don't know how to do it from a root. – c00000fd Feb 26 '23 at 18:30
  • As `root`, you can try `sudo -u your-user launchctl load /Library/LaunchAgents/com.example.MyAgent.plist` – Philippe Feb 26 '23 at 18:36
  • @Philippe OK, thanks. that's one solution. But then I need to get the list of all the logged in users. How do you do that? – c00000fd Feb 26 '23 at 19:54
  • Try this command `last | awk '/still logged in/{print $1}' | sort -u` – Philippe Feb 26 '23 at 20:06
  • @Philippe: hmm. can you please explain what it does? – c00000fd Feb 26 '23 at 20:35
  • Also, just tried your suggested `sudo -u your-user launchctl load ...` and received: Load failed: 5: Input/output error Try running `launchctl bootstrap` as root for richer errors. – c00000fd Feb 26 '23 at 20:41
  • `last ...` command gets the list of all the logged in users. Message `Load failed` means it's already loaded. – Philippe Feb 26 '23 at 21:04

1 Answers1

1

I realise this is not a direct answer to the exact question you're asking, but may solve your underlying problem. It sounds like you have a launch daemon and N launch agents for N user sessions running, and presumably the launch agents have checked in with the launch daemon via some IPC mechanism (XPC?)? Via this IPC channel, you could have the central launch daemon send out a message to the agent instances which causes them to exit. Depending on the exit code and the launchd plist, launchd will either restart them or not. The exact logic as to when this happens is up to you and you'll want to be careful not to end up in a restart loop of course. (This doesn't solve the initial agent startup after installation though.)

pmdj
  • 22,018
  • 3
  • 52
  • 103
  • 1
    I'm using lower level mach messages instead of XPC. But otherwise, yes, I can signal all launch agents to quit. The issue is that I have `KeepAlive` set to true in the plist file that will simply restart them. (I need this in case one of them crashes, which is kinda helpful.) So I didn't realize that an exit code will dictate the launchd what to do next. Am I supposed to return 0 to have launchd not restart it, or what? – c00000fd Feb 27 '23 at 09:27
  • 1
    The `KeepAlive` property can be more than just a boolean. Set it to [a dictionary containing a `SuccessfulExit` key](https://www.unix.com/man-page/OSX/5/launchd.plist/) to control when launchd restarts it. I usually set `SuccessfulExit` to `false` so that the agent is restarted if it crashes or if I manually return a non-zero exit code from it; launchd will NOT restart it if it exits with a code of zero. (But note that your agent should run for at least 10 seconds before exiting with code zero, or launchd might restart it anyway!) – pmdj Feb 27 '23 at 09:33
  • Aha, interesting. I didn't know that. Thanks. So what about running starting it on demand in all log-in user sessions? – c00000fd Feb 27 '23 at 09:55
  • I'm not aware of a way to launch a newly installed agent in all existing user sessions. (That doesn't mean it's not possible of course. If nobody else comes up with a good solution you could always try asking Apple's DTS by filing a TSI, although I suspect they will recommend your installer prompt the user to reboot the Mac.) – pmdj Feb 27 '23 at 10:07
  • I [came up with a way](https://stackoverflow.com/a/75582697/843732) to list logged in user names. Can you check if it is close to how it could be done? If so, I can use it to launch `launchctl load` via `sudo -u` - just a guess at this point. – c00000fd Feb 27 '23 at 15:56