DASH Shell discussions
 help / color / mirror / Atom feed
* debian patches to exit with code 127 for nonexistent/directory scripts
@ 2010-06-05 16:06 Jilles Tjoelker
  2010-06-08 10:19 ` Herbert Xu
  2010-06-14  9:54 ` [PATCH] [INPUT] exit 127 if command_file is given but doesn't exist Gerrit Pape
  0 siblings, 2 replies; 31+ messages in thread
From: Jilles Tjoelker @ 2010-06-05 16:06 UTC (permalink / raw)
  To: dash

Debian's dash package has some local changes which cause an exit with
code 127, as required by POSIX, if a script (passed with dash
<filename>) cannot be opened or cannot be read because it is a
directory.

Unfortunately, these patches also affect the . builtin (if the pathname
contains a slash) and use EXEXIT, which means such errors always cause
the shell to exit, even in interactive mode or if the builtin's
specialness has been disabled using command.

% dash
$ . ./nonexistent
.: 1: Can't open ./nonexistent
zsh: exit 127   dash
%

% dash -c 'command . ./nonexistent; echo continued'

Note: Do not compare this with bash. Bash deliberately does not follow
POSIX XCU 2.8.1 Consequences of Shell Errors if not in POSIX mode, and
even in POSIX mode trying to source a nonexistent dot script (without
slash in the pathname) fails to abort the shell.

Note 2: POSIX seems unclear about what 'command .' should do, but is
very clear that failure to find/read a dot script shall not cause an
interactive shell to exit.

-- 
Jilles Tjoelker

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: debian patches to exit with code 127 for nonexistent/directory scripts
  2010-06-05 16:06 debian patches to exit with code 127 for nonexistent/directory scripts Jilles Tjoelker
@ 2010-06-08 10:19 ` Herbert Xu
  2010-06-08 10:36   ` Cristian Ionescu-Idbohrn
  2010-06-14  9:54 ` [PATCH] [INPUT] exit 127 if command_file is given but doesn't exist Gerrit Pape
  1 sibling, 1 reply; 31+ messages in thread
From: Herbert Xu @ 2010-06-08 10:19 UTC (permalink / raw)
  To: Jilles Tjoelker; +Cc: dash

Jilles Tjoelker <jilles@stack.nl> wrote:
> Debian's dash package has some local changes which cause an exit with
> code 127, as required by POSIX, if a script (passed with dash
> <filename>) cannot be opened or cannot be read because it is a
> directory.

Please report this through Debian's bug tracking system.

There is nothing that I can do about this.

Thanks,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: debian patches to exit with code 127 for nonexistent/directory scripts
  2010-06-08 10:19 ` Herbert Xu
@ 2010-06-08 10:36   ` Cristian Ionescu-Idbohrn
  2010-06-11  8:39     ` Herbert Xu
  0 siblings, 1 reply; 31+ messages in thread
From: Cristian Ionescu-Idbohrn @ 2010-06-08 10:36 UTC (permalink / raw)
  To: dash

On Tue, 8 Jun 2010, Herbert Xu wrote:

> Jilles Tjoelker <jilles@stack.nl> wrote:
> > Debian's dash package has some local changes which cause an exit
> > with code 127, as required by POSIX, if a script (passed with dash
> > <filename>) cannot be opened or cannot be read because it is a
> > directory.

My interpretation of the above is that debian's patched dash is POSIX
compliant WRT the named exit code.

> Please report this through Debian's bug tracking system.

Why?

> There is nothing that I can do about this.

Upstream dash is _not_ POSIX compliant WRT the named exit code, seems
to be the meaning of the sentence.  And you can certainly _do_
something about it.

On the other hand, I may have got it all wrong (because of some
language barrier), in which case please accept my apologies.


Cheers,

-- 
Cristian

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: debian patches to exit with code 127 for nonexistent/directory scripts
  2010-06-08 10:36   ` Cristian Ionescu-Idbohrn
@ 2010-06-11  8:39     ` Herbert Xu
  0 siblings, 0 replies; 31+ messages in thread
From: Herbert Xu @ 2010-06-11  8:39 UTC (permalink / raw)
  To: dash

Cristian Ionescu-Idbohrn <cristian.ionescu-idbohrn@axis.com> wrote:
> On Tue, 8 Jun 2010, Herbert Xu wrote:
> 
>> Jilles Tjoelker <jilles@stack.nl> wrote:
>> > Debian's dash package has some local changes which cause an exit
>> > with code 127, as required by POSIX, if a script (passed with dash
>> > <filename>) cannot be opened or cannot be read because it is a
>> > directory.
> 
> My interpretation of the above is that debian's patched dash is POSIX
> compliant WRT the named exit code.

Well if dash is broken then you should submit a patch.

Thanks,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH] [INPUT] exit 127 if command_file is given but doesn't exist
  2010-06-05 16:06 debian patches to exit with code 127 for nonexistent/directory scripts Jilles Tjoelker
  2010-06-08 10:19 ` Herbert Xu
@ 2010-06-14  9:54 ` Gerrit Pape
  2010-06-28  6:53   ` Herbert Xu
  1 sibling, 1 reply; 31+ messages in thread
From: Gerrit Pape @ 2010-06-14  9:54 UTC (permalink / raw)
  To: dash

This commit makes dash exit with return code 127 instead of 2 if
started as non-interactive shell with a non-existent command_file
specified as argument (or a directory), as documented in
 http://www.opengroup.org/onlinepubs/009695399/utilities/sh.html#tag_04_128_14

The wrong exit code was reported by Clint Adams and Jari Aalto through
 http://bugs.debian.org/548743
 http://bugs.debian.org/548687

Signed-off-by: Gerrit Pape <pape@smarden.org>
---

On Sat, Jun 05, 2010 at 06:06:51PM +0200, Jilles Tjoelker wrote:
> Debian's dash package has some local changes which cause an exit with
> code 127, as required by POSIX, if a script (passed with dash
> <filename>) cannot be opened or cannot be read because it is a
> directory.
>
> Unfortunately, these patches also affect the . builtin (if the
> pathname
> contains a slash) and use EXEXIT, which means such errors always cause
> the shell to exit, even in interactive mode or if the builtin's
> specialness has been disabled using command.

Hi Jilles, thanks for the hint, I didn't notice.  I hope this patch does
better, it replaces these two
 http://article.gmane.org/gmane.comp.shells.dash/198
 http://article.gmane.org/gmane.comp.shells.dash/199

Regards, Gerrit.

 src/error.h |    1 +
 src/input.c |    7 +++++--
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/error.h b/src/error.h
index 3162e15..c75cb2c 100644
--- a/src/error.h
+++ b/src/error.h
@@ -69,6 +69,7 @@ extern int exception;
 #define EXSHELLPROC 2	/* execute a shell procedure */
 #define EXEXEC 3	/* command execution failed */
 #define EXEXIT 4	/* exit the shell */
+#define EXIFILE 5	/* inputfile cannot be opened or is a directory */
 
 
 /*
diff --git a/src/input.c b/src/input.c
index e57ad76..a43a7b9 100644
--- a/src/input.c
+++ b/src/input.c
@@ -54,6 +54,7 @@
 #include "parser.h"
 #include "main.h"
 #include "var.h"
+#include "eval.h"
 #ifndef SMALL
 #include "myhistedit.h"
 #endif
@@ -405,11 +406,13 @@ setinputfile(const char *fname, int flags)
 	int fd;
 
 	INTOFF;
-	if ((fd = open(fname, O_RDONLY)) < 0) {
+	if ((fd = open(fname, O_RDWR)) < 0) {
 		if (flags & INPUT_NOFILE_OK)
 			goto out;
-		sh_error("Can't open %s", fname);
+		exitstatus = 127;
+		exerror(EXIFILE, "Can't open %s", fname);
 	}
+	fcntl(fd, F_SETFL, O_RDONLY);
 	if (fd < 10)
 		fd = savefd(fd, fd);
 	setinputfd(fd, flags & INPUT_PUSH_FILE);
-- 
1.6.0.3


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH] [INPUT] exit 127 if command_file is given but doesn't exist
  2010-06-14  9:54 ` [PATCH] [INPUT] exit 127 if command_file is given but doesn't exist Gerrit Pape
@ 2010-06-28  6:53   ` Herbert Xu
  2010-10-06 10:04     ` [PATCH] [OPTIONS] Use exit status 127 when the script to run does not exist Jonathan Nieder
  0 siblings, 1 reply; 31+ messages in thread
From: Herbert Xu @ 2010-06-28  6:53 UTC (permalink / raw)
  To: Gerrit Pape; +Cc: dash

On Mon, Jun 14, 2010 at 09:54:51AM +0000, Gerrit Pape wrote:
>
> @@ -405,11 +406,13 @@ setinputfile(const char *fname, int flags)
>  	int fd;
>  
>  	INTOFF;
> -	if ((fd = open(fname, O_RDONLY)) < 0) {
> +	if ((fd = open(fname, O_RDWR)) < 0) {

Why should the file be writeable?

Please do not mix multiple changes in one patch.

>  		if (flags & INPUT_NOFILE_OK)
>  			goto out;
> -		sh_error("Can't open %s", fname);
> +		exitstatus = 127;
> +		exerror(EXIFILE, "Can't open %s", fname);
>  	}
> +	fcntl(fd, F_SETFL, O_RDONLY);

This is wrong.  You're creating exactly the problem that Jilles
was talking about where dot(1) is returning 127.  This code should
be moved to procargs, which runs only for the "sh script" case.

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH] [OPTIONS] Use exit status 127 when the script to run does not exist
  2010-06-28  6:53   ` Herbert Xu
@ 2010-10-06 10:04     ` Jonathan Nieder
  2010-10-06 10:08       ` [PATCH] [INPUT] Catch attempts to run a directory as a script Jonathan Nieder
  2010-11-28 12:06       ` [PATCH] [OPTIONS] Use exit status 127 when the script to run does not exist Herbert Xu
  0 siblings, 2 replies; 31+ messages in thread
From: Jonathan Nieder @ 2010-10-06 10:04 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Gerrit Pape, dash, Krzysztof A. Sobiecki

Currently dash uses exit status 2 to report failure to run a
script named on the command line that does not exist:

 $ sh nonexistent
 sh: Can't open nonexistent
 $ echo $?
 2

According to SUSv3 and SUSv4[1], the exit code should be 127.

So check errno when opening a command_file during argument
processing and exit(127) when it is ENOENT.  This check is in the
argument processing code to avoid collateral damage to code paths
that read scripts (such as the dot builtin).  Other errors (such
as EACCESS) while opening the command_file will still result in
an exit code of 2.

[1] http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html#tag_20_117_14

Reported-by: Clint Adams <schizo@debian.org>
Fixes: http://bugs.debian.org/548743
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
Herbert Xu wrote:

> This is wrong.  You're creating exactly the problem that Jilles
> was talking about where dot(1) is returning 127.  This code should
> be moved to procargs, which runs only for the "sh script" case.

Makes sense.  How does this look?

It still ignores attempts to run "sh directory"; see the next
patch for that.

 src/options.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/src/options.c b/src/options.c
index 6f381e6..5667b68 100644
--- a/src/options.c
+++ b/src/options.c
@@ -37,6 +37,7 @@
 #include <stdlib.h>
 
 #include "shell.h"
+#include "main.h"
 #define DEFINE_OPTIONS
 #include "options.h"
 #undef DEFINE_OPTIONS
@@ -156,7 +157,13 @@ procargs(int argc, char **argv)
 		if (*xargv)
 			goto setarg0;
 	} else if (!sflag) {
-		setinputfile(*xargv, 0);
+		if (setinputfile(*xargv, INPUT_NOFILE_OK) < 0) {
+			if (errno == ENOENT) {
+				exitstatus = 127;
+				exerror(EXEXIT, "Can't open %s", *xargv);
+			}
+			sh_error("Can't open %s", *xargv);
+		}
 setarg0:
 		arg0 = *xargv++;
 		commandname = arg0;
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH] [INPUT] Catch attempts to run a directory as a script
  2010-10-06 10:04     ` [PATCH] [OPTIONS] Use exit status 127 when the script to run does not exist Jonathan Nieder
@ 2010-10-06 10:08       ` Jonathan Nieder
  2010-10-06 10:29         ` Herbert Xu
  2010-11-28 12:06       ` [PATCH] [OPTIONS] Use exit status 127 when the script to run does not exist Herbert Xu
  1 sibling, 1 reply; 31+ messages in thread
From: Jonathan Nieder @ 2010-10-06 10:08 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

open() succeeds, though read() fails later, when a pathname
passed as argv[0] on the command line points to a directory,
which somehow results in dash thinking everything is okay:

 $ sh dir/
 $ echo $?
 0

But POSIX makes it clear enough that in "sh command_file",
command_file is supposed to be a file, not a directory.  So
diagnose this with an error message and exit with status 2.

Reported-by: Jari Aalto <jari.aalto@cante.net>
Fixes: http://bugs.debian.org/548687
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
Applies on top of the previous patch, which is based on
master.

Thanks to Gerrit and Krzysztof for your help so far.

 src/input.c |   21 ++++++++++++++++++++-
 1 files changed, 20 insertions(+), 1 deletions(-)

diff --git a/src/input.c b/src/input.c
index e57ad76..d68d441 100644
--- a/src/input.c
+++ b/src/input.c
@@ -395,6 +395,19 @@ popstring(void)
 }
 
+/*
+ * Is fd a directory file descriptor?
+ */
+
+static int
+isdir(const char *fname, int fd)
+{
+	struct stat64 statb;
+	if (fstat64(fd, &statb) < 0)
+		sh_error("Can't stat %s", fname);
+	return S_ISDIR(statb.st_mode);
+}
+
 /*
  * Set the input to take input from a file.  If push is set, push the
  * old input onto the stack first.
  */
@@ -405,7 +418,13 @@ setinputfile(const char *fname, int flags)
 	int fd;
 
 	INTOFF;
-	if ((fd = open(fname, O_RDONLY)) < 0) {
+	fd = open(fname, O_RDONLY);
+	if (isdir(fname, fd)) {
+		close(fd);
+		fd = -1;
+		errno = EISDIR;
+	}
+	if (fd < 0) {
 		if (flags & INPUT_NOFILE_OK)
 			goto out;
 		sh_error("Can't open %s", fname);
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH] [INPUT] Catch attempts to run a directory as a script
  2010-10-06 10:08       ` [PATCH] [INPUT] Catch attempts to run a directory as a script Jonathan Nieder
@ 2010-10-06 10:29         ` Herbert Xu
  2010-10-06 10:55           ` Jonathan Nieder
  0 siblings, 1 reply; 31+ messages in thread
From: Herbert Xu @ 2010-10-06 10:29 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

On Wed, Oct 06, 2010 at 05:08:04AM -0500, Jonathan Nieder wrote:
> open() succeeds, though read() fails later, when a pathname
> passed as argv[0] on the command line points to a directory,
> which somehow results in dash thinking everything is okay:
> 
>  $ sh dir/
>  $ echo $?
>  0
> 
> But POSIX makes it clear enough that in "sh command_file",
> command_file is supposed to be a file, not a directory.  So
> diagnose this with an error message and exit with status 2.
> 
> Reported-by: Jari Aalto <jari.aalto@cante.net>
> Fixes: http://bugs.debian.org/548687
> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>

Is this required by POSIX? If not this is simply making dash
bigger for no good reason.

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] [INPUT] Catch attempts to run a directory as a script
  2010-10-06 10:29         ` Herbert Xu
@ 2010-10-06 10:55           ` Jonathan Nieder
  2010-10-06 12:18             ` Eric Blake
  0 siblings, 1 reply; 31+ messages in thread
From: Jonathan Nieder @ 2010-10-06 10:55 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

Herbert Xu wrote:
> On Wed, Oct 06, 2010 at 05:08:04AM -0500, Jonathan Nieder wrote:

>> But POSIX makes it clear enough that in "sh command_file",
>> command_file is supposed to be a file, not a directory.  So
>> diagnose this with an error message and exit with status 2.
[...]
> Is this required by POSIX? If not this is simply making dash
> bigger for no good reason.

Not clear.  I suppose POSIX usually doesn't require anything when the
caller screws up.

Jari Aalto quoted the DESCRIPTION section[1] (and some similar
passages):

>    The sh utility is a command language interpreter that shall
>    execute commands read from a command line string, the standard
> >> input, or a specified file. 

I don't find that alone very convincing.

Under OPERANDS[2]: if the path contains a slash, all the standard says
is "the implementation attempts to read that file".  If the path does
not contain a slash and the file is not in the working directory, the
implementation _may_ perform a search as described in "Command Search
and Execution".

During that search, after execve() fails, "if the executable file is
not a text file, the shell _may_ bypass this command execution. In
this case, it shall write an error message, and shall return an exit
status of 126." (emphasis mine).

So this behavior is allowed as an optional subset of an optional
behavior.  That may have guided the bash implementors:

 $ bash directory
 directory: directory: is a directory
 $ echo $?
 126

It's probably not required.

[1] http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=10;bug=548687
[2] http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html#tag_20_117_05

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] [INPUT] Catch attempts to run a directory as a script
  2010-10-06 10:55           ` Jonathan Nieder
@ 2010-10-06 12:18             ` Eric Blake
  2010-10-06 12:31               ` Herbert Xu
  2010-10-07  1:02               ` [PATCH 0/3] Fix exit status for 'exec nonexistent' and 'exec .' Jonathan Nieder
  0 siblings, 2 replies; 31+ messages in thread
From: Eric Blake @ 2010-10-06 12:18 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Herbert Xu, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

On 10/06/2010 04:55 AM, Jonathan Nieder wrote:
>>> But POSIX makes it clear enough that in "sh command_file",
>>> command_file is supposed to be a file, not a directory.  So
>>> diagnose this with an error message and exit with status 2.
> [...]
>> Is this required by POSIX? If not this is simply making dash
>> bigger for no good reason.
>
> Not clear.  I suppose POSIX usually doesn't require anything when the
> caller screws up.

POSIX requires that input files to bash shall be text files; directories 
do not qualify for this.
http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html
"The input file shall be a text file, except that line lengths shall be 
unlimited. "

However, that is a requirement on the user, not the shell; so running 
'sh /' is a constraint violation by the user, and leaves behavior up to 
the shell.

> Under OPERANDS[2]: if the path contains a slash, all the standard says
> is "the implementation attempts to read that file".  If the path does
> not contain a slash and the file is not in the working directory, the
> implementation _may_ perform a search as described in "Command Search
> and Execution".

It's more than just MAY; it's a requirement:
http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_01_01

"If the command name contains at least one <slash>, the shell shall 
execute the utility in a separate utility environment with actions 
equivalent to calling the execve() function...

"If the execve() function fails due to an error equivalent to the 
[ENOEXEC] error, the shell shall execute a command equivalent to having 
a shell invoked with the command name as its first operand"

>
> During that search, after execve() fails, "if the executable file is
> not a text file, the shell _may_ bypass this command execution. In
> this case, it shall write an error message, and shall return an exit
> status of 126." (emphasis mine).

But yes, that same section is clear that for both command searches along 
PATH for a word without slash, and for a direct command with a slash, if 
execve() fails with ENOEXEC (as it does for directories), then it is 
optional whether the shell bypasses attempts to read the file because it 
was not a text file.

On the other hand, in Linux, execve(".",...) fails with EACCES, as 
permitted by the standard:

http://www.opengroup.org/onlinepubs/9699919799/functions/execve.html
"[EACCES] ...or the new process image file is not a regular file and the 
implementation does not support execution of files of its type."

And since EACCES is not the same class as ENOEXEC, there is no 
requirement for the shell to attempt to execute the same file.  So, 
rather than stat()ing the argument in advance and checking for S_ISDIR, 
it seems like it would be simpler to check after the execve() attempt 
for EACCES and blindly set $? to 126 in that case (since you already 
have to check for ENOEXEC).

> So this behavior is allowed as an optional subset of an optional
> behavior.  That may have guided the bash implementors:
>
>   $ bash directory
>   directory: directory: is a directory
>   $ echo $?
>   126
>
> It's probably not required.

Additionally, the standard REQUIRES that 'sh -c "exec /"' shall fail 
with status 126:

http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#exec
"If command is found, but it is not an executable utility, the exit 
status shall be 126."

Right now, dash gets this wrong:

dash -c 'exec .'; echo $?
exec: 1: /: Permission denied
2

And since you already have the code in dash to detect failure to 'exec' 
a directory, you should be able to reuse that code when detecting 
failure to run a directory as a script, as in 'dash .'.

[Hmm, bash also gets it wrong:
bash -c 'exec .'; echo $?
bash: line 0: exec: .: not found
127
even though . should always be found]

-- 
Eric Blake   eblake@redhat.com    +1-801-349-2682
Libvirt virtualization library http://libvirt.org

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] [INPUT] Catch attempts to run a directory as a script
  2010-10-06 12:18             ` Eric Blake
@ 2010-10-06 12:31               ` Herbert Xu
  2010-10-07  1:02               ` [PATCH 0/3] Fix exit status for 'exec nonexistent' and 'exec .' Jonathan Nieder
  1 sibling, 0 replies; 31+ messages in thread
From: Herbert Xu @ 2010-10-06 12:31 UTC (permalink / raw)
  To: Eric Blake
  Cc: Jonathan Nieder, Gerrit Pape, dash, Krzysztof A. Sobiecki,
	Jari Aalto

On Wed, Oct 06, 2010 at 06:18:05AM -0600, Eric Blake wrote:
>
> Right now, dash gets this wrong:
>
> dash -c 'exec .'; echo $?
> exec: 1: /: Permission denied
> 2
>
> And since you already have the code in dash to detect failure to 'exec'  
> a directory, you should be able to reuse that code when detecting  
> failure to run a directory as a script, as in 'dash .'.

Thanks for the detailed investiagtion!

If someone could send me a patch that does this without bloating
dash too much then I can apply it without feeling too much guilt :)

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 0/3] Fix exit status for 'exec nonexistent' and 'exec .'
  2010-10-06 12:18             ` Eric Blake
  2010-10-06 12:31               ` Herbert Xu
@ 2010-10-07  1:02               ` Jonathan Nieder
  2010-10-07  1:03                 ` [PATCH 1/3] [EXCEPTIONS] Stop documenting EXSHELLPROC Jonathan Nieder
                                   ` (2 more replies)
  1 sibling, 3 replies; 31+ messages in thread
From: Jonathan Nieder @ 2010-10-07  1:02 UTC (permalink / raw)
  To: Eric Blake
  Cc: Herbert Xu, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

Eric Blake wrote:

> Additionally, the standard REQUIRES that 'sh -c "exec /"' shall fail
> with status 126:
> 
> http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#exec
> "If command is found, but it is not an executable utility, the exit
> status shall be 126."
> 
> Right now, dash gets this wrong:
> 
> dash -c 'exec .'; echo $?
> exec: 1: /: Permission denied
> 2
> 
> And since you already have the code in dash to detect failure to
> 'exec' a directory, you should be able to reuse that code when
> detecting failure to run a directory as a script, as in 'dash .'.

Summary:

   Command		Status	Expected status
1) exec .		2	126
2) exec nonexistent	2	127
3) sh .			0	126
4) sh nonexistent	2	127

(1) and (2) seem to be regressions from about 5 years ago.
Reverting the problematic patch fixes it for me; see below.

(3) is not clearly documented in the standard, and there is
some disagreement between shells on how to handle it[1].  The
current behavior seems fine to me.

(4) is a clear bug, well documented in the EXIT STATUS section
of the description of sh in the "Utilities" chapter.  See
http://thread.gmane.org/gmane.comp.shells.dash/291/focus=390
for a patch[2].

Thoughts?
Jonathan Nieder (3):
  [EXCEPTIONS] Stop documenting EXSHELLPROC
  Revert "Eliminated global exerrno."
  [EXCEPTIONS] Eliminate global exerrno

 src/TOUR    |   11 +----------
 src/error.h |    5 ++---
 src/eval.c  |    8 ++++----
 3 files changed, 7 insertions(+), 17 deletions(-)

[1]
$ bash .; echo $?
.: .: is a directory
126
$ ksh93 .; echo $?
ksh93: .: cannot open [Is a directory]
126
$ pdksh .; echo $?
0

[2] Unfortunately this does not share code with the fix to (1)
and (2) as Eric hoped.  Why?  The system calls involved are
different: the exec builtin uses execve(), while 'sh <script>'
uses open() and read().

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 1/3] [EXCEPTIONS] Stop documenting EXSHELLPROC
  2010-10-07  1:02               ` [PATCH 0/3] Fix exit status for 'exec nonexistent' and 'exec .' Jonathan Nieder
@ 2010-10-07  1:03                 ` Jonathan Nieder
  2010-10-07  3:01                   ` Herbert Xu
  2010-10-07  1:04                 ` [PATCH 2/3] Revert "Eliminated global exerrno." Jonathan Nieder
  2010-10-07  1:08                 ` [PATCH 3/3] [EXCEPTIONS] Eliminate global exerrno Jonathan Nieder
  2 siblings, 1 reply; 31+ messages in thread
From: Jonathan Nieder @ 2010-10-07  1:03 UTC (permalink / raw)
  To: Eric Blake
  Cc: Herbert Xu, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

At some point between ash 0.3.5-11.0.1 and ash 0.3.8-37, Debian
ash stopped using the EXSHELLPROC exception to handle shell
scripts without a magic number.

Remove all remaining references to it to avoid confusion.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 src/TOUR    |   11 +----------
 src/error.h |    5 ++---
 2 files changed, 3 insertions(+), 13 deletions(-)

diff --git a/src/TOUR b/src/TOUR
index 4baac62..056e79b 100644
--- a/src/TOUR
+++ b/src/TOUR
@@ -43,10 +43,6 @@ C source files for entries looking like:
                            back to the main command loop */
         }
 
-        SHELLPROC {
-              x = 3;    /* executed when the shell runs a shell procedure */
-        }
-
 It pulls this code out into routines which are when particular
 events occur.  The intent is to improve modularity by isolating
 the information about which modules need to be explicitly
@@ -79,12 +75,7 @@ EXCEPTIONS:  Code for dealing with exceptions appears in
 exceptions.c.  The C language doesn't include exception handling,
 so I implement it using setjmp and longjmp.  The global variable
 exception contains the type of exception.  EXERROR is raised by
-calling error.  EXINT is an interrupt.  EXSHELLPROC is an excep-
-tion which is raised when a shell procedure is invoked.  The pur-
-pose of EXSHELLPROC is to perform the cleanup actions associated
-with other exceptions.  After these cleanup actions, the shell
-can interpret a shell procedure itself without exec'ing a new
-copy of the shell.
+calling error.  EXINT is an interrupt.
 
 INTERRUPTS:  In an interactive shell, an interrupt will cause an
 EXINT exception to return to the main command loop.  (Exception:
diff --git a/src/error.h b/src/error.h
index 3162e15..15ccbe3 100644
--- a/src/error.h
+++ b/src/error.h
@@ -66,9 +66,8 @@ extern int exception;
 /* exceptions */
 #define EXINT 0		/* SIGINT received */
 #define EXERROR 1	/* a generic error */
-#define EXSHELLPROC 2	/* execute a shell procedure */
-#define EXEXEC 3	/* command execution failed */
-#define EXEXIT 4	/* exit the shell */
+#define EXEXEC 2	/* command execution failed */
+#define EXEXIT 3	/* exit the shell */
 
 
 /*
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 2/3] Revert "Eliminated global exerrno."
  2010-10-07  1:02               ` [PATCH 0/3] Fix exit status for 'exec nonexistent' and 'exec .' Jonathan Nieder
  2010-10-07  1:03                 ` [PATCH 1/3] [EXCEPTIONS] Stop documenting EXSHELLPROC Jonathan Nieder
@ 2010-10-07  1:04                 ` Jonathan Nieder
  2010-10-07  2:56                   ` Herbert Xu
  2010-10-07  1:08                 ` [PATCH 3/3] [EXCEPTIONS] Eliminate global exerrno Jonathan Nieder
  2 siblings, 1 reply; 31+ messages in thread
From: Jonathan Nieder @ 2010-10-07  1:04 UTC (permalink / raw)
  To: Eric Blake
  Cc: Herbert Xu, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

This reverts commit c0e07c010e5abdea1a7d1357edb1d08adac529cb.

Yes, it is nicer to pass the exit status through the exitstatus
global, but look at the consequences:

 $ sh -c 'exec nonexistent'; echo $?
 exec: 1: nonexistent: not found
 2
 $ sh -c 'exec .'; echo $?
 exec: 1: .: Permission denied
 2

According to POSIX:
"If command is not found, the exit status shall be 127. If command is
found, but it is not an executable utility, the exit status shall
be 126."

Make it so again.

Reported-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 src/error.h |    1 +
 src/exec.c  |    3 +--
 src/main.c  |    2 ++
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/error.h b/src/error.h
index 15ccbe3..1bb6a82 100644
--- a/src/error.h
+++ b/src/error.h
@@ -62,6 +62,7 @@ struct jmploc {
 
 extern struct jmploc *handler;
 extern int exception;
+extern int exerrno;	/* error for EXEXEC */
 
 /* exceptions */
 #define EXINT 0		/* SIGINT received */
diff --git a/src/exec.c b/src/exec.c
index 42299ea..9525a16 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -86,6 +86,7 @@ struct tblentry {
 
 STATIC struct tblentry *cmdtable[CMDTABLESIZE];
 STATIC int builtinloc = -1;		/* index in path of %builtin, or -1 */
+int exerrno;				/* Last exec error */
 
 
 STATIC void tryexec(char *, char **, char **);
@@ -108,7 +109,6 @@ shellexec(char **argv, const char *path, int idx)
 	char *cmdname;
 	int e;
 	char **envp;
-	int exerrno;
 
 	envp = environment();
 	if (strchr(argv[0], '/') != NULL) {
@@ -138,7 +138,6 @@ shellexec(char **argv, const char *path, int idx)
 		exerrno = 2;
 		break;
 	}
-	exitstatus = exerrno;
 	TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
 		argv[0], e, suppressint ));
 	exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
diff --git a/src/main.c b/src/main.c
index 2bff956..5bc1a99 100644
--- a/src/main.c
+++ b/src/main.c
@@ -115,6 +115,8 @@ main(int argc, char **argv)
 		e = exception;
 		if (e == EXERROR)
 			exitstatus = 2;
+		else if (e == EXEXEC)
+			exitstatus = exerrno;
 
 		s = state;
 		if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 3/3] [EXCEPTIONS] Eliminate global exerrno
  2010-10-07  1:02               ` [PATCH 0/3] Fix exit status for 'exec nonexistent' and 'exec .' Jonathan Nieder
  2010-10-07  1:03                 ` [PATCH 1/3] [EXCEPTIONS] Stop documenting EXSHELLPROC Jonathan Nieder
  2010-10-07  1:04                 ` [PATCH 2/3] Revert "Eliminated global exerrno." Jonathan Nieder
@ 2010-10-07  1:08                 ` Jonathan Nieder
  2010-10-07  3:00                   ` Herbert Xu
  2 siblings, 1 reply; 31+ messages in thread
From: Jonathan Nieder @ 2010-10-07  1:08 UTC (permalink / raw)
  To: Eric Blake
  Cc: Herbert Xu, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

Pass the exit status from the exec builtin through the exitstatus
global.  This just eliminates a global variable; no noticeable
change is intended.

Based on v0.5.3~57 (Eliminated global exerrno, 2005-02-25).

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
That's the end of the series.  Thanks for reading.

 src/error.h |    1 -
 src/eval.c  |    8 ++++----
 src/exec.c  |    3 ++-
 src/main.c  |    2 --
 4 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/src/error.h b/src/error.h
index 1bb6a82..15ccbe3 100644
--- a/src/error.h
+++ b/src/error.h
@@ -62,7 +62,6 @@ struct jmploc {
 
 extern struct jmploc *handler;
 extern int exception;
-extern int exerrno;	/* error for EXEXEC */
 
 /* exceptions */
 #define EXINT 0		/* SIGINT received */
diff --git a/src/eval.c b/src/eval.c
index 5b8d36b..0406571 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -850,15 +850,15 @@ bail:
 				listsetvar(varlist.list, VEXPORT);
 		}
 		if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
-			int status;
 			int i;
 
 			i = exception;
 			if (i == EXEXIT)
 				goto raise;
-
-			status = (i == EXINT) ? SIGINT + 128 : 2;
-			exitstatus = status;
+			if (i == EXINT)
+				exitstatus = SIGINT + 128;
+			if (i == EXERROR)
+				exitstatus = 2;
 
 			if (i == EXINT || spclbltin > 0) {
 raise:
diff --git a/src/exec.c b/src/exec.c
index 9525a16..42299ea 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -86,7 +86,6 @@ struct tblentry {
 
 STATIC struct tblentry *cmdtable[CMDTABLESIZE];
 STATIC int builtinloc = -1;		/* index in path of %builtin, or -1 */
-int exerrno;				/* Last exec error */
 
 
 STATIC void tryexec(char *, char **, char **);
@@ -109,6 +108,7 @@ shellexec(char **argv, const char *path, int idx)
 	char *cmdname;
 	int e;
 	char **envp;
+	int exerrno;
 
 	envp = environment();
 	if (strchr(argv[0], '/') != NULL) {
@@ -138,6 +138,7 @@ shellexec(char **argv, const char *path, int idx)
 		exerrno = 2;
 		break;
 	}
+	exitstatus = exerrno;
 	TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
 		argv[0], e, suppressint ));
 	exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
diff --git a/src/main.c b/src/main.c
index 5bc1a99..2bff956 100644
--- a/src/main.c
+++ b/src/main.c
@@ -115,8 +115,6 @@ main(int argc, char **argv)
 		e = exception;
 		if (e == EXERROR)
 			exitstatus = 2;
-		else if (e == EXEXEC)
-			exitstatus = exerrno;
 
 		s = state;
 		if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/3] Revert "Eliminated global exerrno."
  2010-10-07  1:04                 ` [PATCH 2/3] Revert "Eliminated global exerrno." Jonathan Nieder
@ 2010-10-07  2:56                   ` Herbert Xu
  2010-10-07  3:35                     ` Jonathan Nieder
  0 siblings, 1 reply; 31+ messages in thread
From: Herbert Xu @ 2010-10-07  2:56 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Eric Blake, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

On Wed, Oct 06, 2010 at 08:04:58PM -0500, Jonathan Nieder wrote:
> This reverts commit c0e07c010e5abdea1a7d1357edb1d08adac529cb.
> 
> Yes, it is nicer to pass the exit status through the exitstatus
> global, but look at the consequences:
> 
>  $ sh -c 'exec nonexistent'; echo $?
>  exec: 1: nonexistent: not found
>  2
>  $ sh -c 'exec .'; echo $?
>  exec: 1: .: Permission denied
>  2
> 
> According to POSIX:
> "If command is not found, the exit status shall be 127. If command is
> found, but it is not an executable utility, the exit status shall
> be 126."
> 
> Make it so again.
> 
> Reported-by: Eric Blake <eblake@redhat.com>
> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>

Actually the bug is elsewhere.  This patch works for me.

commit 7f684260a2426ac61c06d2e4822429b00437ae24
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Thu Oct 7 10:55:15 2010 +0800

    [BUILTIN] Fix EXEXEC status clobbering
    
    evalcommand always clobbers the exit status in case of an EXEXEC
    which means that exec always fails with exit status 2 regardless
    of what it actually returns.
    
    This patch adds the missing check for EXEXEC so that the correct
    exit status is preserved.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

diff --git a/ChangeLog b/ChangeLog
index 1dfe241..2faaedd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2010-10-07  Herbert Xu <herbert@gondor.apana.org.au>
+
+	* Fix EXEXEC status clobbering.
+
 2010-09-08  Herbert Xu <herbert@gondor.apana.org.au>
 
 	* Fix ifsfirst/ifslastp leak.
diff --git a/src/eval.c b/src/eval.c
index 5b8d36b..b966749 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -854,7 +854,7 @@ bail:
 			int i;
 
 			i = exception;
-			if (i == EXEXIT)
+			if (i == EXEXIT || i == EXEXEC)
 				goto raise;
 
 			status = (i == EXINT) ? SIGINT + 128 : 2;

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH 3/3] [EXCEPTIONS] Eliminate global exerrno
  2010-10-07  1:08                 ` [PATCH 3/3] [EXCEPTIONS] Eliminate global exerrno Jonathan Nieder
@ 2010-10-07  3:00                   ` Herbert Xu
  0 siblings, 0 replies; 31+ messages in thread
From: Herbert Xu @ 2010-10-07  3:00 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Eric Blake, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

On Wed, Oct 06, 2010 at 08:08:07PM -0500, Jonathan Nieder wrote:
> Pass the exit status from the exec builtin through the exitstatus
> global.  This just eliminates a global variable; no noticeable
> change is intended.
> 
> Based on v0.5.3~57 (Eliminated global exerrno, 2005-02-25).
> 
> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>

Heh, had you sent 2/3 and 3/3 as one patch I would've seen the
problem and just applied it :)

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/3] [EXCEPTIONS] Stop documenting EXSHELLPROC
  2010-10-07  1:03                 ` [PATCH 1/3] [EXCEPTIONS] Stop documenting EXSHELLPROC Jonathan Nieder
@ 2010-10-07  3:01                   ` Herbert Xu
  2010-10-07  3:04                     ` Jonathan Nieder
  0 siblings, 1 reply; 31+ messages in thread
From: Herbert Xu @ 2010-10-07  3:01 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Eric Blake, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

On Wed, Oct 06, 2010 at 08:03:47PM -0500, Jonathan Nieder wrote:
>
> diff --git a/src/error.h b/src/error.h
> index 3162e15..15ccbe3 100644
> --- a/src/error.h
> +++ b/src/error.h
> @@ -66,9 +66,8 @@ extern int exception;
>  /* exceptions */
>  #define EXINT 0		/* SIGINT received */
>  #define EXERROR 1	/* a generic error */
> -#define EXSHELLPROC 2	/* execute a shell procedure */
> -#define EXEXEC 3	/* command execution failed */
> -#define EXEXIT 4	/* exit the shell */
> +#define EXEXEC 2	/* command execution failed */
> +#define EXEXIT 3	/* exit the shell */

There is no need to renumber things.  Just leave a gap.

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/3] [EXCEPTIONS] Stop documenting EXSHELLPROC
  2010-10-07  3:01                   ` Herbert Xu
@ 2010-10-07  3:04                     ` Jonathan Nieder
  2010-10-07  3:29                       ` Herbert Xu
  0 siblings, 1 reply; 31+ messages in thread
From: Jonathan Nieder @ 2010-10-07  3:04 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Eric Blake, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

Herbert Xu wrote:
> On Wed, Oct 06, 2010 at 08:03:47PM -0500, Jonathan Nieder wrote:

>> --- a/src/error.h
>> +++ b/src/error.h
>> @@ -66,9 +66,8 @@ extern int exception;
>>  /* exceptions */
>>  #define EXINT 0		/* SIGINT received */
>>  #define EXERROR 1	/* a generic error */
>> -#define EXSHELLPROC 2	/* execute a shell procedure */
>> -#define EXEXEC 3	/* command execution failed */
>> -#define EXEXIT 4	/* exit the shell */
>> +#define EXEXEC 2	/* command execution failed */
>> +#define EXEXIT 3	/* exit the shell */
>
> There is no need to renumber things.  Just leave a gap.

Ok.  Should I fix it up or would you like to?

Thanks,
Jonathan

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/3] [EXCEPTIONS] Stop documenting EXSHELLPROC
  2010-10-07  3:04                     ` Jonathan Nieder
@ 2010-10-07  3:29                       ` Herbert Xu
  2010-10-07  3:39                         ` [PATCH v2] " Jonathan Nieder
  0 siblings, 1 reply; 31+ messages in thread
From: Herbert Xu @ 2010-10-07  3:29 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Eric Blake, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

On Wed, Oct 06, 2010 at 10:04:14PM -0500, Jonathan Nieder wrote:
> Herbert Xu wrote:
> > On Wed, Oct 06, 2010 at 08:03:47PM -0500, Jonathan Nieder wrote:
> 
> >> --- a/src/error.h
> >> +++ b/src/error.h
> >> @@ -66,9 +66,8 @@ extern int exception;
> >>  /* exceptions */
> >>  #define EXINT 0		/* SIGINT received */
> >>  #define EXERROR 1	/* a generic error */
> >> -#define EXSHELLPROC 2	/* execute a shell procedure */
> >> -#define EXEXEC 3	/* command execution failed */
> >> -#define EXEXIT 4	/* exit the shell */
> >> +#define EXEXEC 2	/* command execution failed */
> >> +#define EXEXIT 3	/* exit the shell */
> >
> > There is no need to renumber things.  Just leave a gap.
> 
> Ok.  Should I fix it up or would you like to?

Yeah please resend the patch with the fix-up.

Thanks!
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/3] Revert "Eliminated global exerrno."
  2010-10-07  2:56                   ` Herbert Xu
@ 2010-10-07  3:35                     ` Jonathan Nieder
  2010-10-07  4:14                       ` Herbert Xu
  2010-11-28 12:45                       ` Herbert Xu
  0 siblings, 2 replies; 31+ messages in thread
From: Jonathan Nieder @ 2010-10-07  3:35 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Eric Blake, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

Herbert Xu wrote:

> Actually the bug is elsewhere.

It does bisect to there. :)  But you're right, it would have been
simpler to send one patch.

> --- a/src/eval.c
> +++ b/src/eval.c
> @@ -854,7 +854,7 @@ bail:
>  			int i;
>  
>  			i = exception;
> -			if (i == EXEXIT)
> +			if (i == EXEXIT || i == EXEXEC)
>  				goto raise;

Good call.  This is better than my patch because it exits like it
ought to for

	command exec nonexistent

(as POSIX says:

	If command is specified, exec shall not return to the shell

).

Maybe the following would make sense on top?

-- 8< --
Subject: [EXCEPTIONS] Use EXEXIT in place of EXEXEC

The intended semantics of EXEXEC are identical to EXEXIT, so
simplify by using EXEXIT directly.

Functional change: in edge cases (exec within a trap handler),
this causes the exit status from exec not to be clobbered.
For example, without this patch:

 $ sh -c 'trap "exec nonexistent" EXIT'; echo $?
 exec: 1: nonexistent: not found
 0

And with it:

 $ sh -c 'trap "exec nonexistent" EXIT'; echo $?
 exec: 1: nonexistent: not found
 127

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 src/error.h |    1 -
 src/eval.c  |    2 +-
 src/exec.c  |    2 +-
 3 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/error.h b/src/error.h
index be0eec9..f236d9f 100644
--- a/src/error.h
+++ b/src/error.h
@@ -66,7 +66,6 @@ extern int exception;
 /* exceptions */
 #define EXINT 0		/* SIGINT received */
 #define EXERROR 1	/* a generic error */
-#define EXEXEC 3	/* command execution failed */
 #define EXEXIT 4	/* exit the shell */
 
 
diff --git a/src/eval.c b/src/eval.c
index b966749..5b8d36b 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -854,7 +854,7 @@ bail:
 			int i;
 
 			i = exception;
-			if (i == EXEXIT || i == EXEXEC)
+			if (i == EXEXIT)
 				goto raise;
 
 			status = (i == EXINT) ? SIGINT + 128 : 2;
diff --git a/src/exec.c b/src/exec.c
index 42299ea..b273420 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -141,7 +141,7 @@ shellexec(char **argv, const char *path, int idx)
 	exitstatus = exerrno;
 	TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
 		argv[0], e, suppressint ));
-	exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
+	exerror(EXEXIT, "%s: %s", argv[0], errmsg(e, E_EXEC));
 	/* NOTREACHED */
 }
 
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v2] [EXCEPTIONS] Stop documenting EXSHELLPROC
  2010-10-07  3:29                       ` Herbert Xu
@ 2010-10-07  3:39                         ` Jonathan Nieder
  2010-11-28 12:47                           ` Herbert Xu
  0 siblings, 1 reply; 31+ messages in thread
From: Jonathan Nieder @ 2010-10-07  3:39 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Eric Blake, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

At some point between ash 0.3.5-11.0.1 and ash 0.3.8-37, Debian
ash stopped using the EXSHELLPROC exception to handle shell
scripts without a magic number.

Remove all remaining references to it to avoid confusion.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
Herbert Xu wrote:

> Yeah please resend the patch with the fix-up.

Done.  (Patch is against master, as before.)

 src/TOUR    |   11 +----------
 src/error.h |    1 -
 2 files changed, 1 insertions(+), 11 deletions(-)

diff --git a/src/TOUR b/src/TOUR
index 4baac62..056e79b 100644
--- a/src/TOUR
+++ b/src/TOUR
@@ -43,10 +43,6 @@ C source files for entries looking like:
                            back to the main command loop */
         }
 
-        SHELLPROC {
-              x = 3;    /* executed when the shell runs a shell procedure */
-        }
-
 It pulls this code out into routines which are when particular
 events occur.  The intent is to improve modularity by isolating
 the information about which modules need to be explicitly
@@ -79,12 +75,7 @@ EXCEPTIONS:  Code for dealing with exceptions appears in
 exceptions.c.  The C language doesn't include exception handling,
 so I implement it using setjmp and longjmp.  The global variable
 exception contains the type of exception.  EXERROR is raised by
-calling error.  EXINT is an interrupt.  EXSHELLPROC is an excep-
-tion which is raised when a shell procedure is invoked.  The pur-
-pose of EXSHELLPROC is to perform the cleanup actions associated
-with other exceptions.  After these cleanup actions, the shell
-can interpret a shell procedure itself without exec'ing a new
-copy of the shell.
+calling error.  EXINT is an interrupt.
 
 INTERRUPTS:  In an interactive shell, an interrupt will cause an
 EXINT exception to return to the main command loop.  (Exception:
diff --git a/src/error.h b/src/error.h
index 3162e15..be0eec9 100644
--- a/src/error.h
+++ b/src/error.h
@@ -66,7 +66,6 @@ extern int exception;
 /* exceptions */
 #define EXINT 0		/* SIGINT received */
 #define EXERROR 1	/* a generic error */
-#define EXSHELLPROC 2	/* execute a shell procedure */
 #define EXEXEC 3	/* command execution failed */
 #define EXEXIT 4	/* exit the shell */
 
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/3] Revert "Eliminated global exerrno."
  2010-10-07  3:35                     ` Jonathan Nieder
@ 2010-10-07  4:14                       ` Herbert Xu
  2010-10-07  4:37                         ` Herbert Xu
  2010-11-28 12:45                       ` Herbert Xu
  1 sibling, 1 reply; 31+ messages in thread
From: Herbert Xu @ 2010-10-07  4:14 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Eric Blake, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

On Wed, Oct 06, 2010 at 10:35:18PM -0500, Jonathan Nieder wrote:
> Herbert Xu wrote:
> 
> > Actually the bug is elsewhere.
> 
> It does bisect to there. :)  But you're right, it would have been
> simpler to send one patch.
> 
> > --- a/src/eval.c
> > +++ b/src/eval.c
> > @@ -854,7 +854,7 @@ bail:
> >  			int i;
> >  
> >  			i = exception;
> > -			if (i == EXEXIT)
> > +			if (i == EXEXIT || i == EXEXEC)
> >  				goto raise;
> 
> Good call.  This is better than my patch because it exits like it
> ought to for
> 
> 	command exec nonexistent
> 
> (as POSIX says:
> 
> 	If command is specified, exec shall not return to the shell
> 
> ).
> 
> Maybe the following would make sense on top?

Nice! I like where you are going with this :)

Let me run it through the tests and apply it.

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/3] Revert "Eliminated global exerrno."
  2010-10-07  4:14                       ` Herbert Xu
@ 2010-10-07  4:37                         ` Herbert Xu
  2010-10-07 21:34                           ` Jonathan Nieder
  0 siblings, 1 reply; 31+ messages in thread
From: Herbert Xu @ 2010-10-07  4:37 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Eric Blake, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

On Thu, Oct 07, 2010 at 12:14:06PM +0800, Herbert Xu wrote:
>
> Let me run it through the tests and apply it.

There is one problem with this and that is changing the exit
status in a trap:

	sh -c 'trap "exec nosuchfile" EXIT; exit 3'; echo $?

This makes dash exit with 127 instead of 3 as it does now.

AFAIK the wording of POSIX is such that we should return 3, however,
it does seem that every other shell exits with 127.

So unless anyone objects, I will apply your patch and adopt this
new behaviour.

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/3] Revert "Eliminated global exerrno."
  2010-10-07  4:37                         ` Herbert Xu
@ 2010-10-07 21:34                           ` Jonathan Nieder
  0 siblings, 0 replies; 31+ messages in thread
From: Jonathan Nieder @ 2010-10-07 21:34 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Eric Blake, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

Herbert Xu wrote:

> 	sh -c 'trap "exec nosuchfile" EXIT; exit 3'; echo $?
> 
> This makes dash exit with 127 instead of 3 as it does now.
> 
> AFAIK the wording of POSIX is such that we should return 3, however,
> it does seem that every other shell exits with 127.

On 'exec':

 "If exec is specified with command, it shall replace the shell with
 command without creating a new process."		(1)

 "If command is specified, exec shall not return to the shell; rather,
 the exit status of the process shall be the exit status of the program
 implementing command, which overlaid the shell. If command is not
 found, the exit status shall be 127. If command is found, but it is
 not an executable utility, the exit status shall be 126. If a
 redirection error occurs (see Consequences of Shell Errors ), the
 shell shall exit with a value in the range 1-125. Otherwise, exec
 shall return a zero exit status."			(2)

On 'exit':

 "...
 A trap on EXIT shall be executed before the shell terminates, except
 when the exit utility is invoked in that trap itself, in which case
 the shell shall exit immediately."			(3)

 "The exit status [of the exit utility -jrn] shall be n, if specified.
 Otherwise, the value shall be the exit value of the last command
 executed, or zero if no command was executed. When exit is executed in
 a trap action, the last command is considered to be the command that
 executed immediately preceding the trap action."	(4)

The passage (3) seems to mean that "exit" triggers an EXIT trap
(except, to avoid having to deal with recursion, when the "exit"
occurs within an EXIT trap).  Then the exec builtin is invoked,
resulting (according to (2)) in an exit(127) without returning to the
shell.

So I think the proposed behavior fits the spec.

Regards,
Jonathan

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] [OPTIONS] Use exit status 127 when the script to run does not exist
  2010-10-06 10:04     ` [PATCH] [OPTIONS] Use exit status 127 when the script to run does not exist Jonathan Nieder
  2010-10-06 10:08       ` [PATCH] [INPUT] Catch attempts to run a directory as a script Jonathan Nieder
@ 2010-11-28 12:06       ` Herbert Xu
  2010-11-28 12:24         ` Herbert Xu
  1 sibling, 1 reply; 31+ messages in thread
From: Herbert Xu @ 2010-11-28 12:06 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: Gerrit Pape, dash, Krzysztof A. Sobiecki

On Wed, Oct 06, 2010 at 05:04:20AM -0500, Jonathan Nieder wrote:
>
> Herbert Xu wrote:
> 
> > This is wrong.  You're creating exactly the problem that Jilles
> > was talking about where dot(1) is returning 127.  This code should
> > be moved to procargs, which runs only for the "sh script" case.
> 
> Makes sense.  How does this look?
> 
> It still ignores attempts to run "sh directory"; see the next
> patch for that.

Actually I was wrong.  I had misunderstood Jilles' report and
thought that the problem is with 127 coming from dotcmd.  His
problem is actually with dotcmd bailing out which your (or was
it Gerrit's?) EXFILE patch already addressed.

However, instead of adding an ad-hoc exception for EXFILE, I'm
simply going to move the exit status setting for EXERROR out of
main.c and into error.c which should let you get what you want.

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH] [OPTIONS] Use exit status 127 when the script to run does not exist
  2010-11-28 12:06       ` [PATCH] [OPTIONS] Use exit status 127 when the script to run does not exist Herbert Xu
@ 2010-11-28 12:24         ` Herbert Xu
  2010-11-28 12:33           ` Herbert Xu
  0 siblings, 1 reply; 31+ messages in thread
From: Herbert Xu @ 2010-11-28 12:24 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: Gerrit Pape, dash, Krzysztof A. Sobiecki

On Sun, Nov 28, 2010 at 08:06:27PM +0800, Herbert Xu wrote:
>
> However, instead of adding an ad-hoc exception for EXFILE, I'm
> simply going to move the exit status setting for EXERROR out of
> main.c and into error.c which should let you get what you want.

Something like this:

commit a42317f10233cf2fcff033cc705fd14315188374
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Sun Nov 28 20:22:00 2010 +0800

    [ERROR] Allow the originator of EXERROR to set the exit status
    
    Some errors have exit status values specified by POSIX and it is
    therefore desirable to be able to set the exit status at the EXERROR
    source rather than in main.c.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

diff --git a/ChangeLog b/ChangeLog
index 76cbeb4..e5479a8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,7 @@
 2010-11-28  Herbert Xu <herbert@gondor.apana.org.au>
 
 	* Fixed trap/return regression due to SKIPEVAL removal.
+	* Allow the originator of EXERROR to set the exit status.
 
 2010-10-18  Herbert Xu <herbert@gondor.apana.org.au>
 
diff --git a/src/error.c b/src/error.c
index e304d3d..f1a358d 100644
--- a/src/error.c
+++ b/src/error.c
@@ -163,6 +163,8 @@ sh_error(const char *msg, ...)
 {
 	va_list ap;
 
+	exitstatus = 2;
+
 	va_start(ap, msg);
 	exverror(EXERROR, msg, ap);
 	/* NOTREACHED */
diff --git a/src/eval.c b/src/eval.c
index ea4afc6..013a8dd 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -823,11 +823,13 @@ evalcommand(union node *cmd, int flags)
 	}
 
 	if (status) {
+bail:
+		exitstatus = status;
+
 		/* We have a redirection error. */
 		if (spclbltin > 0)
 			exraise(EXERROR);
-bail:
-		exitstatus = status;
+
 		goto out;
 	}
 
diff --git a/src/main.c b/src/main.c
index 2bff956..1735c67 100644
--- a/src/main.c
+++ b/src/main.c
@@ -113,8 +113,6 @@ main(int argc, char **argv)
 		reset();
 
 		e = exception;
-		if (e == EXERROR)
-			exitstatus = 2;
 
 		s = state;
 		if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH] [OPTIONS] Use exit status 127 when the script to run does not exist
  2010-11-28 12:24         ` Herbert Xu
@ 2010-11-28 12:33           ` Herbert Xu
  0 siblings, 0 replies; 31+ messages in thread
From: Herbert Xu @ 2010-11-28 12:33 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: Gerrit Pape, dash, Krzysztof A. Sobiecki

On Sun, Nov 28, 2010 at 08:24:37PM +0800, Herbert Xu wrote:
> On Sun, Nov 28, 2010 at 08:06:27PM +0800, Herbert Xu wrote:
> >
> > However, instead of adding an ad-hoc exception for EXFILE, I'm
> > simply going to move the exit status setting for EXERROR out of
> > main.c and into error.c which should let you get what you want.
> 
> Something like this:

And here is the final patch that I applied for this:

commit 34f60a3781ea8f17f3d2a1a743a9aab9b31a296f
Author: Gerrit Pape <pape@smarden.org>
Date:   Sun Nov 28 20:32:00 2010 +0800

    [INPUT] Use exit status 127 when the script to run does not exist
    
    This commit makes dash exit with return code 127 instead of 2 if
    started as non-interactive shell with a non-existent command_file
    specified as argument (or a directory), as documented in
     http://www.opengroup.org/onlinepubs/009695399/utilities/sh.html#tag_04_128_14
    
    The wrong exit code was reported by Clint Adams and Jari Aalto through
     http://bugs.debian.org/548743
     http://bugs.debian.org/548687
    
    Signed-off-by: Gerrit Pape <pape@smarden.org>
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

diff --git a/ChangeLog b/ChangeLog
index e5479a8..a18838c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2010-11-28  Gerrit Pape <pape@smarden.org>
+
+	* Use exit status 127 when the script to run does not exist.
+
 2010-11-28  Philipp Weis <pweis@pweis.com>
 
 	* Document optional open parenthesis for case patterns.
diff --git a/src/input.c b/src/input.c
index e57ad76..bd3a9a2 100644
--- a/src/input.c
+++ b/src/input.c
@@ -42,6 +42,7 @@
  * This file implements the input routines used by the parser.
  */
 
+#include "eval.h"
 #include "shell.h"
 #include "redir.h"
 #include "syntax.h"
@@ -408,7 +409,8 @@ setinputfile(const char *fname, int flags)
 	if ((fd = open(fname, O_RDONLY)) < 0) {
 		if (flags & INPUT_NOFILE_OK)
 			goto out;
-		sh_error("Can't open %s", fname);
+		exitstatus = 127;
+		exerror(EXERROR, "Can't open %s", fname);
 	}
 	if (fd < 10)
 		fd = savefd(fd, fd);

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/3] Revert "Eliminated global exerrno."
  2010-10-07  3:35                     ` Jonathan Nieder
  2010-10-07  4:14                       ` Herbert Xu
@ 2010-11-28 12:45                       ` Herbert Xu
  1 sibling, 0 replies; 31+ messages in thread
From: Herbert Xu @ 2010-11-28 12:45 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Eric Blake, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

On Wed, Oct 06, 2010 at 10:35:18PM -0500, Jonathan Nieder wrote:
>
> Maybe the following would make sense on top?
> 
> -- 8< --
> Subject: [EXCEPTIONS] Use EXEXIT in place of EXEXEC

Patch applied.  Thanks a lot!
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v2] [EXCEPTIONS] Stop documenting EXSHELLPROC
  2010-10-07  3:39                         ` [PATCH v2] " Jonathan Nieder
@ 2010-11-28 12:47                           ` Herbert Xu
  0 siblings, 0 replies; 31+ messages in thread
From: Herbert Xu @ 2010-11-28 12:47 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Eric Blake, Gerrit Pape, dash, Krzysztof A. Sobiecki, Jari Aalto

On Wed, Oct 06, 2010 at 10:39:23PM -0500, Jonathan Nieder wrote:
> At some point between ash 0.3.5-11.0.1 and ash 0.3.8-37, Debian
> ash stopped using the EXSHELLPROC exception to handle shell
> scripts without a magic number.
> 
> Remove all remaining references to it to avoid confusion.
> 
> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>

Also applied.
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2010-11-28 12:47 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-06-05 16:06 debian patches to exit with code 127 for nonexistent/directory scripts Jilles Tjoelker
2010-06-08 10:19 ` Herbert Xu
2010-06-08 10:36   ` Cristian Ionescu-Idbohrn
2010-06-11  8:39     ` Herbert Xu
2010-06-14  9:54 ` [PATCH] [INPUT] exit 127 if command_file is given but doesn't exist Gerrit Pape
2010-06-28  6:53   ` Herbert Xu
2010-10-06 10:04     ` [PATCH] [OPTIONS] Use exit status 127 when the script to run does not exist Jonathan Nieder
2010-10-06 10:08       ` [PATCH] [INPUT] Catch attempts to run a directory as a script Jonathan Nieder
2010-10-06 10:29         ` Herbert Xu
2010-10-06 10:55           ` Jonathan Nieder
2010-10-06 12:18             ` Eric Blake
2010-10-06 12:31               ` Herbert Xu
2010-10-07  1:02               ` [PATCH 0/3] Fix exit status for 'exec nonexistent' and 'exec .' Jonathan Nieder
2010-10-07  1:03                 ` [PATCH 1/3] [EXCEPTIONS] Stop documenting EXSHELLPROC Jonathan Nieder
2010-10-07  3:01                   ` Herbert Xu
2010-10-07  3:04                     ` Jonathan Nieder
2010-10-07  3:29                       ` Herbert Xu
2010-10-07  3:39                         ` [PATCH v2] " Jonathan Nieder
2010-11-28 12:47                           ` Herbert Xu
2010-10-07  1:04                 ` [PATCH 2/3] Revert "Eliminated global exerrno." Jonathan Nieder
2010-10-07  2:56                   ` Herbert Xu
2010-10-07  3:35                     ` Jonathan Nieder
2010-10-07  4:14                       ` Herbert Xu
2010-10-07  4:37                         ` Herbert Xu
2010-10-07 21:34                           ` Jonathan Nieder
2010-11-28 12:45                       ` Herbert Xu
2010-10-07  1:08                 ` [PATCH 3/3] [EXCEPTIONS] Eliminate global exerrno Jonathan Nieder
2010-10-07  3:00                   ` Herbert Xu
2010-11-28 12:06       ` [PATCH] [OPTIONS] Use exit status 127 when the script to run does not exist Herbert Xu
2010-11-28 12:24         ` Herbert Xu
2010-11-28 12:33           ` Herbert Xu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox