bug-bash
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]