我们可以关闭文件描述符3和4吗?我遇到了麻烦

问题描述 投票:0回答:1

我在管理 C 程序中的文件描述符方面面临挑战,特别是在 Pipex 项目的上下文中。程序退出时,Valgrind 报告有 5 个文件描述符打开,其中 3 个是标准描述符。特别是,文件描述符 5 是使用 pipeline.c 文件中第 29 行的管道函数打开的,该函数是从我的程序中地址 0x109622 处的 here_doc 函数调用的。

我在下面添加了 Valgrind 报告中的一个片段以供参考: enter image description here 代码:

pipex.c

#include "../inc/pipex.h"

char    *find_path(char *cmd, char **ev)
{
    char    **allpaths;
    char    *exe;
    int     i;

    i = 0;
    while (ev[i])
    {
        if (ft_strnstr(ev[i], "PATH=", 5) != NULL)
            break ;
        i++;
    }
    allpaths = ft_split((ev[i] + 5), ':');
    i = 0;
    while (allpaths[i])
    {
        exe = build_executable_path(cmd, allpaths[i]);
        if (exe != NULL)
        {
            ft_clear_tab(allpaths);
            return (exe);
        }
        i++;
    }
    ft_clear_tab(allpaths);
    return (NULL);
}

void    exe(char **ev, char *av)
{
    char    **cmd;
    char    *cmd_exe;

    cmd = ft_split(av, ' ');
    cmd_exe = find_path(cmd[0], ev);
    if (cmd_exe == NULL)
    {
        perror("pipex: command not found");
        ft_putendl_fd(cmd[0], 2);
        ft_clear_tab(cmd);
        exit(EXIT_FAILURE);
    }
    if (execve(cmd_exe, cmd, ev) == -1)
    {
        perror("pipex: execution error");
        ft_putendl_fd(cmd[0], 2);
        ft_clear_tab(cmd);
        free(cmd_exe);
        exit(EXIT_FAILURE);
    }
}

void    do_pipe(char **av, char **ev)
{
    pid_t   pid;
    int     fd[2];

    if (pipe(fd) == -1)
        error_arg();
    pid = fork();
    if (pid == 0)
    {
        close(fd[0]);
        dup2(fd[1], STDOUT_FILENO);
        exe(ev, av[0]);
    }
    else
    {
        close(fd[1]);
        dup2(fd[0], STDIN_FILENO);
        waitpid(pid, NULL, 0);
    }
}

void here_doc(char *limiter, int ac)
{
    int fd[2];
    pid_t pid;
    char *line;

    if (ac < 6)
        error_arg();

    if (pipe(fd) == -1 || (pid = fork()) == -1)
    {
        perror("Pipe or Fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0)
    {
        close(fd[0]);

        while (gnl(&line) > 0)
        {
            if (ft_strncmp(line, limiter, ft_strlen(limiter)) == 0 || line[0] == '\0')
                exit(EXIT_SUCCESS);
            write(fd[1], line, ft_strlen(line));
        }
        free(line);
        close(fd[1]);
        exit(EXIT_SUCCESS);
    }
    else
    {
        close(fd[1]);
        dup2(fd[0], STDIN_FILENO);
        close(fd[0]);
        wait(NULL);
    }
}
int main(int ac, char **av, char **ev) 
{
    int in;
    int out;
    int i;

    if (ac < 5)
        error_arg();
    if (ft_strncmp(av[1], "here_doc", 8) == 0) 
    {
        i = 3;
        out = open(av[ac - 1], O_WRONLY | O_CREAT | O_TRUNC, 0777);
        if (out == -1)
            exit(EXIT_FAILURE);
        here_doc(av[2], ac);
    } 
    else
    {
        i = 2;
        out = open(av[ac - 1], O_WRONLY | O_CREAT | O_TRUNC, 0777);
        in = open(av[1], O_RDONLY, 0777);
        if (out == -1 || in == -1)
            exit(EXIT_FAILURE);
        dup2(in, 0);
    }
    while (i < ac - 2)
        do_pipe(av + i++, ev);
    dup2(out, 1);
    exe(ev, av[ac - 2]);
    close(in);
    close(out);
    return 0;
}

utils.c

#include "../inc/pipex.h"
#define BUFFER_SIZE 100000

void    error_arg(void)
{
    write(2, "\033[1;31m!! we need more than 5 arguments :c !!\n\033[0m\n", 49);
    write(2, "\033[1;32mExample: ./Here_doc cmd1 cmd2 outfile\033[0m\n", 50);
    write(2,
        "\033[1;32mExample 2: ./pipex infile cmd1 cmd2 cmd3 ... outfile\033[0m\n",
        65);
    exit(EXIT_FAILURE);
}

#include <unistd.h>
#include <stdlib.h>

int gnl(char **line)
{
    char *buffer;
    int i = 0;
    int r;
    char c;

    buffer = (char *)malloc(10000);
    if (!buffer)
        return (-1);
    while ((r = read(0, &c, 1)) > 0 && c != '\n' && c != '\0')
        buffer[i++] = c;

    buffer[i] = '\0'; 

    *line = buffer;

    if (r > 0 || i > 0)
        return (1); 
    else
        return (r);
}

void    ft_clear_tab(char **tab)
{
    size_t  i;

    i = 0;
    while (tab[i])
    {
        free(tab[i]);
        i++;
    }
    free(tab);
}

char    *build_executable_path(char *cmd, char *path)
{
    char    *part_path;
    char    *exe;

    part_path = ft_strjoin(path, "/");
    exe = ft_strjoin(part_path, cmd);
    free(part_path);
    if (access(exe, F_OK | X_OK) == 0)
        return (exe);
    free(exe);
    return (NULL);
}

c pipe valgrind file-descriptor
1个回答
1
投票

将管道 FD 之一复制到 stdin 或 stdout 后,不再需要打开原始管道 FD。所以重定向的代码应该如下所示:

    if (pid == 0)
    {
        close(fd[0]);
        dup2(fd[1], STDOUT_FILENO);
        close(fd[1]);
        exe(ev, av[0]);
    }
    else
    {
        close(fd[1]);
        dup2(fd[0], STDIN_FILENO);
        close(fd[0]);
        waitpid(pid, NULL, 0);
    }
© www.soinside.com 2019 - 2024. All rights reserved.