[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |