More about disabling standard I/O buffering
In yesterday's article I
described a simple and useful feature that could have been added to
the standard I/O library, to allow an environment variable to override
the default buffering behavior. This would allow the invoker of a
program to request that the program change its buffering behavior even
if the program itself didn't provide an option specifically for doing
that.
Simon Tatham directed me to the GNU Coreutils stdbuf
command
which does something of this sort. It is rather like the
pseudo-tty-pipe program I described, but instead of using the
pseudo-tty hack I suggested, it works by forcing the child program to
dynamically
load
a custom replacement for
stdio .
There appears to be a very similar command in FreeBSD.
[ Addendum 20240820: This description is not accurate; see below. ]
Roderick Schertler pointed out that Dan Bernstein wrote a utility
program, pty , in 1990, atop which my pseudo-tty-pipe program could
easily be built; or maybe its ptybandage utility is exactly what I
wanted. Jonathan de Boyne Pollard has a page explaining it in
detail, and related
packages.
A later version of pty is still
available.
Here's M. Bernstein's blurb about it:
ptyget is a universal pseudo-terminal interface. It is designed to be
used by any program that needs a pty.
ptyget can also serve as a wrapper to improve the behavior of existing
programs. For example, ptybandage telnet is like telnet but
can
be put into a pipeline. nobuf grep is like grep but won't
block-buffer if it's redirected.
Previous pty-allocating programs — rlogind , telnetd , sshd , xterm ,
screen , emacs , expect , etc. — have caused dozens of security problems.
There are two fundamental reasons for this. First, these programs are
installed setuid root so that they can allocate ptys; this turns every
little bug in hundreds of thousands of lines of code into a potential
security hole. Second, these programs are not careful enough to
protect
the pty from access by other users.
ptyget solves both of these problems. All the privileged code is in
one
tiny program. This program guarantees that one user can't touch
another
user's pty.
ptyget is a complete rewrite of pty 4.0, my previous pty-allocating
package. pty 4.0's session management features have been split off
into
a separate package, sess .
Leonardo Taccari informed me that NetBSD's stdio actually
has the environment variable feature I was asking for! Christos
Zoulas suggested adding stdbuf similar to the GNU and FreeBSD
implementations, but the NetBSD people observed, as I did, that it
would be simpler to just control stdio directly with an environment
variable, and did it. Here's the relevant part of the NetBSD setbuf(3) man
page:
The default buffer settings can be overwritten per descriptor
(STDBUF n) where n is the numeric value of the file descriptor
represented by the stream, or for all descriptors (STDBUF ). The
environment variable value is a letter followed by an optional
numeric value indicating the size of the buffer. Valid sizes range
from 0B to 1MB. Valid letters are:
U unbuffered
L line buffered
F fully buffered
Here's the discussion from the NetBSD tech-userlevel mailing
list.
The actual patch looks almost exactly the way I imagined it would.
Finally, Mariusz Ceier pointed out that there is an ancient bug report in
glibc
suggesting essentially the same environment variable mechanism that I
suggested and that was adopted in NetBSD. The suggestion was firmly
and summarily rejected. (“Hell, no … this is a terrible idea.”)
Interesting wrinkle: the bug report was submitted by Pádraig Brady,
who subsequently wrote the stdbuf command I described above.
Thank you, Gentle Readers!
Addenda
20240820
nabijaczleweli has pointed out that my explanation of the GNU stdbuf
command above is not accurate. I said "it works by forcing the child
program to dynamically load a custom replacement for stdio ". It's
less heavyweight than that. Instead, it arranges to load
a dynamic library
that runs before the rest of the program starts, examines the
environment, and simply calls setvbuf as needed on the three
standard streams.
[Other articles in category /Unix]
permanent link
|