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