Another conformance question... This time fputs().
Jordan K. Hubbard
jkh at queasyweasel.com
Tue Mar 2 01:07:01 PST 2004
I submit for your consideration the following test program and the
wonderful variety of test results it produces:
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int rc;
FILE *fp=fopen("/dev/zero", "r");
rc = fputs("Hello world\n", fp);
printf("errno = %d, rc = %d\n", errno, rc);
errno = 0;
rc = fwrite("Hello world again\n", 1, 18, fp);
printf("fwrite errno = %d, rc = %d\n", errno, rc);
fclose(fp);
}
On Red Hat Linux 9.0, it outputs the following:
errno = 9, rc = -1
fwrite errno = 9, rc = 0
Just to save you the grepping, errno #9 is EBADF, "bad file number".
Now we KNOW that the mode on that fopen is (a) on a device which
doesn't allow writing and (b) of the wrong open mode ("r" rather than
"w"), but this discussion concerns "the right thing to do" when faced
with just these sorts of bogus situations and one could probably argue
that Linux returns the wrong errno here, but it does set errno.
What does FreeBSD do? It does this:
errno = 0, rc = -1
fwrite errno = 0, rc = 0
Given that it's just not kosher to write on a read-only fp and get no
error back at all, I would argue (though not passionately) for the
following diff to libc:
--- stdio/fvwrite.c 22 Mar 2002 21:53:04 -0000 1.15
+++ stdio/fvwrite.c 2 Mar 2004 08:40:25 -0000
@@ -43,6 +43,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include "local.h"
#include "fvwrite.h"
@@ -67,8 +68,10 @@
if ((len = uio->uio_resid) == 0)
return (0);
/* make sure we can write */
- if (cantwrite(fp))
+ if (cantwrite(fp)) {
+ errno = EACCES;
return (EOF);
+ }
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define COPY(n) (void)memcpy((void *)fp->_p, (void *)p,
(size_t)(n))
That gives us this behavior for our little test program:
errno = 13, rc = -1
fwrite errno = 13, rc = 0
In both cases, we get EACCES for fputs() or fwrite() attempts on a
read-only file pointer pointing to a read-only device, something we'd
expect to get "permission denied" for I think. In the case where we
open the fp for write access, the FreeBSD behavior is unchanged:
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'm not sure why an error is returned at all in the fputs(3) case since
it seems perfectly valid to write onto /dev/null and simply have the
data be discarded, but that error is coming back from somewhere deeper
of the bowels of stdio and has nothing to do with my proposed diff in
any case. Red Hat Linux, interestingly enough, returns errno 25 in
this case (ENOTTY)!
This is your libc. This is your libc on SUSv2*. Any questions?
* References:
http://www.opengroup.org/onlinepubs/007908799/xsh/fwrite.html
http://www.opengroup.org/onlinepubs/007908799/xsh/fputs.html
--
Jordan K. Hubbard
Engineering Manager, BSD technology group
Apple Computer
More information about the freebsd-hackers
mailing list