我正在读取另一个生成输出(慢速和无限)的过程的输出。因为我想实时读取这些数据,所以我使用“stdbuf -oL”(行缓冲,数据是文本)。我无法控制生成过程,因此我无法修改源以强制刷新。
到目前为止,stdbuf工作正常,但是该过程使用SOCK_RAW并且需要以root身份运行,具有setuid(0)或cap_net_raw
功能。当使用setuid或功能作为非root运行时,stdbuf似乎被忽略了。让我来说明问题:
这是一个简单的作家:
#include <stdio.h>
#include <unistd.h>
int main(){
int i;
for ( i = 0;; i++){
fprintf(stdout, "%d\n", i);
sleep(1);
}
}
一位简单的读者:
#include <stdio.h>
int main(){
char* line = NULL;
size_t n = 0;
while (getline(&line, &n, stdin) != -1 ) {
fputs(line, stdout);
}
}
正如预期的那样,通过执行./writer | ./reader
,在填充缓冲区之前不会显示任何内容。预先stdbuf -oL
启用行缓冲,我将这些行放入读者:
% stdbuf -oL ./writer | ./reader
0
1
2
...
但如果我添加cap_net_raw+ep
,它就会停止工作:
% sudo setcap cap_net_raw+ep ./writer
% stdbuf -oL ./writer | ./reader
(no output)
使用setuid时会出现相同的行为:
% sudo chown root:root ./writer
% sudo chmod +s ./writer
% stdbuf -oL ./writer | ./reader
(no output)
我很想知道为什么会这样,以及如何在不以root身份运行的情况下继续使用stdbuf。我承认我并不完全理解setuid在幕后所做的事情。
答案 0 :(得分:2)
通过设置LD_PRELOAD查看stdbuf source code它看起来是有效的。使用LD_PRELOAD和setuid可执行文件或sudo当然存在安全问题。
我发现有一个建议是disable the noatsecure selinux attribute为您的可执行文件。
另一个更简单的选择是避免使用stdbuf并直接从源代码中调用fflush(stdout)
。
答案 1 :(得分:1)
LD_PRELOAD
您可以使用属于unbuffer
(expect-devel
)软件包的expect
实用程序。 unbuffer
是一个非常短的期望脚本。它不需要LD_PRELOAD
,因为它使用了另一种技巧。 expect
创建一个伪终端(如xterm
或ssh
),因此使用unbuffer
执行的进程被欺骗,认为它正在写入交互设备,因此默认情况下它使用行缓冲stdout
。
在您的情况下使用:
unbuffer ./writer | ./reader
如果stdbuf
适用于程序unbuffer
,那么它也很有可能。由于LD_PRELOAD
带来了一些限制unbuffer
优于stdbuf
。与stdbuf
相反,它将适用于这些类型的可执行文件:
libc