Sunday, October 9, 2022

[SOLVED] Multi-Process Shell in C, using Pipes [Linux]

Issue

I'm trying to code a shell in C that supports multi-pipe process handling, depending on the amount of separate processes given by the user, and each separated by a "|" symbol. The shell forks the amount of processes into a child for each process.

Here's an example:

texto1.txt = "Isto é o Texto 1"

$ cat texto1.txt | grep -c Isto 

result: 1

But I'm having trouble with communicating between children and finally to the parent process.

Here's my current code for the execpipe function, which executes the pipe process, being argv1 and argv2 the 2 separate processes given by user input: (Example: ls -l | wc -l)

int execpipe(char ** argv1, char  ** argv2)
{
    int fds[2];
    pipe(fds);
    int i;
    pid_t p1, p2;
    p1 = fork();
    if (p1 == -1)
    { // error
        char * error = strerror(errno);
        printf("error fork!!\n");
        return 1;
    }
    if (p1 == 0)
    { // child process

        close(fds[0]);
        dup2(fds[1], STDOUT_FILENO);
        close(fds[1]);
        if(execvp(argv1[0], argv1)<0){ // run command AFTER pipe character in userinput
            char * error = strerror(errno);
            printf("unknown command\n");
            return 0;
        }
    }
    else
    { // parent process
        p2 = fork();

        if(p2==0){
            close(fds[1]);
            dup2(fds[0], STDIN_FILENO);
            close(fds[0]);
            if(execvp(argv2[0], argv2)<0){ // run command AFTER pipe character in userinput
                char * error = strerror(errno);
                printf("unknown command\n");
                return 0;
            }
        }else{ //Parent waits for both of it's children
            wait(NULL);
            wait(NULL);
        }
    }
}


Solution

The parent must close the pipe's write end to indicate the second process that no more data will come:

            }
        }else{ //Parent waits for both of it's children
            close(fds[1]); // ++ add this line
            wait(NULL);
            wait(NULL);
        }

Little note: instead of

        char * error = strerror(errno);
        printf("error fork!!\n");

why not

        perror("fork");


Answered By - Mathieu
Answer Checked By - Marie Seifert (WPSolving Admin)