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

typedef struct pipe {
  int fd;           /* file descriptor from which to read */
  pid_t pid;        /* id of the child process */
} Pipe;

Pipe *make_pipe()
{
  Pipe *p = (Pipe *) malloc (sizeof(Pipe));
  return p;
}

Pipe *open_pipe (char *command, char *name, char *arg)
{
  int n, fd[2];
  pid_t pid;
  FILE *fp;
  Pipe *p = make_pipe();

  if (pipe(fd) < 0) {
    fprintf (stderr, "Unable to open pipe.\n");
    exit(-1);
  }

  if ((pid = fork()) < 0) {
    fprintf (stderr, "Unable to fork.\n");
    exit(-1);

  } else if (pid > 0) {            

    /* parent code*/
    close (fd[1]);                 /* close write end */
    p->fd = fd[0];
    p->pid = pid;
    return p;
  }

  /* child code */
  close (fd[0]);                 /* close read end */

  /* make stdout go to the write end of the pipe */
  if (fd[1] != STDOUT_FILENO) {
    if (dup2 (fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
      fprintf (stderr, "Unable to redirect child's output.\n");
      exit(-1);
    }
  }
  if (execl (command, name, arg, (char *)0) < 0) {
    fprintf (stderr, "Unable to execute command %s %s.\n", name, arg);
    exit(-1);
  }
}

#define BUFFSIZE        8192

int main()
{
  Pipe *p = open_pipe("/bin/ls", "ls", "/etc");
  int n;
  char buf[BUFFSIZE];
  pid_t child;

  while ( (n = read(p->fd, buf, BUFFSIZE)) > 0) {
    if (write(STDOUT_FILENO, buf, n) != n) {
      fprintf (stderr, "Write error.\n");
      exit(-1);
    }
  }

  if (n < 0) {
    fprintf (stderr, "Read error.\n");
    exit(-1);
  }

  child = wait(p->pid);
  if (child < 0) {
    fprintf (stderr, "Wait failed.\n");
    exit(-1);
  }
}

