hush: fix "exec 3>FILE" aborting if 3 is exactly the next free fd

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2024-07-13 00:59:02 +02:00
parent 6c38d0e9da
commit 14e28c18ca
8 changed files with 42 additions and 7 deletions

View file

@ -1,3 +1,3 @@
TEST TEST
./redir3.tests: line 4: 9: Bad file descriptor ./redir3.tests: line 4: dup2(9,1): Bad file descriptor
Output to fd#9: 1 Output to fd#9: 1

View file

@ -0,0 +1,4 @@
fd/5
fd/4
fd/3
One:1

View file

@ -0,0 +1,11 @@
cd /proc/$$
exec 5>/dev/null
exec 4>/dev/null
exec 3>/dev/null
ls -1 fd/5
ls -1 fd/4
ls -1 fd/3
exec 5>&-
test -e fd/5 && echo BUG
echo One:$?

View file

@ -1,2 +1,2 @@
./redir_to_bad_fd255.tests: line 2: 255: Bad file descriptor ./redir_to_bad_fd255.tests: line 2: dup2(255,1): Bad file descriptor
OK OK

View file

@ -1,2 +1,2 @@
./redir_to_bad_fd3.tests: line 2: 3: Bad file descriptor ./redir_to_bad_fd3.tests: line 2: dup2(3,1): Bad file descriptor
OK OK

View file

@ -8077,8 +8077,11 @@ static int internally_opened_fd(int fd, struct squirrel *sq)
return 0; return 0;
} }
/* squirrel != NULL means we squirrel away copies of stdin, stdout, /* sqp != NULL means we squirrel away copies of stdin, stdout,
* and stderr if they are redirected. */ * and stderr if they are redirected.
* If redirection fails, return 1. This will make caller
* skip command execution and restore already created redirect fds.
*/
static int setup_redirects(struct command *prog, struct squirrel **sqp) static int setup_redirects(struct command *prog, struct squirrel **sqp)
{ {
struct redir_struct *redir; struct redir_struct *redir;
@ -8109,7 +8112,7 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
* "cmd > <file" (2nd redirect starts too early) * "cmd > <file" (2nd redirect starts too early)
*/ */
syntax_error("invalid redirect"); syntax_error("invalid redirect");
continue; return 1;
} }
mode = redir_table[redir->rd_type].mode; mode = redir_table[redir->rd_type].mode;
p = expand_string_to_string(redir->rd_filename, p = expand_string_to_string(redir->rd_filename,
@ -8124,7 +8127,9 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
*/ */
return 1; return 1;
} }
if (newfd == redir->rd_fd && sqp) { if (newfd == redir->rd_fd && sqp
&& sqp != ERR_PTR /* not a redirect in "exec" */
) {
/* open() gave us precisely the fd we wanted. /* open() gave us precisely the fd we wanted.
* This means that this fd was not busy * This means that this fd was not busy
* (not opened to anywhere). * (not opened to anywhere).

View file

@ -0,0 +1,4 @@
fd/5
fd/4
fd/3
One:1

View file

@ -0,0 +1,11 @@
cd /proc/$$
exec 5>/dev/null
exec 4>/dev/null
exec 3>/dev/null
ls -1 fd/5
ls -1 fd/4
ls -1 fd/3
exec 5>&-
test -e fd/5 && echo BUG
echo One:$?