From owner-freebsd-standards@FreeBSD.ORG Wed Mar 3 01:24:14 2004 Return-Path: Delivered-To: freebsd-standards@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 60C3316A4CE; Wed, 3 Mar 2004 01:24:14 -0800 (PST) Received: from mailout2.pacific.net.au (mailout2.pacific.net.au [61.8.0.85]) by mx1.FreeBSD.org (Postfix) with ESMTP id A4B7043D39; Wed, 3 Mar 2004 01:24:13 -0800 (PST) (envelope-from bde@zeta.org.au) Received: from mailproxy1.pacific.net.au (mailproxy1.pacific.net.au [61.8.0.86])i239OCnX029229; Wed, 3 Mar 2004 20:24:12 +1100 Received: from gamplex.bde.org (katana.zip.com.au [61.8.7.246]) i239O9sJ016323; Wed, 3 Mar 2004 20:24:10 +1100 Date: Wed, 3 Mar 2004 20:24:09 +1100 (EST) From: Bruce Evans X-X-Sender: bde@gamplex.bde.org To: "Jordan K. Hubbard" In-Reply-To: <0805074F-6CC9-11D8-9000-000393BB9222@queasyweasel.com> Message-ID: <20040303195618.K1351@gamplex.bde.org> References: <20040303144451.T5253@gamplex.bde.org> <0805074F-6CC9-11D8-9000-000393BB9222@queasyweasel.com> MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII cc: standards@freebsd.org cc: David Schultz Subject: Re: Another conformance question... This time fputs(). X-BeenThere: freebsd-standards@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Standards compliance List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 03 Mar 2004 09:24:14 -0000 On Tue, 2 Mar 2004, Jordan K. Hubbard wrote: > On Mar 2, 2004, at 8:04 PM, Bruce Evans wrote: > > > 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. > > So, what fix are you suggesting? I'm truly open to suggestions here, > but if all we end up doing at the end of the day is concluding that > things are broken but we don't like any of the proposed fixes, we've > not really accomplished anything either. I'd more than welcome any > diffs to supersede mine. We should try to call the underlying function in more cases. This is not so easy since there are flags that may protect whether the underlying function can even be called. Note that cantwrite() already handles some of the details, and could set errno to EBADF more easily than setting it in all callers: % /* % * Return true iff the given FILE cannot be written now. % */ % #define cantwrite(fp) \ % ((((fp)->_flags & __SWR) == 0 || \ % ((fp)->_bf._base == NULL && ((fp)->_flags & __SSTR) == 0)) && \ % __swsetup(fp)) This returns 0 (canwrite) or calls __swsetup() (or both). So __swsetup() always gets a chance to set errno in a context-sensitive way in the cantwrite cases. It doesn't seem to do much errno setting now: % /* % * Various output routines call wsetup to be sure it is safe to write, % * because either _flags does not include __SWR, or _buf is NULL. % * _wsetup returns 0 if OK to write, nonzero otherwise. % */ % int % __swsetup(fp) % FILE *fp; % { % /* make sure stdio is set up */ % if (!__sdidinit) % __sinit(); % % /* % * If we are not writing, we had better be reading and writing. % */ % if ((fp->_flags & __SWR) == 0) { % if ((fp->_flags & __SRW) == 0) % return (EOF); This is the only failure case. It bogusly returns EOF instead of boolean true. We can set errno to EBADF here if we have no idea why __SRW is clear. But we should know. I think the cases are: (1) a normal fopen() for reading only. Then EBADF is correct. (2) funopen() with no writer, or fropen(). I think this can be determined by checking the function pointer that we write through. Then write is just unsupported and an errno like ENOTSUP is better than EBADF. (3) otherwise, we will call the underlying function and there is no problem here. The underlying function just needs to set errno if it fails, and old ones probably don't. So the only immediate problem with returning EBADF in all cases seems to be in case (2) which is not very interesting. % if (fp->_flags & __SRD) { % /* clobber any ungetc data */ % if (HASUB(fp)) % FREEUB(fp); % fp->_flags &= ~(__SRD|__SEOF); % fp->_r = 0; % fp->_p = fp->_bf._base; % } % fp->_flags |= __SWR; % } % % /* % * Make a buffer if necessary, then set _w. % */ % if (fp->_bf._base == NULL) % __smakebuf(fp); % if (fp->_flags & __SLBF) { % /* % * It is line buffered, so make _lbfsize be -_bufsize % * for the putc() macro. We will change _lbfsize back % * to 0 whenever we turn off __SWR. % */ % fp->_w = 0; % fp->_lbfsize = -fp->_bf._size; % } else % fp->_w = fp->_flags & __SNBF ? 0 : fp->_bf._size; % return (0); % } Bruce