0

Originally asked on Stack Overflow, but it may be more suited for here. Wherever it’s answered first, I’ll be sure to update the counterpart question with the same answer.

I've already checked this similar question.

OS MacOS 10.15.17 (Catalina)

I want to create a script that uses iperf to launch a client that measures my connection speed every several seconds for an extended period. I’ve created a daemon file and put it in ~/Library/LaunchAgents/com.myself.iperfclient.plist.

com.myself.iperfclient.plist

<?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.myself.iperfclient</string>
        
        <key>ProgramArguments</key>
        <array>
            <string>/Users/myself/Documents/bin/iperf/netspeed</string>
        </array>

        <key>StartInterval</key>
        <integer>20</integer>  <!-- in seconds -->

        <key>Disabled</key>
        <false/>
    </dict>
</plist>

netspeed

#!/bin/bash


# see https://stackoverflow.com/a/246128/10200417
script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
script_name=`basename $0`
# echo "called script $script_name from $script_dir"

iperf_server=127.0.0.1
iperf_port=54321

# launch iperf client, log results to ./logs/client.log
iperf \
    -c $iperf_server \
    -p $iperf_port \
    --logfile $script_dir/logs/client.log

The netspeed file is executable for anyone:

$ ls -l netspeed
  -rwxr-xr-x@ 1 myself  staff  379 Jan 11 21:36 netspeed

When I try to add the new daemon, with launchctl load ~/Library/LaunchAgents/com.myself.iperfclient.plist, this is the error message I get in the Console:

Sandbox: bash(50654) System Policy: deny(1) file-read-data /Users/myself/Documents/bin/iperf/netspeed

If in the .plist descriptor for the daemon I add <string>open</string> as the first item in ProgramArguments, there’s no error. However, I don’t want to run the script this way because it launches a new Terminal window every time, which is extremely annoying.

My question

How do I allow my daemon process to execute netspeed?

P.S.

The launchctl status code is 126.

$ launchctl list | grep myself
-   126 com.myself.iperfclient
0

3 Answers 3

4

For anyone else struggling with fdautil (as I was), you need to set the command from the command line before it will work from launchcontrol.

For example:

sudo /usr/local/bin/fdautil set daemon LABEL /bin/bash /full/path/to/your/script.sh 

LABEL can be whatever you like - it's just a way to refer to your script if you want to remove it from fdautil later.

Once you have done this, your LaunchAgents plist file should look something 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>com.yourdomain.LABEL</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/fdautil</string>
        <string>exec</string>
        <string>/bin/bash</string>
        <string>/full/path/to/your/script.sh</string>
    </array>
    <integer>60</integer>
</dict>
</plist>
1

Alright, here’s what I ended up doing, which does work and doesn’t require any other installations. I tried the answer from Gilby, but wasn’t able to get fdautil to work after downloading and installing it via the LaunchControl trial version.

If it had worked, it seems it would have done so by granting LaunchControl’s fdautil utility full disk access, which would then use those permissions somehow to execute my netspeed script (without passing those permissions to /bin/bash?).

Method 1: AppleScript wrapper

I created Users/myself/Documents/bin/iperf/netspeed.scpt, which has the following:

do shell script "/Users/myself/Documents/bin/iperf/netspeed"

I then updated the ProgramArguments entry in the launchd plist to:

<key>ProgramArguments</key>
<array>
    <string>/usr/bin/osascript</string>
    <string>/Users/myself/Documents/bin/iperf/netspeed.scpt</string>
</array>

Finally, in System Preferences > Security and Privacy > Files and Folders I was able to grant access for Users/myself/Documents to /usr/bin/osascript, and successfully launch the daemon.

Method 2: Put script in location with less security

As @user3439894 pointed out, since the main reason it was difficult to execute netspeed in the first place was that I had it in ~myself/Documents.../, which has elevated permissions requirements, I can also just put it in a location with less security.

I followed the suggestion to try /Users/Shared/.../netspeed and it indeed worked with my original script and plist contents! To be clear, the ProgramArguments would now be:

<key>ProgramArguments</key>
<array>
    <string>/Users/Shared/.../netspeed</string>
</array>
3
  • If you put the executable in /Users/Shared or in a user created folder in the root of your home folder you should have to go through all this rigmarole. Commented Jan 12, 2021 at 15:46
  • @user3439894 Ah, that may be the case as well; I’ve not tried it yet.
    – owengall
    Commented Jan 12, 2021 at 18:49
  • @user3439894 I tested to confirm your suggestion works, and updated the answer accordingly. Thanks!
    – owengall
    Commented Jan 13, 2021 at 3:33
0

The program you want to run is bash, so the program arguments should be:

    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>/Users/myself/Documents/bin/iperf/netspeed</string>
    </array>

But I suspect that you may still get sandbox errors. To avoid this use the fdautil command which is part of Launch Control. Then you use:

<key>ProgramArguments</key>
<array>
    <string>/usr/local/bin/fdautil</string>
    <string>exec</string>
    <string>/bin/bash</string>
    <string>/Users/myself/Documents/bin/iperf/netspeed</string>
</array>

This is the mechanism I have used to launch a python script (with the obvious difference).

This answer maybe incomplete, but see how you go.

4
  • It should be possible to execute a bash script directly from launchd (well, actually it is possible), no need to pass it as an argument to bash.
    – nohillside
    Commented Jan 12, 2021 at 7:16
  • Glad to know that. On the few occasions I have done this specifying the shell (or whatever) avoids some confusion - particularly between of versions of python! Will be interested to see if the fdautil method helps the owengall. I will amend my answer when we hear from him.
    – Gilby
    Commented Jan 12, 2021 at 11:04
  • Would I need to purchase launch control to run fdautil? I tried downloading the trial, then installing /usr/local/bin/fdautil as directed in Help, but if I try to run fdautil exec <my_script> it says “You don't have permission to run this command via fdautil”. fdautil is already given full disk access.
    – owengall
    Commented Jan 12, 2021 at 14:42
  • Also, I looked for /Library/Preferences/com.soma-zone.LaunchControl.fdautil.plist, which is where fdautil puts the script it allows to run, but that plist file doesn’t exist.
    – owengall
    Commented Jan 12, 2021 at 14:50

You must log in to answer this question.

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