views:

515

answers:

4

It is not totally rigth that I can run a Bash function with 000 permissions, but almost. My code is:

#!/bin/bash
function hello {
echo Hello! }

The hello-file has permissions:

-r--------  1 UnixBasics hello_file

Firtsly, I type with the current permissions:

$ . ./hello_file;hello

The tweak is to change the 400 permissions to 000 right before running the bash script script:

$ chmod 000 hello_file
$ . ./hello_file;hello                                             [1]
-bash: ./hello_file: Permission denied 
Hello!

It gives one error, but it does not stop running the function. I cannot understand. I now unset the hello-function: "unset hello". I receive the errors:

-bash: ./hello_file: Permission denied
-bash: hello: command not found

Why did I not get them at the first time? Has it something to do with cache, buffer or something like it? Why can I run the Bash script with 000 permissions [1]?

+11  A: 

You are not running the script, you are sourcing (including) it. In order to source a script, you only need the read permission.

By the way, functions simply exist, they don't have permission. Once the file was sourced and the function defined, you can run it as much as you want.


Update:

Why did I not get them at the first time? Has it something to do with cache, buffer or something like it?

Yes, like Pax answered, hello was probably previously defined there from a previous sourcing of the file. You may be confused with what sourcing ("." builtin command) does. Sourcing reads the file and runs all its commands in the current shell, then goes back to the prompt. So, if you run the file once, its functions are defined in the current shell instance, and they stay there until you finish that shell session (or unset them).

Why can I run the Bash script with 000 permissions [1]?

You can't. Note that it presents an error. Quoting your output:

$ . ./hello_file;hello                                             [1]
-bash: ./hello_file: Permission denied 
Hello!

You executed two commands in a single command-line. The sourcing failed with "Permission denied". The "Hello!" output is from a previous sourcing of the file. You just proved it yourself when you unset it and tried the same command-line again.

You can't call that caching... it is how the shell works. You source another file, all its definitions are included in the current shell session and stay there. If you actually run the script (not sourcing) you shouldn't get any residues in the current session.

$ chmod +x hello_file
$ ./hello_file           # note: executed, not sourced
$ hello
-bash: hello: command not found
Juliano
That's not right. With perm=100, it still doesn't allow you to source the script, giving "permission denied". Sourcing just executes in the context of the current shell, rather than a subshell. Suggest you try it yourself.
paxdiablo
Pax: I'm not arguing about 100 or 000 permissions, I'm just arguing that the exec permission doesn't affect sourcing ("." builtin command), that is what he is really doing. Why the downvote?
Juliano
The downvote is because you're wrong - try it and see. Sourcing doesn't work if perm = 000 or 100.
paxdiablo
If you prove me wrong, I'll remove the -1, no problems. But I've already tested it.
paxdiablo
Again, I never mentioned that it is possible to source with either 000 or 100. Read my answer again and tell me where I mentioned 000 or 100.
Juliano
"In order to source a script, you only need the read permission." - that's perm = 1xx.
paxdiablo
Pax, read permission is 400. Read = 400; Write = 200; Exec = 100.
Juliano
Apologies, my brainf*rt. I got it into my head that the 100 was the owner bitmask (rwx), not the full user/group/other mask.
paxdiablo
-(-1) :-)
paxdiablo
Juliano has got a point. Three binary numbers determine tho the user permissions RWX: a * 2^2 + b * 2^1 + c * 2^0, where a, b and c correspond to rwx, respectively. Nice to follow your debating :)
Masi
Pax, no problems, you are welcome.
Juliano
I'd go for this one, @UnixB, it's the best description to date (especially since it uses the phrase, "like Pax answered, ..." :-). The "unset hello" followed by "chmod 100 hello_file ; . ./hello_file ; hello" should result in "permission denied" followed by "hello: no such command".
paxdiablo
+5  A: 

The most likely explanation is that you've run hello_file before it was protected and the function has already been created. Then you protected your script (you say 100 in the command but mention 000 in your text).

So, then the script won't run. But hello() is still defined from you previous run.

Try to open a new shell or just execute unset hello.

paxdiablo
Your answer sounds like you are guessing. I think the first answer given is correct -- he's just sourcing in a readable file. Shell functions don't have nor honor permissions.
Bryan Oakley
It's not a guess, I tested it. And the permissions are on the *file* that creates the function, *not* the function itself.
paxdiablo
I stand corrected. Sorry 'bout that.
Bryan Oakley
1+ for the unset -command and the excellent explanation.
Masi
+1  A: 

Did you source the script (i.e. run ". ./hello_file") before changing the mode to 100? If that's the case, then the "hello" function is simply still loaded into bash. Subsequently attempting to source an unreadable file won't change that. To test correctly, make sure you launch a fresh shell.

Andrew Medico
I made some corrections and added more details to the question. Clearly, they are essential to answer the question.
Masi
+1  A: 

In order to run a program (whether it's a bash script, or binary executable), you need to have execute permissions. When you enter a command, the first word (such as ./foo in the below) specifies the command to run, and that is started up as a separate process; in the case of a shell script, it executes a new copy of the shell interpreter listed on the #! line, and runs the program using that interpreter.

$ ls -l foo
-rw-r--r--  1 lambda  lambda  23 Mar 25 20:02 foo
$ chmod 744 foo # or chmod u+x foo
$ ls -l foo
-rwxr--r--  1 lambda  lambda  23 Mar 25 20:02 foo
$ ./foo
Hello

When you use the . command, that is a shell builtin command that says to source the file into the current shell; that means that it executes the commands in the file as if you had run them from the command line, right in the current file. You need only read permission to source a file. For example, if you set a variable in a sub-process, it doesn't change the value in the current shell; but if you source a bash script into the current shell, then it does change the value:

$ foo=bar
$ cat setvariables 
#!/bin/sh

foo=hello
$ ./setvariables
$ echo $foo
bar
$ . ./setvariables
$ echo $foo
hello

A shell function (like in your example) is a lot like a variable, but it acts like a command in the current shell. So, when you source your hello_file using ., that defines that function in the current shell, and it can execute like any other shell function you have defined.

As far as the permissions are concerned, I would bet that before changing the permissions to 100 (which means only executable, not readable, which is fairly useless for a file since you need to be able to read it and execute it to do anything), you had already sourced the file into your current shell. That would mean that the function was already defined, and it doesn't matter the permissions of the file after it's defined; once the function is defined in the current shell, you can even delete the file, and as long as that shell is still open, the function will still be defined.

Edit: As I see from your edited question, once you unset the function, you get an error. That indicates strongly to me that my hypothesis was correct, and that you had already sourced the file before you changed permissions. As I explained, sourcing and executing the file are entirely different operations, and once you source a file, its permissions (or existence) don't matter at all; the function has already been loaded into the currently running shell. You can tell by running your original experiment after doing the unset hello; if you chmod 000 it, you shouldn't have read permissions, and then the function won't be defined.

Brian Campbell
Uh, why the downvote? Is there anything in my description that is wrong or unhelpful?
Brian Campbell
This is mostly true, but irrelevent to the question (why can - apparently - a mode-100 file be sourced). In particular, files need not be executable to be sourced - only readable.
Andrew Medico
I added a paragraph clarifying about the permissions; he clearly got a permission error when he sourced the file, so he must have had the definition from a previous invocation. The reason I described the difference between sourcing and running is that I think that's where the confusion is.
Brian Campbell
Are you sure about the first line? I am able to get the output "Hello!" with permissions 400 even if I unset the hello-function before the command. I have no execute permissions to "run" the program. Or do I just understand the term "running" wrong?
Masi
I think you understand the term "running" wrong. That's what I was trying to explain. Running a program (as shown in my first example) is different than sourcing a program (as shown in the second one). Did you understand that part of my explanation?
Brian Campbell
@UnixB, technically @Brian is right. Running means running a process in a subshell (./hello_file). Sourcing is not running, it's executing a shell script in the context of the current shell (. ./hello_file). That's covered in his second paragraph.
paxdiablo
+1 since you didn't deserve that downvote for being loquacious You may think I'm smart using that word, but keep in mind I learned it from an Asterix comic :-)
paxdiablo
+1 for mentioning Asterix. I love Asterix.
Brian Campbell