1b4405289SAsias He #include <poll.h> 2b4405289SAsias He #include <stdbool.h> 3b4405289SAsias He #include <termios.h> 4b4405289SAsias He #include <stdio.h> 5b4405289SAsias He #include <unistd.h> 6b4405289SAsias He #include <sys/uio.h> 7f2a0b6a7SAnton Vorontsov #include <signal.h> 81add4b76SSasha Levin #include <pty.h> 91add4b76SSasha Levin #include <utmp.h> 10b4405289SAsias He 11b4405289SAsias He #include "kvm/read-write.h" 12b4405289SAsias He #include "kvm/term.h" 13b4405289SAsias He #include "kvm/util.h" 145358b0e6SSasha Levin #include "kvm/kvm.h" 15629ad9d3SSasha Levin #include "kvm/kvm-cpu.h" 16b4405289SAsias He 171add4b76SSasha Levin #define TERM_FD_IN 0 181add4b76SSasha Levin #define TERM_FD_OUT 1 191add4b76SSasha Levin 205358b0e6SSasha Levin extern struct kvm *kvm; 21b4405289SAsias He static struct termios orig_term; 22b4405289SAsias He 2316588013SAsias He int term_escape_char = 0x01; /* ctrl-a is used for escape */ 2416588013SAsias He bool term_got_escape = false; 2516588013SAsias He 261add4b76SSasha Levin int term_fds[4][2]; 271add4b76SSasha Levin 282651ea58SSasha Levin int term_getc(int term) 29b4405289SAsias He { 30e382487aSMatt Evans unsigned char c; 31b4405289SAsias He 321add4b76SSasha Levin if (read_in_full(term_fds[term][TERM_FD_IN], &c, 1) < 0) 33b4405289SAsias He return -1; 3416588013SAsias He 3516588013SAsias He if (term_got_escape) { 3616588013SAsias He term_got_escape = false; 37c23d9748SSasha Levin if (c == 'x') 38df4239fbSSasha Levin kvm_cpu__reboot(kvm); 3916588013SAsias He if (c == term_escape_char) 4016588013SAsias He return c; 4116588013SAsias He } 4216588013SAsias He 4316588013SAsias He if (c == term_escape_char) { 4416588013SAsias He term_got_escape = true; 4516588013SAsias He return -1; 4616588013SAsias He } 4716588013SAsias He 48b4405289SAsias He return c; 49b4405289SAsias He } 50b4405289SAsias He 512651ea58SSasha Levin int term_putc(char *addr, int cnt, int term) 52b4405289SAsias He { 531add4b76SSasha Levin int ret; 541add4b76SSasha Levin 551add4b76SSasha Levin while (cnt--) { 561add4b76SSasha Levin ret = write(term_fds[term][TERM_FD_OUT], addr++, 1); 571add4b76SSasha Levin if (ret < 0) 581add4b76SSasha Levin return 0; 591add4b76SSasha Levin } 60b4405289SAsias He 61b4405289SAsias He return cnt; 62b4405289SAsias He } 63b4405289SAsias He 642651ea58SSasha Levin int term_getc_iov(struct iovec *iov, int iovcnt, int term) 65b4405289SAsias He { 6616588013SAsias He int c; 67b4405289SAsias He 682651ea58SSasha Levin c = term_getc(term); 6916588013SAsias He 7016588013SAsias He if (c < 0) 7116588013SAsias He return 0; 7216588013SAsias He 73e382487aSMatt Evans *((char *)iov[TERM_FD_IN].iov_base) = (char)c; 7416588013SAsias He 75fbf15b30SAsias He return sizeof(char); 76b4405289SAsias He } 77b4405289SAsias He 782651ea58SSasha Levin int term_putc_iov(struct iovec *iov, int iovcnt, int term) 79b4405289SAsias He { 801add4b76SSasha Levin return writev(term_fds[term][TERM_FD_OUT], iov, iovcnt); 81b4405289SAsias He } 82b4405289SAsias He 832651ea58SSasha Levin bool term_readable(int term) 84b4405289SAsias He { 85b4405289SAsias He struct pollfd pollfd = (struct pollfd) { 861add4b76SSasha Levin .fd = term_fds[term][TERM_FD_IN], 87b4405289SAsias He .events = POLLIN, 88b4405289SAsias He .revents = 0, 89b4405289SAsias He }; 90b4405289SAsias He 91b4405289SAsias He return poll(&pollfd, 1, 0) > 0; 92b4405289SAsias He } 93b4405289SAsias He 94b4405289SAsias He static void term_cleanup(void) 95b4405289SAsias He { 961add4b76SSasha Levin int i; 971add4b76SSasha Levin 981add4b76SSasha Levin for (i = 0; i < 4; i++) 991add4b76SSasha Levin tcsetattr(term_fds[i][TERM_FD_IN], TCSANOW, &orig_term); 100b4405289SAsias He } 101b4405289SAsias He 102f2a0b6a7SAnton Vorontsov static void term_sig_cleanup(int sig) 103f2a0b6a7SAnton Vorontsov { 104f2a0b6a7SAnton Vorontsov term_cleanup(); 105f2a0b6a7SAnton Vorontsov signal(sig, SIG_DFL); 106f2a0b6a7SAnton Vorontsov raise(sig); 107f2a0b6a7SAnton Vorontsov } 108f2a0b6a7SAnton Vorontsov 1091add4b76SSasha Levin void term_set_tty(int term) 1101add4b76SSasha Levin { 1111add4b76SSasha Levin struct termios orig_term; 1121add4b76SSasha Levin int master, slave; 1131add4b76SSasha Levin char new_pty[PATH_MAX]; 1141add4b76SSasha Levin 1151add4b76SSasha Levin if (tcgetattr(STDIN_FILENO, &orig_term) < 0) 1161add4b76SSasha Levin die("unable to save initial standard input settings"); 1171add4b76SSasha Levin 1181add4b76SSasha Levin orig_term.c_lflag &= ~(ICANON | ECHO | ISIG); 1191add4b76SSasha Levin 1201add4b76SSasha Levin if (openpty(&master, &slave, new_pty, &orig_term, NULL) < 0) 1211add4b76SSasha Levin return; 1221add4b76SSasha Levin 1231add4b76SSasha Levin close(slave); 1241add4b76SSasha Levin 1251add4b76SSasha Levin pr_info("Assigned terminal %d to pty %s\n", term, new_pty); 1261add4b76SSasha Levin 1271add4b76SSasha Levin term_fds[term][TERM_FD_IN] = term_fds[term][TERM_FD_OUT] = master; 1281add4b76SSasha Levin } 1291add4b76SSasha Levin 130*dca745e4SSasha Levin int tty_parser(const struct option *opt, const char *arg, int unset) 131*dca745e4SSasha Levin { 132*dca745e4SSasha Levin int tty = atoi(arg); 133*dca745e4SSasha Levin 134*dca745e4SSasha Levin term_set_tty(tty); 135*dca745e4SSasha Levin 136*dca745e4SSasha Levin return 0; 137*dca745e4SSasha Levin } 138*dca745e4SSasha Levin 139*dca745e4SSasha Levin int term_init(struct kvm *kvm) 140b4405289SAsias He { 141b4405289SAsias He struct termios term; 142*dca745e4SSasha Levin int i, r; 143b4405289SAsias He 144*dca745e4SSasha Levin r = tcgetattr(STDIN_FILENO, &orig_term); 145*dca745e4SSasha Levin if (r < 0) { 146*dca745e4SSasha Levin pr_warning("unable to save initial standard input settings"); 147*dca745e4SSasha Levin return r; 148*dca745e4SSasha Levin } 149*dca745e4SSasha Levin 150b4405289SAsias He 151b4405289SAsias He term = orig_term; 152b4405289SAsias He term.c_lflag &= ~(ICANON | ECHO | ISIG); 153b4405289SAsias He tcsetattr(STDIN_FILENO, TCSANOW, &term); 154b4405289SAsias He 1551add4b76SSasha Levin for (i = 0; i < 4; i++) 1561add4b76SSasha Levin if (term_fds[i][TERM_FD_IN] == 0) { 1571add4b76SSasha Levin term_fds[i][TERM_FD_IN] = STDIN_FILENO; 1581add4b76SSasha Levin term_fds[i][TERM_FD_OUT] = STDOUT_FILENO; 1591add4b76SSasha Levin } 1601add4b76SSasha Levin 161f2a0b6a7SAnton Vorontsov signal(SIGTERM, term_sig_cleanup); 162b4405289SAsias He atexit(term_cleanup); 163*dca745e4SSasha Levin 164*dca745e4SSasha Levin return 0; 165*dca745e4SSasha Levin } 166*dca745e4SSasha Levin 167*dca745e4SSasha Levin int term_exit(struct kvm *kvm) 168*dca745e4SSasha Levin { 169*dca745e4SSasha Levin return 0; 170b4405289SAsias He } 171