Index: lib/libc/stdio/fflush.c =================================================================== --- lib/libc/stdio/fflush.c +++ lib/libc/stdio/fflush.c @@ -60,7 +60,7 @@ /* * There is disagreement about the correct behaviour of fflush() - * when passed a file which is not open for reading. According to + * when passed a file which is not open for writing. According to * the ISO C standard, the behaviour is undefined. * Under linux, such an fflush returns success and has no effect; * under Windows, such an fflush is documented as behaving instead @@ -68,11 +68,14 @@ * Given that applications may be written with the expectation of * either of these two behaviours, the only safe (non-astonishing) * option is to return EBADF and ask that applications be fixed. + * SUSv3 now requires that fflush() returns success on a read-only + * stream. In addition, the conformance tests will warn if a fflush + * on a read-only stream does not set the file descriptor's file offset + * to the real position. */ - if ((fp->_flags & (__SWR | __SRW)) == 0) { - errno = EBADF; - retval = EOF; - } else + if ((fp->_flags & (__SWR | __SRW)) == 0) + retval = 0; + else retval = __sflush(fp); FUNLOCKFILE(fp); return (retval); @@ -89,10 +92,9 @@ if (fp == NULL) return (_fwalk(sflush_locked)); - if ((fp->_flags & (__SWR | __SRW)) == 0) { - errno = EBADF; - retval = EOF; - } else + if ((fp->_flags & (__SWR | __SRW)) == 0) + retval = 0; + else retval = __sflush(fp); return (retval); } @@ -122,6 +124,12 @@ for (; n > 0; n -= t, p += t) { t = _swrite(fp, (char *)p, n); if (t <= 0) { + /* Reset _p and _w. */ + if (p > fp->_p) /* Some was written. */ + memmove(fp->_p, p, n); + fp->_p += n; + if ((fp->_flags & (__SLBF | __SNBF)) == 0) + fp->_w -= n; fp->_flags |= __SERR; return (EOF); } Index: lib/libc/stdio/fgetln.3 =================================================================== --- lib/libc/stdio/fgetln.3 +++ lib/libc/stdio/fgetln.3 @@ -97,6 +97,9 @@ The argument .Fa stream is not a stream open for reading. +.It Bq Er ENOMEM +The internal line buffer could not be expanded due to lack of available memory, +or because it would need to expand beyond INT_MAX in size. .El .Pp The Index: lib/libc/stdio/fgetln.c =================================================================== --- lib/libc/stdio/fgetln.c +++ lib/libc/stdio/fgetln.c @@ -37,6 +37,8 @@ __FBSDID("$FreeBSD$"); #include "namespace.h" +#include +#include #include #include #include @@ -61,6 +63,10 @@ #endif if (fp->_lb._size >= newsize) return (0); + if (newsize > INT_MAX) { + errno = ENOMEM; + return (-1); + } if ((p = realloc(fp->_lb._base, newsize)) == NULL) return (-1); fp->_lb._base = p; @@ -159,6 +165,7 @@ error: *lenp = 0; /* ??? */ + fp->_flags |= __SERR; FUNLOCKFILE(fp); return (NULL); /* ??? */ } Index: lib/libc/stdio/fputs.c =================================================================== --- lib/libc/stdio/fputs.c +++ lib/libc/stdio/fputs.c @@ -62,5 +62,7 @@ ORIENT(fp, -1); retval = __sfvwrite(fp, &uio); FUNLOCKFILE(fp); + if (retval == 0) + return iov.iov_len; return (retval); } Index: lib/libc/stdio/freopen.c =================================================================== --- lib/libc/stdio/freopen.c +++ lib/libc/stdio/freopen.c @@ -97,7 +97,7 @@ (dflags & (O_ACCMODE | O_EXEC)) != (oflags & O_ACCMODE)) { fclose(fp); FUNLOCKFILE(fp); - errno = EINVAL; + errno = EBADF; return (NULL); } if (fp->_flags & __SWR) @@ -132,6 +132,7 @@ * descriptor (if any) was associated with it. If it was attached to * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin) * should work. This is unnecessary if it was not a Unix file. + * For UNIX03, we always close if it was open. */ if (fp->_flags == 0) { fp->_flags = __SEOF; /* hold on to it */ @@ -142,15 +143,22 @@ if (fp->_flags & __SWR) (void) __sflush(fp); /* if close is NULL, closing is a no-op, hence pointless */ - isopen = fp->_close != NULL; - if ((wantfd = fp->_file) < 0 && isopen) { + if (fp->_close) (void) (*fp->_close)(fp->_cookie); - isopen = 0; - } + isopen = 0; + wantfd = -1; } /* Get a new descriptor to refer to the new file. */ f = _open(file, oflags, DEFFILEMODE); + if (f < 0 && isopen) { + /* If out of fd's close the old one and try again. */ + if (errno == ENFILE || errno == EMFILE) { + (void) (*fp->_close)(fp->_cookie); + isopen = 0; + f = _open(file, oflags, DEFFILEMODE); + } + } sverrno = errno; finish: @@ -158,11 +166,9 @@ * Finish closing fp. Even if the open succeeded above, we cannot * keep fp->_base: it may be the wrong size. This loses the effect * of any setbuffer calls, but stdio has always done this before. - * - * Leave the existing file descriptor open until dup2() is called - * below to avoid races where a concurrent open() in another thread - * could claim the existing descriptor. */ + if (isopen) + (void) (*fp->_close)(fp->_cookie); if (fp->_flags & __SMBF) free((char *)fp->_bf._base); fp->_w = 0; @@ -181,8 +187,6 @@ memset(&fp->_mbstate, 0, sizeof(mbstate_t)); if (f < 0) { /* did not get it after all */ - if (isopen) - (void) (*fp->_close)(fp->_cookie); fp->_flags = 0; /* set it free */ FUNLOCKFILE(fp); errno = sverrno; /* restore in case _close clobbered */ @@ -194,13 +198,12 @@ * to maintain the descriptor. Various C library routines (perror) * assume stderr is always fd STDERR_FILENO, even if being freopen'd. */ - if (wantfd >= 0) { + if (wantfd >= 0 && f != wantfd) { if ((oflags & O_CLOEXEC ? _fcntl(f, F_DUP2FD_CLOEXEC, wantfd) : _dup2(f, wantfd)) >= 0) { (void)_close(f); f = wantfd; - } else - (void)_close(fp->_file); + } } /* Index: lib/libc/stdio/ftell.c =================================================================== --- lib/libc/stdio/ftell.c +++ lib/libc/stdio/ftell.c @@ -97,6 +97,8 @@ * Find offset of underlying I/O object, then * adjust for buffered bytes. */ + if (__sflush(fp)) /* may adjust seek offset on append stream */ + return (1); if (fp->_flags & __SOFF) pos = fp->_offset; else { Index: lib/libc/stdio/gets.c =================================================================== --- lib/libc/stdio/gets.c +++ lib/libc/stdio/gets.c @@ -52,7 +52,7 @@ int c; char *s; static int warned; - static char w[] = + static const char w[] = "warning: this program uses gets(), which is unsafe.\n"; FLOCKFILE(stdin); Index: lib/libc/stdio/rewind.c =================================================================== --- lib/libc/stdio/rewind.c +++ lib/libc/stdio/rewind.c @@ -53,9 +53,8 @@ __sinit(); FLOCKFILE(fp); - if (_fseeko(fp, (off_t)0, SEEK_SET, 1) == 0) { - clearerr_unlocked(fp); + if (_fseeko(fp, (off_t)0, SEEK_SET, 1) == 0) errno = serrno; - } + clearerr_unlocked(fp); /* POSIX: clear stdio error regardless */ FUNLOCKFILE(fp); } Index: lib/libc/stdio/wbuf.c =================================================================== --- lib/libc/stdio/wbuf.c +++ lib/libc/stdio/wbuf.c @@ -36,6 +36,7 @@ #include __FBSDID("$FreeBSD$"); +#include #include #include "local.h" @@ -59,8 +60,10 @@ * calls might wrap _w from negative to positive. */ fp->_w = fp->_lbfsize; - if (prepwrite(fp) != 0) + if (prepwrite(fp) != 0) { + errno = EBADF; return (EOF); + } c = (unsigned char)c; ORIENT(fp, -1);