在 c 中处理管道时关闭文件描述符

Closing file descriptors when handling pipes in c

我正在尝试实现一个非常简单的 shell,它只处理管道,没有语法错误,所以我有一个这样声明的 AST:

typedef struct s_ast t_ast;

struct s_ast
{
    int     type;
    t_ast   *l;
    t_ast   *r;
    char    **cmd;
};

type 只能容纳 0 或 1(CMD 或 PIPE)。 如果type等于PIPE,lr是管道的左/右分支 cmd 是带参数的命令,如果 type 等于 CMD

然后我有我的 exe 函数,它只调用另外两个函数之一:exe_pipeexe_cmdexe_cmd 函数只是在子进程中调用 execve 并等待它结束。

现在,这是我的 exe_pipe 函数(没有对系统调用进行错误检查以提高可读性):

void exe_pipe(t_ast *ast, char **env)
{
    int fd[2], pid[2];

    pipe(fd);
    if ((pid[0] = fork()) == 0)
    {
        dup2(fd[1], STDOUT_FILENO);
        close(fd[0]);
        exe(ast->l, env);
        close(fd[1]);
        exit(EXIT_FAILRE);
    }
    if ((pid[1] = fork()) == 0)
    {
        dup2(fd[0], STDIN_FILENO);
        close(fd[1]);
        exe(ast->r, env);
        close(fd[0]);
        exit(EXIT_FAILURE);
    }
    waitpid(-1, NULL, 0);
    close(fd[0]); close(fd[1]);
    waitpid(-1, NULL, 0);
}

基本上,我分叉两次以创建 2 个“subshells”,每个都将执行其管道的一侧。

我的问题是这段代码泄露了一些文件描述符,但我不知道在哪里关闭每个文件描述符,我想我必须在某处使用 SIGPIPE 信号,但我对此不太满意.

你可以找到完整的代码here如果你想测试它

复制后需要关闭文件描述符。样板是:

pipe(fd);
...
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
execl(....)

由于您在关闭管道之前正在执行 children,因此当您调用 exe 时打开的 fd 过多。特别是,第一个 child 在执行时仍然有 fd[1] 打开,并且由于该文件描述符仍然打开,第二个 child 永远不会在其标准输入上看到 EOF。 (我假设 exe 调用 exec*。如果是这样,在 exe 之后调用 close 没有任何好处。)

总是计算你的fd。假设您从 3(0、1 和 2)开始。在调用pipe之后,你有5个。在你dup2之后,你还有5个。(一个被dup2打开,一个被关闭。)你只想有3个当 child 执行时,您需要关闭 2.