使用dup2重定向stdout / stderr,然后再使用resinstate

时间:2017-05-17 11:36:09

标签: c linux io-redirection dup

背景:我们有一个运行Busybox的嵌入式Linux系统(资源有限),我们有一个正在运行的进程,它通常会在控制台上发出大量信息(通过stdout / stderr)但是我们会喜欢暂时将命令重命名为syslog(使用syslogd / logger) - 无需重启过程或重新启动。

使用找到的代码here可以很好地工作,直到我们尝试停止/关闭记录器fd,此时写入stdout / stderr失败并且一切都中断。示例如下:

int main()
{

    // Got command to direct all output to syslog:

    FILE *fl;
    fl = popen("logger","w");
    if(fl == NULL)
        return 1;
    fprintf(fl,"logger test new"); // This goes to syslogd
    int nf;
    nf = fileno(fl);
    dup2(nf,STDOUT_FILENO);
    dup2(nf,STDERR_FILENO);
    fprintf(stdout,"Written in stdout\n");
    fprintf(stderr,"Written in stderr\n");

    // ...some time later when we've logged enough things:

    pclose(fl);
    fprintf(stdout,"This will fail\n");
    fprintf(stderr,"Catch fire and die\n");
}

所以问题是,一旦我们完成日志记录,我们可以(如何)恢复原始状态?

dup()dup2()上使用RTFM我不清楚我们究竟能够如何实现这一点,如果可以“重新开启”或许是freopen() stdout / stderr,而是作为一个也许最后可能会将nf指向/dev/null/,因此至少不会崩溃。

2 个答案:

答案 0 :(得分:2)

您必须在dup2之前复制初始文件描述符,否则dup2将关闭它们,并且无法恢复它们。

int stdout_copy = dup(STDOUT_FILENO);
dup2(nf, STDOUT_FILENO);

/* do something with stdout */

dup2(stdout_copy, STDOUT_FILENO);
close(stdout_copy);

抛出错误处理,添加fflush调用以确保不会在stdlib缓冲区中保留未写入的数据,并且你应该做得很好。

答案 1 :(得分:0)

Linux手册页很清楚dup2不会关闭oldfd。别忘了也关闭nf