Writing to both stdout & a file

前端 未结 7 561
耶瑟儿~
耶瑟儿~ 2020-12-07 03:17

I have a parent process which forks out a child to perform execv().

I need the output given by execv() to stdout to be displayed onscreen as also copied to a log fil

相关标签:
7条回答
  • 2020-12-07 04:16

    You can do this entirely within your program, but you will still need to use anonymous pipes as created by the pipe() system call.

    Basically, you will need a subprocess that performs the equivalent of tee, which is quite easy:

    int child_pipe[2];
    pid_t pid_exec_child, pid_output_child;
    
    pipe(child_pipe);
    
    pid_exec_child = fork();
    if (pid_exec_child == 0)
    {
        dup2(child_pipe[1], STDOUT_FILENO);
        close(child_pipe[0]);
        close(child_pipe[1]);
        execve(/* ... */);
        _exit(127);
    }
    
    close(child_pipe[1]);
    
    pid_output_child = fork();
    if (pid_output_child == 0)
    {
        /* This child just loops around, reading from the other child and writing everything
         * to both stdout and the log file. */
        int logfd = open("logfile", O_WRONLY);
        char buffer[4096];
        ssize_t nread;
    
        while ((nread = read(child_pipe[0], buffer, sizeof buffer) != 0)
        {
            size_t nwritten_total;
            ssize_t nwritten;
    
            if (nread < 0)
            {
                if (errno == EINTR)
                    continue;
    
                perror("read");
                _exit(1);
            }
    
            /* Copy data to stdout */
            nwritten_total = 0;
            while (nwritten_total < nread)
            {
                nwritten = write(STDOUT_FILENO, buffer + nwritten_total, nread - nwritten_total);
    
                if (nwritten < 0)
                {
                    if (errno == EINTR)
                        continue;
    
                    perror("write(stdout)");
                    _exit(2);
                }
    
                nwritten_total += nwritten;
            }
    
            /* Copy data to logfile */
            nwritten_total = 0;
            while (nwritten_total < nread)
            {
                nwritten = write(logfd, buffer + nwritten_total, nread - nwritten_total);
    
                if (nwritten < 0)
                {
                    if (errno == EINTR)
                        continue;
    
                    perror("write(logfile)");
                    _exit(3);
                }
    
                nwritten_total += nwritten;
            }
        }
        _exit(0);
    }
    
    close(child_pipe[0]);
    
    /* Parent continues here */
    

    Of course, it is probably easier to just exec tee in that second child instead...

    (Note that the child processes use _exit(), since they have inherited the standard I/O state from the parent).

    0 讨论(0)
提交回复
热议问题