15

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?

6 Answers 6

6

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 ....

2
  • Thanks, putting the command into an extra shell file and launching that did the trick. It’s a very unsatisfactory solution though … why doesn’t invoking the command directly work? By the way, launchctl list did display 1, but only after I started the agent manually using launchctl start. Apr 14, 2010 at 12:04
  • I am not positive, but I think the launchd .plist files are really just intended for defining 'launch-on-demand' criteria for daemons...Perhaps it was not sure what to do with the arguments you had passed in <key>ProgramArguments</key>.
    – CaseyIT
    Apr 14, 2010 at 12:27
12

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.

2
  • Thanks for the info. However: (1) I’ve already read all the documents you linked above, and several more. Nowhere does it actually say how to launch an agent. (At least, I didn’t find it anywhere.) That would be fine, if my intuitive approach were working. (2) Changing the file name doesn’t work either. :-( (3) some of the information are outdated. For example, they suggest the command launchd bash for debugging – but this doesn’t work on Leopard (launchd cannot be launched directly). Apr 14, 2010 at 11:06
  • @Konrad Rudolph: You're welcome: :) @Skylarking gets some interesting points: did you check the file's premission? Or used the sudo command? I also had to reboot sometimes for launchctl to work properly.
    – Arko
    Apr 14, 2010 at 11:57
4

I can't find documentation that this is actually standard behavior, but it seems that launchd requires absolute paths in plist files. So try /usr/bin/rsync instead. Works for me!

0

try this, my scripts work without using the program part, just program args...

replace

    <key>Program</key>
    <string>rsync</string>
    <key>ProgramArguments</key>
    <array>
        <string>-ar</string>
        <string>/path/to/folder/</string>
        <string>/path/to/backup/</string>
    </array>

with

    <key>OnDemand</key>
    <true/>
    <key>ProgramArguments</key>
    <array>
        <string>rsync</string>
        <string>-ar</string>
        <string>/path/to/folder/</string>
        <string>/path/to/backup/</string>
    </array>
0

try to add this keys to your plist file

    <key>KeepAlive</key>
    <true/>
    <key>RunAtLoad</key>
    <true/>
0

You have one wrong thing in your .plist file, and one dodgy thing (each of these points has been touched upon in earlier answers; I'm bringing them together here).

You'd be better writing:

<key>ProgramArguments</key>
<array>
  <string>/usr/local/bin/rsync</string>
  <string>-ar</string>
  <string>/path/to/folder/</string>
  <string>/path/to/backup/</string>
</array>

The first argument in the ProgramArguments array is the program to be executed – you'd omitted this. If the Program key is omitted, then it defaults to the first argument of ProgramArguments; it's probably wise to specify this only once.

Because you omitted this first argument, your .plist will have invoked rsync (through being named in Program), but rsync's 'first argument' would have been /path/to/folder, and not -ar (the running program will have been very briefly visible in ps output, before it exited with an error, but named as -ar, which is the content of the zeroth argument).

You don't have to include the path to rsync, but in this sort of context, it's probably prudent to do so, to avoid having to rely on the PATH being set appropriately.

The documentation for this is in launchd.plist(5). Note that that manpage stresses that the value of the ProgramArguments key is passed to execvp(3). It's the execvp manpage that explains about the PATH searching.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .