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

#define BUFFSIZE 512

char *program;

void cperror(char *func) {
  char buf[BUFFSIZE];
  snprintf(buf, BUFFSIZE, "%s: %s", program, func);
  perror(buf);
}

int err_do(int i, char* s) {
  if (!i) {
    cperror(s);
    exit(1);
  }
}

int main(int argc, char**argv, char**env) {
  int ptm, pts;
  int rbytes;
  int tbytes = 0;
  int status;
  pid_t child, pwait;
  char buf[BUFFSIZE];

  program = argv[0];

  err_do((ptm = posix_openpt(O_RDWR | O_NONBLOCK)) > -1, "openpt");
  err_do(!grantpt(ptm), "grantpt");
  err_do(!unlockpt(ptm), "unlockpt");
  err_do(!ptsname_r(ptm, buf, BUFFSIZE), "ptsname");
  err_do((pts = open(buf, O_RDWR)) > -1, "open");

  if (child = fork()) {
    while (rbytes = read(ptm, buf, BUFFSIZE)) {
      if (rbytes < 0) {
        if (errno == EAGAIN) {
          // check if child exited
          pwait = waitpid(child, &rbytes, WNOHANG);
          if (pwait < 0) { // something bogus
            cperror("waitpid");
            exit(1);
          }
          if (pwait) { // something changed
            if (WIFEXITED(rbytes)) { // child done
              break;
            }
          }
          continue;
        } else {
          cperror("read");
          exit(1);
        }
      }
      tbytes += rbytes;
      write(1, buf, rbytes);
    }
  } else {
    dup2(pts, 1);
    argv++;
    execvp(argv[0], argv);
  }
  return 0;
}
