Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
launchctl/launchd cheat sheet

I've never had great understanding of launchctl but the deprecation of the old commands with launchctl 2 (10.10) has been terrible as all resources only cover the old commands, and documentation for Apple utilities is generally disgracefully bad, with launchctl not dissembling.

Mad props to https://babodee.wordpress.com/2016/04/09/launchctl-2-0-syntax/ which contains most details

domains

Internally, launchd has several domains, but launchctl 1 would only ask for service names, inferring the domain based on context. This made for straightforward commands (once you've loaded a plist you just use the service name it specifies) but had rough edge cases or odd behaviours.

Launchctl 2 separates service names, domain targets and service targets:

  • a service target is <domain-target>/<service-name> and used to point to most services
  • a service name is what is specified in the plist file
  • a domain target is a namespace for services, each namespace has specific behaviours associated:
    • system is privileged (runs services as root) and requires root for interaction
    • user/<uid> runs as that user, but does not require that the user be logged in
    • gui/<uid> runs as that user, but is only active when the user is logged in at the GUI

important commands

bootstrap <domain-target> <paths...>

The paths can be plist files, XPC bundles, or directories of them. Each plist or bundle is loaded into the specified domain.

bootout <service-target> | <domain-target> <paths...>

Unloads the specified service(s).

WARNING

The paths are actually optional, you can unload an entire domain, which you probably should not do.

enable <service-target> | disable <service-target>

Marks the service as runnable (or not), allows overriding a Disabled plist key. Behaviour is a bit odd and I haven't looked much into it, you may need to bootstrap a service (it will complain that the service is disabled), enable it, then bootstrap it again.

kickstart <service-target>

Starts a service. -k will kill then restart existing instances.

Supposedly -p will print the service's pid (even if it's already started), doesn't seem to work for me.

print <service-target>

Dumps the service's definition, properties & metadata.

WARNING

The output of print is not officially structured, do not rely either on the format or on the information.

print <domain-target>

Prints the domain's metadata, including but not limited to all services in the domain.

kill <signame | signum> <service-target>

Sends a signal to a service's process (without having to look it up manually).

@fantix
Copy link

fantix commented May 3, 2021

I think it's bootstrap?

Loading

@masklinn
Copy link
Author

masklinn commented May 8, 2021

Sure, probably.

Loading

@mailinglists35
Copy link

mailinglists35 commented Jun 30, 2021

$ launchctl list|egrep -i 'team'
81131   -9      com.teamviewer.service
76878   -9      com.teamviewer.desktop
76955   -9      com.teamviewer.teamviewer

how do I gracefully terminate these with launchctl? very unclear and confused what command should use

$ sudo launchctl bootout system/com.teamviewer.service
Boot-out failed: 3: No such process
$ sudo launchctl bootout user/501/com.teamviewer.service
Boot-out failed: 3: No such process
$ sudo launchctl bootout gui/501/com.teamviewer.service
Boot-out failed: 36: Operation now in progress
$ sudo launchctl kill 15 system/com.teamviewer.service
Password:
Could not find service "com.teamviewer.service" in domain for system
$ sudo launchctl kill 15 gui/501/com.teamviewer.service
Could not find service "com.teamviewer.service" in domain for login: 100009
$ sudo launchctl kill 15 user/501/com.teamviewer.service
Could not find service "com.teamviewer.service" in domain for uid: 501

Loading

@tqwhite
Copy link

tqwhite commented Aug 22, 2021

Please!! Someone answer mailinglists35's question.

I have exactly the same experience with a process of my own. I can load/unload it but cannot find any way to make the un-deprecated commands touch it in any way.

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment