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