On Fri, Aug 28, 2020 at 2:50 PM Rob Newberry <robthed...@mac.com> wrote:
> 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)? (fwiw, i didn't check FreeBSD but Android [via OpenBSD] doesn't have this either.) > And why does vfprintf not have the same restriction/limitation? > > Thanks! > > Rob > >