Adds option to create master/slave pseudoterminals

Creates a master/slave pseudoterminal on behalf users when
creating LPC devices and passing the option autopty: -l com1,autopty

This change enables people to easily access virtual machines
through serial terminal emulators on /dev/ttys* devices created
by xhyve.

When running xhyve with autopty, before booting the guest OS, it
outputs the slave pty device path users can plug into using screen,
minicom or the terminal emulator or their preference.
Ex: screen /dev/ttys003

In order to get a shell on COM2, users need to make sure getty
is invoked on the ttyS* created inside the guest OS. If using
autopty on COM1, getty is automatically invoked in most cases.
This commit is contained in:
Camilo Aguilar 2015-09-23 18:41:58 -04:00
parent cd782515ff
commit a85426bced

View file

@ -90,6 +90,7 @@ struct fifo {
struct ttyfd {
bool opened;
int fd; /* tty device file descriptor */
char *name; /* slave pty name when using autopty*/
struct termios tio_orig, tio_new; /* I/O Terminals */
};
@ -330,11 +331,11 @@ uart_drain(int fd, enum ev_type ev, void *arg)
struct uart_softc *sc;
int ch;
sc = arg;
sc = arg;
assert(fd == sc->tty.fd);
assert(ev == EVF_READ);
/*
* This routine is called in the context of the mevent thread
* to take out the softc lock to protect against concurrent
@ -362,7 +363,7 @@ uart_write(struct uart_softc *sc, int offset, uint8_t value)
uint8_t msr;
pthread_mutex_lock(&sc->mtx);
/*
* Take care of the special case DLAB accesses first
*/
@ -371,7 +372,7 @@ uart_write(struct uart_softc *sc, int offset, uint8_t value)
sc->dll = value;
goto done;
}
if (offset == REG_DLH) {
sc->dlh = value;
goto done;
@ -501,7 +502,7 @@ uart_read(struct uart_softc *sc, int offset)
reg = sc->dll;
goto done;
}
if (offset == REG_DLH) {
reg = sc->dlh;
goto done;
@ -519,7 +520,7 @@ uart_read(struct uart_softc *sc, int offset)
iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0;
intr_reason = (uint8_t) uart_intr_reason(sc);
/*
* Deal with side effects of reading the IIR register
*/
@ -623,7 +624,7 @@ uart_tty_backend(struct uart_softc *sc, const char *opts)
sc->tty.opened = true;
retval = 0;
}
return (retval);
}
@ -631,27 +632,49 @@ int
uart_set_backend(struct uart_softc *sc, const char *opts)
{
int retval;
int ptyfd;
char *ptyname;
retval = -1;
if (opts == NULL)
return (0);
if (strcmp("stdio", opts) == 0) {
if (!uart_stdio) {
sc->tty.fd = STDIN_FILENO;
sc->tty.opened = true;
uart_stdio = true;
retval = 0;
if (strcmp("stdio", opts) == 0 && !uart_stdio) {
sc->tty.fd = STDIN_FILENO;
sc->tty.opened = true;
uart_stdio = true;
retval = fcntl(sc->tty.fd, F_SETFL, O_NONBLOCK);
} else if (strcmp("autopty", opts) == 0) {
if ((ptyfd = open("/dev/ptmx", O_RDWR | O_NONBLOCK)) == -1) {
fprintf(stderr, "error opening /dev/ptmx char device");
return retval;
}
if ((ptyname = ptsname(ptyfd)) == NULL) {
perror("ptsname: error getting name for slave pseudo terminal");
return retval;
}
if ((retval = grantpt(ptyfd)) == -1) {
perror("error setting up ownership and permissions on slave pseudo terminal");
return retval;
}
if ((retval = unlockpt(ptyfd)) == -1) {
perror("error unlocking slave pseudo terminal, to allow its usage");
return retval;
}
fprintf(stdout, "Hook up a terminal emulator to %s in order too access your VM\n", ptyname);
sc->tty.fd = ptyfd;
sc->tty.name = ptyname;
sc->tty.opened = true;
retval = 0;
} else if (uart_tty_backend(sc, opts) == 0) {
retval = 0;
}
/* Make the backend file descriptor non-blocking */
if (retval == 0)
retval = fcntl(sc->tty.fd, F_SETFL, O_NONBLOCK);
if (retval == 0)
uart_opentty(sc);