xref: /kvmtool/term.c (revision 1add4b76d64864e9b43f0057a21d9b80cd1f6ac1)
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