launchd
For services running in the background (or foreground), macOS uses launchd (think cron jobs on Linux or scheduled tasks on Windows).
Legacy Subcommands
If you’ve been managing Macs for a while, you may be familiar with a particular syntax for loading launchd.
For launch agents (usually run as user), you may typically have launched them with
launchctl load /Library/LaunchAgents/com.domainname.app.plist
For launch daemons (usually run as root), you may typically have launched them with
sudo launchctl load /Library/LaunchDaemons/com.domainname.app.plist
If you read the manual for launchctl (man launchctl
), you’ll see load
and unload
listed as legacy subcommands:
Legacy subcommands should still work. I don’t believe they’re fully deprecated (at least as of this writing).
“New” subcommands
But there are now subcommands that aren’t legacy:
For a super-comprehensive breakdown on what all these “new” subcommands are, you may want to check out Babo D’s Launchctl 2.0 Syntax post (from 2016!), but I thought I’d just do a quick breakdown here of the basics.
launchctl subcommand basics
Don’t come for me. As I mentioned above, there are far more comprehensive breakdowns of launchctl
subcommands. This is just the basics. Not much nuance. Just how do you do it if you’ve been doing it the “legacy” way this whole time.
Listing with launchctl
With legacy subcommands, to get launch agents, you’d run
launchctl list
and that would give you a list of launch agents that are running.
With the “new” subcommands, you would do something like
launchctl print gui/501
Well, that’s assuming your uid is 501, which it may not be. If you want to find your uid, you can use id -u
. If you want to find the uid of a specific other user account, you can use id -u username
. You could also find the uids of a bunch of users by running dscl . -list /Users UniqueID | grep -v _
With legacy subcommands, to get launch daemons, you’d run
sudo launchctl list
or run launchctl list
as root (e.g., via Munki or Jamf).
With the “new” subcommands, you would do
launchctl print system
The nice thing about doing that is you’re specifying system
, so it doesn’t matter if you run it as root or as user—you’ll just get the system (root-level) launchd.
With either type of listing type, you won’t just get a list of process IDs and labels (you will still get those under services
), but you’ll also get a list of what are called disabled services
, which is a bit confusing, because that list will include both disabled and enabled services.
So, for example, for Nudge, you might see something like
0 0 com.github.macadmins.Nudge
under services
but then something like
"com.github.macadmins.Nudge" => enabled
under disabled services
.
You’ll probably find ways to parse the output, but just be aware there is this note in man launchctl
:
IMPORTANT: This output is NOT API in any sense at all. Do NOT
rely on the structure or information emitted for ANY reason. It
may change from release to release without warning.
Launching launch agents
Instead of running
launchctl load /Library/LaunchAgents/com.github.macadmins.Nudge.plist
you’d run something like
launchctl bootstrap gui/501 /Library/LaunchAgents/com.github.macadmins.Nudge.plist
Launching launch daemons
Instead of running
sudo launchctl load /Library/LaunchDaemons/com.github.macadmins.Nudge.logger.plist
you’d run something like
sudo launchctl bootstrap system /Library/LaunchDaemons/com.github.macadmins.Nudge.logger.plist
Obviously, if you’re running this in a script from a root-run management tool (e.g., Munki or Jamf), you wouldn’t preface commands with sudo
.
Unloading launch agents
Instead of running
launchctl unload /Library/LaunchAgents/com.github.macadmins.Nudge.plist
you’d run something like
launchctl bootout gui/501/com.github.macadmins.Nudge
Unloading launch daemons
Instead of running
sudo launchctl unload /Library/LaunchDaemons/com.github.macadmins.Nudge.logger.plist
you’d run something like
sudo launchctl bootout system/com.github.macadmins.Nudge.Logger
Reminder: don’t preface with sudo
in root-run scripts.
Disabling a launch daemon or agent
Instead of bootout
, you would use disable
to disable a launch daemon or agent. Example:
sudo launchctl disable system/com.github.macadmins.Nudge.Logger
Just be careful with this. If you disable it, you can’t then just bootstrap
it right afterwards:
sudo launchctl bootstrap system /Library/LaunchDaemons/com.github.macadmins.Nudge.logger.plist
Bootstrap failed: 5: Input/output error
First, you want to re-enable it:
sudo launchctl enable system/com.github.macadmins.Nudge.Logger
Then you can bootstrap it:
sudo launchctl bootstrap system /Library/LaunchDaemons/com.github.macadmins.Nudge.logger.plist
That’s all I’ve got for now. As I mentioned earlier, you can read a more comprehensive breakdown at Launchctl 2.0 Syntax.
Leave a Reply