1 /*
2 * Copyright 2009-2017 Citrix Ltd and other contributors
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published
6 * by the Free Software Foundation; version 2.1 only. with the special
7 * exception on linking described in file LICENSE.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 */
14
15 #include "libxl_osdeps.h"
16
17 #include "libxl_internal.h"
18
libxl__console_tty_path(libxl__gc * gc,uint32_t domid,int cons_num,libxl_console_type type,char ** tty_path)19 int libxl__console_tty_path(libxl__gc *gc, uint32_t domid, int cons_num,
20 libxl_console_type type, char **tty_path)
21 {
22 int rc;
23 char *dom_path;
24
25 dom_path = libxl__xs_get_dompath(gc, domid);
26 if (!dom_path) {
27 rc = ERROR_FAIL;
28 goto out;
29 }
30
31 switch (type) {
32 case LIBXL_CONSOLE_TYPE_SERIAL:
33 *tty_path = GCSPRINTF("%s/serial/%d/tty", dom_path, cons_num);
34 rc = 0;
35 break;
36 case LIBXL_CONSOLE_TYPE_PV:
37 if (cons_num == 0)
38 *tty_path = GCSPRINTF("%s/console/tty", dom_path);
39 else
40 *tty_path = GCSPRINTF("%s/tty",
41 libxl__domain_device_frontend_path(gc, domid,
42 cons_num, LIBXL__DEVICE_KIND_CONSOLE));
43 rc = 0;
44 break;
45 default:
46 rc = ERROR_INVAL;
47 goto out;
48 }
49
50 out:
51 return rc;
52 }
53
libxl_console_exec(libxl_ctx * ctx,uint32_t domid,int cons_num,libxl_console_type type,int notify_fd,char * escape_character)54 int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num,
55 libxl_console_type type, int notify_fd,
56 char* escape_character)
57 {
58 GC_INIT(ctx);
59 char *p = GCSPRINTF("%s/xenconsole", libxl__private_bindir_path());
60 char *domid_s = GCSPRINTF("%d", domid);
61 char *cons_num_s = GCSPRINTF("%d", cons_num);
62 char *notify_fd_s;
63 char *cons_type_s;
64
65 switch (type) {
66 case LIBXL_CONSOLE_TYPE_PV:
67 cons_type_s = "pv";
68 break;
69 case LIBXL_CONSOLE_TYPE_SERIAL:
70 cons_type_s = "serial";
71 break;
72 case LIBXL_CONSOLE_TYPE_VUART:
73 cons_type_s = "vuart";
74 break;
75 default:
76 goto out;
77 }
78
79 char *args[] = {
80 p, domid_s, "--num", cons_num_s, "--type", cons_type_s,
81 NULL, NULL, NULL, NULL, /* start-notify-fd, escape */
82 NULL, /* list terminator - do not use */
83 };
84 char **args_extra = args + 6;
85
86 if (notify_fd != -1) {
87 notify_fd_s = GCSPRINTF("%d", notify_fd);
88 *args_extra++ = "--start-notify-fd";
89 *args_extra++ = notify_fd_s;
90 }
91
92 if (escape_character) {
93 *args_extra++ = "--escape";
94 *args_extra++ = escape_character;
95 }
96
97 execv(p, args);
98
99 out:
100 GC_FREE;
101 return ERROR_FAIL;
102 }
103
libxl_console_get_tty(libxl_ctx * ctx,uint32_t domid,int cons_num,libxl_console_type type,char ** path)104 int libxl_console_get_tty(libxl_ctx *ctx, uint32_t domid, int cons_num,
105 libxl_console_type type, char **path)
106 {
107 GC_INIT(ctx);
108 char *tty_path;
109 char *tty;
110 int rc;
111
112 rc = libxl__console_tty_path(gc, domid, cons_num, type, &tty_path);
113 if (rc) {
114 LOGD(ERROR, domid, "Failed to get tty path\n");
115 goto out;
116 }
117
118 tty = libxl__xs_read(gc, XBT_NULL, tty_path);
119 if (!tty || tty[0] == '\0') {
120 LOGED(ERROR, domid, "Unable to read console tty path `%s'",
121 tty_path);
122 rc = ERROR_FAIL;
123 goto out;
124 }
125
126 *path = libxl__strdup(NOGC, tty);
127 rc = 0;
128 out:
129 GC_FREE;
130 return rc;
131 }
132
libxl__primary_console_find(libxl_ctx * ctx,uint32_t domid_vm,uint32_t * domid,int * cons_num,libxl_console_type * type)133 static int libxl__primary_console_find(libxl_ctx *ctx, uint32_t domid_vm,
134 uint32_t *domid, int *cons_num,
135 libxl_console_type *type)
136 {
137 GC_INIT(ctx);
138 uint32_t stubdomid = libxl_get_stubdom_id(ctx, domid_vm);
139 int rc;
140
141 if (stubdomid) {
142 *domid = stubdomid;
143 *cons_num = STUBDOM_CONSOLE_SERIAL;
144 *type = LIBXL_CONSOLE_TYPE_PV;
145 } else {
146 switch (libxl__domain_type(gc, domid_vm)) {
147 case LIBXL_DOMAIN_TYPE_HVM:
148 *domid = domid_vm;
149 *cons_num = 0;
150 *type = LIBXL_CONSOLE_TYPE_SERIAL;
151 break;
152 case LIBXL_DOMAIN_TYPE_PVH:
153 case LIBXL_DOMAIN_TYPE_PV:
154 *domid = domid_vm;
155 *cons_num = 0;
156 *type = LIBXL_CONSOLE_TYPE_PV;
157 break;
158 case LIBXL_DOMAIN_TYPE_INVALID:
159 rc = ERROR_INVAL;
160 goto out;
161 default: abort();
162 }
163 }
164
165 rc = 0;
166 out:
167 GC_FREE;
168 return rc;
169 }
170
libxl_primary_console_exec(libxl_ctx * ctx,uint32_t domid_vm,int notify_fd,char * escape_character)171 int libxl_primary_console_exec(libxl_ctx *ctx, uint32_t domid_vm, int notify_fd,
172 char* escape_character)
173 {
174 uint32_t domid;
175 int cons_num;
176 libxl_console_type type;
177 int rc;
178
179 rc = libxl__primary_console_find(ctx, domid_vm, &domid, &cons_num, &type);
180 if ( rc ) return rc;
181 return libxl_console_exec(ctx, domid, cons_num, type, notify_fd,
182 escape_character);
183 }
184
libxl_primary_console_get_tty(libxl_ctx * ctx,uint32_t domid_vm,char ** path)185 int libxl_primary_console_get_tty(libxl_ctx *ctx, uint32_t domid_vm,
186 char **path)
187 {
188 uint32_t domid;
189 int cons_num;
190 libxl_console_type type;
191 int rc;
192
193 rc = libxl__primary_console_find(ctx, domid_vm, &domid, &cons_num, &type);
194 if ( rc ) return rc;
195 return libxl_console_get_tty(ctx, domid, cons_num, type, path);
196 }
197
libxl_vncviewer_exec(libxl_ctx * ctx,uint32_t domid,int autopass)198 int libxl_vncviewer_exec(libxl_ctx *ctx, uint32_t domid, int autopass)
199 {
200 GC_INIT(ctx);
201 const char *vnc_port;
202 const char *vnc_listen = NULL, *vnc_pass = NULL;
203 int port = 0, autopass_fd = -1;
204 char *vnc_bin, *args[] = {
205 "vncviewer",
206 NULL, /* hostname:display */
207 NULL, /* -autopass */
208 NULL,
209 };
210
211 vnc_port = libxl__xs_read(gc, XBT_NULL,
212 GCSPRINTF(
213 "/local/domain/%d/console/vnc-port", domid));
214 if (!vnc_port) {
215 LOGD(ERROR, domid, "Cannot get vnc-port");
216 goto x_fail;
217 }
218
219 port = atoi(vnc_port) - 5900;
220
221 vnc_listen = libxl__xs_read(gc, XBT_NULL,
222 GCSPRINTF("/local/domain/%d/console/vnc-listen",
223 domid));
224
225 if ( autopass )
226 vnc_pass = libxl__xs_read(gc, XBT_NULL,
227 GCSPRINTF("/local/domain/%d/console/vnc-pass",
228 domid));
229
230 if ( NULL == vnc_listen )
231 vnc_listen = "localhost";
232
233 if ( (vnc_bin = getenv("VNCVIEWER")) )
234 args[0] = vnc_bin;
235
236 args[1] = GCSPRINTF("%s:%d", vnc_listen, port);
237
238 if ( vnc_pass ) {
239 char tmpname[] = "/tmp/vncautopass.XXXXXX";
240 autopass_fd = mkstemp(tmpname);
241 if ( autopass_fd < 0 ) {
242 LOGED(ERROR, domid, "mkstemp %s failed", tmpname);
243 goto x_fail;
244 }
245
246 if ( unlink(tmpname) ) {
247 /* should never happen */
248 LOGED(ERROR, domid, "unlink %s failed", tmpname);
249 goto x_fail;
250 }
251
252 if ( libxl_write_exactly(ctx, autopass_fd, vnc_pass, strlen(vnc_pass),
253 tmpname, "vnc password") )
254 goto x_fail;
255
256 if ( lseek(autopass_fd, SEEK_SET, 0) ) {
257 LOGED(ERROR, domid, "rewind %s (autopass) failed", tmpname);
258 goto x_fail;
259 }
260
261 args[2] = "-autopass";
262 }
263
264 libxl__exec(gc, autopass_fd, -1, -1, args[0], args, NULL);
265
266 x_fail:
267 GC_FREE;
268 return ERROR_FAIL;
269 }
270
libxl__device_console_add(libxl__gc * gc,uint32_t domid,libxl__device_console * console,libxl__domain_build_state * state,libxl__device * device)271 int libxl__device_console_add(libxl__gc *gc, uint32_t domid,
272 libxl__device_console *console,
273 libxl__domain_build_state *state,
274 libxl__device *device)
275 {
276 flexarray_t *front, *ro_front;
277 flexarray_t *back;
278 int rc;
279
280 if (console->devid && state) {
281 rc = ERROR_INVAL;
282 goto out;
283 }
284 if (!console->devid && (console->name || console->path)) {
285 LOGD(ERROR, domid, "Primary console has invalid configuration");
286 rc = ERROR_INVAL;
287 goto out;
288 }
289
290 front = flexarray_make(gc, 16, 1);
291 ro_front = flexarray_make(gc, 16, 1);
292 back = flexarray_make(gc, 16, 1);
293
294 device->backend_devid = console->devid;
295 device->backend_domid = console->backend_domid;
296 device->backend_kind = LIBXL__DEVICE_KIND_CONSOLE;
297 device->devid = console->devid;
298 device->domid = domid;
299 device->kind = LIBXL__DEVICE_KIND_CONSOLE;
300
301 flexarray_append(back, "frontend-id");
302 flexarray_append(back, GCSPRINTF("%d", domid));
303 flexarray_append(back, "online");
304 flexarray_append(back, "1");
305 flexarray_append(back, "state");
306 flexarray_append(back, GCSPRINTF("%d", XenbusStateInitialising));
307 flexarray_append(back, "protocol");
308 flexarray_append(back, LIBXL_XENCONSOLE_PROTOCOL);
309
310 if (console->name) {
311 flexarray_append(ro_front, "name");
312 flexarray_append(ro_front, console->name);
313 flexarray_append(back, "name");
314 flexarray_append(back, console->name);
315 }
316 if (console->connection) {
317 flexarray_append(back, "connection");
318 flexarray_append(back, console->connection);
319 }
320 if (console->path) {
321 flexarray_append(back, "path");
322 flexarray_append(back, console->path);
323 }
324
325 flexarray_append(front, "backend-id");
326 flexarray_append(front, GCSPRINTF("%d", console->backend_domid));
327
328 flexarray_append(ro_front, "limit");
329 flexarray_append(ro_front, GCSPRINTF("%d", LIBXL_XENCONSOLE_LIMIT));
330 flexarray_append(ro_front, "type");
331 if (console->consback == LIBXL__CONSOLE_BACKEND_XENCONSOLED)
332 flexarray_append(ro_front, "xenconsoled");
333 else
334 flexarray_append(ro_front, "ioemu");
335 flexarray_append(ro_front, "output");
336 flexarray_append(ro_front, console->output);
337 flexarray_append(ro_front, "tty");
338 if (state && state->console_tty)
339 flexarray_append(ro_front, state->console_tty);
340 else
341 flexarray_append(ro_front, "");
342
343 if (state) {
344 flexarray_append(ro_front, "port");
345 flexarray_append(ro_front, GCSPRINTF("%"PRIu32, state->console_port));
346 flexarray_append(ro_front, "ring-ref");
347 flexarray_append(ro_front, GCSPRINTF("%lu", state->console_mfn));
348 } else {
349 flexarray_append(front, "state");
350 flexarray_append(front, GCSPRINTF("%d", XenbusStateInitialising));
351 flexarray_append(front, "protocol");
352 flexarray_append(front, LIBXL_XENCONSOLE_PROTOCOL);
353 }
354 rc = libxl__device_generic_add(gc, XBT_NULL, device,
355 libxl__xs_kvs_of_flexarray(gc, back),
356 libxl__xs_kvs_of_flexarray(gc, front),
357 libxl__xs_kvs_of_flexarray(gc, ro_front));
358 out:
359 return rc;
360 }
361
libxl_console_add_xenstore(libxl_ctx * ctx,uint32_t domid,uint32_t backend,unsigned int evtch,unsigned long gfn,const libxl_asyncop_how * ao_how)362 int libxl_console_add_xenstore(libxl_ctx *ctx, uint32_t domid, uint32_t backend,
363 unsigned int evtch, unsigned long gfn,
364 const libxl_asyncop_how *ao_how)
365 {
366 AO_CREATE(ctx, domid, ao_how);
367 int rc;
368 libxl__device_console console = { .backend_domid = backend,
369 .output = "pty",
370 .consback = LIBXL__CONSOLE_BACKEND_XENCONSOLED,
371 };
372 libxl__domain_build_state state = { .console_port = evtch,
373 .console_mfn = gfn,
374 };
375 libxl__device device = { };
376
377 rc = libxl__device_console_add(gc, domid, &console, &state, &device);
378 if (rc < 0)
379 LOGED(ERROR, domid, "Adding console Xenstore entries");
380
381 libxl__ao_complete(egc, ao, rc);
382 return AO_INPROGRESS;
383 }
384
libxl__device_vuart_add(libxl__gc * gc,uint32_t domid,libxl__device_console * console,libxl__domain_build_state * state)385 int libxl__device_vuart_add(libxl__gc *gc, uint32_t domid,
386 libxl__device_console *console,
387 libxl__domain_build_state *state)
388 {
389 libxl__device device;
390 flexarray_t *ro_front;
391 flexarray_t *back;
392 int rc;
393
394 ro_front = flexarray_make(gc, 16, 1);
395 back = flexarray_make(gc, 16, 1);
396
397 device.backend_devid = console->devid;
398 device.backend_domid = console->backend_domid;
399 device.backend_kind = LIBXL__DEVICE_KIND_VUART;
400 device.devid = console->devid;
401 device.domid = domid;
402 device.kind = LIBXL__DEVICE_KIND_VUART;
403
404 flexarray_append(back, "frontend-id");
405 flexarray_append(back, GCSPRINTF("%d", domid));
406 flexarray_append(back, "online");
407 flexarray_append(back, "1");
408 flexarray_append(back, "state");
409 flexarray_append(back, GCSPRINTF("%d", XenbusStateInitialising));
410 flexarray_append(back, "protocol");
411 flexarray_append(back, LIBXL_XENCONSOLE_PROTOCOL);
412
413 flexarray_append(ro_front, "port");
414 flexarray_append(ro_front, GCSPRINTF("%"PRIu32, state->vuart_port));
415 flexarray_append(ro_front, "ring-ref");
416 flexarray_append(ro_front, GCSPRINTF("%"PRIu_xen_pfn, state->vuart_gfn));
417 flexarray_append(ro_front, "limit");
418 flexarray_append(ro_front, GCSPRINTF("%d", LIBXL_XENCONSOLE_LIMIT));
419 flexarray_append(ro_front, "type");
420 flexarray_append(ro_front, "xenconsoled");
421
422 rc = libxl__device_generic_add(gc, XBT_NULL, &device,
423 libxl__xs_kvs_of_flexarray(gc, back),
424 NULL,
425 libxl__xs_kvs_of_flexarray(gc, ro_front));
426 return rc;
427 }
428
libxl__init_console_from_channel(libxl__gc * gc,libxl__device_console * console,int dev_num,libxl_device_channel * channel)429 int libxl__init_console_from_channel(libxl__gc *gc,
430 libxl__device_console *console,
431 int dev_num,
432 libxl_device_channel *channel)
433 {
434 int rc;
435
436 libxl__device_console_init(console);
437
438 /* Perform validation first, allocate second. */
439
440 if (channel->devid == -1)
441 channel->devid = dev_num;
442
443 if (!channel->name) {
444 LOG(ERROR, "channel %d has no name", channel->devid);
445 return ERROR_INVAL;
446 }
447
448 if (channel->backend_domname) {
449 rc = libxl_domain_qualifier_to_domid(CTX, channel->backend_domname,
450 &channel->backend_domid);
451 if (rc < 0) return rc;
452 }
453
454 /* The xenstore 'output' node tells the backend what to connect the console
455 to. If the channel has "connection = pty" then the "output" node will be
456 set to "pty". If the channel has "connection = socket" then the "output"
457 node will be set to "chardev:libxl-channel%d". This tells the qemu
458 backend to proxy data between the console ring and the character device
459 with id "libxl-channel%d". These character devices are currently defined
460 on the qemu command-line via "-chardev" options in libxl_dm.c */
461
462 switch (channel->connection) {
463 case LIBXL_CHANNEL_CONNECTION_UNKNOWN:
464 LOG(ERROR, "channel %d has no defined connection; "
465 "to where should it be connected?", channel->devid);
466 return ERROR_INVAL;
467 case LIBXL_CHANNEL_CONNECTION_PTY:
468 console->connection = libxl__strdup(NOGC, "pty");
469 console->output = libxl__sprintf(NOGC, "pty");
470 break;
471 case LIBXL_CHANNEL_CONNECTION_SOCKET:
472 if (!channel->u.socket.path) {
473 LOG(ERROR, "channel %d has no path", channel->devid);
474 return ERROR_INVAL;
475 }
476 console->connection = libxl__strdup(NOGC, "socket");
477 console->path = libxl__strdup(NOGC, channel->u.socket.path);
478 console->output = libxl__sprintf(NOGC, "chardev:libxl-channel%d",
479 channel->devid);
480 break;
481 default:
482 /* We've forgotten to add the clause */
483 LOG(ERROR, "%s: missing implementation for channel connection %d",
484 __func__, channel->connection);
485 abort();
486 }
487
488 console->devid = channel->devid;
489 console->consback = LIBXL__CONSOLE_BACKEND_IOEMU;
490 console->backend_domid = channel->backend_domid;
491 console->name = libxl__strdup(NOGC, channel->name);
492
493 return 0;
494 }
495
libxl__device_channel_from_xenstore(libxl__gc * gc,const char * libxl_path,libxl_device_channel * channel)496 static int libxl__device_channel_from_xenstore(libxl__gc *gc,
497 const char *libxl_path,
498 libxl_device_channel *channel)
499 {
500 const char *tmp;
501 int rc;
502
503 libxl_device_channel_init(channel);
504
505 rc = libxl__xs_read_checked(NOGC, XBT_NULL,
506 GCSPRINTF("%s/name", libxl_path),
507 (const char **)(&channel->name));
508 if (rc) goto out;
509 rc = libxl__xs_read_checked(gc, XBT_NULL,
510 GCSPRINTF("%s/connection", libxl_path), &tmp);
511 if (rc) goto out;
512 if (!strcmp(tmp, "pty")) {
513 channel->connection = LIBXL_CHANNEL_CONNECTION_PTY;
514 } else if (!strcmp(tmp, "socket")) {
515 channel->connection = LIBXL_CHANNEL_CONNECTION_SOCKET;
516 rc = libxl__xs_read_checked(NOGC, XBT_NULL,
517 GCSPRINTF("%s/path", libxl_path),
518 (const char **)(&channel->u.socket.path));
519 if (rc) goto out;
520 } else {
521 rc = ERROR_INVAL;
522 goto out;
523 }
524
525 rc = 0;
526 out:
527 return rc;
528 }
529
libxl__append_channel_list(libxl__gc * gc,uint32_t domid,libxl_device_channel ** channels,int * nchannels)530 static int libxl__append_channel_list(libxl__gc *gc,
531 uint32_t domid,
532 libxl_device_channel **channels,
533 int *nchannels)
534 {
535 char *libxl_dir_path = NULL;
536 char **dir = NULL;
537 unsigned int n = 0, devid = 0;
538 libxl_device_channel *next = NULL;
539 int rc = 0, i;
540
541 libxl_dir_path = GCSPRINTF("%s/device/%s",
542 libxl__xs_libxl_path(gc, domid),
543 libxl__device_kind_to_string(
544 LIBXL__DEVICE_KIND_CONSOLE));
545 dir = libxl__xs_directory(gc, XBT_NULL, libxl_dir_path, &n);
546 if (!dir || !n)
547 goto out;
548
549 for (i = 0; i < n; i++) {
550 const char *libxl_path, *name;
551 libxl_device_channel *tmp;
552
553 libxl_path = GCSPRINTF("%s/%s", libxl_dir_path, dir[i]);
554 name = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/name", libxl_path));
555 /* 'channels' are consoles with names, so ignore all consoles
556 without names */
557 if (!name) continue;
558 tmp = realloc(*channels,
559 sizeof(libxl_device_channel) * (*nchannels + devid + 1));
560 if (!tmp) {
561 rc = ERROR_NOMEM;
562 goto out;
563 }
564 *channels = tmp;
565 next = *channels + *nchannels + devid;
566 rc = libxl__device_channel_from_xenstore(gc, libxl_path, next);
567 if (rc) goto out;
568 next->devid = devid;
569 devid++;
570 }
571 *nchannels += devid;
572 return 0;
573
574 out:
575 return rc;
576 }
577
libxl_device_channel_list(libxl_ctx * ctx,uint32_t domid,int * num)578 libxl_device_channel *libxl_device_channel_list(libxl_ctx *ctx,
579 uint32_t domid,
580 int *num)
581 {
582 GC_INIT(ctx);
583 libxl_device_channel *channels = NULL;
584 int rc;
585
586 *num = 0;
587
588 rc = libxl__append_channel_list(gc, domid, &channels, num);
589 if (rc) goto out_err;
590
591 GC_FREE;
592 return channels;
593
594 out_err:
595 LOGD(ERROR, domid, "Unable to list channels");
596 while (*num) {
597 (*num)--;
598 libxl_device_channel_dispose(&channels[*num]);
599 }
600 free(channels);
601 return NULL;
602 }
603
libxl_device_channel_getinfo(libxl_ctx * ctx,uint32_t domid,const libxl_device_channel * channel,libxl_channelinfo * channelinfo)604 int libxl_device_channel_getinfo(libxl_ctx *ctx, uint32_t domid,
605 const libxl_device_channel *channel,
606 libxl_channelinfo *channelinfo)
607 {
608 GC_INIT(ctx);
609 char *fe_path, *libxl_path;
610 char *val;
611 int rc;
612
613 channelinfo->devid = channel->devid;
614
615 fe_path = libxl__domain_device_frontend_path(gc, domid,
616 channelinfo->devid + 1,
617 LIBXL__DEVICE_KIND_CONSOLE);
618 libxl_path = libxl__domain_device_libxl_path(gc, domid,
619 channelinfo->devid + 1,
620 LIBXL__DEVICE_KIND_CONSOLE);
621
622 channelinfo->backend = xs_read(ctx->xsh, XBT_NULL,
623 GCSPRINTF("%s/backend", libxl_path), NULL);
624 if (!channelinfo->backend) {
625 GC_FREE;
626 return ERROR_FAIL;
627 }
628 rc = libxl__backendpath_parse_domid(gc, channelinfo->backend,
629 &channelinfo->backend_id);
630 if (rc) goto out;
631
632 val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/state", fe_path));
633 channelinfo->state = val ? strtoul(val, NULL, 10) : -1;
634 channelinfo->frontend = libxl__strdup(NOGC, fe_path);
635 channelinfo->frontend_id = domid;
636 val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/ring-ref", fe_path));
637 channelinfo->rref = val ? strtoul(val, NULL, 10) : -1;
638 val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/port", fe_path));
639 channelinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
640
641 channelinfo->connection = channel->connection;
642 switch (channel->connection) {
643 case LIBXL_CHANNEL_CONNECTION_PTY:
644 val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/tty", fe_path));
645 /*
646 * It is obviously very wrong for this value to be in the
647 * frontend. But in XSA-175 we don't want to re-engineer
648 * this because other xenconsole code elsewhere (some
649 * even out of tree, perhaps) expects this node to be
650 * here.
651 *
652 * FE/pty is readonly for the guest. It always exists if
653 * FE does because libxl__device_console_add
654 * unconditionally creates it and nothing deletes it.
655 *
656 * The guest can delete the whole FE (which it has write
657 * privilege on) but the containing directories
658 * /local/GUEST[/device[/console]] are also RO for the
659 * guest. So if the guest deletes FE it cannot recreate
660 * it.
661 *
662 * Therefore the guest cannot cause FE/pty to contain bad
663 * data, although it can cause it to not exist.
664 */
665 if (!val) val = "/NO-SUCH-PATH";
666 channelinfo->u.pty.path = strdup(val);
667 if (channelinfo->u.pty.path == NULL)
668 abort();
669 break;
670 default:
671 break;
672 }
673 rc = 0;
674 out:
675 GC_FREE;
676 return rc;
677 }
678
libxl__device_vfb_setdefault(libxl__gc * gc,uint32_t domid,libxl_device_vfb * vfb,bool hotplug)679 static int libxl__device_vfb_setdefault(libxl__gc *gc, uint32_t domid,
680 libxl_device_vfb *vfb, bool hotplug)
681 {
682 int rc;
683
684 libxl_defbool_setdefault(&vfb->vnc.enable, true);
685 if (libxl_defbool_val(vfb->vnc.enable)) {
686 if (!vfb->vnc.listen) {
687 vfb->vnc.listen = strdup("127.0.0.1");
688 if (!vfb->vnc.listen) return ERROR_NOMEM;
689 }
690
691 libxl_defbool_setdefault(&vfb->vnc.findunused, true);
692 } else {
693 libxl_defbool_setdefault(&vfb->vnc.findunused, false);
694 }
695
696 libxl_defbool_setdefault(&vfb->sdl.enable, false);
697 libxl_defbool_setdefault(&vfb->sdl.opengl, false);
698
699 rc = libxl__resolve_domid(gc, vfb->backend_domname, &vfb->backend_domid);
700 return rc;
701 }
702
libxl_device_vfb_add(libxl_ctx * ctx,uint32_t domid,libxl_device_vfb * vfb,const libxl_asyncop_how * ao_how)703 int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb,
704 const libxl_asyncop_how *ao_how)
705 {
706 AO_CREATE(ctx, domid, ao_how);
707 int rc;
708
709 rc = libxl__device_add(gc, domid, &libxl__vfb_devtype, vfb);
710 if (rc) {
711 LOGD(ERROR, domid, "Unable to add vfb device");
712 goto out;
713 }
714
715 out:
716 libxl__ao_complete(egc, ao, rc);
717 return AO_INPROGRESS;
718 }
719
libxl__set_xenstore_vfb(libxl__gc * gc,uint32_t domid,libxl_device_vfb * vfb,flexarray_t * back,flexarray_t * front,flexarray_t * ro_front)720 static int libxl__set_xenstore_vfb(libxl__gc *gc, uint32_t domid,
721 libxl_device_vfb *vfb,
722 flexarray_t *back, flexarray_t *front,
723 flexarray_t *ro_front)
724 {
725 flexarray_append_pair(back, "vnc",
726 libxl_defbool_val(vfb->vnc.enable) ? "1" : "0");
727 flexarray_append_pair(back, "vnclisten", vfb->vnc.listen);
728 flexarray_append_pair(back, "vncpasswd", vfb->vnc.passwd);
729 flexarray_append_pair(back, "vncdisplay",
730 GCSPRINTF("%d", vfb->vnc.display));
731 flexarray_append_pair(back, "vncunused",
732 libxl_defbool_val(vfb->vnc.findunused) ? "1" : "0");
733 flexarray_append_pair(back, "sdl",
734 libxl_defbool_val(vfb->sdl.enable) ? "1" : "0");
735 flexarray_append_pair(back, "opengl",
736 libxl_defbool_val(vfb->sdl.opengl) ? "1" : "0");
737 if (vfb->sdl.xauthority) {
738 flexarray_append_pair(back, "xauthority", vfb->sdl.xauthority);
739 }
740 if (vfb->sdl.display) {
741 flexarray_append_pair(back, "display", vfb->sdl.display);
742 }
743
744 return 0;
745 }
746
747 /* The following functions are defined:
748 * libxl_device_vfb_remove
749 * libxl_device_vfb_destroy
750 */
751
752 /* channel/console hotunplug is not implemented. There are 2 possibilities:
753 * 1. add support for secondary consoles to xenconsoled
754 * 2. dynamically add/remove qemu chardevs via qmp messages. */
755
756 #define libxl__add_vfbs NULL
757 #define libxl_device_vfb_list NULL
758 #define libxl_device_vfb_compare NULL
759
760 static LIBXL_DEFINE_UPDATE_DEVID(vfb)
761 static LIBXL_DEFINE_DEVICE_FROM_TYPE(vfb)
762
763 /* vfb */
764 LIBXL_DEFINE_DEVICE_REMOVE(vfb)
765
766 DEFINE_DEVICE_TYPE_STRUCT(vfb, VFB, vfbs,
767 .skip_attach = 1,
768 .set_xenstore_config = (device_set_xenstore_config_fn_t)
769 libxl__set_xenstore_vfb,
770 );
771
772 libxl_xen_console_reader *
libxl_xen_console_read_start(libxl_ctx * ctx,int clear)773 libxl_xen_console_read_start(libxl_ctx *ctx, int clear)
774 {
775 GC_INIT(ctx);
776 libxl_xen_console_reader *cr;
777 unsigned int size = 16384;
778
779 cr = libxl__zalloc(NOGC, sizeof(libxl_xen_console_reader));
780 cr->buffer = libxl__zalloc(NOGC, size);
781 cr->size = size;
782 cr->count = size;
783 cr->clear = clear;
784 cr->incremental = 1;
785
786 GC_FREE;
787 return cr;
788 }
789
790 /* return values: *line_r
791 * 1 success, whole line obtained from buffer non-0
792 * 0 no more lines available right now 0
793 * negative error code ERROR_* 0
794 * On success *line_r is updated to point to a nul-terminated
795 * string which is valid until the next call on the same console
796 * reader. The libxl caller may overwrite parts of the string
797 * if it wishes. */
libxl_xen_console_read_line(libxl_ctx * ctx,libxl_xen_console_reader * cr,char ** line_r)798 int libxl_xen_console_read_line(libxl_ctx *ctx,
799 libxl_xen_console_reader *cr,
800 char **line_r)
801 {
802 int ret;
803 GC_INIT(ctx);
804
805 memset(cr->buffer, 0, cr->size);
806 ret = xc_readconsolering(ctx->xch, cr->buffer, &cr->count,
807 cr->clear, cr->incremental, &cr->index);
808 if (ret < 0) {
809 LOGE(ERROR, "reading console ring buffer");
810 GC_FREE;
811 return ERROR_FAIL;
812 }
813 if (!ret) {
814 if (cr->count) {
815 *line_r = cr->buffer;
816 ret = 1;
817 } else {
818 *line_r = NULL;
819 ret = 0;
820 }
821 }
822
823 GC_FREE;
824 return ret;
825 }
826
libxl_xen_console_read_finish(libxl_ctx * ctx,libxl_xen_console_reader * cr)827 void libxl_xen_console_read_finish(libxl_ctx *ctx,
828 libxl_xen_console_reader *cr)
829 {
830 free(cr->buffer);
831 free(cr);
832 }
833
834 /*
835 * Local variables:
836 * mode: C
837 * c-basic-offset: 4
838 * indent-tabs-mode: nil
839 * End:
840 */
841