简体   繁体   中英

Pipe execvp linux command from child to parent process

I try to write a program in C language that takes a simple Linux command in input like "ls /home". This command is executed in child process with "execvp" and sent to the parent process to be displayed on the screen..

My problem is that the program is running and display nothing and don't give back the prompt. I have to quit with "ctrl + C".

Is the problem in the while loop or my pipe send my command nowhere?

Thanks for your feedback

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>

int main(int argc, char* argv[])
{
        int     fd[2];
        int   pid;

        pipe(fd);
        
        if((pid = fork()) == -1)
        {
                perror("fork");
                exit(1);
        }

        if(pid == 0)
        {
                close(fd[0]);

            dup2(fd[1], STDOUT_FILENO);

            close(fd[1]);

            execvp(argv[1], &argv[1]);
        }
        else
        {
                close(fd[1]);

            dup2(fd[0], STDIN_FILENO);
            close(fd[0]);
            char result;
            while(read(fd[0], &result, sizeof(result) > 0))
            {
                write(fd[1], &result, sizeof(result));
            }
            wait(NULL);
        }
    close(fd[1]); 
    close(fd[0]);
    return(0);
}

In the parent , the read loop has problems. Compare

while(read(fd[0], &result, sizeof(result) > 0))

to

while(read(fd[0], &result, sizeof(result)) > 0)

The former, in your program, is using the result of the comparison sizeof(result) > 0 as the size of the buffer, and looping as long as read returns a nonzero value.

Note that result is a char , and sizeof (char) is guaranteed to be 1 .

1 > 0 is 1 , which just happens to be the size of your buffer, so this partially works. The loop will continue on error ( -1 ) though, and will continue to attempt writing output.

It is also trying to read from fd[0] , which was closed after

dup2(fd[0], STDIN_FILENO);
close(fd[0]);

This duplication is not needed.

Additionally,

write(fd[1], &result, sizeof(result));

is attempting to write the output back into the pipe. That said, the parent closed this file descriptor earlier ( close(fd[1]); ).

Note the close(fd[1]); outside of the else block is redundant (and redundant closes can be a source of bugs in more complex programs).


In the child , you should handle the event that execvp fails, because if the function succeeds, it never returns. Anything expected to run after execvp is operating in a failure state (in your program, that is the lines after the else block).


A cursory example:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    int fd[2];
    pid_t pid;

    if (argc < 2) {
        fprintf(stderr, "too few arguments\n");
        exit(EXIT_FAILURE);
    }

    if (-1 == pipe(fd)) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    if (-1 == (pid = fork())) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) {
        /* child */
        close(fd[0]);
        dup2(fd[1], STDOUT_FILENO);
        close(fd[1]);

        argv++;

        execvp(*argv, argv);
        perror("execvp");
        exit(EXIT_FAILURE);
    }

    /* parent */
    char result;

    close(fd[1]);

    while (read(fd[0], &result, 1) > 0)
        write(STDOUT_FILENO, &result, 1);

    close(fd[0]);
    wait(NULL);
}

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