开发者

Writing to both stdout & a file

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

How do I write the 开发者_运维知识库same output to both stdout & a file, without using pipes or tees?


If you don't want to use a tee, before you write the data, write it to a file, then send it to stdout.

You should write a logging function that does this for you to make it cleaner.


Pipe it through tee.


You can use dup2() - this link provides an example


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


Also, you can use fifo's. mkfifo my.fifo; in execv: program > my.fifo; and open fifo as a regular file, reading from it. This way you can have your stdout parsed, but it has minor drawbacks with shared access.


Do you want only the output of the child to go to the log?

The tee unix command does exactly what you describe: you pipe in data and it writes to a log and to stdout.


Use Tee like this:

./myprog | tee outputfile
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜