Mon, 21 May 2018
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:
ptygetis a universal pseudo-terminal interface. It is designed to be used by any program that needs a pty.
ptygetcan also serve as a wrapper to improve the behavior of existing programs. For example,ptybandage telnetis liketelnetbut can be put into a pipeline.nobuf grepis likegrepbut 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.
ptygetsolves 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.
ptygetis a complete rewrite ofpty4.0, my previous pty-allocating package.pty4.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 (
STDBUFn) 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:
Uunbuffered
Lline buffered
Ffully 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


