On Thu, Jul 22, 2010 at 9:11 PM, Ted Unangst <[email protected]> wrote:
> On Thu, Jul 22, 2010 at 6:52 PM, Daniel Dickman <[email protected]>
wrote:
>> sure. let me try. the problem is that right now i think env on OpenBSD
>> can return 4 ambiguous values: 0, 1, 126, 127. if any of these values
>> are returned i don't think it's possible to know if the value was
>> returned from env itself or from the underlying utility. (and in fact
>
> The only thing close to ambiguous is running env with a bad command
> line, in which case you get usage and exit 1.  Don't do that.

Sorry Ted, but there are many more ambiguous cases.

If you run a command that smells kinda posixy and you get back a
status of 127, that _probably_ means that *somewhere* in the chain of
processes that was involved in the execution of that command,
something tried to execute a command and got an ENOENT error from the
kernel.

It doesn't mean that the 'outermost' command got an ENOENT error from execve.
It doesn't mean that the child process tried to invoked execve() at all.
It doesn't guarantee that *any* command got that error.

Ditto for the similar rules for a status of 126.  All you know is that
the command you invoked returned 127 or 126...which may be the result
of it passing through that status from a command that _it_ invoked!


So what does the rule about env return 127 or 126 after execve fails
get you?  It helps rule *out* failure cases: if you _don't_ get that,
then any failure wasn't because a posixy command couldn't find
something to exec.


> If you get back a 0 it means, tada, it worked!

(Well, it means the command that env invoked returned zero, which
hopefully means "success" )


> If you get back 127, it means env didn't find the command.  Unless you
> did something retarded like run env env env env diddly, and then it's
> not env returning 127 but the inner inner inner env.  I really hope
> this is not the kind of problem you are facing when writing a shell
> script.

I know legitimate cases where 'env' will end up invoking 'env', albeit
via an indirection.  Others may consider more legit situations that
mix env and other commands (xargs, find, nice, nohup, etc...).

The thing is that "a command" is an abstraction.  A process forks, and
at some point it gets an exit status from that child.  It can't
directly tell whether the child process successfully invoked execve(),
zero times, once, twice, or a thousand times before exiting.  All the
kernel tells it is "child returned status N".  That's true whether N
is 0, 1, 126, 127, or 42.  All a status of 126 tells you is "someone
probably screwed up permissions on a program"; all 127 tells you is
"someone probably misspelled a program".


>> the second problem, is that according to (my reading of posix)
>> something that uses env will expect a return value in the range of
>> 1-125 to mean "something went wrong in env" and 126 to mean "something
>> went wrong with invoking utility". but at the moment there are 2
>> places in the code where 126 is returned where something went wrong in
>> env.
>
> You are clearly reading this exactly backwards.

I actually agree with the original poster on his original patch to
env.c: env shouldn't return 126 on a non-execve() error, because the
user expectation on getting that status is that execve() was called,
but it failed with errno!=ENOENT, and they'll look in the wrong place
to fix the problem.

env can directly return any status from 0 to 127.  IMO, it should only
return 0 'directly' (without successfully invoking execve) in the case
where it is invoked without a command, and it should only directly
return the 126 and 127 exit statuses if execve was invoked but failed.

(And yes, execve() can fail 'late': at some point, the process of
execing a program crosses a "can't roll back" point after which if
something goes wrong, the process will die instead of the execve()
call returning.  The status the parent gets depends on the
implementation and the exact point at which it died.  The system is
imperfect; get over it.)


Philip Guenther

Reply via email to