Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 10 Sep 2002 14:48:06 -0700
From:      Terry Lambert <tlambert2@mindspring.com>
To:        Archie Cobbs <archie@dellroad.org>
Cc:        freebsd-arch@freebsd.org
Subject:   Re: /dev/stdout behavior
Message-ID:  <3D7E6896.B586D5E1@mindspring.com>
References:  <200209101656.g8AGuJ433605@arch20m.dellroad.org>

next in thread | previous in thread | raw e-mail | index | archive | help
Archie Cobbs wrote:
> Is there an 'official' spec about how /dev/stdout is supposed to behave?
> 
> For example, if you use fcntl() to set flags on fd 0, and then open
> /dev/stdout, the new file descriptor you get back will have those
> same flags set. Run the program below to see an example. This is
> in agreement with the man page, which states that opening /dev/stdout
> is equivalent to dup(2)'ing fd 0.
> 
> However, on RedHat Linux 7.3, the program below behaves in the opposite
> manner from FreeBSD, i.e., it prints "O_NONBLOCK is not set".
> 
> So at least one of FreeBSD or Linux is 'wrong' about /dev/stdout, or maybe
> there is no general agreement about what /dev/stdout means..  ?

The "O_NDELAY"/"O_NONBLOCK" is part and parcel with the "partial
open" state for tty devices, so the value is actually supposed to
be reset.  There's a similar value that gets set with O_EXCL, or
is supposed to.

Basically, Linux is exhibiting SVR4 behaviour, which is technically
more correct than BSD behaviour, given the adoption of the POSIX
specification by BSD.

There are a couple of ways to look at how this could be happening;
I would have to look at the Linux kernel sources, which are hard
to keep up to date, given that there is no moral equivalent to
cvsup or anoncvs, in order to be certain what the root cause is.

The difference comes down to the resetting of the flags, and whether
or not the flags are per descriptor, per struct file, or per device
node.  BSD shares the struct file and the device node after the open;
Linux may or may not share the struct file.  Where the flag lives
dictates which behaviour you end up getting.

The O_EXCL (exclusive use bit) is similarly handled.

I think the best public code you are going to find that
indirectly documents the assumptions here is mgetty, and looking
at what it does to open the port without DCD present on SVR4 boxes.

FWIW, the "partial open hack", for opening a tty on SVR4 without
DCD present, in order to be able to talk to a modem, without
disabling modem control on the port so that DCD/DTR drop could
still be correctly detected, was implemented like so:

	/* unset O_EXCL, set by blocking open, and not reset by
	 * aborting the blocking open, by performing a blocking
	 * open without O_EXCL set to reset the bits on the device;
	 * alarm out of it, in case DCD not present or modem control,
	 * so that we do not block forever.  This is necessary so a
	 * fork() child process doesn't lose access to the device
	 * later because of O_EXCL, which is not reset if O_NDELAY
	 * is used.
	 */
	alarm(1);
	fd = open( portname, O_RDWR, 0);
	alarm(0);
	/* If the open was successful, instead of alarming out, close it*/
	if( fd != -1)
		close( fd);

	/* Perform a non-blocking open; this will leave the descriptor
	 * in non-blocking mode, which can not be unset on some devices,
	 * e.g. those opened over Intel OpenNET, or those which do not
	 * implement an fcntl() method entry point for unsetting O_NDELAY.
	 */
	fdn = open( portname, O_NDELAY | O_RDWR, 0);

	/* Perform second blocking open.  Because it is the second open,
	 * it will not block, merely increment the reference count.  Note
	 * the the system open file table entry ("struct file") is not
	 * shared, and the O_NDELAY flag is implemented there, so we will
	 * be able to do blocking reads/write on the fd returned.  In
	 * other words, the device is already "partially open".
	 */
	fd = open( portname, O_RDWR, 0);

	/* Close the non-blocking descriptor, because we are going to
	 * only use the blocking descriptor, so that we don't end up
	 * buzz-looping with read returning 0 characters available (is
	 * also needed to detect EOF condition via a short read).
	 */
	close( fdn);

Maybe this is legacy SVR4 code you are looking at porting to BSD here?

-- Terry

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-arch" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3D7E6896.B586D5E1>