简体   繁体   中英

Child shell process bidirectional redirection to parent process

Hello stackoverflow I tried to create a program which execute a son shell process and redirect his I/O to a pipe in order to communicate with his father process.

I can execute command via the write pipe (wpipefd) but I can't get the response from the shell process on the read pipe (rpipefd).

I had 3 errors so far according to Strace : First the read function was blocking the program so I made ​​the read fd of the reading pipe non-blocking ( rpipe[0] ). Then I had an EAGAIN error with the read function... Finally I got an EPIPE error when I close the read fd from rpipe ( close(rpipefd[0]) ) in the forked process just after the use of dup2() .

I don't understand what I did wrong. Here's what I did so far :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#define BUF_SIZE 1024

int main(int argc, char **argv)
{
    int rpipefd[2], wpipefd[2], pid;
    pipe(rpipefd);
    pipe(wpipefd);
    char buffer[BUF_SIZE] = {0};

  int flags = fcntl(rpipefd[0], F_GETFL, 0);
    fcntl(rpipefd[0], F_SETFL, flags | O_NONBLOCK);

    pid = fork();
    if(pid == 0)
    {
        close(rpipefd[0]);
        dup2(rpipefd[1],1);
        dup2(rpipefd[1],2);
        close(wpipefd[1]);
        dup2(wpipefd[0],0);
        close(rpipefd[1]);
        close(wpipefd[0]);
        execl("/bin/sh","/bin/sh",NULL);
    }
    close(wpipefd[0]);
    write(wpipefd[1],"echo helloWorld",strlen("echo helloWorld"));
    close(rpipefd[1]);
    read(rpipefd[0],buffer,BUF_SIZE);       
    //perror("read()");
    printf("%s",buffer);


    exit(0);
}

Please help !

The main issue doesn't come from the code itself: the command passed to the shell is incomplete, you missed the final '\\n' and thus the child process (your shell) is waiting for the rest of the command.

The non-blocking part is not a good idea (or at least, you should spin around you pipe in order to retrieve its content.)

Once you're done with your command, you should close the output pipe so the shell get the end-of-file on its input.

Other remarks: you should wait for the child termination (using wait(2)), you should leave after your execl in the child process (use with err(3) for the error message) to handle exec errors. And, seriously, calling strlen on string literal ? I know that gcc is replacing it at compile time, but …

Here is a modified version of your code:

 #include <err.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <sys/wait.h>
 #include <unistd.h>
 #define BUF_SIZE 1024

 int main(int argc, char **argv)
 {
         int rpipefd[2], wpipefd[2], pid;
         pipe(rpipefd);
         pipe(wpipefd);
         char buffer[BUF_SIZE] = {0};

         pid = fork();
         if(pid == 0)
         {
                 close(rpipefd[0]);
                 dup2(rpipefd[1],STDOUT_FILENO);
                 dup2(rpipefd[1],STDERR_FILENO);
                 close(wpipefd[1]);
                 dup2(wpipefd[0],STDIN_FILENO);
                 close(rpipefd[1]);
                 close(wpipefd[0]);
                 execl("/bin/sh","/bin/sh",NULL);
                 err(1, "execl()");
         }
         close(wpipefd[0]);
         close(rpipefd[1]);
         write(wpipefd[1], "echo helloWorld\n", 16);
         close(wpipefd[1]); // we're done, say it to the shell
         int r;
         while ( (r = read(rpipefd[0],buffer,BUF_SIZE)) )
         {
                 if (r == -1)
                 {
                         if (errno == EAGAIN || errno == EINTR) continue;
                         err(1, "read()");
                 }
                 write(STDOUT_FILENO, buffer, r);
         }
         wait(NULL);
         return 0;
 }

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