|
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);
}
|