Having trouble with fork(), pipe(), dup2() and exec() in C

后端 未结 6 652
时光取名叫无心
时光取名叫无心 2020-12-01 03:44

Here\'s my code:

#include 
#include 
#include 
#include 
#include 

#         


        
6条回答
  •  挽巷
    挽巷 (楼主)
    2020-12-01 04:23

    Even after the first command of your pipeline exits (and thust closes stdout=~fdPipe[1]), the parent still has fdPipe[1] open.

    Thus, the second command of the pipeline has a stdin=~fdPipe[0] that never gets an EOF, because the other endpoint of the pipe is still open.

    You need to create a new pipe(fdPipe) for each |, and make sure to close both endpoints in the parent; i.e.

    for cmd in cmds
        if there is a next cmd
            pipe(new_fds)
        fork
        if child
            if there is a previous cmd
                dup2(old_fds[0], 0)
                close(old_fds[0])
                close(old_fds[1])
            if there is a next cmd
                close(new_fds[0])
                dup2(new_fds[1], 1)
                close(new_fds[1])
            exec cmd || die
        else
            if there is a previous cmd
                close(old_fds[0])
                close(old_fds[1])
            if there is a next cmd
                old_fds = new_fds
    if there are multiple cmds
        close(old_fds[0])
        close(old_fds[1])
    

    Also, to be safer, you should handle the case of fdPipe and {STDIN_FILENO,STDOUT_FILENO} overlapping before performing any of the close and dup2 operations. This may happen if somebody has managed to start your shell with stdin or stdout closed, and will result in great confusion with the code here.

    Edit

       fdPipe1           fdPipe3
          v                 v
    cmd1  |  cmd2  |  cmd3  |  cmd4  |  cmd5
                   ^                 ^
                fdPipe2           fdPipe4
    

    In addition to making sure you close the pipe's endpoints in the parent, I was trying to make the point that fdPipe1, fdPipe2, etc. cannot be the same pipe().

    /* suppose stdin and stdout have been closed...
     * for example, if your program was started with "./a.out <&- >&-" */
    close(0), close(1);
    
    /* then the result you get back from pipe() is {0, 1} or {1, 0}, since
     * fd numbers are always allocated from the lowest available */
    pipe(fdPipe);
    
    close(0);
    dup2(fdPipe[0], 0);
    

    I know you don't use close(0) in your present code, but the last paragraph is warning you to watch out for this case.

    Edit

    The following minimal change to your code makes it work in the specific failing case you mentioned:

    @@ -12,6 +12,4 @@
         pid_t pid;
    
    -    pipe(fdPipe);
    -
         while(1) {
             bBuffer = readline("Shell> ");
    @@ -29,4 +27,6 @@
             } while(aPtr);
    
    +        pipe(fdPipe);
    +
             for(i = 0; i < pCount; i++) {
                     aCount = -1;
    @@ -72,4 +72,7 @@
             }
    
    +        close(fdPipe[0]);
    +        close(fdPipe[1]);
    +
             for(i = 0; i < pCount; i++) {
                     waitpid(lPids[i], &status, 0);
    

    This won't work for more than one command in the pipeline; for that, you'd need something like this: (untested, as you have to fix other things as well)

    @@ -9,9 +9,7 @@
     int main(int argc, char *argv[]) {
         char *bBuffer, *sPtr, *aPtr = NULL, *pipeComms[NUMPIPES], *cmdArgs[10];
    -    int fdPipe[2], pCount, aCount, i, status, lPids[NUMPIPES];
    +    int fdPipe[2], fdPipe2[2], pCount, aCount, i, status, lPids[NUMPIPES];
         pid_t pid;
    
    -    pipe(fdPipe);
    -
         while(1) {
             bBuffer = readline("Shell> ");
    @@ -32,4 +30,7 @@
                     aCount = -1;
    
    +                if (i + 1 < pCount)
    +                    pipe(fdPipe2);
    +
                     do {
                             aPtr = strsep(&pipeComms[i], " ");
    @@ -43,11 +44,12 @@
    
                             if(pid == 0) {
    -                                if(i == 0) {
    -                                        close(fdPipe[0]);
    +                                if(i + 1 < pCount) {
    +                                        close(fdPipe2[0]);
    
    -                                        dup2(fdPipe[1], STDOUT_FILENO);
    +                                        dup2(fdPipe2[1], STDOUT_FILENO);
    
    -                                        close(fdPipe[1]);
    -                                } else if(i == 1) {
    +                                        close(fdPipe2[1]);
    +                                }
    +                                if(i != 0) {
                                             close(fdPipe[1]);
    
    @@ -70,4 +72,17 @@
                             }
                     }
    +
    +                if (i != 0) {
    +                    close(fdPipe[0]);
    +                    close(fdPipe[1]);
    +                }
    +
    +                fdPipe[0] = fdPipe2[0];
    +                fdPipe[1] = fdPipe2[1];
    +        }
    +
    +        if (pCount) {
    +            close(fdPipe[0]);
    +            close(fdPipe[1]);
             }
    

提交回复
热议问题