How To Use '`launchctl print`' as a Replacement for '`launchctl bslist`?'
Solution 1:
Short answer
Use:
bash -c "if [ \$(id -u) -eq 0 ]; then domain=system; else domain=\"user/\$(id -u)\"; fi; launchctl print \$domain | sed -e '1,/endpoints = {/d' -e '/}/,\$d' -e 's/.* \([A|D]\)\( *\)\(.*\)/\1 \3/'"
If you prefer a script, create a file, for example /usr/local/bin/bslist
, with these contents:
#!/bin/bash
if [ $(id -u) -eq 0 ]; then
domain=system
else
domain="user/$(id -u)"
fi
launchctl print $domain | sed -e '1,/endpoints = {/d' -e '/}/,$d' -e 's/.* \([A|D]\)\( *\)\(.*\)/\1 \3/';
and make it executable: chmod a+x /usr/local/bin/bslist
. (See the end of this post for an explanation of how the script works.)
Note that both the command and script above fully support sudo
:
-
To the get the output equivalent to running
sudo launchctl bslist
, simply prependsudo
:sudo bash -c "if [ \$(id -u) -eq 0 ]; then domain=system; else domain=\"user/\$(id -u)\"; fi; launchctl print \$domain | sed -e '1,/endpoints = {/d' -e '/}/,\$d' -e 's/.* \([A|D]\)\( *\)\(.*\)/\1 \3/'"
sudo /user/local/bin/bslist
. -
To get the output for a different user
<user>
, that is, the outputsudo -u <user> launchctl bslist
would produce, prependsudo -u <user>
instead.
(Tested in macOS 10.15 "Catalina" and OS X 10.10 "Yosemite".)
Long answer
The long gone bslist
bslist
was removed with OS X 10.10 "Yosemite". According to OS X 10.9 Mavericks' man page of launchctl, bslist
(...) prints out Mach bootstrap services and their respective states. While the namespace appears flat, it is in fact hierarchical, thus allowing for certain services to be only available to a subset of processes. The three states a service can be in are active ("A"), inactive ("I") and on-demand ("D").
Typical output is:
A com.apple.finder.ServiceProvider
D com.apple.udb.system-push
D com.apple.systemprofiler
A com.apple.systemuiserver.ServiceProvider
A com.apple.dock.server
[...]
where:
- the first column is the bootstrap service state (
A
for "Active" andD
"On-demand") - the second column is the name of the bootstrap service
print
, the new kid in town
Apple replaced bslist
with an enhanced subcommand: print
.
Why enhanced? As nicely explained here, bootstrap services are arraged in a hierarchical namespace. While bslist
hides this complexity from the user by making the following assumptions:
-
When run as root (whether it is via a root shell or
sudo
),bslist
outputs the system-wide domain. - When run from as a non-privileged user, the target is assumed to be the per-user domain for that current user.
print
takes another approach: it gives the user a finer control on the output by accepting the desired domain as an argument (see the man page of launchctl for details).
Making print
behave like bslist
Luckily, after running bslist
in OS X 10.9 "Mavericks" and print
in OS X 10.10 "Yosemite" multiple times and comparing the output, I can confirm that all information provided by bslist
is contained in print
:
- The system-wide domain printed by
bslist
when run as root can is provided by thesystem
option in the endpoints array. - The per-user domain is provided by
print
with theuser/<UID>
option, also in the endpoints array.
The exact commands are provided above in the short answer section of this post, here I revisit the script (with comments) for a better understanding of what it does:
#!/bin/bash
# Compare the user UID (from command "id -u") with 0
if [ $(id -u) -eq 0 ]; then
# If the user is root (that is, the user UID is 0), request
# the "system" domain
domain=system
else
# Otherwise request the user domain
domain="user/$(id -u)"
fi
# Run launchctl
launchctl print $domain |\
# Remove the output before "endpoints = {"
sed -e '1,/endpoints = {/d' \
# Remove the output after "}"
-e '/}/,$d' \
# Remove the port information and format the output as bslist
-e 's/.* \([A|D]\)\( *\)\(.*\)/\1 \3/';
A few words on bootstrap services
This answer deals with bootstrap services, but, what are they?
macOS uses a hybrid kernel, called XNU, that combines the Mach kernel developed at Carnegie Mellon University with components from FreeBSD and a C++ API for writing drivers called IOKit.
Interprocess communication (IPC) plays a large role in the Mach component of the kernel. The Mach implementation of IPC relies on the notion of "ports".
In Mach IPC, ports are somewhat similar to TCP and UDP ports: in the same way that a process requires the TCP/UDP port of a resource on the network to be able to communicate with it, processes communicating over Mach IPC need to know the port of the desired service. This information is provided by the bootstrap server, which is one of the functions of the launchd
process.
So, in this oversimplified analogy, the bootstrap server plays a role roughly equivalent to /etc/services
.
As with the /etc/services
file, the bootstrap server maintains a list of ports and names. You can get a list of them with launchctl print
, just look for the endpoint array section, for example:
port: 0x3e607
name: com.apple.dock.server
Stretching the analogy, the difference between the services file and Mach IPC is that, while /etc/services
is static, the list of ports and names the bootstrap server maintains is dynamic, as services can request to be added to it.
And that brings us back to the original question: Bootstrap services are simply services registered with the bootstrap server.
References
If you are interested in the macOS launch process, Mach IPC, launchd
and its internals, you may find these references useful:
See Mach Bootstrap Basics and Mach Messaging and Mach Interprocess Communication (IPC) for more information on bootstrap basics and IPC.
See Kernel Architecture Overview for more information on the architecture of the macOS kernel.
See Mach Overview for an overview of the Mach component of the macOS kernel.
See Mac OS X For Unix Geeks and The Alpha and the Omega - launchd for an overview of the startup process in macOS.
See LAUNCHCTL 2.0 SYNTAX for a discussion about changes in the launchctl
syntax.
See Mach Message and Bootstrap Server on OS X for an overview of Mach messaging and the bootstrap server.
See the source code of the bslist subcommand (look for bslist_cmd
) for an insight on launchctl
. You can download launchd
tarballs from here.
See macOS IPC Man in the Middle for a presentation on implementation flaws in Mach IPC.