Home > Net >  c pipe ls returned strings to parent
c pipe ls returned strings to parent

Time:03-31

I'm currently trying to run an ls command in my C code and then pipe the outputted strings to the parent process via a fd.

The problem I'm currently facing is, that I execv the ls command but I don't know how to store the strings (if that is even necessary) and then pipe them to my parent process and execute another command with the given input like I wrote in the comment. Is there also a way to block the ls output to the terminal in my child process?

int main(void)
{

   int fd1[2]; // Used to store two ends of first pipe
   int fd2[2]; // Used to store two ends of second pipe

   pid_t p;

   p = fork(); // Now forking to create a child

   // Parent process
   else if (p > 0)
   {    
      close(fd1[0]); // Close reading end of first pipe

      // Wait for child to send the strings
      wait(NULL);

      close(fd2[1]); // Close writing end of second pipe

      // Read strings from child, print it and close
      // reading end.
      read(fd2[0], "", 100);
      close(fd2[0]);
      // todo another command like "wc -l" and print the result to the terminal with write 

   }
   // Child process
   else
   {
      close(fd1[1]); // Close writing end of first pipe

      // execute ls command and send the strings to the parent
      int status;
      char *args[2];

      args[0] = "/bin/ls";        // first arg is the full path to the executable
      args[1] = NULL;             // list of args must be NULL terminated

      execv( args[0], args );     // child: call execv with the path and the args
      
      // Close both reading ends
      close(fd1[0]);
      close(fd2[0]);

      // write the strings to the parent
      write(fd2[1], "", strlen("")   1);
      close(fd2[1]);

      exit(0);
   }

   return EXIT_SUCCESS;
}

I'm sorry if this is a silly question, but I'm very new to forking and using pipes.

CodePudding user response:

To start, must call pipe on an int [2] to create a pipe. You have not done this.


In the parent process:

This read call

read(fd2[0], "", 100);

does not make sense. "" is a read-only, char [1]. Trying to store data in it will invoke Undefined Behavior.

You need a reasonably sized buffer (array) to store the data you read in. Additionally, you should check if any data was actually read by testing the return value of read, which is the number of bytes read.

Remember that this data is not null terminated - it is raw bytes, not a string. If you want to treat it as a string, you need to null terminate the buffer manually (make sure to leave room).


In the child process:

To redirect the standard output of ls to be the write end of the pipe, instead of the terminal, dup2 is used:

dup2 makes the file descriptor specified by its second argument refer to the same file description as its first argument.

The code after execv makes little sense, as execv never returns if it succeeds. You should close any unnecessary file descriptors before this point, and only handle failure states afterwards.


A cursory example of all this.

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

int main(void) {
    int my_pipe[2];

    if (pipe(my_pipe)) {
        perror("pipe");
        return 1;
    }

    if (fork()) {
        ssize_t bytes;
        char buffer[512];

        close(my_pipe[1]);

        while ((bytes = read(my_pipe[0], buffer, sizeof buffer - 1)) > 0) {
            buffer[bytes] = 0;
            printf("Parent got:\n%s\n", buffer);
        }

        close(my_pipe[0]);

        wait(NULL);
    } else {
        char *args[] = {
            "/bin/ls",
            NULL
        };

        close(my_pipe[0]);
        dup2(my_pipe[1], fileno(stdout));
        close(my_pipe[1]);

        execv(args[0], args);

        /* we only get here if execv fails */
        perror("execv");
    }
}
  • Related