Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 3 Mar 2004 15:04:58 +1100 (EST)
From:      Bruce Evans <bde@zeta.org.au>
To:        David Schultz <das@freebsd.org>
Cc:        "Jordan K. Hubbard" <jkh@queasyweasel.com>
Subject:   Re: Another conformance question...  This time fputs().
Message-ID:  <20040303144451.T5253@gamplex.bde.org>
In-Reply-To: <20040302165323.GA17665@VARK.homeunix.com>
References:  <F648D56F-6C28-11D8-9000-000393BB9222@queasyweasel.com> <20040302165323.GA17665@VARK.homeunix.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Tue, 2 Mar 2004, David Schultz wrote:

> Nice catch.  I think the wording of POSIX suggests that the error
> code is supposed to be EBADF, which is returned if ``the file
> descriptor [...] is not a valid file descriptor for writing.''
> Although you could argue that the standard is wrong, Linux and
> Solaris return EBADF, so we probably should, too.

I don't think there is any option for fwrite().  Its underlying function
is normally write(2) and that would return EBADF (this is what is
arguably wrong).  fwrite() must do what the underlying function would.

> (By the way, there are a few other cantwrite() calls in libc that
> probably have the same bug.)

One is vfprintf(), which may output to non-files.  Oops, so can
__svfwrite().  The underlying function isn't always write(2).  EBADF
is a very bogus errno if the output is not to a file.  It can be to a
string or anything set up by funopen()/fropen()/fwopen().  Strings are
writable, so they don't cause a problem here, but anything set up by
fropen() or funopen() without a write function is unwritable and
returning EBADF is wrong for it.

NetBSD just returns EBADF for all the cantwrite() cases.  This incomplete
fix was made less than 7 years ago:

% RCS file: /home/NetBSD/NetBSD-cvs/src/lib/libc/stdio/fvwrite.c,v
% Working file: fvwrite.c
% head: 1.15
% ...
% ----------------------------
% revision 1.6
% date: 1997/05/03 09:01:48;  author: kleink;  state: Exp;  lines: +6 -3
% Upon an attempt to write to a stream that can't be written to, set errno
% to EBADF.
% ----------------------------

> > errno = 19, rc = 0
> > fwrite errno = 0, rc = 18
> >
> > Which gives us ENODEV for the fputs(3) and no error for the fwrite(3).
> ...
> I'll bet the isatty() call in __smakebuf() is setting errno
> because /dev/null doesn't support the relevant ioctl.  Note that
> rc=0 so libc is ignoring the error and completing the write, even
> though it spuriously sets errno.  In any case, you're right that
> this is an unrelated bug.

Very unrelated.  As explained in my earlier reply, rc = 0 indicates
an error.  errno is not set since we don't support the POSIX extension
of setting it.  The bug is that ioctls on /dev/zero return a wrong errno
(ENODEV instead of ENOTTY).  I fixed tens if not hundreds of instances
of this bug but never got around to it in the /dev/null family.

Bruce



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