Pipe and Process management

214 views Asked by At

I am working on a tiny shell(tsh) implemented in C(it's an assignment). One part of assignment belongs to PIPING. I have to pipe a command's output to another command. e.g:ls -l | sort

When I run the shell, every command that I execute on it, is processed by a child process that it spawns. After the child finishes the result is returned. For piping I wanted to implement a harcoded example first to check how it works. I wrote a method, that partially works. The problems is when I run the pipe command, after child process finishes, the whole program quits with it! Obviously I am not handling the child process signal properly(Method code below).

My Question:

  • How does process management with pipe() works? if i run a command ls -l | sort does it create a child process for ls -l and another process for sort ? From the piping examples that I have seen so far, only one process is created(fork()).

  • When the second command (sort from our example) is processed, how can i get its process ID?

EDIT: Also while running this code I get the result twice. don't know why it runs twice, there is no loop in there.

Here is my code:

pid_t pipeIt(void){
    pid_t pid;
    int pipefd[2];

    if(pipe(pipefd)){
        unix_error("pipe");
        return -1;
    }

    if((pid = fork()) <0){
        unix_error("fork");
        return -1;  
    }
    if(pid == 0){
        close(pipefd[0]);
        dup2(pipefd[1],1);
        close(pipefd[1]);
        if(execl("/bin/ls", "ls", (char *)NULL) < 0){
            unix_error("/bin/ls");
            return -1;
        }// End of if command wasn't successful

    }// End of pid == 0
    else{
        close(pipefd[1]);
        dup2(pipefd[0],0);
        close(pipefd[0]);
        if(execl("/usr/bin/tr", "tr", "e", "f", (char *)NULL) < 0){
            unix_error("/usr/bin/tr");
            return -1;
        }
    }

    return pid;

}// End of pipeIt
2

There are 2 answers

3
John Bollinger On BEST ANSWER

Yes, the shell must fork to exec each subprocess. Remember that when you call one of the execve() family of functions, it replaces the current process image with the exec'ed one. Your shell cannot continue to process further commands if it directly execs a subprocess, because thereafter it no longer exists (except as the subprocess).

To fix it, simply fork() again in the pid == 0 branch, and exec the ls command in that child. Remember to wait() for both (all) child processes if you don't mean the pipeline to be executed asynchronously.

1
Joni On

Yes, you do need to call fork at least twice, once for each program in the pipeline. Remember that exec replaces the program image of the current process, so your shell stops existing the moment you start running sort or (tr).