Search code examples
cshellunixpiping

Piping Given an Array of UNIX Commands


So I am at the very end of a project to create a basic UNIX shell using C. I have finished a lot of different pieces of the program, but now I would like to conquer piping. I would specifically like to create a program that can handle any number of pipes.

For some reason my code get to s certain line (labeled: //DIES HERE) and then stops and I can't figure out why.

Here is the code that I have so far:

//the contents of args[0] is {"ls","-l","-o"}
//the contents of args[1] is {"wc","-l"}

int pipefd[2];

pipe(&pipefd[0]);   // Error check!

fflush(stdout);
for (i = 0; i < commands; i++){
    int pid = fork();

    if (pid == 0){

        int command_no = i;
        int prev_pipe = ((command_no - 1) % 2) * 2;
        int current_pipe = (command_no % 2) * 2;
        printf("\ncmd %d: prev pipe %d, curr pipe %d\n\n", i, prev_pipe, current_pipe);
        fflush(stdout);

        // If current command is the first command, close the
        // read end, else read from the last command's pipe
        if (command_no == 0){
            close(pipefd[0]);
        }
        else{
            dup2(pipefd[prev_pipe], 0);
            close(pipefd[current_pipe]);                    
        }

        // If current command is the last command, close the
        // write end, else write to the pipe
        if (command_no == commands - 1){
            close(pipefd[current_pipe + 1]);                    
        }
        else{
            dup2(pipefd[current_pipe + 1], 1); //DIES HERE
        }
        // printf("Here?\n\n");
        execvp(*args[i], args[i]);
        fprintf(stderr, "Failed to exec: %s (%d: %s)\n", arrayOfCommands[i], errno, strerror(errno));
        _exit(1);
    }
}

Any help is appreciated! :)


Solution

  • The primary issue I see is that pipe() is outside the loop. You're going to need a new pipe() between every pair of processes. The comments on your question make some good points as well.

    I wrote a shell many years ago in college and here's the similar loop from my code. I'm sure I'd do it much differently now, but it may be of use to you:

        for (i = 0; i < iNumPipes; ++i) {
                if (i == iNumPipes - 1) {
                        /* this is the last command
                         */
                        p[1] = fdOutput;
                        p[0] = -1;
                } else if (-1 == pipe(p)) {
                        perror("pipe");
                        exit(1);
                }
    
                switch (iPid = fork()) {
                case -1:
                        perror("fork");
                        exit(1);
                case 0:
                        close(0);
                        dup2(fdInput, 0);
                        close(fdInput);
    
                        close(1);
                        dup2(p[1], 1);
                        close(p[1]);
    
                        if (-1 != fdErr) {
                                close(2);
                                dup2(fdErr, 2);
                                close(fdErr);
                        }
    
                        pc = SearchPath(pppcAvs[i][0]);
                        execve(pc, pppcAvs[i], ppcEnv);
                        perror(pc);
                        _exit(-1);
                default:
                        close(fdInput);
                        close(p[1]);
                        fdInput = p[0];
                }
    
        }