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