Я следую идее @slacy, которая создает функцию popen2.
Но обнаруженная проблема, когда дочерний процесс умирает, родительский процесс, который все еще читает дескриптор файла outfp
, не возвращается из функции.
Это можно исправить, добавив закрыть неиспользуемый канал в родительском процессе.
close(p_stdin[READ]);
close(p_stdout[WRITE]);
Мы можем получить правильный pid нового процесса, используя bash в качестве оболочки.
execl("/bin/bash", "bash", "-c", command, NULL);
Когда умирает дочерний процесс, вызывающая функция popen2
должна получить статус дочернего процесса путем вызова pclose2
. если мы не собираем этот статус, дочерний процесс может быть зомби-процессом, когда он завершается.
Это полный код, который протестирован и работает, как и ожидалось.
#define READ 0
#define WRITE 1
pid_t
popen2(const char *command, int *infp, int *outfp)
{
int p_stdin[2], p_stdout[2];
pid_t pid;
if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
return -1;
pid = fork();
if (pid < 0)
return pid;
else if (pid == 0)
{
dup2(p_stdin[READ], STDIN_FILENO);
dup2(p_stdout[WRITE], STDOUT_FILENO);
//close unuse descriptors on child process.
close(p_stdin[READ]);
close(p_stdin[WRITE]);
close(p_stdout[READ]);
close(p_stdout[WRITE]);
//can change to any exec* function family.
execl("/bin/bash", "bash", "-c", command, NULL);
perror("execl");
exit(1);
}
// close unused descriptors on parent process.
close(p_stdin[READ]);
close(p_stdout[WRITE]);
if (infp == NULL)
close(p_stdin[WRITE]);
else
*infp = p_stdin[WRITE];
if (outfp == NULL)
close(p_stdout[READ]);
else
*outfp = p_stdout[READ];
return pid;
}
int
pclose2(pid_t pid) {
int internal_stat;
waitpid(pid, &internal_stat, 0);
return WEXITSTATUS(internal_stat);
}