Discussion:
[Help-bash] Option execfail does not work in subshells
R. Diez
2017-08-08 09:51:11 UTC
Permalink
Hi all:

When I run this test script:


#!/bin/bash

test ()
{
shopt -s execfail
exec "non-existing-command"
echo "This message should therefore always appear."
}

test
(test)
test &



The output is:

$ ./execfail-test.sh
./execfail-test.sh: line 6: exec: non-existing-command: not found
This message should therefore always appear.
./execfail-test.sh: line 6: exec: non-existing-command: not found
./execfail-test.sh: line 6: exec: non-existing-command: not found


That is, it looks like execfail is being ignored in the subshells.

Is that a bug? Or have I missed something?

Thanks in advance,
rdiez
Chet Ramey
2017-08-08 12:26:05 UTC
Permalink
Post by R. Diez
#!/bin/bash
test ()
{
shopt -s execfail
exec "non-existing-command"
echo "This message should therefore always appear."
}
test
(test)
test &
$ ./execfail-test.sh
./execfail-test.sh: line 6: exec: non-existing-command: not found
This message should therefore always appear.
./execfail-test.sh: line 6: exec: non-existing-command: not found
./execfail-test.sh: line 6: exec: non-existing-command: not found
That is, it looks like execfail is being ignored in the subshells.
Is that a bug? Or have I missed something?
`execfail' only works when the shell is interactive. Subshells are
not considered interactive shells.
--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU ***@case.edu http://cnswww.cns.cwru.edu/~chet/
R. Diez
2017-08-08 15:04:12 UTC
Permalink
Post by Chet Ramey
`execfail' only works when the shell is interactive. Subshells are
not considered interactive shells.
But that is not what the documentation says:

-----8<-----8<-----8<-----
execfail

If this is set, a non-interactive shell will not exit if it cannot
execute the file specified as an argument to the exec builtin command.
An interactive shell does not exit if exec fails.
-----8<-----8<-----8<-----

Therefore, a non-interactive shell, such as a subshell, should not exit
when the execfail option is set, right? So the 3 ways that my script
runs exec should all output the same text.

Regards,
rdiez
Chet Ramey
2017-08-09 11:56:54 UTC
Permalink
Post by Chet Ramey
`execfail' only works when the shell is interactive. Subshells are
not considered interactive shells.
I had to look at the source. Subshells are specifically exempted from the
execfail settings. It's been this way for at least 24 years, so the exact
reason is lost to time.

Chet
--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU ***@case.edu http://cnswww.cns.cwru.edu/~chet/
R. Diez
2017-08-09 12:43:45 UTC
Permalink
Post by Chet Ramey
I had to look at the source. Subshells are specifically exempted from the
execfail settings. It's been this way for at least 24 years, so the exact
reason is lost to time.
Thanks for looking. I could almost forgive your wrong answer yesterday. }8-)

I am writing a shell script which needs execfail to work in a subshell,
specifically when starting a background process with & . The reason is,
I want to print a proper error message when the user passes the wrong
command (for example), but I could think of other actions, like logging
the failure somewhere.

There does not seem to be a valid reason for execfail to not work in a
subshell. Should I create a bug for this? (I am assuming that there is a
public bug tracker for Bash).

There is one other thing that I noticed. When the 'exec' calls redirects
stdout and stderr, they remain redirected after 'exec' fails. I resorted
to saving and restoring their file descriptors in this scenario.
However, I think that this fact should be clearly documented, because,
at the moment, after reading the docs you tend to believe that such a
permanent redirection should only be the case if you specify no command
to run in the 'exec' calls.

In any case, I wonder what other things do not get restored properly
after 'exec' fails.

Regards,
rdiez
DJ Mills
2017-08-09 17:38:45 UTC
Permalink
If you don't mind my asking, why are you having a user pass commands in the
first place? That's an excellent way to be rather insecure.
Post by Chet Ramey
I had to look at the source. Subshells are specifically exempted from the
Post by Chet Ramey
execfail settings. It's been this way for at least 24 years, so the exact
reason is lost to time.
Thanks for looking. I could almost forgive your wrong answer yesterday. }8-)
I am writing a shell script which needs execfail to work in a subshell,
specifically when starting a background process with & . The reason is, I
want to print a proper error message when the user passes the wrong command
(for example), but I could think of other actions, like logging the failure
somewhere.
There does not seem to be a valid reason for execfail to not work in a
subshell. Should I create a bug for this? (I am assuming that there is a
public bug tracker for Bash).
There is one other thing that I noticed. When the 'exec' calls redirects
stdout and stderr, they remain redirected after 'exec' fails. I resorted to
saving and restoring their file descriptors in this scenario. However, I
think that this fact should be clearly documented, because, at the moment,
after reading the docs you tend to believe that such a permanent
redirection should only be the case if you specify no command to run in the
'exec' calls.
In any case, I wonder what other things do not get restored properly after
'exec' fails.
Regards,
rdiez
R. Diez
2017-08-10 06:36:33 UTC
Permalink
Post by DJ Mills
If you don't mind my asking, why are you having a user pass commands in
the first place? That's an excellent way to be rather insecure.
I regularly use the following script I wrote to let me know when
low-priority, "background" processes (like a long compilation) finish:

https://github.com/rdiez/Tools/tree/master/Background

The script lets you specify a command that you want to run, and it runs
it with low priority, redirecting its output to log files that are
(more-or-less) automatically rotated over time.

I am considering enhancing the script. If the user does not need a
notification at the end, I could use 'exec' to replace the script with
the user's process.

But I have a more important reason now. I recently asked the following
question on this mailing list:

Automatically "disown -h" all background jobs
https://lists.gnu.org/archive/html/help-bash/2017-08/msg00000.html

I am investigating whether it is possibly to write a similar helper
script that starts any GUI command in the background, detached from the
console. I think that blocking SIGHUP, like nohup does, may not be
necessary. The helper script should redirect stdout and stderr to
automatically-rotated log files.

The main problem I am facing is that, if you type something like
"StartDetached.sh mycommand", and 'mycommand' does not exist, the error
message goes to the redirected stderr, which is not very user friendly.
I am investigating how much comfortable error detection and reporting is
possible with Bash/Linux in this scenario.

Tool 'nohup' does try to report any error that 'exec' reports. It may
not be possible to do more, but at least you get an error message if the
command does not exist at all. I thought I could do the same with Bash,
but then I hit the execfail problem I reported.

Regards,
rdiez
Chet Ramey
2017-08-15 12:20:13 UTC
Permalink
Post by R. Diez
There does not seem to be a valid reason for execfail to not work in a
subshell. Should I create a bug for this? (I am assuming that there is a
public bug tracker for Bash).
This has been the case for so long there is probably code that depends on
it. I'm reluctant to change it now in the absence of a compelling reason
to do so.
Post by R. Diez
There is one other thing that I noticed. When the 'exec' calls redirects
stdout and stderr, they remain redirected after 'exec' fails. I resorted to
saving and restoring their file descriptors in this scenario. However, I
think that this fact should be clearly documented, because, at the moment,
after reading the docs you tend to believe that such a permanent
redirection should only be the case if you specify no command to run in the
'exec' calls.
I'll take a look.

Chet
--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU ***@case.edu http://cnswww.cns.cwru.edu/~chet/
R. Diez
2017-08-15 13:08:37 UTC
Permalink
Post by Chet Ramey
Post by R. Diez
There does not seem to be a valid reason for execfail to not work in a
subshell. Should I create a bug for this? (I am assuming that there is a
public bug tracker for Bash).
This has been the case for so long there is probably code that depends on
it. I'm reluctant to change it now in the absence of a compelling reason
to do so.
In my opinion, this is not really the best way to handle bug reports.

Could you at least update the documentation to mention that execfail
does not work at all in subshells?
Post by Chet Ramey
I'll take a look.
OK, thanks,
rdiez
Chet Ramey
2017-08-15 13:41:31 UTC
Permalink
Post by R. Diez
Post by Chet Ramey
Post by R. Diez
There does not seem to be a valid reason for execfail to not work in a
subshell. Should I create a bug for this? (I am assuming that there is a
public bug tracker for Bash).
This has been the case for so long there is probably code that depends on
it. I'm reluctant to change it now in the absence of a compelling reason
to do so.
In my opinion, this is not really the best way to handle bug reports.
What suggestions would you have for improvement? Someone is always going to
be disappointed when you tell them their report isn't going to result in a
behavior change.
Post by R. Diez
Could you at least update the documentation to mention that execfail does
not work at all in subshells?
Sure, I can look at that.
--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU ***@case.edu http://cnswww.cns.cwru.edu/~chet/
d***@mail.com
2017-08-09 17:50:26 UTC
Permalink
On Tue, 8 Aug 2017 17:04:12 +0200
Post by R. Diez
Post by Chet Ramey
`execfail' only works when the shell is interactive. Subshells are
not considered interactive shells.
-----8<-----8<-----8<-----
execfail
If this is set, a non-interactive shell will not exit if it cannot
execute the file specified as an argument to the exec builtin command.
An interactive shell does not exit if exec fails.
-----8<-----8<-----8<-----
<snip>

Notice that the two statements above are similar but not the *same*.
Post by R. Diez
If this is set, a non-interactive shell will not exit if it cannot
execute the file specified as an argument to the exec builtin command.
See the word "file", it's not equivalent to the word "function"[1].
Notice also that exec could fail for other reasons which are not listed
above but also not covered.
Post by R. Diez
An interactive shell does not exit if exec fails.
OTOH, an interactive shell would not exit if, for *any* reason exec fails.

What confuses me is why the word "builtin" is used in terms of exec in
the non-interactive case, whereas it is not used in the interactive case.
Perhaps bash needs some form of control over the function that could not
be achieved using a file.

Sincerely,
David


[1] Technically, calling a file and a function in sh should be identical,
but this is probably a side case.
Chet Ramey
2017-08-14 14:52:14 UTC
Permalink
Post by d***@mail.com
On Tue, 8 Aug 2017 17:04:12 +0200
Post by R. Diez
Post by Chet Ramey
`execfail' only works when the shell is interactive. Subshells are
not considered interactive shells.
-----8<-----8<-----8<-----
execfail
If this is set, a non-interactive shell will not exit if it cannot
execute the file specified as an argument to the exec builtin command.
An interactive shell does not exit if exec fails.
-----8<-----8<-----8<-----
<snip>
Notice that the two statements above are similar but not the *same*.
The second sentence is intended to be the same as the first, but shorter
to avoid saying the same thing multiple times; the only difference is
whether or not the shell is interactive.
Post by d***@mail.com
Post by R. Diez
If this is set, a non-interactive shell will not exit if it cannot
execute the file specified as an argument to the exec builtin command.
See the word "file", it's not equivalent to the word "function"[1].
True, but it doesn't matter in this case, since the example does not
have exec attempting to execute a shell function. `exec' always treats
its argument as an executable file.
Post by d***@mail.com
Notice also that exec could fail for other reasons which are not listed
above but also not covered.
But execfail doesn't cover those. The idea behind execfail is that if
execve fails, the shell doesn't exit.
Post by d***@mail.com
Post by R. Diez
An interactive shell does not exit if exec fails.
OTOH, an interactive shell would not exit if, for *any* reason exec fails.
You're reading too much into it. The only other reasons the builtin would
fail is if given an invalid option or if the shell is restricted, and
execfail doesn't act on those cases. The shell doesn't exit if those happen.
--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU ***@case.edu http://cnswww.cns.cwru.edu/~chet/
David Niklas
2017-08-16 13:53:42 UTC
Permalink
On Mon, 14 Aug 2017 10:52:14 -0400
Post by Chet Ramey
Post by d***@mail.com
On Tue, 8 Aug 2017 17:04:12 +0200
Post by R. Diez
Post by Chet Ramey
`execfail' only works when the shell is interactive. Subshells are
not considered interactive shells.
-----8<-----8<-----8<-----
execfail
If this is set, a non-interactive shell will not exit if it cannot
execute the file specified as an argument to the exec builtin
command. An interactive shell does not exit if exec fails.
-----8<-----8<-----8<-----
<snip>
Notice that the two statements above are similar but not the *same*.
The second sentence is intended to be the same as the first, but shorter
to avoid saying the same thing multiple times; the only difference is
whether or not the shell is interactive.
I'm used to manuals where if something is said differently, then it means
something different.
Why not use the short version for both?
Post by Chet Ramey
Post by d***@mail.com
Post by R. Diez
If this is set, a non-interactive shell will not exit if it cannot
execute the file specified as an argument to the exec builtin
command.
See the word "file", it's not equivalent to the word "function"[1].
True, but it doesn't matter in this case, since the example does not
have exec attempting to execute a shell function. `exec' always treats
its argument as an executable file.
I mean that exec is a builtin which is a C function (I would imagine), and
is not a program, but a builtin. But that is probably another case
of reading too much into what was written.
Post by Chet Ramey
Post by d***@mail.com
Notice also that exec could fail for other reasons which are not
listed above but also not covered.
But execfail doesn't cover those. The idea behind execfail is that if
execve fails, the shell doesn't exit.
Post by d***@mail.com
Post by R. Diez
An interactive shell does not exit if exec fails.
OTOH, an interactive shell would not exit if, for *any* reason exec
fails.
You're reading too much into it. The only other reasons the builtin
would fail is if given an invalid option or if the shell is restricted,
and execfail doesn't act on those cases. The shell doesn't exit if
those happen.
What about having incorrect permissions for the file, like read but no
exec, or exec but no read?
Or, how about an OOM condition?

Sincerely,
David
Chet Ramey
2017-08-16 14:56:16 UTC
Permalink
Post by David Niklas
Post by Chet Ramey
Post by d***@mail.com
Post by R. Diez
If this is set, a non-interactive shell will not exit if it cannot
execute the file specified as an argument to the exec builtin
command.
See the word "file", it's not equivalent to the word "function"[1].
True, but it doesn't matter in this case, since the example does not
have exec attempting to execute a shell function. `exec' always treats
its argument as an executable file.
I mean that exec is a builtin which is a C function (I would imagine), and
is not a program, but a builtin. But that is probably another case
of reading too much into what was written.
What does this mean? I still don't understand how the fact that exec is a
builtin implemented as a C function affects how it treats its argument.
Post by David Niklas
Post by Chet Ramey
Post by d***@mail.com
Notice also that exec could fail for other reasons which are not
listed above but also not covered.
But execfail doesn't cover those. The idea behind execfail is that if
execve fails, the shell doesn't exit.
Post by d***@mail.com
Post by R. Diez
An interactive shell does not exit if exec fails.
OTOH, an interactive shell would not exit if, for *any* reason exec
fails.
You're reading too much into it. The only other reasons the builtin
would fail is if given an invalid option or if the shell is restricted,
and execfail doesn't act on those cases. The shell doesn't exit if
those happen.
What about having incorrect permissions for the file, like read but no
exec, or exec but no read?
Or, how about an OOM condition?
That is what I wrote. Those are all reasons for execve(2) to fail:

[EACCES] Search permission is denied for a component of the
path prefix.

[EACCES] The new process file is not an ordinary file.

[EACCES] The new process file mode denies execute permission.

[EACCES] The new process file is on a filesystem mounted with
execution disabled (MNT_NOEXEC in <sys/mount.h>).

[...]

[ENOMEM] The new process requires more virtual memory than is
allowed by the imposed maximum (getrlimit(2)).

and so on. These are the cases where execfail has an effect. If you supply
an invalid option to the builtin, the builtin will fail (return a non-zero
status), but the shell will not exit. These are the "other reasons."
--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU ***@case.edu http://cnswww.cns.cwru.edu/~chet/
Loading...