Search code examples
objective-cmacosservicelaunchctl

Enable, disable and start services programmatically in macOS


I am writing a program that comes with a service. What I did so far is to create a helper tool that can run elevated tasks for my process and can communicate via XPC.

My program comes bundled with a service and I want to use the helper tool to install and start/stop this service so my program can have a checkbox "start service with system" in the settings.

I can successfully copy the plist for the service, but I cannot find any way to enable, disable, start or stop the service programmatically. I think the solution to call system("launchctl load /path/to/service.plist"); pretty ugly. Is there any mechanism in objective C to accomplish this task and get a success or failed result?


Solution

  • Apple has a deprecated C API for starting, stopping, and enabling launchd services in launch.h. The source code for the API is on their opensource site: https://opensource.apple.com/source/launchd/launchd-442.26.2/liblaunch/

    Here's some sample code that asks launchd to start the LittleSnitchUIAgent service:

    #include <launch.h>
    
    int main(int argc, const char * argv[]) {
        const char *job = "at.obdev.LittleSnitchUIAgent";
        launch_data_t resp, msg;
        msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
        launch_data_dict_insert(
            msg, launch_data_new_string(job), LAUNCH_KEY_STARTJOB);
        resp = launch_msg(msg);
        launch_data_free(msg);
        return 0;
    }
    

    The LittleSnitchUIAgent isn't signification -- I chose it at random from my local list of services. I left error checking out of the sample to keep it straight forward.

    If you haven't already I would recommend giving the launchd man pages and the Daemons and Services Programming Guide a very close study. Launchd can start your processes in response to almost anything: a timer, a socket connection, a device being added to the system, among many others. It's rare that you actually need to manage your own services. I haven't been able to confirm this but I suspect that's why they've deprecated the API.