Bash script callable from home but not scripts directory

I'm having a very weird error when trying to make a script callable. I have a scripts directory in /srv/projectname/scripts where I store you know scripts to be called as cron jobs for different projects. I'm trying at add a new one and seeing very weird behavior. In debugging I reproduce it using this set of commands

from /srv/projectname/scripts create a file create a file

vi helloworld.sh

insert text exactly:

#!/usr/bin/env bash

echo "Hello World!"

Make the script executable and try to call it:

chmod +x helloworld.sh
./helloworld.sh

Which gives:

-bash: ./helloworld.sh: Permission denied

Make sure there isn't a code error:

bash helloworld.sh

Which gives:

Hello World!

Copy the script to home and call it:

cp helloworld.sh ~/helloword.sh
~/helloword.sh

Which gives:

Hello World!

I have no idea what is going on. I have tried a lot of variants where I give the full path, same error, or if I sudo which gives no error, but also doesn't print "Hello World!".

Other details: Running on: Ubuntu 12.04.4 LTS I have also noticed that I can't tab-complete to the full name of a script that gives me this error, but I can once I have moved it. The directory /srv/projectname is a git repo but this script hasn't been added to it yet, I because I usually only do that once its working yet.

ls -l lines for the script and scripts directory are

-rwxrwxr-x 1 ubuntu ubuntu     41 Apr 21 20:25 helloworld.sh
drwxrwxr-x 3 ubuntu ubuntu 4096 Apr 21 20:25 scripts

respectively

Any help would be awesome.

EDIT: Gilles had the answer. To save anyone else who has this problem a google search.

sudo mount /srv/projectname/ -o remount

reloads the edited fstab, and everything works again.


Solution 1:

The file permissions say that it is executable, yet the file is not executable. There are three reasons why this can happen.

  • You didn't dig deep enough into the file permissions — there is an access control list that makes the file non-executable to you. You can see a file's ACL with the command getfacl /path/to/file. This is not the case here since ls -l shows that there is no ACL on the file (there would be a + at the end of the permissions, e.g. -rwxr-xr-x+).
  • The file is stored on a volume that is mounted with the noexec option. This option is implied by having users in an fstab line (if you want to make a filesystem user-mountable and to allow users to execute files on it, use noauto,users,exec). This mount option causes all regular files to be non-executable regardless of their permissions.
  • The file is a script that references an interpreter that isn't executable in its shebang line, or a dynamically-linked binary that references a dynamic loader that isn't executable. This isn't the case here given that copying the file results in a file that you can execute (and /usr/bin/env is executable anyway).

By a process of elimination, the file is on a volume mounted with the noexec option.

The only workarounds are:

  • Don't mount the volume with the noexec option. This option has no security implications (unlike nosuid and nodev, which do). It is mostly useful for filesystems with no notion of execute permissions, where you get to choose between making everything executable or nothing.
  • Copy the file before executing it.
  • Use a bind mount or bindfs to create a view of the filesystem where executable files are executable.
  • Invoke the interpreter or dynamic loader explicitly, e.g. here bash helloworld.sh. This doesn't execute helloworld.sh, it excecutes /bin/bash which reads from helloworld.sh.