[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 5/9] libxl: carve out console specific functions from libxl.c



libxl.c has grown to an uncomfortable size. Carve out the console
related functions (including channels, keyboard and frame buffer)
to libxl_console.c.

Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
---
 tools/libxl/Makefile        |   2 +-
 tools/libxl/libxl.c         | 846 -------------------------------------------
 tools/libxl/libxl_console.c | 862 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 863 insertions(+), 847 deletions(-)
 create mode 100644 tools/libxl/libxl_console.c

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index baf591d..dd7aa41 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -136,7 +136,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o 
libxl_pci.o \
                        libxl_save_callout.o _libxl_save_msgs_callout.o \
                        libxl_qmp.o libxl_event.o libxl_fork.o \
                        libxl_dom_suspend.o libxl_dom_save.o libxl_usb.o \
-                       libxl_vtpm.o libxl_nic.o libxl_disk.o \
+                       libxl_vtpm.o libxl_nic.o libxl_disk.o libxl_console.o \
                        libxl_cpupool.o libxl_sched.o \
                         $(LIBXL_OBJS-y)
 LIBXL_OBJS += libxl_genid.o
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 043c3d6..a0663eb 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1509,239 +1509,6 @@ static void domain_destroy_domid_cb(libxl__egc *egc,
     dis->callback(egc, dis, rc);
 }
 
-static int libxl__console_tty_path(libxl__gc *gc, uint32_t domid, int cons_num,
-                                   libxl_console_type type, char **tty_path)
-{
-    int rc;
-    char *dom_path;
-
-    dom_path = libxl__xs_get_dompath(gc, domid);
-    if (!dom_path) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    switch (type) {
-    case LIBXL_CONSOLE_TYPE_SERIAL:
-        *tty_path = GCSPRINTF("%s/serial/%d/tty", dom_path, cons_num);
-        rc = 0;
-        break;
-    case LIBXL_CONSOLE_TYPE_PV:
-        if (cons_num == 0)
-            *tty_path = GCSPRINTF("%s/console/tty", dom_path);
-        else
-            *tty_path = GCSPRINTF("%s/device/console/%d/tty", dom_path,
-                                  cons_num);
-        rc = 0;
-        break;
-    default:
-        rc = ERROR_INVAL;
-        goto out;
-    }
-
-out:
-    return rc;
-}
-
-int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num,
-                       libxl_console_type type, int notify_fd)
-{
-    GC_INIT(ctx);
-    char *p = GCSPRINTF("%s/xenconsole", libxl__private_bindir_path());
-    char *domid_s = GCSPRINTF("%d", domid);
-    char *cons_num_s = GCSPRINTF("%d", cons_num);
-    char *notify_fd_s;
-    char *cons_type_s;
-
-    switch (type) {
-    case LIBXL_CONSOLE_TYPE_PV:
-        cons_type_s = "pv";
-        break;
-    case LIBXL_CONSOLE_TYPE_SERIAL:
-        cons_type_s = "serial";
-        break;
-    default:
-        goto out;
-    }
-
-    if (notify_fd != -1) {
-        notify_fd_s = GCSPRINTF("%d", notify_fd);
-        execl(p, p, domid_s, "--num", cons_num_s, "--type", cons_type_s,
-              "--start-notify-fd", notify_fd_s, (void *)NULL);
-    } else {
-        execl(p, p, domid_s, "--num", cons_num_s, "--type", cons_type_s,
-              (void *)NULL);
-    }
-
-out:
-    GC_FREE;
-    return ERROR_FAIL;
-}
-
-int libxl_console_get_tty(libxl_ctx *ctx, uint32_t domid, int cons_num,
-                          libxl_console_type type, char **path)
-{
-    GC_INIT(ctx);
-    char *tty_path;
-    char *tty;
-    int rc;
-
-    rc = libxl__console_tty_path(gc, domid, cons_num, type, &tty_path);
-    if (rc) {
-        LOGD(ERROR, domid, "Failed to get tty path\n");
-        goto out;
-    }
-
-    tty = libxl__xs_read(gc, XBT_NULL, tty_path);
-    if (!tty || tty[0] == '\0') {
-       LOGED(ERROR, domid, "Unable to read console tty path `%s'",
-             tty_path);
-       rc = ERROR_FAIL;
-       goto out;
-    }
-
-    *path = libxl__strdup(NOGC, tty);
-    rc = 0;
-out:
-    GC_FREE;
-    return rc;
-}
-
-static int libxl__primary_console_find(libxl_ctx *ctx, uint32_t domid_vm,
-                                       uint32_t *domid, int *cons_num,
-                                       libxl_console_type *type)
-{
-    GC_INIT(ctx);
-    uint32_t stubdomid = libxl_get_stubdom_id(ctx, domid_vm);
-    int rc;
-
-    if (stubdomid) {
-        *domid = stubdomid;
-        *cons_num = STUBDOM_CONSOLE_SERIAL;
-        *type = LIBXL_CONSOLE_TYPE_PV;
-    } else {
-        switch (libxl__domain_type(gc, domid_vm)) {
-        case LIBXL_DOMAIN_TYPE_HVM:
-            *domid = domid_vm;
-            *cons_num = 0;
-            *type = LIBXL_CONSOLE_TYPE_SERIAL;
-            break;
-        case LIBXL_DOMAIN_TYPE_PV:
-            *domid = domid_vm;
-            *cons_num = 0;
-            *type = LIBXL_CONSOLE_TYPE_PV;
-            break;
-        case LIBXL_DOMAIN_TYPE_INVALID:
-            rc = ERROR_INVAL;
-            goto out;
-        default: abort();
-        }
-    }
-
-    rc = 0;
-out:
-    GC_FREE;
-    return rc;
-}
-
-int libxl_primary_console_exec(libxl_ctx *ctx, uint32_t domid_vm, int 
notify_fd)
-{
-    uint32_t domid;
-    int cons_num;
-    libxl_console_type type;
-    int rc;
-
-    rc = libxl__primary_console_find(ctx, domid_vm, &domid, &cons_num, &type);
-    if ( rc ) return rc;
-    return libxl_console_exec(ctx, domid, cons_num, type, notify_fd);
-}
-
-int libxl_primary_console_get_tty(libxl_ctx *ctx, uint32_t domid_vm,
-                                  char **path)
-{
-    uint32_t domid;
-    int cons_num;
-    libxl_console_type type;
-    int rc;
-
-    rc = libxl__primary_console_find(ctx, domid_vm, &domid, &cons_num, &type);
-    if ( rc ) return rc;
-    return libxl_console_get_tty(ctx, domid, cons_num, type, path);
-}
-
-int libxl_vncviewer_exec(libxl_ctx *ctx, uint32_t domid, int autopass)
-{
-    GC_INIT(ctx);
-    const char *vnc_port;
-    const char *vnc_listen = NULL, *vnc_pass = NULL;
-    int port = 0, autopass_fd = -1;
-    char *vnc_bin, *args[] = {
-        "vncviewer",
-        NULL, /* hostname:display */
-        NULL, /* -autopass */
-        NULL,
-    };
-
-    vnc_port = libxl__xs_read(gc, XBT_NULL,
-                            GCSPRINTF(
-                            "/local/domain/%d/console/vnc-port", domid));
-    if (!vnc_port) {
-        LOGD(ERROR, domid, "Cannot get vnc-port");
-        goto x_fail;
-    }
-
-    port = atoi(vnc_port) - 5900;
-
-    vnc_listen = libxl__xs_read(gc, XBT_NULL,
-                                
GCSPRINTF("/local/domain/%d/console/vnc-listen",
-                                          domid));
-
-    if ( autopass )
-        vnc_pass = libxl__xs_read(gc, XBT_NULL,
-                                  
GCSPRINTF("/local/domain/%d/console/vnc-pass",
-                                           domid));
-
-    if ( NULL == vnc_listen )
-        vnc_listen = "localhost";
-
-    if ( (vnc_bin = getenv("VNCVIEWER")) )
-        args[0] = vnc_bin;
-
-    args[1] = GCSPRINTF("%s:%d", vnc_listen, port);
-
-    if ( vnc_pass ) {
-        char tmpname[] = "/tmp/vncautopass.XXXXXX";
-        autopass_fd = mkstemp(tmpname);
-        if ( autopass_fd < 0 ) {
-            LOGED(ERROR, domid, "mkstemp %s failed", tmpname);
-            goto x_fail;
-        }
-
-        if ( unlink(tmpname) ) {
-            /* should never happen */
-            LOGED(ERROR, domid, "unlink %s failed", tmpname);
-            goto x_fail;
-        }
-
-        if ( libxl_write_exactly(ctx, autopass_fd, vnc_pass, strlen(vnc_pass),
-                                    tmpname, "vnc password") )
-            goto x_fail;
-
-        if ( lseek(autopass_fd, SEEK_SET, 0) ) {
-            LOGED(ERROR, domid, "rewind %s (autopass) failed", tmpname);
-            goto x_fail;
-        }
-
-        args[2] = "-autopass";
-    }
-
-    libxl__exec(gc, autopass_fd, -1, -1, args[0], args, NULL);
-
- x_fail:
-    GC_FREE;
-    return ERROR_FAIL;
-}
-
 int libxl__get_domid(libxl__gc *gc, uint32_t *domid)
 {
     int rc;
@@ -1815,557 +1582,6 @@ int libxl__resolve_domid(libxl__gc *gc, const char 
*name, uint32_t *domid)
 }
 
 
/******************************************************************************/
-int libxl__device_console_add(libxl__gc *gc, uint32_t domid,
-                              libxl__device_console *console,
-                              libxl__domain_build_state *state,
-                              libxl__device *device)
-{
-    flexarray_t *front, *ro_front;
-    flexarray_t *back;
-    int rc;
-
-    if (console->devid && state) {
-        rc = ERROR_INVAL;
-        goto out;
-    }
-    if (!console->devid && (console->name || console->path)) {
-        LOGD(ERROR, domid, "Primary console has invalid configuration");
-        rc = ERROR_INVAL;
-        goto out;
-    }
-
-    front = flexarray_make(gc, 16, 1);
-    ro_front = flexarray_make(gc, 16, 1);
-    back = flexarray_make(gc, 16, 1);
-
-    device->backend_devid = console->devid;
-    device->backend_domid = console->backend_domid;
-    device->backend_kind = LIBXL__DEVICE_KIND_CONSOLE;
-    device->devid = console->devid;
-    device->domid = domid;
-    device->kind = LIBXL__DEVICE_KIND_CONSOLE;
-
-    flexarray_append(back, "frontend-id");
-    flexarray_append(back, GCSPRINTF("%d", domid));
-    flexarray_append(back, "online");
-    flexarray_append(back, "1");
-    flexarray_append(back, "state");
-    flexarray_append(back, GCSPRINTF("%d", XenbusStateInitialising));
-    flexarray_append(back, "protocol");
-    flexarray_append(back, LIBXL_XENCONSOLE_PROTOCOL);
-
-    if (console->name) {
-        flexarray_append(ro_front, "name");
-        flexarray_append(ro_front, console->name);
-        flexarray_append(back, "name");
-        flexarray_append(back, console->name);
-    }
-    if (console->connection) {
-        flexarray_append(back, "connection");
-        flexarray_append(back, console->connection);
-    }
-    if (console->path) {
-        flexarray_append(back, "path");
-        flexarray_append(back, console->path);
-    }
-
-    flexarray_append(front, "backend-id");
-    flexarray_append(front, GCSPRINTF("%d", console->backend_domid));
-
-    flexarray_append(ro_front, "limit");
-    flexarray_append(ro_front, GCSPRINTF("%d", LIBXL_XENCONSOLE_LIMIT));
-    flexarray_append(ro_front, "type");
-    if (console->consback == LIBXL__CONSOLE_BACKEND_XENCONSOLED)
-        flexarray_append(ro_front, "xenconsoled");
-    else
-        flexarray_append(ro_front, "ioemu");
-    flexarray_append(ro_front, "output");
-    flexarray_append(ro_front, console->output);
-    flexarray_append(ro_front, "tty");
-    flexarray_append(ro_front, "");
-
-    if (state) {
-        flexarray_append(ro_front, "port");
-        flexarray_append(ro_front, GCSPRINTF("%"PRIu32, state->console_port));
-        flexarray_append(ro_front, "ring-ref");
-        flexarray_append(ro_front, GCSPRINTF("%lu", state->console_mfn));
-    } else {
-        flexarray_append(front, "state");
-        flexarray_append(front, GCSPRINTF("%d", XenbusStateInitialising));
-        flexarray_append(front, "protocol");
-        flexarray_append(front, LIBXL_XENCONSOLE_PROTOCOL);
-    }
-    libxl__device_generic_add(gc, XBT_NULL, device,
-                              libxl__xs_kvs_of_flexarray(gc, back),
-                              libxl__xs_kvs_of_flexarray(gc, front),
-                              libxl__xs_kvs_of_flexarray(gc, ro_front));
-    rc = 0;
-out:
-    return rc;
-}
-
-/******************************************************************************/
-
-int libxl__init_console_from_channel(libxl__gc *gc,
-                                     libxl__device_console *console,
-                                     int dev_num,
-                                     libxl_device_channel *channel)
-{
-    int rc;
-
-    libxl__device_console_init(console);
-
-    /* Perform validation first, allocate second. */
-
-    if (!channel->name) {
-        LOG(ERROR, "channel %d has no name", channel->devid);
-        return ERROR_INVAL;
-    }
-
-    if (channel->backend_domname) {
-        rc = libxl_domain_qualifier_to_domid(CTX, channel->backend_domname,
-                                             &channel->backend_domid);
-        if (rc < 0) return rc;
-    }
-
-    /* The xenstore 'output' node tells the backend what to connect the console
-       to. If the channel has "connection = pty" then the "output" node will be
-       set to "pty". If the channel has "connection = socket" then the "output"
-       node will be set to "chardev:libxl-channel%d". This tells the qemu
-       backend to proxy data between the console ring and the character device
-       with id "libxl-channel%d". These character devices are currently defined
-       on the qemu command-line via "-chardev" options in libxl_dm.c */
-
-    switch (channel->connection) {
-        case LIBXL_CHANNEL_CONNECTION_UNKNOWN:
-            LOG(ERROR, "channel %d has no defined connection; "
-                "to where should it be connected?", channel->devid);
-            return ERROR_INVAL;
-        case LIBXL_CHANNEL_CONNECTION_PTY:
-            console->connection = libxl__strdup(NOGC, "pty");
-            console->output = libxl__sprintf(NOGC, "pty");
-            break;
-        case LIBXL_CHANNEL_CONNECTION_SOCKET:
-            if (!channel->u.socket.path) {
-                LOG(ERROR, "channel %d has no path", channel->devid);
-                return ERROR_INVAL;
-            }
-            console->connection = libxl__strdup(NOGC, "socket");
-            console->path = libxl__strdup(NOGC, channel->u.socket.path);
-            console->output = libxl__sprintf(NOGC, "chardev:libxl-channel%d",
-                                             channel->devid);
-            break;
-        default:
-            /* We've forgotten to add the clause */
-            LOG(ERROR, "%s: missing implementation for channel connection %d",
-                __func__, channel->connection);
-            abort();
-    }
-
-    console->devid = dev_num;
-    console->consback = LIBXL__CONSOLE_BACKEND_IOEMU;
-    console->backend_domid = channel->backend_domid;
-    console->name = libxl__strdup(NOGC, channel->name);
-
-    return 0;
-}
-
-static int libxl__device_channel_from_xenstore(libxl__gc *gc,
-                                            const char *libxl_path,
-                                            libxl_device_channel *channel)
-{
-    const char *tmp;
-    int rc;
-
-    libxl_device_channel_init(channel);
-
-    rc = libxl__xs_read_checked(NOGC, XBT_NULL,
-                                GCSPRINTF("%s/name", libxl_path),
-                                (const char **)(&channel->name));
-    if (rc) goto out;
-    rc = libxl__xs_read_checked(gc, XBT_NULL,
-                                GCSPRINTF("%s/connection", libxl_path), &tmp);
-    if (rc) goto out;
-    if (!strcmp(tmp, "pty")) {
-        channel->connection = LIBXL_CHANNEL_CONNECTION_PTY;
-    } else if (!strcmp(tmp, "socket")) {
-        channel->connection = LIBXL_CHANNEL_CONNECTION_SOCKET;
-        rc = libxl__xs_read_checked(NOGC, XBT_NULL,
-                                    GCSPRINTF("%s/path", libxl_path),
-                                    (const char **)(&channel->u.socket.path));
-        if (rc) goto out;
-    } else {
-        rc = ERROR_INVAL;
-        goto out;
-    }
-
-    rc = 0;
- out:
-    return rc;
-}
-
-static int libxl__append_channel_list(libxl__gc *gc,
-                                              uint32_t domid,
-                                              libxl_device_channel **channels,
-                                              int *nchannels)
-{
-    char *libxl_dir_path = NULL;
-    char **dir = NULL;
-    unsigned int n = 0, devid = 0;
-    libxl_device_channel *next = NULL;
-    int rc = 0, i;
-
-    libxl_dir_path = GCSPRINTF("%s/device/console",
-                               libxl__xs_libxl_path(gc, domid));
-    dir = libxl__xs_directory(gc, XBT_NULL, libxl_dir_path, &n);
-    if (!dir || !n)
-      goto out;
-
-    for (i = 0; i < n; i++) {
-        const char *libxl_path, *name;
-        libxl_device_channel *tmp;
-
-        libxl_path = GCSPRINTF("%s/%s", libxl_dir_path, dir[i]);
-        name = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/name", libxl_path));
-        /* 'channels' are consoles with names, so ignore all consoles
-           without names */
-        if (!name) continue;
-        tmp = realloc(*channels,
-                      sizeof(libxl_device_channel) * (*nchannels + devid + 1));
-        if (!tmp) {
-          rc = ERROR_NOMEM;
-          goto out;
-        }
-        *channels = tmp;
-        next = *channels + *nchannels + devid;
-        rc = libxl__device_channel_from_xenstore(gc, libxl_path, next);
-        if (rc) goto out;
-        next->devid = devid;
-        devid++;
-    }
-    *nchannels += devid;
-    return 0;
-
- out:
-    return rc;
-}
-
-libxl_device_channel *libxl_device_channel_list(libxl_ctx *ctx,
-                                                uint32_t domid,
-                                                int *num)
-{
-    GC_INIT(ctx);
-    libxl_device_channel *channels = NULL;
-    int rc;
-
-    *num = 0;
-
-    rc = libxl__append_channel_list(gc, domid, &channels, num);
-    if (rc) goto out_err;
-
-    GC_FREE;
-    return channels;
-
-out_err:
-    LOGD(ERROR, domid, "Unable to list channels");
-    while (*num) {
-        (*num)--;
-        libxl_device_channel_dispose(&channels[*num]);
-    }
-    free(channels);
-    return NULL;
-}
-
-int libxl_device_channel_getinfo(libxl_ctx *ctx, uint32_t domid,
-                                 libxl_device_channel *channel,
-                                 libxl_channelinfo *channelinfo)
-{
-    GC_INIT(ctx);
-    char *dompath, *fe_path, *libxl_path;
-    char *val;
-    int rc;
-
-    dompath = libxl__xs_get_dompath(gc, domid);
-    channelinfo->devid = channel->devid;
-
-    fe_path = GCSPRINTF("%s/device/console/%d", dompath,
-                        channelinfo->devid + 1);
-    libxl_path = GCSPRINTF("%s/device/console/%d",
-                           libxl__xs_libxl_path(gc, domid),
-                           channelinfo->devid + 1);
-    channelinfo->backend = xs_read(ctx->xsh, XBT_NULL,
-                                   GCSPRINTF("%s/backend", libxl_path), NULL);
-    if (!channelinfo->backend) {
-        GC_FREE;
-        return ERROR_FAIL;
-    }
-    rc = libxl__backendpath_parse_domid(gc, channelinfo->backend,
-                                        &channelinfo->backend_id);
-    if (rc) goto out;
-
-    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/state", fe_path));
-    channelinfo->state = val ? strtoul(val, NULL, 10) : -1;
-    channelinfo->frontend = libxl__strdup(NOGC, fe_path);
-    channelinfo->frontend_id = domid;
-    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/ring-ref", fe_path));
-    channelinfo->rref = val ? strtoul(val, NULL, 10) : -1;
-    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/port", fe_path));
-    channelinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
-
-    channelinfo->connection = channel->connection;
-    switch (channel->connection) {
-         case LIBXL_CHANNEL_CONNECTION_PTY:
-             val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/tty", fe_path));
-             /*
-              * It is obviously very wrong for this value to be in the
-              * frontend.  But in XSA-175 we don't want to re-engineer
-              * this because other xenconsole code elsewhere (some
-              * even out of tree, perhaps) expects this node to be
-              * here.
-              *
-              * FE/pty is readonly for the guest.  It always exists if
-              * FE does because libxl__device_console_add
-              * unconditionally creates it and nothing deletes it.
-              *
-              * The guest can delete the whole FE (which it has write
-              * privilege on) but the containing directories
-              * /local/GUEST[/device[/console]] are also RO for the
-              * guest.  So if the guest deletes FE it cannot recreate
-              * it.
-              *
-              * Therefore the guest cannot cause FE/pty to contain bad
-              * data, although it can cause it to not exist.
-              */
-             if (!val) val = "/NO-SUCH-PATH";
-             channelinfo->u.pty.path = strdup(val);
-             break;
-         default:
-             break;
-    }
-    rc = 0;
- out:
-    GC_FREE;
-    return rc;
-}
-
-/******************************************************************************/
-
-int libxl__device_vkb_setdefault(libxl__gc *gc, libxl_device_vkb *vkb)
-{
-    int rc;
-    rc = libxl__resolve_domid(gc, vkb->backend_domname, &vkb->backend_domid);
-    return rc;
-}
-
-static int libxl__device_from_vkb(libxl__gc *gc, uint32_t domid,
-                                  libxl_device_vkb *vkb,
-                                  libxl__device *device)
-{
-    device->backend_devid = vkb->devid;
-    device->backend_domid = vkb->backend_domid;
-    device->backend_kind = LIBXL__DEVICE_KIND_VKBD;
-    device->devid = vkb->devid;
-    device->domid = domid;
-    device->kind = LIBXL__DEVICE_KIND_VKBD;
-
-    return 0;
-}
-
-int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb,
-                         const libxl_asyncop_how *ao_how)
-{
-    AO_CREATE(ctx, domid, ao_how);
-    int rc;
-
-    rc = libxl__device_vkb_add(gc, domid, vkb);
-    if (rc) {
-        LOGD(ERROR, domid, "Unable to add vkb device");
-        goto out;
-    }
-
-out:
-    libxl__ao_complete(egc, ao, rc);
-    return AO_INPROGRESS;
-}
-
-int libxl__device_vkb_add(libxl__gc *gc, uint32_t domid,
-                          libxl_device_vkb *vkb)
-{
-    flexarray_t *front;
-    flexarray_t *back;
-    libxl__device device;
-    int rc;
-
-    rc = libxl__device_vkb_setdefault(gc, vkb);
-    if (rc) goto out;
-
-    front = flexarray_make(gc, 16, 1);
-    back = flexarray_make(gc, 16, 1);
-
-    if (vkb->devid == -1) {
-        if ((vkb->devid = libxl__device_nextid(gc, domid, "vkb")) < 0) {
-            rc = ERROR_FAIL;
-            goto out;
-        }
-    }
-
-    rc = libxl__device_from_vkb(gc, domid, vkb, &device);
-    if (rc != 0) goto out;
-
-    flexarray_append(back, "frontend-id");
-    flexarray_append(back, GCSPRINTF("%d", domid));
-    flexarray_append(back, "online");
-    flexarray_append(back, "1");
-    flexarray_append(back, "state");
-    flexarray_append(back, GCSPRINTF("%d", XenbusStateInitialising));
-
-    flexarray_append(front, "backend-id");
-    flexarray_append(front, GCSPRINTF("%d", vkb->backend_domid));
-    flexarray_append(front, "state");
-    flexarray_append(front, GCSPRINTF("%d", XenbusStateInitialising));
-
-    libxl__device_generic_add(gc, XBT_NULL, &device,
-                              libxl__xs_kvs_of_flexarray(gc, back),
-                              libxl__xs_kvs_of_flexarray(gc, front),
-                              NULL);
-    rc = 0;
-out:
-    return rc;
-}
-
-/******************************************************************************/
-
-int libxl__device_vfb_setdefault(libxl__gc *gc, libxl_device_vfb *vfb)
-{
-    int rc;
-
-    libxl_defbool_setdefault(&vfb->vnc.enable, true);
-    if (libxl_defbool_val(vfb->vnc.enable)) {
-        if (!vfb->vnc.listen) {
-            vfb->vnc.listen = strdup("127.0.0.1");
-            if (!vfb->vnc.listen) return ERROR_NOMEM;
-        }
-
-        libxl_defbool_setdefault(&vfb->vnc.findunused, true);
-    } else {
-        libxl_defbool_setdefault(&vfb->vnc.findunused, false);
-    }
-
-    libxl_defbool_setdefault(&vfb->sdl.enable, false);
-    libxl_defbool_setdefault(&vfb->sdl.opengl, false);
-
-    rc = libxl__resolve_domid(gc, vfb->backend_domname, &vfb->backend_domid);
-    return rc;
-}
-
-static int libxl__device_from_vfb(libxl__gc *gc, uint32_t domid,
-                                  libxl_device_vfb *vfb,
-                                  libxl__device *device)
-{
-    device->backend_devid = vfb->devid;
-    device->backend_domid = vfb->backend_domid;
-    device->backend_kind = LIBXL__DEVICE_KIND_VFB;
-    device->devid = vfb->devid;
-    device->domid = domid;
-    device->kind = LIBXL__DEVICE_KIND_VFB;
-    return 0;
-}
-
-int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb,
-                         const libxl_asyncop_how *ao_how)
-{
-    AO_CREATE(ctx, domid, ao_how);
-    int rc;
-
-    rc = libxl__device_vfb_add(gc, domid, vfb);
-    if (rc) {
-        LOGD(ERROR, domid, "Unable to add vfb device");
-        goto out;
-    }
-
-out:
-    libxl__ao_complete(egc, ao, rc);
-    return AO_INPROGRESS;
-}
-
-int libxl__device_vfb_add(libxl__gc *gc, uint32_t domid, libxl_device_vfb *vfb)
-{
-    flexarray_t *front;
-    flexarray_t *back;
-    libxl__device device;
-    int rc;
-
-    rc = libxl__device_vfb_setdefault(gc, vfb);
-    if (rc) goto out;
-
-    front = flexarray_make(gc, 16, 1);
-    back = flexarray_make(gc, 16, 1);
-
-    if (vfb->devid == -1) {
-        if ((vfb->devid = libxl__device_nextid(gc, domid, "vfb")) < 0) {
-            rc = ERROR_FAIL;
-            goto out;
-        }
-    }
-
-    rc = libxl__device_from_vfb(gc, domid, vfb, &device);
-    if (rc != 0) goto out;
-
-    flexarray_append_pair(back, "frontend-id", GCSPRINTF("%d", domid));
-    flexarray_append_pair(back, "online", "1");
-    flexarray_append_pair(back, "state", GCSPRINTF("%d", 
XenbusStateInitialising));
-    flexarray_append_pair(back, "vnc",
-                          libxl_defbool_val(vfb->vnc.enable) ? "1" : "0");
-    flexarray_append_pair(back, "vnclisten", vfb->vnc.listen);
-    flexarray_append_pair(back, "vncpasswd", vfb->vnc.passwd);
-    flexarray_append_pair(back, "vncdisplay",
-                          GCSPRINTF("%d", vfb->vnc.display));
-    flexarray_append_pair(back, "vncunused",
-                          libxl_defbool_val(vfb->vnc.findunused) ? "1" : "0");
-    flexarray_append_pair(back, "sdl",
-                          libxl_defbool_val(vfb->sdl.enable) ? "1" : "0");
-    flexarray_append_pair(back, "opengl",
-                          libxl_defbool_val(vfb->sdl.opengl) ? "1" : "0");
-    if (vfb->sdl.xauthority) {
-        flexarray_append_pair(back, "xauthority", vfb->sdl.xauthority);
-    }
-    if (vfb->sdl.display) {
-        flexarray_append_pair(back, "display", vfb->sdl.display);
-    }
-
-    flexarray_append_pair(front, "backend-id",
-                          GCSPRINTF("%d", vfb->backend_domid));
-    flexarray_append_pair(front, "state", GCSPRINTF("%d", 
XenbusStateInitialising));
-
-    libxl__device_generic_add(gc, XBT_NULL, &device,
-                              libxl__xs_kvs_of_flexarray(gc, back),
-                              libxl__xs_kvs_of_flexarray(gc, front),
-                              NULL);
-    rc = 0;
-out:
-    return rc;
-}
-
-/******************************************************************************/
-
-/* The following functions are defined:
- * libxl_device_vkb_remove
- * libxl_device_vkb_destroy
- * libxl_device_vfb_remove
- * libxl_device_vfb_destroy
- */
-
-/* channel/console hotunplug is not implemented. There are 2 possibilities:
- * 1. add support for secondary consoles to xenconsoled
- * 2. dynamically add/remove qemu chardevs via qmp messages. */
-
-/* vkb */
-LIBXL_DEFINE_DEVICE_REMOVE(vkb)
-
-/* vfb */
-LIBXL_DEFINE_DEVICE_REMOVE(vfb)
-
-/******************************************************************************/
 
 /*
  * Data structures used to track devices handled by driver domains
@@ -3863,68 +3079,6 @@ int libxl_send_debug_keys(libxl_ctx *ctx, char *keys)
     return 0;
 }
 
-libxl_xen_console_reader *
-    libxl_xen_console_read_start(libxl_ctx *ctx, int clear)
-{
-    GC_INIT(ctx);
-    libxl_xen_console_reader *cr;
-    unsigned int size = 16384;
-
-    cr = libxl__zalloc(NOGC, sizeof(libxl_xen_console_reader));
-    cr->buffer = libxl__zalloc(NOGC, size);
-    cr->size = size;
-    cr->count = size;
-    cr->clear = clear;
-    cr->incremental = 1;
-
-    GC_FREE;
-    return cr;
-}
-
-/* return values:                                          *line_r
- *   1          success, whole line obtained from buffer    non-0
- *   0          no more lines available right now           0
- *   negative   error code ERROR_*                          0
- * On success *line_r is updated to point to a nul-terminated
- * string which is valid until the next call on the same console
- * reader.  The libxl caller may overwrite parts of the string
- * if it wishes. */
-int libxl_xen_console_read_line(libxl_ctx *ctx,
-                                libxl_xen_console_reader *cr,
-                                char **line_r)
-{
-    int ret;
-    GC_INIT(ctx);
-
-    memset(cr->buffer, 0, cr->size);
-    ret = xc_readconsolering(ctx->xch, cr->buffer, &cr->count,
-                             cr->clear, cr->incremental, &cr->index);
-    if (ret < 0) {
-        LOGE(ERROR, "reading console ring buffer");
-        GC_FREE;
-        return ERROR_FAIL;
-    }
-    if (!ret) {
-        if (cr->count) {
-            *line_r = cr->buffer;
-            ret = 1;
-        } else {
-            *line_r = NULL;
-            ret = 0;
-        }
-    }
-
-    GC_FREE;
-    return ret;
-}
-
-void libxl_xen_console_read_finish(libxl_ctx *ctx,
-                                   libxl_xen_console_reader *cr)
-{
-    free(cr->buffer);
-    free(cr);
-}
-
 uint32_t libxl_vm_get_start_time(libxl_ctx *ctx, uint32_t domid)
 {
     GC_INIT(ctx);
diff --git a/tools/libxl/libxl_console.c b/tools/libxl/libxl_console.c
new file mode 100644
index 0000000..cbc70b7
--- /dev/null
+++ b/tools/libxl/libxl_console.c
@@ -0,0 +1,862 @@
+/*
+ * Copyright 2009-2017 Citrix Ltd and other contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+#include "libxl_osdeps.h"
+
+#include "libxl_internal.h"
+
+static int libxl__console_tty_path(libxl__gc *gc, uint32_t domid, int cons_num,
+                                   libxl_console_type type, char **tty_path)
+{
+    int rc;
+    char *dom_path;
+
+    dom_path = libxl__xs_get_dompath(gc, domid);
+    if (!dom_path) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    switch (type) {
+    case LIBXL_CONSOLE_TYPE_SERIAL:
+        *tty_path = GCSPRINTF("%s/serial/%d/tty", dom_path, cons_num);
+        rc = 0;
+        break;
+    case LIBXL_CONSOLE_TYPE_PV:
+        if (cons_num == 0)
+            *tty_path = GCSPRINTF("%s/console/tty", dom_path);
+        else
+            *tty_path = GCSPRINTF("%s/device/console/%d/tty", dom_path,
+                                  cons_num);
+        rc = 0;
+        break;
+    default:
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+out:
+    return rc;
+}
+
+int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num,
+                       libxl_console_type type, int notify_fd)
+{
+    GC_INIT(ctx);
+    char *p = GCSPRINTF("%s/xenconsole", libxl__private_bindir_path());
+    char *domid_s = GCSPRINTF("%d", domid);
+    char *cons_num_s = GCSPRINTF("%d", cons_num);
+    char *notify_fd_s;
+    char *cons_type_s;
+
+    switch (type) {
+    case LIBXL_CONSOLE_TYPE_PV:
+        cons_type_s = "pv";
+        break;
+    case LIBXL_CONSOLE_TYPE_SERIAL:
+        cons_type_s = "serial";
+        break;
+    default:
+        goto out;
+    }
+
+    if (notify_fd != -1) {
+        notify_fd_s = GCSPRINTF("%d", notify_fd);
+        execl(p, p, domid_s, "--num", cons_num_s, "--type", cons_type_s,
+              "--start-notify-fd", notify_fd_s, (void *)NULL);
+    } else {
+        execl(p, p, domid_s, "--num", cons_num_s, "--type", cons_type_s,
+              (void *)NULL);
+    }
+
+out:
+    GC_FREE;
+    return ERROR_FAIL;
+}
+
+int libxl_console_get_tty(libxl_ctx *ctx, uint32_t domid, int cons_num,
+                          libxl_console_type type, char **path)
+{
+    GC_INIT(ctx);
+    char *tty_path;
+    char *tty;
+    int rc;
+
+    rc = libxl__console_tty_path(gc, domid, cons_num, type, &tty_path);
+    if (rc) {
+        LOGD(ERROR, domid, "Failed to get tty path\n");
+        goto out;
+    }
+
+    tty = libxl__xs_read(gc, XBT_NULL, tty_path);
+    if (!tty || tty[0] == '\0') {
+       LOGED(ERROR, domid, "Unable to read console tty path `%s'",
+             tty_path);
+       rc = ERROR_FAIL;
+       goto out;
+    }
+
+    *path = libxl__strdup(NOGC, tty);
+    rc = 0;
+out:
+    GC_FREE;
+    return rc;
+}
+
+static int libxl__primary_console_find(libxl_ctx *ctx, uint32_t domid_vm,
+                                       uint32_t *domid, int *cons_num,
+                                       libxl_console_type *type)
+{
+    GC_INIT(ctx);
+    uint32_t stubdomid = libxl_get_stubdom_id(ctx, domid_vm);
+    int rc;
+
+    if (stubdomid) {
+        *domid = stubdomid;
+        *cons_num = STUBDOM_CONSOLE_SERIAL;
+        *type = LIBXL_CONSOLE_TYPE_PV;
+    } else {
+        switch (libxl__domain_type(gc, domid_vm)) {
+        case LIBXL_DOMAIN_TYPE_HVM:
+            *domid = domid_vm;
+            *cons_num = 0;
+            *type = LIBXL_CONSOLE_TYPE_SERIAL;
+            break;
+        case LIBXL_DOMAIN_TYPE_PV:
+            *domid = domid_vm;
+            *cons_num = 0;
+            *type = LIBXL_CONSOLE_TYPE_PV;
+            break;
+        case LIBXL_DOMAIN_TYPE_INVALID:
+            rc = ERROR_INVAL;
+            goto out;
+        default: abort();
+        }
+    }
+
+    rc = 0;
+out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl_primary_console_exec(libxl_ctx *ctx, uint32_t domid_vm, int 
notify_fd)
+{
+    uint32_t domid;
+    int cons_num;
+    libxl_console_type type;
+    int rc;
+
+    rc = libxl__primary_console_find(ctx, domid_vm, &domid, &cons_num, &type);
+    if ( rc ) return rc;
+    return libxl_console_exec(ctx, domid, cons_num, type, notify_fd);
+}
+
+int libxl_primary_console_get_tty(libxl_ctx *ctx, uint32_t domid_vm,
+                                  char **path)
+{
+    uint32_t domid;
+    int cons_num;
+    libxl_console_type type;
+    int rc;
+
+    rc = libxl__primary_console_find(ctx, domid_vm, &domid, &cons_num, &type);
+    if ( rc ) return rc;
+    return libxl_console_get_tty(ctx, domid, cons_num, type, path);
+}
+
+int libxl_vncviewer_exec(libxl_ctx *ctx, uint32_t domid, int autopass)
+{
+    GC_INIT(ctx);
+    const char *vnc_port;
+    const char *vnc_listen = NULL, *vnc_pass = NULL;
+    int port = 0, autopass_fd = -1;
+    char *vnc_bin, *args[] = {
+        "vncviewer",
+        NULL, /* hostname:display */
+        NULL, /* -autopass */
+        NULL,
+    };
+
+    vnc_port = libxl__xs_read(gc, XBT_NULL,
+                            GCSPRINTF(
+                            "/local/domain/%d/console/vnc-port", domid));
+    if (!vnc_port) {
+        LOGD(ERROR, domid, "Cannot get vnc-port");
+        goto x_fail;
+    }
+
+    port = atoi(vnc_port) - 5900;
+
+    vnc_listen = libxl__xs_read(gc, XBT_NULL,
+                                
GCSPRINTF("/local/domain/%d/console/vnc-listen",
+                                          domid));
+
+    if ( autopass )
+        vnc_pass = libxl__xs_read(gc, XBT_NULL,
+                                  
GCSPRINTF("/local/domain/%d/console/vnc-pass",
+                                            domid));
+
+    if ( NULL == vnc_listen )
+        vnc_listen = "localhost";
+
+    if ( (vnc_bin = getenv("VNCVIEWER")) )
+        args[0] = vnc_bin;
+
+    args[1] = GCSPRINTF("%s:%d", vnc_listen, port);
+
+    if ( vnc_pass ) {
+        char tmpname[] = "/tmp/vncautopass.XXXXXX";
+        autopass_fd = mkstemp(tmpname);
+        if ( autopass_fd < 0 ) {
+            LOGED(ERROR, domid, "mkstemp %s failed", tmpname);
+            goto x_fail;
+        }
+
+        if ( unlink(tmpname) ) {
+            /* should never happen */
+            LOGED(ERROR, domid, "unlink %s failed", tmpname);
+            goto x_fail;
+        }
+
+        if ( libxl_write_exactly(ctx, autopass_fd, vnc_pass, strlen(vnc_pass),
+                                    tmpname, "vnc password") )
+            goto x_fail;
+
+        if ( lseek(autopass_fd, SEEK_SET, 0) ) {
+            LOGED(ERROR, domid, "rewind %s (autopass) failed", tmpname);
+            goto x_fail;
+        }
+
+        args[2] = "-autopass";
+    }
+
+    libxl__exec(gc, autopass_fd, -1, -1, args[0], args, NULL);
+
+ x_fail:
+    GC_FREE;
+    return ERROR_FAIL;
+}
+
+int libxl__device_console_add(libxl__gc *gc, uint32_t domid,
+                              libxl__device_console *console,
+                              libxl__domain_build_state *state,
+                              libxl__device *device)
+{
+    flexarray_t *front, *ro_front;
+    flexarray_t *back;
+    int rc;
+
+    if (console->devid && state) {
+        rc = ERROR_INVAL;
+        goto out;
+    }
+    if (!console->devid && (console->name || console->path)) {
+        LOGD(ERROR, domid, "Primary console has invalid configuration");
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    front = flexarray_make(gc, 16, 1);
+    ro_front = flexarray_make(gc, 16, 1);
+    back = flexarray_make(gc, 16, 1);
+
+    device->backend_devid = console->devid;
+    device->backend_domid = console->backend_domid;
+    device->backend_kind = LIBXL__DEVICE_KIND_CONSOLE;
+    device->devid = console->devid;
+    device->domid = domid;
+    device->kind = LIBXL__DEVICE_KIND_CONSOLE;
+
+    flexarray_append(back, "frontend-id");
+    flexarray_append(back, GCSPRINTF("%d", domid));
+    flexarray_append(back, "online");
+    flexarray_append(back, "1");
+    flexarray_append(back, "state");
+    flexarray_append(back, GCSPRINTF("%d", XenbusStateInitialising));
+    flexarray_append(back, "protocol");
+    flexarray_append(back, LIBXL_XENCONSOLE_PROTOCOL);
+
+    if (console->name) {
+        flexarray_append(ro_front, "name");
+        flexarray_append(ro_front, console->name);
+        flexarray_append(back, "name");
+        flexarray_append(back, console->name);
+    }
+    if (console->connection) {
+        flexarray_append(back, "connection");
+        flexarray_append(back, console->connection);
+    }
+    if (console->path) {
+        flexarray_append(back, "path");
+        flexarray_append(back, console->path);
+    }
+
+    flexarray_append(front, "backend-id");
+    flexarray_append(front, GCSPRINTF("%d", console->backend_domid));
+
+    flexarray_append(ro_front, "limit");
+    flexarray_append(ro_front, GCSPRINTF("%d", LIBXL_XENCONSOLE_LIMIT));
+    flexarray_append(ro_front, "type");
+    if (console->consback == LIBXL__CONSOLE_BACKEND_XENCONSOLED)
+        flexarray_append(ro_front, "xenconsoled");
+    else
+        flexarray_append(ro_front, "ioemu");
+    flexarray_append(ro_front, "output");
+    flexarray_append(ro_front, console->output);
+    flexarray_append(ro_front, "tty");
+    flexarray_append(ro_front, "");
+
+    if (state) {
+        flexarray_append(ro_front, "port");
+        flexarray_append(ro_front, GCSPRINTF("%"PRIu32, state->console_port));
+        flexarray_append(ro_front, "ring-ref");
+        flexarray_append(ro_front, GCSPRINTF("%lu", state->console_mfn));
+    } else {
+        flexarray_append(front, "state");
+        flexarray_append(front, GCSPRINTF("%d", XenbusStateInitialising));
+        flexarray_append(front, "protocol");
+        flexarray_append(front, LIBXL_XENCONSOLE_PROTOCOL);
+    }
+    libxl__device_generic_add(gc, XBT_NULL, device,
+                              libxl__xs_kvs_of_flexarray(gc, back),
+                              libxl__xs_kvs_of_flexarray(gc, front),
+                              libxl__xs_kvs_of_flexarray(gc, ro_front));
+    rc = 0;
+out:
+    return rc;
+}
+
+int libxl__init_console_from_channel(libxl__gc *gc,
+                                     libxl__device_console *console,
+                                     int dev_num,
+                                     libxl_device_channel *channel)
+{
+    int rc;
+
+    libxl__device_console_init(console);
+
+    /* Perform validation first, allocate second. */
+
+    if (!channel->name) {
+        LOG(ERROR, "channel %d has no name", channel->devid);
+        return ERROR_INVAL;
+    }
+
+    if (channel->backend_domname) {
+        rc = libxl_domain_qualifier_to_domid(CTX, channel->backend_domname,
+                                             &channel->backend_domid);
+        if (rc < 0) return rc;
+    }
+
+    /* The xenstore 'output' node tells the backend what to connect the console
+       to. If the channel has "connection = pty" then the "output" node will be
+       set to "pty". If the channel has "connection = socket" then the "output"
+       node will be set to "chardev:libxl-channel%d". This tells the qemu
+       backend to proxy data between the console ring and the character device
+       with id "libxl-channel%d". These character devices are currently defined
+       on the qemu command-line via "-chardev" options in libxl_dm.c */
+
+    switch (channel->connection) {
+        case LIBXL_CHANNEL_CONNECTION_UNKNOWN:
+            LOG(ERROR, "channel %d has no defined connection; "
+                "to where should it be connected?", channel->devid);
+            return ERROR_INVAL;
+        case LIBXL_CHANNEL_CONNECTION_PTY:
+            console->connection = libxl__strdup(NOGC, "pty");
+            console->output = libxl__sprintf(NOGC, "pty");
+            break;
+        case LIBXL_CHANNEL_CONNECTION_SOCKET:
+            if (!channel->u.socket.path) {
+                LOG(ERROR, "channel %d has no path", channel->devid);
+                return ERROR_INVAL;
+            }
+            console->connection = libxl__strdup(NOGC, "socket");
+            console->path = libxl__strdup(NOGC, channel->u.socket.path);
+            console->output = libxl__sprintf(NOGC, "chardev:libxl-channel%d",
+                                             channel->devid);
+            break;
+        default:
+            /* We've forgotten to add the clause */
+            LOG(ERROR, "%s: missing implementation for channel connection %d",
+                __func__, channel->connection);
+            abort();
+    }
+
+    console->devid = dev_num;
+    console->consback = LIBXL__CONSOLE_BACKEND_IOEMU;
+    console->backend_domid = channel->backend_domid;
+    console->name = libxl__strdup(NOGC, channel->name);
+
+    return 0;
+}
+
+static int libxl__device_channel_from_xenstore(libxl__gc *gc,
+                                            const char *libxl_path,
+                                            libxl_device_channel *channel)
+{
+    const char *tmp;
+    int rc;
+
+    libxl_device_channel_init(channel);
+
+    rc = libxl__xs_read_checked(NOGC, XBT_NULL,
+                                GCSPRINTF("%s/name", libxl_path),
+                                (const char **)(&channel->name));
+    if (rc) goto out;
+    rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                GCSPRINTF("%s/connection", libxl_path), &tmp);
+    if (rc) goto out;
+    if (!strcmp(tmp, "pty")) {
+        channel->connection = LIBXL_CHANNEL_CONNECTION_PTY;
+    } else if (!strcmp(tmp, "socket")) {
+        channel->connection = LIBXL_CHANNEL_CONNECTION_SOCKET;
+        rc = libxl__xs_read_checked(NOGC, XBT_NULL,
+                                    GCSPRINTF("%s/path", libxl_path),
+                                    (const char **)(&channel->u.socket.path));
+        if (rc) goto out;
+    } else {
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    rc = 0;
+ out:
+    return rc;
+}
+
+static int libxl__append_channel_list(libxl__gc *gc,
+                                              uint32_t domid,
+                                              libxl_device_channel **channels,
+                                              int *nchannels)
+{
+    char *libxl_dir_path = NULL;
+    char **dir = NULL;
+    unsigned int n = 0, devid = 0;
+    libxl_device_channel *next = NULL;
+    int rc = 0, i;
+
+    libxl_dir_path = GCSPRINTF("%s/device/console",
+                               libxl__xs_libxl_path(gc, domid));
+    dir = libxl__xs_directory(gc, XBT_NULL, libxl_dir_path, &n);
+    if (!dir || !n)
+      goto out;
+
+    for (i = 0; i < n; i++) {
+        const char *libxl_path, *name;
+        libxl_device_channel *tmp;
+
+        libxl_path = GCSPRINTF("%s/%s", libxl_dir_path, dir[i]);
+        name = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/name", libxl_path));
+        /* 'channels' are consoles with names, so ignore all consoles
+           without names */
+        if (!name) continue;
+        tmp = realloc(*channels,
+                      sizeof(libxl_device_channel) * (*nchannels + devid + 1));
+        if (!tmp) {
+          rc = ERROR_NOMEM;
+          goto out;
+        }
+        *channels = tmp;
+        next = *channels + *nchannels + devid;
+        rc = libxl__device_channel_from_xenstore(gc, libxl_path, next);
+        if (rc) goto out;
+        next->devid = devid;
+        devid++;
+    }
+    *nchannels += devid;
+    return 0;
+
+ out:
+    return rc;
+}
+
+libxl_device_channel *libxl_device_channel_list(libxl_ctx *ctx,
+                                                uint32_t domid,
+                                                int *num)
+{
+    GC_INIT(ctx);
+    libxl_device_channel *channels = NULL;
+    int rc;
+
+    *num = 0;
+
+    rc = libxl__append_channel_list(gc, domid, &channels, num);
+    if (rc) goto out_err;
+
+    GC_FREE;
+    return channels;
+
+out_err:
+    LOGD(ERROR, domid, "Unable to list channels");
+    while (*num) {
+        (*num)--;
+        libxl_device_channel_dispose(&channels[*num]);
+    }
+    free(channels);
+    return NULL;
+}
+
+int libxl_device_channel_getinfo(libxl_ctx *ctx, uint32_t domid,
+                                 libxl_device_channel *channel,
+                                 libxl_channelinfo *channelinfo)
+{
+    GC_INIT(ctx);
+    char *dompath, *fe_path, *libxl_path;
+    char *val;
+    int rc;
+
+    dompath = libxl__xs_get_dompath(gc, domid);
+    channelinfo->devid = channel->devid;
+
+    fe_path = GCSPRINTF("%s/device/console/%d", dompath,
+                        channelinfo->devid + 1);
+    libxl_path = GCSPRINTF("%s/device/console/%d",
+                           libxl__xs_libxl_path(gc, domid),
+                           channelinfo->devid + 1);
+    channelinfo->backend = xs_read(ctx->xsh, XBT_NULL,
+                                   GCSPRINTF("%s/backend", libxl_path), NULL);
+    if (!channelinfo->backend) {
+        GC_FREE;
+        return ERROR_FAIL;
+    }
+    rc = libxl__backendpath_parse_domid(gc, channelinfo->backend,
+                                        &channelinfo->backend_id);
+    if (rc) goto out;
+
+    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/state", fe_path));
+    channelinfo->state = val ? strtoul(val, NULL, 10) : -1;
+    channelinfo->frontend = libxl__strdup(NOGC, fe_path);
+    channelinfo->frontend_id = domid;
+    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/ring-ref", fe_path));
+    channelinfo->rref = val ? strtoul(val, NULL, 10) : -1;
+    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/port", fe_path));
+    channelinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
+
+    channelinfo->connection = channel->connection;
+    switch (channel->connection) {
+         case LIBXL_CHANNEL_CONNECTION_PTY:
+             val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/tty", fe_path));
+             /*
+              * It is obviously very wrong for this value to be in the
+              * frontend.  But in XSA-175 we don't want to re-engineer
+              * this because other xenconsole code elsewhere (some
+              * even out of tree, perhaps) expects this node to be
+              * here.
+              *
+              * FE/pty is readonly for the guest.  It always exists if
+              * FE does because libxl__device_console_add
+              * unconditionally creates it and nothing deletes it.
+              *
+              * The guest can delete the whole FE (which it has write
+              * privilege on) but the containing directories
+              * /local/GUEST[/device[/console]] are also RO for the
+              * guest.  So if the guest deletes FE it cannot recreate
+              * it.
+              *
+              * Therefore the guest cannot cause FE/pty to contain bad
+              * data, although it can cause it to not exist.
+              */
+             if (!val) val = "/NO-SUCH-PATH";
+             channelinfo->u.pty.path = strdup(val);
+             break;
+         default:
+             break;
+    }
+    rc = 0;
+ out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl__device_vkb_setdefault(libxl__gc *gc, libxl_device_vkb *vkb)
+{
+    int rc;
+    rc = libxl__resolve_domid(gc, vkb->backend_domname, &vkb->backend_domid);
+    return rc;
+}
+
+static int libxl__device_from_vkb(libxl__gc *gc, uint32_t domid,
+                                  libxl_device_vkb *vkb,
+                                  libxl__device *device)
+{
+    device->backend_devid = vkb->devid;
+    device->backend_domid = vkb->backend_domid;
+    device->backend_kind = LIBXL__DEVICE_KIND_VKBD;
+    device->devid = vkb->devid;
+    device->domid = domid;
+    device->kind = LIBXL__DEVICE_KIND_VKBD;
+
+    return 0;
+}
+
+int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb,
+                         const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    int rc;
+
+    rc = libxl__device_vkb_add(gc, domid, vkb);
+    if (rc) {
+        LOGD(ERROR, domid, "Unable to add vkb device");
+        goto out;
+    }
+
+out:
+    libxl__ao_complete(egc, ao, rc);
+    return AO_INPROGRESS;
+}
+
+int libxl__device_vkb_add(libxl__gc *gc, uint32_t domid,
+                          libxl_device_vkb *vkb)
+{
+    flexarray_t *front;
+    flexarray_t *back;
+    libxl__device device;
+    int rc;
+
+    rc = libxl__device_vkb_setdefault(gc, vkb);
+    if (rc) goto out;
+
+    front = flexarray_make(gc, 16, 1);
+    back = flexarray_make(gc, 16, 1);
+
+    if (vkb->devid == -1) {
+        if ((vkb->devid = libxl__device_nextid(gc, domid, "vkb")) < 0) {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
+    rc = libxl__device_from_vkb(gc, domid, vkb, &device);
+    if (rc != 0) goto out;
+
+    flexarray_append(back, "frontend-id");
+    flexarray_append(back, GCSPRINTF("%d", domid));
+    flexarray_append(back, "online");
+    flexarray_append(back, "1");
+    flexarray_append(back, "state");
+    flexarray_append(back, GCSPRINTF("%d", XenbusStateInitialising));
+
+    flexarray_append(front, "backend-id");
+    flexarray_append(front, GCSPRINTF("%d", vkb->backend_domid));
+    flexarray_append(front, "state");
+    flexarray_append(front, GCSPRINTF("%d", XenbusStateInitialising));
+
+    libxl__device_generic_add(gc, XBT_NULL, &device,
+                              libxl__xs_kvs_of_flexarray(gc, back),
+                              libxl__xs_kvs_of_flexarray(gc, front),
+                              NULL);
+    rc = 0;
+out:
+    return rc;
+}
+
+int libxl__device_vfb_setdefault(libxl__gc *gc, libxl_device_vfb *vfb)
+{
+    int rc;
+
+    libxl_defbool_setdefault(&vfb->vnc.enable, true);
+    if (libxl_defbool_val(vfb->vnc.enable)) {
+        if (!vfb->vnc.listen) {
+            vfb->vnc.listen = strdup("127.0.0.1");
+            if (!vfb->vnc.listen) return ERROR_NOMEM;
+        }
+
+        libxl_defbool_setdefault(&vfb->vnc.findunused, true);
+    } else {
+        libxl_defbool_setdefault(&vfb->vnc.findunused, false);
+    }
+
+    libxl_defbool_setdefault(&vfb->sdl.enable, false);
+    libxl_defbool_setdefault(&vfb->sdl.opengl, false);
+
+    rc = libxl__resolve_domid(gc, vfb->backend_domname, &vfb->backend_domid);
+    return rc;
+}
+
+static int libxl__device_from_vfb(libxl__gc *gc, uint32_t domid,
+                                  libxl_device_vfb *vfb,
+                                  libxl__device *device)
+{
+    device->backend_devid = vfb->devid;
+    device->backend_domid = vfb->backend_domid;
+    device->backend_kind = LIBXL__DEVICE_KIND_VFB;
+    device->devid = vfb->devid;
+    device->domid = domid;
+    device->kind = LIBXL__DEVICE_KIND_VFB;
+    return 0;
+}
+
+int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb,
+                         const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    int rc;
+
+    rc = libxl__device_vfb_add(gc, domid, vfb);
+    if (rc) {
+        LOGD(ERROR, domid, "Unable to add vfb device");
+        goto out;
+    }
+
+out:
+    libxl__ao_complete(egc, ao, rc);
+    return AO_INPROGRESS;
+}
+
+int libxl__device_vfb_add(libxl__gc *gc, uint32_t domid, libxl_device_vfb *vfb)
+{
+    flexarray_t *front;
+    flexarray_t *back;
+    libxl__device device;
+    int rc;
+
+    rc = libxl__device_vfb_setdefault(gc, vfb);
+    if (rc) goto out;
+
+    front = flexarray_make(gc, 16, 1);
+    back = flexarray_make(gc, 16, 1);
+
+    if (vfb->devid == -1) {
+        if ((vfb->devid = libxl__device_nextid(gc, domid, "vfb")) < 0) {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
+    rc = libxl__device_from_vfb(gc, domid, vfb, &device);
+    if (rc != 0) goto out;
+
+    flexarray_append_pair(back, "frontend-id", GCSPRINTF("%d", domid));
+    flexarray_append_pair(back, "online", "1");
+    flexarray_append_pair(back, "state", GCSPRINTF("%d", 
XenbusStateInitialising));
+    flexarray_append_pair(back, "vnc",
+                          libxl_defbool_val(vfb->vnc.enable) ? "1" : "0");
+    flexarray_append_pair(back, "vnclisten", vfb->vnc.listen);
+    flexarray_append_pair(back, "vncpasswd", vfb->vnc.passwd);
+    flexarray_append_pair(back, "vncdisplay",
+                          GCSPRINTF("%d", vfb->vnc.display));
+    flexarray_append_pair(back, "vncunused",
+                          libxl_defbool_val(vfb->vnc.findunused) ? "1" : "0");
+    flexarray_append_pair(back, "sdl",
+                          libxl_defbool_val(vfb->sdl.enable) ? "1" : "0");
+    flexarray_append_pair(back, "opengl",
+                          libxl_defbool_val(vfb->sdl.opengl) ? "1" : "0");
+    if (vfb->sdl.xauthority) {
+        flexarray_append_pair(back, "xauthority", vfb->sdl.xauthority);
+    }
+    if (vfb->sdl.display) {
+        flexarray_append_pair(back, "display", vfb->sdl.display);
+    }
+
+    flexarray_append_pair(front, "backend-id",
+                          GCSPRINTF("%d", vfb->backend_domid));
+    flexarray_append_pair(front, "state", GCSPRINTF("%d", 
XenbusStateInitialising));
+
+    libxl__device_generic_add(gc, XBT_NULL, &device,
+                              libxl__xs_kvs_of_flexarray(gc, back),
+                              libxl__xs_kvs_of_flexarray(gc, front),
+                              NULL);
+    rc = 0;
+out:
+    return rc;
+}
+
+/* The following functions are defined:
+ * libxl_device_vkb_remove
+ * libxl_device_vkb_destroy
+ * libxl_device_vfb_remove
+ * libxl_device_vfb_destroy
+ */
+
+/* channel/console hotunplug is not implemented. There are 2 possibilities:
+ * 1. add support for secondary consoles to xenconsoled
+ * 2. dynamically add/remove qemu chardevs via qmp messages. */
+
+/* vkb */
+LIBXL_DEFINE_DEVICE_REMOVE(vkb)
+
+/* vfb */
+LIBXL_DEFINE_DEVICE_REMOVE(vfb)
+
+libxl_xen_console_reader *
+    libxl_xen_console_read_start(libxl_ctx *ctx, int clear)
+{
+    GC_INIT(ctx);
+    libxl_xen_console_reader *cr;
+    unsigned int size = 16384;
+
+    cr = libxl__zalloc(NOGC, sizeof(libxl_xen_console_reader));
+    cr->buffer = libxl__zalloc(NOGC, size);
+    cr->size = size;
+    cr->count = size;
+    cr->clear = clear;
+    cr->incremental = 1;
+
+    GC_FREE;
+    return cr;
+}
+
+/* return values:                                          *line_r
+ *   1          success, whole line obtained from buffer    non-0
+ *   0          no more lines available right now           0
+ *   negative   error code ERROR_*                          0
+ * On success *line_r is updated to point to a nul-terminated
+ * string which is valid until the next call on the same console
+ * reader.  The libxl caller may overwrite parts of the string
+ * if it wishes. */
+int libxl_xen_console_read_line(libxl_ctx *ctx,
+                                libxl_xen_console_reader *cr,
+                                char **line_r)
+{
+    int ret;
+    GC_INIT(ctx);
+
+    memset(cr->buffer, 0, cr->size);
+    ret = xc_readconsolering(ctx->xch, cr->buffer, &cr->count,
+                             cr->clear, cr->incremental, &cr->index);
+    if (ret < 0) {
+        LOGE(ERROR, "reading console ring buffer");
+        GC_FREE;
+        return ERROR_FAIL;
+    }
+    if (!ret) {
+        if (cr->count) {
+            *line_r = cr->buffer;
+            ret = 1;
+        } else {
+            *line_r = NULL;
+            ret = 0;
+        }
+    }
+
+    GC_FREE;
+    return ret;
+}
+
+void libxl_xen_console_read_finish(libxl_ctx *ctx,
+                                   libxl_xen_console_reader *cr)
+{
+    free(cr->buffer);
+    free(cr);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.10.2


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.