Logo  

CS473 - Computer Networks

Displaying exercises/e8a/solution/pty.c

#define _XOPEN_SOURCE 600
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <errno.h>

#define K	1024

int runshell(pid_t *pid, struct termios *tio, struct winsize *ws)
{
  int pty, tty, r;
  char *pts, buf[K];
  fd_set rfds;
  
//   // Get the line attributes from our TTY:
//   if (tcgetattr(STDIN_FILENO, &tio) < 0) {
//     perror("tcgetattr");
//     exit(1);
//   }
//   if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) {
//     perror("window size");
//     exit(2);
//   }
  // Open the master end of the PTY:
  if ((pty = posix_openpt(O_RDWR | O_NOCTTY)) < 0) {
    perror("openpt");
    exit(3);
  }
  // Remaining can probably be done in the child process:
  // Allocate the slave terminal to us:
  if (grantpt(pty) < 0) {
    perror("grantpt");
    exit(4);
  }
  if (unlockpt(pty) < 0) {
    perror("ptsname");
    exit(5);
  }
  if ((pts = ptsname(pty)) == NULL) {
    perror("ptsname");
    exit(6);
  }
  
  *pid = fork();
  if (*pid < 0) return -1;
  if (*pid == 0) {
    // Open the slave PTY:
    if ((tty = open(pts, O_RDWR)) < 0) {
      perror("slave open");
      exit(1);
    }
    dup2(tty, STDIN_FILENO);
    dup2(tty, STDOUT_FILENO);
    dup2(tty, STDERR_FILENO);
    close(tty);
    
    // Set the line attributes (immediately):
    if (tcsetattr(STDIN_FILENO, TCSANOW, tio) < 0) {
      perror("tcsetattr");
    }
    if (ioctl(STDIN_FILENO, TIOCSWINSZ, ws) < 0) {
      perror("set window size");
    }
    execlp("", "arogue", NULL);
    perror("execlp");
    exit(1);
  }
  // In the parent process:
  noecho(&tio);

  while(1) {
    FD_ZERO(&rfds);
    FD_SET(STDIN_FILENO, &rfds);
    FD_SET(pty, &rfds);
    r = select(pty+1, &rfds, NULL, NULL, NULL);
    if (r <= 0) continue;

    if (FD_ISSET(STDIN_FILENO, &rfds)) {
      r = read(STDOUT_FILENO, buf, K);
      if (r < 0) break;
      write(pty, buf, r);
    }
    if (FD_ISSET(pty, &rfds)) {
      r = read(pty, buf, K);
      if (r < 0) break;
      write(STDOUT_FILENO, buf, r);
    }
  }

  echo(&tio);

  exit(0);
}