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