How to register an agent with launchd

I’m unable to schedule a periodic launch with launchctl/launchd on OS X (Leopard). Basically, I’m unable to find a step-by-step list of instructions on the web and the intuitive approach doesn’t work.

The sync.plist file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Label</key>
        <string>net.madrat.utils.sync</string>
        <key>Program</key>
        <string>rsync</string>
        <key>ProgramArguments</key>
        <array>
            <string>-ar</string>
            <string>/path/to/folder/</string>
            <string>/path/to/backup/</string>
        </array>
        <key>StartInterval</key>
        <integer>7200</integer>
    </dict>
</plist>

I’ve put this script inside the path ~/Library/LaunchAgents.

Next, I’ve registered the script using

launchctl load ~/Library/LaunchAgents/sync.plist

Finally, to test that it works, I started the job:

 launchctl start net.madrat.utils.sync

– Nothing happened. Manually executing the rsync command in the terminal yields the expected result.

I’m fairly sure that the job was registered correctly because if I try to start a non-existing job, I get an error message (which I didn’t get in the above command).

What did I do wrong?


Solution 1:

Lingon is a good GUI tool to manage launchd. The project appears to be unsupported now... but it definitely still works on 10.5.x.

But to your specific problem... have you tried

sudo launchctl list 

This will tell you if the .plist is firing correctly. It'll return 1 if the daemon is not lauching , and a '0' if it is successful. Maybe look for that.

Whenever I see a '1' it's usually because I've put the script in the wrong place, made a typo or have set permissions incorrectly.

Also.... reboot often .. I've seen

launchctl start

not be effective where a reboot was ..

Also, in looking at your question closer....why not just put that rsync code into a bash script...and stick it in /usr/bin/..... Then you could just chmod+x that file....and simplify your .plist to fire that script whenever you like ....

Solution 2:

Long answer:

It is hard to work with launchd without understanding some basic principles. So it is likely you won't find any step-by-step instruction, it has so much capabilities. A good move is to head for the getting started guide on the ADC: http://developer.apple.com/macosx/launchd.html

You can also read the man pages for launchd, launchctl and the .plist files syntax, launchd.plist.

There's a frequent misunderstanding on where to put your agent or deamon, so let me push some info about it here:

  • If your job needs to run even when no users are logged in, put it in /Library/LaunchDaemons.
  • If it is only useful when users are logged in, put it in /Library/LaunchAgents, or in the personal LaunchAgents directories of specific users (~/Library/LaunchAgents).
  • Do not put your job in /System/Library, which is reserved for system-provided daemons.
~/Library/LaunchAgents         Per-user agents provided by the user.
/Library/LaunchAgents          Per-user agents provided by the administrator.
/Library/LaunchDaemons         System wide daemons provided by the administrator.
/System/Library/LaunchAgents   Mac OS X Per-user agents.
/System/Library/LaunchDaemons  Mac OS X System wide daemons.

Short answer:

The name of your plist file may be wrong, can't test right now but I would have set it to net.madrat.utils.sync.plist. It may be also useful to first unload your deamon before loading it if you edited the file.