0

I've been trying to write a program that will send and receive commands to a bash shell (/bin/sh). Like a wrapper program around a bash shell. So, I could write to stdin "cd ~/Desktop", then write again "ls" and I will receive a listing of the files on the desktop. I can't get it working though. On the second write command in this code, it will echo back whatever I wrote to stdin. I've also tried using popen() but that only provides output, not allowing me to write to stdin. Could someone please help solve this problem? Thanks

void main()
{
    // Create a pipe and fork
    //
    int fd[2];
    int p = pipe(fd);
    pid_t pid = fork();

    if (pid > 0)
    {
        // Read from the pipe and output the result
        //
        //close(fd[1]);
        char buf[1024] = { 0 };

        read(fd[0], buf, sizeof(buf));

        printf("1 - %s\n", buf);

        write (fd[1], "ifconfig", strlen ("ifconfig") );

        // problem is here, read is returning echo'd bytes from write()

        read(fd[0], buf, sizeof(buf));

        printf("2 - %s\n", buf);    


        // Wait for child to terminate
        int status;
        wait(&status);
    }
    else if (pid == 0)
    {
        // Redirect stdout and stderr to the pipe and execute the shell
        // command
        //
        dup2(fd[0], STDIN_FILENO);
        dup2(fd[1], STDOUT_FILENO);
        dup2(fd[1], STDERR_FILENO);
        //close(fd[0]);
        execl("/bin/sh", "exec sh", "-c", "ls", (char*) NULL );
    }

}

EDIT - Updated code per 1st answer, now there is no output from the 2nd read() call

void main()
{
    // Create a pipe and fork
    //
    int fd[2];

int ChildToParent[2], ParentToChild[2];



    pipe (ParentToChild);
pipe (ChildToParent);

    pid_t pid = fork();

    if (pid > 0)
    {
        // In parent process

        // Read the output of the child from child_to_parent[0]
        // We don't need child_to_parent[1] so close it
        close(ChildToParent[1]);

        // Write output to the child using parent_to_child[1]
        // We don't need parent_to_child[0] so close it
        close(ParentToChild[0]);

        // Read from and write to the child process...
        char buf[1024] = { 0 };

        read(ChildToParent[0], buf, sizeof(buf));   
    printf("1 - %s\n", buf);


    write(ParentToChild[1], "whoami", strlen ("whoami") );

    memset (buf, 0, 1024);

    // this call to read returns nothing
    read(ChildToParent[0], buf, sizeof(buf));
    printf("2 - %s\n", buf);



    }
    else if (pid == 0)
    {
        // Redirect stdout and stderr to the pipe and execute the shell
        // command
        //
    // child_to_parent[1] is were we write output, it's the
        // new standard output, child_to_parent[0] can be closed
        dup2 (ChildToParent[1], STDOUT_FILENO);
        close(ChildToParent[0]);

        // parent_to_child[0] is where we read input from, it's the
        // new standard input, parent_to_child[1] can be closed
        dup2 (ParentToChild[0], STDIN_FILENO);
        close(ParentToChild[1]);

        //close(fd[0]);
        execl("/bin/sh", "exec sh", "-c", "ls", (char*) NULL );
    }

}

  • You need two pipes: One for the parent process to write to and the child process to read from, and another pipe for the opposite direction. – Some programmer dude Sep 08 '16 at 16:12
  • Isn't that what "dup2(fd[0], STDIN_FILENO); dup2(fd[1], STDOUT_FILENO);" is for? Can you explain what you're talking about in code. – shelly3783 Sep 08 '16 at 16:15

1 Answers1

2

Remember that pipes are a one-way communication stream. You can't use it for two-way communication between two processes. For that you need two pipes, one in each direction.

Perhaps something like this simple example:

// Pipe for the child process to write to the parent process
int child_to_parent[2];

// Pipe for the parent process to write to the child process
int parent_to_child[2];

// Create the TWO pipes
pipe(child_to_parent);
pipe(parent_to_child);

pid_t pid = fork();
if (pid > 0)
{
    // In parent process

    // Read the output of the child from child_to_parent[0]
    // We don't need child_to_parent[1] so close it
    close(child_to_parent[1]);

    // Write output to the child using parent_to_child[1]
    // We don't need parent_to_child[0] so close it
    close(parent_to_child[0]);

    // Read from and write to the child process...
}
else if (pid == 0)
{
    // In child process

    // child_to_parent[1] is were we write output, it's the
    // new standard output, child_to_parent[0] can be closed
    dup2(child_to_parent[1], STDOUT_FILENO);
    close(child_to_parent[0]);

    // parent_to_child[0] is where we read input from, it's the
    // new standard input, parent_to_child[1] can be closed
    dup2(parent_to_child[0], STDIN_FILENO);
    close(parent_to_child[1]);

    // Do whatever the child is supposed to do
}
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Hmm, I'm going to try this but all you did was add to calls to close() from my original code. Sorry but this is still a bit unclear, especially as this won't compile but I'll try it... – shelly3783 Sep 08 '16 at 16:30
  • Could you please specify where exactly I'm supposed to read() and write() from? – shelly3783 Sep 08 '16 at 16:31
  • @shelly3783 Count the number of pipes in my example, compared to your code... And you did read the comments? Noticed the two different variables for the pipes? – Some programmer dude Sep 08 '16 at 16:36
  • yes with that edit I can now see the difference, thank you I am trying it. – shelly3783 Sep 08 '16 at 16:46
  • Still not working, I'm going to update the original code – shelly3783 Sep 08 '16 at 16:56
  • The arguments are being passed to stdin on /bin/sh via the command line, this method does not work to write to stdin of the child process sh. Perhaps in other situations it may, but for /bin/sh it does not. – shelly3783 Sep 08 '16 at 17:32
  • I've solved the problem, the pipes need to be opened & closed a bit differently than how you mention, and execv(), not exec(), needs to be used. The code in this link works for /bin/sh - https://jineshkj.wordpress.com/2006/12/22/how-to-capture-stdin-stdout-and-stderr-of-child-program/ - you may want to edit your information as not to spread confusion – shelly3783 Sep 08 '16 at 17:59