Looks like no one’s replied in a while. To start the conversation again, simply ask a new question.

launchd disobeying plist

I am using launchd to execute a shell script whenever any of a set of directories is modified and also when a filesystem is mounted.


The script should not run when it is loaded. It should also run only once whenever a condition for its running is satisfied.


According to my reading of the the man page for launchd.plist, I should be able to make this work with a plist that contains only Label, Program, QueueDirectories, and StartOnMount parameters.


However, in fact the script gets executed when I load the /Library/LaunchAgents directory, and it continues to do this even if I insert a false-valued RunAtLoad key into the plist. So launchd appears to be disobeying the default value of RunAtLoad and also an explicit false value of that key.


Also, once it runs the script is respawned continuously. And this happens even if I add a false-valued KeepAlive key into the plist. So launchd appears to be disobeying the default value of KeepAlive and also an explicit false value of that key.


Moreover, if I specify the script's pathname as the value of a Program key, I get an "Exec format error" message. To make the script run, I need to specify it as the only value of a ProgramArguments key. By my reading these should be equivalent. So launchd appears to be disobeying the value of a Program key.


When the script runs, it runs correctly, and, if launchd is queried about it while it is being respawned, launchd reports that its last exit status was 0.


Here is a plist that seems to at least function, though it runs on load when it should not. I'd like to know why launchd is behaving in all these ways that seem to contradict the man page.


<?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>RunAtLoad</key>

          <false/>

          <key>ProgramArguments</key>

          <array>

                    <string>/Users/Shared/Library/panlex/org.panlex.syncd.txt</string>

          </array>

          <key>LaunchOnlyOnce</key>

          <true/>

          <key>ThrottleInterval</key>

          <integer>36000</integer>

          <key>KeepAlive</key>

          <false/>

          <key>QueueDirectories</key>

          <array>

                    <string>/Topics/panlex/panlex-dics/panlex-dics-data/panlex-dics-data-todo/queued</string>

                    <string>/Topics/panlex/panlex-dics/panlex-dics-data/used</string>

          </array>

          <key>StartOnMount</key>

          <true/>

          <key>Label</key>

          <string>org.panlex.syncd.txt</string>

</dict>

</plist>

Mac Pro, Mac OS X (10.5.7), iPhone 8GB, Airport Extreme

Posted on May 5, 2012 5:28 PM

Reply
34 replies

May 6, 2012 8:32 PM in response to Jonathan Pool

org.panlex.syncd.txt sure does not look like a valid script.


I suggest reviewing you parameters. The LaunchOnlyOnce parameter doesn't look appropriate. If you are using the same value as a default setting, then get rid of it. Avoid adding both QueueDirectories and StartOnMount until you are sure one is doing what you want the way you want.

May 6, 2012 11:00 PM in response to etresoft

Yes, LaunchOnlyOnce was necessary in order to stop the script from being respawned indefinitely. But LaunchOnlyOnce went too far. It stopped the script from running again, even when the QueueDirectories condition was satisfied again.


I inserted the default keys only because launchd was not complying with the defaults. It didn't help anyway. The script continued to be respawned forever, even after KeepAlive was explicitly set to false.

May 6, 2012 11:20 PM in response to Jonathan Pool

KeepAlive set to false does not mean what you think it means - it tells launchd to restart the process immediately if the process returns with an error. Since you keep getting an exec format error, launchd keeps trying to restart the process.


QueueDirectories are tricky to use. more on that later if need be.


I'm not sure how wise it is to give a unix script a .txt extension. The system expects that a .txt file is a data file, not an executable. That's probably why you're getting an error in the first place.


LaunchOnlyOnce is only supposed to be used when it's critical that a process only run once. It's better to handle that in the script using conditionals.


it would be helpful to know what your script is trying to do - that might narrow down the problem.

May 6, 2012 11:58 PM in response to twtwtw

The exec format error occurred only when I used the Program key to specify the script. When I used ProgramArguments instead, no exec format error occurred. That's when the script kept being respawned.


The documentation says that KeepAlive set to false (or left with its default value) means that "only demand will start the job". That is what I wanted. But after the job exited successfully it kept getting restarted automatically.


If ".txt" can make a path illegal for a launchd executable, then I would hope the documentation would say so. But the program did execute, and did so correctly, with exit code 0. The problem is that launchd kept respawning it indefinitely thereafter every few seconds.


The purpose here is to synchronize a remote file repository with a local one. When the local one changes, and once a day when the local host is booted, the script (containing rsync commands) is to run, to assure that the remote repository contains copies of all and only the same files as the local one.


Thanks for your concern. Since my script is being launched now by cron and is working properly, my main interest now is to help determine whether launchd is properly documented and usable for this and other purposes.

May 7, 2012 12:31 AM in response to Jonathan Pool

launchd works fine - it's integral to the system (even cron is launchd-based in OS X, so don't think you're getting away from it). There's just something in your script or plist that's out of kilter. I suspect this is an rsync issue; rsync uses multiple sub-processes, and launchd can handle sub-process ungracefully (in order to avoid zombie processes) unless you set the AbandonProcessGroup key to true.


From what you've said, I can tell part of why your script isn't working. QueueDirectories is unsuited to rsync; QD requires that the watched folder be emptied completely before it will trigger again. you'd really want to use the WatchPaths key instead (which would trigger with every change to the folder), except that an rsync run probably takes longer than the average change period of the folder (unless it's a really dead folder), meaning that rsync would be constantly running on your machine.


If I were you, I'd forget about the StartOnMount and QueueDirectories trigger, and just run a periodic sync using StartInterval or StartCalendarInterval. It would make your life much easier.

May 7, 2012 7:18 AM in response to twtwtw

Thank you for the additional thoughts.


Are you saying that rsync launches subprocesses and dies before they do? If so, and if launchd kills the running subprocesses, then the launchd documentation doesn't tell me that launchd will treat this discovery and termination of subprocesses as an error that requires trying to run the main process again, while not disclosing anything other than a normal exit status to the user in response to a "launchctl list label" command.


As for QueueDirectories, the documentation tells me something different from what you say. You say "QD requires that the watched folder be emptied completely before it will trigger again." But the documentation doesn't say this. It says QD makes launchd "watch the paths for modifications", and that "the job will only be started if the path is a directory and the directory is not empty." So, I expect any modification to a listed path to trigger the job.


For the moment, my preference is to use a solution that can be ported to other OSs and doesn't require custom documentation on the utility being used, so I am following your recommended periodic (rather than directory-watching) strategy, but with cron.

May 7, 2012 7:58 AM in response to Linc Davis

Thanks for the suggestion. I'd try this, except that it still seems that the RunAtLoad and Program keys don't work right and (according to twtwtw) the QueueDirectories key doesn't work as documented either. Unless launchd invocation can be straightforward, I'm not willing to rely on it, since cron still exists and (at least in my experience) works as documented.

May 7, 2012 8:30 AM in response to twtwtw

Sorry to learn that I can't understand this documentation. If you know of something I should study in order to make documentation such as launchd's intelligible (e.g., so when I read the QD documentation I will understand that "QD requires that the watched folder be emptied completely before it will trigger again"), I would appreciate the reference.

May 7, 2012 8:38 AM in response to Jonathan Pool

You haven't shown us your script, so anything I say is only a best guess based on general information. If you want definitive, give more information. And what you quoted about QueueDirectories says explicitly that the job will only launch if the directory is empty. Ipso facto, if something is added to the directory, it must be removed before the trigger will fire again. Man pages are not intended to be Ikea-style constrution manuals.


How you solve your problem is your business, and I'm happy to help whichever you choose. If cron works for you and you want to use it, great. However, I'm getting annoyed because you seem set on spreading misinformation rather than figuring out where you goofed up. launchd works fine - if it didn't your computer wouldn't boot - so please stop blaming the system for mistakes you don't realize you're making. Either ask for some honest help, or give it up and use cron.

May 7, 2012 8:47 AM in response to Jonathan Pool

Both launchd and rsync are really meant for software developers. Documentation is always poor in this context. It is expected that developers will take a systematic approach to learning how the software works and what the documentation means. Furthermore, rsync is much more complex than launchd. You are using both. That's just painful.


I suggest looking for a 3rd party, commercial solution. In addition to all of the above, rsync is "free software". Neither support nor documentation is provided. You are expected to exercise your freedom and hack up rsync as you wish. Because of this, no software developer has any incentive to make rsync easier to use like the developer of Lingon has make launchd easier to use.

launchd disobeying plist

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple ID.