I'm writing a program to execute another program as a forked process and redirect it's output to a file or /dev/null on demand.
我正在编写一个程序,将另一个程序作为一个分叉的进程执行,并根据需要将它的输出重定向到一个文件或/dev/null。
Currently I have forked and executed the external program using execvp(). Then redirected the stdout from a thread created before forking as the forked process will inherit parents file descriptor table allowing me to redirect after foking.
目前我已经使用execvp()对外部程序进行了分叉和执行。然后从分叉之前创建的线程重定向stdout,因为分叉进程将继承父文件描述符表,允许我在分叉后重定向。
But, I can initially redirect stdout to a desired file and both parents and child's stdouts are being redirected. However if I try to redirect it again to another file, only parents stdout is redirected, child's stdout stays the same.
但是,我可以先将stdout重定向到需要的文件,并且父母和孩子的stdouts都被重定向。但是,如果我尝试重新将它重定向到另一个文件,只有父类stdout被重定向,child的stdout保持不变。
Here's the code without all the error checking bits.
这是没有错误校验位的代码。
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);
}
}
}
Well, I changed the code a bit so you guys will understand, so some parts will make no sense. But you get the basic idea.
我对代码做了一点修改,这样你们就能理解了,有些部分就没有意义了。但是你知道基本的概念。
How can I redirect child's stdout as I wish after forking.
我要如何重定向孩子的stdout后,我希望。
1 个解决方案
#1
1
Since you asked, here is a simple example. Some shortcuts have been taken for brevity but hopefully it gives you some idea. The program opens file1 and redirects stdout to that file. It then does a fork. The child process writes a counter to stdout (via printf
) every 1 second. After a few seconds the parent process uses IPC, a pipe
in this example, to tell the child to switch redirect file.
既然你问了,这里有一个简单的例子。为了简洁起见,我们采用了一些捷径,但希望它能给您一些建议。程序打开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();
}
}
If this program is run you will find that half the child output went to file1 (first redirect) and other half of the output goes to file2 (second redirect).
如果运行此程序,您将发现一半的子输出转到file1(第一次重定向),另一半输出转到file2(第二次重定向)。
$ cat file1.txt
0
1
2
3
4
$ cat file2.txt
5
6
7
8
9
One final note. The example program does the first dup
before the fork
. I did it like that because that's how your code was shown and also to emphasise the before and after fork
aspect of the issue. But in real code the conventional way of doing that is to do fork
first, then dup
and finally exec
. The dup
is done after the fork
so that only the child process gets affected and not the parent (unless that is really what you want).
最后一个音符。示例程序在fork之前执行第一个dup。我这样做是因为您的代码是这样显示的,同时也强调了问题的前后分叉方面。但是在实际代码中,传统的做法是先做fork,然后是dup,最后是exec。dup是在fork之后完成的,因此只有子进程受到影响,而不是父进程(除非这是您真正想要的)。
#1
1
Since you asked, here is a simple example. Some shortcuts have been taken for brevity but hopefully it gives you some idea. The program opens file1 and redirects stdout to that file. It then does a fork. The child process writes a counter to stdout (via printf
) every 1 second. After a few seconds the parent process uses IPC, a pipe
in this example, to tell the child to switch redirect file.
既然你问了,这里有一个简单的例子。为了简洁起见,我们采用了一些捷径,但希望它能给您一些建议。程序打开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();
}
}
If this program is run you will find that half the child output went to file1 (first redirect) and other half of the output goes to file2 (second redirect).
如果运行此程序,您将发现一半的子输出转到file1(第一次重定向),另一半输出转到file2(第二次重定向)。
$ cat file1.txt
0
1
2
3
4
$ cat file2.txt
5
6
7
8
9
One final note. The example program does the first dup
before the fork
. I did it like that because that's how your code was shown and also to emphasise the before and after fork
aspect of the issue. But in real code the conventional way of doing that is to do fork
first, then dup
and finally exec
. The dup
is done after the fork
so that only the child process gets affected and not the parent (unless that is really what you want).
最后一个音符。示例程序在fork之前执行第一个dup。我这样做是因为您的代码是这样显示的,同时也强调了问题的前后分叉方面。但是在实际代码中,传统的做法是先做fork,然后是dup,最后是exec。dup是在fork之后完成的,因此只有子进程受到影响,而不是父进程(除非这是您真正想要的)。