stdout – Expected Behavior of stdbuf for Subprocesses

bufferldstdout

I didn't exactly find something about the following in the man-page. How is the supposed behavior in subprocesses spawned by a process which was itself spawned by stdbuf?

E.g.:

stdbuf -oL myprog

From the code, I get that it sets LD_PRELOAD, and as far as I know, all environment variables are inherited in any subprocesses.

I'm interested in both fork(); and fork(); execv(); subprocesses. (Not sure if that would make a difference.)

fork(); should not change the behavior at all. execv() would use the same LD_PRELOAD (as well as the stdbuf settings which also stored in env) and thus apply the same behavior (from the example: stdout is line-buffered).

Right?

Best Answer

straceing the execve (with environ) and write system calls can help see what's going on:

Here with the stdbuf of GNU coreutils 8.25. I beleive FreeBSD's stdbuf works similarly:

exec and no fork:

$ env -i strace -s200 -vfe execve,write /usr/bin/stdbuf -o0 /usr/bin/env /usr/bin/env > /dev/null
execve("/usr/bin/stdbuf", ["/usr/bin/stdbuf", "-o0", "/usr/bin/env", "/usr/bin/env"], []) = 0
execve("/usr/bin/env", ["/usr/bin/env", "/usr/bin/env"], ["_STDBUF_O=0", "LD_PRELOAD=/usr/lib/x86_64-linux-gnu/coreutils/libstdbuf.so"]) = 0
execve("/usr/bin/env", ["/usr/bin/env"], ["_STDBUF_O=0", "LD_PRELOAD=/usr/lib/x86_64-linux-gnu/coreutils/libstdbuf.so"]) = 0
write(1, "_STDBUF_O=0\n", 12)           = 12
write(1, "LD_PRELOAD=/usr/lib/x86_64-linux-gnu/coreutils/libstdbuf.so\n", 60) = 60
+++ exited with 0 +++

LD_PRELOAD and the config in _STDBUF_O is passed to both env commands. The two write() system calls even though the output doesn't go to a terminal confirms the output is not buffered.

fork and exec:

$ env -i strace -s200 -vfe execve,write /usr/bin/stdbuf -o0 /bin/sh -c '/usr/bin/env; :' > /dev/null
execve("/usr/bin/stdbuf", ["/usr/bin/stdbuf", "-o0", "/bin/sh", "-c", "/usr/bin/env; :"], []) = 0
execve("/bin/sh", ["/bin/sh", "-c", "/usr/bin/env; :"], ["_STDBUF_O=0", "LD_PRELOAD=/usr/lib/x86_64-linux-gnu/coreutils/libstdbuf.so"]) = 0
Process 16809 attached
[pid 16809] execve("/usr/bin/env", ["/usr/bin/env"], ["_STDBUF_O=0", "LD_PRELOAD=/usr/lib/x86_64-linux-gnu/coreutils/libstdbuf.so", "PWD=/home/stephane"]) = 0
[pid 16809] write(1, "_STDBUF_O=0\n", 12) = 12
[pid 16809] write(1, "LD_PRELOAD=/usr/lib/x86_64-linux-gnu/coreutils/libstdbuf.so\n", 60) = 60
[pid 16809] write(1, "PWD=/home/stephane\n", 19) = 19
[pid 16809] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED,

Same situation.

So yes stdbuf applies to the command it runs and all of its descendants (provided they don't clean their environment like the dynamic linker or libc do with LD_PRELOAD for setuid/setgid... applications).

Related Question