Scheduling With LaunchD on MacOS

Mac OS LaunchD

I’m working on setting up some scheduled tasks to backup select files to my NAS from my MacOS desktop. Since MacOS keeps deprecating various unix utilities, I checked to see if cron was still supported, and while it still works, it has officially been deprecated in favor of LaunchD. This started an adventure.

Since I like to keep things supported I figured I’d do a quick LaunchD service and be done, but unfortunately my google fu failed to find any official documentation that on it. I was left with a smattering of how to guides with no dates associated.

After an hour or so of struggling with poor logging, bad documentation, and deprecated options, I finally got it working. Below are the steps I used to get it working.

Create a plist file

LaunchD runs off plist files, below is sample

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plist version="1.0">

	<dict>

	 <key>Label</key>

		<string>com.mkmarshallhome.footage_backup</string>

		<key>Program</key>

		<string>/Users/matt/bin/backup_footage.sh</string>

		<key>StartCalendarInterval</key>

		<dict>

			<key>Hour</key>

			<integer>1</integer>

			<key>Minute</key>

			<integer>0</integer>

		</dict>

    </dict>

</plist>

This goes in the $HOME/Library/LaunchAgents directory, make sure the filename has the plist exentions.

I also strongly reccomend running plutil <plist file>

Add to LaunchD

There are a couple of ways to add items to LaunchD, unfortunately the most documented items have been deprecated. The new way to add items is as follows

# Enable Plist
launchctl enable <service targe>

Service Target is not the name of the plist file of course, it is prepended by the following strings gui/$UID/ so in this example it would be

launchctl enable gui/501/$HOME/Library/LaunchAgents/com.mkmarshallhome.footage_backup.plist

Test the Agent

To test the agent run the following command

# Run agent
launchctl kickstart <service target>

However Service target is now just

gui/501/com.mkmarshallhome.footage_backup.plist

Troubleshooting

While hopefully this will work for you, if it does not the troubleshooting process for this is cryptic.

The best way to see what the error is is to run the command launchctl list which will produce output like

> launchctl list 
PID Status Label
...
- 0 com.mkmarshallhome.footage_backup
...

The first column is the PID if it is currently running, and the status is the exit code from the last run.

I haven’t found the documentation for the status codes yet, other than random posts on Stack Overflow.

However, 78 means “Function not implemented”. In my case this was because my script did not start with the #!/bin/bash line.

There is also a tool called Launch Control which provides help, however it is paid with a limited trial.

References

https://www.reddit.com/r/MacOS/comments/kbko61/launchctl_broken/

https://stackoverflow.com/questions/34215527/what-does-launchd-status-78-mean-why-my-user-agent-not-running

comments