MacOS – Launchd won’t execute a bindfs command

filesystemlaunchdmacos

I want to use launchd to run bindfs commands at login, as root. I have a plist in /Library/LaunchAgents/loginsftpjailmount.plist (with chmod 600) and a shell script in /usr/local/bin/loginsftpjailmount.sh.

I should start by saying it works – if I change the bash script to run

mkdir /Users/Me/Desktop/itworks

then it successfully creates the directory "itworks", both on login and by running

sudo launchctl load /Library/launchAgents/loginsftpjailmount.plist

And the folder created is owned by root and I have to type in my password to delete it. When I manually run the bash script from the terminal using sudo, the bindfs command works.

So to summarize – I know the script works. I know the plist works. I know they work together with launchd. But the bindfs command doesn't run! I checked the system log with

sudo grep com.user /var/log/system.log

and it says it exits with error 127 (com.user is part of the label for my plist). I searched online and none of the solutions for error 127 work for me. For reference, two plists I have used are:

<?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.user.loginitem</string>
<key>ProgramArguments</key>
<array>
    <string>bash</string>
    <string>-c</string>
    <string>bash -c "bindfs /Volumes/BRIGHTRED/ServedDocuments /sftpjail/Documents"</string>
</array>
<key>RunAtLoad</key>
<true/>

and also

<?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.user.loginitem</string>
        <key>Program</key>
        <string>/usr/local/bin/loginsftpjailmount.sh</string>
        <key>RunAtLoad</key>
        <true/>
    </dict>
</plist>

Best Answer

The bindfs process has to be started with root privileges. Launching it as agent would prevent this.

So sudo launchctl unload ... and sudo launchctl remove ... (the subcommand remove removes the agent from the launchd database - the file won't get deleted!) the plist, move the plist to /Library/LaunchDaemons/ and reload it with sudo launchctl load ....

A properly named and composed org.user.bindfs.sftpjail.plist would look like this:

<?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>org.user.bindfs.sftpjail</string>
        <key>ProgramArguments</key>
        <array>
                <string>/opt/local/bin/bindfs</string>
                <string>/Volumes/BRIGHTRED/ServedDocuments</string>
                <string>/sftpjail/Documents</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>StandardErrorPath</key>
        <string>/tmp/org.user.bindfs.sftpjail.err</string>
        <key>StandardOutPath</key>
        <string>/tmp/org.user.bindfs.sftpjail.out</string>
        <key>WatchPaths</key>
        <array>
                <string>/Volumes/BRIGHTRED</string>
        </array>
</dict>
</plist>

The WatchPath key is often required (it was in my case) to avoid timing problems. You may remove the keys StandardErrorPath/StandardOutPath and its strings after ensuring that everything works properly.