[GNU Manual] [No POSIX requirement] [Linux man] [FreeBSD man]
Summary
stdbuf - run a command with modified I/O stream buffering
Lines of code: 395
Principal syscall: execvp()
Support syscalls: stat()
Options: 8 (3 short, 5 long)
This is a relatively recent utility
Added to Shellutils in June 2009 [First version]
Number of revisions: 44 [Code Evolution]
The stdbuf utility alters the buffering mode of the standard streams for the given command to either unbuffered, line buffered, or fully buffered. By default, we assume STDERR is unbuffered, while STDIN and STDOUT are fully buffered in most cases (exception: line buffered for true terminals). The mechanism to change buffering mode relies on LD_PRELOAD to load the libstdbuf shared object which applies changes at load time using the setvbuf() syscall
Helpers:optc_to_fileno()
- Converts a character to a stream referenceparse_size()
- Parses buffer size by converting the string to an integer.set_LD_PRELOAD()
- Adds libstdbuf to LD_PRELOADset_libstdbuf_options()
- Add the desired streams to the environmentset_program_path()
- Sets theprogram_path
global from $PATH to include the program to execute
die()
- Exit with mandatory non-zero error and message to stderrerror()
- Outputs error message to standard error with possible process termination
Setup
stdbuf keeps two important elements at global scope. The first is *program_path
, which holds the computed path of the program to run. The second global is a struct, stdbuf
to hold the details of the execution.
main() defines a local variable, c
to hold the first letter of the next option to parse
Parsing begins with the short options passed as a string literal:
"+i:o:e:"
Parsing
Parsing stdbuf
uses Getopt to pull user input to change buffering across the three input streams. A fully buffered steam includes parsing a buffer size:
Parsing failures
Parsing could fail in several ways:
- The user requests line buffering of STDIN
- User provides an invalid mode
- No command to execute
- No change to stream buffering modes
Execution
stdbuf
relies on a load-time mechanism to adjust streams before executing the target command. It takes advantage of the GCC constructor attrbiute within libstdbuf.c. This compiled library is loaded and executed before stdbufmain()
by adding it to LD_PRELOAD.
The overall utility logic is brief:
- Update the stream options in the global
struct stdbuf
array - Set the program path
- Update the LD_PRELOAD with the new library
- Execute target commend with updated constructor modifying streams
Note that since a successful execvp()
never returns, any execution within stdbuf implicilty means something failed. The subsequent command should return successful but the utility itself has no 'successful' return.
The stdbuf utility may fail in several ways. An EXIT_CANCELED status indicates a failure of stdbuf, while EXIT_ENOENT or EXIT_CANNOT_INVOKE points to a problem with the target command.
Failure cases:
- Unable to set environment options
- Unable to set LD_PRELOAD
execvp()
on target command fails
All failures at this stage output an error message to STDERR and return without displaying usage help