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