C – 从父母分娩后重定向stdout

我正在编写一个程序来执行另一个程序作为分叉进程,并根据需要将其输出重定向到文件或/ dev / null.

目前我已经使用execvp()分叉并执行了外部程序.
然后从分叉之前创建的线程重定向stdout,因为分叉进程将继承父文件描述符表,允许我在foking之后重定向.

但是,我最初可以将stdout重定向到所需的文件,父母和孩子的stdouts都被重定向.但是,如果我尝试将其重定向到另一个文件,则只重定向父项stdout,子项的stdout保持不变.

这是没有所有错误检查位的代码.

struct params {
    const char *p;
    int fd;
    int wait;
};

#define EXIT_NOEXEC 126
#define EXIT_NOTFOUND   127
#define EXIT_MISC   127

static void dofile(struct params* st);
void dupit(const char *p, struct params* st);
void* reload_config(void* para);

int
main(int argc, char *argv[]) {
    int exit_status, prog_status;
    struct params init;
    pid_t prog_pid;


    dofile(&init);

    prog_pid = fork();
    if (prog_pid == 0) {
        execvp(*argv, argv);
        exit_status = (errno == ENOENT) ? EXIT_NOTFOUND : EXIT_NOEXEC;
        err(exit_status, "%s", argv[0]);
        exit(EXIT_FAILURE);
    } else {
        while (wait(&prog_status) != prog_pid);
        return prog_status;
    }
}

static void dofile(struct params* st) {
    const char *p
    p = out.txt;
    dupit(p, st);

}


void dupit(const char *p, struct params* st) {
    pthread_t tid;
    st->wait = 0;
    int err = pthread_create(&(tid), NULL, &reload_config, st);
    if (err != 0) {
        printf("\ncan't create thread :[%s]", strerror(err));
        exit(1);
    } else {
        while (st->wait == 0) {
            sleep(1)
        }
    }
}

void* reload_config(void* para) {
    struct params *passed = (struct params *) para;
    int pre_config = 3; 
    int cur_config = 1; 
    int saved_stdout = dup(STDOUT_FILENO);
    char infile[5];
    int devNull = open("/dev/null", O_WRONLY);
    int file = open("out.txt", O_WRONLY);
    FILE *config;
    config = fopen("config.txt", "r");
    if (access("config.txt", F_OK) != -1) {
        while (1) {
            fgets(infile, 5, config);
            fclose(config);
            cur_config = infile[0] - '0';
            printf("output from thread, current config = %d\n", cur_config);
            if (pre_config != cur_config) {
                if (cur_config == 1) {
                    if (dup2(file, STDOUT_FILENO) == -1) {
                        err(EXIT_MISC, NULL);
                    }
                } else {
                    dup2(devNull, STDOUT_FILENO);
                }
                pre_config = cur_config;
            }
            if (passed->wait==0) {
                passed->wait = 1;
            }
            sleep(1);
        }
    } else {
        if (dup2(passed->fd, STDOUT_FILENO) == -1) {
            err(EXIT_MISC, NULL);
        }
    }
}

好吧,我改变了一些代码,所以你们会理解,所以有些部分没有意义.但是你得到了基本的想法.

如何在分叉后按照我的意愿重定向孩子的标准输出.

最佳答案 既然你问过,这里有一个简单的例子.为简洁起见,我们采取了一些捷径,但希望它会给你一些想法.该程序打开file1并将stdout重定向到该文件.它然后做一个分叉.子进程每1秒向stdout(通过printf)写一个计数器.几秒钟之后,父进程使用IPC(本例中的管道)告诉子进程切换重定向文件.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

int main(int argc, char **argv)
{  
    pid_t pid;
    const char *file1 = "file1.txt";
    const char *file2 = "file2.txt";
    int pipefd[2];
    int fd;
    int rval;

    fd = open(file1, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
    if (fd == -1) {
        perror("file1 open");
        exit(-1);
    }

    /*
     * This pipe will be used by parent process to tell child which file
     * to redirect to.
     */
    rval = pipe2(pipefd, O_NONBLOCK);
    if (fd == -1) {
        perror("pipe");
        exit(-1);
    }

    /* Redirect stdout to the file opened before the fork. */
    dup2(fd, STDOUT_FILENO);

    pid = fork();

    if (pid == -1) {
        perror("fork");
        exit(-1);
    } else if (pid == 0) {
        /* Child process. */
        int ix;
        char redirect_file[100];

        close(pipefd[1]);

        for (ix = 0; ix < 10; ix++) {

            printf("%d\n", ix);
            sleep(1);

            rval = read(pipefd[0], redirect_file, sizeof(redirect_file));
            if (rval > 0) {
                /*
                 * Parent process has written a filename to the pipe.
                 */ 
                fd = open(redirect_file, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
                if (fd == -1) {
                    perror("file2 open");
                    exit(-1);
                }

                /* Ensure previous output has been written to current file. */
                fflush(stdout);

                /* Change redirect now. */
                dup2(fd, STDOUT_FILENO);
            }
        }
    } else {
        /* Parent process. */
        close(pipefd[0]);

        /* Wait a little and then tell child to change redirect file. */
        sleep(5);
        write(pipefd[1], file2, strlen(file2) + 1);

        wait();
    }
}

如果运行此程序,您会发现子输出的一半转到file1(第一次重定向),另一半输出转到file2(第二次重定向).

$cat file1.txt 
0
1
2
3
4
$cat file2.txt 
5
6
7
8
9

最后一点说明.示例程序在fork之前执行第一个dup.我是这样做的,因为这是你的代码的显示方式,也是为了强调问题的前后方面.但在实际代码中,传统的做法是首先执行fork,然后执行dup,最后执行exec.在fork之后完成dup,这样只有子进程受到影响而不是父进程(除非那真的是你想要的).

点赞