1 /*
2  *  Copyright (C) International Business Machines  Corp., 2005
3  *  Author(s): Anthony Liguori <aliguori@us.ibm.com>
4  *
5  *  Xen Console Daemon
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; under version 2 of the License.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #define _GNU_SOURCE
21 
22 #include "utils.h"
23 #include "io.h"
24 #include <xenevtchn.h>
25 #include <xengnttab.h>
26 #include <xenstore.h>
27 #include <xen/io/console.h>
28 #include <xen/grant_table.h>
29 
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <poll.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <termios.h>
37 #include <stdarg.h>
38 #include <sys/mman.h>
39 #include <time.h>
40 #include <assert.h>
41 #include <sys/types.h>
42 #if defined(__NetBSD__) || defined(__OpenBSD__)
43 #include <util.h>
44 #elif defined(__linux__)
45 #include <pty.h>
46 #elif defined(__sun__)
47 #include <stropts.h>
48 #elif defined(__FreeBSD__)
49 #include <sys/ioctl.h>
50 #include <libutil.h>
51 #endif
52 
53 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
54 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
55 
56 /* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */
57 #define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2)
58 
59 /* How many events are allowed in each time period */
60 #define RATE_LIMIT_ALLOWANCE 30
61 /* Duration of each time period in ms */
62 #define RATE_LIMIT_PERIOD 200
63 
64 extern int log_reload;
65 extern int log_guest;
66 extern int log_hv;
67 extern int log_time_hv;
68 extern int log_time_guest;
69 extern char *log_dir;
70 extern int discard_overflowed_data;
71 extern int replace_escape;
72 
73 static int log_time_hv_needts = 1;
74 static int log_time_guest_needts = 1;
75 static int log_hv_fd = -1;
76 
77 static xengnttab_handle *xgt_handle = NULL;
78 
79 static struct pollfd  *fds;
80 static unsigned int current_array_size;
81 static unsigned int nr_fds;
82 
83 #define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1))
84 
85 struct buffer {
86 	char *data;
87 	size_t consumed;
88 	size_t size;
89 	size_t capacity;
90 	size_t max_capacity;
91 };
92 
93 struct console {
94 	char *ttyname;
95 	int master_fd;
96 	int master_pollfd_idx;
97 	int slave_fd;
98 	int log_fd;
99 	struct buffer buffer;
100 	char *xspath;
101 	char *log_suffix;
102 	int ring_ref;
103 	xenevtchn_handle *xce_handle;
104 	int xce_pollfd_idx;
105 	int event_count;
106 	long long next_period;
107 	xenevtchn_port_or_error_t local_port;
108 	xenevtchn_port_or_error_t remote_port;
109 	struct xencons_interface *interface;
110 	struct domain *d;
111 	bool optional;
112 	bool use_gnttab;
113 };
114 
115 struct console_type {
116 	char *xsname;
117 	char *ttyname;
118 	char *log_suffix;
119 	bool optional;
120 	bool use_gnttab;
121 };
122 
123 static struct console_type console_type[] = {
124 	{
125 		.xsname = "/console",
126 		.ttyname = "tty",
127 		.log_suffix = "",
128 		.optional = false,
129 		.use_gnttab = true,
130 	},
131 #if defined(CONFIG_ARM)
132 	{
133 		.xsname = "/vuart/0",
134 		.ttyname = "tty",
135 		.log_suffix = "-vuart0",
136 		.optional = true,
137 		.use_gnttab = false,
138 	},
139 #endif
140 };
141 
142 #define NUM_CONSOLE_TYPE (sizeof(console_type)/sizeof(struct console_type))
143 
144 struct domain {
145 	int domid;
146 	bool is_dead;
147 	unsigned last_seen;
148 	struct domain *next;
149 	struct console console[NUM_CONSOLE_TYPE];
150 };
151 
152 static struct domain *dom_head;
153 
154 typedef void (*VOID_ITER_FUNC_ARG1)(struct console *);
155 typedef int (*INT_ITER_FUNC_ARG1)(struct console *);
156 typedef void (*VOID_ITER_FUNC_ARG2)(struct console *,  void *);
157 typedef int (*INT_ITER_FUNC_ARG3)(struct console *,
158 				  struct domain *dom, void **);
159 
console_enabled(struct console * con)160 static inline bool console_enabled(struct console *con)
161 {
162 	return con->local_port != -1;
163 }
164 
console_iter_void_arg1(struct domain * d,VOID_ITER_FUNC_ARG1 iter_func)165 static inline void console_iter_void_arg1(struct domain *d,
166 					  VOID_ITER_FUNC_ARG1 iter_func)
167 {
168 	unsigned int i;
169 	struct console *con = &d->console[0];
170 
171 	for (i = 0; i < NUM_CONSOLE_TYPE; i++, con++) {
172 		iter_func(con);
173 	}
174 }
175 
console_iter_void_arg2(struct domain * d,VOID_ITER_FUNC_ARG2 iter_func,void * iter_data)176 static inline void console_iter_void_arg2(struct domain *d,
177 					  VOID_ITER_FUNC_ARG2 iter_func,
178 					  void *iter_data)
179 {
180 	unsigned int i;
181 	struct console *con = &d->console[0];
182 
183 	for (i = 0; i < NUM_CONSOLE_TYPE; i++, con++) {
184 		iter_func(con, iter_data);
185 	}
186 }
187 
console_iter_int_arg1(struct domain * d,INT_ITER_FUNC_ARG1 iter_func)188 static inline int console_iter_int_arg1(struct domain *d,
189 					INT_ITER_FUNC_ARG1 iter_func)
190 {
191 	unsigned int i;
192 	int ret;
193 	struct console *con = &d->console[0];
194 
195 	for (i = 0; i < NUM_CONSOLE_TYPE; i++, con++) {
196 		/*
197 		 * Zero return values means success.
198 		 *
199 		 * Non-zero return value indicates an error in which
200 		 * case terminate the loop.
201 		 */
202 		ret = iter_func(con);
203 		if (ret)
204 			break;
205 	}
206 	return ret;
207 }
208 
console_iter_int_arg3(struct domain * d,INT_ITER_FUNC_ARG3 iter_func,void ** iter_data)209 static inline int console_iter_int_arg3(struct domain *d,
210 					INT_ITER_FUNC_ARG3 iter_func,
211 					void **iter_data)
212 {
213 	unsigned int i;
214 	int ret;
215 	struct console *con = &d->console[0];
216 
217 	for (i = 0; i < NUM_CONSOLE_TYPE; i++, con++) {
218 		/*
219 		 * Zero return values means success.
220 		 *
221 		 * Non-zero return value indicates an error in which
222 		 * case terminate the loop.
223 		 */
224 		ret = iter_func(con, d, iter_data);
225 		if (ret)
226 			break;
227 	}
228 	return ret;
229 }
230 
do_replace_escape(const char * src,char * dest,int len)231 static void do_replace_escape(const char *src, char *dest, int len)
232 {
233 	int i;
234 
235 	for (i = 0; i < len; i++) {
236 		if (src[i] == '\033')
237 			dest[i] = '.';
238 		else
239 			dest[i] = src[i];
240 	}
241 }
242 
write_all(int fd,const char * buf,size_t len)243 static int write_all(int fd, const char* buf, size_t len)
244 {
245 	while (len) {
246 		ssize_t ret;
247 		if (replace_escape) {
248 			char buf_replaced[1024];
249 			size_t this_round;
250 
251 			if (len > sizeof(buf_replaced))
252 				this_round = sizeof(buf_replaced);
253 			else
254 				this_round = len;
255 			do_replace_escape(buf, buf_replaced, this_round);
256 			ret = write(fd, buf_replaced, this_round);
257 		} else
258 			ret = write(fd, buf, len);
259 		if (ret == -1 && errno == EINTR)
260 			continue;
261 		if (ret <= 0)
262 			return -1;
263 		len -= ret;
264 		buf += ret;
265 	}
266 
267 	return 0;
268 }
269 
write_with_timestamp(int fd,const char * data,size_t sz,int * needts)270 static int write_with_timestamp(int fd, const char *data, size_t sz,
271 				int *needts)
272 {
273 	char ts[32];
274 	time_t now = time(NULL);
275 	const struct tm *tmnow = localtime(&now);
276 	size_t tslen = strftime(ts, sizeof(ts), "[%Y-%m-%d %H:%M:%S] ", tmnow);
277 	const char *last_byte = data + sz - 1;
278 
279 	while (data <= last_byte) {
280 		const char *nl = memchr(data, '\n', last_byte + 1 - data);
281 		int found_nl = (nl != NULL);
282 		if (!found_nl)
283 			nl = last_byte;
284 
285 		if ((*needts && write_all(fd, ts, tslen))
286 		    || write_all(fd, data, nl + 1 - data))
287 			return -1;
288 
289 		*needts = found_nl;
290 		data = nl + 1;
291 		if (found_nl) {
292 			// If we printed a newline, strip all \r following it
293 			while (data <= last_byte && *data == '\r')
294 				data++;
295 		}
296 	}
297 
298 	return 0;
299 }
300 
buffer_available(struct console * con)301 static inline bool buffer_available(struct console *con)
302 {
303 	if (discard_overflowed_data ||
304 	    !con->buffer.max_capacity ||
305 	    con->buffer.size < con->buffer.max_capacity)
306 		return true;
307 	else
308 		return false;
309 }
310 
buffer_append(struct console * con)311 static void buffer_append(struct console *con)
312 {
313 	struct buffer *buffer = &con->buffer;
314 	struct domain *dom = con->d;
315 	XENCONS_RING_IDX cons, prod, size;
316 	struct xencons_interface *intf = con->interface;
317 
318 	cons = intf->out_cons;
319 	prod = intf->out_prod;
320 	xen_mb();
321 
322 	size = prod - cons;
323 	if ((size == 0) || (size > sizeof(intf->out)))
324 		return;
325 
326 	if ((buffer->capacity - buffer->size) < size) {
327 		buffer->capacity += (size + 1024);
328 		buffer->data = realloc(buffer->data, buffer->capacity);
329 		if (buffer->data == NULL) {
330 			dolog(LOG_ERR, "Memory allocation failed");
331 			exit(ENOMEM);
332 		}
333 	}
334 
335 	while (cons != prod)
336 		buffer->data[buffer->size++] = intf->out[
337 			MASK_XENCONS_IDX(cons++, intf->out)];
338 
339 	xen_mb();
340 	intf->out_cons = cons;
341 	xenevtchn_notify(con->xce_handle, con->local_port);
342 
343 	/* Get the data to the logfile as early as possible because if
344 	 * no one is listening on the console pty then it will fill up
345 	 * and handle_tty_write will stop being called.
346 	 */
347 	if (con->log_fd != -1) {
348 		int logret;
349 		if (log_time_guest) {
350 			logret = write_with_timestamp(
351 				con->log_fd,
352 				buffer->data + buffer->size - size,
353 				size, &log_time_guest_needts);
354 		} else {
355 			logret = write_all(
356 				con->log_fd,
357 				buffer->data + buffer->size - size,
358 				size);
359 		}
360 		if (logret < 0)
361 			dolog(LOG_ERR, "Write to log failed "
362 			      "on domain %d: %d (%s)\n",
363 			      dom->domid, errno, strerror(errno));
364 	}
365 
366 	if (discard_overflowed_data && buffer->max_capacity &&
367 	    buffer->size > 5 * buffer->max_capacity / 4) {
368 		if (buffer->consumed > buffer->max_capacity / 4) {
369 			/* Move data up in buffer, since beginning has
370 			 * been output.  Only needed because buffer is
371 			 * not a ring buffer *sigh* */
372 			memmove(buffer->data,
373 				buffer->data + buffer->consumed,
374 				buffer->size - buffer->consumed);
375 			buffer->size -= buffer->consumed;
376 			buffer->consumed = 0;
377 		} else {
378 			/* Discard the middle of the data. */
379 			size_t over = buffer->size - buffer->max_capacity;
380 
381 			memmove(buffer->data + buffer->max_capacity / 2,
382 				buffer->data + buffer->max_capacity,
383 				over);
384 			buffer->size = buffer->max_capacity / 2 + over;
385 		}
386 	}
387 }
388 
buffer_empty(struct buffer * buffer)389 static bool buffer_empty(struct buffer *buffer)
390 {
391 	return buffer->size == 0;
392 }
393 
buffer_advance(struct buffer * buffer,size_t len)394 static void buffer_advance(struct buffer *buffer, size_t len)
395 {
396 	buffer->consumed += len;
397 	if (buffer->consumed == buffer->size) {
398 		buffer->consumed = 0;
399 		buffer->size = 0;
400 		if (buffer->max_capacity &&
401 		    buffer->capacity > buffer->max_capacity) {
402 			buffer->data = realloc(buffer->data, buffer->max_capacity);
403 			buffer->capacity = buffer->max_capacity;
404 		}
405 	}
406 }
407 
domain_is_valid(int domid)408 static bool domain_is_valid(int domid)
409 {
410 	bool ret;
411 	xc_dominfo_t info;
412 
413 	ret = (xc_domain_getinfo(xc, domid, 1, &info) == 1 &&
414 	       info.domid == domid);
415 
416 	return ret;
417 }
418 
create_hv_log(void)419 static int create_hv_log(void)
420 {
421 	char logfile[PATH_MAX];
422 	int fd;
423 	snprintf(logfile, PATH_MAX-1, "%s/hypervisor.log", log_dir);
424 	logfile[PATH_MAX-1] = '\0';
425 
426 	fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644);
427 	if (fd == -1)
428 		dolog(LOG_ERR, "Failed to open log %s: %d (%s)",
429 		      logfile, errno, strerror(errno));
430 	if (fd != -1 && log_time_hv) {
431 		if (write_with_timestamp(fd, "Logfile Opened\n",
432 					 strlen("Logfile Opened\n"),
433 					 &log_time_hv_needts) < 0) {
434 			dolog(LOG_ERR, "Failed to log opening timestamp "
435 				       "in %s: %d (%s)", logfile, errno,
436 				       strerror(errno));
437 			close(fd);
438 			return -1;
439 		}
440 	}
441 	return fd;
442 }
443 
create_console_log(struct console * con)444 static int create_console_log(struct console *con)
445 {
446 	char logfile[PATH_MAX];
447 	char *namepath, *data, *s;
448 	int fd;
449 	unsigned int len;
450 	struct domain *dom = con->d;
451 
452 	namepath = xs_get_domain_path(xs, dom->domid);
453 	s = realloc(namepath, strlen(namepath) + 6);
454 	if (s == NULL) {
455 		free(namepath);
456 		return -1;
457 	}
458 	namepath = s;
459 	strcat(namepath, "/name");
460 	data = xs_read(xs, XBT_NULL, namepath, &len);
461 	free(namepath);
462 	if (!data)
463 		return -1;
464 	if (!len) {
465 		free(data);
466 		return -1;
467 	}
468 
469 	snprintf(logfile, PATH_MAX-1, "%s/guest-%s%s.log",
470 		 log_dir, data, con->log_suffix);
471 
472 	free(data);
473 	logfile[PATH_MAX-1] = '\0';
474 
475 	fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644);
476 	if (fd == -1)
477 		dolog(LOG_ERR, "Failed to open log %s: %d (%s)",
478 		      logfile, errno, strerror(errno));
479 	if (fd != -1 && log_time_guest) {
480 		if (write_with_timestamp(fd, "Logfile Opened\n",
481 					 strlen("Logfile Opened\n"),
482 					 &log_time_guest_needts) < 0) {
483 			dolog(LOG_ERR, "Failed to log opening timestamp "
484 				       "in %s: %d (%s)", logfile, errno,
485 				       strerror(errno));
486 			close(fd);
487 			return -1;
488 		}
489 	}
490 	return fd;
491 }
492 
console_close_tty(struct console * con)493 static void console_close_tty(struct console *con)
494 {
495 	if (con->master_fd != -1) {
496 		close(con->master_fd);
497 		con->master_fd = -1;
498 	}
499 
500 	if (con->slave_fd != -1) {
501 		close(con->slave_fd);
502 		con->slave_fd = -1;
503 	}
504 }
505 
506 #ifdef __sun__
openpty(int * amaster,int * aslave,char * name,struct termios * termp,struct winsize * winp)507 static int openpty(int *amaster, int *aslave, char *name,
508 		   struct termios *termp, struct winsize *winp)
509 {
510 	const char *slave;
511 	int mfd = -1, sfd = -1;
512 
513 	*amaster = *aslave = -1;
514 
515 	mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
516 	if (mfd < 0)
517 		goto err;
518 
519 	if (grantpt(mfd) == -1 || unlockpt(mfd) == -1)
520 		goto err;
521 
522 	if ((slave = ptsname(mfd)) == NULL)
523 		goto err;
524 
525 	if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1)
526 		goto err;
527 
528 	if (ioctl(sfd, I_PUSH, "ptem") == -1)
529 		goto err;
530 
531 	if (amaster)
532 		*amaster = mfd;
533 	if (aslave)
534 		*aslave = sfd;
535 	if (winp)
536 		ioctl(sfd, TIOCSWINSZ, winp);
537 
538 	if (termp)
539 		tcsetattr(sfd, TCSAFLUSH, termp);
540 
541 	assert(name == NULL);
542 
543 	return 0;
544 
545 err:
546 	if (sfd != -1)
547 		close(sfd);
548 	close(mfd);
549 	return -1;
550 }
551 
cfmakeraw(struct termios * termios_p)552 void cfmakeraw(struct termios *termios_p)
553 {
554 	termios_p->c_iflag &=
555 	    ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
556 	termios_p->c_oflag &= ~OPOST;
557 	termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
558 	termios_p->c_cflag &= ~(CSIZE|PARENB);
559 	termios_p->c_cflag |= CS8;
560 
561 	termios_p->c_cc[VMIN] = 0;
562 	termios_p->c_cc[VTIME] = 0;
563 }
564 #endif /* __sun__ */
565 
console_create_tty(struct console * con)566 static int console_create_tty(struct console *con)
567 {
568 	const char *slave;
569 	char *path;
570 	int err;
571 	bool success;
572 	char *data;
573 	unsigned int len;
574 	struct termios term;
575 	struct domain *dom = con->d;
576 
577 	assert(con->slave_fd == -1);
578 	assert(con->master_fd == -1);
579 
580 	if (openpty(&con->master_fd, &con->slave_fd, NULL, NULL, NULL) < 0) {
581 		err = errno;
582 		dolog(LOG_ERR, "Failed to create tty for domain-%d "
583 		      "(errno = %i, %s)",
584 		      dom->domid, err, strerror(err));
585 		return 0;
586 	}
587 
588 	if (tcgetattr(con->slave_fd, &term) < 0) {
589 		err = errno;
590 		dolog(LOG_ERR, "Failed to get tty attributes for domain-%d "
591 			"(errno = %i, %s)",
592 			dom->domid, err, strerror(err));
593 		goto out;
594 	}
595 	cfmakeraw(&term);
596 	if (tcsetattr(con->slave_fd, TCSANOW, &term) < 0) {
597 		err = errno;
598 		dolog(LOG_ERR, "Failed to set tty attributes for domain-%d "
599 			"(errno = %i, %s)",
600 			dom->domid, err, strerror(err));
601 		goto out;
602 	}
603 
604 	if ((slave = ptsname(con->master_fd)) == NULL) {
605 		err = errno;
606 		dolog(LOG_ERR, "Failed to get slave name for domain-%d "
607 		      "(errno = %i, %s)",
608 		      dom->domid, err, strerror(err));
609 		goto out;
610 	}
611 
612 	success = asprintf(&path, "%s/limit", con->xspath) !=
613 		-1;
614 	if (!success)
615 		goto out;
616 	data = xs_read(xs, XBT_NULL, path, &len);
617 	if (data) {
618 		con->buffer.max_capacity = strtoul(data, 0, 0);
619 		free(data);
620 	}
621 	free(path);
622 
623 	success = (asprintf(&path, "%s/%s", con->xspath, con->ttyname) != -1);
624 	if (!success)
625 		goto out;
626 	success = xs_write(xs, XBT_NULL, path, slave, strlen(slave));
627 	free(path);
628 	if (!success)
629 		goto out;
630 
631 	if (fcntl(con->master_fd, F_SETFL, O_NONBLOCK) == -1)
632 		goto out;
633 
634 	return 1;
635 out:
636 	console_close_tty(con);
637 	return 0;
638 }
639 
640 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
xs_gather(struct xs_handle * xs,const char * dir,...)641 static int xs_gather(struct xs_handle *xs, const char *dir, ...)
642 {
643 	va_list ap;
644 	const char *name;
645 	char *path;
646 	int ret = 0;
647 
648 	va_start(ap, dir);
649 	while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
650 		const char *fmt = va_arg(ap, char *);
651 		void *result = va_arg(ap, void *);
652 		char *p;
653 
654 		if (asprintf(&path, "%s/%s", dir, name) == -1) {
655 			ret = ENOMEM;
656 			break;
657 		}
658 		p = xs_read(xs, XBT_NULL, path, NULL);
659 		free(path);
660 		if (p == NULL) {
661 			ret = ENOENT;
662 			break;
663 		}
664 		if (fmt) {
665 			if (sscanf(p, fmt, result) == 0)
666 				ret = EINVAL;
667 			free(p);
668 		} else
669 			*(char **)result = p;
670 	}
671 	va_end(ap);
672 	return ret;
673 }
674 
console_unmap_interface(struct console * con)675 static void console_unmap_interface(struct console *con)
676 {
677 	if (con->interface == NULL)
678 		return;
679 	if (xgt_handle && con->ring_ref == -1)
680 		xengnttab_unmap(xgt_handle, con->interface, 1);
681 	else
682 		munmap(con->interface, XC_PAGE_SIZE);
683 	con->interface = NULL;
684 	con->ring_ref = -1;
685 }
686 
console_create_ring(struct console * con)687 static int console_create_ring(struct console *con)
688 {
689 	int err, remote_port, ring_ref, rc;
690 	char *type, path[PATH_MAX];
691 	struct domain *dom = con->d;
692 
693 	err = xs_gather(xs, con->xspath,
694 			"ring-ref", "%u", &ring_ref,
695 			"port", "%i", &remote_port,
696 			NULL);
697 
698 	if (err) {
699 		/*
700 		 * This is a normal condition for optional consoles: they might not be
701 		 * present on xenstore at all. In that case, just return without error.
702 		*/
703 		if (con->optional)
704 			err = 0;
705 
706 		goto out;
707 	}
708 
709 	snprintf(path, sizeof(path), "%s/type", con->xspath);
710 	type = xs_read(xs, XBT_NULL, path, NULL);
711 	if (type && strcmp(type, "xenconsoled") != 0) {
712 		free(type);
713 		return 0;
714 	}
715 	free(type);
716 
717 	/* If using ring_ref and it has changed, remap */
718 	if (ring_ref != con->ring_ref && con->ring_ref != -1)
719 		console_unmap_interface(con);
720 
721 	if (!con->interface && xgt_handle && con->use_gnttab) {
722 		/* Prefer using grant table */
723 		con->interface = xengnttab_map_grant_ref(xgt_handle,
724 			dom->domid, GNTTAB_RESERVED_CONSOLE,
725 			PROT_READ|PROT_WRITE);
726 		con->ring_ref = -1;
727 	}
728 	if (!con->interface) {
729 		/* Fall back to xc_map_foreign_range */
730 		con->interface = xc_map_foreign_range(
731 			xc, dom->domid, XC_PAGE_SIZE,
732 			PROT_READ|PROT_WRITE,
733 			(unsigned long)ring_ref);
734 		if (con->interface == NULL) {
735 			err = EINVAL;
736 			goto out;
737 		}
738 		con->ring_ref = ring_ref;
739 	}
740 
741 	/* Go no further if port has not changed and we are still bound. */
742 	if (remote_port == con->remote_port) {
743 		xc_evtchn_status_t status = {
744 			.dom = DOMID_SELF,
745 			.port = con->local_port };
746 		if ((xc_evtchn_status(xc, &status) == 0) &&
747 		    (status.status == EVTCHNSTAT_interdomain))
748 			goto out;
749 	}
750 
751 	con->local_port = -1;
752 	con->remote_port = -1;
753 	if (con->xce_handle != NULL)
754 		xenevtchn_close(con->xce_handle);
755 
756 	/* Opening evtchn independently for each console is a bit
757 	 * wasteful, but that's how the code is structured... */
758 	con->xce_handle = xenevtchn_open(NULL, 0);
759 	if (con->xce_handle == NULL) {
760 		err = errno;
761 		goto out;
762 	}
763 
764 	rc = xenevtchn_bind_interdomain(con->xce_handle,
765 		dom->domid, remote_port);
766 
767 	if (rc == -1) {
768 		err = errno;
769 		xenevtchn_close(con->xce_handle);
770 		con->xce_handle = NULL;
771 		goto out;
772 	}
773 	con->local_port = rc;
774 	con->remote_port = remote_port;
775 
776 	if (con->master_fd == -1) {
777 		if (!console_create_tty(con)) {
778 			err = errno;
779 			xenevtchn_close(con->xce_handle);
780 			con->xce_handle = NULL;
781 			con->local_port = -1;
782 			con->remote_port = -1;
783 			goto out;
784 		}
785 	}
786 
787 	if (log_guest && (con->log_fd == -1))
788 		con->log_fd = create_console_log(con);
789 
790  out:
791 	return err;
792 }
793 
watch_domain(struct domain * dom,bool watch)794 static bool watch_domain(struct domain *dom, bool watch)
795 {
796 	char domid_str[3 + MAX_STRLEN(dom->domid)];
797 	bool success;
798 	struct console *con = &dom->console[0];
799 
800 	snprintf(domid_str, sizeof(domid_str), "dom%u", dom->domid);
801 	if (watch) {
802 		success = xs_watch(xs, con->xspath, domid_str);
803 		if (success)
804 			console_iter_int_arg1(dom, console_create_ring);
805 		else
806 			xs_unwatch(xs, con->xspath, domid_str);
807 	} else {
808 		success = xs_unwatch(xs, con->xspath, domid_str);
809 	}
810 
811 	return success;
812 }
813 
console_init(struct console * con,struct domain * dom,void ** data)814 static int console_init(struct console *con, struct domain *dom, void **data)
815 {
816 	char *s;
817 	int err = -1;
818 	struct timespec ts;
819 	struct console_type **con_type = (struct console_type **)data;
820 	char *xsname, *xspath;
821 
822 	if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
823 		dolog(LOG_ERR, "Cannot get time of day %s:%s:L%d",
824 		      __FILE__, __FUNCTION__, __LINE__);
825 		return err;
826 	}
827 
828 	con->master_fd = -1;
829 	con->master_pollfd_idx = -1;
830 	con->slave_fd = -1;
831 	con->log_fd = -1;
832 	con->ring_ref = -1;
833 	con->local_port = -1;
834 	con->remote_port = -1;
835 	con->xce_pollfd_idx = -1;
836 	con->next_period = ((long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000) + RATE_LIMIT_PERIOD;
837 	con->d = dom;
838 	con->ttyname = (*con_type)->ttyname;
839 	con->log_suffix = (*con_type)->log_suffix;
840 	con->optional = (*con_type)->optional;
841 	con->use_gnttab = (*con_type)->use_gnttab;
842 	xsname = (char *)(*con_type)->xsname;
843 	xspath = xs_get_domain_path(xs, dom->domid);
844 	s = realloc(xspath, strlen(xspath) +
845 		    strlen(xsname) + 1);
846 	if (s) {
847 		xspath = s;
848 		strcat(xspath, xsname);
849 		con->xspath = xspath;
850 		err = 0;
851 	}
852 
853 	(*con_type)++;
854 
855 	return err;
856 }
857 
console_free(struct console * con)858 static void console_free(struct console *con)
859 {
860 	if (con->xspath)
861 		free(con->xspath);
862 }
863 
create_domain(int domid)864 static struct domain *create_domain(int domid)
865 {
866 	struct domain *dom;
867 	struct console_type *con_type = &console_type[0];
868 
869 	dom = calloc(1, sizeof *dom);
870 	if (dom == NULL) {
871 		dolog(LOG_ERR, "Out of memory %s:%s():L%d",
872 		      __FILE__, __FUNCTION__, __LINE__);
873 		exit(ENOMEM);
874 	}
875 
876 	dom->domid = domid;
877 
878 	if (console_iter_int_arg3(dom, console_init, (void **)&con_type))
879 		goto out;
880 
881 	if (!watch_domain(dom, true))
882 		goto out;
883 
884 	dom->next = dom_head;
885 	dom_head = dom;
886 
887 	dolog(LOG_DEBUG, "New domain %d", domid);
888 
889 	return dom;
890  out:
891 	console_iter_void_arg1(dom, console_free);
892 	free(dom);
893 	return NULL;
894 }
895 
lookup_domain(int domid)896 static struct domain *lookup_domain(int domid)
897 {
898 	struct domain *dom;
899 
900 	for (dom = dom_head; dom; dom = dom->next)
901 		if (dom->domid == domid)
902 			return dom;
903 	return NULL;
904 }
905 
remove_domain(struct domain * dom)906 static void remove_domain(struct domain *dom)
907 {
908 	struct domain **pp;
909 
910 	dolog(LOG_DEBUG, "Removing domain-%d", dom->domid);
911 
912 	for (pp = &dom_head; *pp; pp = &(*pp)->next) {
913 		if (dom == *pp) {
914 			*pp = dom->next;
915 			free(dom);
916 			break;
917 		}
918 	}
919 }
920 
console_cleanup(struct console * con)921 static void console_cleanup(struct console *con)
922 {
923 	if (con->log_fd != -1) {
924 		close(con->log_fd);
925 		con->log_fd = -1;
926 	}
927 
928 	free(con->buffer.data);
929 	con->buffer.data = NULL;
930 
931 	free(con->xspath);
932 	con->xspath = NULL;
933 }
934 
cleanup_domain(struct domain * d)935 static void cleanup_domain(struct domain *d)
936 {
937 	console_iter_void_arg1(d, console_close_tty);
938 
939 	console_iter_void_arg1(d, console_cleanup);
940 
941 	remove_domain(d);
942 }
943 
console_close_evtchn(struct console * con)944 static void console_close_evtchn(struct console *con)
945 {
946 	if (con->xce_handle != NULL)
947 		xenevtchn_close(con->xce_handle);
948 
949 	con->xce_handle = NULL;
950 }
951 
shutdown_domain(struct domain * d)952 static void shutdown_domain(struct domain *d)
953 {
954 	d->is_dead = true;
955 	watch_domain(d, false);
956 	console_iter_void_arg1(d, console_unmap_interface);
957 	console_iter_void_arg1(d, console_close_evtchn);
958 }
959 
960 static unsigned enum_pass = 0;
961 
enum_domains(void)962 static void enum_domains(void)
963 {
964 	int domid = 1;
965 	xc_dominfo_t dominfo;
966 	struct domain *dom;
967 
968 	enum_pass++;
969 
970 	while (xc_domain_getinfo(xc, domid, 1, &dominfo) == 1) {
971 		dom = lookup_domain(dominfo.domid);
972 		if (dominfo.dying) {
973 			if (dom)
974 				shutdown_domain(dom);
975 		} else {
976 			if (dom == NULL)
977 				dom = create_domain(dominfo.domid);
978 		}
979 		if (dom)
980 			dom->last_seen = enum_pass;
981 		domid = dominfo.domid + 1;
982 	}
983 }
984 
ring_free_bytes(struct console * con)985 static int ring_free_bytes(struct console *con)
986 {
987 	struct xencons_interface *intf = con->interface;
988 	XENCONS_RING_IDX cons, prod, space;
989 
990 	cons = intf->in_cons;
991 	prod = intf->in_prod;
992 	xen_mb();
993 
994 	space = prod - cons;
995 	if (space > sizeof(intf->in))
996 		return 0; /* ring is screwed: ignore it */
997 
998 	return (sizeof(intf->in) - space);
999 }
1000 
console_handle_broken_tty(struct console * con,int recreate)1001 static void console_handle_broken_tty(struct console *con, int recreate)
1002 {
1003 	console_close_tty(con);
1004 
1005 	if (recreate) {
1006 		console_create_tty(con);
1007 	} else {
1008 		shutdown_domain(con->d);
1009 	}
1010 }
1011 
handle_tty_read(struct console * con)1012 static void handle_tty_read(struct console *con)
1013 {
1014 	ssize_t len = 0;
1015 	char msg[80];
1016 	int i;
1017 	struct xencons_interface *intf = con->interface;
1018 	struct domain *dom = con->d;
1019 	XENCONS_RING_IDX prod;
1020 
1021 	if (dom->is_dead)
1022 		return;
1023 
1024 	len = ring_free_bytes(con);
1025 	if (len == 0)
1026 		return;
1027 
1028 	if (len > sizeof(msg))
1029 		len = sizeof(msg);
1030 
1031 	len = read(con->master_fd, msg, len);
1032 	/*
1033 	 * Note: on Solaris, len == 0 means the slave closed, and this
1034 	 * is no problem, but Linux can't handle this usefully, so we
1035 	 * keep the slave open for the duration.
1036 	 */
1037 	if (len < 0) {
1038 		console_handle_broken_tty(con, domain_is_valid(dom->domid));
1039 	} else if (domain_is_valid(dom->domid)) {
1040 		prod = intf->in_prod;
1041 		for (i = 0; i < len; i++) {
1042 			intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
1043 				msg[i];
1044 		}
1045 		xen_wmb();
1046 		intf->in_prod = prod;
1047 		xenevtchn_notify(con->xce_handle, con->local_port);
1048 	} else {
1049 		console_close_tty(con);
1050 		shutdown_domain(dom);
1051 	}
1052 }
1053 
handle_tty_write(struct console * con)1054 static void handle_tty_write(struct console *con)
1055 {
1056 	ssize_t len;
1057 	struct domain *dom = con->d;
1058 
1059 	if (dom->is_dead)
1060 		return;
1061 
1062 	len = write(con->master_fd, con->buffer.data + con->buffer.consumed,
1063 		    con->buffer.size - con->buffer.consumed);
1064  	if (len < 1) {
1065 		dolog(LOG_DEBUG, "Write failed on domain %d: %zd, %d\n",
1066 		      dom->domid, len, errno);
1067 		console_handle_broken_tty(con, domain_is_valid(dom->domid));
1068 	} else {
1069 		buffer_advance(&con->buffer, len);
1070 	}
1071 }
1072 
console_evtchn_unmask(struct console * con,void * data)1073 static void console_evtchn_unmask(struct console *con, void *data)
1074 {
1075 	long long now = *(long long *)data;
1076 
1077 	if (!console_enabled(con))
1078 		return;
1079 
1080 	/* CS 16257:955ee4fa1345 introduces a 5ms fuzz
1081 	 * for select(), it is not clear poll() has
1082 	 * similar behavior (returning a couple of ms
1083 	 * sooner than requested) as well. Just leave
1084 	 * the fuzz here. Remove it with a separate
1085 	 * patch if necessary */
1086 	if ((now+5) > con->next_period) {
1087 		con->next_period = now + RATE_LIMIT_PERIOD;
1088 		if (con->event_count >= RATE_LIMIT_ALLOWANCE)
1089 			(void)xenevtchn_unmask(con->xce_handle, con->local_port);
1090 		con->event_count = 0;
1091 	}
1092 }
1093 
handle_ring_read(struct console * con)1094 static void handle_ring_read(struct console *con)
1095 {
1096 	xenevtchn_port_or_error_t port;
1097 
1098 	if (con->d->is_dead)
1099 		return;
1100 
1101 	if ((port = xenevtchn_pending(con->xce_handle)) == -1)
1102 		return;
1103 
1104 	if (port != con->local_port) {
1105 		dolog(LOG_ERR,
1106 		      "Event received for invalid port %d, Expected port is %d\n",
1107 		      port, con->local_port);
1108 		return;
1109 	}
1110 
1111 	con->event_count++;
1112 
1113 	buffer_append(con);
1114 
1115 	if (con->event_count < RATE_LIMIT_ALLOWANCE)
1116 		(void)xenevtchn_unmask(con->xce_handle, port);
1117 }
1118 
handle_console_ring(struct console * con)1119 static void handle_console_ring(struct console *con)
1120 {
1121 	if (con->event_count < RATE_LIMIT_ALLOWANCE) {
1122 		if (con->xce_handle != NULL &&
1123 		    con->xce_pollfd_idx != -1 &&
1124 		    !(fds[con->xce_pollfd_idx].revents &
1125 		      ~(POLLIN|POLLOUT|POLLPRI)) &&
1126 		    (fds[con->xce_pollfd_idx].revents &
1127 		     POLLIN))
1128 			handle_ring_read(con);
1129 	}
1130 
1131 	con->xce_pollfd_idx = -1;
1132 }
1133 
handle_xs(void)1134 static void handle_xs(void)
1135 {
1136 	char **vec;
1137 	int domid;
1138 	struct domain *dom;
1139 	unsigned int num;
1140 
1141 	vec = xs_read_watch(xs, &num);
1142 	if (!vec)
1143 		return;
1144 
1145 	if (!strcmp(vec[XS_WATCH_TOKEN], "domlist"))
1146 		enum_domains();
1147 	else if (sscanf(vec[XS_WATCH_TOKEN], "dom%u", &domid) == 1) {
1148 		dom = lookup_domain(domid);
1149 		/* We may get watches firing for domains that have recently
1150 		   been removed, so dom may be NULL here. */
1151 		if (dom && dom->is_dead == false)
1152 			console_iter_int_arg1(dom, console_create_ring);
1153 	}
1154 
1155 	free(vec);
1156 }
1157 
handle_hv_logs(xenevtchn_handle * xce_handle,bool force)1158 static void handle_hv_logs(xenevtchn_handle *xce_handle, bool force)
1159 {
1160 	static char buffer[1024*16];
1161 	char *bufptr = buffer;
1162 	unsigned int size;
1163 	static uint32_t index = 0;
1164 	xenevtchn_port_or_error_t port = -1;
1165 
1166 	if (!force && ((port = xenevtchn_pending(xce_handle)) == -1))
1167 		return;
1168 
1169 	do
1170 	{
1171 		int logret;
1172 
1173 		size = sizeof(buffer);
1174 		if (xc_readconsolering(xc, bufptr, &size, 0, 1, &index) != 0 ||
1175 		    size == 0)
1176 			break;
1177 
1178 		if (log_time_hv)
1179 			logret = write_with_timestamp(log_hv_fd, buffer, size,
1180 						      &log_time_hv_needts);
1181 		else
1182 			logret = write_all(log_hv_fd, buffer, size);
1183 
1184 		if (logret < 0)
1185 			dolog(LOG_ERR, "Failed to write hypervisor log: "
1186 				       "%d (%s)", errno, strerror(errno));
1187 	} while (size == sizeof(buffer));
1188 
1189 	if (port != -1)
1190 		(void)xenevtchn_unmask(xce_handle, port);
1191 }
1192 
console_open_log(struct console * con)1193 static void console_open_log(struct console *con)
1194 {
1195 	if (console_enabled(con)) {
1196 		if (con->log_fd != -1)
1197 			close(con->log_fd);
1198 		con->log_fd = create_console_log(con);
1199 	}
1200 }
1201 
handle_log_reload(void)1202 static void handle_log_reload(void)
1203 {
1204 	if (log_guest) {
1205 		struct domain *d;
1206 		for (d = dom_head; d; d = d->next) {
1207 			console_iter_void_arg1(d, console_open_log);
1208 		}
1209 	}
1210 
1211 	if (log_hv) {
1212 		if (log_hv_fd != -1)
1213 			close(log_hv_fd);
1214 		log_hv_fd = create_hv_log();
1215 	}
1216 }
1217 
1218 /* Returns index inside fds array if succees, -1 if fail */
set_fds(int fd,short events)1219 static int set_fds(int fd, short events)
1220 {
1221 	int ret;
1222 	if (current_array_size < nr_fds + 1) {
1223 		struct pollfd  *new_fds = NULL;
1224 		unsigned long newsize;
1225 
1226 		/* Round up to 2^8 boundary, in practice this just
1227 		 * make newsize larger than current_array_size.
1228 		 */
1229 		newsize = ROUNDUP(nr_fds + 1, 8);
1230 
1231 		new_fds = realloc(fds, sizeof(struct pollfd)*newsize);
1232 		if (!new_fds)
1233 			goto fail;
1234 		fds = new_fds;
1235 
1236 		memset(&fds[0] + current_array_size, 0,
1237 		       sizeof(struct pollfd) * (newsize-current_array_size));
1238 		current_array_size = newsize;
1239 	}
1240 
1241 	fds[nr_fds].fd = fd;
1242 	fds[nr_fds].events = events;
1243 	ret = nr_fds;
1244 	nr_fds++;
1245 
1246 	return ret;
1247 fail:
1248 	dolog(LOG_ERR, "realloc failed, ignoring fd %d\n", fd);
1249 	return -1;
1250 }
1251 
reset_fds(void)1252 static void reset_fds(void)
1253 {
1254 	nr_fds = 0;
1255 	if (fds)
1256 		memset(fds, 0, sizeof(struct pollfd) * current_array_size);
1257 }
1258 
maybe_add_console_evtchn_fd(struct console * con,void * data)1259 static void maybe_add_console_evtchn_fd(struct console *con, void *data)
1260 {
1261 	long long next_timeout = *((long long *)data);
1262 
1263 	if (con->event_count >= RATE_LIMIT_ALLOWANCE) {
1264 		/* Determine if we're going to be the next time slice to expire */
1265 		if (!next_timeout ||
1266 		    con->next_period < next_timeout)
1267 			next_timeout = con->next_period;
1268 	} else if (con->xce_handle != NULL) {
1269 		if (buffer_available(con)) {
1270 			int evtchn_fd = xenevtchn_fd(con->xce_handle);
1271 			con->xce_pollfd_idx = set_fds(evtchn_fd,
1272 						      POLLIN|POLLPRI);
1273 		}
1274 	}
1275 
1276 	*((long long *)data) = next_timeout;
1277 }
1278 
maybe_add_console_tty_fd(struct console * con)1279 static void maybe_add_console_tty_fd(struct console *con)
1280 {
1281 	if (con->master_fd != -1) {
1282 		short events = 0;
1283 		if (!con->d->is_dead && ring_free_bytes(con))
1284 			events |= POLLIN;
1285 
1286 		if (!buffer_empty(&con->buffer))
1287 			events |= POLLOUT;
1288 
1289 		if (events)
1290 			con->master_pollfd_idx =
1291 				set_fds(con->master_fd, events|POLLPRI);
1292 	}
1293 }
1294 
handle_console_tty(struct console * con)1295 static void handle_console_tty(struct console *con)
1296 {
1297 	if (con->master_fd != -1 && con->master_pollfd_idx != -1) {
1298 		if (fds[con->master_pollfd_idx].revents &
1299 		    ~(POLLIN|POLLOUT|POLLPRI))
1300 			console_handle_broken_tty(con, domain_is_valid(con->d->domid));
1301 		else {
1302 			if (fds[con->master_pollfd_idx].revents &
1303 			    POLLIN)
1304 				handle_tty_read(con);
1305 			if (fds[con->master_pollfd_idx].revents &
1306 			    POLLOUT)
1307 				handle_tty_write(con);
1308 		}
1309 	}
1310 	con->master_pollfd_idx = -1;
1311 }
1312 
handle_io(void)1313 void handle_io(void)
1314 {
1315 	int ret;
1316 	xenevtchn_port_or_error_t log_hv_evtchn = -1;
1317 	int xce_pollfd_idx = -1;
1318 	int xs_pollfd_idx = -1;
1319 	xenevtchn_handle *xce_handle = NULL;
1320 
1321 	if (log_hv) {
1322 		xce_handle = xenevtchn_open(NULL, 0);
1323 		if (xce_handle == NULL) {
1324 			dolog(LOG_ERR, "Failed to open xce handle: %d (%s)",
1325 			      errno, strerror(errno));
1326 			goto out;
1327 		}
1328 		log_hv_fd = create_hv_log();
1329 		if (log_hv_fd == -1)
1330 			goto out;
1331 		log_hv_evtchn = xenevtchn_bind_virq(xce_handle, VIRQ_CON_RING);
1332 		if (log_hv_evtchn == -1) {
1333 			dolog(LOG_ERR, "Failed to bind to VIRQ_CON_RING: "
1334 			      "%d (%s)", errno, strerror(errno));
1335 			goto out;
1336 		}
1337 		/* Log the boot dmesg even if VIRQ_CON_RING isn't pending. */
1338 		handle_hv_logs(xce_handle, true);
1339 	}
1340 
1341 	xgt_handle = xengnttab_open(NULL, 0);
1342 	if (xgt_handle == NULL) {
1343 		dolog(LOG_DEBUG, "Failed to open xcg handle: %d (%s)",
1344 		      errno, strerror(errno));
1345 	}
1346 
1347 	enum_domains();
1348 
1349 	for (;;) {
1350 		struct domain *d, *n;
1351 		int poll_timeout; /* timeout in milliseconds */
1352 		struct timespec ts;
1353 		long long now, next_timeout = 0;
1354 
1355 		reset_fds();
1356 
1357 		xs_pollfd_idx = set_fds(xs_fileno(xs), POLLIN|POLLPRI);
1358 
1359 		if (log_hv)
1360 			xce_pollfd_idx = set_fds(xenevtchn_fd(xce_handle),
1361 						 POLLIN|POLLPRI);
1362 
1363 		if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
1364 			break;
1365 		now = ((long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
1366 
1367 		/* Re-calculate any event counter allowances & unblock
1368 		   domains with new allowance */
1369 		for (d = dom_head; d; d = d->next) {
1370 
1371 			console_iter_void_arg2(d, console_evtchn_unmask, (void *)&now);
1372 
1373 			console_iter_void_arg2(d, maybe_add_console_evtchn_fd,
1374 					       (void *)&next_timeout);
1375 
1376 			console_iter_void_arg1(d, maybe_add_console_tty_fd);
1377 		}
1378 
1379 		/* If any domain has been rate limited, we need to work
1380 		   out what timeout to supply to poll */
1381 		if (next_timeout) {
1382 			long long duration = (next_timeout - now);
1383 			if (duration <= 0) /* sanity check */
1384 				duration = 1;
1385 			poll_timeout = (int)duration;
1386 		}
1387 
1388 		ret = poll(fds, nr_fds, next_timeout ? poll_timeout : -1);
1389 
1390 		if (log_reload) {
1391 			int saved_errno = errno;
1392 
1393 			handle_log_reload();
1394 			log_reload = 0;
1395 
1396 			errno = saved_errno;
1397 		}
1398 
1399 		/* Abort if poll failed, except for EINTR cases
1400 		   which indicate a possible log reload */
1401 		if (ret == -1) {
1402 			if (errno == EINTR)
1403 				continue;
1404 			dolog(LOG_ERR, "Failure in poll: %d (%s)",
1405 			      errno, strerror(errno));
1406 			break;
1407 		}
1408 
1409 		if (log_hv && xce_pollfd_idx != -1) {
1410 			if (fds[xce_pollfd_idx].revents & ~(POLLIN|POLLOUT|POLLPRI)) {
1411 				dolog(LOG_ERR,
1412 				      "Failure in poll xce_handle: %d (%s)",
1413 				      errno, strerror(errno));
1414 				break;
1415 			} else if (fds[xce_pollfd_idx].revents & POLLIN)
1416 				handle_hv_logs(xce_handle, false);
1417 
1418 			xce_pollfd_idx = -1;
1419 		}
1420 
1421 		if (ret <= 0)
1422 			continue;
1423 
1424 		if (xs_pollfd_idx != -1) {
1425 			if (fds[xs_pollfd_idx].revents & ~(POLLIN|POLLOUT|POLLPRI)) {
1426 				dolog(LOG_ERR,
1427 				      "Failure in poll xs_handle: %d (%s)",
1428 				      errno, strerror(errno));
1429 				break;
1430 			} else if (fds[xs_pollfd_idx].revents & POLLIN)
1431 				handle_xs();
1432 
1433 			xs_pollfd_idx = -1;
1434 		}
1435 
1436 		for (d = dom_head; d; d = n) {
1437 
1438 			n = d->next;
1439 
1440 			console_iter_void_arg1(d, handle_console_ring);
1441 
1442 			console_iter_void_arg1(d, handle_console_tty);
1443 
1444 			if (d->last_seen != enum_pass)
1445 				shutdown_domain(d);
1446 
1447 			if (d->is_dead)
1448 				cleanup_domain(d);
1449 		}
1450 	}
1451 
1452 	free(fds);
1453 	current_array_size = 0;
1454 
1455  out:
1456 	if (log_hv_fd != -1) {
1457 		close(log_hv_fd);
1458 		log_hv_fd = -1;
1459 	}
1460 	if (xce_handle != NULL) {
1461 		xenevtchn_close(xce_handle);
1462 		xce_handle = NULL;
1463 	}
1464 	if (xgt_handle != NULL) {
1465 		xengnttab_close(xgt_handle);
1466 		xgt_handle = NULL;
1467 	}
1468 	log_hv_evtchn = -1;
1469 }
1470 
1471 /*
1472  * Local variables:
1473  *  mode: C
1474  *  c-file-style: "linux"
1475  *  indent-tabs-mode: t
1476  *  c-basic-offset: 8
1477  *  tab-width: 8
1478  * End:
1479  */
1480