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