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