2

I have little misunderstandng why my ~/Library/LaunchAgents/com.user.loginscript.plist doesn't work.

Here is NOT working code inside my plist:

<key>ProgramArguments</key>
<array>
<string>switchaudiosource</string>
<string>-s</string>
<string>MacBook Pro Speakers</string>
</array>

and here is the working code inside my plist:

<key>Program</key>
<string>/Users/zlapik/bin/setup_output_sound.sh</string>

since inside /Users/zlapik/bin/setup_output_sound.sh is only:

#!/bin/bash
switchaudiosource -s "MacBook Pro Speakers"

Could someone please explain the reason why these happening, although LaunchControl program doesn't complain about anything?

If it helps I also include the whole list 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>EnvironmentVariables</key>
        <dict>
          <key>PATH</key>
          <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/zlapik/bin</string>
        </dict>
        <key>Label</key>
        <string>com.user.loginscript</string>
        <!-- <key>Program</key> -->
        <!-- <string>/Users/zlapik/bin/setup_output_sound.sh</string> -->
        <key>ProgramArguments</key>
        <array>
            <string>switchaudiosource</string>
            <string>-s</string>
            <string>MacBook Pro Speakers</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>KeepAlive</key>
        <false/>
        <key>LaunchOnlyOnce</key>
        <true/>
        <key>StandardOutPath</key>
        <string>/tmp/com.user.loginscript.stdout</string>
        <key>StandardErrorPath</key>
        <string>/tmp/com.user.loginscript.stderr</string>
        <key>UserName</key>
        <string>admin</string>
        <key>GroupName</key>
        <string>staff</string>
        <key>InitGroups</key>
        <true/>
    </dict>
</plist>

Edit: switchaudiosource is cli application installed via brew install switchaudio-osx .

3
  • Where is switchaudiosource? The issue is probaly that it is not on you $PATH in launchd - quick fix is to put its full path in the plist
    – mmmmmm
    Commented Oct 29, 2022 at 12:19
  • It's a program installed via brew install switchaudio-osx. Command which switchaudiosource is telling /usr/local/bin/switchaudiosource and /usr/local/bin is already include in PATH environment varibable. Commented Oct 29, 2022 at 12:32
  • Nice, when I put full path /usr/local/bin/switchaudiosource it's already working, but I still don't understand why it's not working when it's inside PATH env variable. Thank you very much! Commented Oct 29, 2022 at 12:39

1 Answer 1

2

From man launchd.plist:

Program <string>
This key maps to the first argument of execv(3) and indicates the absolute
path to the executable for the job. If this key is missing, then the first
element of the array of strings provided to the ProgramArguments will be
used instead. This key is required in the absence of the ProgramArguments
key.

ProgramArguments <array of strings>
This key maps to the second argument of execvp(3) and specifies the
argument vector to be passed to the job when a process is spawned. This key
is required in the absence of the Program key.  IMPORTANT: Many people are
confused by this key. Please read execvp(3) very carefully!

NOTE: The Program key must be an absolute path. Previous versions of
launchd did not enforce this requirement but failed to run the job. In the
absence of the Program key, the first element of the ProgramArguments array
may be either an absolute path, or a relative path which is resolved using
_PATH_STDPATH.

Your plist specifies ProgramArguments, so that the first element of that array is used as path to the executable. Since it is not an absolute path, it is resolved against _PATH_STDPATH, which is defined in <paths.h> as

/* All standard utilities path. */
#define _PATH_STDPATH   "/usr/bin:/bin:/usr/sbin:/sbin"

Note that this “standard path” does not include "/usr/local/bin", where the switchaudiosource program resides. That's why it does not work with the first version of your plist.

Specifying EnvironmentVariables in the plist does not help: Those environment variables are set for the running job, but not used to locate the executable.

On the other hand, if the login scripts executes the shell script, then the shell parses additional configuration files, in particular /etc/paths, which contains

/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin

So "/usr/local/bin" is added to the search path, and the switchaudiosource program is found in that directory.

Addendum: launchd writes diagnostic messages to

/var/log/com.apple.xpc.launchd/launchd.log

(that is the path on macOS 12 Monterey), you can also find it in the Console application (choose “Log Reports” in the left sidebar, then “launchd.log”). If you load the plist manually with

launchctl load ~/Library/LaunchAgents/com.user.loginscript.plist

then you should see an error message

<Error>: Service could not initialize: posix_spawn(switchaudiosource) error: 0x2: No such file or directory

in the log file if the executable could not be located.

You must log in to answer this question.

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