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