Another conformance question... This time fputs().

Bruce Evans bde at zeta.org.au
Tue Mar 2 20:21:40 PST 2004


On Tue, 2 Mar 2004, Jordan K. Hubbard wrote:

> It's also not clear to me why ENODEV is being returned, though I'm not
> as inclined to blame isatty() since it appears to do the right thing:
>
> #include <stdio.h>
> #include <fcntl.h>
> #include <errno.h>
>
> main() {
>          int fd, ret;
>
>          fd = open("/dev/null", O_RDONLY);
>          ret = isatty(fd);
>          printf("ret = %d, errno = %d\n", ret, errno);
>          close(fd);
> }
>
> Prints:	ret = 0, errno = 25

This is because someone fixed /dev/null but not /dev/zero (I misread
this in my previous reply).  They are implemented in the same file,
but only 1 has this bug.  From null.c:

%%%
static struct cdevsw null_cdevsw = {
	.d_version =	D_VERSION,
	.d_read =	(d_read_t *)nullop,
	.d_write =	null_write,
	.d_ioctl =	null_ioctl,
	.d_name =	"null",
	.d_maj =	CDEV_MAJOR,
};

static struct cdevsw zero_cdevsw = {
	.d_version =	D_VERSION,
	.d_read =	zero_read,
	.d_write =	null_write,
	.d_name =	"zero",
	.d_maj =	CDEV_MAJOR,
	.d_flags =	D_MMAP_ANON,
};
%%%

/dev/null has a special ioctl function "null_ioctl" which does the right
thing without having to do anything (the existence of an ioctl function
means that at least 1 ioctl is supported, so ENOTTY is correct for the
unsupported ones).

/dev/zero doesn't have any ioctl function, so it gets the default which
is enodev() (which just returns ENODEV).  This is almost correct --
ENODEV means that ioctls are completely unsupported, which is technically
correct.  However, it is surprising -- ENOTTY is the errno for most
types of files including regular ones.

> All isatty() does is call tcgetattr(), it doesn't do an
> ioctl(...TIOCGETA...).

Yes it does; see another reply.  (tcgetattr() is tcsetattr(3), not a
hypothetical tcsetattr(2) syscall.  It happens to be implemented using
an old ioctl.)

Bruce


More information about the freebsd-arch mailing list