Classic Shell Scripting - Arnold Robbins [241]
When we copy a file that already has execute permissions—e.g., /bin/pwd—the permissions are preserved, unless the umask value causes them to be taken away:
$ umask
Show the current permission mask
023
$ rm -f foo
Delete any existing file
$ cp /bin/pwd foo
Make a copy of a system command
$ ls -l /bin/pwd foo
List information about the files
-rwxr-xr-x 1 root root 10428 2001-07-23 10:23 /bin/pwd
-rwxr-xr-- 1 jones devel 10428 2002-09-21 16:37 foo
The resulting permission string rwxr-xr-- reflects the loss of privileges: group lost write access, and other lost both write and execute access.
Finally, we use the symbolic form of an argument to chmod to add execute permission for all:
$ chmod a+x foo
Add execute permission for all
$ ls -l foo
List verbose file information
-rwxr-xr-x 1 jones devel 10428 2002-09-21 16:37 foo
The resulting permission string is then rwxr-xr-x, so user, group, and other have execute access. Notice that the permission mask did not affect the chmod operation: the mask is relevant only at file-creation time. The copied file behaves exactly like the original pwd command:
$ /bin/pwd
Try the system version
/tmp
$ pwd
And the shell built-in version
/tmp
$ ./foo
And our copy of the system version
/tmp
$ file foo /bin/pwd
Ask for information about these files
foo: ELF 32-bit LSB executable, Intel 80386, version 1,
dynamically linked (uses shared libs), stripped
/bin/pwd: ELF 32-bit LSB executable, Intel 80386, version 1,
dynamically linked (uses shared libs), stripped
Notice that we invoked foo with a directory prefix: for security reasons, it is never a good idea to include the current directory in the PATH list. If you must have it there, at least put it last!
* * *
Warning
If you try this experiment yourself, you might get a permission-denied response when you try to run commands in the /tmp directory. On systems that provide the capability, such as GNU/Linux, system managers sometimes mount that directory without execute permission anywhere in its file tree; check for the noexec option in /etc/fstab. One reason for that option to be used is that it prevents Trojan horse scripts (see Chapter 15) in a publicly writable directory like /tmp. You can still execute them by feeding them into the shell, but then you presumably know why you are doing so.
* * *
Here is what happens if you remove the execute permission, and then try to run the program:
$ chmod a-x foo
Remove execute permission for all
$ ls -l foo
List verbose file information
-rw-r--r-- 1 jones devel 10428 2002-09-21 16:37 foo
$ ./foo
Try to run the program
bash: ./foo: Permission denied
That is, it is not the ability of a file to function as an executable program, but rather, its possession of execute permission that determines whether it can be run as a command. This is an important safety feature in Unix.
Here is what happens when you give execute permission to a file that doesn't deserve it:
$ umask 002
Remove default for world write permission
$ rm -f foo
Delete any existing file
$ echo 'Hello, world' > foo
Create a one-line file
$ chmod a+x foo
Make it executable
$ ls -l foo
Show our changes
-rwxrwxr-x 1 jones devel 13 2002-09-21 16:51 foo
$ ./foo
Try to run the program
./foo: line 1: Hello,: command not found
$ echo $?
Display the exit status code
127
What happened was that the shell asked the kernel to execute ./foo, and got a failure report back, with the library error indicator set to ENOEXEC. The shell then tried to process the file itself. In the command line Hello, world, it interpreted Hello, as the name of a command to run, and world as its argument. No command by that peculiar name was found in the search path, so the shell reported that conclusion in an error message, and returned an exit status code of 127 (see Chapter 6 for