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