3

man launchctl' remarks that:

LEGACY SUBCOMMANDS
     Subcommands from the previous implementation of launchd are generally available,
     though some may be unimplemented. Unimplemented subcommands are documented
     as such.

 bslist [PID | ..] [-j]
     This subcommand is not implemented and has been superseded by the print
     subcommand, which provides much richer information.

at least as of OS X v10.11.x 'El Capitan.' (Presumably, this was also the case in v10.10.x 'Yosemite,' as that was the OS release that first included 'launchd 2.0,' if I'm reading/recalling my history correctly.) What arguments, then, would one pass to 'launchctl print' to get output like what the 'bslist' sub-command used to provide? Would you need to filter it any (using grep, sed, awk, etc.) to get the desired result(s)?

('launchctl print system' spews a bunch of data out, but I'm not clear on whether that includes the same information the 'bslist' sub-command would have output in the past or, if so, where in the former's output said information might be. Its 'endpoints' key contains a list similar to the example provided in Listing 1 in the 'Mach Bootstrap Basics' section of this old, outdated Apple documentation on 'Daemons and Agents,' but I'm uncertain if that's what I'm looking for, particularly since it contains a couple extra columns.)

nohillside
  • 100,768
  • 1
    Well, what exactly are you looking for, which attributes/properties do you want to see? Or are you asking for a documentation of the output you get from launchctl print? – nohillside Aug 11 '20 at 12:12
  • @nohillside: What 'launchctl bslist' used to print as described in the old documentation I linked. Quoting from there, it states, "…you can run launchctl with the bslist argument. This lists all of the services registered with the bootstrap service." – RandomDSdevel Aug 11 '20 at 13:52
  • Could you just use launchctl list as mentioned here? If it is active it will have a UID else not which covers the bslist status A. It does show more services though - see How to show all running launchctl daemons/agents? so perhaps it isn't exactly what you want. This question looks like a duplicate of this unanswered question incidentally: Get a list of ALL services running and not and whether or not they should be running – lx07 Aug 14 '20 at 09:00
  • @lx07: Admittedly, yes; my question is sort of a duplicate of that other one you linked last — which, I should confess, I actually saw before while searching to see if anybody'd asked a similar one to this one in the past —, though it isn't an exact duplicate. Unlike that user, I'm only looking for a list of all registered Mach bootstrap services, as opposed to any particular process. Whether that makes my question distinct enough to get posted separately is something I wasn't entirely sure about and hence decided to leave up in the air. – RandomDSdevel Aug 15 '20 at 16:34
  • OK, so if 'A' means 'active,' what do the other letters stand for? ('D' for disabled, maybe…?) Is this still documented anywhere? – RandomDSdevel Aug 15 '20 at 16:35
  • (Question edited to clarify what I meant by the 'similar output' available from 'launchctl print system.') – RandomDSdevel Aug 15 '20 at 19:14

1 Answers1

6

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 prepend sudo:

    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 output sudo -u <user> launchctl bslist would produce, prepend sudo -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" and D "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 the system option in the endpoints array.
  • The per-user domain is provided by print with the user/<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.

jaume
  • 15,010