16

I have a launchd script where the command I'm trying to run is erroring (apparently that's not a word, it is now), complaining of improper usage.

The specific error I'm getting is the command's usage text dumped to the system log. From this I infer the other info (path to the command, timing etc.) in the plist is being parsed correctly, just not the command's options.

After the command usage I have one last line:

18/11/2013 09:30:00.101 com.apple.launchd.peruser.501: (fake.lable.seti[33833]) Exited with code: 1

But that just means "I exited with an error".

I know launchd splits the command from its options and in the man page tells you about ProgramArguments: "...Please note: many people are confused by this key. Please read execvp(3) very carefully!.."

Well I read execvp(3) and I'm none the wiser, so I'm asking you lovely lot.

Normally, running the command from the terminal it'd look like this:

/Library/Application\ Support/BOINC\ Data/boinccmd --host localhost --passwd gobbledygook --project http://setiathome.berkeley.edu/ update

This works a treat.

And this is how I've split it in the Program/ProgramArguments section of my LaunchAgent plist:

<key>Program</key>
    <string>/Library/Application Support/BOINC Data/boinccmd</string>
<key>ProgramArguments</key>
    <array>
        <string>--host localhost</string>
        <string>--passwd gobbledygook</string>
        <string>--project http://setiathome.berkeley.edu/ update</string>
    </array>

(for the record, I originally had the path to boinccmd \escaped out, but that doesn't work, launchd escapes spaces in the path for you)

I've tried splitting the arguments down further:

<key>Program</key>
    <string>/Library/Application Support/BOINC Data/boinccmd</string>
<key>ProgramArguments</key>
    <array>
        <string>--host</string>
        <string>localhost</string>
        <string>--passwd</string>
        <string>gobbledygook</string>
        <string>--project</string>
        <string>http://setiathome.berkeley.edu/</string>
        <string>update</string>
    </array>

But that didn't seem to work either.

As ever, I'm very sure I'm missing something so simple.

Thanks.


ANSWER:

The first line of ProgramArguments needs to be the path to the program. This is what was tripping me up and indeed what was probably meant by the "...Please read very carefully!.." comment :) I also found I had to split the arguments down to their component parts. When I had all that in place the whole thing works a charm. Thank you very much.

<key>Program</key>
    <string>/Library/Application Support/BOINC Data/boinccmd</string>
<key>ProgramArguments</key>
    <array>
        <string>/Library/Application Support/BOINC Data/boinccmd</string>
        <string>--host</string>
        <string>localhost</string>
        <string>--passwd</string>
        <string>gobbledygook</string>
        <string>--project</string>
        <string>http://setiathome.berkeley.edu/</string>
        <string>update</string>
    </array>

A final edit to say for an easy to understand explanation as to WHY this should be, see SirPavlova's explanation.

~W

  • Using launchctl list com.label.plist I can see that launchd is getting the correct parts of the command to piece together. I was thinking maybe it was a problem related to the --, but apparently not. – Woodgie Nov 15 '13 at 10:20
  • 1
    I don't have an answer for your problem, but your first example with <string>--host localhost</string> will definitely not work. Remember, when you write a command line to a shell, it has no idea what's part of an option and what's a regular argument — it just splits on spaces before passing the arguments to the program being run. Also, it might help if you were to show the exact error that boinccmd is reporting. – Kevin Reid Nov 16 '13 at 0:09
  • Edited my post to say what I'm seeing. Not that it'll be of any help! Also, I'm getting the same error if I split the options on their whitespace. I'm guessing it's the -- that's causing the problem somehow. – Woodgie Nov 18 '13 at 11:42
  • 1
    I would try using just Program or ProgramArguments not both – Mark Nov 18 '13 at 12:31
16

The Program key specifies the file to execute, & the ProgramArguments key specifies the arguments which will be passed to the executing process. Strictly speaking you can pass whatever arguments you want to a process, but the convention is that the first one should be the name by which the process was invoked, so most programs ignore their first argument. The file to execute is obviously necessary information, but if the Program key is is missing, launchd pretends it has the same value as the first argument in ProgramArguments purely as a convenience.

Your first example starts boinccmd & gives it arguments that would be equivalent to the terminal command

--host\ localhost --passwd\ gobbledygook --project\ http://setiathome.berkeley.edu/\ update

which tells boinccmd that you invoked it as "--host localhost" & only passed it two weird arguments.

Your second example separates the arguments correctly, but as Eddie Kelley suggested it needs one inserted at the front. It tells boinccmd that you invoked it as "--host", then passed another six arguments. boinccmd can recognise the last five as being two options, but has no idea what the "localhost" business is about. As far as boinccmd can tell, it was invoked from the terminal as

/Library/Application\ Support/BOINC\ Data/boinccmd localhost --passwd gobbledygook --project http://setiathome.berkeley.edu/ update

(note the missing "--host").

boinccmd is probably one of the great majority of programs that don't care what their first argument is, so you could probably actually just shove <string>HELLO</string> at the head of the ProgramArguments array, but it's probably cleaner to remove the Program key altogether & just use this:

<key>ProgramArguments</key>
    <array>
        <string>/Library/Application Support/BOINC Data/boinccmd</string>
        <string>--host</string>
        <string>localhost</string>
        <string>--passwd</string>
        <string>gobbledygook</string>
        <string>--project</string>
        <string>http://setiathome.berkeley.edu/</string>
        <string>update</string>
    </array>

It can seem like a meaningless redundancy, but some programs use this to good effect: bash et al. act as login shells if their first argument begins with -, & Vim enters various emulation modes if its first argument is ed or vi instead of vim.

  • 1
    You posted as I was editing my main post! This is a great explanation. Thank you. – Woodgie Nov 18 '13 at 14:29
  • 1
    Glad to be of help :) – SirPavlova Nov 18 '13 at 15:40
  • @SirPavlova, great help! However, is there any tool that helps person to convert console invocation to plist format? – gaussblurinc Sep 5 '14 at 9:44
6

Based on the man page for exec(3), it seems that the first program argument should be the path to the executable:

The execv(), execvp(), and execvP() functions provide an array of pointers to null-terminated strings
 that represent the argument list available to the new program.  The first argument, by convention,
 should point to the file name associated with the file being executed. The array of pointers must be
 terminated by a NULL pointer.

If you can specify the path to the executable as the argument at index 0, it may help...

  • As I've edited the post to show, the boinccmd is being found and run, the options being passed to it are somehow being mangled. Unless I'm missing what you're saying. – Woodgie Nov 18 '13 at 11:45
  • 1
    @Woodgie Yes that was found in Program - your ProgramArguments is imcorrect it needs the path name of the executable – Mark Nov 18 '13 at 12:35
  • Oh. OH! I think I see now. Hang on, lemme test that. – Woodgie Nov 18 '13 at 14:09
  • BINGO, doing that and putting each part of each command in its own <string></string> container worked. Thank you. I TOLD you it was simple! – Woodgie Nov 18 '13 at 14:17

You must log in to answer this question.

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