Front page | perl.perl5.porters |
Postings from January 2011
Re: fcntl() and FD_CLOEXEC
Thread Previous
|
Thread Next
From:
NormW
Date:
January 30, 2011 15:44
Subject:
Re: fcntl() and FD_CLOEXEC
Message ID:
4D45F7C8.1040004@gknw.net
On 31/01/2011 9:00 AM, Zsbán Ambrus wrote:
> On Fri, Jan 28, 2011 at 10:10 PM, NormW<normw@gknw.net> wrote:
>> --- fcntl(fd, F_SETFD, fd> PL_maxsysfd);
>> +++ fcntl(fd, F_SETFD, (fd> PL_maxsysfd ? FD_CLOEXEC : 0));
>
>> From my readings the only flag returned by F_GETFD is the close-on-exec
>> flag,
>
> While FD_CLOEXEC is (afaik) the only file descriptor flag, new ones
> may be introduced in future kernels, so the correct way to set the
> close on exec flag is to retrieve the flags with F_GETFD, bitwise or,
> and set them with F_SETFD. According to the code snippets you quote
> above, perl does not seem to do this.
>
> Let me quote some documentation. Firstly, POSIX says in
> "http://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html#tag_16_122_07".
>
>> The arg values to F_GETFD, F_SETFD, F_GETFL, and F_SETFL all represent
>> flag values to allow for future growth. Applications using these
>> functions should do a read-modify-write operation on them, rather than
>> assuming that only the values defined by this volume of POSIX.1-2008 are
>> valid. It is a common error to forget this, particularly in the case
>> of F_SETFD. Some implementations set additional file status flags to
>> advise the application of default behavior, even though the application
>> did not request these flags.
>
> Next, here's what the GNU libc manual says
> ("http://www.gnu.org/software/libc/manual/html_node/Descriptor-Flags.html").
>
>> If you want to modify the file descriptor flags, you should get the
>> current flags with F_GETFD and modify the value. Don't assume that the
>> flags listed here are the only ones that are implemented; your program
>> may be run years from now and more flags may exist then. For example,
>> here is a function to set or clear the flag FD_CLOEXEC without altering
>> any other flags:
>>
>> /* Set the FD_CLOEXEC flag of desc if value is nonzero,
>> or clear the flag if value is 0.
>> Return 0 on success, or -1 on error with errno set. */
>>
>> int
>> set_cloexec_flag (int desc, int value)
>> {
>> int oldflags = fcntl (desc, F_GETFD, 0);
>> /* If reading the flags failed, return error indication now. */
>> if (oldflags< 0)
>> return oldflags;
>> /* Set just the flag we want to set. */
>> if (value != 0)
>> oldflags |= FD_CLOEXEC;
>> else
>> oldflags&= ~FD_CLOEXEC;
>> /* Store modified flag word in the descriptor. */
>> return fcntl (desc, F_SETFD, oldflags);
>> }
>
> This, of course, does not apply to the FIOCLEX or FIONCLEX ioctls,
> which only set or clear the close on exec flag and do not take an
> argument. These ioctls are available on at least some versions of
> Linux and OpenBSD.
>
> Here are some quickie examples in perl.
>
> [am]king ~$ perl -wE 'open F, ">&", 1 or die; $fd = fileno(F); warn
> "fd=$fd"; exec "/bin/bash", "-c", "echo hello>&$fd"; die "exec";'
> fd=3 at -e line 1.
> /bin/bash: 3: Bad file descriptor
> 1[am]king ~$ perl -wE 'use Fcntl; open F, ">&", 1 or die; $fd =
> fileno(F); warn "fd=$fd"; my $df = fcntl F, F_GETFD(), 0 or die; fcntl
> F, F_SETFD(), $df&~ FD_CLOEXEC(); exec "/bin/bash", "-c", "echo hello
>> &$fd"; die "exec";'
> fd=3 at -e line 1.
> hello
> [am]king ~$ perl -wE 'use constant {FIONCLEX => ($^O =~ /linux/i ?
> 0x5450 : $^O =~ /bsd/i ? 0x20006602 : die "constant")}; open F, ">&",
> 1 or die; $fd = fileno(F); warn "fd=$fd"; ioctl F, FIONCLEX(), 0 or
> die; exec "/bin/bash", "-c", "echo hello>&$fd"; die "exec";'
> fd=3 at -e line 1.
> hello
> [am]king ~$
>
> Ambrus
G/M,
Based on your references, to support a future with possible extra flags
returned by F_GETFD, all instances of fcntl()/F_SETFD use would need to
be reviewed to see there was added need to maintain the settings of
'other' flags, if the intent was only to SET the close-on-exec flag.
At the moment the proposed change supports the present a little better
than the existing code; supporting multiple flags would be a deal more
complicated, embodying a macro similar to the example you gave.
Norm
Thread Previous
|
Thread Next