Tuesday, August 21, 2012

OS X: get a list of running launchd jobs

Here's a nice easy way to get a list of running launchd jobs using PyObjC to talk to the ServiceManagement API:

from ServiceManagement import SMCopyAllJobDictionaries

print SMCopyAllJobDictionaries('kSMDomainSystemLaunchd')
So how does this compare to launchctl? On a first look its great, it provides way more information about each launchd job.
        Label = "com.apple.systemprofiler";
        LastExitStatus = 0;
        LimitLoadToSessionType = Aqua;
        MachServices =         {
            "com.apple.systemprofiler" = 0;
        OnDemand = 1;
        Program = "/Applications/Utilities/System Information.app/Contents/MacOS/System Information";
        TimeOut = 30;
But wait, I'm getting different results:
$ sudo launchctl list | grep airport
- 0 com.apple.airport.updateprefs
- 0 com.apple.airportd
$ sudo python print_daemons.py | grep airport
So what is launchctl doing different? Why am I missing airportd and other services? I spent some time reading the source, but that didn't help. I finally realised this was a execution context issue.
$ sudo /usr/libexec/StartupItemContext python print_daemons.py | grep airport
        Label = "com.apple.airportd";
            "com.apple.airportd" = 0;
        Program = "/usr/libexec/airportd";
        Label = "com.apple.airport.updateprefs";
            "com.apple.airport.updateprefs" = 0;
            "com.apple.airport.wps" = 0;
The launchd jobs are running in the System context (there are a bunch of others, see table 1 here), and can't see jobs running in other contexts. This also means that if we use StartupItemContext as above to run in the System context, we're going to miss jobs that have set LimitLoadToSessionType to something else, as with the systemprofiler job, which only runs in the Aqua (GUI) context.
$ sudo /usr/libexec/StartupItemContext python print_daemons.py | grep systemprofiler
$ sudo python temp.py | grep systemprofiler
        Label = "com.apple.systemprofiler";
            "com.apple.systemprofiler" = 0;

No comments: