パイプでcat

#include <stdio.h>
#include <errno.h>
#include <unistd.h>

#define MIN(m, n) ((m) < (n) ? (m) : (n))
#define BUFFER_SIZE 512

static int cat(const char *bufin, int inlen, char *bufout, int outlen) {
  int pfd_stdin[2];
  int pfd_stdout[2];
  pid_t pid;
  size_t len = 0;

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

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

  pid = fork();

  if (pid > 0) {
    // parent
    char buf[256];
    size_t n;
    int status;

    close(pfd_stdin[0]);
    close(pfd_stdout[1]);

    if (write(pfd_stdin[1], bufin, inlen) == -1) {
      perror("write");
      exit(1);
    }

    close(pfd_stdin[1]);

    while ((n = read(pfd_stdout[0], buf, 256)) > 0) {
      memcpy(bufout, buf, MIN(n, outlen));
      len += MIN(n, outlen);
      outlen -= n;

      if (outlen <= 0) {
        break;
      }
    }

    close(pfd_stdout[0]);
    bufout[(outlen < 0 ? len - 1 : len)] = '\0';

    if (waitpid(pid, &status, 0) == -1) {
      perror("waitpid");
      exit(1);
    }

    printf("exited, status=%d\n", status);
  } else if (pid == 0) {
    // child
    close(pfd_stdin[1]);
    close(pfd_stdout[0]);

    if (dup2(pfd_stdin[0], STDIN_FILENO) == -1) {
      perror("dup2");
      exit(1);
    }

    if (dup2(pfd_stdout[1], STDOUT_FILENO) == -1) {
      perror("dup2");
      exit(1);
    }

    if (execlp("cat", "cat", NULL) == -1) {
      perror("execlp");
      exit(1);
    }
  } else {
    perror("fork");
    exit(1);
  }

  return len;
}

int main() {
  char *str = "London bridge is falling down";
  char buf[BUFFER_SIZE + 1];
  int len;

  cat(str, strlen(str), buf, BUFFER_SIZE + 1);
  puts(buf);

  return 0;
}


~/work$ gcc foo.c -o foo && ./foo.exe
exited, status=0
London bridge is falling down