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