cbashforkwaitwaitpid

Implementation Bash pipes and redirections in c


interesting screen lldb

I encounter an issue with my implementation of pipes and output redirection. It works fine individually, but when I try 'ls | wc > a', it doesn't function as in real Bash. It creates the file 'a', but it doesn't redirect the output of 'ls | wc' to this file and creat infinite loop It waits for the pid, but I have the loop to wait for all the function at the end, I made a mistake, but I don't know where ?

I have a function for creating my pipes and their execution and the same for redirection I can't find the solution i my probleme why my 'ls | wc > file' is not redirected from my file

pipeline.c

void create_pipe(int pipe_fd[2], int i, int last) 
{
    if (i < (last - 1))
    {
        if (pipe(pipe_fd) == -1) 
        {
            perror("pipe");
            exit(EXIT_FAILURE);
        }
    }
}

void close_pipes_in_parent(int i, t_data *data, int *input_fd) 
{
    if (i != data->first)
        close(*input_fd);
    if (i < data->last) 
    {
        close(data->pipe_fd[1]);
        *input_fd = data->pipe_fd[0];
    }

}


pid_t fork_process_pipe(int i, int input_fd, t_data *data, t_Token *curr, char **envp, t_Token *lst_tok) 
{
    pid_t pid = fork(); 

    if (pid == 0)
    { 
        printf("111111111111111111");
        if (i != data->first) 
        {
                dup2(input_fd, STDIN_FILENO);
                close(input_fd);
        }
        if (i < data->last) 
        {
                dup2(data->pipe_fd[1], STDOUT_FILENO);
                close(data->pipe_fd[0]);
                close(data->pipe_fd[1]);
        }
        data->path_exe = ft_get_reading(data, curr, envp);
        if(!data->path_exe)
        {
            printf("Bash : command not found : %s\n", data->cmd[0]);
            ft_free_tabtab(data->cmd);
            free_token(lst_tok);
            exit(EXIT_FAILURE);
        }
        if (execve(data->path_exe, data->cmd, envp) == -1) 
        {
            ft_free_tabtab(data->cmd);
            free(data->path_exe);
            exit(EXIT_FAILURE);
        }
        free(curr->Token_str);
        free(curr);
    }
    return (pid);
}


redir.c

int *creat_fd_out(t_data *data, t_Token *curr, int *output_fd)
{
    int i;

    i = 0;
    while(i < data->nb_file)
    {
        output_fd[i] =  open(curr->next->next->Token_str, O_CREAT | O_WRONLY | O_TRUNC, 0644);
        if (output_fd[i] == -1) 
            exit(EXIT_FAILURE);
        i++;
        curr = curr->next->next ;
    }
    return(output_fd);
}

void close_fd_in(t_data *data, int *output_fd)
{
    int i;

    i = 0;
    while(i < data->nb_file)
    {    
        close(output_fd[i]);
        i++;
    }
}

pid_t fork_process_redi(t_data *data, t_Token *curr, char **envp, t_Token *lst_tok) 
{
    pid_t pid = fork(); 
    int *output_fd = malloc(data->nb_file * sizeof(int)); 
    
    if (pid == 0)
    { 
        if ((curr->type == E_WORD && curr->next != NULL) && (curr->next->Token_str[0] == '>'))
        {  
            data->path_exe = ft_get_reading(data, curr, envp);
            if(!data->path_exe)
            {
                printf("Bash : command not found : %s\n", data->cmd[0]);
                ft_free_tabtab(data->cmd);
                free_token(lst_tok);
            }
            output_fd = creat_fd_out(data, curr, output_fd);
            dup2(output_fd[data->nb_file -1], STDOUT_FILENO);
            close_fd_in(data, output_fd);

        }
        if (execve(data->path_exe, data->cmd, envp) == -1) 
        {
            ft_free_tabtab(data->cmd);
            free(data->path_exe);
            exit(EXIT_FAILURE);
        }
        free(curr->Token_str);
        free(curr);
    }
    return (pid);
}

lanch_exe.c

void execute_pipeline_redirection(t_data *data, t_Token *list_token, char **envp) 
{
    int index_fork;
    int input_fd;
    t_Token *curr;

    data->last = data->nb_cmd;
    curr = list_token;
    input_fd = STDIN_FILENO;
    data->first = 0;
    index_fork = 0;
    pid_t pid[data->last];
    

    while (curr != NULL) 
    {   
        if ((curr->type == E_WORD && curr->next != NULL) && (curr->next->Token_str[0] == '>') && (curr->next->next->type == E_FILE))   
        {
            pid[index_fork] = -1;        
            pid[index_fork] = fork_process_redi(data, curr, envp, list_token);
            index_fork++;
        }
        if (((curr->type == E_WORD || curr->next->type ==  E_FILE ) && curr->next != NULL && curr->next->Token_str[0] == '|') && (curr->type == E_WORD && curr->next == NULL))
        {        
            pid[index_fork] = -1;        
            create_pipe(data->pipe_fd, index_fork, data->last);
            pid[index_fork] = fork_process_pipe(index_fork, input_fd, data, curr, envp, list_token);
            close_pipes_in_parent(index_fork, data, &input_fd);
            index_fork++;

        }
        curr = curr->next;
    }
    wait_for_children(data->last, pid);
}

When i ruen crestain test like ls | wc > a my PID seems to remain indefinitely wating, whereas when i execute hen ls | cat fichier.txt > a, it works correctly

-> image test0 <-

-> image test1 <-

-> lldb witch will test "ls | wc > test.txt"<-


Solution

  • In fork_process_redi you are setting the output file descriptor but not the input, like you are doing in fork_process_pipe. The last command in pipeline with redirection will be reading from STDIN until EoF readed instead from the pipe of the last command. "cat file" will not read from stdin and it runs ok.

    Not related, but the free sentences after execve will never be executed. The memory is freed when the forked process exits so it's not an issue.