(Also posting to tech-userlevel...)

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

Reply via email to