aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2009-11-09 19:54:28 +0000
committerKeir Fraser <keir.fraser@citrix.com>2009-11-09 19:54:28 +0000
commitc5c301ac774d8cb36ccbc775bb7f1d7005d78a71 (patch)
tree8fcd7201e14424ae0b5041f186087e06639a69f6
parent85f5921bdf8216ae1fd9cb5963f897562f1b2380 (diff)
downloadxen-c5c301ac774d8cb36ccbc775bb7f1d7005d78a71.tar.gz
xen-c5c301ac774d8cb36ccbc775bb7f1d7005d78a71.tar.bz2
xen-c5c301ac774d8cb36ccbc775bb7f1d7005d78a71.zip
libxenlight: initial libxenlight implementation under tools/libxl
Signed-off-by: Vincent Hanquez <Vincent.Hanquez@eu.citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
-rw-r--r--tools/Makefile1
-rw-r--r--tools/libxl/Makefile72
-rw-r--r--tools/libxl/flexarray.c78
-rw-r--r--tools/libxl/flexarray.h33
-rw-r--r--tools/libxl/libxl.c742
-rw-r--r--tools/libxl/libxl.h200
-rw-r--r--tools/libxl/libxl_device.c241
-rw-r--r--tools/libxl/libxl_dom.c271
-rw-r--r--tools/libxl/libxl_exec.c48
-rw-r--r--tools/libxl/libxl_internal.c159
-rw-r--r--tools/libxl/libxl_internal.h135
-rw-r--r--tools/libxl/libxl_utils.c159
-rw-r--r--tools/libxl/libxl_utils.h34
-rw-r--r--tools/libxl/libxl_xshelp.c108
-rw-r--r--tools/libxl/osdeps.c62
-rw-r--r--tools/libxl/osdeps.h24
-rw-r--r--tools/libxl/xenguest.c49
-rw-r--r--tools/libxl/xl.c727
18 files changed, 3143 insertions, 0 deletions
diff --git a/tools/Makefile b/tools/Makefile
index 78b3990604..3170b95886 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -32,6 +32,7 @@ SUBDIRS-$(CONFIG_Linux) += fs-back
SUBDIRS-$(CONFIG_NetBSD) += fs-back
SUBDIRS-$(CONFIG_IOEMU) += ioemu-dir
SUBDIRS-y += xenpmd
+SUBDIRS-y += libxl
# These don't cross-compile
ifeq ($(XEN_COMPILE_ARCH),$(XEN_TARGET_ARCH))
diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
new file mode 100644
index 0000000000..30e236d145
--- /dev/null
+++ b/tools/libxl/Makefile
@@ -0,0 +1,72 @@
+#
+# tools/libxl/Makefile
+#
+
+XEN_ROOT = ../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+MAJOR = 1.0
+MINOR = 0
+
+#CFLAGS += -Werror
+CFLAGS += -I. -fPIC
+CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) $(CFLAGS_libxenstore)
+
+LDFLAGS = $(LDFLAGS_libxenctrl) $(LDFLAGS_libxenguest) $(LDFLAGS_libxenstore) -luuid
+
+LIBCONFIG_URL ?= http://www.hyperrealm.com/libconfig
+LIBCONFIG_SOURCE = libconfig-1.3.2
+LIBCONFIG_OUTPUT = $(LIBCONFIG_SOURCE)/.libs
+WGET=wget -c
+
+LIBXL_OBJS = flexarray.o libxl.o libxl_dom.o libxl_exec.o libxl_xshelp.o libxl_device.o libxl_internal.o xenguest.o osdeps.o libxl_utils.o
+
+CLIENTS = xl
+
+.PHONY: all
+all: $(CLIENTS) libxenlight.so libxenlight.a
+
+libxenlight.so: libxenlight.so.$(MAJOR)
+ ln -sf $< $@
+
+libxenlight.so.$(MAJOR): libxenlight.so.$(MAJOR).$(MINOR)
+ ln -sf $< $@
+
+libxenlight.so.$(MAJOR).$(MINOR): $(LIBXL_OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenlight.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $^
+
+libxenlight.a: $(LIBXL_OBJS)
+ $(AR) rcs libxenlight.a $^
+
+$(LIBCONFIG_SOURCE).tar.gz:
+ $(WGET) $(LIBCONFIG_URL)/$@
+
+$(LIBCONFIG_SOURCE): $(LIBCONFIG_SOURCE).tar.gz
+ tar xzf $<
+
+$(LIBCONFIG_OUTPUT)/libconfig.so: $(LIBCONFIG_SOURCE)
+ cd $(LIBCONFIG_SOURCE) && ./configure --prefix=$(DESTDIR)$(PREFIX) && $(MAKE)
+
+xl.o: $(LIBCONFIG_SOURCE)
+ $(CC) $(CFLAGS) -I$(LIBCONFIG_SOURCE) -c xl.c
+
+$(CLIENTS): xl.o libxenlight.so $(LIBCONFIG_OUTPUT)/libconfig.so
+ $(CC) $(LDFLAGS) -o $@ $< -L . -lxenlight -L$(LIBCONFIG_OUTPUT) -lconfig
+
+.PHONY: install
+install: all
+ $(INSTALL_PROG) xl $(DESTDIR)$(SBINDIR)
+ $(INSTALL_PROG) libxenlight.so.$(MAJOR).$(MINOR) $(DESTDIR)$(LIBDIR)
+ ln -sf libxenlight.so.$(MAJOR).$(MINOR) $(DESTDIR)$(LIBDIR)/libxenlight.so.$(MAJOR)
+ ln -sf libxenlight.so.$(MAJOR) $(DESTDIR)$(LIBDIR)/libxenlight.so
+ $(INSTALL_DATA) libxenlight.a $(DESTDIR)$(LIBDIR)
+ cd $(LIBCONFIG_SOURCE) && DESTDIR= $(MAKE) install
+
+.PHONY: clean
+clean:
+ $(RM) -f *.o *.so* *.a $(CLIENTS)
+ $(RM) -rf $(LIBCONFIG_SOURCE)
+
+distclean: clean
+ $(RM) -f $(LIBCONFIG_SOURCE).tar.gz
+
diff --git a/tools/libxl/flexarray.c b/tools/libxl/flexarray.c
new file mode 100644
index 0000000000..ba7f5e1902
--- /dev/null
+++ b/tools/libxl/flexarray.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * 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 <stdlib.h>
+#include "flexarray.h"
+
+flexarray_t *flexarray_make(int size, int autogrow)
+{
+ flexarray_t *array = malloc(sizeof(struct flexarray));
+ if (array) {
+ array->size = size;
+ array->autogrow = autogrow;
+ array->data = calloc(size, sizeof(void *));
+ }
+ return array;
+}
+
+void flexarray_free(flexarray_t *array)
+{
+ free(array->data);
+ free(array);
+}
+
+int flexarray_grow(flexarray_t *array, int extents)
+{
+ void **data;
+ int newsize;
+
+ newsize = array->size + extents;
+ data = realloc(array->data, sizeof(void *) * newsize);
+ if (!data)
+ return 1;
+ array->size += extents;
+ array->data = data;
+ return 0;
+}
+
+int flexarray_set(flexarray_t *array, unsigned int index, void *ptr)
+{
+ if (index >= array->size) {
+ int newsize;
+ if (!array->autogrow)
+ return 1;
+ newsize = (array->size * 2 < index) ? index + 1 : array->size * 2;
+ if (flexarray_grow(array, newsize - array->size))
+ return 2;
+ }
+ array->data[index] = ptr;
+ return 0;
+}
+
+int flexarray_get(flexarray_t *array, int index, void **ptr)
+{
+ if (index >= array->size)
+ return 1;
+ *ptr = array->data[index];
+ return 0;
+}
+
+void **flexarray_contents(flexarray_t *array)
+{
+ void **data;
+ data = array->data;
+ free(array);
+ return data;
+}
diff --git a/tools/libxl/flexarray.h b/tools/libxl/flexarray.h
new file mode 100644
index 0000000000..70e4c1aad3
--- /dev/null
+++ b/tools/libxl/flexarray.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * 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.
+ */
+
+#ifndef FLEXARRAY_H
+#define FLEXARRAY_H
+
+typedef struct flexarray {
+ int size;
+ int autogrow;
+ void **data; /* array of pointer */
+} flexarray_t;
+
+flexarray_t *flexarray_make(int size, int autogrow);
+void flexarray_free(flexarray_t *array);
+int flexarray_grow(flexarray_t *array, int extents);
+int flexarray_set(flexarray_t *array, unsigned int index, void *ptr);
+int flexarray_get(flexarray_t *array, int index, void **ptr);
+
+void **flexarray_contents(flexarray_t *array);
+
+#endif
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
new file mode 100644
index 0000000000..05f136ae38
--- /dev/null
+++ b/tools/libxl/libxl.c
@@ -0,0 +1,742 @@
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/select.h>
+#include <signal.h>
+#include "libxl.h"
+#include "libxl_utils.h"
+#include "libxl_internal.h"
+#include "flexarray.h"
+
+int libxl_ctx_init(struct libxl_ctx *ctx)
+{
+ memset(ctx, 0, sizeof(struct libxl_ctx));
+ ctx->alloc_maxsize = 256;
+ ctx->alloc_ptrs = calloc(ctx->alloc_maxsize, sizeof(void *));
+ if (!ctx->alloc_ptrs)
+ return ERROR_NOMEM;
+
+ ctx->xch = xc_interface_open();
+ ctx->xsh = xs_daemon_open();
+ return 0;
+}
+
+int libxl_ctx_free(struct libxl_ctx *ctx)
+{
+ libxl_free_all(ctx);
+ free(ctx->alloc_ptrs);
+ ctx->alloc_ptrs = NULL;
+ xc_interface_close(ctx->xch);
+ xs_daemon_close(ctx->xsh);
+ return 0;
+}
+
+int libxl_ctx_set_log(struct libxl_ctx *ctx, libxl_log_callback log_callback, void *log_data)
+{
+ ctx->log_callback = log_callback;
+ ctx->log_userdata = log_data;
+ return 0;
+}
+
+/******************************************************************************/
+
+int libxl_domain_make(struct libxl_ctx *ctx, libxl_domain_create_info *info,
+ uint32_t *domid)
+{
+ int flags, ret, i;
+ char *uuid_string;
+ char *rw_paths[] = { "device" };
+ char *ro_paths[] = { "cpu", "memory", "device", "error", "drivers",
+ "control", "attr", "data", "messages" };
+ char *dom_path, *vm_path, *vss_path;
+ struct xs_permissions roperm[2];
+ struct xs_permissions rwperm[1];
+ xs_transaction_t t;
+
+ uuid_string = uuid_to_string(ctx, info->uuid);
+ if (!uuid_string) {
+ XL_LOG(ctx, XL_LOG_ERROR, "missing uuid");
+ return ERROR_FAIL;
+ }
+
+ flags = info->hvm ? XEN_DOMCTL_CDF_hvm_guest : 0;
+ flags |= info->hap ? XEN_DOMCTL_CDF_hap : 0;
+ *domid = 0;
+
+ ret = xc_domain_create(ctx->xch, info->ssidref, info->uuid, flags, domid);
+ if (ret < 0) {
+ XL_LOG(ctx, XL_LOG_ERROR, "domain creation fail: %d", ret);
+ return ERROR_FAIL;
+ }
+
+ dom_path = libxl_xs_get_dompath(ctx, *domid);
+ vm_path = libxl_sprintf(ctx, "/vm/%s", uuid_string);
+ vss_path = libxl_sprintf(ctx, "/vss/%s", uuid_string);
+ if (!dom_path || !vm_path || !vss_path) {
+ XL_LOG(ctx, XL_LOG_ERROR, "cannot allocate create paths");
+ return ERROR_FAIL;
+ }
+
+ roperm[0].id = 0;
+ roperm[0].perms = XS_PERM_NONE;
+ roperm[1].id = *domid;
+ roperm[1].perms = XS_PERM_READ;
+ rwperm[0].id = *domid;
+ rwperm[0].perms = XS_PERM_NONE;
+
+retry_transaction:
+ t = xs_transaction_start(ctx->xsh);
+ xs_rm(ctx->xsh, t, dom_path);
+ xs_mkdir(ctx->xsh, t, dom_path);
+ xs_set_permissions(ctx->xsh, t, dom_path, roperm, ARRAY_SIZE(roperm));
+
+ xs_rm(ctx->xsh, t, vm_path);
+ xs_mkdir(ctx->xsh, t, vm_path);
+ xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm));
+
+ xs_rm(ctx->xsh, t, vss_path);
+ xs_mkdir(ctx->xsh, t, vss_path);
+ xs_set_permissions(ctx->xsh, t, vss_path, rwperm, ARRAY_SIZE(rwperm));
+
+ xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vm", dom_path), vm_path, strlen(vm_path));
+ xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vss", dom_path), vss_path, strlen(vss_path));
+ xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/name", dom_path), info->name, strlen(info->name));
+
+ for (i = 0; i < ARRAY_SIZE(rw_paths); i++) {
+ char *path = libxl_sprintf(ctx, "%s/%s", dom_path, rw_paths[i]);
+ xs_mkdir(ctx->xsh, t, path);
+ xs_set_permissions(ctx->xsh, t, path, rwperm, ARRAY_SIZE(rwperm));
+ libxl_free(ctx, path);
+ }
+ for (i = 0; i < ARRAY_SIZE(ro_paths); i++) {
+ char *path = libxl_sprintf(ctx, "%s/%s", dom_path, ro_paths[i]);
+ xs_mkdir(ctx->xsh, t, path);
+ xs_set_permissions(ctx->xsh, t, path, roperm, ARRAY_SIZE(roperm));
+ libxl_free(ctx, path);
+ }
+
+ xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/uuid", vm_path), uuid_string, strlen(uuid_string));
+ xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/name", vm_path), info->name, strlen(info->name));
+
+ libxl_xs_writev(ctx, t, dom_path, info->xsdata);
+ libxl_xs_writev(ctx, t, libxl_sprintf(ctx, "%s/platform", dom_path), info->platformdata);
+
+ xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/control/platform-feature-multiprocessor-suspend", dom_path), "1", 1);
+
+ if (!xs_transaction_end(ctx->xsh, t, 0))
+ if (errno == EAGAIN)
+ goto retry_transaction;
+ return 0;
+}
+
+int libxl_domain_build(struct libxl_ctx *ctx, libxl_domain_build_info *info, uint32_t domid)
+{
+ libxl_domain_build_state state;
+ char **vments = NULL, **localents = NULL;
+
+ memset(&state, '\0', sizeof(state));
+
+ build_pre(ctx, domid, info, &state);
+ if (info->hvm) {
+ build_hvm(ctx, domid, info, &state);
+ vments = libxl_calloc(ctx, 4, sizeof(char *));
+ vments[0] = libxl_sprintf(ctx, "rtc/timeoffset");
+ vments[1] = libxl_sprintf(ctx, "%s", (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "");
+ } else {
+ build_pv(ctx, domid, info, &state);
+ }
+ build_post(ctx, domid, info, &state, vments, localents);
+ return 0;
+}
+
+int libxl_domain_restore(struct libxl_ctx *ctx, libxl_domain_build_info *info,
+ uint32_t domid, int fd)
+{
+ libxl_domain_build_state state;
+ char **vments = NULL, **localents = NULL;
+
+ memset(&state, '\0', sizeof(state));
+
+ build_pre(ctx, domid, info, &state);
+ restore_common(ctx, domid, info, &state, fd);
+ if (info->hvm) {
+ vments = libxl_calloc(ctx, 4, sizeof(char *));
+ vments[0] = libxl_sprintf(ctx, "rtc/timeoffset");
+ vments[1] = libxl_sprintf(ctx, "%s", (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "");
+ } else {
+ localents = libxl_calloc(ctx, 4 * 2, sizeof(char *));
+ localents[0] = libxl_sprintf(ctx, "serial/0/limit");
+ localents[1] = libxl_sprintf(ctx, "%d", 65536);
+ localents[2] = libxl_sprintf(ctx, "console/port");
+ localents[3] = libxl_sprintf(ctx, "%d", state.console_port);
+ localents[4] = libxl_sprintf(ctx, "console/ring-ref");
+ localents[5] = libxl_sprintf(ctx, "%ld", state.console_mfn);
+ }
+ build_post(ctx, domid, info, &state, vments, localents);
+ return 0;
+}
+
+struct libxl_dominfo * libxl_domain_list(struct libxl_ctx *ctx, int *nb_domain)
+{
+ struct libxl_dominfo *ptr;
+ int index, i, ret, first_domain;
+ xc_domaininfo_t info[16];
+ int size = 16;
+
+ first_domain = 1;
+ index = 0;
+ ptr = libxl_calloc(ctx, size, sizeof(struct libxl_dominfo));
+ if (!ptr)
+ return NULL;
+redo:
+ ret = xc_domain_getinfolist(ctx->xch, first_domain, 16, info);
+ for (i = 0; i < ret; i++) {
+ if (index == size) {
+ struct libxl_dominfo *ptr2;
+
+ ptr2 = libxl_calloc(ctx, size * 2, sizeof(struct libxl_dominfo));
+ if (!ptr2) {
+ libxl_free(ctx, ptr);
+ return NULL;
+ }
+ memcpy(ptr2, ptr, sizeof(struct libxl_dominfo) * size);
+ libxl_free(ctx, ptr);
+ ptr = ptr2;
+ size *= 2;
+ }
+ memcpy(ptr[index].uuid, info[i].handle, 16 * sizeof(uint8_t));
+ ptr[index].domid = info[i].domain;
+ first_domain = info[i].domain + 1;
+ index++;
+ }
+ if (ret == 16)
+ goto redo;
+ *nb_domain = index;
+ return ptr;
+}
+
+xc_dominfo_t * libxl_domain_infolist(struct libxl_ctx *ctx, int *nb_domain)
+{
+ int index, first_domain;
+ xc_dominfo_t *info;
+ int size = 1024;
+
+ first_domain = 0;
+ index = 0;
+ info = (xc_dominfo_t *) libxl_calloc(ctx, size, sizeof(xc_dominfo_t));
+ if (!info) {
+ *nb_domain = 0;
+ return NULL;
+ }
+ *nb_domain = xc_domain_getinfo(ctx->xch, first_domain, 1024, info);
+ return info;
+}
+
+int libxl_domain_suspend(struct libxl_ctx *ctx, libxl_domain_suspend_info *info,
+ uint32_t domid, int fd)
+{
+ int hvm = 1;
+ int live = 0;
+ int debug = 0;
+ char savesig[] = "XenSavedDomain\n";
+
+ write(fd, savesig, strlen(savesig));
+
+ core_suspend(ctx, domid, fd, hvm, live, debug);
+
+ return 0;
+}
+
+int libxl_domain_pause(struct libxl_ctx *ctx, uint32_t domid)
+{
+ xc_domain_pause(ctx->xch, domid);
+ return 0;
+}
+
+int libxl_domain_unpause(struct libxl_ctx *ctx, uint32_t domid)
+{
+ xc_domain_unpause(ctx->xch, domid);
+ return 0;
+}
+
+static char *req_table[] = {
+ [0] = "poweroff",
+ [1] = "reboot",
+ [2] = "suspend",
+ [3] = "crash",
+ [4] = "halt",
+};
+
+int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req)
+{
+ char *shutdown_path;
+ char *dom_path;
+
+ if (req > ARRAY_SIZE(req_table))
+ return ERROR_INVAL;
+
+ dom_path = libxl_xs_get_dompath(ctx, domid);
+ shutdown_path = libxl_sprintf(ctx, "%s/control/shutdown", dom_path);
+
+ xs_write(ctx->xsh, XBT_NULL, shutdown_path, req_table[req], strlen(req_table[req]));
+ if (/* hvm */ 0) {
+ unsigned long acpi_s_state = 0;
+ unsigned long pvdriver = 0;
+ xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_ACPI_S_STATE, &acpi_s_state);
+ xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_CALLBACK_IRQ, &pvdriver);
+ if (!pvdriver && acpi_s_state != 0)
+ xc_domain_shutdown(ctx->xch, domid, req);
+ }
+ return 0;
+}
+
+static int libxl_destroy_device_model(struct libxl_ctx *ctx, uint32_t domid)
+{
+ char *pid;
+ int ret;
+
+ pid = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/%d/image/device-model-pid", domid));
+ if (!pid) {
+ XL_LOG(ctx, XL_LOG_ERROR, "Couldn't find device model's pid\n");
+ return -1;
+ }
+ xs_rm(ctx->xsh, XBT_NULL, libxl_sprintf(ctx, "/local/domain/0/device-model/%d", domid));
+
+ ret = kill(atoi(pid), SIGHUP);
+ if (ret < 0 && errno == ESRCH) {
+ XL_LOG(ctx, XL_LOG_DEBUG, "Device Model already exited\n");
+ ret = 0;
+ } else if (ret == 0) {
+ XL_LOG(ctx, XL_LOG_DEBUG, "Device Model signaled\n");
+ ret = 0;
+ } else {
+ XL_LOG(ctx, XL_LOG_ERROR, "kill %d returned %d errno=%d\n", atoi(pid), ret, errno);
+ }
+ return ret;
+}
+
+int libxl_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force)
+{
+ char *dom_path, vm_path[41];
+ uint8_t *uuid;
+
+ dom_path = libxl_xs_get_dompath(ctx, domid);
+ if (!dom_path) {
+ XL_LOG(ctx, XL_LOG_ERROR, "dompath doesn't exist for %d\n", domid);
+ return -1;
+ }
+ if (libxl_domid_to_uuid(ctx, &uuid, domid) < 0) {
+ XL_LOG(ctx, XL_LOG_ERROR, "failed ot get uuid for %d\n", domid);
+ return -1;
+ }
+ xs_write(ctx->xsh, XBT_NULL,
+ libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid),
+ "shutdown", strlen("shutdown"));
+ if (xc_domain_pause(ctx->xch, domid) < 0) {
+ XL_LOG(ctx, XL_LOG_ERROR, "xc_domain_pause failed for %d\n", domid);
+ return -1;
+ }
+ /* do_FLR */
+ if (xc_domain_destroy(ctx->xch, domid) < 0) {
+ XL_LOG(ctx, XL_LOG_ERROR, "xc_domain_destroy failed for %d\n", domid);
+ return -1;
+ }
+ if (libxl_devices_destroy(ctx, domid, force) < 0)
+ XL_LOG(ctx, XL_LOG_ERROR, "libxl_destroy_devices failed for %d\n", domid);
+ if (libxl_destroy_device_model(ctx, domid) < 0)
+ XL_LOG(ctx, XL_LOG_ERROR, "libxl_destroy_device_model failed for %d\n", domid);
+ if (!xs_rm(ctx->xsh, XBT_NULL, dom_path))
+ XL_LOG(ctx, XL_LOG_ERROR, "xs_rm failed for %s\n", dom_path);
+ snprintf(vm_path, sizeof(vm_path), "/vm/%s", uuid_to_string(ctx, uuid));
+ if (!xs_rm(ctx->xsh, XBT_NULL, vm_path))
+ XL_LOG(ctx, XL_LOG_ERROR, "xs_rm failed for %s\n", vm_path);
+ return 0;
+}
+
+static char ** libxl_build_device_model_args(struct libxl_ctx *ctx,
+ libxl_device_model_info *info,
+ libxl_device_nic *vifs,
+ int num_vifs)
+{
+ int num = 0, i;
+ flexarray_t *dm_args;
+ dm_args = flexarray_make(16, 1);
+ if (!dm_args)
+ return NULL;
+
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "qemu-dm"));
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-d"));
+
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d", info->domid));
+
+ if (info->dom_name) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-domain-name"));
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->dom_name));
+ }
+ if (info->videoram) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-videoram"));
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d", info->videoram));
+ }
+ if (info->stdvga) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-std-vga"));
+ }
+ if (info->vnc || info->vncdisplay || info->vnclisten || info->vncunused) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-vnc"));
+ if (info->vncdisplay) {
+ if (info->vnclisten && strchr(info->vnclisten, ':') == NULL) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s:%d", info->vnclisten, info->vncdisplay));
+ } else {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "127.0.0.1:%d", info->vncdisplay));
+ }
+ } else if (info->vnclisten) {
+ if (strchr(info->vnclisten, ':') != NULL) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->vnclisten));
+ } else {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s:0", info->vnclisten));
+ }
+ } else {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "127.0.0.1:0"));
+ }
+ if (info->vncunused) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-vncunused"));
+ }
+ }
+ if (info->sdl || info->opengl) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-sdl"));
+ if (info->opengl) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-disable-opengl"));
+ }
+ }
+ if (info->keymap) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-k"));
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->keymap));
+ }
+ if (info->nographic && (!info->sdl && !info->vnc)) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-nographic"));
+ }
+ if (info->serial) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-serial"));
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->serial));
+ }
+ if (info->boot) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-boot"));
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->boot));
+ }
+ if (info->usb) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-usb"));
+ if (info->usbdevice) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-usbdevice"));
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->usbdevice));
+ }
+ }
+ if (info->apic) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-acpi"));
+ }
+ if (info->extra) {
+ int i = 0;
+ while (info->extra[i] != NULL) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s", info->extra[i]));
+ }
+ }
+ for (i = 0; i < num_vifs; i++) {
+ if (vifs[i].nictype == NICTYPE_IOEMU) {
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-net"));
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "nic,vlan=%d,macaddr=%s,model=%s",
+ vifs[i].devid, vifs[i].smac, vifs[i].model));
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-net"));
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "tap,vlan=%d,ifname=%s,bridge=%s",
+ vifs[i].devid, vifs[i].ifname, vifs[i].bridge));
+ }
+ }
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "-M"));
+ flexarray_set(dm_args, num++, libxl_sprintf(ctx, "xenfv"));
+ flexarray_set(dm_args, num++, NULL);
+
+ return (char **) flexarray_contents(dm_args);
+}
+
+int libxl_create_device_model(struct libxl_ctx *ctx,
+ libxl_device_model_info *info,
+ libxl_device_nic *vifs, int num_vifs)
+{
+ char *dom_path, *path, *logfile, *logfile_new;
+ char *kvs[3];
+ struct stat stat_buf;
+ int logfile_w, null, pid;
+ int i;
+ char **args;
+
+ args = libxl_build_device_model_args(ctx, info, vifs, num_vifs);
+ if (!args)
+ return ERROR_FAIL;
+
+ dom_path = libxl_xs_get_dompath(ctx, info->domid);
+
+ path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d", info->domid);
+ xs_mkdir(ctx->xsh, XBT_NULL, path);
+
+ logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log", info->dom_name);
+ if (stat(logfile, &stat_buf) == 0) {
+ /* file exists, rotate */
+ logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log.10", info->dom_name);
+ unlink(logfile);
+ for (i = 9; i > 0; i--) {
+ logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log.%d", info->dom_name, i);
+ logfile_new = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log.%d", info->dom_name, i + 1);
+ rename(logfile, logfile_new);
+ }
+ logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log", info->dom_name);
+ logfile_new = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log.1", info->dom_name);
+ rename(logfile, logfile_new);
+ }
+ logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log", info->dom_name);
+ logfile_w = open(logfile, O_WRONLY|O_CREAT);
+ null = open("/dev/null", O_RDONLY);
+ pid = libxl_exec(ctx, null, logfile_w, logfile_w, info->device_model, args);
+ close(null);
+ close(logfile_w);
+
+ kvs[0] = libxl_sprintf(ctx, "image/device-model-pid");
+ kvs[1] = libxl_sprintf(ctx, "%d", pid);
+ kvs[2] = NULL;
+ libxl_xs_writev(ctx, XBT_NULL, dom_path, kvs);
+
+ return 0;
+}
+
+/******************************************************************************/
+int libxl_device_disk_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
+{
+ flexarray_t *front;
+ flexarray_t *back;
+ char *backend_type;
+ unsigned int boffset = 0;
+ unsigned int foffset = 0;
+ int devid;
+ libxl_device device;
+
+ front = flexarray_make(16, 1);
+ if (!front)
+ return ERROR_NOMEM;
+ back = flexarray_make(16, 1);
+ if (!back) /* leaks front if error */
+ return ERROR_NOMEM;
+
+ backend_type = device_disk_backend_type_of_phystype(disk->phystype);
+ devid = device_disk_dev_number(disk->virtpath);
+
+ device.backend_devid = devid;
+ device.backend_domid = disk->backend_domid;
+ device.devid = devid;
+ device.domid = disk->domid;
+ device.kind = DEVICE_VBD;
+
+ switch (disk->phystype) {
+ case PHYSTYPE_FILE:
+ return ERROR_NI; /* FIXME */
+ break;
+ case PHYSTYPE_PHY: {
+ int major, minor;
+
+ device_disk_major_minor(disk->virtpath, &major, &minor);
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "physical-device"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x:%x", major, minor));
+
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "params"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", disk->physpath));
+
+ device.backend_kind = DEVICE_VBD;
+ break;
+ }
+ case PHYSTYPE_AIO: case PHYSTYPE_QCOW: case PHYSTYPE_QCOW2: case PHYSTYPE_VHD:
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "params"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s:%s",
+ device_disk_string_of_phystype(disk->phystype), disk->physpath));
+
+ device.backend_kind = DEVICE_TAP;
+ break;
+ }
+
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", disk->domid));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "online"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "1"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "removable"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", (disk->unpluggable) ? 1 : 0));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", disk->virtpath));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "type"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", backend_type));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "mode"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", (disk->readwrite) ? "w" : "r"));
+
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id"));
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", disk->backend_domid));
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "state"));
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "virtual-device"));
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", devid));
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "device-type"));
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "%s", (disk->is_cdrom) ? "cdrom" : "disk"));
+
+ if (0 /* protocol != native*/) {
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "protocol"));
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "x86_32-abi")); /* hardcoded ! */
+ }
+
+ libxl_device_generic_add(ctx, &device,
+ libxl_xs_kvs_of_flexarray(ctx, back, boffset),
+ libxl_xs_kvs_of_flexarray(ctx, front, foffset));
+ /* leaks both flexarray here */
+ return 0;
+}
+
+int libxl_device_disk_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
+{
+ return ERROR_NI;
+}
+
+int libxl_device_disk_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
+{
+ return ERROR_NI;
+}
+
+/******************************************************************************/
+int libxl_device_nic_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
+{
+ flexarray_t *front;
+ flexarray_t *back;
+ unsigned int boffset = 0;
+ unsigned int foffset = 0;
+ libxl_device device;
+
+ front = flexarray_make(16, 1);
+ if (!front)
+ return ERROR_NOMEM;
+ back = flexarray_make(16, 1);
+ if (!back)
+ return ERROR_NOMEM;
+
+ device.backend_devid = nic->devid;
+ device.backend_domid = nic->backend_domid;
+ device.backend_kind = DEVICE_VIF;
+ device.devid = nic->devid;
+ device.domid = nic->domid;
+ device.kind = DEVICE_VIF;
+
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "frontend-id"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", nic->domid));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "online"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "1"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "state"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "script"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", nic->script));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "mac"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
+ nic->mac[0], nic->mac[1], nic->mac[2],
+ nic->mac[3], nic->mac[4], nic->mac[5]));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "handle"));
+ flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", nic->devid));
+
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "backend-id"));
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", nic->backend_domid));
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "state"));
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "handle"));
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", nic->devid));
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "mac"));
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
+ nic->mac[0], nic->mac[1], nic->mac[2],
+ nic->mac[3], nic->mac[4], nic->mac[5]));
+ if (0 /* protocol != native*/) {
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "protocol"));
+ flexarray_set(front, foffset++, libxl_sprintf(ctx, "x86_32-abi")); /* hardcoded ! */
+ }
+
+ libxl_device_generic_add(ctx, &device,
+ libxl_xs_kvs_of_flexarray(ctx, back, boffset),
+ libxl_xs_kvs_of_flexarray(ctx, front, foffset));
+
+ /* FIXME: wait for plug */
+ return 0;
+}
+
+int libxl_device_nic_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
+{
+ return ERROR_NI;
+}
+
+int libxl_device_nic_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
+{
+ return ERROR_NI;
+}
+
+/******************************************************************************/
+int libxl_device_vkb_add(struct libxl_ctx *ctx, uint32_t domid)
+{
+ return ERROR_NI;
+}
+
+int libxl_device_vkb_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
+{
+ return ERROR_NI;
+}
+
+int libxl_device_vkb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
+{
+ return ERROR_NI;
+}
+
+/******************************************************************************/
+int libxl_device_vfb_add(struct libxl_ctx *ctx, uint32_t domid)
+{
+ return ERROR_NI;
+}
+
+int libxl_device_vfb_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
+{
+ return ERROR_NI;
+}
+
+int libxl_device_vfb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
+{
+ return ERROR_NI;
+}
+
+/******************************************************************************/
+int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid)
+{
+ return ERROR_NI;
+}
+
+int libxl_device_pci_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
+{
+ return ERROR_NI;
+}
+
+int libxl_device_pci_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
+{
+ return ERROR_NI;
+}
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
new file mode 100644
index 0000000000..b314d37655
--- /dev/null
+++ b/tools/libxl/libxl.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * 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.
+ */
+#ifndef LIBXL_H
+#define LIBXL_H
+
+#include "osdeps.h"
+#include <stdint.h>
+#include <stdarg.h>
+#include <netinet/in.h>
+#include <xenctrl.h>
+
+typedef int bool;
+
+typedef void (*libxl_log_callback)(void *userdata, int loglevel, const char *file,
+ int line, const char *func, char *s);
+
+struct libxl_dominfo {
+ uint8_t uuid[16];
+ uint32_t domid;
+};
+
+struct libxl_ctx {
+ int xch;
+ struct xs_handle *xsh;
+ /* errors/debug buf */
+ void *log_userdata;
+ libxl_log_callback log_callback;
+
+ /* mini-GC */
+ int alloc_maxsize;
+ void **alloc_ptrs;
+};
+
+typedef struct {
+ bool hvm;
+ bool hap;
+ int ssidref;
+ char *name;
+ uint8_t *uuid;
+ char **xsdata;
+ char **platformdata;
+} libxl_domain_create_info;
+
+typedef struct {
+ int timer_mode;
+ int hpet;
+ int vpt_align;
+ int max_vcpus;
+ uint32_t max_memkb;
+ uint32_t video_memkb;
+ uint32_t shadow_memkb;
+ const char *kernel;
+ int hvm;
+ union {
+ struct {
+ bool pae;
+ bool apic;
+ bool acpi;
+ bool nx;
+ bool viridian;
+ char *timeoffset;
+ } hvm;
+ struct {
+ const char *cmdline;
+ const char *ramdisk;
+ } pv;
+ } u;
+} libxl_domain_build_info;
+
+typedef struct {
+ int flags;
+ int (*suspend_callback)(void *, int);
+} libxl_domain_suspend_info;
+
+typedef struct {
+ int domid;
+ char *dom_name;
+ char *device_model;
+ int videoram; /* size of the videoram in MB */
+ bool stdvga; /* stdvga enabled or disabled */
+ bool vnc; /* vnc enabled or disabled */
+ char *vnclisten; /* address:port that should be listened on for the VNC server if vnc is set */
+ int vncdisplay; /* set VNC display number */
+ bool vncunused; /* try to find an unused port for the VNC server */
+ char *keymap; /* set keyboard layout, default is en-us keyboard */
+ bool sdl; /* sdl enabled or disabled */
+ bool opengl; /* opengl enabled or disabled (if enabled requires sdl enabled) */
+ bool nographic; /* no graphics, use serial port */
+ char *serial; /* serial port re-direct to pty deivce */
+ char *boot; /* boot order, for example dca */
+ bool usb; /* usb support enabled or disabled */
+ char *usbdevice; /* enable usb mouse: tablet for absolute mouse, mouse for PS/2 protocol relative mouse */
+ bool apic; /* apic enabled or disabled */
+ char **extra; /* extra parameters pass directly to qemu, NULL terminated */
+ /* Network is missing */
+} libxl_device_model_info;
+
+typedef enum {
+ PHYSTYPE_QCOW,
+ PHYSTYPE_QCOW2,
+ PHYSTYPE_VHD,
+ PHYSTYPE_AIO,
+ PHYSTYPE_FILE,
+ PHYSTYPE_PHY,
+} libxl_disk_phystype;
+
+typedef struct {
+ uint32_t backend_domid;
+ uint32_t domid;
+ char *physpath;
+ libxl_disk_phystype phystype;
+ char *virtpath;
+ int unpluggable;
+ int readwrite;
+ int is_cdrom;
+} libxl_device_disk;
+
+typedef enum {
+ NICTYPE_IOEMU,
+ NICTYPE_VIF,
+} libxl_nic_type;
+
+typedef struct {
+ uint32_t backend_domid;
+ uint32_t domid;
+ int devid;
+ int mtu;
+ char *model;
+ uint8_t mac[6];
+ char *smac;
+ struct in_addr ip;
+ char *bridge;
+ char *ifname;
+ char *script;
+ libxl_nic_type nictype;
+} libxl_device_nic;
+
+#define ERROR_FAIL (-2)
+#define ERROR_NI (-101)
+#define ERROR_NOMEM (-1032)
+#define ERROR_INVAL (-1245)
+
+/* context functions */
+int libxl_ctx_init(struct libxl_ctx *ctx);
+int libxl_ctx_free(struct libxl_ctx *ctx);
+int libxl_ctx_set_log(struct libxl_ctx *ctx, libxl_log_callback log_callback, void *log_data);
+
+/* domain related functions */
+int libxl_domain_make(struct libxl_ctx *ctx, libxl_domain_create_info *info, uint32_t *domid);
+int libxl_domain_build(struct libxl_ctx *ctx, libxl_domain_build_info *info, uint32_t domid);
+int libxl_domain_restore(struct libxl_ctx *ctx, libxl_domain_build_info *info,
+ uint32_t domid, int fd);
+int libxl_domain_suspend(struct libxl_ctx *ctx, libxl_domain_suspend_info *info,
+ uint32_t domid, int fd);
+int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req);
+int libxl_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force);
+
+int libxl_domain_pause(struct libxl_ctx *ctx, uint32_t domid);
+int libxl_domain_unpause(struct libxl_ctx *ctx, uint32_t domid);
+
+struct libxl_dominfo * libxl_domain_list(struct libxl_ctx *ctx, int *nb_domain);
+xc_dominfo_t * libxl_domain_infolist(struct libxl_ctx *ctx, int *nb_domain);
+
+int libxl_create_device_model(struct libxl_ctx *ctx,
+ libxl_device_model_info *info,
+ libxl_device_nic *vifs, int num_vifs);
+
+int libxl_device_disk_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk);
+int libxl_device_disk_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid);
+int libxl_device_disk_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid);
+
+int libxl_device_nic_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic);
+int libxl_device_nic_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid);
+int libxl_device_nic_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid);
+
+int libxl_device_vkb_add(struct libxl_ctx *ctx, uint32_t domid);
+int libxl_device_vkb_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid);
+int libxl_device_vkb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid);
+
+int libxl_device_vfb_add(struct libxl_ctx *ctx, uint32_t domid);
+int libxl_device_vfb_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid);
+int libxl_device_vfb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid);
+
+int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid);
+int libxl_device_pci_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid);
+int libxl_device_pci_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid);
+
+#endif
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
new file mode 100644
index 0000000000..f10ddd1f23
--- /dev/null
+++ b/tools/libxl/libxl_device.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+ *
+ * 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 <string.h>
+#include "libxl.h"
+#include "libxl_internal.h"
+
+char *string_of_kinds[] = {
+ [DEVICE_VIF] = "vif",
+ [DEVICE_VBD] = "vbd",
+ [DEVICE_TAP] = "tap",
+ [DEVICE_PCI] = "pci",
+ [DEVICE_VFB] = "vfb",
+ [DEVICE_VKBD] = "vkbd",
+};
+
+int libxl_device_generic_add(struct libxl_ctx *ctx, libxl_device *device,
+ char **bents, char **fents)
+{
+ char *dom_path_backend, *dom_path, *frontend_path, *backend_path, *hotplug_path;
+ xs_transaction_t t;
+ struct xs_permissions frontend_perms[2];
+ struct xs_permissions backend_perms[2];
+ struct xs_permissions hotplug_perms[1];
+
+ dom_path_backend = xs_get_domain_path(ctx->xsh, device->backend_domid);
+ dom_path = xs_get_domain_path(ctx->xsh, device->domid);
+
+ frontend_path = libxl_sprintf(ctx, "%s/device/%s/%d",
+ dom_path, string_of_kinds[device->kind], device->devid);
+ backend_path = libxl_sprintf(ctx, "%s/backend/%s/%u/%d",
+ dom_path_backend, string_of_kinds[device->backend_kind], device->domid, device->devid);
+ hotplug_path = libxl_sprintf(ctx, "/xapi/%d/hotplug/%s/%d",
+ device->domid, string_of_kinds[device->kind], device->devid);
+
+ frontend_perms[0].id = device->domid;
+ frontend_perms[0].perms = XS_PERM_NONE;
+ frontend_perms[1].id = device->backend_domid;
+ frontend_perms[1].perms = XS_PERM_READ;
+
+ backend_perms[0].id = device->backend_domid;
+ backend_perms[0].perms = XS_PERM_NONE;
+ backend_perms[1].id = device->domid;
+ backend_perms[1].perms = XS_PERM_READ;
+
+ hotplug_perms[0].id = device->backend_domid;
+ hotplug_perms[0].perms = XS_PERM_NONE;
+
+retry_transaction:
+ t = xs_transaction_start(ctx->xsh);
+ /* FIXME: read frontend_path and check state before removing stuff */
+
+ xs_rm(ctx->xsh, t, frontend_path);
+ xs_rm(ctx->xsh, t, backend_path);
+
+ xs_mkdir(ctx->xsh, t, frontend_path);
+ xs_set_permissions(ctx->xsh, t, frontend_path, frontend_perms, ARRAY_SIZE(frontend_perms));
+
+ xs_mkdir(ctx->xsh, t, backend_path);
+ xs_set_permissions(ctx->xsh, t, backend_path, backend_perms, ARRAY_SIZE(backend_perms));
+
+ xs_mkdir(ctx->xsh, t, hotplug_path);
+ xs_set_permissions(ctx->xsh, t, hotplug_path, hotplug_perms, ARRAY_SIZE(hotplug_perms));
+
+ xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/backend", frontend_path), backend_path, strlen(backend_path));
+ xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/frontend", backend_path), frontend_path, strlen(frontend_path));
+
+ /* and write frontend kvs and backend kvs */
+ libxl_xs_writev(ctx, t, backend_path, bents);
+ libxl_xs_writev(ctx, t, frontend_path, fents);
+
+ if (!xs_transaction_end(ctx->xsh, t, 0))
+ if (errno == EAGAIN)
+ goto retry_transaction;
+ return 0;
+}
+
+char *device_disk_string_of_phystype(libxl_disk_phystype phystype)
+{
+ switch (phystype) {
+ case PHYSTYPE_QCOW: return "qcow";
+ case PHYSTYPE_QCOW2: return "qcow2";
+ case PHYSTYPE_VHD: return "vhd";
+ case PHYSTYPE_AIO: return "aio";
+ case PHYSTYPE_FILE: return "file";
+ case PHYSTYPE_PHY: return "phy";
+ default: return NULL;
+ }
+}
+
+char *device_disk_backend_type_of_phystype(libxl_disk_phystype phystype)
+{
+ switch (phystype) {
+ case PHYSTYPE_QCOW: return "tap";
+ case PHYSTYPE_VHD: return "tap";
+ case PHYSTYPE_AIO: return "tap";
+ case PHYSTYPE_FILE: return "file";
+ case PHYSTYPE_PHY: return "phy";
+ default: return NULL;
+ }
+}
+
+int device_disk_major_minor(char *virtpath, int *major, int *minor)
+{
+ if (strstr(virtpath, "sd") == virtpath) {
+ return -1;
+ } else if (strstr(virtpath, "xvd") == virtpath) {
+ return -1;
+ } else if (strstr(virtpath, "hd") == virtpath) {
+ char letter, letter2;
+
+ *major = 0; *minor = 0;
+ letter = virtpath[2];
+ if (letter < 'a' || letter > 't')
+ return -1;
+ letter2 = virtpath[3];
+
+ *major = letter - 'a';
+ *minor = atoi(virtpath + 3);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+int device_disk_dev_number(char *virtpath)
+{
+ int majors_table[] = { 3, 22, 33, 34, 56, 57, 88, 89, 90, 91 };
+ int major, minor;
+
+ if (device_disk_major_minor(virtpath, &major, &minor))
+ return -1;
+ return majors_table[major / 2] * 256 + (64 * (major % 2)) + minor;
+}
+
+int libxl_device_destroy(struct libxl_ctx *ctx, char *be_path, int force)
+{
+ xs_transaction_t t;
+ char *state_path = libxl_sprintf(ctx, "%s/state", be_path);
+ char *state = libxl_xs_read(ctx, XBT_NULL, state_path);
+ if (!state)
+ return 0;
+ if (atoi(state) <= 3) {
+ xs_rm(ctx->xsh, XBT_NULL, be_path);
+ return 0;
+ }
+
+retry_transaction:
+ t = xs_transaction_start(ctx->xsh);
+ xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/online", be_path), "0", strlen("0"));
+ xs_write(ctx->xsh, t, state_path, "5", strlen("5"));
+ if (!xs_transaction_end(ctx->xsh, t, 0)) {
+ if (errno == EAGAIN)
+ goto retry_transaction;
+ else
+ return -1;
+ }
+ if (!force) {
+ xs_watch(ctx->xsh, state_path, be_path);
+ return 1;
+ } else
+ return 0;
+}
+
+int libxl_devices_destroy(struct libxl_ctx *ctx, uint32_t domid, int force)
+{
+ char *path, *be_path, *fe_path;
+ unsigned int num1, num2;
+ char **l1 = NULL, **l2 = NULL;
+ int i, j, nfds, n = 0, n_watches = 0;
+ fd_set rfds;
+ struct timeval tv;
+ flexarray_t *toremove;
+
+ toremove = flexarray_make(16, 1);
+ path = libxl_sprintf(ctx, "/local/domain/%d/device", domid);
+ l1 = libxl_xs_directory(ctx, XBT_NULL, path, &num1);
+ if (!l1) {
+ XL_LOG(ctx, XL_LOG_ERROR, "%s is empty\n", path);
+ return -1;
+ }
+ for (i = 0; i < num1; i++) {
+ path = libxl_sprintf(ctx, "/local/domain/%d/device/%s", domid, l1[i]);
+ l2 = libxl_xs_directory(ctx, XBT_NULL, path, &num2);
+ if (!l2)
+ continue;
+ for (j = 0; j < num2; j++) {
+ fe_path = libxl_sprintf(ctx, "/local/domain/%d/device/%s/%s", domid, l1[i], l2[j]);
+ be_path = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend", fe_path));
+ if (be_path != NULL) {
+ if (libxl_device_destroy(ctx, be_path, force) > 0)
+ n_watches++;
+ flexarray_set(toremove, n++, libxl_dirname(ctx, be_path));
+ } else {
+ xs_rm(ctx->xsh, XBT_NULL, path);
+ }
+ }
+ }
+ if (!force) {
+ nfds = xs_fileno(ctx->xsh) + 1;
+ /* Linux-ism */
+ tv.tv_sec = LIBXL_DESTROY_TIMEOUT;
+ tv.tv_usec = 0;
+ while (n_watches > 0 && tv.tv_sec > 0) {
+ FD_ZERO(&rfds);
+ FD_SET(xs_fileno(ctx->xsh), &rfds);
+ if (select(nfds, &rfds, NULL, NULL, &tv) > 0) {
+ l1 = xs_read_watch(ctx->xsh, &num1);
+ if (l1 != NULL) {
+ char *state = libxl_xs_read(ctx, XBT_NULL, l1[0]);
+ if (!state || atoi(state) == 6) {
+ xs_unwatch(ctx->xsh, l1[0], l1[1]);
+ xs_rm(ctx->xsh, XBT_NULL, l1[1]);
+ XL_LOG(ctx, XL_LOG_DEBUG, "Destroyed device backend at %s\n", l1[1]);
+ n_watches--;
+ }
+ }
+ } else
+ break;
+ }
+ }
+ for (i = 0; i < n; i++) {
+ flexarray_get(toremove, i, (void**) &path);
+ xs_rm(ctx->xsh, XBT_NULL, path);
+ }
+ flexarray_free(toremove);
+ return 0;
+}
diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
new file mode 100644
index 0000000000..72eec36861
--- /dev/null
+++ b/tools/libxl/libxl_dom.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * 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.h"
+#include "libxl_internal.h"
+#include <inttypes.h>
+#include <xenguest.h>
+#include <string.h>
+
+int is_hvm(struct libxl_ctx *ctx, uint32_t domid)
+{
+ xc_domaininfo_t info;
+ int ret;
+
+ ret = xc_domain_getinfolist(ctx->xch, domid, 1, &info);
+ if (ret != 1)
+ return -1;
+ if (info.domain != domid)
+ return -1;
+ return !!(info.flags & XEN_DOMINF_hvm_guest);
+}
+
+int build_pre(struct libxl_ctx *ctx, uint32_t domid,
+ libxl_domain_build_info *info, libxl_domain_build_state *state)
+{
+ unsigned long shadow;
+ if (info->timer_mode != -1)
+ xc_set_hvm_param(ctx->xch, domid, HVM_PARAM_TIMER_MODE,
+ (unsigned long) info->timer_mode);
+ if (info->hpet != -1)
+ xc_set_hvm_param(ctx->xch, domid, HVM_PARAM_HPET_ENABLED, (unsigned long) info->hpet);
+ if (info->vpt_align != -1)
+ xc_set_hvm_param(ctx->xch, domid, HVM_PARAM_VPT_ALIGN, (unsigned long) info->vpt_align);
+ xc_domain_max_vcpus(ctx->xch, domid, info->max_vcpus);
+ xc_domain_setmaxmem(ctx->xch, domid, info->max_memkb + info->video_memkb);
+ xc_domain_set_memmap_limit(ctx->xch, domid, info->max_memkb);
+ shadow = (info->shadow_memkb + 1023) / 1024;
+ xc_shadow_control(ctx->xch, domid, XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION, NULL, 0, &shadow, 0, NULL);
+
+ state->store_port = xc_evtchn_alloc_unbound(ctx->xch, domid, 0);
+ state->console_port = xc_evtchn_alloc_unbound(ctx->xch, domid, 0);
+ return 0;
+}
+
+int build_post(struct libxl_ctx *ctx, uint32_t domid,
+ libxl_domain_build_info *info, libxl_domain_build_state *state,
+ char **vms_ents, char **local_ents)
+{
+ char *dom_path, *vm_path;
+ xs_transaction_t t;
+ char **ents;
+
+ ents = libxl_calloc(ctx, 6 * 2, sizeof(char *));
+ ents[0] = libxl_sprintf(ctx, "memory/static-max");
+ ents[1] = libxl_sprintf(ctx, "%d", info->max_memkb);
+ ents[2] = libxl_sprintf(ctx, "memory/target");
+ ents[3] = libxl_sprintf(ctx, "%d", info->max_memkb); /* PROBABLY WRONG */
+ ents[4] = libxl_sprintf(ctx, "domid");
+ ents[5] = libxl_sprintf(ctx, "%d", domid);
+ ents[6] = libxl_sprintf(ctx, "store/port");
+ ents[7] = libxl_sprintf(ctx, "%"PRIu32, state->store_port);
+ ents[8] = libxl_sprintf(ctx, "store/ring-ref");
+ ents[9] = libxl_sprintf(ctx, "%lu", state->store_mfn);
+
+ dom_path = libxl_xs_get_dompath(ctx, domid);
+ vm_path = xs_read(ctx->xsh, XBT_NULL, libxl_sprintf(ctx, "%s/vm", dom_path), NULL);
+retry_transaction:
+ t = xs_transaction_start(ctx->xsh);
+
+ libxl_xs_writev(ctx, t, dom_path, ents);
+ libxl_xs_writev(ctx, t, dom_path, local_ents);
+ libxl_xs_writev(ctx, t, vm_path, vms_ents);
+
+ if (!xs_transaction_end(ctx->xsh, t, 0))
+ if (errno == EAGAIN)
+ goto retry_transaction;
+ xs_introduce_domain(ctx->xsh, domid, state->store_mfn, state->store_port);
+ return 0;
+}
+
+int build_pv(struct libxl_ctx *ctx, uint32_t domid,
+ libxl_domain_build_info *info, libxl_domain_build_state *state)
+{
+ int mem_target_kib = info->max_memkb;
+ char *domid_str = libxl_sprintf(ctx, "%d", domid);
+ char *memsize_str = libxl_sprintf(ctx, "%d", mem_target_kib / 1024);
+ char *store_port_str = libxl_sprintf(ctx, "%d", state->store_port);
+ char *console_port_str = libxl_sprintf(ctx, "%d", state->console_port);
+ return ERROR_NI;
+}
+
+int build_hvm(struct libxl_ctx *ctx, uint32_t domid,
+ libxl_domain_build_info *info, libxl_domain_build_state *state)
+{
+ int ret;
+
+ ret = xc_hvm_build(ctx->xch, domid, info->max_memkb / 1024, info->kernel);
+ if (ret) {
+ XL_LOG(ctx, XL_LOG_ERROR, "hvm building failed: %d", ret);
+ return ERROR_FAIL;
+ }
+ ret = hvm_build_set_params(ctx->xch, domid, info->u.hvm.apic, info->u.hvm.acpi,
+ info->u.hvm.pae, info->u.hvm.nx, info->u.hvm.viridian,
+ info->max_vcpus,
+ state->store_port, &state->store_mfn);
+ if (ret) {
+ XL_LOG(ctx, XL_LOG_ERROR, "hvm build set params failed: %d", ret);
+ return ERROR_FAIL;
+ }
+ xc_cpuid_apply_policy(ctx->xch, domid);
+ return 0;
+}
+
+int restore_common(struct libxl_ctx *ctx, uint32_t domid,
+ libxl_domain_build_info *info, libxl_domain_build_state *state,
+ int fd)
+{
+ /* read signature */
+ xc_domain_restore(ctx->xch, fd, domid,
+ state->store_port, &state->store_mfn,
+ state->console_port, &state->console_mfn,
+ info->hvm, info->u.hvm.pae, 0);
+ return 0;
+}
+
+/* the following code is extremely ugly and racy without forking.
+ we intend to fix the re-entrancy of the underlying code instead of forking */
+static struct libxl_ctx *global_suspend_ctx = NULL;
+static struct suspendinfo {
+ int xch;
+ int xce; /* event channel handle */
+ int suspend_eventchn;
+ int domid;
+ int hvm;
+ unsigned int flags;
+} si;
+
+void core_suspend_switch_qemu_logdirty(int domid, unsigned int enable)
+{
+ struct xs_handle *xs;
+ char *path, *ret_path, *cmd_path, *ret_str, *cmd_str, **watch;
+ unsigned int len;
+ struct timeval tv;
+ fd_set fdset;
+ struct libxl_ctx *ctx = global_suspend_ctx;
+
+ xs = xs_daemon_open();
+ if (!xs)
+ return;
+ path = libxl_sprintf(ctx, "/local/domain/0/device-model/%i/logdirty", domid);
+ if (!path)
+ return;
+ ret_path = libxl_sprintf(ctx, "%s/ret", path);
+ if (!ret_path)
+ return;
+ cmd_path = libxl_sprintf(ctx, "%s/cmd", path);
+ if (!ret_path)
+ return;
+
+ /* Watch for qemu's return value */
+ if (!xs_watch(xs, ret_path, "qemu-logdirty-ret"))
+ return;
+
+ cmd_str = (enable == 0) ? "disable" : "enable";
+
+ /* Tell qemu that we want it to start logging dirty page to Xen */
+ if (!xs_write(xs, XBT_NULL, cmd_path, cmd_str, strlen(cmd_str)))
+ return;
+
+ /* Wait a while for qemu to signal that it has service logdirty command */
+read_again:
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ FD_ZERO(&fdset);
+ FD_SET(xs_fileno(xs), &fdset);
+
+ if ((select(xs_fileno(xs) + 1, &fdset, NULL, NULL, &tv)) != 1)
+ return;
+
+ watch = xs_read_watch(xs, &len);
+ free(watch);
+
+ ret_str = xs_read(xs, XBT_NULL, ret_path, &len);
+ if (ret_str == NULL || strcmp(ret_str, cmd_str))
+ /* Watch fired but value is not yet right */
+ goto read_again;
+ free(ret_str);
+}
+
+static int core_suspend_callback(void)
+{
+ unsigned long s_state = 0;
+ int ret;
+
+ if (si.hvm)
+ xc_get_hvm_param(si.xch, si.domid, HVM_PARAM_ACPI_S_STATE, &s_state);
+ if ((s_state == 0) && (si.suspend_eventchn >= 0)) {
+ ret = xc_evtchn_notify(si.xch, si.suspend_eventchn);
+ if (ret < 0) {
+ return 0;
+ }
+ ret = xc_await_suspend(si.xch, si.suspend_eventchn);
+ if (ret < 0) {
+ return 0;
+ }
+ return 1;
+ }
+ /* need to shutdown (to suspend) the domain here */
+ return 0;
+}
+
+int core_suspend(struct libxl_ctx *ctx, uint32_t domid, int fd, int hvm, int live, int debug)
+{
+ int flags;
+ int port;
+
+ flags = (live) ? XCFLAGS_LIVE : 0
+ | (debug) ? XCFLAGS_DEBUG : 0;
+
+ /* crappy global lock until we make everything clean */
+ while (global_suspend_ctx) {
+ sleep(1);
+ }
+ global_suspend_ctx = ctx;
+
+ si.domid = domid;
+ si.flags = flags;
+ si.hvm = hvm;
+ si.suspend_eventchn = si.xce = -1;
+ si.xch = ctx->xch;
+
+ si.xce = xc_evtchn_open();
+ if (si.xce < 0)
+ return -1;
+
+ if (si.xce > 0) {
+ port = xs_suspend_evtchn_port(si.domid);
+
+ if (port < 0) {
+ } else {
+ si.suspend_eventchn = xc_suspend_evtchn_init(si.xch, si.xce, si.domid, port);
+
+ if (si.suspend_eventchn < 0) {
+ }
+ }
+ }
+
+ xc_domain_save(ctx->xch, fd, domid, 0, 0, flags,
+ core_suspend_callback, hvm,
+ core_suspend_switch_qemu_logdirty);
+
+ if (si.suspend_eventchn > 0)
+ xc_suspend_evtchn_release(si.xce, si.suspend_eventchn);
+ if (si.xce > 0)
+ xc_evtchn_close(si.xce);
+
+ global_suspend_ctx = NULL;
+ return 0;
+}
diff --git a/tools/libxl/libxl_exec.c b/tools/libxl/libxl_exec.c
new file mode 100644
index 0000000000..8d7928b4e8
--- /dev/null
+++ b/tools/libxl/libxl_exec.c
@@ -0,0 +1,48 @@
+
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+ *
+ * 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 <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "libxl.h"
+#include "libxl_internal.h"
+
+int libxl_exec(struct libxl_ctx *ctx, int stdinfd, int stdoutfd, int stderrfd,
+ char *arg0, char **args)
+{
+ int pid, i;
+
+ pid = fork();
+ if (pid == -1) {
+ XL_LOG(ctx, XL_LOG_ERROR, "fork failed");
+ return -1;
+ }
+ if (pid == 0) {
+ /* child */
+ if (stdinfd != -1)
+ dup2(stdinfd, STDIN_FILENO);
+ if (stdoutfd != -1)
+ dup2(stdoutfd, STDOUT_FILENO);
+ if (stderrfd != -1)
+ dup2(stderrfd, STDERR_FILENO);
+ for (i = 4; i < 256; i++)
+ close(i);
+ execv(arg0, args);
+ exit(256);
+ }
+ return pid;
+}
diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c
new file mode 100644
index 0000000000..407cf2230e
--- /dev/null
+++ b/tools/libxl/libxl_internal.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * 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.h"
+#include "libxl_internal.h"
+#include "libxl_utils.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+int libxl_error_set(struct libxl_ctx *ctx, int code)
+{
+ return 0;
+}
+
+int libxl_ptr_add(struct libxl_ctx *ctx, void *ptr)
+{
+ int i;
+ void **re;
+
+ if (!ptr)
+ return 0;
+
+ /* fast case: we have space in the array for storing the pointer */
+ for (i = 0; i < ctx->alloc_maxsize; i++) {
+ if (!ctx->alloc_ptrs[i]) {
+ ctx->alloc_ptrs[i] = ptr;
+ return 0;
+ }
+ }
+ /* realloc alloc_ptrs manually with calloc/free/replace */
+ re = calloc(ctx->alloc_maxsize + 25, sizeof(void *));
+ if (!re)
+ return -1;
+ for (i = 0; i < ctx->alloc_maxsize; i++)
+ re[i] = ctx->alloc_ptrs[i];
+ /* assign the next pointer */
+ re[i] = ptr;
+
+ /* replace the old alloc_ptr */
+ free(ctx->alloc_ptrs);
+ ctx->alloc_ptrs = re;
+ ctx->alloc_maxsize += 25;
+ return 0;
+}
+
+int libxl_free(struct libxl_ctx *ctx, void *ptr)
+{
+ int i;
+
+ if (!ptr)
+ return 0;
+
+ /* remove the pointer from the tracked ptrs */
+ for (i = 0; i < ctx->alloc_maxsize; i++) {
+ if (ctx->alloc_ptrs[i] == ptr) {
+ ctx->alloc_ptrs[i] = NULL;
+ free(ptr);
+ return 0;
+ }
+ }
+ /* haven't find the pointer, really bad */
+ return -1;
+}
+
+int libxl_free_all(struct libxl_ctx *ctx)
+{
+ void *ptr;
+ int i;
+
+ for (i = 0; i < ctx->alloc_maxsize; i++) {
+ ptr = ctx->alloc_ptrs[i];
+ ctx->alloc_ptrs[i] = NULL;
+ free(ptr);
+ }
+ return 0;
+}
+
+void *libxl_zalloc(struct libxl_ctx *ctx, int bytes)
+{
+ void *ptr = calloc(bytes, 1);
+ if (!ptr) {
+ libxl_error_set(ctx, ENOMEM);
+ return NULL;
+ }
+
+ libxl_ptr_add(ctx, ptr);
+ return ptr;
+}
+
+void *libxl_calloc(struct libxl_ctx *ctx, size_t nmemb, size_t size)
+{
+ void *ptr = calloc(nmemb, size);
+ if (!ptr) {
+ libxl_error_set(ctx, ENOMEM);
+ return NULL;
+ }
+
+ libxl_ptr_add(ctx, ptr);
+ return ptr;
+}
+
+char *libxl_sprintf(struct libxl_ctx *ctx, const char *fmt, ...)
+{
+ char *s;
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(NULL, 0, fmt, ap);
+ va_end(ap);
+
+ if (ret < 0) {
+ return NULL;
+ }
+
+ s = libxl_zalloc(ctx, ret + 1);
+ if (s) {
+ va_start(ap, fmt);
+ ret = vsnprintf(s, ret + 1, fmt, ap);
+ va_end(ap);
+ }
+ return s;
+}
+
+char *libxl_dirname(struct libxl_ctx *ctx, const char *s)
+{
+ char *c;
+ char *ptr = libxl_sprintf(ctx, "%s", s);
+
+ c = strrchr(ptr, '/');
+ if (!c)
+ return NULL;
+ *c = '\0';
+ return ptr;
+}
+
+void xl_log(struct libxl_ctx *ctx, int loglevel, const char *file, int line, const char *func, char *fmt, ...)
+{
+ va_list ap;
+ char *s;
+ va_start(ap, fmt);
+ vasprintf(&s, fmt, ap);
+ va_end(ap);
+
+ ctx->log_callback(ctx->log_userdata, loglevel, file, line, func, s);
+ free(s);
+}
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
new file mode 100644
index 0000000000..c0b50a537f
--- /dev/null
+++ b/tools/libxl/libxl_internal.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+ *
+ * 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.
+ */
+
+#ifndef LIBXL_INTERNAL_H
+# define LIBXL_INTERNAL_H
+
+#include <stdint.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include <xs.h>
+#include <xenctrl.h>
+
+#include "flexarray.h"
+#include "libxl_utils.h"
+
+#define LIBXL_DESTROY_TIMEOUT 10
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+
+#define XL_LOGGING_ENABLED
+
+#ifdef XL_LOGGING_ENABLED
+#define XL_LOG(ctx, loglevel, _f, _a...) xl_log(ctx, loglevel, __FILE__, __LINE__, __func__, _f, ##_a)
+#else
+#define XL_LOG(ctx, loglevel, _f, _a...)
+#endif
+
+#define XL_LOG_DEBUG 3
+#define XL_LOG_INFO 2
+#define XL_LOG_WARNING 1
+#define XL_LOG_ERROR 0
+
+void xl_log(struct libxl_ctx *ctx, int loglevel, const char *file, int line, const char *func, char *fmt, ...);
+
+typedef struct {
+ uint32_t store_port;
+ unsigned long store_mfn;
+ uint32_t console_port;
+ unsigned long console_mfn;
+} libxl_domain_build_state;
+
+typedef enum {
+ DEVICE_VIF,
+ DEVICE_VBD,
+ DEVICE_TAP,
+ DEVICE_PCI,
+ DEVICE_VFB,
+ DEVICE_VKBD,
+} libxl_device_kinds;
+
+typedef struct {
+ uint32_t backend_devid;
+ uint32_t backend_domid;
+ uint32_t devid;
+ uint32_t domid;
+ libxl_device_kinds backend_kind;
+ libxl_device_kinds kind;
+} libxl_device;
+
+#define PRINTF_ATTRIBUTE(x, y) __attribute__((format(printf, x, y)))
+
+/* memory allocation tracking/helpers */
+int libxl_ptr_add(struct libxl_ctx *ctx, void *ptr);
+int libxl_free(struct libxl_ctx *ctx, void *ptr);
+int libxl_free_all(struct libxl_ctx *ctx);
+void *libxl_zalloc(struct libxl_ctx *ctx, int bytes);
+void *libxl_calloc(struct libxl_ctx *ctx, size_t nmemb, size_t size);
+char *libxl_sprintf(struct libxl_ctx *ctx, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
+char *libxl_dirname(struct libxl_ctx *ctx, const char *s);
+char *uuid_to_string(struct libxl_ctx *ctx, uint8_t *uuid);
+
+char **libxl_xs_kvs_of_flexarray(struct libxl_ctx *ctx, flexarray_t *array, int length);
+int libxl_xs_writev(struct libxl_ctx *ctx, xs_transaction_t t,
+ char *dir, char **kvs);
+int libxl_xs_write(struct libxl_ctx *ctx, xs_transaction_t t,
+ char *path, char *fmt, ...);
+char *libxl_xs_get_dompath(struct libxl_ctx *ctx, uint32_t domid);
+char *libxl_xs_read(struct libxl_ctx *ctx, xs_transaction_t t, char *path);
+char **libxl_xs_directory(struct libxl_ctx *ctx, xs_transaction_t t, char *path, unsigned int *nb);
+
+/* from xd_dom */
+int is_hvm(struct libxl_ctx *ctx, uint32_t domid);
+int build_pre(struct libxl_ctx *ctx, uint32_t domid,
+ libxl_domain_build_info *info, libxl_domain_build_state *state);
+int build_post(struct libxl_ctx *ctx, uint32_t domid,
+ libxl_domain_build_info *info, libxl_domain_build_state *state,
+ char **vms_ents, char **local_ents);
+
+int build_pv(struct libxl_ctx *ctx, uint32_t domid,
+ libxl_domain_build_info *info, libxl_domain_build_state *state);
+int build_hvm(struct libxl_ctx *ctx, uint32_t domid,
+ libxl_domain_build_info *info, libxl_domain_build_state *state);
+
+int restore_common(struct libxl_ctx *ctx, uint32_t domid,
+ libxl_domain_build_info *info, libxl_domain_build_state *state, int fd);
+int core_suspend(struct libxl_ctx *ctx, uint32_t domid, int fd, int hvm, int live, int debug);
+
+/* from xd_device */
+char *device_disk_backend_type_of_phystype(libxl_disk_phystype phystype);
+char *device_disk_string_of_phystype(libxl_disk_phystype phystype);
+
+int device_disk_major_minor(char *virtpath, int *major, int *minor);
+int device_disk_dev_number(char *virtpath);
+
+int libxl_device_generic_add(struct libxl_ctx *ctx, libxl_device *device,
+ char **bents, char **fents);
+int libxl_device_destroy(struct libxl_ctx *ctx, char *be_path, int force);
+int libxl_devices_destroy(struct libxl_ctx *ctx, uint32_t domid, int force);
+
+/* from xenguest (helper */
+int hvm_build_set_params(int handle, uint32_t domid,
+ int apic, int acpi, int pae, int nx, int viridian,
+ int vcpus, int store_evtchn, unsigned long *store_mfn);
+
+/* xd_exec */
+int libxl_exec(struct libxl_ctx *ctx, int stdinfd, int stdoutfd, int stderrfd,
+ char *arg0, char **args);
+
+#endif
+
diff --git a/tools/libxl/libxl_utils.c b/tools/libxl/libxl_utils.c
new file mode 100644
index 0000000000..97f2f3b0e4
--- /dev/null
+++ b/tools/libxl/libxl_utils.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+ *
+ * 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_utils.h"
+#include "libxl_internal.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <xs.h>
+#include <xenctrl.h>
+#include <ctype.h>
+#include <errno.h>
+
+
+
+unsigned long libxl_get_required_shadow_memory(unsigned long maxmem_kb, unsigned int smp_cpus)
+{
+ /* 256 pages (1MB) per vcpu,
+ plus 1 page per MiB of RAM for the P2M map,
+ plus 1 page per MiB of RAM to shadow the resident processes.
+ This is higher than the minimum that Xen would allocate if no value
+ were given (but the Xen minimum is for safety, not performance).
+ */
+ return 4 * (256 * smp_cpus + 2 * (maxmem_kb / 1024));
+}
+
+char *libxl_domid_to_name(struct libxl_ctx *ctx, uint32_t domid)
+{
+ unsigned int len;
+ char path[strlen("/local/domain") + 12];
+ char *s;
+
+ snprintf(path, sizeof(path), "/local/domain/%d/name", domid);
+ s = xs_read(ctx->xsh, XBT_NULL, path, &len);
+ libxl_ptr_add(ctx, s);
+ return s;
+}
+
+int libxl_name_to_domid(struct libxl_ctx *ctx, char *name, uint32_t *domid)
+{
+ unsigned int num, len;
+ char path[strlen("/local/domain") + 12];
+ int i;
+ char *domname, **l;
+
+ l = xs_directory(ctx->xsh, XBT_NULL, "/local/domain", &num);
+ for (i = 0; i < num; i++) {
+ snprintf(path, sizeof(path), "/local/domain/%s/name", l[i]);
+ domname = xs_read(ctx->xsh, XBT_NULL, path, &len);
+ if (domname != NULL && !strncmp(domname, name, len)) {
+ *domid = atoi(l[i]);
+ free(l);
+ free(domname);
+ return 0;
+ }
+ free(domname);
+ }
+ free(l);
+ return -1;
+}
+
+int libxl_uuid_to_domid(struct libxl_ctx *ctx, uint8_t *uuid, uint32_t *domid)
+{
+ int nb_domain, i;
+ struct libxl_dominfo *info = libxl_domain_list(ctx, &nb_domain);
+ for (i = 0; i < nb_domain; i++) {
+ if (!memcmp(info[i].uuid, uuid, 16)) {
+ *domid = info[i].domid;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int libxl_domid_to_uuid(struct libxl_ctx *ctx, uint8_t **uuid, uint32_t domid)
+{
+ int nb_domain, i;
+ struct libxl_dominfo *info = libxl_domain_list(ctx, &nb_domain);
+ for (i = 0; i < nb_domain; i++) {
+ if (domid == info[i].domid) {
+ *uuid = libxl_zalloc(ctx, 16);
+ memcpy(*uuid, info[i].uuid, 16);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int libxl_is_uuid(char *s)
+{
+ int i;
+ if (!s || strlen(s) != 36)
+ return 0;
+ for (i = 0; i < 36; i++) {
+ if (i == 8 || i == 13 || i == 18 || i == 23) {
+ if (s[i] != '-')
+ return 0;
+ } else {
+ if (!isxdigit(s[i]))
+ return 0;
+ }
+ }
+ return 1;
+}
+
+uint8_t *string_to_uuid(struct libxl_ctx *ctx, char *s)
+{
+ uint8_t *buf;
+ if (!s || !ctx)
+ return NULL;
+
+ buf = libxl_zalloc(ctx, 16);
+ sscanf(s, UUID_FMT, &buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5],
+ &buf[6], &buf[7], &buf[8], &buf[9], &buf[10], &buf[11], &buf[12],
+ &buf[13], &buf[14], &buf[15]);
+ return buf;
+}
+
+char *uuid_to_string(struct libxl_ctx *ctx, uint8_t *uuid)
+{
+ if (!uuid)
+ return NULL;
+ return libxl_sprintf(ctx, UUID_FMT,
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5], uuid[6], uuid[7],
+ uuid[8], uuid[9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15]);
+}
+
+int libxl_param_to_domid(struct libxl_ctx *ctx, char *p, uint32_t *domid)
+{
+ uint8_t *uuid;
+ uint32_t d;
+
+ if (libxl_is_uuid(p)) {
+ uuid = string_to_uuid(ctx, p);
+ return libxl_uuid_to_domid(ctx, uuid, domid);
+ }
+ errno = 0;
+ d = strtol(p, (char **) NULL, 10);
+ if (!errno && d != 0 && d != LONG_MAX && d != LONG_MIN) {
+ *domid = d;
+ return 0;
+ }
+ return libxl_name_to_domid(ctx, p, domid);
+}
diff --git a/tools/libxl/libxl_utils.h b/tools/libxl/libxl_utils.h
new file mode 100644
index 0000000000..d5cc2c09e9
--- /dev/null
+++ b/tools/libxl/libxl_utils.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+ *
+ * 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.
+ */
+
+#ifndef LIBXL_UTILS_H
+#define LIBXL_UTILS_H
+
+#include "libxl.h"
+
+#define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
+
+unsigned long libxl_get_required_shadow_memory(unsigned long maxmem_kb, unsigned int smp_cpus);
+int libxl_name_to_domid(struct libxl_ctx *ctx, char *name, uint32_t *domid);
+char *libxl_domid_to_name(struct libxl_ctx *ctx, uint32_t domid);
+int libxl_uuid_to_domid(struct libxl_ctx *ctx, uint8_t *uuid, uint32_t *domid);
+int libxl_domid_to_uuid(struct libxl_ctx *ctx, uint8_t **uuid, uint32_t domid);
+int libxl_is_uuid(char *s);
+uint8_t *string_to_uuid(struct libxl_ctx *ctx, char *s);
+char *uuid_to_string(struct libxl_ctx *ctx, uint8_t *uuid);
+int libxl_param_to_domid(struct libxl_ctx *ctx, char *p, uint32_t *domid);
+
+#endif
+
diff --git a/tools/libxl/libxl_xshelp.c b/tools/libxl/libxl_xshelp.c
new file mode 100644
index 0000000000..6286d02826
--- /dev/null
+++ b/tools/libxl/libxl_xshelp.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * 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 <string.h>
+#include <stddef.h>
+#include "libxl.h"
+#include "libxl_internal.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+char **libxl_xs_kvs_of_flexarray(struct libxl_ctx *ctx, flexarray_t *array, int length)
+{
+ char **kvs;
+ int i;
+
+ kvs = libxl_calloc(ctx, length + 2, sizeof(char *));
+ if (kvs) {
+ for (i = 0; i < length; i += 2) {
+ void *ptr;
+
+ flexarray_get(array, i, &ptr);
+ kvs[i] = (char *) ptr;
+ flexarray_get(array, i + 1, &ptr);
+ kvs[i + 1] = (char *) ptr;
+ }
+ kvs[i] = NULL;
+ kvs[i + 1] = NULL;
+ }
+ return kvs;
+}
+
+int libxl_xs_writev(struct libxl_ctx *ctx, xs_transaction_t t,
+ char *dir, char *kvs[])
+{
+ char *path;
+ int i;
+
+ if (!kvs)
+ return 0;
+
+ for (i = 0; kvs[i] != NULL; i += 2) {
+ path = libxl_sprintf(ctx, "%s/%s", dir, kvs[i]);
+ if (path) {
+ int length = strlen(kvs[i + 1]);
+ xs_write(ctx->xsh, t, path, kvs[i + 1], length);
+ }
+ libxl_free(ctx, path);
+ }
+ return 0;
+}
+
+int libxl_xs_write(struct libxl_ctx *ctx, xs_transaction_t t,
+ char *path, char *fmt, ...)
+{
+ char *s;
+ va_list ap;
+ int ret;
+ va_start(ap, fmt);
+ ret = vasprintf(&s, fmt, ap);
+ va_end(ap);
+
+ if (ret == -1) {
+ return -1;
+ }
+ xs_write(ctx->xsh, t, path, s, ret);
+ free(s);
+ return 0;
+}
+
+char * libxl_xs_read(struct libxl_ctx *ctx, xs_transaction_t t, char *path)
+{
+ unsigned int len;
+ char *ptr;
+
+ ptr = xs_read(ctx->xsh, t, path, &len);
+ if (ptr != NULL) {
+ libxl_ptr_add(ctx, ptr);
+ return ptr;
+ }
+ return 0;
+}
+
+char *libxl_xs_get_dompath(struct libxl_ctx *ctx, uint32_t domid)
+{
+ char *s = xs_get_domain_path(ctx->xsh, domid);
+ libxl_ptr_add(ctx, s);
+ return s;
+}
+
+char **libxl_xs_directory(struct libxl_ctx *ctx, xs_transaction_t t, char *path, unsigned int *nb)
+{
+ char **ret = NULL;
+ ret = xs_directory(ctx->xsh, XBT_NULL, path, nb);
+ libxl_ptr_add(ctx, ret);
+ return ret;
+}
diff --git a/tools/libxl/osdeps.c b/tools/libxl/osdeps.c
new file mode 100644
index 0000000000..81175aa328
--- /dev/null
+++ b/tools/libxl/osdeps.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+ *
+ * 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 <unistd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <stdlib.h>
+
+int vasprintf(char **buffer, const char *fmt, va_list ap)
+{
+ int size = 0;
+ int nchars;
+
+ *buffer = 0;
+
+ nchars = vsnprintf(*buffer, 0, fmt, ap);
+
+ if (nchars >= size)
+ {
+ char *tmpbuff;
+ /* Reallocate buffer now that we know how much space is needed. */
+ size = nchars+1;
+ tmpbuff = (char*)realloc(*buffer, size);
+
+
+ if (tmpbuff == NULL) { /* we need to free it*/
+ free(*buffer);
+ return -1;
+ }
+
+ *buffer=tmpbuff;
+ /* Try again. */
+ nchars = vsnprintf(*buffer, size, fmt, ap);
+ }
+
+ if (nchars < 0) return nchars;
+ return size;
+}
+
+int asprintf(char **buffer, char *fmt, ...)
+{
+ int status;
+ va_list ap;
+
+ va_start (ap, fmt);
+ status = vasprintf (buffer, fmt, ap);
+ va_end (ap);
+ return status;
+}
diff --git a/tools/libxl/osdeps.h b/tools/libxl/osdeps.h
new file mode 100644
index 0000000000..d5bc27d752
--- /dev/null
+++ b/tools/libxl/osdeps.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+ *
+ * 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.
+ */
+
+#ifndef LIBXL_OSDEP
+#define LIBXL_OSDEP
+
+#include <stdarg.h>
+
+int asprintf(char **buffer, char *fmt, ...);
+int vasprintf(char **buffer, const char *fmt, va_list ap);
+
+#endif
diff --git a/tools/libxl/xenguest.c b/tools/libxl/xenguest.c
new file mode 100644
index 0000000000..dc2a4e856a
--- /dev/null
+++ b/tools/libxl/xenguest.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * 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 <xenctrl.h>
+#include <xenguest.h>
+#include <sys/mman.h>
+#include <xen/hvm/hvm_info_table.h>
+
+int hvm_build_set_params(int handle, uint32_t domid,
+ int apic, int acpi, int pae, int nx, int viridian,
+ int vcpus, int store_evtchn, unsigned long *store_mfn)
+{
+ struct hvm_info_table *va_hvm;
+ uint8_t *va_map, sum;
+ int i;
+
+ va_map = xc_map_foreign_range(handle, domid,
+ XC_PAGE_SIZE, PROT_READ | PROT_WRITE,
+ HVM_INFO_PFN);
+ if (va_map == NULL)
+ return -1;
+
+ va_hvm = (struct hvm_info_table *)(va_map + HVM_INFO_OFFSET);
+ va_hvm->acpi_enabled = acpi;
+ va_hvm->apic_mode = apic;
+ va_hvm->nr_vcpus = vcpus;
+ for (i = 0, sum = 0; i < va_hvm->length; i++)
+ sum += ((uint8_t *) va_hvm)[i];
+ va_hvm->checksum -= sum;
+ munmap(va_map, XC_PAGE_SIZE);
+
+ xc_get_hvm_param(handle, domid, HVM_PARAM_STORE_PFN, store_mfn);
+ xc_set_hvm_param(handle, domid, HVM_PARAM_PAE_ENABLED, pae);
+ xc_set_hvm_param(handle, domid, HVM_PARAM_VIRIDIAN, viridian);
+ xc_set_hvm_param(handle, domid, HVM_PARAM_STORE_EVTCHN, store_evtchn);
+ return 0;
+}
diff --git a/tools/libxl/xl.c b/tools/libxl/xl.c
new file mode 100644
index 0000000000..ada61573ba
--- /dev/null
+++ b/tools/libxl/xl.c
@@ -0,0 +1,727 @@
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * 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.h"
+#include "libxl_utils.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <uuid/uuid.h>
+#include <libconfig.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <xenctrl.h>
+
+void log_callback(void *userdata, int loglevel, const char *file, int line, const char *func, char *s)
+{
+ fprintf(stderr, "[%d] %s:%d:%s: %s\n", loglevel, file, line, func, s);
+}
+
+static void printf_info(libxl_domain_create_info *c_info,
+ libxl_domain_build_info *b_info,
+ libxl_device_disk *disks,
+ int num_disks,
+ libxl_device_nic *vifs,
+ int num_vifs,
+ libxl_device_model_info *dm_info)
+{
+ int i;
+ printf("*** domain_create_info ***\n");
+ printf("hvm: %d\n", c_info->hvm);
+ printf("hap: %d\n", c_info->hap);
+ printf("ssidref: %d\n", c_info->ssidref);
+ printf("name: %s\n", c_info->name);
+ printf("uuid: " UUID_FMT "\n", c_info->uuid[0], c_info->uuid[1], c_info->uuid[2], c_info->uuid[3],
+ c_info->uuid[4], c_info->uuid[5], c_info->uuid[6], c_info->uuid[7],
+ c_info->uuid[8], c_info->uuid[9], c_info->uuid[10], c_info->uuid[11],
+ c_info->uuid[12], c_info->uuid[13], c_info->uuid[14], c_info->uuid[15]);
+ if (c_info->xsdata)
+ printf("xsdata: contains data\n");
+ else
+ printf("xsdata: (null)\n");
+ if (c_info->platformdata)
+ printf("platformdata: contains data\n");
+ else
+ printf("platformdata: (null)\n");
+
+
+ printf("\n\n\n*** domain_build_info ***\n");
+ printf("timer_mode: %d\n", b_info->timer_mode);
+ printf("hpet: %d\n", b_info->hpet);
+ printf("vpt_align: %d\n", b_info->vpt_align);
+ printf("max_vcpus: %d\n", b_info->max_vcpus);
+ printf("max_memkb: %d\n", b_info->max_memkb);
+ printf("video_memkb: %d\n", b_info->video_memkb);
+ printf("shadow_memkb: %d\n", b_info->shadow_memkb);
+ printf("kernel: %s\n", b_info->kernel);
+ printf("hvm: %d\n", b_info->hvm);
+
+ if (b_info->hvm) {
+ printf(" pae: %d\n", b_info->u.hvm.pae);
+ printf(" apic: %d\n", b_info->u.hvm.apic);
+ printf(" acpi: %d\n", b_info->u.hvm.acpi);
+ printf(" nx: %d\n", b_info->u.hvm.nx);
+ printf(" viridian: %d\n", b_info->u.hvm.viridian);
+ } else {
+ printf("cmdline: %s\n", b_info->u.pv.cmdline);
+ printf("ramdisk: %s\n", b_info->u.pv.ramdisk);
+ }
+
+ for (i = 0; i < num_disks; i++) {
+ printf("\n\n\n*** disks_info: %d ***\n", i);
+ printf("backend_domid %d\n", disks[i].backend_domid);
+ printf("domid %d\n", disks[i].domid);
+ printf("physpath %s\n", disks[i].physpath);
+ printf("phystype %d\n", disks[i].phystype);
+ printf("virtpath %s\n", disks[i].virtpath);
+ printf("unpluggable %d\n", disks[i].unpluggable);
+ printf("readwrite %d\n", disks[i].readwrite);
+ printf("is_cdrom %d\n", disks[i].is_cdrom);
+ }
+
+ for (i = 0; i < num_vifs; i++) {
+ printf("\n\n\n*** vifs_info: %d ***\n", i);
+ printf("backend_domid %d\n", vifs[i].backend_domid);
+ printf("domid %d\n", vifs[i].domid);
+ printf("devid %d\n", vifs[i].devid);
+ printf("mtu %d\n", vifs[i].mtu);
+ printf("model %s\n", vifs[i].model);
+ printf("mac %02x:%02x:%02x:%02x:%02x:%02x\n", vifs[i].mac[0], vifs[i].mac[1], vifs[i].mac[2], vifs[i].mac[3], vifs[i].mac[4], vifs[i].mac[5]);
+ printf("smac %s\n", vifs[i].mac);
+ }
+
+ printf("\n\n\n*** device_model_info ***\n");
+ printf("domid: %d\n", dm_info->domid);
+ printf("dom_name: %s\n", dm_info->dom_name);
+ printf("device_model: %s\n", dm_info->device_model);
+ printf("videoram: %d\n", dm_info->videoram);
+ printf("stdvga: %d\n", dm_info->stdvga);
+ printf("vnc: %d\n", dm_info->vnc);
+ printf("vnclisten: %s\n", dm_info->vnclisten);
+ printf("vncdisplay: %d\n", dm_info->vncdisplay);
+ printf("vncunused: %d\n", dm_info->vncunused);
+ printf("keymap: %s\n", dm_info->keymap);
+ printf("sdl: %d\n", dm_info->sdl);
+ printf("opengl: %d\n", dm_info->opengl);
+ printf("nographic: %d\n", dm_info->nographic);
+ printf("serial: %s\n", dm_info->serial);
+ printf("boot: %s\n", dm_info->boot);
+ printf("usb: %d\n", dm_info->usb);
+ printf("usbdevice: %s\n", dm_info->usbdevice);
+ printf("apic: %d\n", dm_info->apic);
+}
+
+static char* compat_config_file(const char *filename)
+{
+ char t;
+ char *newfile = (char*) malloc(strlen(filename) + 4);
+ char *buf = (char *) malloc(2048);
+ int size = 2048, i;
+ FILE *s;
+ FILE *d;
+
+ sprintf(newfile, "%s.xl", filename);
+
+ s = fopen(filename, "r");
+ if (!s) {
+ perror("cannot open file for reading");
+ return NULL;
+ }
+ d = fopen(newfile, "w");
+ if (!d) {
+ fclose(s);
+ perror("cannot open file for writting");
+ return NULL;
+ }
+
+ while (!feof(s)) {
+ fgets(buf, size, s);
+ while (buf[strlen(buf) - 1] != '\n' && !feof(s)) {
+ size += 1024;
+ buf = realloc(buf, size + 1024);
+ fgets(buf + (size - 1025), 1025, s);
+ }
+ for (i = 0; i < strlen(buf); i++)
+ if (buf[i] == '\'')
+ buf[i] = '\"';
+ if (strchr(buf, '=') != NULL) {
+ if ((buf[strlen(buf) - 1] == '\n' && buf[strlen(buf) - 2] == ';') ||
+ buf[strlen(buf) - 1] == ';') {
+ fputs(buf, d);
+ } else {
+ t = buf[strlen(buf) - 1];
+ buf[strlen(buf) - 1] = ';';
+ fputs(buf, d);
+ fputc(t, d);
+ }
+ } else if (buf[0] == '#' || buf[0] == ' ' || buf[0] == '\n') {
+ fputs(buf, d);
+ }
+ }
+
+ fclose(s);
+ fclose(d);
+
+ free(buf);
+
+ return newfile;
+}
+
+void init_create_info(libxl_domain_create_info *c_info)
+{
+ memset(c_info, '\0', sizeof(*c_info));
+ c_info->xsdata = NULL;
+ c_info->platformdata = NULL;
+ c_info->hvm = 1;
+ c_info->ssidref = 0;
+}
+
+void init_build_info(libxl_domain_build_info *b_info, libxl_domain_create_info *c_info)
+{
+ memset(b_info, '\0', sizeof(*b_info));
+ b_info->timer_mode = -1;
+ b_info->hpet = 1;
+ b_info->vpt_align = -1;
+ b_info->max_vcpus = 1;
+ b_info->max_memkb = 32 * 1024;
+ b_info->shadow_memkb = libxl_get_required_shadow_memory(b_info->max_memkb, b_info->max_vcpus);
+ b_info->video_memkb = 8 * 1024;
+ b_info->kernel = "/usr/lib/xen/boot/hvmloader";
+ if (c_info->hvm) {
+ b_info->hvm = 1;
+ b_info->u.hvm.pae = 1;
+ b_info->u.hvm.apic = 1;
+ b_info->u.hvm.acpi = 1;
+ b_info->u.hvm.nx = 1;
+ b_info->u.hvm.viridian = 0;
+ }
+}
+
+void init_dm_info(libxl_device_model_info *dm_info,
+ libxl_domain_create_info *c_info, libxl_domain_build_info *b_info)
+{
+ memset(dm_info, '\0', sizeof(*dm_info));
+
+ dm_info->dom_name = c_info->name;
+ dm_info->device_model = "/usr/lib/xen/bin/qemu-dm";
+ dm_info->videoram = b_info->video_memkb / 1024;
+ dm_info->apic = b_info->u.hvm.apic;
+
+ dm_info->stdvga = 0;
+ dm_info->vnc = 1;
+ dm_info->vnclisten = "127.0.0.1";
+ dm_info->vncdisplay = 0;
+ dm_info->vncunused = 0;
+ dm_info->keymap = NULL;
+ dm_info->sdl = 0;
+ dm_info->opengl = 0;
+ dm_info->nographic = 0;
+ dm_info->serial = NULL;
+ dm_info->boot = "cda";
+ dm_info->usb = 0;
+ dm_info->usbdevice = NULL;
+}
+
+void init_nic_info(libxl_device_nic *nic_info, int devnum)
+{
+ memset(nic_info, '\0', sizeof(*nic_info));
+
+
+ nic_info->backend_domid = 0;
+ nic_info->domid = 0;
+ nic_info->devid = devnum;
+ nic_info->mtu = 1492;
+ nic_info->model = "e1000";
+ srand(time(0));
+ nic_info->mac[0] = 0x00;
+ nic_info->mac[1] = 0x16;
+ nic_info->mac[2] = 0x3e;
+ nic_info->mac[3] = 1 + (int) (0x7f * (rand() / (RAND_MAX + 1.0)));
+ nic_info->mac[4] = 1 + (int) (0xff * (rand() / (RAND_MAX + 1.0)));
+ nic_info->mac[5] = 1 + (int) (0xff * (rand() / (RAND_MAX + 1.0)));
+ asprintf(&(nic_info->smac), "%02x:%02x:%02x:%02x:%02x:%02x", nic_info->mac[0], nic_info->mac[1], nic_info->mac[2], nic_info->mac[3], nic_info->mac[4], nic_info->mac[5]);
+ nic_info->ifname = NULL;
+ nic_info->bridge = "xenbr0";
+ nic_info->script = "/etc/xen/scripts/vif-bridge";
+ nic_info->nictype = NICTYPE_IOEMU;
+}
+
+void nic_info_domid_fixup(libxl_device_nic *nic_info, int domid)
+{
+ nic_info->domid = domid;
+ if (!nic_info->ifname)
+ asprintf(&(nic_info->ifname), "tap%d.%d", domid, nic_info->devid - 1);
+}
+
+void disk_info_domid_fixup(libxl_device_disk *disk_info, int domid)
+{
+ disk_info->domid = domid;
+}
+
+void device_model_info_domid_fixup(libxl_device_model_info *dm_info, int domid)
+{
+ dm_info->domid = domid;
+}
+
+static void parse_config_file(const char *filename,
+ libxl_domain_create_info *c_info,
+ libxl_domain_build_info *b_info,
+ libxl_device_disk **disks,
+ int *num_disks,
+ libxl_device_nic **vifs,
+ int *num_vifs,
+ libxl_device_model_info *dm_info)
+{
+ const char *buf;
+ uint8_t uuid[16];
+ long l;
+ struct config_t config;
+ struct config_setting_t *vbds, *nics;
+
+ config_init (&config);
+
+ if (!config_read_file(&config, filename)) {
+ char *newfilename;
+ config_destroy(&config);
+ newfilename = compat_config_file(filename);
+ config_init (&config);
+ if (!config_read_file(&config, newfilename)) {
+ fprintf(stderr, "Failed to parse config file %s, try removing any embedded python code\n", config_error_text(&config));
+ exit(1);
+ }
+ free(newfilename);
+ }
+
+ init_create_info(c_info);
+
+ if (config_lookup_string (&config, "builder", &buf) == CONFIG_TRUE) {
+ if (!strncmp(buf, "hvm", strlen(buf)))
+ c_info->hvm = 1;
+ else
+ c_info->hvm = 0;
+ }
+
+ /* hap is missing */
+ if (config_lookup_string (&config, "name", &buf) == CONFIG_TRUE)
+ c_info->name = strdup(buf);
+ else
+ c_info->name = "test";
+ uuid_generate(uuid);
+ c_info->uuid = uuid;
+
+ init_build_info(b_info, c_info);
+
+ /* the following is the actual config parsing with overriding values in the structures */
+ if (config_lookup_int (&config, "vcpus", &l) == CONFIG_TRUE)
+ b_info->max_vcpus = l;
+
+ if (config_lookup_int (&config, "memory", &l) == CONFIG_TRUE)
+ b_info->max_memkb = l * 1024;
+
+ if (config_lookup_int (&config, "shadow_memory", &l) == CONFIG_TRUE)
+ b_info->shadow_memkb = l * 1024;
+
+ if (config_lookup_int (&config, "videoram", &l) == CONFIG_TRUE)
+ b_info->video_memkb = l * 1024;
+
+ if (config_lookup_string (&config, "kernel", &buf) == CONFIG_TRUE)
+ b_info->kernel = strdup(buf);
+
+ if (c_info->hvm == 1) {
+ if (config_lookup_int (&config, "pae", &l) == CONFIG_TRUE)
+ b_info->u.hvm.pae = l;
+ if (config_lookup_int (&config, "apic", &l) == CONFIG_TRUE)
+ b_info->u.hvm.apic = l;
+ if (config_lookup_int (&config, "acpi", &l) == CONFIG_TRUE)
+ b_info->u.hvm.acpi = l;
+ if (config_lookup_int (&config, "nx", &l) == CONFIG_TRUE)
+ b_info->u.hvm.nx = l;
+ if (config_lookup_int (&config, "viridian", &l) == CONFIG_TRUE)
+ b_info->u.hvm.viridian = l;
+ } else {
+ if (config_lookup_string (&config, "cmdline", &buf) == CONFIG_TRUE)
+ b_info->u.pv.cmdline = buf;
+ if (config_lookup_string (&config, "ramdisk", &buf) == CONFIG_TRUE)
+ b_info->u.pv.ramdisk = buf;
+ }
+
+ if ((vbds = config_lookup (&config, "disk")) != NULL) {
+ *num_disks = 0;
+ *disks = NULL;
+ while ((buf = config_setting_get_string_elem (vbds, *num_disks)) != NULL) {
+ char *buf2 = strdup(buf);
+ char *p, *p2;
+ *disks = (libxl_device_disk *) realloc(*disks, sizeof (libxl_device_disk) * ((*num_disks) + 1));
+ (*disks)[*num_disks].backend_domid = 0;
+ (*disks)[*num_disks].domid = 0;
+ (*disks)[*num_disks].unpluggable = 0;
+ p = strtok(buf2, ",:");
+ while (*p == ' ')
+ p++;
+ if (!strcmp(p, "phy")) {
+ (*disks)[*num_disks].phystype = PHYSTYPE_PHY;
+ } else if (!strcmp(p, "file")) {
+ (*disks)[*num_disks].phystype = PHYSTYPE_FILE;
+ } else if (!strcmp(p, "tap")) {
+ p = strtok(NULL, ":");
+ if (!strcmp(p, "aio")) {
+ (*disks)[*num_disks].phystype = PHYSTYPE_AIO;
+ } else if (!strcmp(p, "vhd")) {
+ (*disks)[*num_disks].phystype = PHYSTYPE_VHD;
+ } else if (!strcmp(p, "qcow")) {
+ (*disks)[*num_disks].phystype = PHYSTYPE_QCOW;
+ } else if (!strcmp(p, "qcow2")) {
+ (*disks)[*num_disks].phystype = PHYSTYPE_QCOW2;
+ }
+ }
+ p = strtok(NULL, ",");
+ while (*p == ' ')
+ p++;
+ (*disks)[*num_disks].physpath= strdup(p);
+ p = strtok(NULL, ",");
+ while (*p == ' ')
+ p++;
+ p2 = strchr(p, ':');
+ if (p2 == NULL) {
+ (*disks)[*num_disks].virtpath = strdup(p);
+ (*disks)[*num_disks].is_cdrom = 0;
+ } else {
+ *p2 = '\0';
+ (*disks)[*num_disks].virtpath = strdup(p);
+ if (!strcmp(p2 + 1, "cdrom"))
+ (*disks)[*num_disks].is_cdrom = 1;
+ else
+ (*disks)[*num_disks].is_cdrom = 0;
+ }
+ p = strtok(NULL, ",");
+ while (*p == ' ')
+ p++;
+ (*disks)[*num_disks].readwrite = (p[0] == 'w') ? 1 : 0;
+ free(buf2);
+ *num_disks = (*num_disks) + 1;
+ }
+ }
+
+ if ((nics = config_lookup (&config, "vif")) != NULL) {
+ *num_vifs = 0;
+ *vifs = NULL;
+ while ((buf = config_setting_get_string_elem (nics, *num_vifs)) != NULL) {
+ char *buf2 = strdup(buf);
+ char *p, *p2;
+ *vifs = (libxl_device_nic *) realloc(*vifs, sizeof (libxl_device_nic) * ((*num_vifs) + 1));
+ init_nic_info((*vifs) + (*num_vifs), (*num_vifs) + 1);
+ p = strtok(buf2, ",");
+ if (!p)
+ goto skip;
+ do {
+ while (*p == ' ')
+ p++;
+ if ((p2 = strchr(p, '=')) == NULL)
+ break;
+ *p2 = '\0';
+ if (!strcmp(p, "model")) {
+ (*vifs)[*num_vifs].model = strdup(p2 + 1);
+ } else if (!strcmp(p, "mac")) {
+ char *p3 = p2 + 1;
+ (*vifs)[*num_vifs].smac = strdup(p3);
+ *(p3 + 2) = '\0';
+ (*vifs)[*num_vifs].mac[0] = strtol(p3, NULL, 16);
+ p3 = p3 + 3;
+ *(p3 + 2) = '\0';
+ (*vifs)[*num_vifs].mac[1] = strtol(p3, NULL, 16);
+ p3 = p3 + 3;
+ *(p3 + 2) = '\0';
+ (*vifs)[*num_vifs].mac[2] = strtol(p3, NULL, 16);
+ p3 = p3 + 3;
+ *(p3 + 2) = '\0';
+ (*vifs)[*num_vifs].mac[3] = strtol(p3, NULL, 16);
+ p3 = p3 + 3;
+ *(p3 + 2) = '\0';
+ (*vifs)[*num_vifs].mac[4] = strtol(p3, NULL, 16);
+ p3 = p3 + 3;
+ *(p3 + 2) = '\0';
+ (*vifs)[*num_vifs].mac[5] = strtol(p3, NULL, 16);
+ } else if (!strcmp(p, "bridge")) {
+ (*vifs)[*num_vifs].bridge = strdup(p2 + 1);
+ } else if (!strcmp(p, "type")) {
+ if (!strcmp(p2 + 1, "ioemu"))
+ (*vifs)[*num_vifs].nictype = NICTYPE_IOEMU;
+ else
+ (*vifs)[*num_vifs].nictype = NICTYPE_VIF;
+ } else if (!strcmp(p, "ip")) {
+ inet_pton(AF_INET, p2 + 1, &((*vifs)[*num_vifs].ip));
+ } else if (!strcmp(p, "script")) {
+ (*vifs)[*num_vifs].script = strdup(p2 + 1);
+ } else if (!strcmp(p, "vifname")) {
+ (*vifs)[*num_vifs].ifname = strdup(p2 + 1);
+ } else if (!strcmp(p, "rate")) {
+ fprintf(stderr, "the rate parameter for vifs is currently not supported\n");
+ } else if (!strcmp(p, "accel")) {
+ fprintf(stderr, "the accel parameter for vifs is currently not supported\n");
+ }
+ } while ((p = strtok(NULL, ",")) != NULL);
+skip:
+ free(buf2);
+ *num_vifs = (*num_vifs) + 1;
+ }
+ }
+
+ /* init dm from c and b */
+ init_dm_info(dm_info, c_info, b_info);
+
+ /* then process config related to dm */
+ if (config_lookup_string (&config, "device_model", &buf) == CONFIG_TRUE)
+ dm_info->device_model = strdup(buf);
+ if (config_lookup_int (&config, "stdvga", &l) == CONFIG_TRUE)
+ dm_info->stdvga = l;
+ if (config_lookup_int (&config, "vnc", &l) == CONFIG_TRUE)
+ dm_info->vnc = l;
+ if (config_lookup_string (&config, "vnclisten", &buf) == CONFIG_TRUE)
+ dm_info->vnclisten = strdup(buf);
+ if (config_lookup_int (&config, "vncdisplay", &l) == CONFIG_TRUE)
+ dm_info->vncdisplay = l;
+ if (config_lookup_int (&config, "vncunused", &l) == CONFIG_TRUE)
+ dm_info->vncunused = l;
+ if (config_lookup_string (&config, "keymap", &buf) == CONFIG_TRUE)
+ dm_info->keymap = strdup(buf);
+ if (config_lookup_int (&config, "sdl", &l) == CONFIG_TRUE)
+ dm_info->sdl = l;
+ if (config_lookup_int (&config, "opengl", &l) == CONFIG_TRUE)
+ dm_info->opengl = l;
+ if (config_lookup_int (&config, "nographic", &l) == CONFIG_TRUE)
+ dm_info->nographic = l;
+ if (config_lookup_string (&config, "serial", &buf) == CONFIG_TRUE)
+ dm_info->serial = strdup(buf);
+ if (config_lookup_string (&config, "boot", &buf) == CONFIG_TRUE)
+ dm_info->boot = strdup(buf);
+ if (config_lookup_int (&config, "usb", &l) == CONFIG_TRUE)
+ dm_info->usb = l;
+ if (config_lookup_string (&config, "usbdevice", &buf) == CONFIG_TRUE)
+ dm_info->usbdevice = strdup(buf);
+
+ config_destroy(&config);
+}
+
+static void create_domain(int debug, const char *filename)
+{
+ struct libxl_ctx ctx;
+ uint32_t domid;
+ libxl_domain_create_info info1;
+ libxl_domain_build_info info2;
+ libxl_device_model_info dm_info;
+ libxl_device_disk *disks = NULL;
+ libxl_device_nic *vifs = NULL;
+ int num_disks = 0, num_vifs = 0;
+ int i;
+
+ printf("Parsing config file %s\n", filename);
+ parse_config_file(filename, &info1, &info2, &disks, &num_disks, &vifs, &num_vifs, &dm_info);
+ if (debug)
+ printf_info(&info1, &info2, disks, num_disks, vifs, num_vifs, &dm_info);
+
+ libxl_ctx_init(&ctx);
+ libxl_ctx_set_log(&ctx, log_callback, NULL);
+ libxl_domain_make(&ctx, &info1, &domid);
+ libxl_domain_build(&ctx, &info2, domid);
+
+ device_model_info_domid_fixup(&dm_info, domid);
+
+ for (i = 0; i < num_disks; i++) {
+ disk_info_domid_fixup(disks + i, domid);
+ libxl_device_disk_add(&ctx, domid, &disks[i]);
+ }
+ for (i = 0; i < num_vifs; i++) {
+ nic_info_domid_fixup(vifs + i, domid);
+ libxl_device_nic_add(&ctx, domid, &vifs[i]);
+ }
+ libxl_create_device_model(&ctx, &dm_info, vifs, num_vifs);
+ libxl_domain_unpause(&ctx, domid);
+
+}
+
+static void help(char *command)
+{
+ if (!command || !strcmp(command, "help")) {
+ printf("Usage xl <subcommand> [args]\n\n");
+ printf("xl full list of subcommands:\n\n");
+ printf(" create create a domain from config file <filename>\n\n");
+ printf(" list list information about all domains\n\n");
+ printf(" destroy terminate a domain immediately\n\n");
+ } else if(!strcmp(command, "create")) {
+ printf("Usage: xl create <ConfigFile> [options] [vars]\n\n");
+ printf("Create a domain based on <ConfigFile>.\n\n");
+ printf("Options:\n\n");
+ printf("-h Print this help.\n");
+ printf("-d Enable debug messages.\n");
+ } else if(!strcmp(command, "list")) {
+ printf("Usage: xl list [Domain]\n\n");
+ printf("List information about all/some domains.\n\n");
+ } else if(!strcmp(command, "destroy")) {
+ printf("Usage: xl destroy <Domain>\n\n");
+ printf("Terminate a domain immediately.\n\n");
+ }
+}
+
+void destroy_domain(char *p)
+{
+ struct libxl_ctx ctx;
+ uint32_t domid;
+
+ libxl_ctx_init(&ctx);
+ libxl_ctx_set_log(&ctx, log_callback, NULL);
+
+ if (libxl_param_to_domid(&ctx, p, &domid) < 0) {
+ fprintf(stderr, "%s is an invalid domain identifier\n", p);
+ exit(2);
+ }
+ libxl_domain_destroy(&ctx, domid, 0);
+}
+
+void list_domains(void)
+{
+ struct libxl_ctx ctx;
+ xc_dominfo_t *info;
+ int nb_domain, i;
+
+ libxl_ctx_init(&ctx);
+ libxl_ctx_set_log(&ctx, log_callback, NULL);
+
+ info = libxl_domain_infolist(&ctx, &nb_domain);
+
+ if (info < 0) {
+ fprintf(stderr, "libxl_domain_infolist failed.\n");
+ exit(1);
+ }
+ printf("Name ID Mem VCPUs\tState\tTime(s)\n");
+ for (i = 0; i < nb_domain; i++) {
+ printf("%-40s %5d %5lu %5d %c%c%c%c%c%c %8.1f\n",
+ libxl_domid_to_name(&ctx, info[i].domid),
+ info[i].domid,
+ info[i].nr_pages * XC_PAGE_SIZE/(1024*1024),
+ info[i].nr_online_vcpus,
+ info[i].running ? 'r' : '-',
+ info[i].blocked ? 'b' : '-',
+ info[i].paused ? 'p' : '-',
+ info[i].shutdown ? 's' : '-',
+ info[i].crashed ? 'c' : '-',
+ info[i].dying ? 'd' : '-',
+ ((float)info[i].cpu_time / 1e9));
+ }
+}
+
+int main_destroy(int argc, char **argv)
+{
+ int opt;
+ char *p;
+
+ while ((opt = getopt(argc, argv, "h")) != -1) {
+ switch (opt) {
+ case 'h':
+ help("destroy");
+ exit(0);
+ default:
+ fprintf(stderr, "option not supported\n");
+ break;
+ }
+ }
+ if (optind >= argc) {
+ help("destroy");
+ exit(2);
+ }
+
+ p = argv[optind];
+
+ destroy_domain(p);
+ exit(0);
+}
+
+int main_list(int argc, char **argv)
+{
+ int opt;
+
+ while ((opt = getopt(argc, argv, "h")) != -1) {
+ switch (opt) {
+ case 'h':
+ help("list");
+ exit(0);
+ default:
+ fprintf(stderr, "option not supported\n");
+ break;
+ }
+ }
+
+ list_domains();
+ exit(0);
+}
+
+int main_create(int argc, char **argv)
+{
+ char *filename = NULL;
+ int debug = 0;
+ int opt;
+
+ while ((opt = getopt(argc, argv, "hd")) != -1) {
+ switch (opt) {
+ case 'd':
+ debug = 1;
+ break;
+ case 'h':
+ help("create");
+ exit(0);
+ default:
+ fprintf(stderr, "option not supported\n");
+ break;
+ }
+ }
+
+ if (optind >= argc) {
+ help("create");
+ exit(2);
+ }
+
+ filename = argv[optind];
+ create_domain(debug, filename);
+ exit(0);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc < 2) {
+ help(NULL);
+ exit(1);
+ }
+
+ if (!strcmp(argv[1], "create")) {
+ main_create(argc - 1, argv + 1);
+ } else if (!strcmp(argv[1], "list")) {
+ main_list(argc - 1, argv + 1);
+ } else if (!strcmp(argv[1], "destroy")) {
+ main_destroy(argc - 1, argv + 1);
+ } else if (!strcmp(argv[1], "help")) {
+ if (argc > 2)
+ help(argv[2]);
+ else
+ help(NULL);
+ exit(0);
+ } else {
+ fprintf(stderr, "command not implemented\n");
+ exit(1);
+ }
+}
+