From a85426bced00107e3cd7628c86e0d83840d3f396 Mon Sep 17 00:00:00 2001 From: Camilo Aguilar Date: Wed, 23 Sep 2015 18:41:58 -0400 Subject: [PATCH] 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. --- src/uart_emul.c | 57 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/src/uart_emul.c b/src/uart_emul.c index 73021d0..0d19acb 100644 --- a/src/uart_emul.c +++ b/src/uart_emul.c @@ -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);