如何将所有 stdio 记录并代理到子进程?

How can I log and proxy all stdio to a sub-process?

我有两个进程,一个父进程和一个子进程。父进程执行子进程并使用 stdin/out 来通信和控制子进程。

我想通过记录这两个进程之间发生的所有 io(​​stdin、out、err)来检查这两个进程之间使用的协议。

我有能力指定父进程执行的命令来启动子进程,所以我的问题是:

是否有命令行工具 and/or 简单 C/Java/python 程序可以 "wrap" 子命令并记录(到文件)所有标准输入 + 标准输出,同时转发所有 io他们(所以子流程继续工作?)

图形化,我的想法是:

目前:Parent <-io-> Child

想法:Parent <-io-> Wrapper/Proxy <-io-> Child

提前致谢!

它不是很漂亮,但是很管用。它不能很好地关闭,但它允许我通过用我自己的可执行文件包装子进程命令来检查父进程和子进程之间的通信:

概览:

  • 它期望子命令(及其参数)作为包装参数
  • 它设置了 3 个管道来重新路由 + 拦截 std{in,out,err}
  • 它在内部分叉了很多次,以便有一个进程来消费和记录每个 stdio 流
  • 写入文件 stdin.logstdout.logstderr.log
  • 最终分叉预期的可执行文件,设置拦截的 stdio 管道

用法:./wrapper /bin/othercommand -a -b -c

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>

int ioin[2];
int ioout[2];
int ioerr[2];

void handler(int sig)
{
    printf("Closing everything!\n");

    close(ioin[0]);
    close(ioin[1]);
    close(ioout[0]);
    close(ioout[1]);
    close(ioerr[0]);
    close(ioerr[1]);
}

int main(int argc, const char * argv[]) {
    pipe(ioin);
    pipe(ioout);
    pipe(ioerr);

    // execvp(argv[1], argv+1);

    signal(SIGHUP, &handler);

    if(fork() == 0)
    {
        close(ioin[0]); // close in read
        close(ioout[1]); // close in write
        close(ioerr[1]); // close in write

        if(fork() == 0)
        {
            if(fork() == 0)
            {
                char buf;
                FILE* f = fopen("stdin.log", "w+");
                // fprintf(f, "%d\n", getpid());
                // fflush(f);
                while (read(STDIN_FILENO, &buf, 1) > 0) {
                    write(ioin[1], &buf, 1);
                    fwrite(&buf, 1, 1, f);
                    fflush(f);
                }
                fprintf(f, "Done\n");

                fclose(f);
                close(ioin[1]);
                close(0);

                kill(0, SIGHUP);

                _exit(0);
            }
            else
            {
                char buf;
                FILE* f = fopen("stdout.log", "w+");
                // fprintf(f, "%d\n", getpid());
                // fflush(f);
                while (read(ioout[0], &buf, 1) > 0) {
                    write(STDOUT_FILENO, &buf, 1);
                    fwrite(&buf, 1, 1, f);
                    fflush(f);
                }
                fprintf(f, "Done\n");

                fclose(f);
                close(ioout[0]);
                _exit(0);
            }
        }
        else
        {
            char buf;
            FILE* f = fopen("stderr.log", "w+");
            // fprintf(f, "%d\n", getpid());
            // fflush(f);
            while (read(ioerr[0], &buf, 1) > 0) {
                write(STDERR_FILENO, &buf, 1);
                fwrite(&buf, 1, 1, f);
                fflush(f);
            }
            fprintf(f, "Done\n");


            fclose(f);
            close(ioerr[0]);
            _exit(0);
        }
    }
    else
    {
        close(ioin[1]); // close in write
        close(ioout[0]); // close in read
        close(ioerr[0]); // close in read

        if(fork() == 0)
        {
            close(0);
            dup(ioin[0]);

            close(1);
            dup(ioout[1]);

            close(2);
            dup(ioerr[1]);

            execvp(argv[1], argv+1);
        }
        else
        {
            wait(NULL);
        }
    }
}

我很高兴接受另一个更清晰 and/or 更正确的答案。