6

macOS Catalina

I have a python script that should write a file to an external drive. This works if I run the script manually. However, if the script is kicked off from a LaunchAgent bash script, it doesn't have permission to do so.

Simplified python script for example's sake:

with open('/Volumes/nas_1/test/somefile.txt', 'a') as the_file:
                            the_file.write('Hello\n')

Bash script that the LaunchAgent kicks off located in /Applications:

#!/bin/bash

#Start test script only if it is not running
if [ "$(ps -ef | grep -v grep | grep python_test.py | wc -l)" -le 0 ]
then

echo "Python Test Starting"
/Users/admin-user/.venvs/test/bin/python /Users/admin-user/projects/test/scripts/python_test.py

else
 echo "Python Test Already Running"
fi

plist located in ~/Library/LaunchAgents:

<?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>EnvironmentVariables</key>
    <dict>
      <key>PATH</key>
      <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:</string>
    </dict>
    <key>Label</key>
    <string>com.test.agent</string>
    <key>Program</key>
    <string>/Applications/runTest.sh</string>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <false/>
    <key>LaunchOnlyOnce</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/tmp/runTest.stdout</string>
    <key>StandardErrorPath</key>
    <string>/tmp/runTest.stderr</string>
  </dict>
</plist>

Error:

PermissionError: [Errno 1] Operation not permitted: '/Volumes/nas_1/test/somefile.txt'

I've given /Volumes/nas_1/test 777 permissions while debugging and that has not helped. Should I move the bash and or python scripts some where else?

brewcrazy
  • 623
  • 13
  • 30
  • I'm not so familiar with MacOS and here is a possible scenario with assumptions: `LaunchAgent` or `launchd` runs with its own priviledge. Once you create `somefile.txt` with your priviledge, `launchd` does not have the permission to open the file to append. Please remove the existing file and try again. – tshiono Nov 03 '19 at 11:03
  • Same issue with the existing file removed and using `with open('/Volumes/nas_1/test/somefile.txt', 'w') as the_file:`. My real script creates a new file each time anyway. I provided that example for simplicity's sake since I see the same behavior creating a txt file and running my full script. macOS Catalina introduced some privacy protections for Launch Daemons & agents: https://developer.apple.com/documentation/macos_release_notes/macos_catalina_10_15_release_notes. This script and LaunchAgent configuration worked prior to the Catalina update. – brewcrazy Nov 03 '19 at 13:54
  • Sorry I was off the mark. BTW what happens if you change the destination to the internal drive? – tshiono Nov 04 '19 at 02:16
  • Changing the destination to ‘~/Desktop’ works. If I can’t make this work, I’m going to have it write to a local directory and then have a cron move everything to the external drive every minute. – brewcrazy Nov 04 '19 at 04:01
  • I cannot figure out what causes the difference but I suppose your workaround makes sense. Sorry for not being able to help. – tshiono Nov 04 '19 at 08:21

1 Answers1

8

I have run into a similar problem. My bash script which copies files to an external drive via rsync fails to run after upgrading to Catalina.

The following is what I did to make it work again:

  • Add /bin/bash in System Preferences / Security & Privacy / Full Disk Access
  • Replace my shebang in the bash script with /bin/bash (was /usr/bin/env bash)
  • Remove StandardErrorPath and StandardOutPath entries from my plist (Writing log files was denied because it was spawned as another process)

After that it starts to work again, maybe there are better solutions though.

5t111111
  • 700
  • 5
  • 14
  • 1
    +1000 I was using `zsh`, so I added `/bin/zsh` instead. I didn't have to remove the log files from my plist though, it still worked to have them in there (although the log file paths are in `/tmp` and not on the removable drive). – Seafish May 04 '20 at 02:42