Search code examples
pythonmacosshelllaunchctl

OS X 10.10.3 launchctl Permission denied


I execute launchctl start com.xxx.xxx.plist

I can find AutoMakeLog.err and the content :

Traceback (most recent call last):
File "/Users/xxxx/Downloads/Kevin/auto.py", line 67, in <module>
output = open(file_name, 'w')
IOError: [Errno 13] Permission denied: '2015-04-22-09:15:40.log'

plist content :

<array>
  <string>/Users/xxxx/Downloads/Kevin/auto.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
    <key>Minute</key>
    <integer>30</integer>
    <key>Hour</key>
    <integer>08</integer>
</dict>
<key>StandardOutPath</key>
<string>/Users/xxxx/Downloads/Kevin/AutoMakeLog.log</string>
<key>StandardErrorPath</key>
<string>/Users/xxx/Downloads/Kevin/AutoMakeLog.err</string>

auto.sh

#!/bin/sh
/usr/bin/python /Users/xxxx/Downloads/Kevin/auto.py

auto.py

file_name = time.strftime('%Y-%m-%d-%H:%M:%S', time.localtime(time.time()))
file_name += '.log'
output = open(file_name, 'w')
output.writelines(response.text)
output.close()

auto.sh and auto.py have chomd 777

PS: I direct execution auto.sh there is nothing error.


Solution

  • Even user-specific launchd jobs on OSX are executed with /as the current directory.

    Since auto.py is creating a file with a mere filename, without path, it effectively tries to create a file in / and fails due to insufficient privileges.

    Thus, either change to a directory the current user can create files in, or specify an explicit path; e.g. (assuming import os):

    file_name = os.getenv('HOME') + '/' + time.strftime('%Y-%m-%d-%H:%M:%S', time.localtime(time.time()))
    

    As for how you can run your python scripts directly, without the need for an intermediate shell script:

    In your plist file, specify the command to execute as follows:

      <key>ProgramArguments</key>
      <array>
        <string>python</string>
        <string>/Users/xxxx/Downloads/Kevin/auto.py</string>
      </array>
    

    Note that you needn't specify a path for python, because it is in the $PATH when launchd runs your job.

    However, note that the $PATH contains fewer entries than what you see in Terminal, and a notable absence is /user/local/bin; the value is (as of OSX 10.10.3):

    /usr/bin:/bin:/usr/sbin:/sbin