[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: exec redirection is undone if fd (>9) has O_CLOEXEC
From: |
Emanuele Torre |
Subject: |
Re: exec redirection is undone if fd (>9) has O_CLOEXEC |
Date: |
Sat, 24 Feb 2024 07:32:34 +0100 |
User-agent: |
Mutt/2.2.12 (2023-09-09) |
On Sat, Feb 24, 2024 at 02:11:25PM +0900, Koichi Murase wrote:
> I have a question. Maybe it's not technically a bug as fd > 9 is
> involved, but the resulting behavior appears to be strange. I
> received some reports from users in my project and tried to find out
> what is happening. This is a reduced case:
Thank you for bringing this up; I have also noticed weird behaviour with
redirections of cloexec file descriptors a couple months ago.
Bash seems to check for the CLOEXEC flag in the source file descriptor,
and preserves it in the destination file descriptor when performing a
n<&m redirection.
$ bash -c 'enable fdflags; exec 6</dev/null; fdflags -s+cloexec,nonblock 6;
exec 7<&6; fdflags 6 7'
6:cloexec
7:cloexec
That is very surprising; I would expect 7 to not be cloexec since
CLOEXEC is a file descriptor flag; that is the behaviour you normally
get when you if you duplicate 7 before applying CLOEXEC to 7:
$ bash -c 'enable fdflags; exec 6</dev/null 7<&6; fdflags -s+cloexec 6;
fdflags 6 7'
6:cloexec
7:
With strace you can see bash checking if 6 has the CLOEXEC flag, and
applying it to 7 manually after duping it:
$ strace -qqefd=6,7 bash -c 'enable fdflags; exec 6</dev/null; fdflags
-s+cloexec 6; exec 7<&6'
fcntl(6, F_GETFD) = -1 EBADF (Bad file descriptor)
dup2(3, 6) = 6
fcntl(6, F_GETFD) = 0
fcntl(6, F_GETFL) = 0x8000 (flags O_RDONLY|O_LARGEFILE)
fcntl(6, F_SETFD, FD_CLOEXEC) = 0
fcntl(7, F_GETFD) = -1 EBADF (Bad file descriptor)
dup2(6, 7) = 7
fcntl(6, F_GETFD) = 0x1 (flags FD_CLOEXEC)
fcntl(7, F_SETFD, FD_CLOEXEC) = 0
This is very confusing/annoying because I would expect to be able to do
something like this:
#!/bin/bash --
enable fdflags
exec {fifofd}< fifo
fdflags -s +cloexec "$fifofd"
# ...
cmd /dev/fd/3 3<&"$fifofd"
# ...
To only make cmd inherit $fifofd, but I cannot do that because bash
will copy CLOEXEC from $fifofd, and fd 3 will be closed for cmd:
$ bash -c 'enable fdflags; exec 6</dev/null; fdflags -s+cloexec 6; ls -ld
/proc/self/fd/3 3<&6'
ls: cannot access '/proc/self/fd/3': No such file or directory
So I have to use something like:
(
fdflag -s-cloexec "$fifofd"
cmd /dev/fd/3 3<&"$fifofd"
)
This only happens whe redirecting to an fd >= 3.
I don't know why bash wants/needs to copy the CLOEXEC flag when the user
duplicates a file descriptor.
o/
emanuele6