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> 8*1add4b76SSasha Levin #include <pty.h> 9*1add4b76SSasha 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 17*1add4b76SSasha Levin 18*1add4b76SSasha Levin #define TERM_FD_IN 0 19*1add4b76SSasha Levin #define TERM_FD_OUT 1 20*1add4b76SSasha Levin 215358b0e6SSasha Levin extern struct kvm *kvm; 22b4405289SAsias He static struct termios orig_term; 23b4405289SAsias He 2416588013SAsias He int term_escape_char = 0x01; /* ctrl-a is used for escape */ 2516588013SAsias He bool term_got_escape = false; 2616588013SAsias He 279aa4a0ebSAsias He int active_console; 28b4405289SAsias He 29*1add4b76SSasha Levin int term_fds[4][2]; 30*1add4b76SSasha Levin 31*1add4b76SSasha Levin int term_getc(int who, int term) 32b4405289SAsias He { 33b4405289SAsias He int c; 34b4405289SAsias He 35b4405289SAsias He if (who != active_console) 36b4405289SAsias He return -1; 37b4405289SAsias He 38*1add4b76SSasha Levin if (read_in_full(term_fds[term][TERM_FD_IN], &c, 1) < 0) 39b4405289SAsias He return -1; 4016588013SAsias He 4116588013SAsias He c &= 0xff; 4216588013SAsias He 4316588013SAsias He if (term_got_escape) { 4416588013SAsias He term_got_escape = false; 45c23d9748SSasha Levin if (c == 'x') 46629ad9d3SSasha Levin kvm_cpu__reboot(); 4716588013SAsias He if (c == term_escape_char) 4816588013SAsias He return c; 4916588013SAsias He } 5016588013SAsias He 5116588013SAsias He if (c == term_escape_char) { 5216588013SAsias He term_got_escape = true; 5316588013SAsias He return -1; 5416588013SAsias He } 5516588013SAsias He 56b4405289SAsias He return c; 57b4405289SAsias He } 58b4405289SAsias He 59*1add4b76SSasha Levin int term_putc(int who, char *addr, int cnt, int term) 60b4405289SAsias He { 61*1add4b76SSasha Levin int ret; 62*1add4b76SSasha Levin 63b4405289SAsias He if (who != active_console) 64b4405289SAsias He return -1; 65b4405289SAsias He 66*1add4b76SSasha Levin while (cnt--) { 67*1add4b76SSasha Levin ret = write(term_fds[term][TERM_FD_OUT], addr++, 1); 68*1add4b76SSasha Levin if (ret < 0) 69*1add4b76SSasha Levin return 0; 70*1add4b76SSasha Levin } 71b4405289SAsias He 72b4405289SAsias He return cnt; 73b4405289SAsias He } 74b4405289SAsias He 75*1add4b76SSasha Levin int term_getc_iov(int who, struct iovec *iov, int iovcnt, int term) 76b4405289SAsias He { 7716588013SAsias He int c; 78b4405289SAsias He 7916588013SAsias He if (who != active_console) 8016588013SAsias He return 0; 8116588013SAsias He 82*1add4b76SSasha Levin c = term_getc(who, term); 8316588013SAsias He 8416588013SAsias He if (c < 0) 8516588013SAsias He return 0; 8616588013SAsias He 87*1add4b76SSasha Levin *((int *)iov[TERM_FD_IN].iov_base) = c; 8816588013SAsias He 89fbf15b30SAsias He return sizeof(char); 90b4405289SAsias He } 91b4405289SAsias He 92*1add4b76SSasha Levin int term_putc_iov(int who, struct iovec *iov, int iovcnt, int term) 93b4405289SAsias He { 94b4405289SAsias He if (who != active_console) 9516588013SAsias He return 0; 96b4405289SAsias He 97*1add4b76SSasha Levin return writev(term_fds[term][TERM_FD_OUT], iov, iovcnt); 98b4405289SAsias He } 99b4405289SAsias He 100*1add4b76SSasha Levin bool term_readable(int who, int term) 101b4405289SAsias He { 102b4405289SAsias He struct pollfd pollfd = (struct pollfd) { 103*1add4b76SSasha Levin .fd = term_fds[term][TERM_FD_IN], 104b4405289SAsias He .events = POLLIN, 105b4405289SAsias He .revents = 0, 106b4405289SAsias He }; 107b4405289SAsias He 108b4405289SAsias He if (who != active_console) 109b4405289SAsias He return false; 110b4405289SAsias He 111b4405289SAsias He return poll(&pollfd, 1, 0) > 0; 112b4405289SAsias He } 113b4405289SAsias He 114b4405289SAsias He static void term_cleanup(void) 115b4405289SAsias He { 116*1add4b76SSasha Levin int i; 117*1add4b76SSasha Levin 118*1add4b76SSasha Levin for (i = 0; i < 4; i++) 119*1add4b76SSasha Levin tcsetattr(term_fds[i][TERM_FD_IN], TCSANOW, &orig_term); 120b4405289SAsias He } 121b4405289SAsias He 122f2a0b6a7SAnton Vorontsov static void term_sig_cleanup(int sig) 123f2a0b6a7SAnton Vorontsov { 124f2a0b6a7SAnton Vorontsov term_cleanup(); 125f2a0b6a7SAnton Vorontsov signal(sig, SIG_DFL); 126f2a0b6a7SAnton Vorontsov raise(sig); 127f2a0b6a7SAnton Vorontsov } 128f2a0b6a7SAnton Vorontsov 129*1add4b76SSasha Levin void term_set_tty(int term) 130*1add4b76SSasha Levin { 131*1add4b76SSasha Levin struct termios orig_term; 132*1add4b76SSasha Levin int master, slave; 133*1add4b76SSasha Levin char new_pty[PATH_MAX]; 134*1add4b76SSasha Levin 135*1add4b76SSasha Levin if (tcgetattr(STDIN_FILENO, &orig_term) < 0) 136*1add4b76SSasha Levin die("unable to save initial standard input settings"); 137*1add4b76SSasha Levin 138*1add4b76SSasha Levin orig_term.c_lflag &= ~(ICANON | ECHO | ISIG); 139*1add4b76SSasha Levin 140*1add4b76SSasha Levin if (openpty(&master, &slave, new_pty, &orig_term, NULL) < 0) 141*1add4b76SSasha Levin return; 142*1add4b76SSasha Levin 143*1add4b76SSasha Levin close(slave); 144*1add4b76SSasha Levin 145*1add4b76SSasha Levin pr_info("Assigned terminal %d to pty %s\n", term, new_pty); 146*1add4b76SSasha Levin 147*1add4b76SSasha Levin term_fds[term][TERM_FD_IN] = term_fds[term][TERM_FD_OUT] = master; 148*1add4b76SSasha Levin } 149*1add4b76SSasha Levin 150b4405289SAsias He void term_init(void) 151b4405289SAsias He { 152b4405289SAsias He struct termios term; 153*1add4b76SSasha Levin int i; 154b4405289SAsias He 155b4405289SAsias He if (tcgetattr(STDIN_FILENO, &orig_term) < 0) 156b4405289SAsias He die("unable to save initial standard input settings"); 157b4405289SAsias He 158b4405289SAsias He term = orig_term; 159b4405289SAsias He term.c_lflag &= ~(ICANON | ECHO | ISIG); 160b4405289SAsias He tcsetattr(STDIN_FILENO, TCSANOW, &term); 161b4405289SAsias He 162*1add4b76SSasha Levin for (i = 0; i < 4; i++) 163*1add4b76SSasha Levin if (term_fds[i][TERM_FD_IN] == 0) { 164*1add4b76SSasha Levin term_fds[i][TERM_FD_IN] = STDIN_FILENO; 165*1add4b76SSasha Levin term_fds[i][TERM_FD_OUT] = STDOUT_FILENO; 166*1add4b76SSasha Levin } 167*1add4b76SSasha Levin 168f2a0b6a7SAnton Vorontsov signal(SIGTERM, term_sig_cleanup); 169b4405289SAsias He atexit(term_cleanup); 170b4405289SAsias He } 171