tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

NetBSD bug/misbehavior in vdprintf



NetBSD's implementation of vdprintf makes a special check -- if the descriptor is in non-blocking mode, it needs to be a regular file (I think I read that code correctly).  But it apparently doesn't have this check problem for vfprintf.  I think it's been there a long time (since the introduction of vdprintf), but it makes vdprintf behave differently than vfprintf.  In my view, "vfprintf( FILE, ...)" and "vdprintf( fileno( FILE ), ... )" ought to behave the same -- but they don't (on NetBSD) if "fileno( FILE )" has been marked non-blocking and it's not a regular file.

Other OSes do not behave this way.

Here's some very simple code that demonstrates:

	#include <stdio.h>
	#include <fcntl.h>
	#include <errno.h>

	static void check_result( int n )
	{
		if ( n < 0 ) { fprintf( stderr, "\tfailure (error = %d)\n", errno ); }
		else { fprintf( stderr, "\tsuccess!\n" ); }
	}

	int main(int argc, const char * argv[])
	{
		int n;
		int flags;
		int err;

		n = fprintf( stdout, "fprintf to stdout (blocking)\n" );
		check_result( n );

		n = dprintf( fileno( stdout ), "dprintf to stdout (blocking)\n" );
		check_result( n );

		// now set stdout to non-blocking
		flags = fcntl( fileno( stdout ), F_GETFL );
		err = fcntl( fileno( stdout ), F_SETFL, flags | O_NONBLOCK );
		if ( err != 0 )
		{
			fprintf( stderr, "fcntl( F_SETFL ) failure (%d)\n", errno );
		}

		n = fprintf( stdout, "fprintf to stdout (non-blocking)\n" );
		check_result( n );

		n = dprintf( fileno( stdout ), "dprintf to stdout (non-blocking)\n" );
		check_result( n );

		return 0;
	}

Here's the output on mac OS, FreeBSD and Linux:

	> ./dprintf_test 
	fprintf to stdout (blocking)
		success!
	dprintf to stdout (blocking)
		success!
	fprintf to stdout (non-blocking)
		success!
	dprintf to stdout (non-blocking)
		success!

But here's the output on NetBSD:

	> ./dprintf_test
	fprintf to stdout (blocking)
      	success!
	dprintf to stdout (blocking)
      	success!
	fprintf to stdout (non-blocking)
      	success!
	        failure (error = 79)

The behavior is caused by code in libc/stdio/vdprintf.c -- around line 92:

	if (fdflags & O_NONBLOCK) {
		struct stat st;
		if (fstat(fd, &st) == -1)
			return -1;
		if (!S_ISREG(st.st_mode)) {
			errno = EFTYPE;
			return EOF;
		}
	}

Why is this done on NetBSD (when it isn't on other OSes)?  And why does vfprintf not have the same restriction/limitation?

Thanks!

Rob


Home | Main Index | Thread Index | Old Index