ia64/xen-unstable

view tools/console/daemon/io.c @ 17838:e5c9c8e6e726

tools: replace sprintf with snprintf where applicable

Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jun 12 15:41:15 2008 +0100 (2008-06-12)
parents 78d0a147216f
children 750eee596adf
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 #include <sys/time.h>
39 #include <assert.h>
40 #if defined(__NetBSD__) || defined(__OpenBSD__)
41 #include <util.h>
42 #elif defined(__linux__) || defined(__Linux__)
43 #include <pty.h>
44 #endif
45 #if defined(__sun__)
46 #include <stropts.h>
47 #endif
49 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
50 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
52 /* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */
53 #define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2)
55 /* How many events are allowed in each time period */
56 #define RATE_LIMIT_ALLOWANCE 30
57 /* Duration of each time period in ms */
58 #define RATE_LIMIT_PERIOD 200
60 extern int log_reload;
61 extern int log_guest;
62 extern int log_hv;
63 extern int log_time_hv;
64 extern int log_time_guest;
65 extern char *log_dir;
66 extern int discard_overflowed_data;
68 static int log_time_hv_needts = 1;
69 static int log_time_guest_needts = 1;
70 static int log_hv_fd = -1;
71 static evtchn_port_or_error_t log_hv_evtchn = -1;
72 static int xc_handle = -1;
73 static int xce_handle = -1;
75 struct buffer {
76 char *data;
77 size_t consumed;
78 size_t size;
79 size_t capacity;
80 size_t max_capacity;
81 };
83 struct domain {
84 int domid;
85 int master_fd;
86 int slave_fd;
87 int log_fd;
88 bool is_dead;
89 struct buffer buffer;
90 struct domain *next;
91 char *conspath;
92 char *serialpath;
93 int use_consolepath;
94 int ring_ref;
95 evtchn_port_or_error_t local_port;
96 evtchn_port_or_error_t remote_port;
97 int xce_handle;
98 struct xencons_interface *interface;
99 int event_count;
100 long long next_period;
101 };
103 static struct domain *dom_head;
105 static int write_all(int fd, const char* buf, size_t len)
106 {
107 while (len) {
108 ssize_t ret = write(fd, buf, len);
109 if (ret == -1 && errno == EINTR)
110 continue;
111 if (ret <= 0)
112 return -1;
113 len -= ret;
114 buf += ret;
115 }
117 return 0;
118 }
120 static int write_with_timestamp(int fd, const char *data, size_t sz,
121 int *needts)
122 {
123 char ts[32];
124 time_t now = time(NULL);
125 const struct tm *tmnow = localtime(&now);
126 size_t tslen = strftime(ts, sizeof(ts), "[%Y-%m-%d %H:%M:%S] ", tmnow);
127 const char *last_byte = data + sz - 1;
129 while (data <= last_byte) {
130 const char *nl = memchr(data, '\n', sz);
131 int found_nl = (nl != NULL);
132 if (!found_nl)
133 nl = last_byte;
135 if ((*needts && write_all(fd, ts, tslen))
136 || write_all(fd, data, nl + 1 - data))
137 return -1;
139 *needts = found_nl;
140 data = nl + 1;
141 if (found_nl) {
142 // If we printed a newline, strip all \r following it
143 while (data <= last_byte && *data == '\r')
144 data++;
145 }
146 }
148 return 0;
149 }
151 static void buffer_append(struct domain *dom)
152 {
153 struct buffer *buffer = &dom->buffer;
154 XENCONS_RING_IDX cons, prod, size;
155 struct xencons_interface *intf = dom->interface;
157 cons = intf->out_cons;
158 prod = intf->out_prod;
159 xen_mb();
161 size = prod - cons;
162 if ((size == 0) || (size > sizeof(intf->out)))
163 return;
165 if ((buffer->capacity - buffer->size) < size) {
166 buffer->capacity += (size + 1024);
167 buffer->data = realloc(buffer->data, buffer->capacity);
168 if (buffer->data == NULL) {
169 dolog(LOG_ERR, "Memory allocation failed");
170 exit(ENOMEM);
171 }
172 }
174 while (cons != prod)
175 buffer->data[buffer->size++] = intf->out[
176 MASK_XENCONS_IDX(cons++, intf->out)];
178 xen_mb();
179 intf->out_cons = cons;
180 xc_evtchn_notify(dom->xce_handle, dom->local_port);
182 /* Get the data to the logfile as early as possible because if
183 * no one is listening on the console pty then it will fill up
184 * and handle_tty_write will stop being called.
185 */
186 if (dom->log_fd != -1) {
187 int logret;
188 if (log_time_guest) {
189 logret = write_with_timestamp(
190 dom->log_fd,
191 buffer->data + buffer->size - size,
192 size, &log_time_guest_needts);
193 } else {
194 logret = write_all(
195 dom->log_fd,
196 buffer->data + buffer->size - size,
197 size);
198 }
199 if (logret < 0)
200 dolog(LOG_ERR, "Write to log failed "
201 "on domain %d: %d (%s)\n",
202 dom->domid, errno, strerror(errno));
203 }
205 if (discard_overflowed_data && buffer->max_capacity &&
206 buffer->size > buffer->max_capacity) {
207 /* Discard the middle of the data. */
209 size_t over = buffer->size - buffer->max_capacity;
210 char *maxpos = buffer->data + buffer->max_capacity;
212 memmove(maxpos - over, maxpos, over);
213 buffer->data = realloc(buffer->data, buffer->max_capacity);
214 buffer->size = buffer->capacity = buffer->max_capacity;
216 if (buffer->consumed > buffer->max_capacity - over)
217 buffer->consumed = buffer->max_capacity - over;
218 }
219 }
221 static bool buffer_empty(struct buffer *buffer)
222 {
223 return buffer->size == 0;
224 }
226 static void buffer_advance(struct buffer *buffer, size_t len)
227 {
228 buffer->consumed += len;
229 if (buffer->consumed == buffer->size) {
230 buffer->consumed = 0;
231 buffer->size = 0;
232 if (buffer->max_capacity &&
233 buffer->capacity > buffer->max_capacity) {
234 buffer->data = realloc(buffer->data, buffer->max_capacity);
235 buffer->capacity = buffer->max_capacity;
236 }
237 }
238 }
240 static bool domain_is_valid(int domid)
241 {
242 bool ret;
243 xc_dominfo_t info;
245 ret = (xc_domain_getinfo(xc, domid, 1, &info) == 1 &&
246 info.domid == domid);
248 return ret;
249 }
251 static int create_hv_log(void)
252 {
253 char logfile[PATH_MAX];
254 int fd;
255 snprintf(logfile, PATH_MAX-1, "%s/hypervisor.log", log_dir);
256 logfile[PATH_MAX-1] = '\0';
258 fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644);
259 if (fd == -1)
260 dolog(LOG_ERR, "Failed to open log %s: %d (%s)",
261 logfile, errno, strerror(errno));
262 if (fd != -1 && log_time_hv) {
263 if (write_with_timestamp(fd, "Logfile Opened",
264 strlen("Logfile Opened"),
265 &log_time_hv_needts) < 0) {
266 dolog(LOG_ERR, "Failed to log opening timestamp "
267 "in %s: %d (%s)", logfile, errno,
268 strerror(errno));
269 return -1;
270 }
271 }
272 return fd;
273 }
275 static int create_domain_log(struct domain *dom)
276 {
277 char logfile[PATH_MAX];
278 char *namepath, *data, *s;
279 int fd;
280 unsigned int len;
282 namepath = xs_get_domain_path(xs, dom->domid);
283 s = realloc(namepath, strlen(namepath) + 6);
284 if (s == NULL) {
285 free(namepath);
286 return -1;
287 }
288 namepath = s;
289 strcat(namepath, "/name");
290 data = xs_read(xs, XBT_NULL, namepath, &len);
291 if (!data)
292 return -1;
293 if (!len) {
294 free(data);
295 return -1;
296 }
298 snprintf(logfile, PATH_MAX-1, "%s/guest-%s.log", log_dir, data);
299 free(data);
300 logfile[PATH_MAX-1] = '\0';
302 fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644);
303 if (fd == -1)
304 dolog(LOG_ERR, "Failed to open log %s: %d (%s)",
305 logfile, errno, strerror(errno));
306 if (fd != -1 && log_time_guest) {
307 if (write_with_timestamp(fd, "Logfile Opened",
308 strlen("Logfile Opened"),
309 &log_time_guest_needts) < 0) {
310 dolog(LOG_ERR, "Failed to log opening timestamp "
311 "in %s: %d (%s)", logfile, errno,
312 strerror(errno));
313 return -1;
314 }
315 }
316 return fd;
317 }
319 static void domain_close_tty(struct domain *dom)
320 {
321 if (dom->master_fd != -1) {
322 close(dom->master_fd);
323 dom->master_fd = -1;
324 }
326 if (dom->slave_fd != -1) {
327 close(dom->slave_fd);
328 dom->slave_fd = -1;
329 }
330 }
332 #ifdef __sun__
333 static int openpty(int *amaster, int *aslave, char *name,
334 struct termios *termp, struct winsize *winp)
335 {
336 const char *slave;
337 int mfd = -1, sfd = -1;
339 *amaster = *aslave = -1;
341 mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
342 if (mfd < 0)
343 goto err;
345 if (grantpt(mfd) == -1 || unlockpt(mfd) == -1)
346 goto err;
348 if ((slave = ptsname(mfd)) == NULL)
349 goto err;
351 if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1)
352 goto err;
354 if (ioctl(sfd, I_PUSH, "ptem") == -1)
355 goto err;
357 if (amaster)
358 *amaster = mfd;
359 if (aslave)
360 *aslave = sfd;
361 if (winp)
362 ioctl(sfd, TIOCSWINSZ, winp);
364 if (termp)
365 tcsetattr(sfd, TCSAFLUSH, termp);
367 assert(name == NULL);
369 return 0;
371 err:
372 if (sfd != -1)
373 close(sfd);
374 close(mfd);
375 return -1;
376 }
378 void cfmakeraw(struct termios *termios_p)
379 {
380 termios_p->c_iflag &=
381 ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
382 termios_p->c_oflag &= ~OPOST;
383 termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
384 termios_p->c_cflag &= ~(CSIZE|PARENB);
385 termios_p->c_cflag |= CS8;
387 termios_p->c_cc[VMIN] = 0;
388 termios_p->c_cc[VTIME] = 0;
389 }
390 #endif /* __sun__ */
392 static int domain_create_tty(struct domain *dom)
393 {
394 const char *slave;
395 char *path;
396 int err;
397 bool success;
398 char *data;
399 unsigned int len;
400 struct termios term;
402 assert(dom->slave_fd == -1);
403 assert(dom->master_fd == -1);
405 cfmakeraw(&term);
407 if (openpty(&dom->master_fd, &dom->slave_fd, NULL, &term, NULL) < 0) {
408 err = errno;
409 dolog(LOG_ERR, "Failed to create tty for domain-%d "
410 "(errno = %i, %s)",
411 dom->domid, err, strerror(err));
412 return 0;
413 }
415 if ((slave = ptsname(dom->master_fd)) == NULL) {
416 err = errno;
417 dolog(LOG_ERR, "Failed to get slave name for domain-%d "
418 "(errno = %i, %s)",
419 dom->domid, err, strerror(err));
420 goto out;
421 }
423 if (dom->use_consolepath) {
424 success = asprintf(&path, "%s/limit", dom->conspath) !=
425 -1;
426 if (!success)
427 goto out;
428 data = xs_read(xs, XBT_NULL, path, &len);
429 if (data) {
430 dom->buffer.max_capacity = strtoul(data, 0, 0);
431 free(data);
432 }
433 free(path);
434 }
436 success = asprintf(&path, "%s/limit", dom->serialpath) != -1;
437 if (!success)
438 goto out;
439 data = xs_read(xs, XBT_NULL, path, &len);
440 if (data) {
441 dom->buffer.max_capacity = strtoul(data, 0, 0);
442 free(data);
443 }
444 free(path);
446 success = asprintf(&path, "%s/tty", dom->serialpath) != -1;
447 if (!success)
448 goto out;
449 success = xs_write(xs, XBT_NULL, path, slave, strlen(slave));
450 free(path);
451 if (!success)
452 goto out;
454 if (dom->use_consolepath) {
455 success = (asprintf(&path, "%s/tty", dom->conspath) != -1);
456 if (!success)
457 goto out;
458 success = xs_write(xs, XBT_NULL, path, slave, strlen(slave));
459 free(path);
460 if (!success)
461 goto out;
462 }
464 if (fcntl(dom->master_fd, F_SETFL, O_NONBLOCK) == -1)
465 goto out;
467 return 1;
468 out:
469 domain_close_tty(dom);
470 return 0;
471 }
473 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
474 int xs_gather(struct xs_handle *xs, const char *dir, ...)
475 {
476 va_list ap;
477 const char *name;
478 char *path;
479 int ret = 0;
481 va_start(ap, dir);
482 while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
483 const char *fmt = va_arg(ap, char *);
484 void *result = va_arg(ap, void *);
485 char *p;
487 if (asprintf(&path, "%s/%s", dir, name) == -1) {
488 ret = ENOMEM;
489 break;
490 }
491 p = xs_read(xs, XBT_NULL, path, NULL);
492 free(path);
493 if (p == NULL) {
494 ret = ENOENT;
495 break;
496 }
497 if (fmt) {
498 if (sscanf(p, fmt, result) == 0)
499 ret = EINVAL;
500 free(p);
501 } else
502 *(char **)result = p;
503 }
504 va_end(ap);
505 return ret;
506 }
508 static int domain_create_ring(struct domain *dom)
509 {
510 int err, remote_port, ring_ref, rc;
511 char *type, path[PATH_MAX];
513 err = xs_gather(xs, dom->serialpath,
514 "ring-ref", "%u", &ring_ref,
515 "port", "%i", &remote_port,
516 NULL);
517 if (err) {
518 err = xs_gather(xs, dom->conspath,
519 "ring-ref", "%u", &ring_ref,
520 "port", "%i", &remote_port,
521 NULL);
522 if (err)
523 goto out;
524 dom->use_consolepath = 1;
525 } else
526 dom->use_consolepath = 0;
528 snprintf(path, sizeof(path), "%s/type",
529 dom->use_consolepath ? dom->conspath: dom->serialpath);
530 type = xs_read(xs, XBT_NULL, path, NULL);
531 if (type && strcmp(type, "xenconsoled") != 0) {
532 free(type);
533 return 0;
534 }
535 free(type);
537 if ((ring_ref == dom->ring_ref) && (remote_port == dom->remote_port))
538 goto out;
540 if (ring_ref != dom->ring_ref) {
541 if (dom->interface != NULL)
542 munmap(dom->interface, getpagesize());
543 dom->interface = xc_map_foreign_range(
544 xc, dom->domid, getpagesize(),
545 PROT_READ|PROT_WRITE,
546 (unsigned long)ring_ref);
547 if (dom->interface == NULL) {
548 err = EINVAL;
549 goto out;
550 }
551 dom->ring_ref = ring_ref;
552 }
554 dom->local_port = -1;
555 dom->remote_port = -1;
556 if (dom->xce_handle != -1)
557 xc_evtchn_close(dom->xce_handle);
559 /* Opening evtchn independently for each console is a bit
560 * wasteful, but that's how the code is structured... */
561 dom->xce_handle = xc_evtchn_open();
562 if (dom->xce_handle == -1) {
563 err = errno;
564 goto out;
565 }
567 rc = xc_evtchn_bind_interdomain(dom->xce_handle,
568 dom->domid, remote_port);
570 if (rc == -1) {
571 err = errno;
572 xc_evtchn_close(dom->xce_handle);
573 dom->xce_handle = -1;
574 goto out;
575 }
576 dom->local_port = rc;
577 dom->remote_port = remote_port;
579 if (dom->master_fd == -1) {
580 if (!domain_create_tty(dom)) {
581 err = errno;
582 xc_evtchn_close(dom->xce_handle);
583 dom->xce_handle = -1;
584 dom->local_port = -1;
585 dom->remote_port = -1;
586 goto out;
587 }
588 }
590 if (log_guest)
591 dom->log_fd = create_domain_log(dom);
593 out:
594 return err;
595 }
597 static bool watch_domain(struct domain *dom, bool watch)
598 {
599 char domid_str[3 + MAX_STRLEN(dom->domid)];
600 bool success;
602 snprintf(domid_str, sizeof(domid_str), "dom%u", dom->domid);
603 if (watch) {
604 success = xs_watch(xs, dom->serialpath, domid_str);
605 if (success) {
606 success = xs_watch(xs, dom->conspath, domid_str);
607 if (success)
608 domain_create_ring(dom);
609 else
610 xs_unwatch(xs, dom->serialpath, domid_str);
611 }
612 } else {
613 success = xs_unwatch(xs, dom->serialpath, domid_str);
614 success = xs_unwatch(xs, dom->conspath, domid_str);
615 }
617 return success;
618 }
621 static struct domain *create_domain(int domid)
622 {
623 struct domain *dom;
624 char *s;
625 struct timeval tv;
627 if (gettimeofday(&tv, NULL) < 0) {
628 dolog(LOG_ERR, "Cannot get time of day %s:%s:L%d",
629 __FILE__, __FUNCTION__, __LINE__);
630 return NULL;
631 }
633 dom = (struct domain *)malloc(sizeof(struct domain));
634 if (dom == NULL) {
635 dolog(LOG_ERR, "Out of memory %s:%s():L%d",
636 __FILE__, __FUNCTION__, __LINE__);
637 exit(ENOMEM);
638 }
640 dom->domid = domid;
642 dom->serialpath = xs_get_domain_path(xs, dom->domid);
643 s = realloc(dom->serialpath, strlen(dom->serialpath) +
644 strlen("/serial/0") + 1);
645 if (s == NULL)
646 goto out;
647 dom->serialpath = s;
648 strcat(dom->serialpath, "/serial/0");
650 dom->conspath = xs_get_domain_path(xs, dom->domid);
651 s = realloc(dom->conspath, strlen(dom->conspath) +
652 strlen("/console") + 1);
653 if (s == NULL)
654 goto out;
655 dom->conspath = s;
656 strcat(dom->conspath, "/console");
658 dom->master_fd = -1;
659 dom->slave_fd = -1;
660 dom->log_fd = -1;
662 dom->is_dead = false;
663 dom->buffer.data = 0;
664 dom->buffer.consumed = 0;
665 dom->buffer.size = 0;
666 dom->buffer.capacity = 0;
667 dom->buffer.max_capacity = 0;
668 dom->event_count = 0;
669 dom->next_period = (tv.tv_sec * 1000) + (tv.tv_usec / 1000) + RATE_LIMIT_PERIOD;
670 dom->next = NULL;
672 dom->ring_ref = -1;
673 dom->local_port = -1;
674 dom->remote_port = -1;
675 dom->interface = NULL;
676 dom->xce_handle = -1;
678 if (!watch_domain(dom, true))
679 goto out;
681 dom->next = dom_head;
682 dom_head = dom;
684 dolog(LOG_DEBUG, "New domain %d", domid);
686 return dom;
687 out:
688 free(dom->serialpath);
689 free(dom->conspath);
690 free(dom);
691 return NULL;
692 }
694 static struct domain *lookup_domain(int domid)
695 {
696 struct domain *dom;
698 for (dom = dom_head; dom; dom = dom->next)
699 if (dom->domid == domid)
700 return dom;
701 return NULL;
702 }
704 static void remove_domain(struct domain *dom)
705 {
706 struct domain **pp;
708 dolog(LOG_DEBUG, "Removing domain-%d", dom->domid);
710 for (pp = &dom_head; *pp; pp = &(*pp)->next) {
711 if (dom == *pp) {
712 *pp = dom->next;
713 free(dom);
714 break;
715 }
716 }
717 }
719 static void cleanup_domain(struct domain *d)
720 {
721 domain_close_tty(d);
723 free(d->buffer.data);
724 d->buffer.data = NULL;
726 free(d->serialpath);
727 d->serialpath = NULL;
729 free(d->conspath);
730 d->conspath = NULL;
732 remove_domain(d);
733 }
735 static void shutdown_domain(struct domain *d)
736 {
737 d->is_dead = true;
738 watch_domain(d, false);
739 if (d->interface != NULL)
740 munmap(d->interface, getpagesize());
741 d->interface = NULL;
742 if (d->xce_handle != -1)
743 xc_evtchn_close(d->xce_handle);
744 d->xce_handle = -1;
745 }
747 void enum_domains(void)
748 {
749 int domid = 1;
750 xc_dominfo_t dominfo;
751 struct domain *dom;
753 while (xc_domain_getinfo(xc, domid, 1, &dominfo) == 1) {
754 dom = lookup_domain(dominfo.domid);
755 if (dominfo.dying) {
756 if (dom)
757 shutdown_domain(dom);
758 } else {
759 if (dom == NULL)
760 create_domain(dominfo.domid);
761 }
762 domid = dominfo.domid + 1;
763 }
764 }
766 static int ring_free_bytes(struct domain *dom)
767 {
768 struct xencons_interface *intf = dom->interface;
769 XENCONS_RING_IDX cons, prod, space;
771 cons = intf->in_cons;
772 prod = intf->in_prod;
773 xen_mb();
775 space = prod - cons;
776 if (space > sizeof(intf->in))
777 return 0; /* ring is screwed: ignore it */
779 return (sizeof(intf->in) - space);
780 }
782 static void handle_tty_read(struct domain *dom)
783 {
784 ssize_t len = 0;
785 char msg[80];
786 int i;
787 struct xencons_interface *intf = dom->interface;
788 XENCONS_RING_IDX prod;
790 if (dom->is_dead)
791 return;
793 len = ring_free_bytes(dom);
794 if (len == 0)
795 return;
797 if (len > sizeof(msg))
798 len = sizeof(msg);
800 len = read(dom->master_fd, msg, len);
801 /*
802 * Note: on Solaris, len == 0 means the slave closed, and this
803 * is no problem, but Linux can't handle this usefully, so we
804 * keep the slave open for the duration.
805 */
806 if (len < 0) {
807 domain_close_tty(dom);
809 if (domain_is_valid(dom->domid)) {
810 domain_create_tty(dom);
811 } else {
812 shutdown_domain(dom);
813 }
814 } else if (domain_is_valid(dom->domid)) {
815 prod = intf->in_prod;
816 for (i = 0; i < len; i++) {
817 intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
818 msg[i];
819 }
820 xen_wmb();
821 intf->in_prod = prod;
822 xc_evtchn_notify(dom->xce_handle, dom->local_port);
823 } else {
824 domain_close_tty(dom);
825 shutdown_domain(dom);
826 }
827 }
829 static void handle_tty_write(struct domain *dom)
830 {
831 ssize_t len;
833 if (dom->is_dead)
834 return;
836 len = write(dom->master_fd, dom->buffer.data + dom->buffer.consumed,
837 dom->buffer.size - dom->buffer.consumed);
838 if (len < 1) {
839 dolog(LOG_DEBUG, "Write failed on domain %d: %zd, %d\n",
840 dom->domid, len, errno);
842 domain_close_tty(dom);
844 if (domain_is_valid(dom->domid)) {
845 domain_create_tty(dom);
846 } else {
847 shutdown_domain(dom);
848 }
849 } else {
850 buffer_advance(&dom->buffer, len);
851 }
852 }
854 static void handle_ring_read(struct domain *dom)
855 {
856 evtchn_port_or_error_t port;
858 if (dom->is_dead)
859 return;
861 if ((port = xc_evtchn_pending(dom->xce_handle)) == -1)
862 return;
864 dom->event_count++;
866 buffer_append(dom);
868 if (dom->event_count < RATE_LIMIT_ALLOWANCE)
869 (void)xc_evtchn_unmask(dom->xce_handle, port);
870 }
872 static void handle_xs(void)
873 {
874 char **vec;
875 int domid;
876 struct domain *dom;
877 unsigned int num;
879 vec = xs_read_watch(xs, &num);
880 if (!vec)
881 return;
883 if (!strcmp(vec[XS_WATCH_TOKEN], "domlist"))
884 enum_domains();
885 else if (sscanf(vec[XS_WATCH_TOKEN], "dom%u", &domid) == 1) {
886 dom = lookup_domain(domid);
887 /* We may get watches firing for domains that have recently
888 been removed, so dom may be NULL here. */
889 if (dom && dom->is_dead == false)
890 domain_create_ring(dom);
891 }
893 free(vec);
894 }
896 static void handle_hv_logs(void)
897 {
898 char buffer[1024*16];
899 char *bufptr = buffer;
900 unsigned int size = sizeof(buffer);
901 static uint32_t index = 0;
902 evtchn_port_or_error_t port;
904 if ((port = xc_evtchn_pending(xce_handle)) == -1)
905 return;
907 if (xc_readconsolering(xc_handle, &bufptr, &size, 0, 1, &index) == 0 && size > 0) {
908 int logret;
909 if (log_time_hv)
910 logret = write_with_timestamp(log_hv_fd, buffer, size,
911 &log_time_hv_needts);
912 else
913 logret = write_all(log_hv_fd, buffer, size);
915 if (logret < 0)
916 dolog(LOG_ERR, "Failed to write hypervisor log: "
917 "%d (%s)", errno, strerror(errno));
918 }
920 (void)xc_evtchn_unmask(xce_handle, port);
921 }
923 static void handle_log_reload(void)
924 {
925 if (log_guest) {
926 struct domain *d;
927 for (d = dom_head; d; d = d->next) {
928 if (d->log_fd != -1)
929 close(d->log_fd);
930 d->log_fd = create_domain_log(d);
931 }
932 }
934 if (log_hv) {
935 if (log_hv_fd != -1)
936 close(log_hv_fd);
937 log_hv_fd = create_hv_log();
938 }
939 }
941 void handle_io(void)
942 {
943 fd_set readfds, writefds;
944 int ret;
946 if (log_hv) {
947 xc_handle = xc_interface_open();
948 if (xc_handle == -1) {
949 dolog(LOG_ERR, "Failed to open xc handle: %d (%s)",
950 errno, strerror(errno));
951 goto out;
952 }
953 xce_handle = xc_evtchn_open();
954 if (xce_handle == -1) {
955 dolog(LOG_ERR, "Failed to open xce handle: %d (%s)",
956 errno, strerror(errno));
957 goto out;
958 }
959 log_hv_fd = create_hv_log();
960 if (log_hv_fd == -1)
961 goto out;
962 log_hv_evtchn = xc_evtchn_bind_virq(xce_handle, VIRQ_CON_RING);
963 if (log_hv_evtchn == -1) {
964 dolog(LOG_ERR, "Failed to bind to VIRQ_CON_RING: "
965 "%d (%s)", errno, strerror(errno));
966 goto out;
967 }
968 }
970 for (;;) {
971 struct domain *d, *n;
972 int max_fd = -1;
973 struct timeval timeout;
974 struct timeval tv;
975 long long now, next_timeout = 0;
977 FD_ZERO(&readfds);
978 FD_ZERO(&writefds);
980 FD_SET(xs_fileno(xs), &readfds);
981 max_fd = MAX(xs_fileno(xs), max_fd);
983 if (log_hv) {
984 FD_SET(xc_evtchn_fd(xce_handle), &readfds);
985 max_fd = MAX(xc_evtchn_fd(xce_handle), max_fd);
986 }
988 if (gettimeofday(&tv, NULL) < 0)
989 return;
990 now = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
992 /* Re-calculate any event counter allowances & unblock
993 domains with new allowance */
994 for (d = dom_head; d; d = d->next) {
995 /* Add 5ms of fuzz since select() often returns
996 a couple of ms sooner than requested. Without
997 the fuzz we typically do an extra spin in select()
998 with a 1/2 ms timeout every other iteration */
999 if ((now+5) > d->next_period) {
1000 d->next_period = now + RATE_LIMIT_PERIOD;
1001 if (d->event_count >= RATE_LIMIT_ALLOWANCE) {
1002 (void)xc_evtchn_unmask(d->xce_handle, d->local_port);
1004 d->event_count = 0;
1008 for (d = dom_head; d; d = d->next) {
1009 if (d->event_count >= RATE_LIMIT_ALLOWANCE) {
1010 /* Determine if we're going to be the next time slice to expire */
1011 if (!next_timeout ||
1012 d->next_period < next_timeout)
1013 next_timeout = d->next_period;
1014 } else if (d->xce_handle != -1) {
1015 if (discard_overflowed_data ||
1016 !d->buffer.max_capacity ||
1017 d->buffer.size < d->buffer.max_capacity) {
1018 int evtchn_fd = xc_evtchn_fd(d->xce_handle);
1019 FD_SET(evtchn_fd, &readfds);
1020 max_fd = MAX(evtchn_fd, max_fd);
1024 if (d->master_fd != -1) {
1025 if (!d->is_dead && ring_free_bytes(d))
1026 FD_SET(d->master_fd, &readfds);
1028 if (!buffer_empty(&d->buffer))
1029 FD_SET(d->master_fd, &writefds);
1030 max_fd = MAX(d->master_fd, max_fd);
1034 /* If any domain has been rate limited, we need to work
1035 out what timeout to supply to select */
1036 if (next_timeout) {
1037 long long duration = (next_timeout - now);
1038 if (duration <= 0) /* sanity check */
1039 duration = 1;
1040 timeout.tv_sec = duration / 1000;
1041 timeout.tv_usec = ((duration - (timeout.tv_sec * 1000))
1042 * 1000);
1045 ret = select(max_fd + 1, &readfds, &writefds, 0,
1046 next_timeout ? &timeout : NULL);
1048 if (log_reload) {
1049 handle_log_reload();
1050 log_reload = 0;
1053 /* Abort if select failed, except for EINTR cases
1054 which indicate a possible log reload */
1055 if (ret == -1) {
1056 if (errno == EINTR)
1057 continue;
1058 dolog(LOG_ERR, "Failure in select: %d (%s)",
1059 errno, strerror(errno));
1060 break;
1063 if (log_hv && FD_ISSET(xc_evtchn_fd(xce_handle), &readfds))
1064 handle_hv_logs();
1066 if (ret <= 0)
1067 continue;
1069 if (FD_ISSET(xs_fileno(xs), &readfds))
1070 handle_xs();
1072 for (d = dom_head; d; d = n) {
1073 n = d->next;
1074 if (d->event_count < RATE_LIMIT_ALLOWANCE) {
1075 if (d->xce_handle != -1 &&
1076 FD_ISSET(xc_evtchn_fd(d->xce_handle),
1077 &readfds))
1078 handle_ring_read(d);
1081 if (d->master_fd != -1 && FD_ISSET(d->master_fd,
1082 &readfds))
1083 handle_tty_read(d);
1085 if (d->master_fd != -1 && FD_ISSET(d->master_fd,
1086 &writefds))
1087 handle_tty_write(d);
1089 if (d->is_dead)
1090 cleanup_domain(d);
1094 out:
1095 if (log_hv_fd != -1) {
1096 close(log_hv_fd);
1097 log_hv_fd = -1;
1099 if (xc_handle != -1) {
1100 xc_interface_close(xc_handle);
1101 xc_handle = -1;
1103 if (xce_handle != -1) {
1104 xc_evtchn_close(xce_handle);
1105 xce_handle = -1;
1107 log_hv_evtchn = -1;
1110 /*
1111 * Local variables:
1112 * c-file-style: "linux"
1113 * indent-tabs-mode: t
1114 * c-indent-level: 8
1115 * c-basic-offset: 8
1116 * tab-width: 8
1117 * End:
1118 */