0

I've doing custom shell for an assignment, and I wanted to implement the pseudo code from emphemient here for multiple piping. However, my code is still hanging on the read end of the pipe (in my test command, I do echo hello | wc and it's hanging on wc).

Is my implementation incorrect based on the pseudocode? I think I close the pipes properly

void piped()
{
    // test command
    char args[] = "echo hello | wc";

    int status;
    pid_t pid;
    int cmdsRun = 0;
    int newfds[2];
    int oldfds[2];

    char *nextCmd;
    char *prevCmd = NULL;
    char *cmdToken;
    char *cmdSavePter;
    cmdToken = strtok_r(args, "|", &cmdSavePter);
    while (cmdToken)
    {
        nextCmd = strtok_r(NULL, "|", &cmdSavePter);
        fprintf(stderr, "cmdToken: %s, nextCmd: %s, prev: %s\n", cmdToken, nextCmd, prevCmd);
        struct command *commands = parseW(cmdToken);

        // if next command make new pipes
        if (nextCmd)
            pipe(newfds);

        // fork
        pid = fork();
        if (pid == 0) // child
        {
            // if there was prev cmd
            if (prevCmd)
            {
                dup2(oldfds[0], STDIN_FILENO);
                close(oldfds[0]);
                close(oldfds[1]);
            }

            // if next cmd
            if (nextCmd)
            {
                close(newfds[0]);
                dup2(newfds[1], STDOUT_FILENO);
                close(newfds[1]);
            }

            // this function simply execvps the commands
            runSimple(commands);
        }
        else if (pid < 0)
        {
            perror("error");
            exit(EXIT_FAILURE);
        }
        else // parent
        {
            // if there was a prev command
            if (prevCmd)
            {
                close(oldfds[0]);
                close(oldfds[1]);
            }
            // if next command
            if (nextCmd)
            {
                memcpy(oldfds, newfds, sizeof(oldfds));
            }
        }

        waitpid(pid, &status, 0);
        prevCmd = cmdToken;
        cmdToken = nextCmd;
        cmdsRun++;
    }

    // parent: if multiple cmds, close
    if (cmdsRun > 1)
    {
        close(oldfds[0]);
        close(oldfds[1]);
    }
}
Aaron Li
  • 89
  • 10
  • because you closed it??? `for (i = 0; i < 2 * numPipes; i++) {close(pipefds[i]);}` – user253751 Nov 13 '20 at 20:51
  • thanks, I had no idea i would be this stupid.. the code was fetched from another post about pipes but i glossed over that piece of code. I updated the code a bit, but the problem now is that when the command `wc -l` executes in `runSimple`, it hangs and is waiting for input from `STDIN`. Do I have to give `runSimple` the file descriptors and `dup2` in that function as well? – Aaron Li Nov 13 '20 at 21:17
  • If wc hangs waiting for input from STDIN, that means its in pipe's write end wasn't closed. The write end doesn't get closed until *all* of the descriptors of the write end are closed. Were they? – user253751 Nov 13 '20 at 21:20
  • I'm a bit confused by what you're saying (pipes confuse me a lot). In the updated code, I made it so that each iteration of the while loop forks a child (essentially resetting the STDOUT and STDIN file descriptors since the parent doesn't `dup2` right?) Then, the body of the while loop `dup2`s the read and write end of the pipe respectively. The `wc` command only has its STDIN duped, since it is the last command. The `ls -al` command only dupes the STDOUT, so I'm not sure why it's hanging. – Aaron Li Nov 13 '20 at 21:23
  • The code structure i use is based on this link: https://stackoverflow.com/a/8439286/14006754. I originally closed all the `pipefds` because based on the code in the link, you are supposed to in order to chain multiple pipes. What am I missing? – Aaron Li Nov 13 '20 at 21:28
  • I have completely reimplemented my code using ephemient's pseudo-code: https://stackoverflow.com/a/917700/14006754, yet it is still hanging – Aaron Li Nov 13 '20 at 22:24

0 Answers0