0

Perfectly incidentally, I typed ./ into a sh shell today running ARM linux and it produced "permission denied" as an error, as opposed to "Is a directory" which is the usual error.

ARM Linux in sh:

[root@zynq DEBUG]# ./ -sh: ./: Permission denied [root@zynq DEBUG]# uname -a Linux zynq 3.8.0-xilinx #1 SMP PREEMPT Mon May 19 13:01:00 PDT 2014 armv7l GNU/Linux [root@zynq DEBUG]# echo $SHELL /bin/sh 

Debian Jessie in bash:

root@hotbox:~# ./ bash: ./: Is a directory root@hotbox:~# uname -a Linux hotbox 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt9-3~deb8u1 (2015-04-24) x86_64 GNU/Linux root@hotbox:~# echo $SHELL /bin/bash 

I understand that I'm attempting to execute a directory, but I'm curious: Why does sh produces a permission error?

2
  • 1
    What is sh? It's usually linked to something else, what? Commented Nov 12, 2015 at 17:51
  • @muru /bin/sh -> busybox . Busybox, apparently. Good catch. Commented Nov 12, 2015 at 17:53

1 Answer 1

7

If I were to guess, your sh favours simplicity or performance over user friendliness. The "permission denied" error is that provided by perror(3), a standard function for printing an error message. For example:

$ cat foo.c #include <stdio.h> #include <unistd.h> int main() { char* const args[] = { "/usr", NULL }; if (execv(args[0], args)) perror(args[0]); return 0; } $ gcc -o foo foo.c $ ./foo /usr: Permission denied 

bash probably makes a check to see if the path is a directory. That will, of course, be slightly slower and be slightly longer code.

bash, zsh, etc. have more than one reason to make the check - they allow you to "run" a path to a directory to cd to it:

$ shopt -s autocd $ cd / $ pwd / $ /usr/share cd /usr/share $ pwd /usr/share 

In the case of dash (Debian's /bin/sh points to /bin/dash), that's pretty much the case. The code that executes the command is in shellexec():

if (strchr(argv[0], '/') != NULL) { tryexec(argv[0], argv, envp); e = errno; } else { // snip exerror(EXEXIT, "%s: %s", argv[0], errmsg(e, E_EXEC)); 

That function calls errms():

const char * errmsg(int e, int action) { if (e != ENOENT && e != ENOTDIR) return strerror(e); if (action & E_OPEN) return "No such file"; else if (action & E_CREAT) return "Directory nonexistent"; else return "not found"; } 

strerror(3) is another standard function, like perror. strerror returns the error message, perror prints it directly.

3
  • Check it out with strace -fv /bin/sh ./. Commented Nov 12, 2015 at 18:11
  • And in this case, it's not dash, but BusyBox ash, which is specifically designed to minimize code size. Commented Nov 12, 2015 at 23:25
  • @Gilles I know it's Busybox ash. I'm just more "familiar" with dash's source. Commented Nov 12, 2015 at 23:26

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.