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