5

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?

3

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).

| improve this answer | |
  • I was also interested in fork and no exec. But I guess that is very much straight-forward as it really should inherit everything, i.e. also same behavior. – Albert Apr 29 '16 at 16:27
  • It's not libc but the dynamic linker which clears LD_PRELOAD & co from the environment for setuid binaries. – mosvy Apr 18 at 17:45
  • @mosvy, well, at least on GNU systems, the dynamic linker comes from the same source as the libc and for statically linked applications, the libc does unset those same variables (in libc.a:_dl_non_dynamic_init()). – Stéphane Chazelas Apr 19 at 6:14
  • Yes, on GNU systems, glibc and rtld are part of the same software package, but they're still separate binaries. And they're completely different on other systems like BSD or Android. But an implementation where some constructor function pushed by libc would clear those envvars, while dumb, is perfectly imaginable -- does such a thing exist? – mosvy Apr 19 at 6:16
1

The buffering is inherited through the fork/exec of timeout as illustrated by the following test code:

bash-4.1$ cat isbuffed.c 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
    printf("should not appear if buffered");
    sleep(999);
    exit(EXIT_SUCCESS);
}
bash-4.1$ make isbuffed
cc     isbuffed.c   -o isbuffed
bash-4.1$ timeout 3 ./isbuffed
bash-4.1$ stdbuf -o0 timeout 3 ./isbuffed
should not appear if bufferedbash-4.1$ 
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.