[launchd-dev] multiple commands in one launchd item

Damien Sorresso dsorresso at apple.com
Sun Dec 13 15:07:07 PST 2009


On Dec 12, 2009, at 6:46 PM, Scott Haneda wrote:
> If I can run a command in the terminal, should it also be possible to put that entire command into a launchhd plist?
> 
> For example, this will work in a shell, as a one liner:
> cd /Users/me/Desktop; mkdir zzzzzzzz; cd zzzzzzzz; touch test; chown 0:0 test; rm -rf /Users/me/Desktop/zzzzzzzz;
> 
> Putting that into a plist, I get errors to syslog:
> Dec 12 18:37:23 macbook com.test.me.test.foo[1596]: /usr/bin/cd: line 4: cd: /Users/me/Desktop;: No such file or directory
> Dec 12 18:37:23 macbook com.apple.launchd[1] (com.test.me.test.foo[1596]): Exited with exit code: 1
> 
> Here is how I have tried it:
> <?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.test.me.test.foo</string>
> 	<key>ProgramArguments</key>
> 	<array>
> 		<string>cd</string>
> 		<string>/Users/me/Desktop;</string>
> 		<string>mkdir</string>
> 		<string>zzzzzzzz;</string>
> 		<string>cd</string>
> 		<string>zzzzzzzz;</string>
> 		<string>touch</string>
> 		<string>test;</string>
> 		<string>chown</string>
> 		<string>0:0</string>
> 		<string>test;</string>
> 		<string>rm</string>
> 		<string>-rf</string>
> 		<string>/Users/me/Desktop/zzzzzzzz;</string>
> 	</array>
> 	<key>RunAtLoad</key>
> 	<true/>
> 	<key>StartInterval</key>
> 	<integer>10</integer>
> </dict>
> </plist>
> 
> I have also tried removing the ";" terminator, and reloading, that does not seem to work either.  I am resoting to shoving these commands into a shell script, which launchd will then call.  This works, but is one more file I need to manage, and wold love to be able to manage this in one launchd file.
> 
> My goal, it to have a schedule, once every 5 minutes, it will chown 0:0 a file, and set the executable bit on it.  So something like cd /Users/me/.hidden; chown 0:0 .runner; chmod +x .runner;

Several things. Firstly, launchd is not a shell interpreter, so please don't assume that it acts like one or makes the same guarantees. launchd jobs consist of a plist describing the job and an executable file that will be run. This is our model, and your deployment scenario clearly allows for you being able to install a plist into /Library/LaunchDaemons, so there's no reason you couldn't also deploy a shell script to, say, /usr/local/bin.

Secondly, you're doing yourself a disservice by putting the commands in the launchd.plist directly, because you are forcing yourself to reload the plist every time you make a change to the embedded script. If you just point to an executable file on-disk, you can change it to your heart's content without ever having to reload the launchd job.

Thirdly, you should be specifying the full paths to these commands in your shell script or guaranteeing that your PATH is sanitized, just as a matter of best practices. This kind of sanitation is much easier to accomplish in a single shell script file. (Remember, launchd doesn't make any guarantees about what its PATH is or what PATH its jobs will inherit.)

Fourthly, you're clearly working with your own user account here, so this job should be an agent, not a daemon, so that the files you create are created with the proper ownership and permissions.

Lastly, if you're absolutely dead-set on doing things this way, you have to again remember that launchd is not a shell interpreter, so those commands have no syntactical meaning to it. It just sees "/Users/me/Desktop;" and copies *that entire string* as the argument. Since it's not a shell interpreter, the ending semi-colon doesn't carry any meaning. It's just the second argument you want passed into an execve(3) call with "cd" as its first argument.

What you should be doing is specifying a Program pointing to the shell of your choice (i.e. "/bin/bash"), followed by the appropriate flag to ask the shell to interpret the argument following as a script ("-c" for bash).
-- 
Damien Sorresso
BSD Engineering
Apple Inc.



More information about the launchd-dev mailing list