C语言 我们能关闭文件描述符3和4吗?我有问题

mnemlml8  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(89)

在我的C程序中,特别是在我的Pipex项目的上下文中,我面临着管理文件描述符的挑战。在程序退出时,Valgrind报告有5个文件描述符打开,其中3个是标准描述符。特别是,文件描述符5是在pipe. c文件的第29行用管道函数打开的,在我的程序中从地址0x109622的here_doc函数调用。
我在下面引用了Valgrind报告的一个片段以供参考:valgrind 1valgrind 2
代码: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);
}

krugob8w

krugob8w1#

当你将一个管道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);
    }

字符串
main()中,你需要在重复它之后执行close(out)。你在调用exe()之后执行这个操作。但是exe()永远不会返回,因为它调用了execve()。所以把这个调用移到exe()之前。

dup2(out, STDOUT_FILENO);
    close(in);
    exe(ev, av[ac - 2]);

相关问题