简体   繁体   中英

Bad File Descriptor In Recursive Piping Function using Execvp, fork, and pipe

I'm attempting to create a recursive piping function using dup2() , fork() , and pipe() . However, when my array is something like {"ls", "grep shell"} (where shell is the name of my shell), it goes in an endless loop of displaying the results of ls and saying "write error: bad file descriptor". I'm sure that somehow I'm not properly terminating my recursion, and I suspect the issue is with trying to dup either fd[1] or fd[0] , but after debugging this for hours I still can't figure it out. Any help is appreciated!

void recursive_piping(char *recursive_pipe_args[MAX_ARGS]) {
    int i = 0;
    int fd[2];

    char *first_arg[2] = {"", NULL};
    char *rest_of_args[81];

    // if its of size 1, base case
    if (recursive_pipe_args[1] == NULL) {
        if (execvp(recursive_pipe_args[0], recursive_pipe_args) == -1) {
            printf("\nExecute didn't work");
            fflush(stdout); 
        }
        return;
    }

    // recursive case, split args into the first on and the rest of them
    first_arg[0] = recursive_pipe_args[0];
    for (i = 0; i < (num_pipes); i++) {
        rest_of_args[i] = malloc(81);
        strcpy(rest_of_args[i], recursive_pipe_args[i+1]);
    }
    if (pipe(fd) < 0) {
        printf("\npipe Failure");
    }

    // parent section, reads file descriptor fd[0]
    if (fork()) {
        close(fd[0]);
        dup2(fd[1], 0);
        recursive_piping(rest_of_args);
        // return;
    }
    close(fd[1]);
    dup2(fd[0], 1);
    execvp(first_arg[0], first_arg);
}

I prepared a variation of your function with these changes :

  • it adds a check for the first element of recursive_pipe_args being NULL , in which case it emits a diagnostic without executing anything.
  • it counts the number of initial non-NULL elements in the recursive_pipe_args array, and dynamically allocates rest_of_args with that capacity (thus allowing space for one fewer argument plus the NULL sentinel).
  • it copies the tail of recursive_pipe_args into rest_of_args based on the actual count of elements of the former, thus being certain to copy the NULL sentinel.
  • it recognizes and handles errors in fork() .
  • it corrects the duping so that the write end of each pipe ( fd[1] ) is duped onto a standard output (file descriptor 1 ), the read end is duped onto a standard input ( fd[0] and 0 , respectively), and in each process the pipe ends that go unused in that process are closed.
  • it writes error messages to the standard error stream instead of the standard output, relying on perror() for that as much as possible.

The resulting program works as expected for me: it emits the result of the specified pipeline of commands to its standard output. Note well, however, that your design is inherently limited to commands without any arguments, which heavily constrains its utility. My test case was { "ls", "wc" } .

Code implementing those changes is left as an exercise.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM