ia64/xen-unstable

view tools/console/daemon/io.c @ 16264:3bb94bb35dad

Allow incremental access to hypervisor console log.
Signed-off-by: Keir Fraser <keir@xensource.com>
author Keir Fraser <keir@xensource.com>
date Mon Oct 29 12:56:27 2007 +0000 (2007-10-29)
parents a4df9c0c33fd
children 955ee4fa1345
line source
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, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
21 #define _GNU_SOURCE
23 #include "utils.h"
24 #include "io.h"
25 #include <xs.h>
26 #include <xen/io/console.h>
27 #include <xenctrl.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <sys/select.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <termios.h>
36 #include <stdarg.h>
37 #include <sys/mman.h>
38 #if defined(__NetBSD__) || defined(__OpenBSD__)
39 #include <util.h>
40 #elif defined(__linux__) || defined(__Linux__)
41 #include <pty.h>
42 #endif
44 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
45 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
47 /* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */
48 #define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2)
50 extern int log_reload;
51 extern int log_guest;
52 extern int log_hv;
53 extern char *log_dir;
55 static int log_hv_fd = -1;
56 static evtchn_port_or_error_t log_hv_evtchn = -1;
57 static int xc_handle = -1;
58 static int xce_handle = -1;
60 struct buffer
61 {
62 char *data;
63 size_t consumed;
64 size_t size;
65 size_t capacity;
66 size_t max_capacity;
67 };
69 struct domain
70 {
71 int domid;
72 int tty_fd;
73 int log_fd;
74 bool is_dead;
75 struct buffer buffer;
76 struct domain *next;
77 char *conspath;
78 char *serialpath;
79 int use_consolepath;
80 int ring_ref;
81 evtchn_port_or_error_t local_port;
82 evtchn_port_or_error_t remote_port;
83 int xce_handle;
84 struct xencons_interface *interface;
85 };
87 static struct domain *dom_head;
89 static void buffer_append(struct domain *dom)
90 {
91 struct buffer *buffer = &dom->buffer;
92 XENCONS_RING_IDX cons, prod, size;
93 struct xencons_interface *intf = dom->interface;
95 cons = intf->out_cons;
96 prod = intf->out_prod;
97 mb();
99 size = prod - cons;
100 if ((size == 0) || (size > sizeof(intf->out)))
101 return;
103 if ((buffer->capacity - buffer->size) < size) {
104 buffer->capacity += (size + 1024);
105 buffer->data = realloc(buffer->data, buffer->capacity);
106 if (buffer->data == NULL) {
107 dolog(LOG_ERR, "Memory allocation failed");
108 exit(ENOMEM);
109 }
110 }
112 while (cons != prod)
113 buffer->data[buffer->size++] = intf->out[
114 MASK_XENCONS_IDX(cons++, intf->out)];
116 mb();
117 intf->out_cons = cons;
118 xc_evtchn_notify(dom->xce_handle, dom->local_port);
120 /* Get the data to the logfile as early as possible because if
121 * no one is listening on the console pty then it will fill up
122 * and handle_tty_write will stop being called.
123 */
124 if (dom->log_fd != -1) {
125 int len = write(dom->log_fd,
126 buffer->data + buffer->size - size,
127 size);
128 if (len < 0)
129 dolog(LOG_ERR, "Write to log failed on domain %d: %d (%s)\n",
130 dom->domid, errno, strerror(errno));
131 }
133 if (buffer->max_capacity &&
134 buffer->size > buffer->max_capacity) {
135 /* Discard the middle of the data. */
137 size_t over = buffer->size - buffer->max_capacity;
138 char *maxpos = buffer->data + buffer->max_capacity;
140 memmove(maxpos - over, maxpos, over);
141 buffer->data = realloc(buffer->data, buffer->max_capacity);
142 buffer->size = buffer->capacity = buffer->max_capacity;
144 if (buffer->consumed > buffer->max_capacity - over)
145 buffer->consumed = buffer->max_capacity - over;
146 }
147 }
149 static bool buffer_empty(struct buffer *buffer)
150 {
151 return buffer->size == 0;
152 }
154 static void buffer_advance(struct buffer *buffer, size_t len)
155 {
156 buffer->consumed += len;
157 if (buffer->consumed == buffer->size) {
158 buffer->consumed = 0;
159 buffer->size = 0;
160 }
161 }
163 static bool domain_is_valid(int domid)
164 {
165 bool ret;
166 xc_dominfo_t info;
168 ret = (xc_domain_getinfo(xc, domid, 1, &info) == 1 &&
169 info.domid == domid);
171 return ret;
172 }
174 static int create_hv_log(void)
175 {
176 char logfile[PATH_MAX];
177 int fd;
178 snprintf(logfile, PATH_MAX-1, "%s/hypervisor.log", log_dir);
179 logfile[PATH_MAX-1] = '\0';
181 fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644);
182 if (fd == -1)
183 dolog(LOG_ERR, "Failed to open log %s: %d (%s)",
184 logfile, errno, strerror(errno));
185 return fd;
186 }
188 static int create_domain_log(struct domain *dom)
189 {
190 char logfile[PATH_MAX];
191 char *namepath, *data, *s;
192 int fd;
193 unsigned int len;
195 namepath = xs_get_domain_path(xs, dom->domid);
196 s = realloc(namepath, strlen(namepath) + 6);
197 if (s == NULL) {
198 free(namepath);
199 return -1;
200 }
201 namepath = s;
202 strcat(namepath, "/name");
203 data = xs_read(xs, XBT_NULL, namepath, &len);
204 if (!data)
205 return -1;
206 if (!len) {
207 free(data);
208 return -1;
209 }
211 snprintf(logfile, PATH_MAX-1, "%s/guest-%s.log", log_dir, data);
212 free(data);
213 logfile[PATH_MAX-1] = '\0';
215 fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644);
216 if (fd == -1)
217 dolog(LOG_ERR, "Failed to open log %s: %d (%s)",
218 logfile, errno, strerror(errno));
219 return fd;
220 }
222 #ifdef __sun__
223 /* Once Solaris has openpty(), this is going to be removed. */
224 int openpty(int *amaster, int *aslave, char *name,
225 struct termios *termp, struct winsize *winp)
226 {
227 int mfd, sfd;
229 *amaster = *aslave = -1;
230 mfd = sfd = -1;
232 mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
233 if (mfd < 0)
234 goto err0;
236 if (grantpt(mfd) == -1 || unlockpt(mfd) == -1)
237 goto err1;
239 /* This does not match openpty specification,
240 * but as long as this does not hurt, this is acceptable.
241 */
242 mfd = sfd;
244 if (termp != NULL && tcgetattr(sfd, termp) < 0)
245 goto err1;
247 if (amaster)
248 *amaster = mfd;
249 if (aslave)
250 *aslave = sfd;
251 if (name)
252 strlcpy(name, ptsname(mfd), sizeof(slave));
253 if (winp)
254 ioctl(sfd, TIOCSWINSZ, winp);
256 return 0;
258 err1:
259 close(mfd);
260 err0:
261 return -1;
262 }
263 #endif
266 static int domain_create_tty(struct domain *dom)
267 {
268 char slave[80];
269 struct termios term;
270 char *path;
271 int master, slavefd;
272 int err;
273 bool success;
274 char *data;
275 unsigned int len;
277 if (openpty(&master, &slavefd, slave, &term, NULL) < 0) {
278 master = -1;
279 err = errno;
280 dolog(LOG_ERR, "Failed to create tty for domain-%d (errno = %i, %s)",
281 dom->domid, err, strerror(err));
282 return master;
283 }
285 cfmakeraw(&term);
286 if (tcsetattr(master, TCSAFLUSH, &term) < 0) {
287 err = errno;
288 dolog(LOG_ERR, "Failed to set tty attribute for domain-%d (errno = %i, %s)",
289 dom->domid, err, strerror(err));
290 goto out;
291 }
294 if (dom->use_consolepath) {
295 success = asprintf(&path, "%s/limit", dom->conspath) !=
296 -1;
297 if (!success)
298 goto out;
299 data = xs_read(xs, XBT_NULL, path, &len);
300 if (data) {
301 dom->buffer.max_capacity = strtoul(data, 0, 0);
302 free(data);
303 }
304 free(path);
305 }
307 success = asprintf(&path, "%s/limit", dom->serialpath) != -1;
308 if (!success)
309 goto out;
310 data = xs_read(xs, XBT_NULL, path, &len);
311 if (data) {
312 dom->buffer.max_capacity = strtoul(data, 0, 0);
313 free(data);
314 }
315 free(path);
317 success = asprintf(&path, "%s/tty", dom->serialpath) != -1;
318 if (!success)
319 goto out;
320 success = xs_write(xs, XBT_NULL, path, slave, strlen(slave));
321 free(path);
322 if (!success)
323 goto out;
325 if (dom->use_consolepath) {
326 success = (asprintf(&path, "%s/tty", dom->conspath) != -1);
327 if (!success)
328 goto out;
329 success = xs_write(xs, XBT_NULL, path, slave, strlen(slave));
330 free(path);
331 if (!success)
332 goto out;
333 }
335 if (fcntl(master, F_SETFL, O_NONBLOCK) == -1)
336 goto out;
338 return master;
339 out:
340 close(master);
341 return -1;
342 }
344 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
345 int xs_gather(struct xs_handle *xs, const char *dir, ...)
346 {
347 va_list ap;
348 const char *name;
349 char *path;
350 int ret = 0;
352 va_start(ap, dir);
353 while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
354 const char *fmt = va_arg(ap, char *);
355 void *result = va_arg(ap, void *);
356 char *p;
358 if (asprintf(&path, "%s/%s", dir, name) == -1) {
359 ret = ENOMEM;
360 break;
361 }
362 p = xs_read(xs, XBT_NULL, path, NULL);
363 free(path);
364 if (p == NULL) {
365 ret = ENOENT;
366 break;
367 }
368 if (fmt) {
369 if (sscanf(p, fmt, result) == 0)
370 ret = EINVAL;
371 free(p);
372 } else
373 *(char **)result = p;
374 }
375 va_end(ap);
376 return ret;
377 }
379 static int domain_create_ring(struct domain *dom)
380 {
381 int err, remote_port, ring_ref, rc;
382 char *type, path[PATH_MAX];
384 err = xs_gather(xs, dom->serialpath,
385 "ring-ref", "%u", &ring_ref,
386 "port", "%i", &remote_port,
387 NULL);
388 if (err) {
389 err = xs_gather(xs, dom->conspath,
390 "ring-ref", "%u", &ring_ref,
391 "port", "%i", &remote_port,
392 NULL);
393 if (err)
394 goto out;
395 dom->use_consolepath = 1;
396 } else
397 dom->use_consolepath = 0;
399 sprintf(path, "%s/type", dom->use_consolepath ? dom->conspath: dom->serialpath);
400 type = xs_read(xs, XBT_NULL, path, NULL);
401 if (type && strcmp(type, "xenconsoled") != 0) {
402 free(type);
403 return 0;
404 }
405 free(type);
407 if ((ring_ref == dom->ring_ref) && (remote_port == dom->remote_port))
408 goto out;
410 if (ring_ref != dom->ring_ref) {
411 if (dom->interface != NULL)
412 munmap(dom->interface, getpagesize());
413 dom->interface = xc_map_foreign_range(
414 xc, dom->domid, getpagesize(),
415 PROT_READ|PROT_WRITE,
416 (unsigned long)ring_ref);
417 if (dom->interface == NULL) {
418 err = EINVAL;
419 goto out;
420 }
421 dom->ring_ref = ring_ref;
422 }
424 dom->local_port = -1;
425 dom->remote_port = -1;
426 if (dom->xce_handle != -1)
427 xc_evtchn_close(dom->xce_handle);
429 /* Opening evtchn independently for each console is a bit
430 * wasteful, but that's how the code is structured... */
431 dom->xce_handle = xc_evtchn_open();
432 if (dom->xce_handle == -1) {
433 err = errno;
434 goto out;
435 }
437 rc = xc_evtchn_bind_interdomain(dom->xce_handle,
438 dom->domid, remote_port);
440 if (rc == -1) {
441 err = errno;
442 xc_evtchn_close(dom->xce_handle);
443 dom->xce_handle = -1;
444 goto out;
445 }
446 dom->local_port = rc;
447 dom->remote_port = remote_port;
449 if (dom->tty_fd == -1) {
450 dom->tty_fd = domain_create_tty(dom);
452 if (dom->tty_fd == -1) {
453 err = errno;
454 xc_evtchn_close(dom->xce_handle);
455 dom->xce_handle = -1;
456 dom->local_port = -1;
457 dom->remote_port = -1;
458 goto out;
459 }
460 }
462 if (log_guest)
463 dom->log_fd = create_domain_log(dom);
465 out:
466 return err;
467 }
469 static bool watch_domain(struct domain *dom, bool watch)
470 {
471 char domid_str[3 + MAX_STRLEN(dom->domid)];
472 bool success;
474 snprintf(domid_str, sizeof(domid_str), "dom%u", dom->domid);
475 if (watch) {
476 success = xs_watch(xs, dom->serialpath, domid_str);
477 if (success) {
478 success = xs_watch(xs, dom->conspath, domid_str);
479 if (success)
480 domain_create_ring(dom);
481 else
482 xs_unwatch(xs, dom->serialpath, domid_str);
483 }
484 } else {
485 success = xs_unwatch(xs, dom->serialpath, domid_str);
486 success = xs_unwatch(xs, dom->conspath, domid_str);
487 }
489 return success;
490 }
493 static struct domain *create_domain(int domid)
494 {
495 struct domain *dom;
496 char *s;
498 dom = (struct domain *)malloc(sizeof(struct domain));
499 if (dom == NULL) {
500 dolog(LOG_ERR, "Out of memory %s:%s():L%d",
501 __FILE__, __FUNCTION__, __LINE__);
502 exit(ENOMEM);
503 }
505 dom->domid = domid;
507 dom->serialpath = xs_get_domain_path(xs, dom->domid);
508 s = realloc(dom->serialpath, strlen(dom->serialpath) +
509 strlen("/serial/0") + 1);
510 if (s == NULL)
511 goto out;
512 dom->serialpath = s;
513 strcat(dom->serialpath, "/serial/0");
515 dom->conspath = xs_get_domain_path(xs, dom->domid);
516 s = realloc(dom->conspath, strlen(dom->conspath) +
517 strlen("/console") + 1);
518 if (s == NULL)
519 goto out;
520 dom->conspath = s;
521 strcat(dom->conspath, "/console");
523 dom->tty_fd = -1;
524 dom->log_fd = -1;
526 dom->is_dead = false;
527 dom->buffer.data = 0;
528 dom->buffer.consumed = 0;
529 dom->buffer.size = 0;
530 dom->buffer.capacity = 0;
531 dom->buffer.max_capacity = 0;
532 dom->next = NULL;
534 dom->ring_ref = -1;
535 dom->local_port = -1;
536 dom->remote_port = -1;
537 dom->interface = NULL;
538 dom->xce_handle = -1;
540 if (!watch_domain(dom, true))
541 goto out;
543 dom->next = dom_head;
544 dom_head = dom;
546 dolog(LOG_DEBUG, "New domain %d", domid);
548 return dom;
549 out:
550 free(dom->serialpath);
551 free(dom->conspath);
552 free(dom);
553 return NULL;
554 }
556 static struct domain *lookup_domain(int domid)
557 {
558 struct domain *dom;
560 for (dom = dom_head; dom; dom = dom->next)
561 if (dom->domid == domid)
562 return dom;
563 return NULL;
564 }
566 static void remove_domain(struct domain *dom)
567 {
568 struct domain **pp;
570 dolog(LOG_DEBUG, "Removing domain-%d", dom->domid);
572 for (pp = &dom_head; *pp; pp = &(*pp)->next) {
573 if (dom == *pp) {
574 *pp = dom->next;
575 free(dom);
576 break;
577 }
578 }
579 }
581 static void cleanup_domain(struct domain *d)
582 {
583 if (d->tty_fd != -1) {
584 close(d->tty_fd);
585 d->tty_fd = -1;
586 }
587 if (d->log_fd != -1) {
588 close(d->log_fd);
589 d->log_fd = -1;
590 }
592 free(d->buffer.data);
593 d->buffer.data = NULL;
595 free(d->serialpath);
596 d->serialpath = NULL;
598 free(d->conspath);
599 d->conspath = NULL;
601 remove_domain(d);
602 }
604 static void shutdown_domain(struct domain *d)
605 {
606 d->is_dead = true;
607 watch_domain(d, false);
608 if (d->interface != NULL)
609 munmap(d->interface, getpagesize());
610 d->interface = NULL;
611 if (d->xce_handle != -1)
612 xc_evtchn_close(d->xce_handle);
613 d->xce_handle = -1;
614 cleanup_domain(d);
615 }
617 void enum_domains(void)
618 {
619 int domid = 1;
620 xc_dominfo_t dominfo;
621 struct domain *dom;
623 while (xc_domain_getinfo(xc, domid, 1, &dominfo) == 1) {
624 dom = lookup_domain(dominfo.domid);
625 if (dominfo.dying) {
626 if (dom)
627 shutdown_domain(dom);
628 } else {
629 if (dom == NULL)
630 create_domain(dominfo.domid);
631 }
632 domid = dominfo.domid + 1;
633 }
634 }
636 static int ring_free_bytes(struct domain *dom)
637 {
638 struct xencons_interface *intf = dom->interface;
639 XENCONS_RING_IDX cons, prod, space;
641 cons = intf->in_cons;
642 prod = intf->in_prod;
643 mb();
645 space = prod - cons;
646 if (space > sizeof(intf->in))
647 return 0; /* ring is screwed: ignore it */
649 return (sizeof(intf->in) - space);
650 }
652 static void handle_tty_read(struct domain *dom)
653 {
654 ssize_t len = 0;
655 char msg[80];
656 int i;
657 struct xencons_interface *intf = dom->interface;
658 XENCONS_RING_IDX prod;
660 len = ring_free_bytes(dom);
661 if (len == 0)
662 return;
664 if (len > sizeof(msg))
665 len = sizeof(msg);
667 len = read(dom->tty_fd, msg, len);
668 if (len < 1) {
669 close(dom->tty_fd);
670 dom->tty_fd = -1;
672 if (domain_is_valid(dom->domid)) {
673 dom->tty_fd = domain_create_tty(dom);
674 } else {
675 shutdown_domain(dom);
676 }
677 } else if (domain_is_valid(dom->domid)) {
678 prod = intf->in_prod;
679 for (i = 0; i < len; i++) {
680 intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
681 msg[i];
682 }
683 wmb();
684 intf->in_prod = prod;
685 xc_evtchn_notify(dom->xce_handle, dom->local_port);
686 } else {
687 close(dom->tty_fd);
688 dom->tty_fd = -1;
689 shutdown_domain(dom);
690 }
691 }
693 static void handle_tty_write(struct domain *dom)
694 {
695 ssize_t len;
697 len = write(dom->tty_fd, dom->buffer.data + dom->buffer.consumed,
698 dom->buffer.size - dom->buffer.consumed);
699 if (len < 1) {
700 dolog(LOG_DEBUG, "Write failed on domain %d: %zd, %d\n",
701 dom->domid, len, errno);
703 close(dom->tty_fd);
704 dom->tty_fd = -1;
706 if (domain_is_valid(dom->domid)) {
707 dom->tty_fd = domain_create_tty(dom);
708 } else {
709 shutdown_domain(dom);
710 }
711 } else {
712 buffer_advance(&dom->buffer, len);
713 }
714 }
716 static void handle_ring_read(struct domain *dom)
717 {
718 evtchn_port_or_error_t port;
720 if ((port = xc_evtchn_pending(dom->xce_handle)) == -1)
721 return;
723 buffer_append(dom);
725 (void)xc_evtchn_unmask(dom->xce_handle, port);
726 }
728 static void handle_xs(void)
729 {
730 char **vec;
731 int domid;
732 struct domain *dom;
733 unsigned int num;
735 vec = xs_read_watch(xs, &num);
736 if (!vec)
737 return;
739 if (!strcmp(vec[XS_WATCH_TOKEN], "domlist"))
740 enum_domains();
741 else if (sscanf(vec[XS_WATCH_TOKEN], "dom%u", &domid) == 1) {
742 dom = lookup_domain(domid);
743 /* We may get watches firing for domains that have recently
744 been removed, so dom may be NULL here. */
745 if (dom && dom->is_dead == false)
746 domain_create_ring(dom);
747 }
749 free(vec);
750 }
752 static void handle_hv_logs(void)
753 {
754 char buffer[1024*16];
755 char *bufptr = buffer;
756 unsigned int size = sizeof(buffer);
757 static uint32_t index = 0;
758 evtchn_port_or_error_t port;
760 if ((port = xc_evtchn_pending(xce_handle)) == -1)
761 return;
763 if (xc_readconsolering(xc_handle, &bufptr, &size, 0, 1, &index) == 0) {
764 int len = write(log_hv_fd, buffer, size);
765 if (len < 0)
766 dolog(LOG_ERR, "Failed to write hypervisor log: %d (%s)",
767 errno, strerror(errno));
768 }
770 (void)xc_evtchn_unmask(xce_handle, port);
771 }
773 static void handle_log_reload(void)
774 {
775 if (log_guest) {
776 struct domain *d;
777 for (d = dom_head; d; d = d->next) {
778 if (d->log_fd != -1)
779 close(d->log_fd);
780 d->log_fd = create_domain_log(d);
781 }
782 }
784 if (log_hv) {
785 if (log_hv_fd != -1)
786 close(log_hv_fd);
787 log_hv_fd = create_hv_log();
788 }
789 }
791 void handle_io(void)
792 {
793 fd_set readfds, writefds;
794 int ret;
796 if (log_hv) {
797 xc_handle = xc_interface_open();
798 if (xc_handle == -1) {
799 dolog(LOG_ERR, "Failed to open xc handle: %d (%s)",
800 errno, strerror(errno));
801 goto out;
802 }
803 xce_handle = xc_evtchn_open();
804 if (xce_handle == -1) {
805 dolog(LOG_ERR, "Failed to open xce handle: %d (%s)",
806 errno, strerror(errno));
807 goto out;
808 }
809 log_hv_fd = create_hv_log();
810 if (log_hv_fd == -1)
811 goto out;
812 log_hv_evtchn = xc_evtchn_bind_virq(xce_handle, VIRQ_CON_RING);
813 if (log_hv_evtchn == -1) {
814 dolog(LOG_ERR, "Failed to bind to VIRQ_CON_RING: "
815 "%d (%s)", errno, strerror(errno));
816 goto out;
817 }
818 }
820 for (;;) {
821 struct domain *d, *n;
822 int max_fd = -1;
824 FD_ZERO(&readfds);
825 FD_ZERO(&writefds);
827 FD_SET(xs_fileno(xs), &readfds);
828 max_fd = MAX(xs_fileno(xs), max_fd);
830 if (log_hv) {
831 FD_SET(xc_evtchn_fd(xce_handle), &readfds);
832 max_fd = MAX(xc_evtchn_fd(xce_handle), max_fd);
833 }
835 for (d = dom_head; d; d = d->next) {
836 if (d->xce_handle != -1) {
837 int evtchn_fd = xc_evtchn_fd(d->xce_handle);
838 FD_SET(evtchn_fd, &readfds);
839 max_fd = MAX(evtchn_fd, max_fd);
840 }
842 if (d->tty_fd != -1) {
843 if (!d->is_dead && ring_free_bytes(d))
844 FD_SET(d->tty_fd, &readfds);
846 if (!buffer_empty(&d->buffer))
847 FD_SET(d->tty_fd, &writefds);
848 max_fd = MAX(d->tty_fd, max_fd);
849 }
850 }
852 ret = select(max_fd + 1, &readfds, &writefds, 0, NULL);
854 if (log_reload) {
855 handle_log_reload();
856 log_reload = 0;
857 }
859 /* Abort if select failed, except for EINTR cases
860 which indicate a possible log reload */
861 if (ret == -1) {
862 if (errno == EINTR)
863 continue;
864 dolog(LOG_ERR, "Failure in select: %d (%s)",
865 errno, strerror(errno));
866 break;
867 }
869 if (log_hv && FD_ISSET(xc_evtchn_fd(xce_handle), &readfds))
870 handle_hv_logs();
872 if (ret <= 0)
873 continue;
875 if (FD_ISSET(xs_fileno(xs), &readfds))
876 handle_xs();
878 for (d = dom_head; d; d = n) {
879 n = d->next;
880 if (d->xce_handle != -1 &&
881 FD_ISSET(xc_evtchn_fd(d->xce_handle), &readfds))
882 handle_ring_read(d);
884 if (d->tty_fd != -1 && FD_ISSET(d->tty_fd, &readfds))
885 handle_tty_read(d);
887 if (d->tty_fd != -1 && FD_ISSET(d->tty_fd, &writefds))
888 handle_tty_write(d);
890 if (d->is_dead)
891 cleanup_domain(d);
892 }
893 }
895 out:
896 if (log_hv_fd != -1) {
897 close(log_hv_fd);
898 log_hv_fd = -1;
899 }
900 if (xc_handle != -1) {
901 xc_interface_close(xc_handle);
902 xc_handle = -1;
903 }
904 if (xce_handle != -1) {
905 xc_evtchn_close(xce_handle);
906 xce_handle = -1;
907 }
908 log_hv_evtchn = -1;
909 }
911 /*
912 * Local variables:
913 * c-file-style: "linux"
914 * indent-tabs-mode: t
915 * c-indent-level: 8
916 * c-basic-offset: 8
917 * tab-width: 8
918 * End:
919 */