【发布时间】:2015-12-18 03:30:01
【问题描述】:
我正在编写一个程序来执行另一个程序作为分叉进程,并将其输出重定向到文件或 /dev/null 按需。
目前我已经使用 execvp() 分叉并执行了外部程序。 然后从分叉之前创建的线程重定向标准输出,因为分叉的进程将继承父文件描述符表,允许我在分叉后重定向。
但是,我最初可以将标准输出重定向到所需的文件,并且父母和孩子的标准输出都被重定向。但是,如果我尝试再次将其重定向到另一个文件,则仅重定向父母的标准输出,孩子的标准输出保持不变。
这是没有所有错误检查位的代码。
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);
}
}
}
好吧,我稍微更改了代码以便你们理解,所以有些部分没有意义。但是你明白了基本的想法。
如何在分叉后按照我的意愿重定向孩子的标准输出。
【问题讨论】:
-
AFAIK,一个进程不能直接改变另一个进程的流。父进程将需要使用 IPC 机制来告诉子进程要重定向到哪个新文件,而子进程本身需要进行重定向。
-
但是初始重定向有效,这意味着孩子确实继承了父母的fd表。但我不清楚的是,在初次通话后,我无法重定向孩子的标准输出。
-
那是在分叉之前。也就是说,当时只有一个进程。一旦分叉完成,就会有两个进程具有相同的文件描述符。但从那时起,它们就独立了。也就是说,您可以在 fork 之前设置文件描述符,并且子进程一旦启动就会获得这些文件描述符 - 正如您所描述的那样。但是在fork之后,父级没有办法改变子文件描述符。
-
谢谢@kaylum,你是对的。这很有帮助。上面提到的 IPC 实施的一个小例子现在是黄金 :)
-
在贴出的代码中的某些地方调用了函数:
err()。在代码的其他地方,使用了变量err。让变量名与系统函数相同是一种非常糟糕的编程习惯。强烈建议将变量err更改为唯一名称