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

[Xen-devel] [PATCH 1/1] backport libxl from xen-unstable to xen-4.0-testing



Signed-off-by: Gianni Tedesco <gianni.tedesco@xxxxxxxxxx>

b/tools/libxl/bash-completion |   21 
 b/tools/libxl/libxl_paths.c   |   61 
 b/tools/libxl/xl.h            |   81 
 b/tools/libxl/xl_cmdimpl.c    | 4243 ++++++++++++++++++++++++++++++++++++++++++
 b/tools/libxl/xl_cmdtable.c   |  322 +++
 tools/libxl/Makefile          |   28 
 tools/libxl/libxl.c           | 1030 ++++++++--
 tools/libxl/libxl.h           |  191 +
 tools/libxl/libxl_device.c    |   76 
 tools/libxl/libxl_dom.c       |  194 +
 tools/libxl/libxl_exec.c      |   34 
 tools/libxl/libxl_internal.c  |   13 
 tools/libxl/libxl_internal.h  |   24 
 tools/libxl/libxl_utils.c     |  297 ++
 tools/libxl/libxl_utils.h     |   45 
 tools/libxl/libxl_xshelp.c    |    6 
 tools/libxl/libxlu_cfg.c      |   37 
 tools/libxl/libxlutil.h       |    3 
 tools/libxl/xenguest.c        |   18 
 tools/libxl/xl.c              | 1750 -----------------
 tools/xenstore/xs.c           |   52 
 tools/xenstore/xs.h           |    3 
 22 files changed, 6555 insertions(+), 1974 deletions(-)

diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/Makefile
--- a/tools/libxl/Makefile      Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/libxl/Makefile      Mon Jul 05 12:19:50 2010 +0100
@@ -11,13 +11,13 @@
 XLUMAJOR = 1.0
 XLUMINOR = 0
 
-#CFLAGS += -Werror
+CFLAGS += -Werror
 CFLAGS += -I. -fPIC
 CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) $(CFLAGS_libxenstore)
 
 LIBS = $(LDFLAGS_libxenctrl) $(LDFLAGS_libxenguest) $(LDFLAGS_libxenstore)
 
-LIBXL_OBJS-y = osdeps.o
+LIBXL_OBJS-y = osdeps.o libxl_paths.o
 LIBXL_OBJS = flexarray.o libxl.o libxl_dom.o libxl_exec.o libxl_xshelp.o 
libxl_device.o libxl_internal.o xenguest.o libxl_utils.o $(LIBXL_OBJS-y)
 
 AUTOINCS= libxlu_cfg_y.h libxlu_cfg_l.h
@@ -43,6 +43,15 @@
 %.c: %.l
        $(FLEX) --header-file=$*.h --outfile=$@ $<
 
+genpath-target = $(call buildmakevars2file,_libxl_paths.h)
+$(eval $(genpath-target))
+
+_libxl_paths.h: genpath
+       sed -e "s/\([^=]*\)=\(.*\)/#define \1 \2/g" $@ >_$@
+       mv _$@ $@
+
+libxl_paths.c: _libxl_paths.h
+
 libxenlight.so: libxenlight.so.$(MAJOR)
        ln -sf $< $@
 
@@ -70,11 +79,21 @@
 xl.o: xl.c
        $(CC) $(CFLAGS) -c xl.c
 
-$(CLIENTS): xl.o libxlutil.so libxenlight.so
+xl_cmdimpl.o: xl_cmdimpl.c
+       $(CC) $(CFLAGS) -c xl_cmdimpl.c
+
+xl_cmdtable.o: xl_cmdtable.c
+       $(CC) $(CFLAGS) -c xl_cmdtable.c
+
+$(CLIENTS): xl.o xl_cmdimpl.o xl_cmdtable.o libxlutil.so libxenlight.so
        $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
 
 .PHONY: install
 install: all
+       $(INSTALL_DIR) $(DESTDIR)$(SBINDIR)
+       $(INSTALL_DIR) $(DESTDIR)$(LIBDIR)
+       $(INSTALL_DIR) $(DESTDIR)$(INCLUDEDIR)
+       $(INSTALL_DIR) $(DESTDIR)$(BASH_COMPLETION_DIR)
        $(INSTALL_PROG) xl $(DESTDIR)$(SBINDIR)
        $(INSTALL_PROG) libxenlight.so.$(MAJOR).$(MINOR) $(DESTDIR)$(LIBDIR)
        ln -sf libxenlight.so.$(MAJOR).$(MINOR) 
$(DESTDIR)$(LIBDIR)/libxenlight.so.$(MAJOR)
@@ -85,10 +104,11 @@
        ln -sf libxlutil.so.$(XLUMAJOR) $(DESTDIR)$(LIBDIR)/libxlutil.so
        $(INSTALL_DATA) libxlutil.a $(DESTDIR)$(LIBDIR)
        $(INSTALL_DATA) libxl.h $(DESTDIR)$(INCLUDEDIR)
+       $(INSTALL_DATA) bash-completion $(DESTDIR)$(BASH_COMPLETION_DIR)/xl.sh
 
 .PHONY: clean
 clean:
-       $(RM) -f *.o *.so* *.a $(CLIENTS) $(DEPS)
+       $(RM) -f _*.h *.o *.so* *.a $(CLIENTS) $(DEPS)
 #      $(RM) -f $(AUTOSRCS) $(AUTOINCS)
 
 distclean: clean
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/bash-completion
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxl/bash-completion       Mon Jul 05 12:19:50 2010 +0100
@@ -0,0 +1,21 @@
+#!/bin/bash
+# Copy this file to /etc/bash_completion.d/xl.sh
+
+_xl()
+{
+       local IFS=$'\n,'
+
+       local cur opts xl
+       COMPREPLY=()
+       cur="${COMP_WORDS[COMP_CWORD]}"
+       xl=xl
+       
+       if [[ $COMP_CWORD == 1 ]] ; then
+               opts=`${xl} help 2>/dev/null | sed '1,4d' | awk '{print $1}' | 
sed 's/$/ ,/g'` && COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
+               return 0
+       fi
+
+       return 0
+}
+
+complete -F _xl -o nospace -o default xl
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/libxl.c
--- a/tools/libxl/libxl.c       Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/libxl/libxl.c       Mon Jul 05 12:19:50 2010 +0100
@@ -45,6 +45,7 @@
     ctx->alloc_ptrs = calloc(ctx->alloc_maxsize, sizeof(void *));
     if (!ctx->alloc_ptrs)
         return ERROR_NOMEM;
+    memset(&ctx->version_info, 0, sizeof(libxl_version_info));
 
     ctx->xch = xc_interface_open();
     if (ctx->xch == -1) {
@@ -66,7 +67,7 @@
     libxl_free_all(ctx);
     free(ctx->alloc_ptrs);
     xc_interface_close(ctx->xch);
-    xs_daemon_close(ctx->xsh); 
+    if (ctx->xsh) xs_daemon_close(ctx->xsh); 
     return 0;
 }
 
@@ -82,7 +83,7 @@
 int libxl_domain_make(struct libxl_ctx *ctx, libxl_domain_create_info *info,
                        uint32_t *domid)
 {
-    int flags, ret, i;
+    int flags, ret, i, rc;
     char *uuid_string;
     char *rw_paths[] = { "device", "device/suspend/event-channel" , "data"};
     char *ro_paths[] = { "cpu", "memory", "device", "error", "drivers",
@@ -93,14 +94,12 @@
     xs_transaction_t t;
     xen_domain_handle_t handle;
 
-    uuid_string = string_of_uuid(ctx, info->uuid);
-    if (!uuid_string) {
-        XL_LOG(ctx, XL_LOG_ERROR, "cannot allocate uuid string");
-        return ERROR_FAIL;
-    }
+    uuid_string = libxl_uuid2string(ctx, info->uuid);
+    if (!uuid_string) return ERROR_NOMEM;
 
     flags = info->hvm ? XEN_DOMCTL_CDF_hvm_guest : 0;
     flags |= info->hap ? XEN_DOMCTL_CDF_hap : 0;
+    flags |= info->oos ? 0 : XEN_DOMCTL_CDF_oos_off;
     *domid = -1;
 
     /* Ultimately, handle is an array of 16 uint8_t, same as uuid */
@@ -146,7 +145,8 @@
 
     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));
+    rc = libxl_domain_rename(ctx, *domid, 0, info->name, t);
+    if (rc) return rc;
 
     for (i = 0; i < ARRAY_SIZE(rw_paths); i++) {
         char *path = libxl_sprintf(ctx, "%s/%s", dom_path, rw_paths[i]);
@@ -175,33 +175,118 @@
     return 0;
 }
 
+int libxl_domain_rename(struct libxl_ctx *ctx, uint32_t domid,
+                        const char *old_name, const char *new_name,
+                        xs_transaction_t trans) {
+    char *dom_path = 0;
+    const char *name_path;
+    char *got_old_name;
+    unsigned int got_old_len;
+    xs_transaction_t our_trans = 0;
+    int rc;
+
+    dom_path = libxl_xs_get_dompath(ctx, domid);
+    if (!dom_path) goto x_nomem;
+
+    name_path= libxl_sprintf(ctx, "%s/name", dom_path);
+    if (!name_path) goto x_nomem;
+
+ retry_transaction:
+    if (!trans) {
+        trans = our_trans = xs_transaction_start(ctx->xsh);
+        if (!our_trans) {
+            XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, errno,
+                            "create xs transaction for domain (re)name");
+            goto x_fail;
+        }
+    }
+
+    if (old_name) {
+        got_old_name = xs_read(ctx->xsh, trans, name_path, &got_old_len);
+        if (!got_old_name) {
+            XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, errno, "check old name"
+                            " for domain %"PRIu32" allegedly named `%s'",
+                            domid, old_name);
+            goto x_fail;
+        }
+        if (strcmp(old_name, got_old_name)) {
+            XL_LOG(ctx, XL_LOG_ERROR, "domain %"PRIu32" allegedly named "
+                   "`%s' is actually named `%s' - racing ?",
+                   domid, old_name, got_old_name);
+            free(got_old_name);
+            goto x_fail;
+        }
+        free(got_old_name);
+    }
+    if (!xs_write(ctx->xsh, trans, name_path,
+                  new_name, strlen(new_name))) {
+        XL_LOG(ctx, XL_LOG_ERROR, "failed to write new name `%s'"
+               " for domain %"PRIu32" previously named `%s'",
+               new_name, domid, old_name);
+        goto x_fail;
+    }
+
+    if (our_trans) {
+        if (!xs_transaction_end(ctx->xsh, our_trans, 0)) {
+            trans = our_trans = 0;
+            if (errno != EAGAIN) {
+                XL_LOG(ctx, XL_LOG_ERROR, "failed to commit new name `%s'"
+                       " for domain %"PRIu32" previously named `%s'",
+                       new_name, domid, old_name);
+                goto x_fail;
+            }
+            XL_LOG(ctx, XL_LOG_DEBUG, "need to retry rename transaction"
+                   " for domain %"PRIu32" (name_path=\"%s\", new_name=\"%s\")",
+                   domid, name_path, new_name);
+            goto retry_transaction;
+        }
+        our_trans = 0;
+    }
+
+    rc = 0;
+ x_rc:
+    if (dom_path) libxl_free(ctx, dom_path);
+    if (our_trans) xs_transaction_end(ctx->xsh, our_trans, 1);
+    return rc;
+
+ x_fail:  rc = ERROR_FAIL;  goto x_rc;
+ x_nomem: rc = ERROR_NOMEM; goto x_rc;
+}
+
 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;
+    struct timeval start_time;
     int i, ret;
 
     ret = build_pre(ctx, domid, info, state);
     if (ret) goto out;
 
+    gettimeofday(&start_time, NULL);
+
     if (info->hvm) {
         ret = build_hvm(ctx, domid, info, state);
         if (ret) goto out;
 
-        vments = libxl_calloc(ctx, 5, sizeof(char *));
+        vments = libxl_calloc(ctx, 7, sizeof(char *));
         vments[0] = "rtc/timeoffset";
         vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
         vments[2] = "image/ostype";
         vments[3] = "hvm";
+        vments[4] = "start_time";
+        vments[5] = libxl_sprintf(ctx, "%lu.%02d", 
start_time.tv_sec,(int)start_time.tv_usec/10000);
     } else {
         ret = build_pv(ctx, domid, info, state);
         if (ret) goto out;
 
-        vments = libxl_calloc(ctx, 9, sizeof(char *));
+        vments = libxl_calloc(ctx, 11, sizeof(char *));
         i = 0;
         vments[i++] = "image/ostype";
         vments[i++] = "linux";
         vments[i++] = "image/kernel";
         vments[i++] = (char*) info->kernel;
+        vments[i++] = "start_time";
+        vments[i++] = libxl_sprintf(ctx, "%lu.%02d", 
start_time.tv_sec,(int)start_time.tv_usec/10000);
         if (info->u.pv.ramdisk) {
             vments[i++] = "image/ramdisk";
             vments[i++] = (char*) info->u.pv.ramdisk;
@@ -221,7 +306,8 @@
                          libxl_device_model_info *dm_info)
 {
     char **vments = NULL, **localents = NULL;
-    int i, ret;
+    struct timeval start_time;
+    int i, ret, esave, flags;
 
     ret = build_pre(ctx, domid, info, state);
     if (ret) goto out;
@@ -229,19 +315,25 @@
     ret = restore_common(ctx, domid, info, state, fd);
     if (ret) goto out;
 
+    gettimeofday(&start_time, NULL);
+
     if (info->hvm) {
-        vments = libxl_calloc(ctx, 5, sizeof(char *));
+        vments = libxl_calloc(ctx, 7, sizeof(char *));
         vments[0] = "rtc/timeoffset";
         vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
         vments[2] = "image/ostype";
         vments[3] = "hvm";
+        vments[4] = "start_time";
+        vments[5] = libxl_sprintf(ctx, "%lu.%02d", 
start_time.tv_sec,(int)start_time.tv_usec/10000);
     } else {
-        vments = libxl_calloc(ctx, 9, sizeof(char *));
+        vments = libxl_calloc(ctx, 11, sizeof(char *));
         i = 0;
         vments[i++] = "image/ostype";
         vments[i++] = "linux";
         vments[i++] = "image/kernel";
         vments[i++] = (char*) info->kernel;
+        vments[i++] = "start_time";
+        vments[i++] = libxl_sprintf(ctx, "%lu.%02d", 
start_time.tv_sec,(int)start_time.tv_usec/10000);
         if (info->u.pv.ramdisk) {
             vments[i++] = "image/ramdisk";
             vments[i++] = (char*) info->u.pv.ramdisk;
@@ -254,11 +346,27 @@
     ret = build_post(ctx, domid, info, state, vments, localents);
     if (ret) goto out;
 
-    if (info->hvm)
-        asprintf(&(dm_info->saved_state), "/var/lib/xen/qemu-save.%d", domid);
-    else
-        dm_info->saved_state = NULL;
+    dm_info->saved_state = NULL;
+    if (info->hvm) {
+        ret = asprintf(&dm_info->saved_state,
+                       "/var/lib/xen/qemu-save.%d", domid);
+        ret = (ret < 0) ? ERROR_FAIL : 0;
+    }
+
 out:
+    esave = errno;
+
+    flags = fcntl(fd, F_GETFL);
+    if (flags == -1) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "unable to get flags on restore fd");
+    } else {
+        flags &= ~O_NONBLOCK;
+        if (fcntl(fd, F_SETFL, flags) == -1)
+            XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "unable to put restore fd"
+                         " back to blocking mode");
+    }
+
+    errno = esave;
     return ret;
 }
 
@@ -284,6 +392,24 @@
     return 0;
 }
 
+static void xcinfo2xlinfo(const xc_domaininfo_t *xcinfo,
+                          struct libxl_dominfo *xlinfo) {
+    memcpy(&(xlinfo->uuid), xcinfo->handle, sizeof(xen_domain_handle_t));
+    xlinfo->domid = xcinfo->domain;
+
+    if (xcinfo->flags & XEN_DOMINF_dying)
+        xlinfo->dying = 1;
+    else if (xcinfo->flags & XEN_DOMINF_paused)
+        xlinfo->paused = 1;
+    else if (xcinfo->flags & XEN_DOMINF_blocked ||
+             xcinfo->flags & XEN_DOMINF_running)
+        xlinfo->running = 1;
+    xlinfo->max_memkb = PAGE_TO_MEMKB(xcinfo->tot_pages);
+    xlinfo->cpu_time = xcinfo->cpu_time;
+    xlinfo->vcpu_max_id = xcinfo->max_vcpu_id;
+    xlinfo->vcpu_online = xcinfo->nr_online_vcpus;
+}
+
 struct libxl_dominfo * libxl_list_domain(struct libxl_ctx *ctx, int *nb_domain)
 {
     struct libxl_dominfo *ptr;
@@ -292,29 +418,31 @@
     int size = 1024;
 
     ptr = calloc(size, sizeof(struct libxl_dominfo));
-    if (!ptr)
-        return NULL;
+    if (!ptr) return NULL;
 
     ret = xc_domain_getinfolist(ctx->xch, 0, 1024, info);
+    if (ret<0) return NULL;
+
     for (i = 0; i < ret; i++) {
-        memcpy(&(ptr[i].uuid), info[i].handle, sizeof(xen_domain_handle_t));
-        ptr[i].domid = info[i].domain;
-
-        if (info[i].flags & XEN_DOMINF_dying)
-            ptr[i].dying = 1;
-        else if (info[i].flags & XEN_DOMINF_paused)
-            ptr[i].paused = 1;
-        else if (info[i].flags & XEN_DOMINF_blocked || info[i].flags & 
XEN_DOMINF_running)
-            ptr[i].running = 1;
-        ptr[i].max_memkb = PAGE_TO_MEMKB(info[i].tot_pages);
-        ptr[i].cpu_time = info[i].cpu_time;
-        ptr[i].vcpu_max_id = info[i].max_vcpu_id;
-        ptr[i].vcpu_online = info[i].nr_online_vcpus;
+        xcinfo2xlinfo(&info[i], &ptr[i]);
     }
     *nb_domain = ret;
     return ptr;
 }
 
+int libxl_domain_info(struct libxl_ctx *ctx, struct libxl_dominfo *info_r,
+                      uint32_t domid) {
+    xc_domaininfo_t xcinfo;
+    int ret;
+
+    ret = xc_domain_getinfolist(ctx->xch, domid, 1, &xcinfo);
+    if (ret<0) return ERROR_FAIL;
+    if (ret==0 || xcinfo.domain != domid) return ERROR_INVAL;
+
+    xcinfo2xlinfo(&xcinfo, info_r);
+    return 0;
+}
+
 /* this API call only list VM running on this host. a VM can be an aggregate 
of multiple domains. */
 struct libxl_vminfo * libxl_list_vm(struct libxl_ctx *ctx, int *nb_vm)
 {
@@ -345,11 +473,11 @@
 {
     int hvm = is_hvm(ctx, domid);
     int live = info != NULL && info->flags & XL_SUSPEND_LIVE;
-    int debug = info != NULL && info->flags & XL_SUSPEND_LIVE;
+    int debug = info != NULL && info->flags & XL_SUSPEND_DEBUG;
 
     core_suspend(ctx, domid, fd, hvm, live, debug);
     if (hvm)
-        save_device_model(ctx, domid, fd);
+        return save_device_model(ctx, domid, fd);
     return 0;
 }
 
@@ -400,12 +528,12 @@
     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) {
+    if (is_hvm(ctx,domid)) {
         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)
+        if (!pvdriver || acpi_s_state != 0)
             xc_domain_shutdown(ctx->xch, domid, req);
     }
     return 0;
@@ -420,7 +548,8 @@
 int libxl_wait_for_domain_death(struct libxl_ctx *ctx, uint32_t domid, 
libxl_waiter *waiter)
 {
     waiter->path = strdup("@releaseDomain");
-    asprintf(&(waiter->token), "%d", DOMAIN_DEATH);
+    if (asprintf(&(waiter->token), "%d", DOMAIN_DEATH) < 0)
+        return -1;
     if (!xs_watch(ctx->xsh, waiter->path, waiter->token))
         return -1;
     return 0;
@@ -435,8 +564,12 @@
         domid = guest_domid;
 
     for (i = 0; i < num_disks; i++) {
-        asprintf(&(waiter[i].path), "%s/device/vbd/%d/eject", 
libxl_xs_get_dompath(ctx, domid), device_disk_dev_number(disks[i].virtpath));
-        asprintf(&(waiter[i].token), "%d", DISK_EJECT);
+        if (asprintf(&(waiter[i].path), "%s/device/vbd/%d/eject",
+                     libxl_xs_get_dompath(ctx, domid),
+                     device_disk_dev_number(disks[i].virtpath)) < 0)
+            return -1;
+        if (asprintf(&(waiter[i].token), "%d", DISK_EJECT) < 0)
+            return -1;
         xs_watch(ctx->xsh, waiter->path, waiter->token);
     }
     return 0;
@@ -616,6 +749,8 @@
         if (!xs_rm(ctx->xsh, XBT_NULL, xapi_path))
             XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xs_rm failed for %s", xapi_path);
 
+    libxl__userdata_destroyall(ctx, domid);
+
     rc = xc_domain_destroy(ctx->xch, domid);
     if (rc < 0) {
         XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_domain_destroy failed for 
%d", domid);
@@ -626,16 +761,9 @@
 
 int libxl_console_attach(struct libxl_ctx *ctx, uint32_t domid, int cons_num)
 {
-    struct stat st;
-    const char *XENCONSOLE = "/usr/lib/xen/bin/xenconsole";
-    char *cmd;
-
-    if (stat(XENCONSOLE, &st) != 0) {
-        XL_LOG(ctx, XL_LOG_ERROR, "could not access %s", XENCONSOLE);
-        return ERROR_FAIL;
-    }
-
-    cmd = libxl_sprintf(ctx, "%s %d --num %d", XENCONSOLE, domid, cons_num);
+    char *cmd = libxl_sprintf(
+        ctx, "%s/xenconsole %d --num %d",
+        libxl_private_bindir_path(), domid, cons_num);
     return (system(cmd) != 0) ? ERROR_FAIL : 0;
 }
 
@@ -663,7 +791,12 @@
         flexarray_set(dm_args, num++, "-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));
+                flexarray_set(
+                    dm_args, num++,
+                    libxl_sprintf(ctx, "%s:%d%s",
+                                  info->vnclisten,
+                                  info->vncdisplay,
+                                  info->vncpasswd ? ",password" : ""));
             } else {
                 flexarray_set(dm_args, num++, libxl_sprintf(ctx, 
"127.0.0.1:%d", info->vncdisplay));
             }
@@ -680,7 +813,7 @@
             flexarray_set(dm_args, num++, "-vncunused");
         }
     }
-    if (info->sdl || info->opengl) {
+    if (info->sdl) {
         flexarray_set(dm_args, num++, "-sdl");
         if (info->opengl) {
             flexarray_set(dm_args, num++, "-disable-opengl");
@@ -698,6 +831,8 @@
         flexarray_set(dm_args, num++, info->serial);
     }
     if (info->type == XENFV) {
+        int ioemu_vifs = 0;
+
         if (info->videoram) {
             flexarray_set(dm_args, num++, "-videoram");
             flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d", 
info->videoram));
@@ -720,6 +855,14 @@
         if (info->apic) {
             flexarray_set(dm_args, num++, "-acpi");
         }
+        if (info->vcpus > 1) {
+            flexarray_set(dm_args, num++, "-vcpus");
+            flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d", 
info->vcpus));
+        }
+        if (info->vcpu_avail) {
+            flexarray_set(dm_args, num++, "-vcpu_avail");
+            flexarray_set(dm_args, num++, libxl_sprintf(ctx, "0x%x", 
info->vcpu_avail));
+        }
         for (i = 0; i < num_vifs; i++) {
             if (vifs[i].nictype == NICTYPE_IOEMU) {
                 char *smac = libxl_sprintf(ctx, 
"%02x:%02x:%02x:%02x:%02x:%02x",
@@ -733,8 +876,14 @@
                 flexarray_set(dm_args, num++, "-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));
+                ioemu_vifs++;
             }
         }
+        /* If we have no emulated nics, tell qemu not to create any */
+        if ( ioemu_vifs == 0 ) {
+            flexarray_set(dm_args, num++, "-net");
+            flexarray_set(dm_args, num++, "none");
+        }
     }
     if (info->saved_state) {
         flexarray_set(dm_args, num++, "-loadvm");
@@ -763,7 +912,8 @@
     /* we mustn't use the parent's handle in the child */
 
     kvs[0] = "image/device-model-pid";
-    asprintf(&kvs[1], "%d", innerchild);
+    if (asprintf(&kvs[1], "%d", innerchild) < 0)
+        return;
     kvs[2] = NULL;
 
     rc = xs_writev(xsh, XBT_NULL, starting->dom_path, kvs);
@@ -786,6 +936,7 @@
     vfb->vnclisten = info->vnclisten;
     vfb->vncdisplay = info->vncdisplay;
     vfb->vncunused = info->vncunused;
+    vfb->vncpasswd = info->vncpasswd;
     vfb->keymap = info->keymap;
     vfb->sdl = info->sdl;
     vfb->opengl = info->opengl;
@@ -875,7 +1026,7 @@
     b_info.max_vcpus = 1;
     b_info.max_memkb = 32 * 1024;
     b_info.target_memkb = b_info.max_memkb;
-    b_info.kernel = "/usr/lib/xen/boot/ioemu-stubdom.gz";
+    b_info.kernel = libxl_abs_path(ctx, "ioemu-stubdom.gz", 
libxl_xenfirmwaredir_path());
     b_info.u.pv.cmdline = libxl_sprintf(ctx, " -d %d", info->domid);
     b_info.u.pv.ramdisk = "";
     b_info.u.pv.features = "";
@@ -976,6 +1127,9 @@
     int rc;
     char **args;
     struct libxl_device_model_starting buf_starting, *p;
+    xs_transaction_t t; 
+    char *vm_path;
+    char **pass_stuff;
 
     if (strstr(info->device_model, "stubdom-dm")) {
         libxl_device_vfb vfb;
@@ -991,6 +1145,7 @@
 
     path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d", info->domid);
     xs_mkdir(ctx->xsh, XBT_NULL, path);
+    libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/disable_pf", path), 
"%d", !info->xen_platform_pci);
 
     libxl_create_logfile(ctx, libxl_sprintf(ctx, "qemu-dm-%s", 
info->dom_name), &logfile);
     logfile_w = open(logfile, O_WRONLY|O_CREAT, 0644);
@@ -1012,11 +1167,29 @@
     p->dom_path = libxl_xs_get_dompath(ctx, info->domid);
     if (!p->dom_path) { libxl_free(ctx, p); return ERROR_FAIL; }
 
+    if (info->vncpasswd) {
+    retry_transaction:
+        /* Find uuid and the write the vnc password to xenstore for qemu. */
+        t = xs_transaction_start(ctx->xsh);
+        vm_path = libxl_xs_read(ctx,t,libxl_sprintf(ctx, "%s/vm", 
p->dom_path));
+        if (vm_path) {
+            /* Now write the vncpassword into it. */
+            pass_stuff = libxl_calloc(ctx, 2, sizeof(char *));
+            pass_stuff[0] = "vncpasswd";
+            pass_stuff[1] = info->vncpasswd;
+            libxl_xs_writev(ctx,t,vm_path,pass_stuff);
+            if (!xs_transaction_end(ctx->xsh, t, 0))
+                if (errno == EAGAIN)
+                    goto retry_transaction;
+        }
+    }
+
     rc = libxl_spawn_spawn(ctx, p, "device model", dm_xenstore_record_pid);
     if (rc < 0) goto xit;
     if (!rc) { /* inner child */
         libxl_exec(null, logfile_w, logfile_w,
-                   info->device_model, args);
+                   libxl_abs_path(ctx, info->device_model, 
libxl_private_bindir_path()),
+                   args);
     }
 
     rc = 0;
@@ -1078,7 +1251,8 @@
 
     
     while (!feof(f)) {
-        fscanf(f, "%d %s", &devnum, buf);
+        if (fscanf(f, "%d %s", &devnum, buf) != 2)
+            continue;
         p = strchr(buf, ':');
         if (p == NULL)
             continue;
@@ -1146,15 +1320,9 @@
                 char buf[1024], *dev;
                 dev = get_blktap2_device(ctx, disk->physpath, 
device_disk_string_of_phystype(disk->phystype));
                 if (dev == NULL) {
-                    if (pipe(p) < 0) {
-                        XL_LOG(ctx, XL_LOG_ERROR, "Failed to create a pipe");
-                        return -1;
-                    }
-                    rc = fork();
-                    if (rc < 0) {
-                        XL_LOG(ctx, XL_LOG_ERROR, "Failed to fork a new 
process");
-                        return -1;
-                    } else if (!rc) { /* child */
+                    rc= libxl_pipe(ctx, p);  if (rc==-1) return -1;
+                    rc= libxl_fork(ctx);  if (rc==-1) return -1;
+                    if (!rc) { /* child */
                         int null_r, null_w;
                         char *args[4];
                         args[0] = "tapdisk2";
@@ -1164,7 +1332,10 @@
 
                         null_r = open("/dev/null", O_RDONLY);
                         null_w = open("/dev/null", O_WRONLY);
-                        libxl_exec(null_r, p[1], null_w, "/usr/sbin/tapdisk2", 
args);
+                        libxl_exec(null_r, p[1], null_w,
+                                   libxl_abs_path(ctx, "tapdisk2",
+                                                  libxl_sbindir_path()),
+                                   args);
                         XL_LOG(ctx, XL_LOG_ERROR, "Error execing tapdisk2");
                     }
                     close(p[1]);
@@ -1262,6 +1433,8 @@
     unsigned int boffset = 0;
     unsigned int foffset = 0;
     libxl_device device;
+    char *dompath, **l;
+    unsigned int nb;
 
     front = flexarray_make(16, 1);
     if (!front)
@@ -1270,6 +1443,19 @@
     if (!back)
         return ERROR_NOMEM;
 
+    if (nic->devid == -1) {
+        if (!(dompath = libxl_xs_get_dompath(ctx, domid))) {
+            return ERROR_FAIL;
+        }
+        if (!(l = libxl_xs_directory(ctx, XBT_NULL,
+                                     libxl_sprintf(ctx, "%s/device/vif", 
dompath), &nb))) {
+            nic->devid = 0;
+        } else {
+            nic->devid = strtoul(l[nb - 1], NULL, 10) + 1;
+            libxl_free(ctx, l);
+        }
+    }
+
     device.backend_devid = nic->devid;
     device.backend_domid = nic->backend_domid;
     device.backend_kind = DEVICE_VIF;
@@ -1289,6 +1475,8 @@
     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++, "bridge");
+    flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", nic->bridge));
     flexarray_set(back, boffset++, "handle");
     flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", nic->devid));
 
@@ -1332,6 +1520,66 @@
     return libxl_device_del(ctx, &device, wait);
 }
 
+libxl_nicinfo *libxl_list_nics(struct libxl_ctx *ctx, uint32_t domid, unsigned 
int *nb)
+{
+    char *dompath, *nic_path_fe;
+    char **l;
+    char *val, *tok;
+    unsigned int nb_nics, i;
+    libxl_nicinfo *res, *nics;
+
+    dompath = libxl_xs_get_dompath(ctx, domid);
+    if (!dompath) {
+        return NULL;
+    }
+    l = libxl_xs_directory(ctx, XBT_NULL,
+                           libxl_sprintf(ctx, "%s/device/vif", dompath), 
&nb_nics);
+    if (!l) {
+        return NULL;
+    }
+    res = libxl_calloc(ctx, nb_nics, sizeof (libxl_device_nic));
+    if (!res) {
+        libxl_free(ctx, l);
+        return NULL;
+    }
+    nics = res;
+    for (*nb = nb_nics; nb_nics > 0; --nb_nics, ++l, ++nics) {
+        nic_path_fe = libxl_sprintf(ctx, "%s/device/vif/%s", dompath, *l);
+
+        nics->backend = libxl_xs_read(ctx, XBT_NULL,
+                                      libxl_sprintf(ctx, "%s/backend", 
nic_path_fe));
+        val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend-id", 
nic_path_fe));
+        nics->backend_id = val ? strtoul(val, NULL, 10) : -1;
+
+        nics->devid = strtoul(*l, NULL, 10);
+        val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/state", 
nic_path_fe));
+        nics->state = val ? strtoul(val, NULL, 10) : -1;
+        val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/mac", 
nic_path_fe));
+        for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
+             ++i, tok = strtok(NULL, ":")) {
+            nics->mac[i] = strtoul(tok, NULL, 16);
+        }
+        val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/event-channel", nic_path_fe));
+        nics->evtch = val ? strtol(val, NULL, 10) : -1;
+        val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/tx-ring-ref", nic_path_fe));
+        nics->rref_tx = val ? strtol(val, NULL, 10) : -1;
+        val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/rx-ring-ref", nic_path_fe));
+        nics->rref_rx = val ? strtol(val, NULL, 10) : -1;
+        nics->frontend = libxl_xs_read(ctx, XBT_NULL,
+                                       libxl_sprintf(ctx, "%s/frontend", 
nics->backend));
+        val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/frontend-id", nics->backend));
+        nics->frontend_id = val ? strtoul(val, NULL, 10) : -1;
+        nics->script = libxl_xs_read(ctx, XBT_NULL,
+                                     libxl_sprintf(ctx, "%s/script", 
nics->backend));
+
+        libxl_free(ctx, nic_path_fe);
+    }
+
+    libxl_free(ctx, l);
+    return res;
+}
+
+
 
/******************************************************************************/
 int libxl_device_console_add(struct libxl_ctx *ctx, uint32_t domid, 
libxl_device_console *console)
 {
@@ -1470,57 +1718,90 @@
 libxl_device_disk *libxl_device_disk_list(struct libxl_ctx *ctx, uint32_t 
domid, int *num)
 {
     char *be_path_tap, *be_path_vbd;
-    libxl_device_disk *disks = NULL;
-    char **l = NULL;
+    libxl_device_disk *dend, *disks, *ret = NULL;
+    char **b, **l = NULL;
     unsigned int numl;
-    int num_disks = 0, i;
     char *type;
 
     be_path_vbd = libxl_sprintf(ctx, "%s/backend/vbd/%d", 
libxl_xs_get_dompath(ctx, 0), domid);
     be_path_tap = libxl_sprintf(ctx, "%s/backend/tap/%d", 
libxl_xs_get_dompath(ctx, 0), domid);
 
-    l = libxl_xs_directory(ctx, XBT_NULL, be_path_vbd, &numl);
+    b = l = libxl_xs_directory(ctx, XBT_NULL, be_path_vbd, &numl);
     if (l) {
-        num_disks += numl;
-        disks = realloc(disks, sizeof(libxl_device_disk) * num_disks);
-        for (i = 0; i < numl; i++) {
-            disks[i].backend_domid = 0;
-            disks[i].domid = domid;
-            disks[i].physpath = libxl_xs_read(ctx, XBT_NULL, 
libxl_sprintf(ctx, "%s/%s/params", be_path_vbd, l[i]));
-            libxl_string_to_phystype(ctx, libxl_xs_read(ctx, XBT_NULL, 
libxl_sprintf(ctx, "%s/%s/type", be_path_vbd, l[i])), &(disks[i].phystype));
-            disks[i].virtpath = libxl_xs_read(ctx, XBT_NULL, 
libxl_sprintf(ctx, "%s/%s/dev", be_path_vbd, l[i]));
-            disks[i].unpluggable = atoi(libxl_xs_read(ctx, XBT_NULL, 
libxl_sprintf(ctx, "%s/%s/removable", be_path_vbd, l[i])));
-            if (!strcmp(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/%s/mode", be_path_vbd, l[i])), "w"))
-                disks[i].readwrite = 1;
+        ret = realloc(ret, sizeof(libxl_device_disk) * numl);
+        disks = ret;
+        *num = numl;
+        dend = ret + *num;
+        for (; disks < dend; ++disks, ++l) {
+            disks->backend_domid = 0;
+            disks->domid = domid;
+            disks->physpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/%s/params", be_path_vbd, *l));
+            libxl_string_to_phystype(ctx, libxl_xs_read(ctx, XBT_NULL, 
libxl_sprintf(ctx, "%s/%s/type", be_path_vbd, *l)), &(disks->phystype));
+            disks->virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/%s/dev", be_path_vbd, *l));
+            disks->unpluggable = atoi(libxl_xs_read(ctx, XBT_NULL, 
libxl_sprintf(ctx, "%s/%s/removable", be_path_vbd, *l)));
+            if (!strcmp(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/%s/mode", be_path_vbd, *l)), "w"))
+                disks->readwrite = 1;
             else
-                disks[i].readwrite = 0;
-            type = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/device-type", libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/%s/frontend", be_path_vbd, l[i]))));
-            disks[i].is_cdrom = !strcmp(type, "cdrom");
+                disks->readwrite = 0;
+            type = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/device-type", libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/%s/frontend", be_path_vbd, *l))));
+            disks->is_cdrom = !strcmp(type, "cdrom");
         }
-        free(l);
+        libxl_free(ctx, b);
     }
-    l = libxl_xs_directory(ctx, XBT_NULL, be_path_tap, &numl);
+    b = l = libxl_xs_directory(ctx, XBT_NULL, be_path_tap, &numl);
     if (l) {
-        num_disks += numl;
-        disks = realloc(disks, sizeof(libxl_device_disk) * num_disks);
-        for (i = 0; i < numl; i++) {
-            disks[i].backend_domid = 0;
-            disks[i].domid = domid;
-            disks[i].physpath = libxl_xs_read(ctx, XBT_NULL, 
libxl_sprintf(ctx, "%s/%s/params", be_path_tap, l[i]));
-            libxl_string_to_phystype(ctx, libxl_xs_read(ctx, XBT_NULL, 
libxl_sprintf(ctx, "%s/%s/type", be_path_tap, l[i])), &(disks[i].phystype));
-            disks[i].virtpath = libxl_xs_read(ctx, XBT_NULL, 
libxl_sprintf(ctx, "%s/%s/dev", be_path_tap, l[i]));
-            disks[i].unpluggable = atoi(libxl_xs_read(ctx, XBT_NULL, 
libxl_sprintf(ctx, "%s/%s/removable", be_path_tap, l[i])));
-            if (!strcmp(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/%s/mode", be_path_tap, l[i])), "w"))
-                disks[i].readwrite = 1;
+        ret = realloc(ret, sizeof(libxl_device_disk) * (*num + numl));
+        disks = ret + *num;
+        *num += numl;
+        for (dend = ret + *num; disks < dend; ++disks, ++l) {
+            disks->backend_domid = 0;
+            disks->domid = domid;
+            disks->physpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/%s/params", be_path_tap, *l));
+            libxl_string_to_phystype(ctx, libxl_xs_read(ctx, XBT_NULL, 
libxl_sprintf(ctx, "%s/%s/type", be_path_tap, *l)), &(disks->phystype));
+            disks->virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/%s/dev", be_path_tap, *l));
+            disks->unpluggable = atoi(libxl_xs_read(ctx, XBT_NULL, 
libxl_sprintf(ctx, "%s/%s/removable", be_path_tap, *l)));
+            if (!strcmp(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/%s/mode", be_path_tap, *l)), "w"))
+                disks->readwrite = 1;
             else
-                disks[i].readwrite = 0;
-            type = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/device-type", libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/%s/frontend", be_path_vbd, l[i]))));
-            disks[i].is_cdrom = !strcmp(type, "cdrom");
+                disks->readwrite = 0;
+            type = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/device-type", libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/%s/frontend", be_path_tap, *l))));
+            disks->is_cdrom = !strcmp(type, "cdrom");
         }
-        free(l);
+        libxl_free(ctx, b);
     }
-    *num = num_disks;
-    return disks;
+    return ret;
+}
+
+int libxl_device_disk_getinfo(struct libxl_ctx *ctx, uint32_t domid,
+                              libxl_device_disk *disk, libxl_diskinfo 
*diskinfo)
+{
+    char *dompath, *diskpath;
+    char *val;
+
+    dompath = libxl_xs_get_dompath(ctx, domid);
+    diskinfo->devid = device_disk_dev_number(disk->virtpath);
+
+    /* tap devices entries in xenstore are written as vbd devices. */
+    diskpath = libxl_sprintf(ctx, "%s/device/vbd/%d", dompath, 
diskinfo->devid);
+    diskinfo->backend = libxl_xs_read(ctx, XBT_NULL,
+                                      libxl_sprintf(ctx, "%s/backend", 
diskpath));
+    if (!diskinfo->backend) {
+        return ERROR_FAIL;
+    }
+    val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend-id", 
diskpath));
+    diskinfo->backend_id = val ? strtoul(val, NULL, 10) : -1;
+    val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/state", 
diskpath));
+    diskinfo->state = val ? strtoul(val, NULL, 10) : -1;
+    val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/event-channel", 
diskpath));
+    diskinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
+    val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/ring-ref", 
diskpath));
+    diskinfo->rref = val ? strtoul(val, NULL, 10) : -1;
+    diskinfo->frontend = libxl_xs_read(ctx, XBT_NULL,
+                                       libxl_sprintf(ctx, "%s/frontend", 
diskinfo->backend));
+    val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/frontend-id", 
diskinfo->backend));
+    diskinfo->frontend_id = val ? strtoul(val, NULL, 10) : -1;
+
+    return 0;
 }
 
 int libxl_cdrom_insert(struct libxl_ctx *ctx, uint32_t domid, 
libxl_device_disk *disk)
@@ -1571,6 +1852,8 @@
         info->vnclisten = libxl_sprintf(ctx, "%s", vfb->vnclisten);
     info->vncdisplay = vfb->vncdisplay;
     info->vncunused = vfb->vncunused;
+    if (vfb->vncpasswd)
+        info->vncpasswd = vfb->vncpasswd;
     if (vfb->keymap)
         info->keymap = libxl_sprintf(ctx, "%s", vfb->keymap);
     info->sdl = vfb->sdl;
@@ -1602,7 +1885,7 @@
     }
     info->domid = vfb->domid;
     info->dom_name = libxl_domid_to_name(ctx, vfb->domid);
-    info->device_model = "/usr/lib/xen/bin/qemu-dm";
+    info->device_model = libxl_abs_path(ctx, "qemu-dm", libxl_libexec_path());
     info->type = XENPV;
     return 0;
 }
@@ -1652,6 +1935,8 @@
     flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->vnc));
     flexarray_set(back, boffset++, "vnclisten");
     flexarray_set(back, boffset++, vfb->vnclisten);
+    flexarray_set(back, boffset++, "vncpasswd");
+    flexarray_set(back, boffset++, vfb->vncpasswd);
     flexarray_set(back, boffset++, "vncdisplay");
     flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->vncdisplay));
     flexarray_set(back, boffset++, "vncunused");
@@ -1939,7 +2224,7 @@
 
     /* TODO: check if the device can be assigned */
 
-    libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, 
pcidev->func);
+    libxl_device_pci_reset(ctx, pcidev->domain, pcidev->bus, pcidev->dev, 
pcidev->func);
 
     stubdomid = libxl_get_stubdom_id(ctx, domid);
     if (stubdomid != 0) {
@@ -1974,7 +2259,7 @@
         char *sysfs_path = libxl_sprintf(ctx, 
SYSFS_PCI_DEV"/"PCI_BDF"/resource", pcidev->domain,
                                          pcidev->bus, pcidev->dev, 
pcidev->func);
         FILE *f = fopen(sysfs_path, "r");
-        unsigned int start = 0, end = 0, flags = 0, size = 0;
+        unsigned long long start = 0, end = 0, flags = 0, size = 0;
         int irq = 0;
         int i;
 
@@ -1983,18 +2268,19 @@
             return -1;
         }
         for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
-            fscanf(f, "0x%x 0x%x 0x%x", &start, &end, &flags);
+            if (fscanf(f, "0x%llx 0x%llx 0x%llx\n", &start, &end, &flags) != 3)
+                continue;
             size = end - start + 1;
             if (start) {
                 if (flags & PCI_BAR_IO) {
                     rc = xc_domain_ioport_permission(ctx->xch, domid, start, 
size, 1);
                     if (rc < 0)
-                        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "Error: 
xc_domain_ioport_permission error 0x%x/0x%x", start, size);
+                        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "Error: 
xc_domain_ioport_permission error 0x%llx/0x%llx", start, size);
                 } else {
                     rc = xc_domain_iomem_permission(ctx->xch, domid, 
start>>XC_PAGE_SHIFT,
                                                     
(size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 1);
                     if (rc < 0)
-                        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "Error: 
xc_domain_iomem_permission error 0x%x/0x%x", start, size);
+                        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "Error: 
xc_domain_iomem_permission error 0x%llx/0x%llx", start, size);
                 }
             }
         }
@@ -2006,8 +2292,7 @@
             XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Couldn't open %s", sysfs_path);
             goto out;
         }
-        fscanf(f, "%u", &irq);
-        if (irq) {
+        if ((fscanf(f, "%u", &irq) == 1) && irq) {
             rc = xc_physdev_map_pirq(ctx->xch, domid, irq, &irq);
             if (rc < 0) {
                 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "Error: 
xc_physdev_map_pirq irq=%d", irq);
@@ -2071,7 +2356,8 @@
             goto skip1;
         }
         for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
-            fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags);
+            if (fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags) != 3)
+                continue;
             size = end - start + 1;
             if (start) {
                 if (flags & PCI_BAR_IO) {
@@ -2095,8 +2381,7 @@
             XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Couldn't open %s", sysfs_path);
             goto out;
         }
-        fscanf(f, "%u", &irq);
-        if (irq) {
+        if ((fscanf(f, "%u", &irq) == 1) && irq) {
             rc = xc_physdev_unmap_pirq(ctx->xch, domid, irq);
             if (rc < 0) {
                 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_physdev_map_pirq 
irq=%d", irq);
@@ -2109,7 +2394,7 @@
         fclose(f);
     }
 out:
-    libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, 
pcidev->func);
+    libxl_device_pci_reset(ctx, pcidev->domain, pcidev->bus, pcidev->dev, 
pcidev->func);
 
     if (!libxl_is_stubdom(ctx, domid, NULL)) {
         rc = xc_deassign_device(ctx->xch, domid, pcidev->value);
@@ -2184,20 +2469,80 @@
     return 0;
 }
 
-int libxl_set_memory_target(struct libxl_ctx *ctx, uint32_t domid, uint32_t 
target_memkb)
+int libxl_domain_setmaxmem(struct libxl_ctx *ctx, uint32_t domid, uint32_t 
max_memkb)
+{
+    char *mem, *endptr;
+    uint32_t memorykb;
+    char *dompath = libxl_xs_get_dompath(ctx, domid);
+
+    mem = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/memory/target", 
dompath));
+    if (!mem) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "cannot get memory info from 
%s/memory/target\n", dompath);
+        return 1;
+    }
+    memorykb = strtoul(mem, &endptr, 10);
+    if (*endptr != '\0') {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "invalid memory %s from 
%s/memory/target\n", mem, dompath);
+        return 1;
+    }
+
+    if (max_memkb < memorykb) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "memory_static_max must be greater 
than or or equal to memory_dynamic_max\n");
+        return 1;
+    }
+
+    if (domid != 0)
+        libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/memory/static-max", dompath), "%lu", max_memkb);
+
+    return 0;
+}
+
+int libxl_set_memory_target(struct libxl_ctx *ctx, uint32_t domid, uint32_t 
target_memkb, int enforce)
 {
     int rc = 0;
-    uint32_t videoram;
-    char *videoram_s = NULL;
+    uint32_t memorykb = 0, videoram = 0;
+    char *memmax, *endptr, *videoram_s = NULL;
     char *dompath = libxl_xs_get_dompath(ctx, domid);
+    xc_domaininfo_t info;
+    struct libxl_dominfo ptr;
+    char *uuid;
+
+    if (domid) {
+        memmax = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/memory/static-max", dompath));
+        if (!memmax) {
+            XL_LOG_ERRNO(ctx, XL_LOG_ERROR,
+                "cannot get memory info from %s/memory/static-max\n", dompath);
+            return 1;
+        }
+        memorykb = strtoul(memmax, &endptr, 10);
+        if (*endptr != '\0') {
+            XL_LOG_ERRNO(ctx, XL_LOG_ERROR,
+                "invalid max memory %s from %s/memory/static-max\n", memmax, 
dompath);
+            return 1;
+        }
+
+        if (target_memkb > memorykb) {
+            XL_LOG(ctx, XL_LOG_ERROR,
+                "memory_dynamic_max must be less than or equal to 
memory_static_max\n");
+            return 1;
+        }
+    }
 
     videoram_s = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/memory/videoram", dompath));
-    if (!videoram_s)
-        return -1;
-    videoram = atoi(videoram_s);
+    videoram = videoram_s ? atoi(videoram_s) : 0;
 
     libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/memory/target", 
dompath), "%lu", target_memkb);
-    rc = xc_domain_setmaxmem(ctx->xch, domid, target_memkb + 
LIBXL_MAXMEM_CONSTANT);
+
+    rc = xc_domain_getinfolist(ctx->xch, domid, 1, &info);
+    if (rc != 1 || info.domain != domid)
+        return rc;
+    xcinfo2xlinfo(&info, &ptr);
+    uuid = libxl_uuid2string(ctx, ptr.uuid);
+    libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "/vm/%s/memory", uuid), 
"%lu", target_memkb / 1024);
+
+    if (enforce || !domid)
+        memorykb = target_memkb;
+    rc = xc_domain_setmaxmem(ctx->xch, domid, memorykb + 
LIBXL_MAXMEM_CONSTANT);
     if (rc != 0)
         return rc;
     rc = xc_domain_memory_set_pod_target(ctx->xch, domid, (target_memkb - 
videoram) / 4, NULL, NULL, NULL);
@@ -2221,3 +2566,446 @@
 
     return rc;
 }
+
+int libxl_get_physinfo(struct libxl_ctx *ctx, struct libxl_physinfo *physinfo)
+{
+    xc_physinfo_t xcphysinfo = { 0 };
+    int rc;
+
+    rc = xc_physinfo(ctx->xch, &xcphysinfo);
+    if (rc != 0) {
+        return rc;
+    }
+    physinfo->threads_per_core = xcphysinfo.threads_per_core;
+    physinfo->cores_per_socket = xcphysinfo.cores_per_socket;
+    physinfo->max_cpu_id = xcphysinfo.max_cpu_id;
+    physinfo->nr_cpus = xcphysinfo.nr_cpus;
+    physinfo->cpu_khz = xcphysinfo.cpu_khz;
+    physinfo->total_pages = xcphysinfo.total_pages;
+    physinfo->free_pages = xcphysinfo.free_pages;
+    physinfo->scrub_pages = xcphysinfo.scrub_pages;
+    memcpy(physinfo->hw_cap,xcphysinfo.hw_cap, sizeof(physinfo->hw_cap));
+    physinfo->phys_cap = xcphysinfo.capabilities;
+
+    return 0;
+}
+
+const libxl_version_info* libxl_get_version_info(struct libxl_ctx *ctx)
+{
+    union {
+        xen_extraversion_t xen_extra;
+        xen_compile_info_t xen_cc;
+        xen_changeset_info_t xen_chgset;
+        xen_capabilities_info_t xen_caps;
+        xen_platform_parameters_t p_parms;
+        xen_commandline_t xen_commandline;
+    } u;
+    long xen_version;
+    libxl_version_info *info = &ctx->version_info;
+
+    if (info->xen_version_extra != NULL)
+        return info;
+
+    xen_version = xc_version(ctx->xch, XENVER_version, NULL);
+    info->xen_version_major = xen_version >> 16;
+    info->xen_version_minor = xen_version & 0xFF;
+    xc_version(ctx->xch, XENVER_extraversion, &u.xen_extra);
+    info->xen_version_extra = libxl_sprintf(ctx, "%s", u.xen_extra);
+
+    xc_version(ctx->xch, XENVER_compile_info, &u.xen_cc);
+    info->compiler = libxl_sprintf(ctx, "%s", u.xen_cc.compiler);
+    info->compile_by = libxl_sprintf(ctx, "%s", u.xen_cc.compile_by);
+    info->compile_domain = libxl_sprintf(ctx, "%s", u.xen_cc.compile_domain);
+    info->compile_date = libxl_sprintf(ctx, "%s", u.xen_cc.compile_date);
+
+    xc_version(ctx->xch, XENVER_capabilities, &u.xen_caps);
+    info->capabilities = libxl_sprintf(ctx, "%s", u.xen_caps);
+
+    xc_version(ctx->xch, XENVER_changeset, &u.xen_chgset);
+    info->changeset = libxl_sprintf(ctx, "%s", u.xen_chgset);
+
+    xc_version(ctx->xch, XENVER_platform_parameters, &u.p_parms);
+    info->virt_start = u.p_parms.virt_start;
+
+    info->pagesize = xc_version(ctx->xch, XENVER_pagesize, NULL);
+
+    xc_version(ctx->xch, XENVER_commandline, &u.xen_commandline);
+    info->commandline = libxl_sprintf(ctx, "%s", u.xen_commandline);
+
+    return info;
+}
+
+struct libxl_vcpuinfo *libxl_list_vcpu(struct libxl_ctx *ctx, uint32_t domid,
+                                       int *nb_vcpu, int *cpusize)
+{
+    struct libxl_vcpuinfo *ptr, *ret;
+    xc_domaininfo_t domaininfo;
+    xc_vcpuinfo_t vcpuinfo;
+    xc_physinfo_t physinfo = { 0 };
+
+    if (xc_domain_getinfolist(ctx->xch, domid, 1, &domaininfo) != 1) {
+        return NULL;
+    }
+    if (xc_physinfo(ctx->xch, &physinfo) == -1) {
+        return NULL;
+    }
+    *cpusize = physinfo.max_cpu_id + 1;
+    ptr = libxl_calloc(ctx, domaininfo.max_vcpu_id + 1, sizeof (struct 
libxl_vcpuinfo));
+    if (!ptr) {
+        return NULL;
+    }
+
+    ret = ptr;
+    for (*nb_vcpu = 0; *nb_vcpu <= domaininfo.max_vcpu_id; ++*nb_vcpu, ++ptr) {
+        ptr->cpumap = libxl_calloc(ctx, (*cpusize + 63) / 64, sizeof 
(uint64_t));
+        if (!ptr->cpumap) {
+            return NULL;
+        }
+        if (xc_vcpu_getinfo(ctx->xch, domid, *nb_vcpu, &vcpuinfo) == -1) {
+            return NULL;
+        }
+        if (xc_vcpu_getaffinity(ctx->xch, domid, *nb_vcpu, ptr->cpumap, 
*cpusize) == -1) {
+            return NULL;
+        }
+        ptr->vcpuid = *nb_vcpu;
+        ptr->cpu = vcpuinfo.cpu;
+        ptr->online = !!vcpuinfo.online;
+        ptr->blocked = !!vcpuinfo.blocked;
+        ptr->running = !!vcpuinfo.running;
+        ptr->vcpu_time = vcpuinfo.cpu_time;
+    }
+    return ret;
+}
+
+int libxl_set_vcpuaffinity(struct libxl_ctx *ctx, uint32_t domid, uint32_t 
vcpuid,
+                           uint64_t *cpumap, int cpusize)
+{
+    return (xc_vcpu_setaffinity(ctx->xch, domid, vcpuid, cpumap, cpusize));
+}
+
+int libxl_set_vcpucount(struct libxl_ctx *ctx, uint32_t domid, uint32_t count)
+{
+    xc_domaininfo_t domaininfo;
+    char *dompath;
+    int i;
+
+    if (xc_domain_getinfolist(ctx->xch, domid, 1, &domaininfo) != 1) {
+        return ERROR_FAIL;
+    }
+    if (!count || ((domaininfo.max_vcpu_id + 1) < count)) {
+        return ERROR_INVAL;
+    }
+    if (!(dompath = libxl_xs_get_dompath(ctx, domid)))
+        return ERROR_FAIL;
+
+    for (i = 0; i <= domaininfo.max_vcpu_id; ++i) {
+        libxl_xs_write(ctx, XBT_NULL,
+                       libxl_sprintf(ctx, "%s/cpu/%u/availability", dompath, 
i),
+                       "%s", ((1 << i) & ((1 << count) - 1)) ? "online" : 
"offline");
+    }
+    return 0;
+}
+
+/*
+ * returns one of the XEN_SCHEDULER_* constants from public/domctl.h
+ * or -1 if an error occured.
+ */
+int libxl_get_sched_id(struct libxl_ctx *ctx)
+{
+    int sched, ret;
+
+    if ((ret = xc_sched_id(ctx->xch, &sched)) != 0)
+        return ret;
+    return sched;
+}
+
+int libxl_sched_credit_domain_get(struct libxl_ctx *ctx, uint32_t domid, 
struct libxl_sched_credit *scinfo)
+{
+    struct xen_domctl_sched_credit sdom;
+    int rc;
+
+    rc = xc_sched_credit_domain_get(ctx->xch, domid, &sdom);
+    if (rc != 0)
+        return rc;
+
+    scinfo->weight = sdom.weight;
+    scinfo->cap = sdom.cap;
+
+    return 0;
+}
+
+int libxl_sched_credit_domain_set(struct libxl_ctx *ctx, uint32_t domid, 
struct libxl_sched_credit *scinfo)
+{
+    struct xen_domctl_sched_credit sdom;
+    xc_domaininfo_t domaininfo;
+    int rc;
+
+    rc = xc_domain_getinfolist(ctx->xch, domid, 1, &domaininfo);
+    if (rc != 1 || domaininfo.domain != domid)
+        return rc;
+
+
+    if (scinfo->weight < 1 || scinfo->weight > 65535) {
+        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc,
+            "Cpu weight out of range, valid values are within range from 1 to 
65535");
+        return -1;
+    }
+
+    if (scinfo->cap < 0 || scinfo->cap > (domaininfo.max_vcpu_id + 1) * 100) {
+        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc,
+            "Cpu cap out of range, valid range is from 0 to %d for specified 
number of vcpus",
+            ((domaininfo.max_vcpu_id + 1) * 100));
+        return -1;
+    }
+
+    sdom.weight = scinfo->weight;
+    sdom.cap = scinfo->cap;
+
+    rc = xc_sched_credit_domain_set(ctx->xch, domid, &sdom);
+    if (rc != 0)
+        return rc;
+
+    return 0;
+}
+
+static int trigger_type_from_string(char *trigger_name)
+{
+    if (!strcmp(trigger_name, "nmi"))
+        return XEN_DOMCTL_SENDTRIGGER_NMI;
+    else if (!strcmp(trigger_name, "reset"))
+        return XEN_DOMCTL_SENDTRIGGER_RESET;
+    else if (!strcmp(trigger_name, "init"))
+        return XEN_DOMCTL_SENDTRIGGER_INIT;
+    else if (!strcmp(trigger_name, "power"))
+        return XEN_DOMCTL_SENDTRIGGER_POWER;
+    else if (!strcmp(trigger_name, "sleep"))
+        return XEN_DOMCTL_SENDTRIGGER_SLEEP;
+    else
+        return -1;
+}
+
+int libxl_send_trigger(struct libxl_ctx *ctx, uint32_t domid, char 
*trigger_name, uint32_t vcpuid)
+{
+    int rc = -1;
+    int trigger_type = trigger_type_from_string(trigger_name);
+
+    if (trigger_type == -1) {
+        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, -1,
+            "Invalid trigger, valid triggers are 
<nmi|reset|init|power|sleep>");
+        return -1;
+    }
+
+    rc = xc_domain_send_trigger(ctx->xch, domid, trigger_type, vcpuid);
+    if (rc != 0)
+        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc,
+            "Send trigger '%s' failed", trigger_name);
+
+    return rc;
+}
+
+int libxl_send_sysrq(struct libxl_ctx *ctx, uint32_t domid, char sysrq)
+{
+    char *dompath = libxl_xs_get_dompath(ctx, domid);
+
+    libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/control/sysrq", 
dompath), "%c", sysrq);
+
+    return 0;
+}
+
+int libxl_send_debug_keys(struct libxl_ctx *ctx, char *keys)
+{
+    return xc_send_debug_keys(ctx->xch, keys);
+}
+
+struct libxl_xen_console_reader *
+    libxl_xen_console_read_start(struct libxl_ctx *ctx, int clear)
+{
+    struct libxl_xen_console_reader *cr;
+    unsigned int size = 16384;
+    char *buf = malloc(size);
+
+    if (!buf) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "cannot malloc buffer for 
libxl_xen_console_reader,"
+            " size is %u", size);
+        return NULL;
+    }
+
+    cr = malloc(sizeof(struct libxl_xen_console_reader));
+    if (!cr) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "cannot malloc 
libxl_xen_console_reader");
+        return NULL;
+    }
+
+    memset(cr, 0, sizeof(struct libxl_xen_console_reader));
+    cr->buffer = buf;
+    cr->size = size;
+    cr->count = size;
+    cr->clear = clear;
+    cr->incremental = 1;
+
+    return cr;
+}
+
+/* return values:                                          *line_r
+ *   1          success, whole line obtained from buffer    non-0
+ *   0          no more lines available right now           0
+ *   negative   error code ERROR_*                          0
+ * On success *line_r is updated to point to a nul-terminated
+ * string which is valid until the next call on the same console
+ * reader.  The libxl caller may overwrite parts of the string
+ * if it wishes. */
+int libxl_xen_console_read_line(struct libxl_ctx *ctx,
+                                struct libxl_xen_console_reader *cr,
+                                char **line_r)
+{
+    int ret;
+
+    memset(cr->buffer, 0, cr->size);
+    ret = xc_readconsolering(ctx->xch, &cr->buffer, &cr->count,
+                             cr->clear, cr->incremental, &cr->index);
+    if (!ret) {
+        if (cr->count) {
+            *line_r = cr->buffer;
+            ret = 1;
+        } else {
+            *line_r = NULL;
+            ret = 0;
+        }
+    }
+
+    return ret;
+}
+
+void libxl_xen_console_read_finish(struct libxl_ctx *ctx,
+                                   struct libxl_xen_console_reader *cr)
+{
+    free(cr->buffer);
+    free(cr);
+}
+
+uint32_t libxl_vm_get_start_time(struct libxl_ctx *ctx, uint32_t domid)
+{
+    char *dompath = libxl_xs_get_dompath(ctx, domid);
+    char *vm_path, *start_time;
+
+    vm_path = libxl_xs_read(
+        ctx, XBT_NULL, libxl_sprintf(ctx, "%s/vm", dompath));
+    start_time = libxl_xs_read(
+        ctx, XBT_NULL, libxl_sprintf(ctx, "%s/start_time", vm_path));
+    if (start_time == NULL) {
+        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, -1,
+                        "Can't get start time of domain '%d'", domid);
+        return -1;
+    }
+
+    return strtoul(start_time, NULL, 10);
+}
+
+char *libxl_tmem_list(struct libxl_ctx *ctx, uint32_t domid, int use_long)
+{
+    int rc;
+    char _buf[32768];
+
+    rc = xc_tmem_control(ctx->xch, -1, TMEMC_LIST, domid, 32768, use_long,
+                         0, _buf);
+    if (rc < 0) {
+        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc,
+            "Can not get tmem list");
+        return NULL;
+    }
+
+    return strdup(_buf);
+}
+
+int libxl_tmem_freeze(struct libxl_ctx *ctx, uint32_t domid)
+{
+    int rc;
+
+    rc = xc_tmem_control(ctx->xch, -1, TMEMC_FREEZE, domid, 0, 0,
+                         0, NULL);
+    if (rc < 0) {
+        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc,
+            "Can not freeze tmem pools");
+        return -1;
+    }
+
+    return rc;
+}
+
+int libxl_tmem_destroy(struct libxl_ctx *ctx, uint32_t domid)
+{
+    int rc;
+
+    rc = xc_tmem_control(ctx->xch, -1, TMEMC_DESTROY, domid, 0, 0,
+                         0, NULL);
+    if (rc < 0) {
+        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc,
+            "Can not destroy tmem pools");
+        return -1;
+    }
+
+    return rc;
+}
+
+int libxl_tmem_thaw(struct libxl_ctx *ctx, uint32_t domid)
+{
+    int rc;
+
+    rc = xc_tmem_control(ctx->xch, -1, TMEMC_THAW, domid, 0, 0,
+                         0, NULL);
+    if (rc < 0) {
+        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc,
+            "Can not thaw tmem pools");
+        return -1;
+    }
+
+    return rc;
+}
+
+static int32_t tmem_setop_from_string(char *set_name)
+{
+    if (!strcmp(set_name, "weight"))
+        return TMEMC_SET_WEIGHT;
+    else if (!strcmp(set_name, "cap"))
+        return TMEMC_SET_CAP;
+    else if (!strcmp(set_name, "compress"))
+        return TMEMC_SET_COMPRESS;
+    else
+        return -1;
+}
+
+int libxl_tmem_set(struct libxl_ctx *ctx, uint32_t domid, char* name, uint32_t 
set)
+{
+    int rc;
+    int32_t subop = tmem_setop_from_string(name);
+
+    if (subop == -1) {
+        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, -1,
+            "Invalid set, valid sets are <weight|cap|compress>");
+        return -1;
+    }
+    rc = xc_tmem_control(ctx->xch, -1, subop, domid, set, 0, 0, NULL);
+    if (rc < 0) {
+        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc,
+            "Can not set tmem %s", name);
+        return -1;
+    }
+
+    return rc;
+}
+
+int libxl_tmem_shared_auth(struct libxl_ctx *ctx, uint32_t domid,
+                           char* uuid, int auth)
+{
+    int rc;
+
+    rc = xc_tmem_auth(ctx->xch, domid, uuid, auth);
+    if (rc < 0) {
+        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc,
+            "Can not set tmem shared auth");
+        return -1;
+    }
+
+    return rc;
+}
+
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/libxl.h
--- a/tools/libxl/libxl.h       Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/libxl/libxl.h       Mon Jul 05 12:19:50 2010 +0100
@@ -41,6 +41,21 @@
     uint32_t domid;
 };
 
+typedef struct {
+    int xen_version_major;
+    int xen_version_minor;
+    char *xen_version_extra;
+    char *compiler;
+    char *compile_by;
+    char *compile_domain;
+    char *compile_date;
+    char *capabilities;
+    char *changeset;
+    unsigned long virt_start;
+    unsigned long pagesize;
+    char *commandline;
+} libxl_version_info;
+
 struct libxl_ctx {
     int xch;
     struct xs_handle *xsh;
@@ -56,11 +71,15 @@
      * set this after libxl_init and before any other call - or
      * may leave them untouched */
     int (*waitpid_instead)(pid_t pid, int *status, int flags);
+    libxl_version_info version_info;
 };
 
+const libxl_version_info* libxl_get_version_info(struct libxl_ctx *ctx);
+
 typedef struct {
     bool hvm;
     bool hap;
+    bool oos;
     int ssidref;
     char *name;
     uint8_t uuid[16];
@@ -74,6 +93,7 @@
     int vpt_align;
     int max_vcpus;
     int cur_vcpus;
+    int tsc_mode;
     uint32_t max_memkb;
     uint32_t target_memkb;
     uint32_t video_memkb;
@@ -128,6 +148,7 @@
     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 */
+    char *vncpasswd; /* the VNC password */
     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 */
@@ -139,6 +160,9 @@
     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 */
+    int vcpus; /* max number of vcpus */
+    int vcpu_avail; /* vcpus actually available */
+    int xen_platform_pci; /* enable/disable the xen platform pci device */
     char **extra; /* extra parameters pass directly to qemu, NULL terminated */
     /* Network is missing */
 } libxl_device_model_info;
@@ -149,6 +173,7 @@
     int devid;
     bool vnc; /* vnc enabled or disabled */
     char *vnclisten; /* address:port that should be listened on for the VNC 
server if vnc is set */
+    char *vncpasswd; /* the VNC password */
     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 */
@@ -241,6 +266,7 @@
     ERROR_NI = -3,
     ERROR_NOMEM = -4,
     ERROR_INVAL = -5,
+    ERROR_BADFAIL = -6,
 };
 
 #define LIBXL_VERSION 0
@@ -249,6 +275,7 @@
 int libxl_ctx_init(struct libxl_ctx *ctx, int version);
 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);
+int libxl_ctx_postfork(struct libxl_ctx *ctx);
 
 /* domain related functions */
 int libxl_domain_make(struct libxl_ctx *ctx, libxl_domain_create_info *info, 
uint32_t *domid);
@@ -262,6 +289,9 @@
 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);
 
+char *libxl_uuid2string(struct libxl_ctx *ctx, uint8_t uuid[16]);
+  /* 0 means ERROR_ENOMEM, which we have logged */
+
 /* events handling */
 
 typedef enum {
@@ -296,15 +326,24 @@
 int libxl_event_get_domain_death_info(struct libxl_ctx *ctx, uint32_t domid, 
libxl_event *event, xc_domaininfo_t *info);
 int libxl_event_get_disk_eject_info(struct libxl_ctx *ctx, uint32_t domid, 
libxl_event *event, libxl_device_disk *disk);
 
+int libxl_domain_rename(struct libxl_ctx *ctx, uint32_t domid,
+                        const char *old_name, const char *new_name,
+                        xs_transaction_t trans);
+  /* if old_name is NULL, any old name is OK; otherwise we check
+   * transactionally that the domain has the old old name; if
+   * trans is not 0 we use caller's transaction and caller must do retries */
 
 int libxl_domain_pause(struct libxl_ctx *ctx, uint32_t domid);
 int libxl_domain_unpause(struct libxl_ctx *ctx, uint32_t domid);
 
-int libxl_set_memory_target(struct libxl_ctx *ctx, uint32_t domid, uint32_t 
target_memkb);
+int libxl_domain_setmaxmem(struct libxl_ctx *ctx, uint32_t domid, uint32_t 
target_memkb);
+int libxl_set_memory_target(struct libxl_ctx *ctx, uint32_t domid, uint32_t 
target_memkb, int enforce);
 
 int libxl_console_attach(struct libxl_ctx *ctx, uint32_t domid, int cons_num);
 
-struct libxl_dominfo * libxl_list_domain(struct libxl_ctx *ctx, int 
*nb_domain);
+int libxl_domain_info(struct libxl_ctx*, struct libxl_dominfo *info_r,
+                      uint32_t domid);
+struct libxl_dominfo * libxl_list_domain(struct libxl_ctx*, int *nb_domain);
 struct libxl_vminfo * libxl_list_vm(struct libxl_ctx *ctx, int *nb_vm);
 
 typedef struct libxl_device_model_starting libxl_device_model_starting;
@@ -325,13 +364,41 @@
                               libxl_device_model_starting *starting);
   /* DM is detached even if error is returned */
 
+typedef struct {
+    char *backend;
+    uint32_t backend_id;
+    char *frontend;
+    uint32_t frontend_id;
+    int devid;
+    int state;
+    int evtch;
+    int rref;
+} libxl_diskinfo;
+
 int libxl_device_disk_add(struct libxl_ctx *ctx, uint32_t domid, 
libxl_device_disk *disk);
 int libxl_device_disk_del(struct libxl_ctx *ctx, libxl_device_disk *disk, int 
wait);
 libxl_device_disk *libxl_device_disk_list(struct libxl_ctx *ctx, uint32_t 
domid, int *num);
+int libxl_device_disk_getinfo(struct libxl_ctx *ctx, uint32_t domid,
+                              libxl_device_disk *disk, libxl_diskinfo 
*diskinfo);
 int libxl_cdrom_insert(struct libxl_ctx *ctx, uint32_t domid, 
libxl_device_disk *disk);
 
+typedef struct {
+    char *backend;
+    uint32_t backend_id;
+    char *frontend;
+    uint32_t frontend_id;
+    int devid;
+    int state;
+    char *script;
+    uint8_t mac[6];
+    int evtch;
+    int rref_tx;
+    int rref_rx;
+} libxl_nicinfo;
+
 int libxl_device_nic_add(struct libxl_ctx *ctx, uint32_t domid, 
libxl_device_nic *nic);
 int libxl_device_nic_del(struct libxl_ctx *ctx, libxl_device_nic *nic, int 
wait);
+libxl_nicinfo *libxl_list_nics(struct libxl_ctx *ctx, uint32_t domid, unsigned 
int *nb);
 
 int libxl_device_console_add(struct libxl_ctx *ctx, uint32_t domid, 
libxl_device_console *console);
 
@@ -353,6 +420,37 @@
                           unsigned int bus, unsigned int dev,
                           unsigned int func, unsigned int vdevfn);
 
+/*
+ * Functions for allowing users of libxl to store private data
+ * relating to a domain.  The data is an opaque sequence of bytes and
+ * is not interpreted or used by libxl.
+ *
+ * Data is indexed by the userdata userid, which is a short printable
+ * ASCII string.  The following list is a registry of userdata userids
+ * (the registry may be updated by posting a patch to xen-devel):
+ *
+ *  userid      Data contents
+ *   "xl"        domain config file in xl format, Unix line endings
+ *
+ * libxl does not enforce the registration of userdata userids or the
+ * semantics of the data.  For specifications of the data formats
+ * see the code or documentation for the libxl caller in question.
+ */
+int libxl_userdata_store(struct libxl_ctx *ctx, uint32_t domid,
+                              const char *userdata_userid,
+                              const uint8_t *data, int datalen);
+  /* If datalen==0, data is not used and the user data for
+   * that domain and userdata_userid is deleted. */
+int libxl_userdata_retrieve(struct libxl_ctx *ctx, uint32_t domid,
+                                 const char *userdata_userid,
+                                 uint8_t **data_r, int *datalen_r);
+  /* On successful return, *data_r is from malloc.
+   * If there is no data for that domain and userdata_userid,
+   * *data_r and *datalen_r will be set to 0.
+   * data_r and datalen_r may be 0.
+   * On error return, *data_r and *datalen_r are undefined.
+   */
+
 typedef enum {
     POWER_BUTTON,
     SLEEP_BUTTON
@@ -360,5 +458,94 @@
 
 int libxl_button_press(struct libxl_ctx *ctx, uint32_t domid, libxl_button 
button);
 
+struct libxl_vcpuinfo {
+    uint32_t vcpuid; /* vcpu's id */
+    uint32_t cpu; /* current mapping */
+    uint8_t online:1; /* currently online (not hotplugged)? */
+    uint8_t blocked:1; /* blocked waiting for an event? */
+    uint8_t running:1; /* currently scheduled on its CPU? */
+    uint64_t vcpu_time; /* total vcpu time ran (ns) */
+    uint64_t *cpumap; /* current cpu's affinities */
+};
+
+struct libxl_physinfo {
+    uint32_t threads_per_core;
+    uint32_t cores_per_socket;
+
+    uint32_t max_cpu_id;
+    uint32_t nr_cpus;
+    uint32_t cpu_khz;
+
+    uint64_t total_pages;
+    uint64_t free_pages;
+    uint64_t scrub_pages;
+
+    uint32_t hw_cap[8];
+    uint32_t phys_cap;
+};
+
+int libxl_get_physinfo(struct libxl_ctx *ctx, struct libxl_physinfo *physinfo);
+struct libxl_vcpuinfo *libxl_list_vcpu(struct libxl_ctx *ctx, uint32_t domid,
+                                       int *nb_vcpu, int *cpusize);
+int libxl_set_vcpuaffinity(struct libxl_ctx *ctx, uint32_t domid, uint32_t 
vcpuid,
+                           uint64_t *cpumap, int cpusize);
+int libxl_set_vcpucount(struct libxl_ctx *ctx, uint32_t domid, uint32_t count);
+
+int libxl_get_sched_id(struct libxl_ctx *ctx);
+
+
+struct libxl_sched_credit {
+    int weight;
+    int cap;
+};
+
+int libxl_sched_credit_domain_get(struct libxl_ctx *ctx, uint32_t domid,
+                                  struct libxl_sched_credit *scinfo);
+int libxl_sched_credit_domain_set(struct libxl_ctx *ctx, uint32_t domid,
+                                  struct libxl_sched_credit *scinfo);
+int libxl_send_trigger(struct libxl_ctx *ctx, uint32_t domid,
+                       char *trigger_name, uint32_t vcpuid);
+int libxl_send_sysrq(struct libxl_ctx *ctx, uint32_t domid, char sysrq);
+int libxl_send_debug_keys(struct libxl_ctx *ctx, char *keys);
+
+struct libxl_xen_console_reader {
+    char *buffer;
+    unsigned int size;
+    unsigned int count;
+    unsigned int clear;
+    unsigned int incremental;
+    unsigned int index;
+};
+
+struct libxl_xen_console_reader *
+    libxl_xen_console_read_start(struct libxl_ctx *ctx, int clear);
+int libxl_xen_console_read_line(struct libxl_ctx *ctx,
+                                struct libxl_xen_console_reader *cr,
+                                char **line_r);
+void libxl_xen_console_read_finish(struct libxl_ctx *ctx,
+                                   struct libxl_xen_console_reader *cr);
+
+uint32_t libxl_vm_get_start_time(struct libxl_ctx *ctx, uint32_t domid);
+
+char *libxl_tmem_list(struct libxl_ctx *ctx, uint32_t domid, int use_long);
+int libxl_tmem_freeze(struct libxl_ctx *ctx, uint32_t domid);
+int libxl_tmem_destroy(struct libxl_ctx *ctx, uint32_t domid);
+int libxl_tmem_thaw(struct libxl_ctx *ctx, uint32_t domid);
+int libxl_tmem_set(struct libxl_ctx *ctx, uint32_t domid, char* name,
+                   uint32_t set);
+int libxl_tmem_shared_auth(struct libxl_ctx *ctx, uint32_t domid, char* uuid,
+                           int auth);
+
+/* libxl_paths.c */
+const char *libxl_sbindir_path(void);
+const char *libxl_bindir_path(void);
+const char *libxl_libexec_path(void);
+const char *libxl_libdir_path(void);
+const char *libxl_sharedir_path(void);
+const char *libxl_private_bindir_path(void);
+const char *libxl_xenfirmwaredir_path(void);
+const char *libxl_xen_config_dir_path(void);
+const char *libxl_xen_script_dir_path(void);
+
 #endif /* LIBXL_H */
 
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/libxl_device.c
--- a/tools/libxl/libxl_device.c        Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/libxl/libxl_device.c        Mon Jul 05 12:19:50 2010 +0100
@@ -22,6 +22,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #include "libxl.h"
 #include "libxl_internal.h"
@@ -301,7 +302,7 @@
     if (!l1) {
         XL_LOG(&clone, XL_LOG_ERROR, "%s is empty", path);
         libxl_ctx_free(&clone);
-        return -1;
+        return 0;
     }
     for (i = 0; i < num1; i++) {
         if (!strcmp("vfs", l1[i]))
@@ -388,22 +389,36 @@
     return 0;
 }
 
-int libxl_device_pci_flr(struct libxl_ctx *ctx, unsigned int domain, unsigned 
int bus,
+int libxl_device_pci_reset(struct libxl_ctx *ctx, unsigned int domain, 
unsigned int bus,
                          unsigned int dev, unsigned int func)
 {
-    char *do_flr = "/sys/bus/pci/drivers/pciback/do_flr";
-    FILE *fd;
+    char *reset = "/sys/bus/pci/drivers/pciback/do_flr";
+    int fd, rc;
 
-    fd = fopen(do_flr, "w");
-    if (fd != NULL) {
-        fprintf(fd, PCI_BDF, domain, bus, dev, func);
-        fclose(fd);
-        return 0;
+    fd = open(reset, O_WRONLY);
+    if (fd > 0) {
+        char *buf = libxl_sprintf(ctx, PCI_BDF, domain, bus, dev, func);
+        rc = write(fd, buf, strlen(buf));
+        if (rc < 0)
+            XL_LOG(ctx, XL_LOG_ERROR, "write to %s returned %d", reset, rc);
+        close(fd);
+        return rc < 0 ? rc : 0;
+    }
+    if (errno != ENOENT)
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Failed to access pciback path %s", 
reset);
+    reset = libxl_sprintf(ctx, "/sys/bus/pci/devices/"PCI_BDF"/reset", domain, 
bus, dev, func);
+    fd = open(reset, O_WRONLY);
+    if (fd > 0) {
+        rc = write(fd, "1", 1);
+        if (rc < 0)
+            XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "write to %s returned %d", reset, 
rc);
+        close(fd);
+        return rc < 0 ? rc : 0;
     }
     if (errno == ENOENT) {
-        XL_LOG(ctx, XL_LOG_ERROR, "Pciback doesn't support do_flr, cannot flr 
the device");
+        XL_LOG(ctx, XL_LOG_ERROR, "The kernel doesn't support PCI device reset 
from sysfs");
     } else {
-        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Failed to access pciback path %s", 
do_flr);
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Failed to access reset path %s", 
reset);
     }
     return -1;
 }
@@ -417,7 +432,7 @@
     char *path;
     char *p;
     unsigned int len;
-    int rc;
+    int rc = 0;
     struct xs_handle *xsh;
     int nfds;
     fd_set rfds;
@@ -431,28 +446,29 @@
     tv.tv_sec = LIBXL_DEVICE_MODEL_START_TIMEOUT;
     tv.tv_usec = 0;
     nfds = xs_fileno(xsh) + 1;
-    while (tv.tv_sec > 0) {
+    while (rc > 0 || (!rc && tv.tv_sec > 0)) {
+        p = xs_read(xsh, XBT_NULL, path, &len);
+        if (p && (!state || !strcmp(state, p))) {
+            free(p);
+            xs_unwatch(xsh, path, path);
+            xs_daemon_close(xsh);
+            if (check_callback) {
+                rc = check_callback(ctx, check_callback_userdata);
+                if (rc) return rc;
+            }
+            return 0;
+        }
+        free(p);
+again:
         FD_ZERO(&rfds);
         FD_SET(xs_fileno(xsh), &rfds);
-        if (select(nfds, &rfds, NULL, NULL, &tv) > 0) {
+        rc = select(nfds, &rfds, NULL, NULL, &tv);
+        if (rc > 0) {
             l = xs_read_watch(xsh, &num);
-            if (l != NULL) {
+            if (l != NULL)
                 free(l);
-                p = xs_read(xsh, XBT_NULL, path, &len);
-                if (!p)
-                    continue;
-                if (!state || !strcmp(state, p)) {
-                    free(p);
-                    xs_unwatch(xsh, path, path);
-                    xs_daemon_close(xsh);
-                    if (check_callback) {
-                        rc = check_callback(ctx, check_callback_userdata);
-                        if (rc) return rc;
-                    }
-                    return 0;
-                }
-                free(p);
-            }
+            else
+                goto again;
         }
     }
     xs_unwatch(xsh, path, path);
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/libxl_dom.c
--- a/tools/libxl/libxl_dom.c   Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/libxl/libxl_dom.c   Mon Jul 05 12:19:50 2010 +0100
@@ -16,6 +16,8 @@
 #include "libxl_osdeps.h"
 
 #include <stdio.h>
+#include <assert.h>
+#include <glob.h>
 #include <inttypes.h>
 #include <string.h>
 #include <sys/time.h> /* for struct timeval */
@@ -72,6 +74,7 @@
     xc_domain_set_memmap_limit(ctx->xch, domid, 
             (info->hvm) ? info->max_memkb : 
             (info->max_memkb + info->u.pv.slack_memkb));
+    xc_domain_set_tsc_info(ctx->xch, domid, info->tsc_mode, 0, 0, 0);
 
     if (info->hvm) {
         unsigned long shadow;
@@ -97,22 +100,22 @@
     xc_cpuid_apply_policy(ctx->xch, domid);
 #endif
 
-    ents = libxl_calloc(ctx, (10 + info->max_vcpus) * 2, sizeof(char *));
+    ents = libxl_calloc(ctx, 12 + (info->max_vcpus * 2) + 2, sizeof(char *));
     ents[0] = "memory/static-max";
     ents[1] = libxl_sprintf(ctx, "%d", info->max_memkb);
     ents[2] = "memory/target";
     ents[3] = libxl_sprintf(ctx, "%d", info->target_memkb);
-    ents[2] = "memory/videoram";
-    ents[3] = libxl_sprintf(ctx, "%d", info->video_memkb);
-    ents[4] = "domid";
-    ents[5] = libxl_sprintf(ctx, "%d", domid);
-    ents[6] = "store/port";
-    ents[7] = libxl_sprintf(ctx, "%"PRIu32, state->store_port);
-    ents[8] = "store/ring-ref";
-    ents[9] = libxl_sprintf(ctx, "%lu", state->store_mfn);
+    ents[4] = "memory/videoram";
+    ents[5] = libxl_sprintf(ctx, "%d", info->video_memkb);
+    ents[6] = "domid";
+    ents[7] = libxl_sprintf(ctx, "%d", domid);
+    ents[8] = "store/port";
+    ents[9] = libxl_sprintf(ctx, "%"PRIu32, state->store_port);
+    ents[10] = "store/ring-ref";
+    ents[11] = libxl_sprintf(ctx, "%lu", state->store_mfn);
     for (i = 0; i < info->max_vcpus; i++) {
-        ents[10+(i*2)]   = libxl_sprintf(ctx, "cpu/%d/availability", i);
-        ents[10+(i*2)+1] = (i && info->cur_vcpus && (i >= info->cur_vcpus))
+        ents[12+(i*2)]   = libxl_sprintf(ctx, "cpu/%d/availability", i);
+        ents[12+(i*2)+1] = (i && info->cur_vcpus && !(info->cur_vcpus & (1 << 
i)))
                             ? "offline" : "online";
     }
 
@@ -168,15 +171,19 @@
 {
     int ret;
 
-    ret = xc_hvm_build_target_mem(ctx->xch, domid, (info->max_memkb - 
info->video_memkb) / 1024, (info->target_memkb - info->video_memkb) / 1024, 
info->kernel);
+    ret = xc_hvm_build_target_mem(
+        ctx->xch,
+        domid,
+        (info->max_memkb - info->video_memkb) / 1024,
+        (info->target_memkb - info->video_memkb) / 1024,
+        libxl_abs_path(ctx, (char *)info->kernel,
+                       libxl_xenfirmwaredir_path()));
     if (ret) {
         XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, ret, "hvm building failed");
         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);
+    ret = hvm_build_set_params(ctx->xch, domid, info, state->store_port,
+                               &state->store_mfn);
     if (ret) {
         XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, ret, "hvm build set params failed");
         return ERROR_FAIL;
@@ -189,11 +196,10 @@
                    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;
+    return 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);
 }
 
 struct suspendinfo {
@@ -340,12 +346,154 @@
     libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, 
"/local/domain/0/device-model/%d/command", domid), "save", strlen("save"));
     libxl_wait_for_device_model(ctx, domid, "paused", NULL, NULL);
 
-    write(fd, QEMU_SIGNATURE, strlen(QEMU_SIGNATURE));
+    c = libxl_write_exactly(ctx, fd, QEMU_SIGNATURE, strlen(QEMU_SIGNATURE),
+                            "saved-state file", "qemu signature");
+    if (c)
+        return c;
     fd2 = open(filename, O_RDONLY);
     while ((c = read(fd2, buf, sizeof(buf))) != 0) {
-        write(fd, buf, c);
+        if (c < 0) {
+            if (errno == EINTR)
+                continue;
+            return errno;
+        }
+        c = libxl_write_exactly(
+            ctx, fd, buf, c, "saved-state file", "qemu state");
+        if (c)
+            return c;
     }
     close(fd2);
     unlink(filename);
     return 0;
 }
+
+char *libxl_uuid2string(struct libxl_ctx *ctx, uint8_t uuid[16]) {
+    char *s = string_of_uuid(ctx, uuid);
+    if (!s) XL_LOG(ctx, XL_LOG_ERROR, "cannot allocate for uuid");
+    return s;
+}
+
+static const char *userdata_path(struct libxl_ctx *ctx, uint32_t domid,
+                                      const char *userdata_userid,
+                                      const char *wh) {
+    char *path, *uuid_string;
+    struct libxl_dominfo info;
+    int rc;
+
+    rc = libxl_domain_info(ctx, &info, domid);
+    if (rc) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "unable to find domain info"
+                     " for domain %"PRIu32, domid);
+        return 0;
+    }
+    uuid_string = string_of_uuid(ctx, info.uuid);
+
+    path = libxl_sprintf(ctx, "/var/lib/xen/"
+                         "userdata-%s.%s.%s",
+                         wh, uuid_string, userdata_userid);
+    if (!path)
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "unable to allocate for"
+                     " userdata path");
+    return path;
+}
+
+static int userdata_delete(struct libxl_ctx *ctx, const char *path) {
+    int r;
+    r = unlink(path);
+    if (r) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "remove failed for %s", path);
+        return errno;
+    }
+    return 0;
+}
+
+void libxl__userdata_destroyall(struct libxl_ctx *ctx, uint32_t domid) {
+    const char *pattern;
+    glob_t gl;
+    int r, i;
+
+    pattern = userdata_path(ctx, domid, "*", "?");
+    if (!pattern) return;
+
+    gl.gl_pathc = 0;
+    gl.gl_pathv = 0;
+    gl.gl_offs = 0;
+    r = glob(pattern, GLOB_ERR|GLOB_NOSORT|GLOB_MARK, 0, &gl);
+    if (r == GLOB_NOMATCH) return;
+    if (r) XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "glob failed for %s", pattern);
+
+    for (i=0; i<gl.gl_pathc; i++) {
+        userdata_delete(ctx, gl.gl_pathv[i]);
+    }
+    globfree(&gl);
+}
+
+int libxl_userdata_store(struct libxl_ctx *ctx, uint32_t domid,
+                              const char *userdata_userid,
+                              const uint8_t *data, int datalen) {
+    const char *filename;
+    const char *newfilename;
+    int e;
+    int fd = -1;
+    FILE *f = 0;
+    size_t rs;
+
+    filename = userdata_path(ctx, domid, userdata_userid, "d");
+    if (!filename) return ENOMEM;
+
+    if (!datalen)
+        return userdata_delete(ctx, filename);
+
+    newfilename = userdata_path(ctx, domid, userdata_userid, "n");
+    if (!newfilename) return ENOMEM;
+
+    fd= open(newfilename, O_RDWR|O_CREAT|O_TRUNC, 0600);
+    if (fd<0) goto xe;
+
+    f= fdopen(fd, "wb");
+    if (!f) goto xe;
+    fd = -1;
+
+    rs = fwrite(data, 1, datalen, f);
+    if (rs != datalen) { assert(ferror(f)); goto xe; }
+
+    if (fclose(f)) goto xe;
+    f = 0;
+
+    if (rename(newfilename,filename)) goto xe;
+
+    return 0;
+
+ xe:
+    e = errno;
+    if (f) fclose(f);
+    if (fd>=0) close(fd);
+
+    XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "cannot write %s for %s",
+                 newfilename, filename);
+    return e;
+}
+
+int libxl_userdata_retrieve(struct libxl_ctx *ctx, uint32_t domid,
+                                 const char *userdata_userid,
+                                 uint8_t **data_r, int *datalen_r) {
+    const char *filename;
+    int e;
+    int datalen = 0;
+    void *data = 0;
+
+    filename = userdata_path(ctx, domid, userdata_userid, "d");
+    if (!filename) return ENOMEM;
+
+    e = libxl_read_file_contents(ctx, filename, data_r ? &data : 0, &datalen);
+
+    if (!e && !datalen) {
+        XL_LOG(ctx, XL_LOG_ERROR, "userdata file %s is empty", filename);
+        if (data_r) assert(!*data_r);
+        return EPROTO;
+    }
+
+    if (data_r) *data_r = data;
+    if (datalen_r) *datalen_r = datalen;
+    return 0;
+}
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/libxl_exec.c
--- a/tools/libxl/libxl_exec.c  Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/libxl/libxl_exec.c  Mon Jul 05 12:19:50 2010 +0100
@@ -30,19 +30,6 @@
 #include "libxl.h"
 #include "libxl_internal.h"
 
-static pid_t libxl_fork(struct libxl_ctx *ctx)
-{
-    pid_t pid;
-
-    pid = fork();
-    if (pid == -1) {
-        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "fork failed");
-        return -1;
-    }
-
-    return pid;
-}
-
 static int call_waitpid(pid_t (*waitpid_cb)(pid_t, int *, int), pid_t pid, int 
*status, int options)
 {
     return (waitpid_cb) ? waitpid_cb(pid, status, options) : waitpid(pid, 
status, options);
@@ -61,38 +48,41 @@
         dup2(stderrfd, STDERR_FILENO);
     for (i = 4; i < 256; i++)
         close(i);
+
+    signal(SIGPIPE, SIG_DFL);
+    /* in case our caller set it to IGN.  subprocesses are entitled
+     * to assume they got DFL. */
+
     execv(arg0, args);
     _exit(-1);
 }
 
-void libxl_report_child_exitstatus(struct libxl_ctx *ctx,
+void libxl_report_child_exitstatus(struct libxl_ctx *ctx, int level,
                                    const char *what, pid_t pid, int status)
 {
-    /* treats all exit statuses as errors; if that's not what you want,
-     * check status yourself first */
 
     if (WIFEXITED(status)) {
         int st = WEXITSTATUS(status);
         if (st)
-            XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] exited"
+            XL_LOG(ctx, level, "%s [%ld] exited"
                    " with error status %d", what, (unsigned long)pid, st);
         else
-            XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] unexpectedly"
+            XL_LOG(ctx, level, "%s [%ld] unexpectedly"
                    " exited status zero", what, (unsigned long)pid);
     } else if (WIFSIGNALED(status)) {
         int sig = WTERMSIG(status);
         const char *str = strsignal(sig);
         const char *coredump = WCOREDUMP(status) ? " (core dumped)" : "";
         if (str)
-            XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] died due to"
+            XL_LOG(ctx, level, "%s [%ld] died due to"
                    " fatal signal %s%s", what, (unsigned long)pid,
                    str, coredump);
         else
-            XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] died due to unknown"
+            XL_LOG(ctx, level, "%s [%ld] died due to unknown"
                    " fatal signal number %d%s", what, (unsigned long)pid,
                    sig, coredump);
     } else {
-        XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] gave unknown"
+        XL_LOG(ctx, level, "%s [%ld] gave unknown"
                " wait status 0x%x", what, (unsigned long)pid, status);
     }
 }
@@ -153,7 +143,7 @@
         char *intermediate_what = libxl_sprintf(ctx,
                           "%s intermediate process (startup monitor)",
                           for_spawn->what);
-        libxl_report_child_exitstatus(ctx, intermediate_what,
+        libxl_report_child_exitstatus(ctx, XL_LOG_ERROR, intermediate_what,
                                       for_spawn->intermediate, status);
     }
 }
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/libxl_internal.c
--- a/tools/libxl/libxl_internal.c      Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/libxl/libxl_internal.c      Mon Jul 05 12:19:50 2010 +0100
@@ -156,11 +156,13 @@
 {
     char *enomem = "[out of memory formatting log message]";
     char *s;
-    int rc;
+    int rc, esave;
 
     if (!ctx->log_callback)
         return;
 
+    esave = errno;
+    
     rc = vasprintf(&s, fmt, ap);
     if (rc<0) { s = enomem; goto x; }
 
@@ -180,6 +182,7 @@
     ctx->log_callback(ctx->log_userdata, loglevel, file, line, func, s);
     if (s != enomem)
         free(s);
+    errno = esave;
 }
 
 void xl_log(struct libxl_ctx *ctx, int loglevel, int errnoval,
@@ -191,3 +194,11 @@
     xl_logv(ctx, loglevel, errnoval, file, line, func, fmt, ap);
     va_end(ap);
 }
+
+char *libxl_abs_path(struct libxl_ctx *ctx, char *s, const char *path)
+{
+    if (!s || s[0] == '/')
+        return s;
+    return libxl_sprintf(ctx, "%s/%s", path, s);
+}
+
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/libxl_internal.h
--- a/tools/libxl/libxl_internal.h      Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/libxl/libxl_internal.h      Mon Jul 05 12:19:50 2010 +0100
@@ -41,21 +41,18 @@
 #ifdef XL_LOGGING_ENABLED
 #define XL_LOG(ctx, loglevel, _f, _a...)   xl_log(ctx, loglevel, -1, __FILE__, 
__LINE__, __func__, _f, ##_a)
 #define XL_LOG_ERRNO(ctx, loglevel, _f, _a...)   xl_log(ctx, loglevel, errno, 
__FILE__, __LINE__, __func__, _f, ##_a)
-#define XL_LOG_ERRNOVAL(ctx, errnoval, loglevel, _f, _a...)   xl_log(ctx, 
loglevel, errnoval, __FILE__, __LINE__, __func__, _f, ##_a)
+#define XL_LOG_ERRNOVAL(ctx, loglevel, errnoval, _f, _a...)   xl_log(ctx, 
loglevel, errnoval, __FILE__, __LINE__, __func__, _f, ##_a)
 #else
 #define XL_LOG(ctx, loglevel, _f, _a...)
 #define XL_LOG_ERRNO(ctx, loglevel, _f, _a...)
 #define XL_LOG_ERRNOVAL(ctx, loglevel, errnoval, _f, _a...)
 #endif
-
-#define XL_LOG_DEBUG 3
-#define XL_LOG_INFO 2
-#define XL_LOG_WARNING 1
-#define XL_LOG_ERROR 0
+  /* all of these macros preserve errno (saving and restoring) */
 
 /* logging */
 void xl_logv(struct libxl_ctx *ctx, int errnoval, int loglevel, const char 
*file, int line, const char *func, char *fmt, va_list al);
 void xl_log(struct libxl_ctx *ctx, int errnoval, int loglevel, const char 
*file, int line, const char *func, char *fmt, ...);
+  /* these functions preserve errno (saving and restoring) */
 

 typedef enum {
@@ -133,6 +130,7 @@
                    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);
 int save_device_model(struct libxl_ctx *ctx, uint32_t domid, int fd);
+void libxl__userdata_destroyall(struct libxl_ctx *ctx, uint32_t domid);
 
 /* from xl_device */
 char *device_disk_backend_type_of_phystype(libxl_disk_phystype phystype);
@@ -152,13 +150,13 @@
                                                       void *userdata),
                                 void *check_callback_userdata);
 int libxl_wait_for_backend(struct libxl_ctx *ctx, char *be_path, char *state);
-int libxl_device_pci_flr(struct libxl_ctx *ctx, unsigned int domain, unsigned 
int bus,
-                         unsigned int dev, unsigned int func);
+int libxl_device_pci_reset(struct libxl_ctx *ctx, unsigned int domain, 
unsigned int bus,
+                           unsigned int dev, unsigned int func);
 
 /* 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);
+                         libxl_domain_build_info *info,
+                         int store_evtchn, unsigned long *store_mfn);
 
 /* xl_exec */
 
@@ -183,8 +181,8 @@
                       void (*intermediate_hook)(void *for_spawn, pid_t 
innerchild));
   /* Logs errors.  A copy of "what" is taken.  Return values:
    *  < 0   error, for_spawn need not be detached
-   *   +1   caller is now the inner child, should probably call libxl_exec
-   *    0   caller is the parent, must call detach on *for_spawn eventually
+   *   +1   caller is the parent, must call detach on *for_spawn eventually
+   *    0   caller is now the inner child, should probably call libxl_exec
    * Caller, may pass 0 for for_spawn, in which case no need to detach.
    */
 int libxl_spawn_detach(struct libxl_ctx *ctx,
@@ -204,5 +202,7 @@
 void libxl_log_child_exitstatus(struct libxl_ctx *ctx,
                                 const char *what, pid_t pid, int status);
 
+char *libxl_abs_path(struct libxl_ctx *ctx, char *s, const char *path);
+
 #endif
 
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/libxl_paths.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxl/libxl_paths.c Mon Jul 05 12:19:50 2010 +0100
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010      Citrix Ltd.
+ *
+ * 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_paths.h"
+
+const char *libxl_sbindir_path(void)
+{
+    return SBINDIR;
+}
+
+const char *libxl_bindir_path(void)
+{
+    return BINDIR;
+}
+
+const char *libxl_libexec_path(void)
+{
+    return LIBEXEC;
+}
+
+const char *libxl_libdir_path(void)
+{
+    return LIBDIR;
+}
+
+const char *libxl_sharedir_path(void)
+{
+    return SHAREDIR;
+}
+
+const char *libxl_private_bindir_path(void)
+{
+    return PRIVATE_BINDIR;
+}
+
+const char *libxl_xenfirmwaredir_path(void)
+{
+    return XENFIRMWAREDIR;
+}
+
+const char *libxl_xen_config_dir_path(void)
+{
+    return XEN_CONFIG_DIR;
+}
+
+const char *libxl_xen_script_dir_path(void)
+{
+    return XEN_SCRIPT_DIR;
+}
+
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/libxl_utils.c
--- a/tools/libxl/libxl_utils.c Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/libxl/libxl_utils.c Mon Jul 05 12:19:50 2010 +0100
@@ -26,6 +26,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <assert.h>
 
 #include "libxl_utils.h"
 #include "libxl_internal.h"
@@ -54,7 +55,8 @@
     return s;
 }
 
-int libxl_name_to_domid(struct libxl_ctx *ctx, char *name, uint32_t *domid)
+int libxl_name_to_domid(struct libxl_ctx *ctx, const char *name,
+                        uint32_t *domid)
 {
     int i, nb_domains;
     char *domname;
@@ -76,6 +78,20 @@
     return -1;
 }
 
+char *libxl_poolid_to_name(struct libxl_ctx *ctx, uint32_t poolid)
+{
+    unsigned int len;
+    char path[strlen("/local/pool") + 12];
+    char *s;
+
+    if (poolid == 0)
+        return "Pool-0";
+    snprintf(path, sizeof(path), "/local/pool/%d/name", poolid);
+    s = xs_read(ctx->xsh, XBT_NULL, path, &len);
+    libxl_ptr_add(ctx, s);
+    return s;
+}
+
 int libxl_get_stubdom_id(struct libxl_ctx *ctx, int guest_domid)
 {
     char * stubdom_id_s = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/image/device-model-domid", libxl_xs_get_dompath(ctx, guest_domid)));
@@ -101,11 +117,25 @@
     return 1;
 }
 
+static int logrename(struct libxl_ctx *ctx, const char *old, const char *new) {
+    int r;
+
+    r = rename(old, new);
+    if (r) {
+        if (errno == ENOENT) return 0; /* ok */
+
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to rotate logfile - could not"
+                     " rename %s to %s", old, new);
+        return ERROR_FAIL;
+    }
+    return 0;
+}
+
 int libxl_create_logfile(struct libxl_ctx *ctx, char *name, char **full_name)
 {
     struct stat stat_buf;
     char *logfile, *logfile_new;
-    int i;
+    int i, rc;
 
     logfile = libxl_sprintf(ctx, "/var/log/xen/%s.log", name);
     if (stat(logfile, &stat_buf) == 0) {
@@ -115,11 +145,19 @@
         for (i = 9; i > 0; i--) {
             logfile = libxl_sprintf(ctx, "/var/log/xen/%s.log.%d", name, i);
             logfile_new = libxl_sprintf(ctx, "/var/log/xen/%s.log.%d", name, i 
+ 1);
-            rename(logfile, logfile_new);
+            rc = logrename(ctx, logfile, logfile_new);
+            if (rc) return rc;
         }
         logfile = libxl_sprintf(ctx, "/var/log/xen/%s.log", name);
         logfile_new = libxl_sprintf(ctx, "/var/log/xen/%s.log.1", name);
-        rename(logfile, logfile_new);
+
+        rc = logrename(ctx, logfile, logfile_new);
+        if (rc) return rc;
+    } else {
+        if (errno != ENOENT)
+            XL_LOG_ERRNO(ctx, XL_LOG_WARNING, "problem checking existence of"
+                         " logfile %s, which might have needed to be rotated",
+                         name);
     }
     *full_name = strdup(logfile);
     return 0;
@@ -155,3 +193,254 @@
     return rc;
 }
 
+int libxl_read_file_contents(struct libxl_ctx *ctx, const char *filename,
+                             void **data_r, int *datalen_r) {
+    FILE *f = 0;
+    uint8_t *data = 0;
+    int datalen = 0;
+    int e;
+    struct stat stab;
+    ssize_t rs;
+    
+    f = fopen(filename, "r");
+    if (!f) {
+        if (errno == ENOENT) return ENOENT;
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to open %s", filename);
+        goto xe;
+    }
+
+    if (fstat(fileno(f), &stab)) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to fstat %s", filename);
+        goto xe;
+    }
+
+    if (!S_ISREG(stab.st_mode)) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "%s is not a plain file", filename);
+        errno = ENOTTY;
+        goto xe;
+    }
+
+    if (stab.st_size > INT_MAX) {
+        XL_LOG(ctx, XL_LOG_ERROR, "file %s is far too large", filename);
+        errno = EFBIG;
+        goto xe;
+    }
+
+    datalen = stab.st_size;
+
+    if (stab.st_size && data_r) {
+        data = malloc(datalen);
+        if (!data) goto xe;
+
+        rs = fread(data, 1, datalen, f);
+        if (rs != datalen) {
+            if (ferror(f))
+                XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to read %s", filename);
+            else if (feof(f))
+                XL_LOG(ctx, XL_LOG_ERROR, "%s changed size while we"
+                       " were reading it", filename);
+            else
+                abort();
+            goto xe;
+        }
+    }
+
+    if (fclose(f)) {
+        f = 0;
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to close %s", filename);
+        goto xe;
+    }
+
+    if (data_r) *data_r = data;
+    if (datalen_r) *datalen_r = datalen;
+
+    return 0;
+
+ xe:
+    e = errno;
+    assert(e != ENOENT);
+    if (f) fclose(f);
+    if (data) free(data);
+    return e;
+}
+
+#define READ_WRITE_EXACTLY(rw, zero_is_eof, constdata)                    \
+                                                                          \
+  int libxl_##rw##_exactly(struct libxl_ctx *ctx, int fd,                 \
+                           constdata void *data, ssize_t sz,              \
+                           const char *filename, const char *what) {      \
+      ssize_t got;                                                        \
+                                                                          \
+      while (sz > 0) {                                                    \
+          got = rw(fd, data, sz);                                         \
+          if (got == -1) {                                                \
+              if (errno == EINTR) continue;                               \
+              if (!ctx) return errno;                                     \
+              XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to " #rw " %s%s%s", \
+                           what?what:"", what?" from ":"", filename);     \
+              return errno;                                               \
+          }                                                               \
+          if (got == 0) {                                                 \
+              if (!ctx) return EPROTO;                                    \
+              XL_LOG(ctx, XL_LOG_ERROR,                                   \
+                     zero_is_eof                                          \
+                     ? "file/stream truncated reading %s%s%s"             \
+                     : "file/stream write returned 0! writing %s%s%s",    \
+                     what?what:"", what?" from ":"", filename);           \
+              return EPROTO;                                              \
+          }                                                               \
+          sz -= got;                                                      \
+          data = (char*)data + got;                                       \
+      }                                                                   \
+      return 0;                                                           \
+  }
+
+READ_WRITE_EXACTLY(read, 1, /* */)
+READ_WRITE_EXACTLY(write, 0, const)
+
+
+int libxl_ctx_postfork(struct libxl_ctx *ctx) {
+    if (ctx->xsh) xs_daemon_destroy_postfork(ctx->xsh);
+    ctx->xsh = xs_daemon_open();
+    if (!ctx->xsh) return ERROR_FAIL;
+    return 0;
+}
+
+pid_t libxl_fork(struct libxl_ctx *ctx)
+{
+    pid_t pid;
+
+    pid = fork();
+    if (pid == -1) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "fork failed");
+        return -1;
+    }
+
+    if (!pid) {
+        if (ctx->xsh) xs_daemon_destroy_postfork(ctx->xsh);
+        ctx->xsh = 0;
+        /* This ensures that anyone who forks but doesn't exec,
+         * and doesn't reinitialise the libxl_ctx, is OK.
+         * It also means they can safely call libxl_ctx_free. */
+    }
+
+    return pid;
+}
+
+int libxl_pipe(struct libxl_ctx *ctx, int pipes[2])
+{
+    if (pipe(pipes) < 0) {
+        XL_LOG(ctx, XL_LOG_ERROR, "Failed to create a pipe");
+        return -1;
+    }
+    return 0;
+}
+
+int libxl_mac_to_device_nic(struct libxl_ctx *ctx, uint32_t domid,
+                            const char *mac, libxl_device_nic *nic)
+{
+    libxl_nicinfo *nics;
+    unsigned int nb, i;
+    uint8_t mac_n[6];
+    uint8_t *a, *b;
+    const char *tok;
+    char *endptr;
+
+    nics = libxl_list_nics(ctx, domid, &nb);
+    if (!nics) {
+        return ERROR_FAIL;
+    }
+
+    for (i = 0, tok = mac; *tok && (i < 6); ++i, tok += 3) {
+        mac_n[i] = strtol(tok, &endptr, 16);
+        if (endptr != (tok + 2)) {
+            return ERROR_INVAL;
+        }
+    }
+    memset(nic, 0, sizeof (libxl_device_nic));
+    for (; nb; --nb, ++nics) {
+        for (i = 0, a = nics->mac, b = mac_n;
+             (b < mac_n + 6) && (*a == *b); ++a, ++b)
+            ;
+        if ((b >= mac_n + 6) && (*a == *b)) {
+            nic->backend_domid = nics->backend_id;
+            nic->domid = nics->frontend_id;
+            nic->devid = nics->devid;
+            memcpy(nic->mac, nics->mac, sizeof (nic->mac));
+            nic->script = nics->script;
+            libxl_free(ctx, nics);
+            return 0;
+        }
+    }
+
+    libxl_free(ctx, nics);
+    return 0;
+}
+
+int libxl_devid_to_device_nic(struct libxl_ctx *ctx, uint32_t domid,
+                              const char *devid, libxl_device_nic *nic)
+{
+    char *tok, *val;
+    char *dompath, *nic_path_fe, *nic_path_be;
+    unsigned int i;
+
+    memset(nic, 0, sizeof (libxl_device_nic));
+    dompath = libxl_xs_get_dompath(ctx, domid);
+    if (!dompath) {
+        return ERROR_FAIL;
+    }
+    nic_path_fe = libxl_sprintf(ctx, "%s/device/vif/%s", dompath, devid);
+    nic_path_be = libxl_xs_read(ctx, XBT_NULL,
+                                libxl_sprintf(ctx, "%s/backend", nic_path_fe));
+    val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend-id", 
nic_path_fe));
+    nic->backend_domid = strtoul(val, NULL, 10);
+    nic->devid = strtoul(devid, NULL, 10);
+    libxl_free(ctx, val);
+
+    val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/mac", 
nic_path_fe));
+    for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
+         ++i, tok = strtok(NULL, ":")) {
+        nic->mac[i] = strtoul(tok, NULL, 16);
+    }
+    libxl_free(ctx, val);
+    nic->script = libxl_xs_read(ctx, XBT_NULL,
+                                libxl_sprintf(ctx, "%s/script", nic_path_be));
+    libxl_free(ctx, nic_path_fe);
+    libxl_free(ctx, nic_path_be);
+    return 0;
+}
+
+int libxl_devid_to_device_disk(struct libxl_ctx *ctx, uint32_t domid,
+                               const char *devid, libxl_device_disk *disk)
+{
+    char *endptr, *val;
+    char *dompath, *diskpath, *be_path;
+    unsigned int devid_n;
+
+    devid_n = strtoul(devid, &endptr, 10);
+    if (devid == endptr) {
+        return ERROR_INVAL;
+    }
+    dompath = libxl_xs_get_dompath(ctx, domid);
+    diskpath = libxl_sprintf(ctx, "%s/device/vbd/%s", dompath, devid);
+    if (!diskpath) {
+        return ERROR_FAIL;
+    }
+
+    val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend-id", 
diskpath));
+    disk->backend_domid = strtoul(val, NULL, 10);
+    disk->domid = domid;
+    be_path = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend", 
diskpath));
+    disk->physpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, 
"%s/params", be_path));
+    val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/type", be_path));
+    libxl_string_to_phystype(ctx, val, &(disk->phystype));
+    disk->virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev", 
be_path));
+    val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/removable", 
be_path));
+    disk->unpluggable = !strcmp(val, "1");
+    val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/mode", be_path));
+    disk->readwrite = !!strcmp(val, "w");
+    val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/device-type", 
diskpath));
+    disk->is_cdrom = !strcmp(val, "cdrom");
+
+    return 0;
+}
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/libxl_utils.h
--- a/tools/libxl/libxl_utils.h Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/libxl/libxl_utils.h Mon Jul 05 12:19:50 2010 +0100
@@ -19,12 +19,55 @@
 #include "libxl.h"
 
 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);
+int libxl_name_to_domid(struct libxl_ctx *ctx, const char *name, uint32_t 
*domid);
 char *libxl_domid_to_name(struct libxl_ctx *ctx, uint32_t domid);
+int libxl_name_to_poolid(struct libxl_ctx *ctx, const char *name, uint32_t 
*poolid);
+char *libxl_poolid_to_name(struct libxl_ctx *ctx, uint32_t poolid);
 int libxl_get_stubdom_id(struct libxl_ctx *ctx, int guest_domid);
 int libxl_is_stubdom(struct libxl_ctx *ctx, uint32_t domid, uint32_t 
*target_domid);
 int libxl_create_logfile(struct libxl_ctx *ctx, char *name, char **full_name);
 int libxl_string_to_phystype(struct libxl_ctx *ctx, char *s, 
libxl_disk_phystype *phystype);
 
+int libxl_read_file_contents(struct libxl_ctx *ctx, const char *filename,
+                             void **data_r, int *datalen_r);
+  /* Reads the contents of the plain file filename into a mallocd
+   * buffer.  Returns 0 or errno.  Any errors other than ENOENT are logged.
+   * If the file is empty, *data_r and *datalen_r are set to 0.
+   * On error, *data_r and *datalen_r are undefined.
+   * data_r and/or datalen_r may be 0.
+   */
+
+int libxl_read_exactly(struct libxl_ctx *ctx, int fd, void *data, ssize_t sz,
+                       const char *filename, const char *what);
+int libxl_write_exactly(struct libxl_ctx *ctx, int fd, const void *data,
+                        ssize_t sz, const char *filename, const char *what);
+  /* Returns 0 or errno.  If file is truncated on reading, returns
+   * EPROTO and you have no way to tell how much was read.  Errors are
+   * logged using filename (which is only used for logging) and what
+   * (which may be 0). */
+    
+pid_t libxl_fork(struct libxl_ctx *ctx);
+int libxl_pipe(struct libxl_ctx *ctx, int pipes[2]);
+  /* Just like fork(2), pipe(2), but log errors. */
+
+void libxl_report_child_exitstatus(struct libxl_ctx *ctx, int level,
+                                   const char *what, pid_t pid, int status);
+    /* treats all exit statuses as errors; if that's not what you want,
+     * check status yourself first */
+
+int libxl_mac_to_device_nic(struct libxl_ctx *ctx, uint32_t domid,
+                            const char *mac, libxl_device_nic *nic);
+int libxl_devid_to_device_nic(struct libxl_ctx *ctx, uint32_t domid,
+                              const char *devid, libxl_device_nic *nic);
+
+int libxl_devid_to_device_disk(struct libxl_ctx *ctx, uint32_t domid,
+                               const char *devid, libxl_device_disk *disk);
+
+/* log levels: */
+#define XL_LOG_DEBUG 3
+#define XL_LOG_INFO 2
+#define XL_LOG_WARNING 1
+#define XL_LOG_ERROR 0
+
 #endif
 
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/libxl_xshelp.c
--- a/tools/libxl/libxl_xshelp.c        Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/libxl/libxl_xshelp.c        Mon Jul 05 12:19:50 2010 +0100
@@ -19,6 +19,7 @@
 #include <stddef.h>
 #include <stdio.h>
 #include <stdarg.h>
+#include <inttypes.h>
 
 #include "libxl.h"
 #include "libxl_internal.h"
@@ -32,7 +33,8 @@
         return 0;
 
     for (i = 0; kvs[i] != NULL; i += 2) {
-        asprintf(&path, "%s/%s", dir, kvs[i]);
+        if (asprintf(&path, "%s/%s", dir, kvs[i]) < 0)
+            return -1;
         if (path && kvs[i + 1]) {
             int length = strlen(kvs[i + 1]);
             xs_write(xsh, t, path, kvs[i + 1], length);
@@ -118,7 +120,7 @@
 {
     char *s = xs_get_domain_path(ctx->xsh, domid);
     if (!s) {
-        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to get dompath for %lu",
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to get dompath for %" PRIu32,
                      domid);
         return NULL;
     }
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/libxlu_cfg.c
--- a/tools/libxl/libxlu_cfg.c  Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/libxl/libxlu_cfg.c  Mon Jul 05 12:19:50 2010 +0100
@@ -53,6 +53,43 @@
     return ctx.err;
 }
 
+int xlu_cfg_readdata(XLU_Config *cfg, const char *data, int length) {
+    CfgParseContext ctx;
+    int e, r;
+    YY_BUFFER_STATE buf= 0;
+
+    ctx.scanner= 0;
+    ctx.cfg= cfg;
+    ctx.err= 0;
+    ctx.lexerrlineno= -1;
+
+    e= xlu__cfg_yylex_init_extra(&ctx, &ctx.scanner);
+    if (e) {
+        fprintf(cfg->report,"%s: unable to create scanner: %s\n",
+                cfg->filename, strerror(e));
+        ctx.err= e;
+        ctx.scanner= 0;
+        goto xe;
+    }
+
+    buf = xlu__cfg_yy_scan_bytes(data, length, ctx.scanner);
+    if (!buf) {
+        fprintf(cfg->report,"%s: unable to allocate scanner buffer\n",
+                cfg->filename);
+        ctx.err= ENOMEM;
+        goto xe;
+    }
+
+    r= xlu__cfg_yyparse(&ctx);
+    if (r) assert(ctx.err);
+
+ xe:
+    if (buf) xlu__cfg_yy_delete_buffer(buf, ctx.scanner);
+    if (ctx.scanner) xlu__cfg_yylex_destroy(ctx.scanner);
+
+    return ctx.err;
+}
+
 void xlu__cfg_set_free(XLU_ConfigSetting *set) {
     free(set->name);
     free(set->values);
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/libxlutil.h
--- a/tools/libxl/libxlutil.h   Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/libxl/libxlutil.h   Mon Jul 05 12:19:50 2010 +0100
@@ -30,7 +30,8 @@
    *  until the Config is destroyed. */
 
 int xlu_cfg_readfile(XLU_Config*, const char *real_filename);
-  /* If this fails, then it is undefined behaviour to call xlu_cfg_get_...
+int xlu_cfg_readdata(XLU_Config*, const char *data, int length);
+  /* If these fail, then it is undefined behaviour to call xlu_cfg_get_...
    * functions.  You have to just xlu_cfg_destroy. */
  
 void xlu_cfg_destroy(XLU_Config*);
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/xenguest.c
--- a/tools/libxl/xenguest.c    Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/libxl/xenguest.c    Mon Jul 05 12:19:50 2010 +0100
@@ -17,10 +17,13 @@
 #include <xenguest.h>
 #include <sys/mman.h>
 #include <xen/hvm/hvm_info_table.h>
+#include <string.h>
+
+#include "libxl.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)
+                         libxl_domain_build_info *info,
+                         int store_evtchn, unsigned long *store_mfn)
 {
     struct hvm_info_table *va_hvm;
     uint8_t *va_map, sum;
@@ -33,18 +36,19 @@
         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;
+    va_hvm->acpi_enabled = info->u.hvm.acpi;
+    va_hvm->apic_mode = info->u.hvm.apic;
+    va_hvm->nr_vcpus = info->max_vcpus;
+    memcpy(va_hvm->vcpu_online, &info->cur_vcpus, sizeof(info->cur_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_PAE_ENABLED, info->u.hvm.pae);
 #if defined(__i386__) || defined(__x86_64__)
-    xc_set_hvm_param(handle, domid, HVM_PARAM_VIRIDIAN, viridian);
+    xc_set_hvm_param(handle, domid, HVM_PARAM_VIRIDIAN, info->u.hvm.viridian);
 #endif
     xc_set_hvm_param(handle, domid, HVM_PARAM_STORE_EVTCHN, store_evtchn);
     return 0;
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/xl.c
--- a/tools/libxl/xl.c  Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/libxl/xl.c  Mon Jul 05 12:19:50 2010 +0100
@@ -21,1756 +21,58 @@
 #include <string.h>
 #include <unistd.h>
 #include <sys/time.h> /* for time */
-#include <getopt.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <arpa/inet.h>
-#include <xenctrl.h>
 #include <ctype.h>
+#include <inttypes.h>
 
 #include "libxl.h"
 #include "libxl_utils.h"
-#include "libxlutil.h"
+#include "xl.h"
 
-#define UUID_FMT 
"%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
+extern struct libxl_ctx ctx;
+extern int logfile;
 
-int logfile = 2;
-
-void log_callback(void *userdata, int loglevel, const char *file, int line, 
const char *func, char *s)
+void log_callback(
+    void *userdata, int loglevel, const char *file,
+    int line, const char *func, char *s)
 {
     char str[1024];
 
-    snprintf(str, sizeof(str), "[%d] %s:%d:%s: %s\n", loglevel, file, line, 
func, s);
-    write(logfile, str, strlen(str));
-}
-
-static int domain_qualifier_to_domid(struct libxl_ctx *ctx, char *p, uint32_t 
*domid)
-{
-    int i, alldigit;
-
-    alldigit = 1;
-    for (i = 0; p[i]; i++) {
-        if (!isdigit((uint8_t)p[i])) {
-            alldigit = 0;
-            break;
-        }
-    }
-
-    if (i > 0 && alldigit) {
-        *domid = strtoul(p, NULL, 10);
-        return 0;
-    } else {
-        /* check here if it's a uuid and do proper conversion */
-    }
-    return libxl_name_to_domid(ctx, p, domid);
-}
-
-#define LOG(_f, _a...)   dolog(__FILE__, __LINE__, __func__, _f "\n", ##_a)
-
-void dolog(const char *file, int line, const char *func, char *fmt, ...)
-{
-    va_list ap;
-    char *s;
-    int rc;
-
-    va_start(ap, fmt);
-    rc = vasprintf(&s, fmt, ap);
-    va_end(ap);
-    if (rc >= 0)
-        write(logfile, s, rc);
-}
-
-static 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;
-}
-
-static 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->target_memkb = b_info->max_memkb;
-    if (c_info->hvm) {
-        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";
-        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;
-    } else {
-        b_info->u.pv.slack_memkb = 8 * 1024;
-    }
-}
-
-static void init_dm_info(libxl_device_model_info *dm_info,
-        libxl_domain_create_info *c_info, libxl_domain_build_info *b_info)
-{
-    int i;
-    memset(dm_info, '\0', sizeof(*dm_info));
-
-    for (i = 0; i < 16; i++) {
-        dm_info->uuid[i] = rand();
-    }
-
-    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;
-}
-
-static 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";
-    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)));
-    nic_info->ifname = NULL;
-    nic_info->bridge = "xenbr0";
-    nic_info->script = "/etc/xen/scripts/vif-bridge";
-    nic_info->nictype = NICTYPE_IOEMU;
-}
-
-static void init_vfb_info(libxl_device_vfb *vfb, int dev_num)
-{
-    memset(vfb, 0x00, sizeof(libxl_device_vfb));
-    vfb->devid = dev_num;
-    vfb->vnc = 1;
-    vfb->vnclisten = "127.0.0.1";
-    vfb->vncdisplay = 0;
-    vfb->vncunused = 1;
-    vfb->keymap = NULL;
-    vfb->sdl = 0;
-    vfb->opengl = 0;
-}
-
-static void init_vkb_info(libxl_device_vkb *vkb, int dev_num)
-{
-    memset(vkb, 0x00, sizeof(libxl_device_vkb));
-    vkb->devid = dev_num;
-}
-
-static void init_console_info(libxl_device_console *console, int dev_num, 
libxl_domain_build_state *state)
-{
-    memset(console, 0x00, sizeof(libxl_device_console));
-    console->devid = dev_num;
-    console->constype = CONSTYPE_XENCONSOLED;
-    if (state)
-        console->build_state = state;
-}
-
-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_pci *pcidevs,
-                        int num_pcidevs,
-                        libxl_device_vfb *vfbs,
-                        int num_vfbs,
-                        libxl_device_vkb *vkb,
-                        int num_vkbs,
-                        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("target_memkb: %d\n", b_info->target_memkb);
-    printf("kernel: %s\n", b_info->kernel);
-    printf("hvm: %d\n", b_info->hvm);
-
-    if (c_info->hvm) {
-        printf("video_memkb: %d\n", b_info->video_memkb);
-        printf("shadow_memkb: %d\n", b_info->shadow_memkb);
-        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]);
-    }
-
-    for (i = 0; i < num_pcidevs; i++) {
-        printf("\n\n\n*** pcidevs_info: %d ***\n", i);
-        printf("pci dev "PCI_BDF_VDEVFN"\n", pcidevs[i].domain, 
pcidevs[i].bus, pcidevs[i].dev, pcidevs[i].func, pcidevs[i].vdevfn);
-        printf("opts msitranslate %d power_mgmt %d\n", 
pcidevs[i].msitranslate, pcidevs[i].power_mgmt);
-    }
-
-    for (i = 0; i < num_vfbs; i++) {
-        printf("\n\n\n*** vfbs_info: %d ***\n", i);
-        printf("backend_domid %d\n", vfbs[i].backend_domid);
-        printf("domid %d\n", vfbs[i].domid);
-        printf("devid %d\n", vfbs[i].devid);
-        printf("vnc: %d\n", vfbs[i].vnc);
-        printf("vnclisten: %s\n", vfbs[i].vnclisten);
-        printf("vncdisplay: %d\n", vfbs[i].vncdisplay);
-        printf("vncunused: %d\n", vfbs[i].vncunused);
-        printf("keymap: %s\n", vfbs[i].keymap);
-        printf("sdl: %d\n", vfbs[i].sdl);
-        printf("opengl: %d\n", vfbs[i].opengl);
-        printf("display: %s\n", vfbs[i].display);
-        printf("xauthority: %s\n", vfbs[i].xauthority);
-    }
-
-    if (c_info->hvm) {
-        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 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_pci **pcidevs,
-                              int *num_pcidevs,
-                              libxl_device_vfb **vfbs,
-                              int *num_vfbs,
-                              libxl_device_vkb **vkbs,
-                              int *num_vkbs,
-                              libxl_device_model_info *dm_info)
-{
-    const char *buf;
-    long l;
-    XLU_Config *config;
-    XLU_ConfigList *vbds, *nics, *pcis, *cvfbs;
-    int pci_power_mgmt = 0;
-    int pci_msitranslate = 1;
-    int i, e;
-
-    config= xlu_cfg_init(stderr, filename);
-    if (!config) {
-        fprintf(stderr, "Failed to allocate for configuration\n");
-        exit(1);
-    }
-
-    e= xlu_cfg_readfile (config, filename);
-    if (e) {
-        fprintf(stderr, "Failed to parse config file: %s\n", strerror(e));
-        exit(1);
-    }
-
-    init_create_info(c_info);
-
-    c_info->hvm = 0;
-    if (!xlu_cfg_get_string (config, "builder", &buf) &&
-        !strncmp(buf, "hvm", strlen(buf)))
-        c_info->hvm = 1;
-
-    /* hap is missing */
-    if (!xlu_cfg_get_string (config, "name", &buf))
-        c_info->name = strdup(buf);
-    else
-        c_info->name = "test";
-    for (i = 0; i < 16; i++) {
-        c_info->uuid[i] = rand();
-    }
-
-    init_build_info(b_info, c_info);
-
-    /* the following is the actual config parsing with overriding values in 
the structures */
-    if (!xlu_cfg_get_long (config, "vcpus", &l))
-        b_info->max_vcpus = l;
-
-    if (!xlu_cfg_get_long (config, "memory", &l)) {
-        b_info->max_memkb = l * 1024;
-        b_info->target_memkb = b_info->max_memkb;
-    }
-
-    if (!xlu_cfg_get_long (config, "shadow_memory", &l))
-        b_info->shadow_memkb = l * 1024;
-
-    if (!xlu_cfg_get_long (config, "videoram", &l))
-        b_info->video_memkb = l * 1024;
-
-    if (!xlu_cfg_get_string (config, "kernel", &buf))
-        b_info->kernel = strdup(buf);
-
-    if (c_info->hvm == 1) {
-        if (!xlu_cfg_get_long (config, "pae", &l))
-            b_info->u.hvm.pae = l;
-        if (!xlu_cfg_get_long (config, "apic", &l))
-            b_info->u.hvm.apic = l;
-        if (!xlu_cfg_get_long (config, "acpi", &l))
-            b_info->u.hvm.acpi = l;
-        if (!xlu_cfg_get_long (config, "nx", &l))
-            b_info->u.hvm.nx = l;
-        if (!xlu_cfg_get_long (config, "viridian", &l))
-            b_info->u.hvm.viridian = l;
-    } else {
-        char *cmdline;
-        if (!xlu_cfg_get_string (config, "root", &buf)) {
-            asprintf(&cmdline, "root=%s", buf);
-            b_info->u.pv.cmdline = cmdline;
-        }
-        if (!xlu_cfg_get_string (config, "ramdisk", &buf))
-            b_info->u.pv.ramdisk = strdup(buf);
-    }
-
-    if (!xlu_cfg_get_list (config, "disk", &vbds, 0)) {
-        *num_disks = 0;
-        *disks = NULL;
-        while ((buf = xlu_cfg_get_listitem (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;
-                (*disks)[*num_disks].unpluggable = 1;
-            } else {
-                *p2 = '\0';
-                (*disks)[*num_disks].virtpath = strdup(p);
-                if (!strcmp(p2 + 1, "cdrom")) {
-                    (*disks)[*num_disks].is_cdrom = 1;
-                    (*disks)[*num_disks].unpluggable = 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 (!xlu_cfg_get_list (config, "vif", &nics, 0)) {
-        *num_vifs = 0;
-        *vifs = NULL;
-        while ((buf = xlu_cfg_get_listitem (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;
-                    *(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;
-        }
-    }
-
-    if (!xlu_cfg_get_list (config, "vfb", &cvfbs, 0)) {
-        *num_vfbs = 0;
-        *num_vkbs = 0;
-        *vfbs = NULL;
-        *vkbs = NULL;
-        while ((buf = xlu_cfg_get_listitem (cvfbs, *num_vfbs)) != NULL) {
-            char *buf2 = strdup(buf);
-            char *p, *p2;
-            *vfbs = (libxl_device_vfb *) realloc(*vfbs, 
sizeof(libxl_device_vfb) * ((*num_vfbs) + 1));
-            init_vfb_info((*vfbs) + (*num_vfbs), (*num_vfbs));
-
-            *vkbs = (libxl_device_vkb *) realloc(*vkbs, 
sizeof(libxl_device_vkb) * ((*num_vkbs) + 1));
-            init_vkb_info((*vkbs) + (*num_vkbs), (*num_vkbs));
-
-            p = strtok(buf2, ",");
-            if (!p)
-                goto skip_vfb;
-            do {
-                while (*p == ' ')
-                    p++;
-                if ((p2 = strchr(p, '=')) == NULL)
-                    break;
-                *p2 = '\0';
-                if (!strcmp(p, "vnc")) {
-                    (*vfbs)[*num_vfbs].vnc = atoi(p2 + 1);
-                } else if (!strcmp(p, "vnclisten")) {
-                    (*vfbs)[*num_vfbs].vnclisten = strdup(p2 + 1);
-                } else if (!strcmp(p, "vncdisplay")) {
-                    (*vfbs)[*num_vfbs].vncdisplay = atoi(p2 + 1);
-                } else if (!strcmp(p, "vncunused")) {
-                    (*vfbs)[*num_vfbs].vncunused = atoi(p2 + 1);
-                } else if (!strcmp(p, "keymap")) {
-                    (*vfbs)[*num_vfbs].keymap = strdup(p2 + 1);
-                } else if (!strcmp(p, "sdl")) {
-                    (*vfbs)[*num_vfbs].sdl = atoi(p2 + 1);
-                } else if (!strcmp(p, "opengl")) {
-                    (*vfbs)[*num_vfbs].opengl = atoi(p2 + 1);
-                } else if (!strcmp(p, "display")) {
-                    (*vfbs)[*num_vfbs].display = strdup(p2 + 1);
-                } else if (!strcmp(p, "xauthority")) {
-                    (*vfbs)[*num_vfbs].xauthority = strdup(p2 + 1);
-                }
-            } while ((p = strtok(NULL, ",")) != NULL);
-skip_vfb:
-            free(buf2);
-            *num_vfbs = (*num_vfbs) + 1;
-            *num_vkbs = (*num_vkbs) + 1;
-        }
-    }
-
-    if (!xlu_cfg_get_long (config, "pci_msitranslate", &l))
-        pci_msitranslate = l;
-
-    if (!xlu_cfg_get_long (config, "pci_power_mgmt", &l))
-        pci_power_mgmt = l;
-
-    if (!xlu_cfg_get_list (config, "pci", &pcis, 0)) {
-        *num_pcidevs = 0;
-        *pcidevs = NULL;
-        while ((buf = xlu_cfg_get_listitem (pcis, *num_pcidevs)) != NULL) {
-            unsigned int domain = 0, bus = 0, dev = 0, func = 0, vdevfn = 0;
-            char *buf2 = strdup(buf);
-            char *p;
-            *pcidevs = (libxl_device_pci *) realloc(*pcidevs, sizeof 
(libxl_device_pci) * ((*num_pcidevs) + 1));
-            memset(*pcidevs + *num_pcidevs, 0x00, sizeof(libxl_device_pci));
-            p = strtok(buf2, ",");
-            if (!p)
-                goto skip_pci;
-            if (!sscanf(p, PCI_BDF_VDEVFN, &domain, &bus, &dev, &func, 
&vdevfn)) {
-                sscanf(p, "%02x:%02x.%01x@%02x", &bus, &dev, &func, &vdevfn);
-                domain = 0;
-            }
-            libxl_device_pci_init(*pcidevs + *num_pcidevs, domain, bus, dev, 
func, vdevfn);
-            (*pcidevs)[*num_pcidevs].msitranslate = pci_msitranslate;
-            (*pcidevs)[*num_pcidevs].power_mgmt = pci_power_mgmt;
-            while ((p = strtok(NULL, ",=")) != NULL) {
-                while (*p == ' ')
-                    p++;
-                if (!strcmp(p, "msitranslate")) {
-                    p = strtok(NULL, ",=");
-                    (*pcidevs)[*num_pcidevs].msitranslate = atoi(p);
-                } else if (!strcmp(p, "power_mgmt")) {
-                    p = strtok(NULL, ",=");
-                    (*pcidevs)[*num_pcidevs].power_mgmt = atoi(p);
-                }
-            }
-            *num_pcidevs = (*num_pcidevs) + 1;
-skip_pci:
-            free(buf2);
-        }
-    }
-
-    if (c_info->hvm == 1) {
-        /* init dm from c and b */
-        init_dm_info(dm_info, c_info, b_info);
-
-        /* then process config related to dm */
-        if (!xlu_cfg_get_string (config, "device_model", &buf))
-            dm_info->device_model = strdup(buf);
-        if (!xlu_cfg_get_long (config, "stdvga", &l))
-            dm_info->stdvga = l;
-        if (!xlu_cfg_get_long (config, "vnc", &l))
-            dm_info->vnc = l;
-        if (!xlu_cfg_get_string (config, "vnclisten", &buf))
-            dm_info->vnclisten = strdup(buf);
-        if (!xlu_cfg_get_long (config, "vncdisplay", &l))
-            dm_info->vncdisplay = l;
-        if (!xlu_cfg_get_long (config, "vncunused", &l))
-            dm_info->vncunused = l;
-        if (!xlu_cfg_get_string (config, "keymap", &buf))
-            dm_info->keymap = strdup(buf);
-        if (!xlu_cfg_get_long (config, "sdl", &l))
-            dm_info->sdl = l;
-        if (!xlu_cfg_get_long (config, "opengl", &l))
-            dm_info->opengl = l;
-        if (!xlu_cfg_get_long (config, "nographic", &l))
-            dm_info->nographic = l;
-        if (!xlu_cfg_get_string (config, "serial", &buf))
-            dm_info->serial = strdup(buf);
-        if (!xlu_cfg_get_string (config, "boot", &buf))
-            dm_info->boot = strdup(buf);
-        if (!xlu_cfg_get_long (config, "usb", &l))
-            dm_info->usb = l;
-        if (!xlu_cfg_get_string (config, "usbdevice", &buf))
-            dm_info->usbdevice = strdup(buf);
-    }
-
-    dm_info->type = c_info->hvm ? XENFV : XENPV;
-
-    xlu_cfg_destroy(config);
-}
-
-#define MUST( call ) ({                                                 \
-        int must_rc = (call);                                           \
-        if (must_rc) {                                                  \
-            fprintf(stderr,"xl: fatal error: %s:%d, rc=%d: %s\n",       \
-                    __FILE__,__LINE__, must_rc, #call);                 \
-            exit(-must_rc);                                             \
-        }                                                               \
-    })
-
-static void create_domain(int debug, int daemonize, const char *config_file, 
const char *restore_file, int paused)
-{
-    struct libxl_ctx ctx;
-    uint32_t domid;
-    libxl_domain_create_info info1;
-    libxl_domain_build_info info2;
-    libxl_domain_build_state state;
-    libxl_device_model_info dm_info;
-    libxl_device_disk *disks = NULL;
-    libxl_device_nic *vifs = NULL;
-    libxl_device_pci *pcidevs = NULL;
-    libxl_device_vfb *vfbs = NULL;
-    libxl_device_vkb *vkbs = NULL;
-    libxl_device_console console;
-    int num_disks = 0, num_vifs = 0, num_pcidevs = 0, num_vfbs = 0, num_vkbs = 
0;
-    int i, fd;
-    int need_daemon = 1;
-    int ret;
-    libxl_device_model_starting *dm_starting = 0;
-    libxl_waiter *w1 = NULL, *w2 = NULL;
-    memset(&dm_info, 0x00, sizeof(dm_info));
-
-    printf("Parsing config file %s\n", config_file);
-    parse_config_file(config_file, &info1, &info2, &disks, &num_disks, &vifs, 
&num_vifs, &pcidevs, &num_pcidevs, &vfbs, &num_vfbs, &vkbs, &num_vkbs, 
&dm_info);
-    if (debug)
-        printf_info(&info1, &info2, disks, num_disks, vifs, num_vifs, pcidevs, 
num_pcidevs, vfbs, num_vfbs, vkbs, num_vkbs, &dm_info);
-
-start:
-    domid = 0;
-
-    if (libxl_ctx_init(&ctx, LIBXL_VERSION)) {
-        fprintf(stderr, "cannot init xl context\n");
-        return;
-    }
-
-    libxl_ctx_set_log(&ctx, log_callback, NULL);
-
-    ret = libxl_domain_make(&ctx, &info1, &domid);
-    if (ret) {
-        fprintf(stderr, "cannot make domain: %d\n", ret);
-        return;
-    }
-
-    if (!restore_file || !need_daemon) {
-        if (dm_info.saved_state) {
-            free(dm_info.saved_state);
-            dm_info.saved_state = NULL;
-        }
-        ret = libxl_domain_build(&ctx, &info2, domid, &state);
-    } else {
-        int restore_fd;
-
-        restore_fd = open(restore_file, O_RDONLY);
-        ret = libxl_domain_restore(&ctx, &info2, domid, restore_fd, &state, 
&dm_info);
-        close(restore_fd);
-    }
-
-    if (ret) {
-        fprintf(stderr, "cannot (re-)build domain: %d\n", ret);
-        return;
-    }
-
-    for (i = 0; i < num_disks; i++) {
-        disks[i].domid = domid;
-        ret = libxl_device_disk_add(&ctx, domid, &disks[i]);
-        if (ret) {
-            fprintf(stderr, "cannot add disk %d to domain: %d\n", i, ret);
-            return;
-        }
-    }
-    for (i = 0; i < num_vifs; i++) {
-        vifs[i].domid = domid;
-        ret = libxl_device_nic_add(&ctx, domid, &vifs[i]);
-        if (ret) {
-            fprintf(stderr, "cannot add nic %d to domain: %d\n", i, ret);
-            return;
-        }
-    }
-    if (info1.hvm) {
-        dm_info.domid = domid;
-        MUST( libxl_create_device_model(&ctx, &dm_info, disks, num_disks,
-                                        vifs, num_vifs, &dm_starting) );
-    } else {
-        for (i = 0; i < num_vfbs; i++) {
-            vfbs[i].domid = domid;
-            libxl_device_vfb_add(&ctx, domid, &vfbs[i]);
-            vkbs[i].domid = domid;
-            libxl_device_vkb_add(&ctx, domid, &vkbs[i]);
-        }
-        init_console_info(&console, 0, &state);
-        console.domid = domid;
-        if (num_vfbs)
-            console.constype = CONSTYPE_IOEMU;
-        libxl_device_console_add(&ctx, domid, &console);
-        if (num_vfbs)
-            libxl_create_xenpv_qemu(&ctx, vfbs, 1, &console, &dm_starting);
-    }
-
-    if (dm_starting)
-        MUST( libxl_confirm_device_model_startup(&ctx, dm_starting) );
-    for (i = 0; i < num_pcidevs; i++)
-        libxl_device_pci_add(&ctx, domid, &pcidevs[i]);
-
-    if (!paused)
-        libxl_domain_unpause(&ctx, domid);
-
-    if (!daemonize)
-        exit(0);
-
-    if (need_daemon) {
-        char *fullname, *name;
-
-        asprintf(&name, "xl-%s", info1.name);
-        libxl_create_logfile(&ctx, name, &fullname);
-        logfile = open(fullname, O_WRONLY|O_CREAT, 0644);
-        free(fullname);
-        free(name);
-
-        daemon(0, 0);
-        need_daemon = 0;
-    }
-    LOG("Waiting for domain %s (domid %d) to die", info1.name, domid);
-    w1 = (libxl_waiter*) malloc(sizeof(libxl_waiter) * num_disks);
-    w2 = (libxl_waiter*) malloc(sizeof(libxl_waiter));
-    libxl_wait_for_disk_ejects(&ctx, domid, disks, num_disks, w1);
-    libxl_wait_for_domain_death(&ctx, domid, w2);
-    libxl_get_wait_fd(&ctx, &fd);
-    while (1) {
-        int ret;
-        fd_set rfds;
-        xc_domaininfo_t info;
-        libxl_event event;
-        libxl_device_disk disk;
-        memset(&info, 0x00, sizeof(xc_dominfo_t));
-
-        FD_ZERO(&rfds);
-        FD_SET(fd, &rfds);
-
-        ret = select(fd + 1, &rfds, NULL, NULL, NULL);
-        if (!ret)
-            continue;
-        libxl_get_event(&ctx, &event);
-        switch (event.type) {
-            case DOMAIN_DEATH:
-                if (libxl_event_get_domain_death_info(&ctx, domid, &event, 
&info)) {
-                    LOG("Domain %d is dead", domid);
-                    if (info.flags & XEN_DOMINF_dying || (info.flags & 
XEN_DOMINF_shutdown && (((info.flags >> XEN_DOMINF_shutdownshift) & 
XEN_DOMINF_shutdownmask) != SHUTDOWN_suspend))) {
-                        LOG("Domain %d needs to be clean: destroying the 
domain", domid);
-                        libxl_domain_destroy(&ctx, domid, 0);
-                        if (info.flags & XEN_DOMINF_shutdown &&
-                            (((info.flags >> XEN_DOMINF_shutdownshift) & 
XEN_DOMINF_shutdownmask) == SHUTDOWN_reboot)) {
-                            libxl_free_waiter(w1);
-                            libxl_free_waiter(w2);
-                            free(w1);
-                            free(w2);
-                            libxl_ctx_free(&ctx);
-                            LOG("Done. Rebooting now");
-                            goto start;
-                        }
-                        LOG("Done. Exiting now");
-                    }
-                    LOG("Domain %d does not need to be clean, exiting now", 
domid);
-                    exit(0);
-                }
-                break;
-            case DISK_EJECT:
-                if (libxl_event_get_disk_eject_info(&ctx, domid, &event, 
&disk))
-                    libxl_cdrom_insert(&ctx, domid, &disk);
-                break;
-        }
-        libxl_free_event(&event);
-    }
-
-    close(logfile);
-    free(disks);
-    free(vifs);
-    free(vfbs);
-    free(vkbs);
-    free(pcidevs);
-}
-
-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");
-        printf(" pci-attach                    insert a new pass-through pci 
device\n\n");
-        printf(" pci-detach                    remove a domain's pass-through 
pci device\n\n");
-        printf(" pci-list                      list pass-through pci devices 
for a domain\n\n");
-        printf(" pause                         pause execution of a 
domain\n\n");
-        printf(" unpause                       unpause a paused domain\n\n");
-        printf(" console                       attach to domain's 
console\n\n");
-        printf(" save                          save a domain state to restore 
later\n\n");
-        printf(" restore                       restore a domain from a saved 
state\n\n");
-        printf(" cd-insert                     insert a cdrom into a guest's 
cd drive\n\n");
-        printf(" cd-eject                      eject a cdrom from a guest's cd 
drive\n\n");
-        printf(" mem-set                       set the current memory usage 
for a domain\n\n");
-        printf(" button-press                  indicate an ACPI button press 
to the domain\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");
-        printf("-e                     Do not wait in the background for the 
death of the domain.\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, "pci-attach")) {
-        printf("Usage: xl pci-attach <Domain> <BDF> [Virtual Slot]\n\n");
-        printf("Insert a new pass-through pci device.\n\n");
-    } else if(!strcmp(command, "pci-detach")) {
-        printf("Usage: xl pci-detach <Domain> <BDF>\n\n");
-        printf("Remove a domain's pass-through pci device.\n\n");
-    } else if(!strcmp(command, "pci-list")) {
-        printf("Usage: xl pci-list <Domain>\n\n");
-        printf("List pass-through pci devices for a domain.\n\n");
-    } else if(!strcmp(command, "pause")) {
-        printf("Usage: xl pause <Domain>\n\n");
-        printf("Pause execution of a domain.\n\n");
-    } else if(!strcmp(command, "unpause")) {
-        printf("Usage: xl unpause <Domain>\n\n");
-        printf("Unpause a paused domain.\n\n");
-    } else if(!strcmp(command, "save")) {
-        printf("Usage: xl save [options] <Domain> <CheckpointFile>\n\n");
-        printf("Save a domain state to restore later.\n\n");
-        printf("Options:\n\n");
-        printf("-h                     Print this help.\n");
-        printf("-c                     Leave domain running after creating the 
snapshot.\n");
-    } else if(!strcmp(command, "restore")) {
-        printf("Usage: xl restore [options] <ConfigFile> 
<CheckpointFile>\n\n");
-        printf("Restore a domain from a saved state.\n\n");
-        printf("Options:\n\n");
-        printf("-h                     Print this help.\n");
-        printf("-p                     Do not unpause domain after restoring 
it.\n");
-        printf("-e                     Do not wait in the background for the 
death of the domain.\n");
-    } else if(!strcmp(command, "destroy")) {
-        printf("Usage: xl destroy <Domain>\n\n");
-        printf("Terminate a domain immediately.\n\n");
-    } else if (!strcmp(command, "console")) {
-        printf("Usage: xl console <Domain>\n\n");
-        printf("Attach to domain's console.\n\n");
-    } else if (!strcmp(command, "cd-insert")) {
-        printf("Usage: xl cd-insert <Domain> <VirtualDevice> <type:path>\n\n");
-        printf("Insert a cdrom into a guest's cd drive.\n\n");
-    } else if (!strcmp(command, "cd-eject")) {
-        printf("Usage: xl cd-eject <Domain> <VirtualDevice>\n\n");
-        printf("Eject a cdrom from a guest's cd drive.\n\n");
-    } else if (!strcmp(command, "mem-set")) {
-        printf("Usage: xl mem-set <Domain> <MemKB>\n\n");
-        printf("Set the current memory usage for a domain.\n\n");
-    } else if (!strcmp(command, "button-press")) {
-        printf("Usage: xl button-press <Domain> <Button>\n\n");
-        printf("Indicate <Button> press to a domain.\n");
-        printf("<Button> may be 'power' or 'sleep'.\n\n");
-    }
-}
-
-void set_memory_target(char *p, char *mem)
-{
-    struct libxl_ctx ctx;
-    uint32_t domid;
-    uint32_t memorykb;
-    char *endptr;
-
-    if (libxl_ctx_init(&ctx, LIBXL_VERSION)) {
-        fprintf(stderr, "cannot init xl context\n");
-        return;
-    }
-    libxl_ctx_set_log(&ctx, log_callback, NULL);
-
-    if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) {
-        fprintf(stderr, "%s is an invalid domain identifier\n", p);
-        exit(2);
-    }
-    memorykb = strtoul(mem, &endptr, 10);
-    if (*endptr != '\0') {
-        fprintf(stderr, "invalid memory size: %s\n", mem);
-        exit(3);
-    }
-    printf("setting domid %d memory to : %d\n", domid, memorykb);
-    libxl_set_memory_target(&ctx, domid, memorykb);
-}
-
-int main_memset(int argc, char **argv)
-{
-    int opt = 0;
-    char *p = NULL, *mem;
-
-    while ((opt = getopt(argc, argv, "h:")) != -1) {
-        switch (opt) {
-        case 'h':
-            help("mem-set");
-            exit(0);
-        default:
-            fprintf(stderr, "option not supported\n");
-            break;
-        }
-    }
-    if (optind >= argc - 1) {
-        help("mem-set");
-        exit(2);
-    }
-
-    p = argv[optind];
-    mem = argv[optind + 1];
-
-    set_memory_target(p, mem);
-    exit(0);
-}
-
-void console(char *p, int cons_num)
-{
-    struct libxl_ctx ctx;
-    uint32_t domid;
-
-    if (libxl_ctx_init(&ctx, LIBXL_VERSION)) {
-        fprintf(stderr, "cannot init xl context\n");
-        return;
-    }
-    libxl_ctx_set_log(&ctx, log_callback, NULL);
-
-    if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) {
-        fprintf(stderr, "%s is an invalid domain identifier\n", p);
-        exit(2);
-    }
-    libxl_console_attach(&ctx, domid, cons_num);
-}
-
-void cd_insert(char *dom, char *virtdev, char *phys)
-{
-    struct libxl_ctx ctx;
-    uint32_t domid;
-    libxl_device_disk disk;
-    char *p;
-
-    if (libxl_ctx_init(&ctx, LIBXL_VERSION)) {
-        fprintf(stderr, "cannot init xl context\n");
-        return;
-    }
-    libxl_ctx_set_log(&ctx, log_callback, NULL);
-
-    if (domain_qualifier_to_domid(&ctx, dom, &domid) < 0) {
-        fprintf(stderr, "%s is an invalid domain identifier\n", dom);
-        exit(2);
-    }
-
-    disk.backend_domid = 0;
-    disk.domid = domid;
-    if (phys) {
-        p = strchr(phys, ':');
-        if (!p) {
-            fprintf(stderr, "No type specified, ");
-            disk.physpath = phys;
-            if (!strncmp(phys, "/dev", 4)) {
-                fprintf(stderr, "assuming phy:\n");
-                disk.phystype = PHYSTYPE_PHY;
-            } else {
-                fprintf(stderr, "assuming file:\n");
-                disk.phystype = PHYSTYPE_FILE;
-            }
-        } else {
-            *p = '\0';
-            p++;
-            disk.physpath = p;
-            libxl_string_to_phystype(&ctx, phys, &disk.phystype);
-        }
-    } else {
-            disk.physpath = NULL;
-            disk.phystype = 0;
-    }
-    disk.virtpath = virtdev;
-    disk.unpluggable = 1;
-    disk.readwrite = 0;
-    disk.is_cdrom = 1;
-
-    libxl_cdrom_insert(&ctx, domid, &disk);
-}
-
-int main_cd_eject(int argc, char **argv)
-{
-    int opt = 0;
-    char *p = NULL, *virtdev;
-
-    while ((opt = getopt(argc, argv, "hn:")) != -1) {
-        switch (opt) {
-        case 'h':
-            help("cd-eject");
-            exit(0);
-        default:
-            fprintf(stderr, "option not supported\n");
-            break;
-        }
-    }
-    if (optind >= argc - 1) {
-        help("cd-eject");
-        exit(2);
-    }
-
-    p = argv[optind];
-    virtdev = argv[optind + 1];
-
-    cd_insert(p, virtdev, NULL);
-    exit(0);
-}
-
-int main_cd_insert(int argc, char **argv)
-{
-    int opt = 0;
-    char *p = NULL, *file = NULL, *virtdev;
-
-    while ((opt = getopt(argc, argv, "hn:")) != -1) {
-        switch (opt) {
-        case 'h':
-            help("cd-insert");
-            exit(0);
-        default:
-            fprintf(stderr, "option not supported\n");
-            break;
-        }
-    }
-    if (optind >= argc - 2) {
-        help("cd-insert");
-        exit(2);
-    }
-
-    p = argv[optind];
-    virtdev = argv[optind + 1];
-    file = argv[optind + 2];
-
-    cd_insert(p, virtdev, file);
-    exit(0);
-}
-
-int main_console(int argc, char **argv)
-{
-    int opt = 0, cons_num = 0;
-    char *p = NULL;
-
-    while ((opt = getopt(argc, argv, "hn:")) != -1) {
-        switch (opt) {
-        case 'h':
-            help("console");
-            exit(0);
-        case 'n':
-            if (optarg) {
-                cons_num = strtol(optarg, NULL, 10);
-            }
-            break;
-        default:
-            fprintf(stderr, "option not supported\n");
-            break;
-        }
-    }
-    if (optind >= argc) {
-        help("console");
-        exit(2);
-    }
-
-    p = argv[optind];
-
-    console(p, cons_num);
-    exit(0);
-}
-
-void pcilist(char *dom)
-{
-    struct libxl_ctx ctx;
-    uint32_t domid;
-    libxl_device_pci *pcidevs;
-    int num, i;
-
-    if (libxl_ctx_init(&ctx, LIBXL_VERSION)) {
-        fprintf(stderr, "cannot init xl context\n");
-        return;
-    }
-    libxl_ctx_set_log(&ctx, log_callback, NULL);
-
-    if (domain_qualifier_to_domid(&ctx, dom, &domid) < 0) {
-        fprintf(stderr, "%s is an invalid domain identifier\n", dom);
-        exit(2);
-    }
-    pcidevs = libxl_device_pci_list(&ctx, domid, &num);
-    if (!num)
-        return;
-    printf("VFn  domain bus  slot func\n");
-    for (i = 0; i < num; i++) {
-        printf("0x%02x 0x%04x 0x%02x 0x%02x 0x%01x\n", pcidevs[i].vdevfn, 
pcidevs[i].domain, pcidevs[i].bus, pcidevs[i].dev, pcidevs[i].func);
-    }
-    free(pcidevs);
-}
-
-int main_pcilist(int argc, char **argv)
-{
-    int opt;
-    char *domname = NULL;
-
-    while ((opt = getopt(argc, argv, "h")) != -1) {
-        switch (opt) {
-        case 'h':
-            help("pci-list");
-            exit(0);
-        default:
-            fprintf(stderr, "option not supported\n");
-            break;
-        }
-    }
-    if (optind >= argc) {
-        help("pci-list");
-        exit(2);
-    }
-
-    domname = argv[optind];
-
-    pcilist(domname);
-    exit(0);
-}
-
-void pcidetach(char *dom, char *bdf)
-{
-    struct libxl_ctx ctx;
-    uint32_t domid;
-    libxl_device_pci pcidev;
-    unsigned int domain, bus, dev, func;
-
-    if (libxl_ctx_init(&ctx, LIBXL_VERSION)) {
-        fprintf(stderr, "cannot init xl context\n");
-        return;
-    }
-    libxl_ctx_set_log(&ctx, log_callback, NULL);
-
-    if (domain_qualifier_to_domid(&ctx, dom, &domid) < 0) {
-        fprintf(stderr, "%s is an invalid domain identifier\n", dom);
-        exit(2);
-    }
-    memset(&pcidev, 0x00, sizeof(pcidev));
-    sscanf(bdf, PCI_BDF, &domain, &bus, &dev, &func);
-    libxl_device_pci_init(&pcidev, domain, bus, dev, func, 0);
-    libxl_device_pci_remove(&ctx, domid, &pcidev);
-}
-
-int main_pcidetach(int argc, char **argv)
-{
-    int opt;
-    char *domname = NULL, *bdf = NULL;
-
-    while ((opt = getopt(argc, argv, "h")) != -1) {
-        switch (opt) {
-        case 'h':
-            help("pci-attach");
-            exit(0);
-        default:
-            fprintf(stderr, "option not supported\n");
-            break;
-        }
-    }
-    if (optind >= argc - 1) {
-        help("pci-detach");
-        exit(2);
-    }
-
-    domname = argv[optind];
-    bdf = argv[optind + 1];
-
-    pcidetach(domname, bdf);
-    exit(0);
-}
-void pciattach(char *dom, char *bdf, char *vs)
-{
-    struct libxl_ctx ctx;
-    uint32_t domid;
-    libxl_device_pci pcidev;
-    unsigned int domain, bus, dev, func;
-
-    if (libxl_ctx_init(&ctx, LIBXL_VERSION)) {
-        fprintf(stderr, "cannot init xl context\n");
-        return;
-    }
-    libxl_ctx_set_log(&ctx, log_callback, NULL);
-
-    if (domain_qualifier_to_domid(&ctx, dom, &domid) < 0) {
-        fprintf(stderr, "%s is an invalid domain identifier\n", dom);
-        exit(2);
-    }
-    memset(&pcidev, 0x00, sizeof(pcidev));
-    sscanf(bdf, PCI_BDF, &domain, &bus, &dev, &func);
-    libxl_device_pci_init(&pcidev, domain, bus, dev, func, 0);
-    libxl_device_pci_add(&ctx, domid, &pcidev);
-}
-
-int main_pciattach(int argc, char **argv)
-{
-    int opt;
-    char *domname = NULL, *bdf = NULL, *vs = NULL;
-
-    while ((opt = getopt(argc, argv, "h")) != -1) {
-        switch (opt) {
-        case 'h':
-            help("pci-attach");
-            exit(0);
-        default:
-            fprintf(stderr, "option not supported\n");
-            break;
-        }
-    }
-    if (optind >= argc - 1) {
-        help("pci-attach");
-        exit(2);
-    }
-
-    domname = argv[optind];
-    bdf = argv[optind + 1];
-
-    if (optind + 1 < argc)
-        vs = argv[optind + 2];
-
-    pciattach(domname, bdf, vs);
-    exit(0);
-}
-
-void pause_domain(char *p)
-{
-    struct libxl_ctx ctx;
-    uint32_t domid;
-
-    if (libxl_ctx_init(&ctx, LIBXL_VERSION)) {
-        fprintf(stderr, "cannot init xl context\n");
-        return;
-    }
-    libxl_ctx_set_log(&ctx, log_callback, NULL);
-
-    if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) {
-        fprintf(stderr, "%s is an invalid domain identifier\n", p);
-        exit(2);
-    }
-    libxl_domain_pause(&ctx, domid);
-}
-
-void unpause_domain(char *p)
-{
-    struct libxl_ctx ctx;
-    uint32_t domid;
-
-    if (libxl_ctx_init(&ctx, LIBXL_VERSION)) {
-        fprintf(stderr, "cannot init xl context\n");
-        return;
-    }
-    libxl_ctx_set_log(&ctx, log_callback, NULL);
-
-    if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) {
-        fprintf(stderr, "%s is an invalid domain identifier\n", p);
-        exit(2);
-    }
-    libxl_domain_unpause(&ctx, domid);
-}
-
-void destroy_domain(char *p)
-{
-    struct libxl_ctx ctx;
-    uint32_t domid;
-
-    if (libxl_ctx_init(&ctx, LIBXL_VERSION)) {
-        fprintf(stderr, "cannot init xl context\n");
-        return;
-    }
-    libxl_ctx_set_log(&ctx, log_callback, NULL);
-
-    if (domain_qualifier_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;
-    struct libxl_dominfo *info;
-    int nb_domain, i;
-
-    if (libxl_ctx_init(&ctx, LIBXL_VERSION)) {
-        fprintf(stderr, "cannot init xl context\n");
-        return;
-    }
-    libxl_ctx_set_log(&ctx, log_callback, NULL);
-
-    info = libxl_list_domain(&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 %8.1f\n",
-                libxl_domid_to_name(&ctx, info[i].domid),
-                info[i].domid,
-                (unsigned long) (info[i].max_memkb / 1024),
-                info[i].vcpu_online,
-                info[i].running ? 'r' : '-',
-                info[i].paused ? 'p' : '-',
-                info[i].dying ? 'd' : '-',
-                ((float)info[i].cpu_time / 1e9));
-    }
-    free(info);
-}
-
-void list_vm(void)
-{
-    struct libxl_ctx ctx;
-    struct libxl_vminfo *info;
-    int nb_vm, i;
-
-    if (libxl_ctx_init(&ctx, LIBXL_VERSION)) {
-        fprintf(stderr, "cannot init xl context\n");
-        return;
-    }
-    libxl_ctx_set_log(&ctx, log_callback, NULL);
-
-    info = libxl_list_vm(&ctx, &nb_vm);
-
-    if (info < 0) {
-        fprintf(stderr, "libxl_domain_infolist failed.\n");
-        exit(1);
-    }
-    printf("UUID                                  ID    name\n");
-    for (i = 0; i < nb_vm; i++) {
-        printf(UUID_FMT "  %d    %-30s\n",
-            info[i].uuid[0], info[i].uuid[1], info[i].uuid[2], info[i].uuid[3],
-            info[i].uuid[4], info[i].uuid[5], info[i].uuid[6], info[i].uuid[7],
-            info[i].uuid[8], info[i].uuid[9], info[i].uuid[10], 
info[i].uuid[11],
-            info[i].uuid[12], info[i].uuid[13], info[i].uuid[14], 
info[i].uuid[15],
-            info[i].domid, libxl_domid_to_name(&ctx, info[i].domid));
-    }
-    free(info);
-}
-
-int save_domain(char *p, char *filename, int checkpoint)
-{
-    struct libxl_ctx ctx;
-    uint32_t domid;
-    int fd;
-
-    if (libxl_ctx_init(&ctx, LIBXL_VERSION)) {
-        fprintf(stderr, "cannot init xl context\n");
-        exit(2);
-    }
-    libxl_ctx_set_log(&ctx, log_callback, NULL);
-
-    if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) {
-        fprintf(stderr, "%s is an invalid domain identifier\n", p);
-        exit(2);
-    }
-    fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644);
-    if (fd < 0) {
-        fprintf(stderr, "Failed to open temp file %s for writing\n", filename);
-        exit(2);
-    }
-    libxl_domain_suspend(&ctx, NULL, domid, fd);
-    close(fd);
-
-    if (checkpoint)
-        libxl_domain_unpause(&ctx, domid);
-    else
-        libxl_domain_destroy(&ctx, domid, 0);
-
-    exit(0);
-}
-
-int main_restore(int argc, char **argv)
-{
-    char *checkpoint_file = NULL;
-    char *config_file = NULL;
-    int paused = 0, debug = 0, daemonize = 1;
-    int opt;
-
-    while ((opt = getopt(argc, argv, "hpde")) != -1) {
-        switch (opt) {
-        case 'p':
-            paused = 1;
-            break;
-        case 'd':
-            debug = 1;
-            break;
-        case 'e':
-            daemonize = 0;
-            break;
-        case 'h':
-            help("restore");
-            exit(0);
-        default:
-            fprintf(stderr, "option not supported\n");
-            break;
-        }
-    }
-
-    if (optind >= argc - 1) {
-        help("restore");
-        exit(2);
-    }
-
-    config_file = argv[optind];
-    checkpoint_file = argv[optind + 1];
-    create_domain(debug, daemonize, config_file, checkpoint_file, paused);
-    exit(0);
-}
-
-int main_save(int argc, char **argv)
-{
-    char *filename = NULL, *p = NULL;
-    int checkpoint = 0;
-    int opt;
-
-    while ((opt = getopt(argc, argv, "hc")) != -1) {
-        switch (opt) {
-        case 'c':
-            checkpoint = 1;
-            break;
-        case 'h':
-            help("save");
-            exit(0);
-        default:
-            fprintf(stderr, "option not supported\n");
-            break;
-        }
-    }
-
-    if (optind >= argc - 1) {
-        help("save");
-        exit(2);
-    }
-
-    p = argv[optind];
-    filename = argv[optind + 1];
-    save_domain(p, filename, checkpoint);
-    exit(0);
-}
-
-int main_pause(int argc, char **argv)
-{
-    int opt;
-    char *p;
-    
-
-    while ((opt = getopt(argc, argv, "h")) != -1) {
-        switch (opt) {
-        case 'h':
-            help("pause");
-            exit(0);
-        default:
-            fprintf(stderr, "option not supported\n");
-            break;
-        }
-    }
-    if (optind >= argc) {
-        help("pause");
-        exit(2);
-    }
-
-    p = argv[optind];
-
-    pause_domain(p);
-    exit(0);
-}
-
-int main_unpause(int argc, char **argv)
-{
-    int opt;
-    char *p;
-    
-
-    while ((opt = getopt(argc, argv, "h")) != -1) {
-        switch (opt) {
-        case 'h':
-            help("unpause");
-            exit(0);
-        default:
-            fprintf(stderr, "option not supported\n");
-            break;
-        }
-    }
-    if (optind >= argc) {
-        help("unpause");
-        exit(2);
-    }
-
-    p = argv[optind];
-
-    unpause_domain(p);
-    exit(0);
-}
-
-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_list_vm(int argc, char **argv)
-{
-    int opt;
-
-    while ((opt = getopt(argc, argv, "h")) != -1) {
-        switch (opt) {
-        case 'h':
-            help("list-vm");
-            exit(0);
-        default:
-            fprintf(stderr, "option not supported\n");
-            break;
-        }
-    }
-
-    list_vm();
-    exit(0);
-}
-
-int main_create(int argc, char **argv)
-{
-    char *filename = NULL;
-    int debug = 0, daemonize = 1;
-    int opt;
-
-    while ((opt = getopt(argc, argv, "hde")) != -1) {
-        switch (opt) {
-        case 'd':
-            debug = 1;
-            break;
-        case 'e':
-            daemonize = 0;
-            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, daemonize, filename, NULL, 0);
-    exit(0);
-}
-
-void button_press(char *p, char *b)
-{
-    struct libxl_ctx ctx;
-    uint32_t domid;
-    libxl_button button;
-
-    libxl_ctx_init(&ctx, LIBXL_VERSION);
-    libxl_ctx_set_log(&ctx, log_callback, NULL);
-
-    if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) {
-        fprintf(stderr, "%s is an invalid domain identifier\n", p);
-        exit(2);
-    }
-
-    if (!strcmp(b, "power")) {
-        button = POWER_BUTTON;
-    } else if (!strcmp(b, "sleep")) {
-        button = SLEEP_BUTTON;
-    } else {
-        fprintf(stderr, "%s is an invalid button identifier\n", b);
-        exit(2);
-    }
-
-    libxl_button_press(&ctx, domid, button);
-}
-
-int main_button_press(int argc, char **argv)
-{
-    int opt;
-    char *p;
-    char *b;
-
-    while ((opt = getopt(argc, argv, "h")) != -1) {
-        switch (opt) {
-        case 'h':
-            help("button-press");
-            exit(0);
-        default:
-            fprintf(stderr, "option not supported\n");
-            break;
-        }
-    }
-    if (optind >= argc - 1) {
-        help("button-press");
-        exit(2);
-    }
-
-    p = argv[optind];
-    b = argv[optind + 1];
-
-    button_press(p, b);
-    exit(0);
+    snprintf(str, sizeof(str), "[%d] %s:%d:%s: %s\n",
+             loglevel, file, line, func, s);
+    libxl_write_exactly(NULL, logfile, str, strlen(str), NULL, NULL);
 }
 
 int main(int argc, char **argv)
 {
+    struct cmd_spec *cspec;
+
     if (argc < 2) {
         help(NULL);
         exit(1);
     }
 
+    if (libxl_ctx_init(&ctx, LIBXL_VERSION)) {
+        fprintf(stderr, "cannot init xl context\n");
+        exit(1);
+    }
+    if (libxl_ctx_set_log(&ctx, log_callback, NULL)) {
+        fprintf(stderr, "cannot set xl log callback\n");
+        exit(-ERROR_FAIL);
+    }
+
     srand(time(0));
 
-    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], "list-vm")) {
-        main_list_vm(argc - 1, argv + 1);
-    } else if (!strcmp(argv[1], "destroy")) {
-        main_destroy(argc - 1, argv + 1);
-    } else if (!strcmp(argv[1], "pci-attach")) {
-        main_pciattach(argc - 1, argv + 1);
-    } else if (!strcmp(argv[1], "pci-detach")) {
-        main_pcidetach(argc - 1, argv + 1);
-    } else if (!strcmp(argv[1], "pci-list")) {
-        main_pcilist(argc - 1, argv + 1);
-    } else if (!strcmp(argv[1], "pause")) {
-        main_pause(argc - 1, argv + 1);
-    } else if (!strcmp(argv[1], "unpause")) {
-        main_unpause(argc - 1, argv + 1);
-    } else if (!strcmp(argv[1], "console")) {
-        main_console(argc - 1, argv + 1);
-    } else if (!strcmp(argv[1], "save")) {
-        main_save(argc - 1, argv + 1);
-    } else if (!strcmp(argv[1], "restore")) {
-        main_restore(argc - 1, argv + 1);
-    } else if (!strcmp(argv[1], "cd-insert")) {
-        main_cd_insert(argc - 1, argv + 1);
-    } else if (!strcmp(argv[1], "cd-eject")) {
-        main_cd_eject(argc - 1, argv + 1);
-    } else if (!strcmp(argv[1], "mem-set")) {
-        main_memset(argc - 1, argv + 1);
-    } else if (!strcmp(argv[1], "button-press")) {
-        main_button_press(argc - 1, argv + 1);
-    } else if (!strcmp(argv[1], "help")) {
-        if (argc > 2)
-            help(argv[2]);
-        else
-            help(NULL);
+    cspec = cmdtable_lookup(argv[1]);
+    if (cspec)
+        return cspec->cmd_impl(argc, argv);
+    else if (!strcmp(argv[1], "help")) {
+        help(argv[optind]);
         exit(0);
     } else {
         fprintf(stderr, "command not implemented\n");
         exit(1);
     }
 }
-
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/xl.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxl/xl.h  Mon Jul 05 12:19:50 2010 +0100
@@ -0,0 +1,81 @@
+/*
+ * Author Yang Hongyang <yanghy@xxxxxxxxxxxxxx>
+ *
+ * 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 XL_H
+#define XL_H
+
+struct cmd_spec {
+    char *cmd_name;
+    int (*cmd_impl)(int argc, char **argv);
+    char *cmd_desc;
+    char *cmd_usage;
+    char *cmd_option;
+};
+
+int main_vcpulist(int argc, char **argv);
+int main_info(int argc, char **argv);
+int main_cd_eject(int argc, char **argv);
+int main_cd_insert(int argc, char **argv);
+int main_console(int argc, char **argv);
+int main_pcilist(int argc, char **argv);
+int main_pcidetach(int argc, char **argv);
+int main_pciattach(int argc, char **argv);
+int main_restore(int argc, char **argv);
+int main_migrate_receive(int argc, char **argv);
+int main_save(int argc, char **argv);
+int main_migrate(int argc, char **argv);
+int main_pause(int argc, char **argv);
+int main_unpause(int argc, char **argv);
+int main_destroy(int argc, char **argv);
+int main_shutdown(int argc, char **argv);
+int main_reboot(int argc, char **argv);
+int main_list(int argc, char **argv);
+int main_list_vm(int argc, char **argv);
+int main_create(int argc, char **argv);
+int main_button_press(int argc, char **argv);
+int main_vcpupin(int argc, char **argv);
+int main_vcpuset(int argc, char **argv);
+int main_memmax(int argc, char **argv);
+int main_memset(int argc, char **argv);
+int main_sched_credit(int argc, char **argv);
+int main_domid(int argc, char **argv);
+int main_domname(int argc, char **argv);
+int main_rename(int argc, char **argv);
+int main_trigger(int argc, char **argv);
+int main_sysrq(int argc, char **argv);
+int main_debug_keys(int argc, char **argv);
+int main_dmesg(int argc, char **argv);
+int main_top(int argc, char **argv);
+int main_networkattach(int argc, char **argv);
+int main_networklist(int argc, char **argv);
+int main_networkdetach(int argc, char **argv);
+int main_blockattach(int argc, char **argv);
+int main_blocklist(int argc, char **argv);
+int main_blockdetach(int argc, char **argv);
+int main_uptime(int argc, char **argv);
+int main_tmem_list(int argc, char **argv);
+int main_tmem_freeze(int argc, char **argv);
+int main_tmem_destroy(int argc, char **argv);
+int main_tmem_thaw(int argc, char **argv);
+int main_tmem_set(int argc, char **argv);
+int main_tmem_shared_auth(int argc, char **argv);
+
+void help(char *command);
+
+/* Look up a command in the table, allowing unambiguous truncation */
+struct cmd_spec *cmdtable_lookup(const char *s);
+extern struct cmd_spec cmd_table[];
+extern int cmdtable_len;
+
+#endif /* XL_H */
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/xl_cmdimpl.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxl/xl_cmdimpl.c  Mon Jul 05 12:19:50 2010 +0100
@@ -0,0 +1,4243 @@
+/*
+ * Copyright (C) 2009      Citrix Ltd.
+ * Author Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
+ * Author Vincent Hanquez <vincent.hanquez@xxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+#include "libxl_osdeps.h"
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h> /* for time */
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <arpa/inet.h>
+#include <sys/utsname.h> /* for utsname in xl info */
+#include <xenctrl.h>
+#include <ctype.h>
+#include <inttypes.h>
+
+#include "libxl.h"
+#include "libxl_utils.h"
+#include "libxlutil.h"
+#include "xl.h"
+
+#define UUID_FMT 
"%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
+
+#define CHK_ERRNO( call ) ({                                            \
+        int chk_errno = (call);                                         \
+        if (chk_errno < 0) {                                                \
+            fprintf(stderr,"xl: fatal error: %s:%d: %s: %s\n",          \
+                    __FILE__,__LINE__, strerror(chk_errno), #call);     \
+            exit(-ERROR_FAIL);                                          \
+        }                                                               \
+    })
+
+#define MUST( call ) ({                                                 \
+        int must_rc = (call);                                           \
+        if (must_rc < 0) {                                                  \
+            fprintf(stderr,"xl: fatal error: %s:%d, rc=%d: %s\n",       \
+                    __FILE__,__LINE__, must_rc, #call);                 \
+            exit(-must_rc);                                             \
+        }                                                               \
+    })
+
+
+int logfile = 2;
+
+/* every libxl action in xl uses this same libxl context */
+struct libxl_ctx ctx;
+
+/* when we operate on a domain, it is this one: */
+static uint32_t domid;
+static const char *common_domname;
+
+
+static const char savefileheader_magic[32]=
+    "Xen saved domain, xl format\n \0 \r";
+
+static const char migrate_receiver_banner[]=
+    "xl migration receiver ready, send binary domain data.\n";
+static const char migrate_receiver_ready[]=
+    "domain received, ready to unpause";
+static const char migrate_permission_to_go[]=
+    "domain is yours, you are cleared to unpause";
+static const char migrate_report[]=
+    "my copy unpause results are as follows";
+  /* followed by one byte:
+   *     0: everything went well, domain is running
+   *            next thing is we all exit
+   * non-0: things went badly
+   *            next thing should be a migrate_permission_to_go
+   *            from target to source
+   */
+
+struct save_file_header {
+    char magic[32]; /* savefileheader_magic */
+    /* All uint32_ts are in domain's byte order. */
+    uint32_t byteorder; /* SAVEFILE_BYTEORDER_VALUE */
+    uint32_t mandatory_flags; /* unknown flags => reject restore */
+    uint32_t optional_flags; /* unknown flags => reject restore */
+    uint32_t optional_data_len; /* skip, or skip tail, if not understood */
+};
+
+/* Optional data, in order:
+ *   4 bytes uint32_t  config file size
+ *   n bytes           config file in Unix text file format
+ */
+
+#define SAVEFILE_BYTEORDER_VALUE ((uint32_t)0x01020304UL)
+
+static int qualifier_to_id(const char *p, uint32_t *id_r)
+{
+    int i, alldigit;
+
+    alldigit = 1;
+    for (i = 0; p[i]; i++) {
+        if (!isdigit((uint8_t)p[i])) {
+            alldigit = 0;
+            break;
+        }
+    }
+
+    if (i > 0 && alldigit) {
+        *id_r = strtoul(p, NULL, 10);
+        return 0;
+    } else {
+        /* check here if it's a uuid and do proper conversion */
+    }
+    return 1;
+}
+
+static int domain_qualifier_to_domid(const char *p, uint32_t *domid_r,
+                                     int *was_name_r)
+{
+    int was_name;
+
+    was_name = qualifier_to_id(p, domid_r);
+    if (was_name_r) *was_name_r = was_name;
+    return was_name ? libxl_name_to_domid(&ctx, p, domid_r) : 0;
+}
+
+static void find_domain(const char *p)
+{
+    int rc, was_name;
+
+    rc = domain_qualifier_to_domid(p, &domid, &was_name);
+    if (rc) {
+        fprintf(stderr, "%s is an invalid domain identifier (rc=%d)\n", p, rc);
+        exit(2);
+    }
+    common_domname = was_name ? p : libxl_domid_to_name(&ctx, domid);
+}
+
+#define LOG(_f, _a...)   dolog(__FILE__, __LINE__, __func__, _f "\n", ##_a)
+
+void dolog(const char *file, int line, const char *func, char *fmt, ...)
+{
+    va_list ap;
+    char *s;
+    int rc;
+
+    va_start(ap, fmt);
+    rc = vasprintf(&s, fmt, ap);
+    va_end(ap);
+    if (rc >= 0)
+        libxl_write_exactly(NULL, logfile, s, rc, NULL, NULL);
+}
+
+static 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->hap = 1;
+    c_info->hvm = 1;
+    c_info->oos = 1;
+    c_info->ssidref = 0;
+}
+
+static 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->target_memkb = b_info->max_memkb;
+    if (c_info->hvm) {
+        b_info->shadow_memkb = 0; /* Set later */
+        b_info->video_memkb = 8 * 1024;
+        b_info->kernel = "hvmloader";
+        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;
+    } else {
+        b_info->u.pv.slack_memkb = 8 * 1024;
+    }
+}
+
+static void init_dm_info(libxl_device_model_info *dm_info,
+        libxl_domain_create_info *c_info, libxl_domain_build_info *b_info)
+{
+    int i;
+    memset(dm_info, '\0', sizeof(*dm_info));
+
+    for (i = 0; i < 16; i++) {
+        dm_info->uuid[i] = rand();
+    }
+
+    dm_info->dom_name = c_info->name;
+    dm_info->device_model = "qemu-dm";
+    dm_info->videoram = b_info->video_memkb / 1024;
+    dm_info->apic = b_info->u.hvm.apic;
+    dm_info->vcpus = b_info->max_vcpus;
+    dm_info->vcpu_avail = b_info->cur_vcpus;
+
+    dm_info->stdvga = 0;
+    dm_info->vnc = 1;
+    dm_info->vnclisten = "127.0.0.1";
+    dm_info->vncdisplay = 0;
+    dm_info->vncunused = 1;
+    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;
+    dm_info->xen_platform_pci = 1;
+}
+
+static 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";
+    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)));
+    nic_info->ifname = NULL;
+    nic_info->bridge = "xenbr0";
+    CHK_ERRNO( asprintf(&nic_info->script, "%s/vif-bridge",
+               libxl_xen_script_dir_path()) );
+    nic_info->nictype = NICTYPE_IOEMU;
+}
+
+static void init_vfb_info(libxl_device_vfb *vfb, int dev_num)
+{
+    memset(vfb, 0x00, sizeof(libxl_device_vfb));
+    vfb->devid = dev_num;
+    vfb->vnc = 1;
+    vfb->vnclisten = "127.0.0.1";
+    vfb->vncdisplay = 0;
+    vfb->vncunused = 1;
+    vfb->keymap = NULL;
+    vfb->sdl = 0;
+    vfb->opengl = 0;
+}
+
+static void init_vkb_info(libxl_device_vkb *vkb, int dev_num)
+{
+    memset(vkb, 0x00, sizeof(libxl_device_vkb));
+    vkb->devid = dev_num;
+}
+
+static void init_console_info(libxl_device_console *console, int dev_num, 
libxl_domain_build_state *state)
+{
+    memset(console, 0x00, sizeof(libxl_device_console));
+    console->devid = dev_num;
+    console->constype = CONSTYPE_XENCONSOLED;
+    if (state)
+        console->build_state = state;
+}
+
+static void printf_info(int domid,
+                        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_pci *pcidevs,
+                        int num_pcidevs,
+                        libxl_device_vfb *vfbs,
+                        int num_vfbs,
+                        libxl_device_vkb *vkb,
+                        int num_vkbs,
+                        libxl_device_model_info *dm_info)
+{
+    int i;
+    printf("(domain\n\t(domid %d)\n", domid);
+    printf("\t(domain_create_info)\n");
+    printf("\t(hvm %d)\n", c_info->hvm);
+    printf("\t(hap %d)\n", c_info->hap);
+    printf("\t(oos %d)\n", c_info->oos);
+    printf("\t(ssidref %d)\n", c_info->ssidref);
+    printf("\t(name %s)\n", c_info->name);
+    printf("\t(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("\t(xsdata contains data)\n");
+    else
+        printf("\t(xsdata (null))\n");
+    if (c_info->platformdata)
+        printf("\t(platformdata contains data)\n");
+    else
+        printf("\t(platformdata (null))\n");
+
+
+    printf("\t(domain_build_info)\n");
+    printf("\t(timer_mode %d)\n", b_info->timer_mode);
+    printf("\t(hpet %d)\n", b_info->hpet);
+    printf("\t(vpt_align %d)\n", b_info->vpt_align);
+    printf("\t(max_vcpus %d)\n", b_info->max_vcpus);
+    printf("\t(tsc_mode %d)\n", b_info->tsc_mode);
+    printf("\t(max_memkb %d)\n", b_info->max_memkb);
+    printf("\t(target_memkb %d)\n", b_info->target_memkb);
+
+    printf("\t(image\n");
+    if (c_info->hvm) {
+        printf("\t\t(hvm\n");
+        printf("\t\t\t(loader %s)\n", b_info->kernel);
+        printf("\t\t\t(video_memkb %d)\n", b_info->video_memkb);
+        printf("\t\t\t(shadow_memkb %d)\n", b_info->shadow_memkb);
+        printf("\t\t\t(pae %d)\n", b_info->u.hvm.pae);
+        printf("\t\t\t(apic %d)\n", b_info->u.hvm.apic);
+        printf("\t\t\t(acpi %d)\n", b_info->u.hvm.acpi);
+        printf("\t\t\t(nx %d)\n", b_info->u.hvm.nx);
+        printf("\t\t\t(viridian %d)\n", b_info->u.hvm.viridian);
+
+        printf("\t\t\t(device_model %s)\n", dm_info->device_model);
+        printf("\t\t\t(videoram %d)\n", dm_info->videoram);
+        printf("\t\t\t(stdvga %d)\n", dm_info->stdvga);
+        printf("\t\t\t(vnc %d)\n", dm_info->vnc);
+        printf("\t\t\t(vnclisten %s)\n", dm_info->vnclisten);
+        printf("\t\t\t(vncdisplay %d)\n", dm_info->vncdisplay);
+        printf("\t\t\t(vncunused %d)\n", dm_info->vncunused);
+        printf("\t\t\t(keymap %s)\n", dm_info->keymap);
+        printf("\t\t\t(sdl %d)\n", dm_info->sdl);
+        printf("\t\t\t(opengl %d)\n", dm_info->opengl);
+        printf("\t\t\t(nographic %d)\n", dm_info->nographic);
+        printf("\t\t\t(serial %s)\n", dm_info->serial);
+        printf("\t\t\t(boot %s)\n", dm_info->boot);
+        printf("\t\t\t(usb %d)\n", dm_info->usb);
+        printf("\t\t\t(usbdevice %s)\n", dm_info->usbdevice);
+        printf("\t\t\t(apic %d)\n", dm_info->apic);
+        printf("\t\t)\n");
+    } else {
+        printf("\t\t(linux %d)\n", b_info->hvm);
+        printf("\t\t\t(kernel %s)\n", b_info->kernel);
+        printf("\t\t\t(cmdline %s)\n", b_info->u.pv.cmdline);
+        printf("\t\t\t(ramdisk %s)\n", b_info->u.pv.ramdisk);
+        printf("\t\t)\n");
+    }
+    printf("\t)\n");
+
+    for (i = 0; i < num_disks; i++) {
+        printf("\t(device\n");
+        printf("\t\t(tap\n");
+        printf("\t\t\t(backend_domid %d)\n", disks[i].backend_domid);
+        printf("\t\t\t(domid %d)\n", disks[i].domid);
+        printf("\t\t\t(physpath %s)\n", disks[i].physpath);
+        printf("\t\t\t(phystype %d)\n", disks[i].phystype);
+        printf("\t\t\t(virtpath %s)\n", disks[i].virtpath);
+        printf("\t\t\t(unpluggable %d)\n", disks[i].unpluggable);
+        printf("\t\t\t(readwrite %d)\n", disks[i].readwrite);
+        printf("\t\t\t(is_cdrom %d)\n", disks[i].is_cdrom);
+        printf("\t\t)\n");
+        printf("\t)\n");
+    }
+
+    for (i = 0; i < num_vifs; i++) {
+        printf("\t(device\n");
+        printf("\t\t(vif\n");
+        printf("\t\t\t(backend_domid %d)\n", vifs[i].backend_domid);
+        printf("\t\t\t(domid %d)\n", vifs[i].domid);
+        printf("\t\t\t(devid %d)\n", vifs[i].devid);
+        printf("\t\t\t(mtu %d)\n", vifs[i].mtu);
+        printf("\t\t\t(model %s)\n", vifs[i].model);
+        printf("\t\t\t(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("\t\t)\n");
+        printf("\t)\n");
+    }
+
+    for (i = 0; i < num_pcidevs; i++) {
+        printf("\t(device\n");
+        printf("\t\t(pci\n");
+        printf("\t\t\t(pci dev "PCI_BDF_VDEVFN")\n", pcidevs[i].domain, 
pcidevs[i].bus, pcidevs[i].dev, pcidevs[i].func, pcidevs[i].vdevfn);
+        printf("\t\t\t(opts msitranslate %d power_mgmt %d)\n", 
pcidevs[i].msitranslate, pcidevs[i].power_mgmt);
+        printf("\t\t)\n");
+        printf("\t)\n");
+    }
+
+    for (i = 0; i < num_vfbs; i++) {
+        printf("\t(device\n");
+        printf("\t\t(vfb\n");
+        printf("\t\t\t(backend_domid %d)\n", vfbs[i].backend_domid);
+        printf("\t\t\t(domid %d)\n", vfbs[i].domid);
+        printf("\t\t\t(devid %d)\n", vfbs[i].devid);
+        printf("\t\t\t(vnc %d)\n", vfbs[i].vnc);
+        printf("\t\t\t(vnclisten %s)\n", vfbs[i].vnclisten);
+        printf("\t\t\t(vncdisplay %d)\n", vfbs[i].vncdisplay);
+        printf("\t\t\t(vncunused %d)\n", vfbs[i].vncunused);
+        printf("\t\t\t(keymap %s)\n", vfbs[i].keymap);
+        printf("\t\t\t(sdl %d)\n", vfbs[i].sdl);
+        printf("\t\t\t(opengl %d)\n", vfbs[i].opengl);
+        printf("\t\t\t(display %s)\n", vfbs[i].display);
+        printf("\t\t\t(xauthority %s)\n", vfbs[i].xauthority);
+        printf("\t\t)\n");
+        printf("\t)\n");
+    }
+       printf(")\n");
+}
+
+static void parse_config_data(const char *configfile_filename_report,
+                              const char *configfile_data,
+                              int configfile_len,
+                              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_pci **pcidevs,
+                              int *num_pcidevs,
+                              libxl_device_vfb **vfbs,
+                              int *num_vfbs,
+                              libxl_device_vkb **vkbs,
+                              int *num_vkbs,
+                              libxl_device_model_info *dm_info)
+{
+    const char *buf;
+    long l;
+    XLU_Config *config;
+    XLU_ConfigList *vbds, *nics, *pcis, *cvfbs;
+    int pci_power_mgmt = 0;
+    int pci_msitranslate = 1;
+    int i, e;
+
+    config= xlu_cfg_init(stderr, configfile_filename_report);
+    if (!config) {
+        fprintf(stderr, "Failed to allocate for configuration\n");
+        exit(1);
+    }
+
+    e= xlu_cfg_readdata(config, configfile_data, configfile_len);
+    if (e) {
+        fprintf(stderr, "Failed to parse config file: %s\n", strerror(e));
+        exit(1);
+    }
+
+    init_create_info(c_info);
+
+    c_info->hvm = 0;
+    if (!xlu_cfg_get_string (config, "builder", &buf) &&
+        !strncmp(buf, "hvm", strlen(buf)))
+        c_info->hvm = 1;
+
+    if (!xlu_cfg_get_long (config, "hap", &l))
+        c_info->hap = l;
+
+    if (!xlu_cfg_get_string (config, "name", &buf))
+        c_info->name = strdup(buf);
+    else
+        c_info->name = "test";
+    for (i = 0; i < 16; i++) {
+        c_info->uuid[i] = rand();
+    }
+
+    if (!xlu_cfg_get_long(config, "oos", &l))
+        c_info->oos = l;
+
+    init_build_info(b_info, c_info);
+
+    /* the following is the actual config parsing with overriding values in 
the structures */
+    if (!xlu_cfg_get_long (config, "vcpus", &l)) {
+        b_info->max_vcpus = l;
+        b_info->cur_vcpus = (1 << l) - 1;
+    }
+
+    if (!xlu_cfg_get_long (config, "memory", &l)) {
+        b_info->max_memkb = l * 1024;
+        b_info->target_memkb = b_info->max_memkb;
+    }
+
+    /* libxl_get_required_shadow_memory() must be called after final values
+     * (default or specified) for vcpus and memory are set, because the
+     * calculation depends on those values. */
+    b_info->shadow_memkb = !xlu_cfg_get_long(config, "shadow_memory", &l)
+        ? l * 1024
+        : libxl_get_required_shadow_memory(b_info->max_memkb,
+                                           b_info->max_vcpus);
+
+    if (!xlu_cfg_get_long(config, "tsc_mode", &l))
+        b_info->tsc_mode = l;
+
+    if (!xlu_cfg_get_long (config, "videoram", &l))
+        b_info->video_memkb = l * 1024;
+
+    if (!xlu_cfg_get_string (config, "kernel", &buf))
+        b_info->kernel = strdup(buf);
+
+    if (c_info->hvm == 1) {
+        if (!xlu_cfg_get_long (config, "pae", &l))
+            b_info->u.hvm.pae = l;
+        if (!xlu_cfg_get_long (config, "apic", &l))
+            b_info->u.hvm.apic = l;
+        if (!xlu_cfg_get_long (config, "acpi", &l))
+            b_info->u.hvm.acpi = l;
+        if (!xlu_cfg_get_long (config, "nx", &l))
+            b_info->u.hvm.nx = l;
+        if (!xlu_cfg_get_long (config, "viridian", &l))
+            b_info->u.hvm.viridian = l;
+    } else {
+        char *cmdline = NULL;
+        const char *root = NULL, *extra = "";
+
+        xlu_cfg_get_string (config, "root", &root);
+        xlu_cfg_get_string (config, "extra", &extra);
+
+        if (root) {
+            if (asprintf(&cmdline, "root=%s %s", root, extra) == -1)
+                cmdline = NULL;
+        } else {
+            cmdline = strdup(extra);
+        }
+
+        if ((root || extra) && !cmdline) {
+            fprintf(stderr, "Failed to allocate memory for cmdline\n");
+            exit(1);
+        }
+
+        b_info->u.pv.cmdline = cmdline;
+        if (!xlu_cfg_get_string (config, "ramdisk", &buf))
+            b_info->u.pv.ramdisk = strdup(buf);
+    }
+
+    if (!xlu_cfg_get_list (config, "disk", &vbds, 0)) {
+        *num_disks = 0;
+        *disks = NULL;
+        while ((buf = xlu_cfg_get_listitem (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;
+                (*disks)[*num_disks].unpluggable = 1;
+            } else {
+                *p2 = '\0';
+                (*disks)[*num_disks].virtpath = strdup(p);
+                if (!strcmp(p2 + 1, "cdrom")) {
+                    (*disks)[*num_disks].is_cdrom = 1;
+                    (*disks)[*num_disks].unpluggable = 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 (!xlu_cfg_get_list (config, "vif", &nics, 0)) {
+        *num_vifs = 0;
+        *vifs = NULL;
+        while ((buf = xlu_cfg_get_listitem (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;
+                    *(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;
+        }
+    }
+
+    if (!xlu_cfg_get_list (config, "vfb", &cvfbs, 0)) {
+        *num_vfbs = 0;
+        *num_vkbs = 0;
+        *vfbs = NULL;
+        *vkbs = NULL;
+        while ((buf = xlu_cfg_get_listitem (cvfbs, *num_vfbs)) != NULL) {
+            char *buf2 = strdup(buf);
+            char *p, *p2;
+            *vfbs = (libxl_device_vfb *) realloc(*vfbs, 
sizeof(libxl_device_vfb) * ((*num_vfbs) + 1));
+            init_vfb_info((*vfbs) + (*num_vfbs), (*num_vfbs));
+
+            *vkbs = (libxl_device_vkb *) realloc(*vkbs, 
sizeof(libxl_device_vkb) * ((*num_vkbs) + 1));
+            init_vkb_info((*vkbs) + (*num_vkbs), (*num_vkbs));
+
+            p = strtok(buf2, ",");
+            if (!p)
+                goto skip_vfb;
+            do {
+                while (*p == ' ')
+                    p++;
+                if ((p2 = strchr(p, '=')) == NULL)
+                    break;
+                *p2 = '\0';
+                if (!strcmp(p, "vnc")) {
+                    (*vfbs)[*num_vfbs].vnc = atoi(p2 + 1);
+                } else if (!strcmp(p, "vnclisten")) {
+                    (*vfbs)[*num_vfbs].vnclisten = strdup(p2 + 1);
+                } else if (!strcmp(p, "vncpasswd")) {
+                    (*vfbs)[*num_vfbs].vncpasswd = strdup(p2 + 1);
+                } else if (!strcmp(p, "vncdisplay")) {
+                    (*vfbs)[*num_vfbs].vncdisplay = atoi(p2 + 1);
+                } else if (!strcmp(p, "vncunused")) {
+                    (*vfbs)[*num_vfbs].vncunused = atoi(p2 + 1);
+                } else if (!strcmp(p, "keymap")) {
+                    (*vfbs)[*num_vfbs].keymap = strdup(p2 + 1);
+                } else if (!strcmp(p, "sdl")) {
+                    (*vfbs)[*num_vfbs].sdl = atoi(p2 + 1);
+                } else if (!strcmp(p, "opengl")) {
+                    (*vfbs)[*num_vfbs].opengl = atoi(p2 + 1);
+                } else if (!strcmp(p, "display")) {
+                    (*vfbs)[*num_vfbs].display = strdup(p2 + 1);
+                } else if (!strcmp(p, "xauthority")) {
+                    (*vfbs)[*num_vfbs].xauthority = strdup(p2 + 1);
+                }
+            } while ((p = strtok(NULL, ",")) != NULL);
+skip_vfb:
+            free(buf2);
+            *num_vfbs = (*num_vfbs) + 1;
+            *num_vkbs = (*num_vkbs) + 1;
+        }
+    }
+
+    if (!xlu_cfg_get_long (config, "pci_msitranslate", &l))
+        pci_msitranslate = l;
+
+    if (!xlu_cfg_get_long (config, "pci_power_mgmt", &l))
+        pci_power_mgmt = l;
+
+    if (!xlu_cfg_get_list (config, "pci", &pcis, 0)) {
+        *num_pcidevs = 0;
+        *pcidevs = NULL;
+        while ((buf = xlu_cfg_get_listitem (pcis, *num_pcidevs)) != NULL) {
+            unsigned int domain = 0, bus = 0, dev = 0, func = 0, vdevfn = 0;
+            char *buf2 = strdup(buf);
+            char *p;
+            *pcidevs = (libxl_device_pci *) realloc(*pcidevs, sizeof 
(libxl_device_pci) * ((*num_pcidevs) + 1));
+            memset(*pcidevs + *num_pcidevs, 0x00, sizeof(libxl_device_pci));
+            p = strtok(buf2, ",");
+            if (!p)
+                goto skip_pci;
+            if (!sscanf(p, PCI_BDF_VDEVFN, &domain, &bus, &dev, &func, 
&vdevfn)) {
+                sscanf(p, "%02x:%02x.%01x@%02x", &bus, &dev, &func, &vdevfn);
+                domain = 0;
+            }
+            libxl_device_pci_init(*pcidevs + *num_pcidevs, domain, bus, dev, 
func, vdevfn);
+            (*pcidevs)[*num_pcidevs].msitranslate = pci_msitranslate;
+            (*pcidevs)[*num_pcidevs].power_mgmt = pci_power_mgmt;
+            while ((p = strtok(NULL, ",=")) != NULL) {
+                while (*p == ' ')
+                    p++;
+                if (!strcmp(p, "msitranslate")) {
+                    p = strtok(NULL, ",=");
+                    (*pcidevs)[*num_pcidevs].msitranslate = atoi(p);
+                } else if (!strcmp(p, "power_mgmt")) {
+                    p = strtok(NULL, ",=");
+                    (*pcidevs)[*num_pcidevs].power_mgmt = atoi(p);
+                }
+            }
+            *num_pcidevs = (*num_pcidevs) + 1;
+skip_pci:
+            free(buf2);
+        }
+    }
+
+    if (c_info->hvm == 1) {
+        /* init dm from c and b */
+        init_dm_info(dm_info, c_info, b_info);
+
+        /* then process config related to dm */
+        if (!xlu_cfg_get_string (config, "device_model", &buf))
+            dm_info->device_model = strdup(buf);
+        if (!xlu_cfg_get_long (config, "stdvga", &l))
+            dm_info->stdvga = l;
+        if (!xlu_cfg_get_long (config, "vnc", &l))
+            dm_info->vnc = l;
+        if (!xlu_cfg_get_string (config, "vnclisten", &buf))
+            dm_info->vnclisten = strdup(buf);
+        if (!xlu_cfg_get_string (config, "vncpasswd", &buf))
+            dm_info->vncpasswd = strdup(buf);
+        if (!xlu_cfg_get_long (config, "vncdisplay", &l))
+            dm_info->vncdisplay = l;
+        if (!xlu_cfg_get_long (config, "vncunused", &l))
+            dm_info->vncunused = l;
+        if (!xlu_cfg_get_string (config, "keymap", &buf))
+            dm_info->keymap = strdup(buf);
+        if (!xlu_cfg_get_long (config, "sdl", &l))
+            dm_info->sdl = l;
+        if (!xlu_cfg_get_long (config, "opengl", &l))
+            dm_info->opengl = l;
+        if (!xlu_cfg_get_long (config, "nographic", &l))
+            dm_info->nographic = l;
+        if (!xlu_cfg_get_string (config, "serial", &buf))
+            dm_info->serial = strdup(buf);
+        if (!xlu_cfg_get_string (config, "boot", &buf))
+            dm_info->boot = strdup(buf);
+        if (!xlu_cfg_get_long (config, "usb", &l))
+            dm_info->usb = l;
+        if (!xlu_cfg_get_string (config, "usbdevice", &buf))
+            dm_info->usbdevice = strdup(buf);
+        if (!xlu_cfg_get_long (config, "xen_platform_pci", &l))
+            dm_info->xen_platform_pci = l;
+    }
+
+    dm_info->type = c_info->hvm ? XENFV : XENPV;
+
+    xlu_cfg_destroy(config);
+}
+
+static void *xmalloc(size_t sz) {
+    void *r;
+    r = malloc(sz);
+    if (!r) { fprintf(stderr,"xl: Unable to malloc %lu bytes.\n",
+                      (unsigned long)sz); exit(-ERROR_FAIL); }
+    return r;
+}
+
+static void *xrealloc(void *ptr, size_t sz) {
+    void *r;
+    if (!sz) { free(ptr); return 0; }
+      /* realloc(non-0, 0) has a useless return value;
+       * but xrealloc(anything, 0) is like free
+       */
+    r = realloc(ptr, sz);
+    if (!r) { fprintf(stderr,"xl: Unable to realloc to %lu bytes.\n",
+                      (unsigned long)sz); exit(-ERROR_FAIL); }
+    return r;
+}
+
+struct domain_create {
+    int debug;
+    int daemonize;
+    int paused;
+    int dryrun;
+    int quiet;
+    const char *config_file;
+    const char *extra_config; /* extra config string */
+    const char *restore_file;
+    int migrate_fd; /* -1 means none */
+    char **migration_domname_r;
+};
+
+static int create_domain(struct domain_create *dom_info)
+{
+    libxl_domain_create_info info1;
+    libxl_domain_build_info info2;
+    libxl_domain_build_state state;
+    libxl_device_model_info dm_info;
+    libxl_device_disk *disks = NULL;
+    libxl_device_nic *vifs = NULL;
+    libxl_device_pci *pcidevs = NULL;
+    libxl_device_vfb *vfbs = NULL;
+    libxl_device_vkb *vkbs = NULL;
+    libxl_device_console console;
+
+    int debug = dom_info->debug;
+    int daemonize = dom_info->daemonize;
+    int paused = dom_info->paused;
+    const char *config_file = dom_info->config_file;
+    const char *extra_config = dom_info->extra_config;
+    const char *restore_file = dom_info->restore_file;
+    int migrate_fd = dom_info->migrate_fd;
+    char **migration_domname_r = dom_info->migration_domname_r;
+
+    int num_disks = 0, num_vifs = 0, num_pcidevs = 0, num_vfbs = 0, num_vkbs = 
0;
+    int i, fd;
+    int need_daemon = 1;
+    int ret, rc;
+    libxl_device_model_starting *dm_starting = 0;
+    libxl_waiter *w1 = NULL, *w2 = NULL;
+    void *config_data = 0;
+    int config_len = 0;
+    int restore_fd = -1;
+    struct save_file_header hdr;
+
+    memset(&dm_info, 0x00, sizeof(dm_info));
+
+    if (restore_file) {
+        uint8_t *optdata_begin = 0;
+        const uint8_t *optdata_here = 0;
+        union { uint32_t u32; char b[4]; } u32buf;
+        uint32_t badflags;
+
+        restore_fd = migrate_fd >= 0 ? migrate_fd :
+            open(restore_file, O_RDONLY);
+
+        CHK_ERRNO( libxl_read_exactly(&ctx, restore_fd, &hdr,
+                   sizeof(hdr), restore_file, "header") );
+        if (memcmp(hdr.magic, savefileheader_magic, sizeof(hdr.magic))) {
+            fprintf(stderr, "File has wrong magic number -"
+                    " corrupt or for a different tool?\n");
+            return ERROR_INVAL;
+        }
+        if (hdr.byteorder != SAVEFILE_BYTEORDER_VALUE) {
+            fprintf(stderr, "File has wrong byte order\n");
+            return ERROR_INVAL;
+        }
+        fprintf(stderr, "Loading new save file %s"
+                " (new xl fmt info"
+                " 0x%"PRIx32"/0x%"PRIx32"/%"PRIu32")\n",
+                restore_file, hdr.mandatory_flags, hdr.optional_flags,
+                hdr.optional_data_len);
+
+        badflags = hdr.mandatory_flags & ~( 0 /* none understood yet */ );
+        if (badflags) {
+            fprintf(stderr, "Savefile has mandatory flag(s) 0x%"PRIx32" "
+                    "which are not supported; need newer xl\n",
+                    badflags);
+            return ERROR_INVAL;
+        }
+        if (hdr.optional_data_len) {
+            optdata_begin = xmalloc(hdr.optional_data_len);
+            CHK_ERRNO( libxl_read_exactly(&ctx, restore_fd, optdata_begin,
+                   hdr.optional_data_len, restore_file, "optdata") );
+        }
+
+#define OPTDATA_LEFT  (hdr.optional_data_len - (optdata_here - optdata_begin))
+#define WITH_OPTDATA(amt, body)                                 \
+            if (OPTDATA_LEFT < (amt)) {                         \
+                fprintf(stderr, "Savefile truncated.\n");       \
+                return ERROR_INVAL;                             \
+            } else {                                            \
+                body;                                           \
+                optdata_here += (amt);                          \
+            }
+
+        optdata_here = optdata_begin;
+
+        if (OPTDATA_LEFT) {
+            fprintf(stderr, " Savefile contains xl domain config\n");
+            WITH_OPTDATA(4, {
+                memcpy(u32buf.b, optdata_here, 4);
+                config_len = u32buf.u32;
+            });
+            WITH_OPTDATA(config_len, {
+                config_data = xmalloc(config_len);
+                memcpy(config_data, optdata_here, config_len);
+            });
+        }
+
+    }
+
+    if (config_file) {
+        free(config_data);  config_data = 0;
+        ret = libxl_read_file_contents(&ctx, config_file,
+                                       &config_data, &config_len);
+        if (ret) { fprintf(stderr, "Failed to read config file: %s: %s\n",
+                           config_file, strerror(errno)); return ERROR_FAIL; }
+        if (!restore_file && extra_config
+            && strlen(extra_config)) {
+            if (config_len > INT_MAX - (strlen(extra_config) + 2)) {
+                fprintf(stderr, "Failed to attach extra configration\n");
+                return ERROR_FAIL;
+            }
+            config_data = realloc(config_data, config_len
+                + strlen(extra_config) + 2);
+            if (!config_data) {
+                fprintf(stderr, "Failed to realloc config_data\n");
+                return ERROR_FAIL;
+            }
+            strcat(config_data, "\n");
+            strcat(config_data, extra_config);
+            strcat(config_data, "\n");
+            config_len += (strlen(extra_config) + 2);
+        }
+    } else {
+        if (!config_data) {
+            fprintf(stderr, "Config file not specified and"
+                    " none in save file\n");
+            return ERROR_INVAL;
+        }
+        config_file = "<saved>";
+    }
+
+    if (!dom_info->quiet)
+        printf("Parsing config file %s\n", config_file);
+
+    parse_config_data(config_file, config_data, config_len, &info1, &info2, 
&disks, &num_disks, &vifs, &num_vifs, &pcidevs, &num_pcidevs, &vfbs, &num_vfbs, 
&vkbs, &num_vkbs, &dm_info);
+
+    if (dom_info->dryrun)
+        return 0;
+
+    if (migrate_fd >= 0) {
+        if (info1.name) {
+            /* when we receive a domain we get its name from the config
+             * file; and we receive it to a temporary name */
+            assert(!common_domname);
+            common_domname = info1.name;
+            if (asprintf(migration_domname_r, "%s--incoming", info1.name) < 0) 
{
+                fprintf(stderr, "Failed to allocate memory in asprintf\n");
+                exit(1);
+            }
+            info1.name = *migration_domname_r;
+        }
+    }
+
+    if (debug)
+        printf_info(-1, &info1, &info2, disks, num_disks, vifs, num_vifs, 
pcidevs, num_pcidevs, vfbs, num_vfbs, vkbs, num_vkbs, &dm_info);
+
+start:
+    domid = 0;
+
+    ret = libxl_domain_make(&ctx, &info1, &domid);
+    if (ret) {
+        fprintf(stderr, "cannot make domain: %d\n", ret);
+        ret = ERROR_FAIL;
+        goto error_out;
+    }
+
+    ret = libxl_userdata_store(&ctx, domid, "xl",
+                                    config_data, config_len);
+    if (ret) {
+        perror("cannot save config file");
+        ret = ERROR_FAIL;
+        goto error_out;
+    }
+
+    if (!restore_file || !need_daemon) {
+        if (dm_info.saved_state) {
+            free(dm_info.saved_state);
+            dm_info.saved_state = NULL;
+        }
+        ret = libxl_domain_build(&ctx, &info2, domid, &state);
+    } else {
+        ret = libxl_domain_restore(&ctx, &info2, domid, restore_fd, &state, 
&dm_info);
+    }
+
+    if (ret) {
+        fprintf(stderr, "cannot (re-)build domain: %d\n", ret);
+        ret = ERROR_FAIL;
+        goto error_out;
+    }
+
+    for (i = 0; i < num_disks; i++) {
+        disks[i].domid = domid;
+        ret = libxl_device_disk_add(&ctx, domid, &disks[i]);
+        if (ret) {
+            fprintf(stderr, "cannot add disk %d to domain: %d\n", i, ret);
+            ret = ERROR_FAIL;
+            goto error_out;
+        }
+    }
+    for (i = 0; i < num_vifs; i++) {
+        vifs[i].domid = domid;
+        ret = libxl_device_nic_add(&ctx, domid, &vifs[i]);
+        if (ret) {
+            fprintf(stderr, "cannot add nic %d to domain: %d\n", i, ret);
+            ret = ERROR_FAIL;
+            goto error_out;
+        }
+    }
+    if (info1.hvm) {
+        dm_info.domid = domid;
+        MUST( libxl_create_device_model(&ctx, &dm_info, disks, num_disks,
+                                        vifs, num_vifs, &dm_starting) );
+    } else {
+        for (i = 0; i < num_vfbs; i++) {
+            vfbs[i].domid = domid;
+            libxl_device_vfb_add(&ctx, domid, &vfbs[i]);
+            vkbs[i].domid = domid;
+            libxl_device_vkb_add(&ctx, domid, &vkbs[i]);
+        }
+        init_console_info(&console, 0, &state);
+        console.domid = domid;
+        if (num_vfbs)
+            console.constype = CONSTYPE_IOEMU;
+        libxl_device_console_add(&ctx, domid, &console);
+        if (num_vfbs)
+            libxl_create_xenpv_qemu(&ctx, vfbs, 1, &console, &dm_starting);
+    }
+
+    if (dm_starting)
+        MUST( libxl_confirm_device_model_startup(&ctx, dm_starting) );
+    for (i = 0; i < num_pcidevs; i++)
+        libxl_device_pci_add(&ctx, domid, &pcidevs[i]);
+
+    if (!paused)
+        libxl_domain_unpause(&ctx, domid);
+
+    if (!daemonize)
+        return domid; /* caller gets success in parent */
+
+    if (need_daemon) {
+        char *fullname, *name;
+        pid_t child1, got_child;
+        int nullfd;
+
+        child1 = libxl_fork(&ctx);
+        if (child1) {
+            int status;
+            for (;;) {
+                got_child = waitpid(child1, &status, 0);
+                if (got_child == child1) break;
+                assert(got_child == -1);
+                if (errno != EINTR) {
+                    perror("failed to wait for daemonizing child");
+                    ret = ERROR_FAIL;
+                    goto error_out;
+                }
+            }
+            if (status) {
+                libxl_report_child_exitstatus(&ctx, XL_LOG_ERROR,
+                           "daemonizing child", child1, status);
+                ret = ERROR_FAIL;
+                goto error_out;
+            }
+            return domid; /* caller gets success in parent */
+        }
+
+        rc = libxl_ctx_postfork(&ctx);
+        if (rc) {
+            LOG("failed to reinitialise context after fork");
+            exit(-1);
+        }
+
+        if (asprintf(&name, "xl-%s", info1.name) < 0) {
+            LOG("Failed to allocate memory in asprintf");
+            exit(1);
+        }
+        rc = libxl_create_logfile(&ctx, name, &fullname);
+        if (rc) {
+            LOG("failed to open logfile %s",fullname,strerror(errno));
+            exit(-1);
+        }
+
+        CHK_ERRNO(( logfile = open(fullname, O_WRONLY|O_CREAT, 0644) )<0);
+        free(fullname);
+        free(name);
+
+        CHK_ERRNO(( nullfd = open("/dev/null", O_RDONLY) )<0);
+        dup2(nullfd, 0);
+        dup2(logfile, 1);
+        dup2(logfile, 2);
+
+        CHK_ERRNO(daemon(0, 1) < 0);
+        need_daemon = 0;
+    }
+    LOG("Waiting for domain %s (domid %d) to die [pid %ld]",
+        info1.name, domid, (long)getpid());
+    w1 = (libxl_waiter*) xmalloc(sizeof(libxl_waiter) * num_disks);
+    w2 = (libxl_waiter*) xmalloc(sizeof(libxl_waiter));
+    libxl_wait_for_disk_ejects(&ctx, domid, disks, num_disks, w1);
+    libxl_wait_for_domain_death(&ctx, domid, w2);
+    libxl_get_wait_fd(&ctx, &fd);
+    while (1) {
+        int ret;
+        fd_set rfds;
+        xc_domaininfo_t info;
+        libxl_event event;
+        libxl_device_disk disk;
+        memset(&info, 0x00, sizeof(xc_domaininfo_t));
+
+        FD_ZERO(&rfds);
+        FD_SET(fd, &rfds);
+
+        ret = select(fd + 1, &rfds, NULL, NULL, NULL);
+        if (!ret)
+            continue;
+        libxl_get_event(&ctx, &event);
+        switch (event.type) {
+            case DOMAIN_DEATH:
+                if (libxl_event_get_domain_death_info(&ctx, domid, &event, 
&info)) {
+                    LOG("Domain %d is dead", domid);
+                    if (info.flags & XEN_DOMINF_dying || (info.flags & 
XEN_DOMINF_shutdown && (((info.flags >> XEN_DOMINF_shutdownshift) & 
XEN_DOMINF_shutdownmask) != SHUTDOWN_suspend))) {
+                        LOG("Domain %d needs to be clean: destroying the 
domain", domid);
+                        libxl_domain_destroy(&ctx, domid, 0);
+                        if (info.flags & XEN_DOMINF_shutdown &&
+                            (((info.flags >> XEN_DOMINF_shutdownshift) & 
XEN_DOMINF_shutdownmask) == SHUTDOWN_reboot)) {
+                            libxl_free_waiter(w1);
+                            libxl_free_waiter(w2);
+                            free(w1);
+                            free(w2);
+                            LOG("Done. Rebooting now");
+                            /*
+                             * XXX FIXME: If this sleep is not there then
+                             * domain re-creation fails sometimes.
+                             */
+                            sleep(2);
+                            goto start;
+                        }
+                        LOG("Done. Exiting now");
+                    }
+                    LOG("Domain %d does not need to be clean, exiting now", 
domid);
+                    exit(0);
+                }
+                break;
+            case DISK_EJECT:
+                if (libxl_event_get_disk_eject_info(&ctx, domid, &event, 
&disk))
+                    libxl_cdrom_insert(&ctx, domid, &disk);
+                break;
+        }
+        libxl_free_event(&event);
+    }
+
+    close(logfile);
+    exit(0);
+
+error_out:
+    if (domid)
+        libxl_domain_destroy(&ctx, domid, 0);
+    return ret;
+}
+
+void help(char *command)
+{
+    int i;
+    struct cmd_spec *cmd;
+
+    if (!command || !strcmp(command, "help")) {
+        printf("Usage xl [-v] <subcommand> [args]\n\n");
+        printf("xl full list of subcommands:\n\n");
+        for (i = 0; i < cmdtable_len; i++)
+            printf(" %-20s%s\n",
+                   cmd_table[i].cmd_name, cmd_table[i].cmd_desc);
+    } else {
+        cmd = cmdtable_lookup(command);
+        if (cmd) {
+            printf("Usage: xl [-v] %s %s\n\n%s.\n\n",
+                   cmd->cmd_name,
+                   cmd->cmd_usage,
+                   cmd->cmd_desc);
+            if (cmd->cmd_option)
+                printf("Options:\n\n%s\n", cmd->cmd_option);
+        }
+        else {
+            printf("command \"%s\" not implemented\n", command);
+        }
+    }
+}
+
+static int64_t parse_mem_size_kb(char *mem)
+{
+    char *endptr;
+    int64_t kbytes;
+
+    kbytes = strtoll(mem, &endptr, 10);
+
+    if (strlen(endptr) > 1)
+        return -1;
+
+    switch (tolower((uint8_t)*endptr)) {
+    case 't':
+        kbytes <<= 10;
+    case 'g':
+        kbytes <<= 10;
+    case '\0':
+    case 'm':
+        kbytes <<= 10;
+    case 'k':
+        break;
+    case 'b':
+        kbytes >>= 10;
+        break;
+    default:
+        return -1;
+    }
+
+    return kbytes;
+}
+
+int set_memory_max(char *p, char *mem)
+{
+    int64_t memorykb;
+    int rc;
+
+    find_domain(p);
+
+    memorykb = parse_mem_size_kb(mem);
+    if (memorykb == -1) {
+        fprintf(stderr, "invalid memory size: %s\n", mem);
+        exit(3);
+    }
+
+    rc = libxl_domain_setmaxmem(&ctx, domid, memorykb);
+
+    return rc;
+}
+
+int main_memmax(int argc, char **argv)
+{
+    int opt = 0;
+    char *p = NULL, *mem;
+    int rc;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("mem-max");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc - 1) {
+        help("mem-max");
+        exit(2);
+    }
+
+    p = argv[optind];
+    mem = argv[optind + 1];
+
+    rc = set_memory_max(p, mem);
+    if (rc) {
+        fprintf(stderr, "cannot set domid %d static max memory to : %s\n", 
domid, mem);
+        exit(1);
+    }
+
+    exit(0);
+}
+
+void set_memory_target(char *p, char *mem)
+{
+    long long int memorykb;
+
+    find_domain(p);
+
+    memorykb = parse_mem_size_kb(mem);
+    if (memorykb == -1)  {
+        fprintf(stderr, "invalid memory size: %s\n", mem);
+        exit(3);
+    }
+
+    libxl_set_memory_target(&ctx, domid, memorykb, /* enforce */ 1);
+}
+
+int main_memset(int argc, char **argv)
+{
+    int opt = 0;
+    char *p = NULL, *mem;
+
+    while ((opt = getopt(argc, argv, "h:")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("mem-set");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc - 1) {
+        help("mem-set");
+        exit(2);
+    }
+
+    p = argv[optind];
+    mem = argv[optind + 1];
+
+    set_memory_target(p, mem);
+    exit(0);
+}
+
+void console(char *p, int cons_num)
+{
+    find_domain(p);
+    libxl_console_attach(&ctx, domid, cons_num);
+}
+
+void cd_insert(char *dom, char *virtdev, char *phys)
+{
+    libxl_device_disk disk;
+    char *p;
+
+    find_domain(dom);
+
+    disk.backend_domid = 0;
+    disk.domid = domid;
+    if (phys) {
+        p = strchr(phys, ':');
+        if (!p) {
+            fprintf(stderr, "No type specified, ");
+            disk.physpath = phys;
+            if (!strncmp(phys, "/dev", 4)) {
+                fprintf(stderr, "assuming phy:\n");
+                disk.phystype = PHYSTYPE_PHY;
+            } else {
+                fprintf(stderr, "assuming file:\n");
+                disk.phystype = PHYSTYPE_FILE;
+            }
+        } else {
+            *p = '\0';
+            p++;
+            disk.physpath = p;
+            libxl_string_to_phystype(&ctx, phys, &disk.phystype);
+        }
+    } else {
+            disk.physpath = NULL;
+            disk.phystype = 0;
+    }
+    disk.virtpath = virtdev;
+    disk.unpluggable = 1;
+    disk.readwrite = 0;
+    disk.is_cdrom = 1;
+
+    libxl_cdrom_insert(&ctx, domid, &disk);
+}
+
+int main_cd_eject(int argc, char **argv)
+{
+    int opt = 0;
+    char *p = NULL, *virtdev;
+
+    while ((opt = getopt(argc, argv, "hn:")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("cd-eject");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc - 1) {
+        help("cd-eject");
+        exit(2);
+    }
+
+    p = argv[optind];
+    virtdev = argv[optind + 1];
+
+    cd_insert(p, virtdev, NULL);
+    exit(0);
+}
+
+int main_cd_insert(int argc, char **argv)
+{
+    int opt = 0;
+    char *p = NULL, *file = NULL, *virtdev;
+
+    while ((opt = getopt(argc, argv, "hn:")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("cd-insert");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc - 2) {
+        help("cd-insert");
+        exit(2);
+    }
+
+    p = argv[optind];
+    virtdev = argv[optind + 1];
+    file = argv[optind + 2];
+
+    cd_insert(p, virtdev, file);
+    exit(0);
+}
+
+int main_console(int argc, char **argv)
+{
+    int opt = 0, cons_num = 0;
+    char *p = NULL;
+
+    while ((opt = getopt(argc, argv, "hn:")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("console");
+            exit(0);
+        case 'n':
+            if (optarg) {
+                cons_num = strtol(optarg, NULL, 10);
+            }
+            break;
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc) {
+        help("console");
+        exit(2);
+    }
+
+    p = argv[optind];
+
+    console(p, cons_num);
+    exit(0);
+}
+
+void pcilist(char *dom)
+{
+    libxl_device_pci *pcidevs;
+    int num, i;
+
+    find_domain(dom);
+
+    pcidevs = libxl_device_pci_list(&ctx, domid, &num);
+    if (!num)
+        return;
+    printf("VFn  domain bus  slot func\n");
+    for (i = 0; i < num; i++) {
+        printf("0x%02x 0x%04x 0x%02x 0x%02x 0x%01x\n", pcidevs[i].vdevfn, 
pcidevs[i].domain, pcidevs[i].bus, pcidevs[i].dev, pcidevs[i].func);
+    }
+    free(pcidevs);
+}
+
+int main_pcilist(int argc, char **argv)
+{
+    int opt;
+    char *domname = NULL;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("pci-list");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc) {
+        help("pci-list");
+        exit(2);
+    }
+
+    domname = argv[optind];
+
+    pcilist(domname);
+    exit(0);
+}
+
+void pcidetach(char *dom, char *bdf)
+{
+    libxl_device_pci pcidev;
+    unsigned int domain, bus, dev, func;
+
+    find_domain(dom);
+
+    memset(&pcidev, 0x00, sizeof(pcidev));
+    if (sscanf(bdf, PCI_BDF, &domain, &bus, &dev, &func) != 4) {
+        fprintf(stderr, "pci-detach: malformed BDF specification \"%s\"\n", 
bdf);
+        exit(2);
+    }
+    libxl_device_pci_init(&pcidev, domain, bus, dev, func, 0);
+    libxl_device_pci_remove(&ctx, domid, &pcidev);
+}
+
+int main_pcidetach(int argc, char **argv)
+{
+    int opt;
+    char *domname = NULL, *bdf = NULL;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("pci-detach");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc - 1) {
+        help("pci-detach");
+        exit(2);
+    }
+
+    domname = argv[optind];
+    bdf = argv[optind + 1];
+
+    pcidetach(domname, bdf);
+    exit(0);
+}
+void pciattach(char *dom, char *bdf, char *vs)
+{
+    libxl_device_pci pcidev;
+    unsigned int domain, bus, dev, func;
+
+    find_domain(dom);
+
+    memset(&pcidev, 0x00, sizeof(pcidev));
+    if (sscanf(bdf, PCI_BDF, &domain, &bus, &dev, &func) != 4) {
+        fprintf(stderr, "pci-attach: malformed BDF specification \"%s\"\n", 
bdf);
+        exit(2);
+    }
+    libxl_device_pci_init(&pcidev, domain, bus, dev, func, 0);
+    libxl_device_pci_add(&ctx, domid, &pcidev);
+}
+
+int main_pciattach(int argc, char **argv)
+{
+    int opt;
+    char *domname = NULL, *bdf = NULL, *vs = NULL;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("pci-attach");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc - 1) {
+        help("pci-attach");
+        exit(2);
+    }
+
+    domname = argv[optind];
+    bdf = argv[optind + 1];
+
+    if (optind + 1 < argc)
+        vs = argv[optind + 2];
+
+    pciattach(domname, bdf, vs);
+    exit(0);
+}
+
+void pause_domain(char *p)
+{
+    find_domain(p);
+    libxl_domain_pause(&ctx, domid);
+}
+
+void unpause_domain(char *p)
+{
+    find_domain(p);
+    libxl_domain_unpause(&ctx, domid);
+}
+
+void destroy_domain(char *p)
+{
+    int rc;
+    find_domain(p);
+    if (domid == 0) {
+        fprintf(stderr, "Cannot destroy privileged domain 0.\n\n");
+        exit(-1);
+    }
+    rc = libxl_domain_destroy(&ctx, domid, 0);
+    if (rc) { fprintf(stderr,"destroy failed (rc=%d)\n.",rc); exit(-1); }
+}
+
+void shutdown_domain(char *p)
+{
+    int rc;
+    find_domain(p);
+    rc=libxl_domain_shutdown(&ctx, domid, 0);
+    if (rc) { fprintf(stderr,"shutdown failed (rc=%d)\n.",rc);exit(-1); }
+}
+
+void reboot_domain(char *p)
+{
+    int rc;
+    find_domain(p);
+    rc=libxl_domain_shutdown(&ctx, domid, 1);
+    if (rc) { fprintf(stderr,"reboot failed (rc=%d)\n.",rc);exit(-1); }
+}
+
+void list_domains_details(void)
+{
+    struct libxl_dominfo *info;
+    char *config_file;
+    uint8_t *data;
+    int nb_domain, i, len, rc;
+    int num_disks = 0, num_vifs = 0, num_pcidevs = 0, num_vfbs = 0, num_vkbs = 
0;
+    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;
+
+    libxl_device_pci *pcidevs = NULL;
+    libxl_device_vfb *vfbs = NULL;
+    libxl_device_vkb *vkbs = NULL;
+
+    info = libxl_list_domain(&ctx, &nb_domain);
+
+    if (!info) {
+        fprintf(stderr, "libxl_domain_infolist failed.\n");
+        exit(1);
+    }
+    for (i = 0; i < nb_domain; i++) {
+        rc = libxl_userdata_retrieve(&ctx, info[i].domid, "xl", &data, &len);
+        if (rc)
+            continue;
+        CHK_ERRNO(asprintf(&config_file, "<domid %d data>", info[i].domid));
+        parse_config_data(config_file, (char *)data, len, &info1, &info2, 
&disks, &num_disks, &vifs, &num_vifs, &pcidevs, &num_pcidevs, &vfbs, &num_vfbs, 
&vkbs, &num_vkbs, &dm_info);
+        printf_info(info[i].domid, &info1, &info2, disks, num_disks, vifs, 
num_vifs, pcidevs, num_pcidevs, vfbs, num_vfbs, vkbs, num_vkbs, &dm_info);
+        free(data);
+        free(config_file);
+    }
+    free(info);
+}
+
+void list_domains(int verbose)
+{
+    struct libxl_dominfo *info;
+    int nb_domain, i;
+
+    info = libxl_list_domain(&ctx, &nb_domain);
+
+    if (!info) {
+        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 %8.1f",
+                libxl_domid_to_name(&ctx, info[i].domid),
+                info[i].domid,
+                (unsigned long) (info[i].max_memkb / 1024),
+                info[i].vcpu_online,
+                info[i].running ? 'r' : '-',
+                info[i].paused ? 'p' : '-',
+                info[i].dying ? 'd' : '-',
+                ((float)info[i].cpu_time / 1e9));
+        if (verbose) {
+            char *uuid = libxl_uuid2string(&ctx, info[i].uuid);
+            printf(" %s", uuid);
+        }
+        putchar('\n');
+    }
+    free(info);
+}
+
+void list_vm(void)
+{
+    struct libxl_vminfo *info;
+    int nb_vm, i;
+
+    info = libxl_list_vm(&ctx, &nb_vm);
+
+    if (info < 0) {
+        fprintf(stderr, "libxl_domain_infolist failed.\n");
+        exit(1);
+    }
+    printf("UUID                                  ID    name\n");
+    for (i = 0; i < nb_vm; i++) {
+        printf(UUID_FMT "  %d    %-30s\n",
+            info[i].uuid[0], info[i].uuid[1], info[i].uuid[2], info[i].uuid[3],
+            info[i].uuid[4], info[i].uuid[5], info[i].uuid[6], info[i].uuid[7],
+            info[i].uuid[8], info[i].uuid[9], info[i].uuid[10], 
info[i].uuid[11],
+            info[i].uuid[12], info[i].uuid[13], info[i].uuid[14], 
info[i].uuid[15],
+            info[i].domid, libxl_domid_to_name(&ctx, info[i].domid));
+    }
+    free(info);
+}
+
+static void save_domain_core_begin(char *domain_spec,
+                                   const char *override_config_file,
+                                   uint8_t **config_data_r,
+                                   int *config_len_r)
+{
+    int rc;
+
+    find_domain(domain_spec);
+
+    /* configuration file in optional data: */
+
+    if (override_config_file) {
+        void *config_v = 0;
+        rc = libxl_read_file_contents(&ctx, override_config_file,
+                                      &config_v, config_len_r);
+        *config_data_r = config_v;
+    } else {
+        rc = libxl_userdata_retrieve(&ctx, domid, "xl",
+                                     config_data_r, config_len_r);
+    }
+    if (rc) {
+        fputs("Unable to get config file\n",stderr);
+        exit(2);
+    }
+}
+
+void save_domain_core_writeconfig(int fd, const char *filename,
+                                  const uint8_t *config_data, int config_len)
+{
+    struct save_file_header hdr;
+    uint8_t *optdata_begin;
+    union { uint32_t u32; char b[4]; } u32buf;
+
+    memset(&hdr, 0, sizeof(hdr));
+    memcpy(hdr.magic, savefileheader_magic, sizeof(hdr.magic));
+    hdr.byteorder = SAVEFILE_BYTEORDER_VALUE;
+
+    optdata_begin= 0;
+
+#define ADD_OPTDATA(ptr, len) ({                                            \
+    if ((len)) {                                                        \
+        hdr.optional_data_len += (len);                                 \
+        optdata_begin = xrealloc(optdata_begin, hdr.optional_data_len); \
+        memcpy(optdata_begin + hdr.optional_data_len - (len),           \
+               (ptr), (len));                                           \
+    }                                                                   \
+                          })
+
+    u32buf.u32 = config_len;
+    ADD_OPTDATA(u32buf.b,    4);
+    ADD_OPTDATA(config_data, config_len);
+
+    /* that's the optional data */
+
+    CHK_ERRNO( libxl_write_exactly(&ctx, fd,
+        &hdr, sizeof(hdr), filename, "header") );
+    CHK_ERRNO( libxl_write_exactly(&ctx, fd,
+        optdata_begin, hdr.optional_data_len, filename, "header") );
+
+    fprintf(stderr, "Saving to %s new xl format (info"
+            " 0x%"PRIx32"/0x%"PRIx32"/%"PRIu32")\n",
+            filename, hdr.mandatory_flags, hdr.optional_flags,
+            hdr.optional_data_len);
+}
+
+int save_domain(char *p, char *filename, int checkpoint,
+                const char *override_config_file)
+{
+    int fd;
+    uint8_t *config_data;
+    int config_len;
+
+    save_domain_core_begin(p, override_config_file, &config_data, &config_len);
+
+    if (!config_len) {
+        fputs(" Savefile will not contain xl domain config\n", stderr);
+    }
+
+    fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+    if (fd < 0) {
+        fprintf(stderr, "Failed to open temp file %s for writing\n", filename);
+        exit(2);
+    }
+
+    save_domain_core_writeconfig(fd, filename, config_data, config_len);
+
+    CHK_ERRNO(libxl_domain_suspend(&ctx, NULL, domid, fd));
+    close(fd);
+
+    if (checkpoint)
+        libxl_domain_unpause(&ctx, domid);
+    else
+        libxl_domain_destroy(&ctx, domid, 0);
+
+    exit(0);
+}
+
+static int migrate_read_fixedmessage(int fd, const void *msg, int msgsz,
+                                     const char *what, const char *rune) {
+    char buf[msgsz];
+    const char *stream;
+    int rc;
+
+    stream = rune ? "migration receiver stream" : "migration stream";
+    rc = libxl_read_exactly(&ctx, fd, buf, msgsz, stream, what);
+    if (rc) return ERROR_FAIL;
+
+    if (memcmp(buf, msg, msgsz)) {
+        fprintf(stderr, "%s contained unexpected data instead of %s\n",
+                stream, what);
+        if (rune)
+            fprintf(stderr, "(command run was: %s )\n", rune);
+        return ERROR_FAIL;
+    }
+    return 0;
+}
+
+static void migration_child_report(pid_t migration_child, int recv_fd) {
+    pid_t child;
+    int status, sr;
+    struct timeval now, waituntil, timeout;
+    static const struct timeval pollinterval = { 0, 1000 }; /* 1ms */
+
+    if (!migration_child) return;
+
+    CHK_ERRNO( gettimeofday(&waituntil, 0) );
+    waituntil.tv_sec += 2;
+
+    for (;;) {
+        child = waitpid(migration_child, &status, WNOHANG);
+
+        if (child == migration_child) {
+            if (status)
+                libxl_report_child_exitstatus(&ctx, XL_LOG_INFO,
+                                              "migration target process",
+                                              migration_child, status);
+            break;
+        }
+        if (child == -1) {
+            if (errno == EINTR) continue;
+            fprintf(stderr, "wait for migration child [%ld] failed: %s\n",
+                    (long)migration_child, strerror(errno));
+            break;
+        }
+        assert(child == 0);
+
+        CHK_ERRNO( gettimeofday(&now, 0) );
+        if (timercmp(&now, &waituntil, >)) {
+            fprintf(stderr, "migration child [%ld] not exiting, no longer"
+                    " waiting (exit status will be unreported)\n",
+                    (long)migration_child);
+            break;
+        }
+        timersub(&waituntil, &now, &timeout);
+
+        if (recv_fd >= 0) {
+            fd_set readfds, exceptfds;
+            FD_ZERO(&readfds);
+            FD_ZERO(&exceptfds);
+            FD_SET(recv_fd, &readfds);
+            FD_SET(recv_fd, &exceptfds);
+            sr = select(recv_fd+1, &readfds,0,&exceptfds, &timeout);
+        } else {
+            if (timercmp(&timeout, &pollinterval, >))
+                timeout = pollinterval;
+            sr = select(0,0,0,0, &timeout);
+        }
+        if (sr > 0) {
+            recv_fd = -1;
+        } else if (sr == 0) {
+        } else if (sr == -1) {
+            if (errno != EINTR) {
+                fprintf(stderr, "migration child [%ld] exit wait select"
+                        " failed unexpectedly: %s\n",
+                        (long)migration_child, strerror(errno));
+                break;
+            }
+        }
+    }
+    migration_child = 0;
+}
+
+static void migrate_domain(char *domain_spec, const char *rune,
+                           const char *override_config_file)
+{
+    pid_t child = -1;
+    int rc;
+    int sendpipe[2], recvpipe[2];
+    int send_fd, recv_fd;
+    libxl_domain_suspend_info suspinfo;
+    char *away_domname;
+    char rc_buf;
+    uint8_t *config_data;
+    int config_len;
+
+    save_domain_core_begin(domain_spec, override_config_file,
+                           &config_data, &config_len);
+
+    if (!config_len) {
+        fprintf(stderr, "No config file stored for running domain and "
+                "none supplied - cannot migrate.\n");
+        exit(1);
+    }
+
+    MUST( libxl_pipe(&ctx, sendpipe) );
+    MUST( libxl_pipe(&ctx, recvpipe) );
+
+    child = libxl_fork(&ctx);
+    if (child==-1) exit(1);
+
+    if (!child) {
+        dup2(sendpipe[0], 0);
+        dup2(recvpipe[1], 1);
+        close(sendpipe[0]); close(sendpipe[1]);
+        close(recvpipe[0]); close(recvpipe[1]);
+        execlp("sh","sh","-c",rune,(char*)0);
+        perror("failed to exec sh");
+        exit(-1);
+    }
+
+    close(sendpipe[0]);
+    close(recvpipe[1]);
+    send_fd = sendpipe[1];
+    recv_fd = recvpipe[0];
+
+    signal(SIGPIPE, SIG_IGN);
+    /* if receiver dies, we get an error and can clean up
+       rather than just dying */
+
+    rc = migrate_read_fixedmessage(recv_fd, migrate_receiver_banner,
+                                   sizeof(migrate_receiver_banner)-1,
+                                   "banner", rune);
+    if (rc) {
+        close(send_fd);
+        migration_child_report(child, recv_fd);
+        exit(-rc);
+    }
+
+    save_domain_core_writeconfig(send_fd, "migration stream",
+                                 config_data, config_len);
+
+    memset(&suspinfo, 0, sizeof(suspinfo));
+    suspinfo.flags |= XL_SUSPEND_LIVE;
+    rc = libxl_domain_suspend(&ctx, &suspinfo, domid, send_fd);
+    if (rc) {
+        fprintf(stderr, "migration sender: libxl_domain_suspend failed"
+                " (rc=%d)\n", rc);
+        goto failed_resume;
+    }
+
+    //fprintf(stderr, "migration sender: Transfer complete.\n");
+    // Should only be printed when debugging as it's a bit messy with
+    // progress indication.
+
+    rc = migrate_read_fixedmessage(recv_fd, migrate_receiver_ready,
+                                   sizeof(migrate_receiver_ready),
+                                   "ready message", rune);
+    if (rc) goto failed_resume;
+
+
+
+    /* right, at this point we are about give the destination
+     * permission to rename and resume, so we must first rename the
+     * domain away ourselves */
+
+    fprintf(stderr, "migration sender: Target has acknowledged transfer.\n");
+
+    if (common_domname) {
+        if (asprintf(&away_domname, "%s--migratedaway", common_domname) < 0)
+            goto failed_resume;
+        rc = libxl_domain_rename(&ctx, domid,
+                                 common_domname, away_domname, 0);
+        if (rc) goto failed_resume;
+    }
+
+    /* point of no return - as soon as we have tried to say
+     * "go" to the receiver, it's not safe to carry on.  We leave
+     * the domain renamed to %s--migratedaway in case that's helpful.
+     */
+
+    fprintf(stderr, "migration sender: Giving target permission to start.\n");
+
+    rc = libxl_write_exactly(&ctx, send_fd,
+                             migrate_permission_to_go,
+                             sizeof(migrate_permission_to_go),
+                             "migration stream", "GO message");
+    if (rc) goto failed_badly;
+
+    rc = migrate_read_fixedmessage(recv_fd, migrate_report,
+                                   sizeof(migrate_report),
+                                   "success/failure report message", rune);
+    if (rc) goto failed_badly;
+
+    rc = libxl_read_exactly(&ctx, recv_fd,
+                            &rc_buf, 1,
+                            "migration ack stream", "success/failure status");
+    if (rc) goto failed_badly;
+
+    if (rc_buf) {
+        fprintf(stderr, "migration sender: Target reports startup failure"
+                " (status code %d).\n", rc_buf);
+
+        rc = migrate_read_fixedmessage(recv_fd, migrate_permission_to_go,
+                                       sizeof(migrate_permission_to_go),
+                                       "permission for sender to resume",
+                                       rune);
+        if (rc) goto failed_badly;
+
+        fprintf(stderr, "migration sender: Trying to resume at our end.\n");
+
+        if (common_domname) {
+            libxl_domain_rename(&ctx, domid,
+                                away_domname, common_domname, 0);
+        }
+        rc = libxl_domain_resume(&ctx, domid);
+        if (!rc) fprintf(stderr, "migration sender: Resumed OK.\n");
+
+        fprintf(stderr, "Migration failed due to problems at target.\n");
+        exit(-ERROR_FAIL);
+    }
+
+    fprintf(stderr, "migration sender: Target reports successful startup.\n");
+    libxl_domain_destroy(&ctx, domid, 1); /* bang! */
+    fprintf(stderr, "Migration successful.\n");
+    exit(0);
+
+ failed_resume:
+    close(send_fd);
+    migration_child_report(child, recv_fd);
+    fprintf(stderr, "Migration failed, resuming at sender.\n");
+    libxl_domain_resume(&ctx, domid);
+    exit(-ERROR_FAIL);
+
+ failed_badly:
+    fprintf(stderr,
+ "** Migration failed during final handshake **\n"
+ "Domain state is now undefined !\n"
+ "Please CHECK AT BOTH ENDS for running instances, before renaming and\n"
+ " resuming at most one instance.  Two simultaneous instances of the domain\n"
+ " would probably result in SEVERE DATA LOSS and it is now your\n"
+ " responsibility to avoid that.  Sorry.\n");
+
+    close(send_fd);
+    migration_child_report(child, recv_fd);
+    exit(-ERROR_BADFAIL);
+}
+
+static void migrate_receive(int debug, int daemonize)
+{
+    int rc, rc2;
+    char rc_buf;
+    char *migration_domname;
+    struct domain_create dom_info;
+
+    signal(SIGPIPE, SIG_IGN);
+    /* if we get SIGPIPE we'd rather just have it as an error */
+
+    fprintf(stderr, "migration target: Ready to receive domain.\n");
+
+    CHK_ERRNO( libxl_write_exactly(&ctx, 1,
+                                   migrate_receiver_banner,
+                                   sizeof(migrate_receiver_banner)-1,
+                                   "migration ack stream",
+                                   "banner") );
+
+    memset(&dom_info, 0, sizeof(dom_info));
+    dom_info.debug = debug;
+    dom_info.daemonize = daemonize;
+    dom_info.paused = 1;
+    dom_info.restore_file = "incoming migration stream";
+    dom_info.migration_domname_r = &migration_domname;
+
+    rc = create_domain(&dom_info);
+    if (rc < 0) {
+        fprintf(stderr, "migration target: Domain creation failed"
+                " (code %d).\n", rc);
+        exit(-rc);
+    }
+
+    fprintf(stderr, "migration target: Transfer complete,"
+            " requesting permission to start domain.\n");
+
+    rc = libxl_write_exactly(&ctx, 1,
+                             migrate_receiver_ready,
+                             sizeof(migrate_receiver_ready),
+                             "migration ack stream", "ready message");
+    if (rc) exit(-rc);
+
+    rc = migrate_read_fixedmessage(0, migrate_permission_to_go,
+                                   sizeof(migrate_permission_to_go),
+                                   "GO message", 0);
+    if (rc) goto perhaps_destroy_notify_rc;
+
+    fprintf(stderr, "migration target: Got permission, starting domain.\n");
+
+    if (migration_domname) {
+        rc = libxl_domain_rename(&ctx, domid,
+                                 migration_domname, common_domname, 0);
+        if (rc) goto perhaps_destroy_notify_rc;
+    }
+
+    rc = libxl_domain_unpause(&ctx, domid);
+    if (rc) goto perhaps_destroy_notify_rc;
+
+    fprintf(stderr, "migration target: Domain started successsfully.\n");
+    rc = 0;
+
+ perhaps_destroy_notify_rc:
+    rc2 = libxl_write_exactly(&ctx, 1,
+                              migrate_report, sizeof(migrate_report),
+                              "migration ack stream",
+                              "success/failure report");
+    if (rc2) exit(-ERROR_BADFAIL);
+
+    rc_buf = -rc;
+    assert(!!rc_buf == !!rc);
+    rc2 = libxl_write_exactly(&ctx, 1, &rc_buf, 1,
+                              "migration ack stream",
+                              "success/failure code");
+    if (rc2) exit(-ERROR_BADFAIL);
+
+    if (rc) {
+        fprintf(stderr, "migration target: Failure, destroying our copy.\n");
+
+        rc2 = libxl_domain_destroy(&ctx, domid, 1);
+        if (rc2) {
+            fprintf(stderr, "migration target: Failed to destroy our copy"
+                    " (code %d).\n", rc2);
+            exit(-ERROR_BADFAIL);
+        }
+
+        fprintf(stderr, "migration target: Cleanup OK, granting sender"
+                " permission to resume.\n");
+
+        rc2 = libxl_write_exactly(&ctx, 1,
+                                  migrate_permission_to_go,
+                                  sizeof(migrate_permission_to_go),
+                                  "migration ack stream",
+                                  "permission to sender to have domain back");
+        if (rc2) exit(-ERROR_BADFAIL);
+    }
+
+    exit(0);
+}
+
+int main_restore(int argc, char **argv)
+{
+    char *checkpoint_file = NULL;
+    char *config_file = NULL;
+    struct domain_create dom_info;
+    int paused = 0, debug = 0, daemonize = 1;
+    int opt, rc;
+
+    while ((opt = getopt(argc, argv, "hpde")) != -1) {
+        switch (opt) {
+        case 'p':
+            paused = 1;
+            break;
+        case 'd':
+            debug = 1;
+            break;
+        case 'e':
+            daemonize = 0;
+            break;
+        case 'h':
+            help("restore");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+
+    if (argc-optind == 1) {
+        checkpoint_file = argv[optind];
+    } else if (argc-optind == 2) {
+        config_file = argv[optind];
+        checkpoint_file = argv[optind + 1];
+    } else {
+        help("restore");
+        exit(2);
+    }
+
+    memset(&dom_info, 0, sizeof(dom_info));
+    dom_info.debug = debug;
+    dom_info.daemonize = daemonize;
+    dom_info.paused = paused;
+    dom_info.config_file = config_file;
+    dom_info.restore_file = checkpoint_file;
+    dom_info.migrate_fd = -1;
+
+    rc = create_domain(&dom_info);
+    if (rc < 0)
+        exit(-rc);
+
+    exit(0);
+}
+
+int main_migrate_receive(int argc, char **argv)
+{
+    int debug = 0, daemonize = 1;
+    int opt;
+
+    while ((opt = getopt(argc, argv, "hed")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("migrate-receive");
+            exit(2);
+            break;
+        case 'e':
+            daemonize = 0;
+            break;
+        case 'd':
+            debug = 1;
+            break;
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+
+    if (argc-optind != 0) {
+        help("migrate-receive");
+        exit(2);
+    }
+    migrate_receive(debug, daemonize);
+    exit(0);
+}
+
+int main_save(int argc, char **argv)
+{
+    char *filename = NULL, *p = NULL;
+    const char *config_filename;
+    int checkpoint = 0;
+    int opt;
+
+    while ((opt = getopt(argc, argv, "hc")) != -1) {
+        switch (opt) {
+        case 'c':
+            checkpoint = 1;
+            break;
+        case 'h':
+            help("save");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+
+    if (argc-optind < 1 || argc-optind > 3) {
+        help("save");
+        exit(2);
+    }
+
+    p = argv[optind];
+    filename = argv[optind + 1];
+    config_filename = argv[optind + 2];
+    save_domain(p, filename, checkpoint, config_filename);
+    exit(0);
+}
+
+int main_migrate(int argc, char **argv)
+{
+    char *p = NULL;
+    const char *config_filename = NULL;
+    const char *ssh_command = "ssh";
+    char *rune = NULL;
+    char *host;
+    int opt, daemonize = 1, debug = 0;
+
+    while ((opt = getopt(argc, argv, "hC:s:ed")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("migrate");
+            exit(0);
+        case 'C':
+            config_filename = optarg;
+            break;
+        case 's':
+            ssh_command = optarg;
+            break;
+        case 'e':
+            daemonize = 0;
+            break;
+        case 'd':
+            debug = 1;
+            break;
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+
+    if (argc-optind < 2 || argc-optind > 2) {
+        help("migrate");
+        exit(2);
+    }
+
+    p = argv[optind];
+    host = argv[optind + 1];
+
+    if (!ssh_command[0]) {
+        rune= host;
+    } else {
+        if (asprintf(&rune, "exec %s %s xl migrate-receive%s%s",
+                     ssh_command, host,
+                     daemonize ? "" : " -e",
+                     debug ? " -d" : "") < 0)
+            exit(1);
+    }
+
+    migrate_domain(p, rune, config_filename);
+    exit(0);
+}
+
+int main_pause(int argc, char **argv)
+{
+    int opt;
+    char *p;
+    
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("pause");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc) {
+        help("pause");
+        exit(2);
+    }
+
+    p = argv[optind];
+
+    pause_domain(p);
+    exit(0);
+}
+
+int main_unpause(int argc, char **argv)
+{
+    int opt;
+    char *p;
+    
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("unpause");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc) {
+        help("unpause");
+        exit(2);
+    }
+
+    p = argv[optind];
+
+    unpause_domain(p);
+    exit(0);
+}
+
+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_shutdown(int argc, char **argv)
+{
+    int opt;
+    char *p;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("shutdown");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc) {
+        help("shutdown");
+        exit(2);
+    }
+
+    p = argv[optind];
+
+    shutdown_domain(p);
+    exit(0);
+}
+
+int main_reboot(int argc, char **argv)
+{
+    int opt;
+    char *p;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("reboot");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc) {
+        help("reboot");
+        exit(2);
+    }
+
+    p = argv[optind];
+
+    reboot_domain(p);
+    exit(0);
+}
+int main_list(int argc, char **argv)
+{
+    int opt, verbose = 0;
+    int details = 0;
+    int option_index = 0;
+    static struct option long_options[] = {
+        {"long", 0, 0, 'l'},
+        {"help", 0, 0, 'h'},
+        {"verbose", 0, 0, 'v'},
+        {0, 0, 0, 0}
+    };
+
+    while (1) {
+        opt = getopt_long(argc, argv, "lvh", long_options, &option_index);
+        if (opt == -1)
+            break;
+
+        switch (opt) {
+        case 'l':
+            details = 1;
+            break;
+        case 'h':
+            help("list");
+            exit(0);
+        case 'v':
+            verbose = 1;
+            break;
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+
+    if (details)
+        list_domains_details();
+    else
+        list_domains(verbose);
+    exit(0);
+}
+
+int main_list_vm(int argc, char **argv)
+{
+    int opt;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("list-vm");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+
+    list_vm();
+    exit(0);
+}
+
+int main_create(int argc, char **argv)
+{
+    char *filename = NULL;
+    char *p, extra_config[1024];
+    struct domain_create dom_info;
+    char dom[10]; /* long enough */
+    int paused = 0, debug = 0, daemonize = 1, console_autoconnect = 0,
+        dryrun = 0, quite = 0;
+    int opt, rc;
+    int option_index = 0;
+    static struct option long_options[] = {
+        {"dryrun", 0, 0, 'n'},
+        {"quiet", 0, 0, 'q'},
+        {"help", 0, 0, 'h'},
+        {"defconfig", 1, 0, 'f'},
+        {0, 0, 0, 0}
+    };
+
+    while (1) {
+        opt = getopt_long(argc, argv, "hnqf:pcde", long_options, 
&option_index);
+        if (opt == -1)
+            break;
+
+        switch (opt) {
+        case 'f':
+            filename = optarg;
+            break;
+        case 'p':
+            paused = 1;
+            break;
+        case 'c':
+            console_autoconnect = 1;
+            break;
+        case 'd':
+            debug = 1;
+            break;
+        case 'e':
+            daemonize = 0;
+            break;
+        case 'h':
+            help("create");
+            exit(0);
+        case 'n':
+            dryrun = 1;
+            break;
+        case 'q':
+            quite = 1;
+            break;
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+
+    memset(extra_config, 0, sizeof(extra_config));
+    while (optind < argc) {
+        if ((p = strchr(argv[optind], '='))) {
+            if (strlen(extra_config) + 1 < sizeof(extra_config)) {
+                if (strlen(extra_config))
+                    strcat(extra_config, "\n");
+                strcat(extra_config, argv[optind]);
+            }
+        } else if (!filename) {
+            filename = argv[optind];
+        } else {
+            help("create");
+            exit(2);
+        }
+        optind++;
+    }
+
+    memset(&dom_info, 0, sizeof(dom_info));
+    dom_info.debug = debug;
+    dom_info.daemonize = daemonize;
+    dom_info.paused = paused;
+    dom_info.dryrun = dryrun;
+    dom_info.quiet = quite;
+    dom_info.config_file = filename;
+    dom_info.extra_config = extra_config;
+    dom_info.migrate_fd = -1;
+
+    rc = create_domain(&dom_info);
+    if (rc < 0)
+        exit(-rc);
+
+    if (console_autoconnect) {
+        snprintf(dom, sizeof(dom), "%d", rc);
+        console(dom, 0);
+    }
+
+    exit(0);
+}
+
+void button_press(char *p, char *b)
+{
+    libxl_button button;
+
+    find_domain(p);
+
+    if (!strcmp(b, "power")) {
+        button = POWER_BUTTON;
+    } else if (!strcmp(b, "sleep")) {
+        button = SLEEP_BUTTON;
+    } else {
+        fprintf(stderr, "%s is an invalid button identifier\n", b);
+        exit(2);
+    }
+
+    libxl_button_press(&ctx, domid, button);
+}
+
+int main_button_press(int argc, char **argv)
+{
+    int opt;
+    char *p;
+    char *b;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("button-press");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc - 1) {
+        help("button-press");
+        exit(2);
+    }
+
+    p = argv[optind];
+    b = argv[optind + 1];
+
+    button_press(p, b);
+    exit(0);
+}
+
+static void print_vcpuinfo(uint32_t tdomid,
+                           const struct libxl_vcpuinfo *vcpuinfo,
+                           uint32_t nr_cpus)
+{
+    int i, l;
+    uint64_t *cpumap;
+    uint64_t pcpumap;
+
+    /*      NAME  ID  VCPU */
+    printf("%-32s %5u %5u",
+           libxl_domid_to_name(&ctx, tdomid), tdomid, vcpuinfo->vcpuid);
+    if (!vcpuinfo->online) {
+        /*      CPU STA */
+        printf("%5c %3c%cp ", '-', '-', '-');
+    } else {
+        /*      CPU STA */
+        printf("%5u %3c%c- ", vcpuinfo->cpu,
+               vcpuinfo->running ? 'r' : '-',
+               vcpuinfo->blocked ? 'b' : '-');
+    }
+    /*      TIM */
+    printf("%9.1f  ", ((float)vcpuinfo->vcpu_time / 1e9));
+    /* CPU AFFINITY */
+    pcpumap = nr_cpus > 64 ? -1 : ((1 << nr_cpus) - 1);
+    for (cpumap = vcpuinfo->cpumap; nr_cpus; ++cpumap) {
+        if (*cpumap < pcpumap) {
+            break;
+        }
+        if (nr_cpus > 64) {
+            pcpumap = -1;
+            nr_cpus -= 64;
+        } else {
+            pcpumap = ((1 << nr_cpus) - 1);
+            nr_cpus = 0;
+        }
+    }
+    if (!nr_cpus) {
+        printf("any cpu\n");
+    } else {
+        for (cpumap = vcpuinfo->cpumap; nr_cpus; ++cpumap) {
+            pcpumap = *cpumap;
+            for (i = 0; !(pcpumap & 1); ++i, pcpumap >>= 1)
+                ;
+            printf("%u", i);
+            for (l = i, pcpumap = (pcpumap >> 1); (pcpumap & 1); ++i, pcpumap 
>>= 1)
+                ;
+            if (l < i) {
+                printf("-%u", i);
+            }
+            for (++i; pcpumap; ++i, pcpumap >>= 1) {
+                if (pcpumap & 1) {
+                    printf(",%u", i);
+                    for (l = i, pcpumap = (pcpumap >> 1); (pcpumap & 1); ++i, 
pcpumap >>= 1)
+                        ;
+                    if (l < i) {
+                        printf("-%u", i);
+                    }
+                    ++i;
+                }
+            }
+            printf("\n");
+            nr_cpus = nr_cpus > 64 ? nr_cpus - 64 : 0;
+        }
+    }
+}
+
+void vcpulist(int argc, char **argv)
+{
+    struct libxl_dominfo *dominfo;
+    struct libxl_vcpuinfo *vcpuinfo;
+    struct libxl_physinfo physinfo;
+    int nb_vcpu, nb_domain, cpusize;
+
+    if (libxl_get_physinfo(&ctx, &physinfo) != 0) {
+        fprintf(stderr, "libxl_physinfo failed.\n");
+        goto vcpulist_out;
+    }
+    printf("%-32s %5s %5s %5s %5s %9s %s\n",
+           "Name", "ID", "VCPU", "CPU", "State", "Time(s)", "CPU Affinity");
+    if (!argc) {
+        if (!(dominfo = libxl_list_domain(&ctx, &nb_domain))) {
+            fprintf(stderr, "libxl_list_domain failed.\n");
+            goto vcpulist_out;
+        }
+        for (; nb_domain > 0; --nb_domain, ++dominfo) {
+            if (!(vcpuinfo = libxl_list_vcpu(&ctx, dominfo->domid, &nb_vcpu, 
&cpusize))) {
+                fprintf(stderr, "libxl_list_vcpu failed.\n");
+                goto vcpulist_out;
+            }
+            for (; nb_vcpu > 0; --nb_vcpu, ++vcpuinfo) {
+                print_vcpuinfo(dominfo->domid, vcpuinfo, physinfo.nr_cpus);
+            }
+        }
+    } else {
+        for (; argc > 0; ++argv, --argc) {
+            if (domain_qualifier_to_domid(*argv, &domid, 0) < 0) {
+                fprintf(stderr, "%s is an invalid domain identifier\n", *argv);
+            }
+            if (!(vcpuinfo = libxl_list_vcpu(&ctx, domid, &nb_vcpu, 
&cpusize))) {
+                fprintf(stderr, "libxl_list_vcpu failed.\n");
+                goto vcpulist_out;
+            }
+            for (; nb_vcpu > 0; --nb_vcpu, ++vcpuinfo) {
+                print_vcpuinfo(domid, vcpuinfo, physinfo.nr_cpus);
+            }
+        }
+    }
+  vcpulist_out:
+    ;
+}
+
+int main_vcpulist(int argc, char **argv)
+{
+    int opt;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("vcpu-list");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    vcpulist(argc - 2, argv + 2);
+    exit(0);
+}
+
+void vcpupin(char *d, const char *vcpu, char *cpu)
+{
+    struct libxl_vcpuinfo *vcpuinfo;
+    struct libxl_physinfo physinfo;
+    uint64_t *cpumap = NULL;
+
+    uint32_t vcpuid, cpuida, cpuidb;
+    char *endptr, *toka, *tokb;
+    int i, nb_vcpu, cpusize;
+
+    vcpuid = strtoul(vcpu, &endptr, 10);
+    if (vcpu == endptr) {
+        if (strcmp(vcpu, "all")) {
+            fprintf(stderr, "Error: Invalid argument.\n");
+            return;
+        }
+        vcpuid = -1;
+    }
+
+    find_domain(d);
+
+    if (libxl_get_physinfo(&ctx, &physinfo) != 0) {
+        fprintf(stderr, "libxl_get_physinfo failed.\n");
+        goto vcpupin_out1;
+    }
+
+    cpumap = calloc(physinfo.max_cpu_id + 1, sizeof (uint64_t));
+    if (!cpumap) {
+        goto vcpupin_out1;
+    }
+    if (strcmp(cpu, "all")) {
+        for (toka = strtok(cpu, ","), i = 0; toka; toka = strtok(NULL, ","), 
++i) {
+            cpuida = strtoul(toka, &endptr, 10);
+            if (toka == endptr) {
+                fprintf(stderr, "Error: Invalid argument.\n");
+                goto vcpupin_out;
+            }
+            if (*endptr == '-') {
+                tokb = endptr + 1;
+                cpuidb = strtoul(tokb, &endptr, 10);
+                if ((tokb == endptr) || (cpuida > cpuidb)) {
+                    fprintf(stderr, "Error: Invalid argument.\n");
+                    goto vcpupin_out;
+                }
+                while (cpuida <= cpuidb) {
+                    cpumap[cpuida / 64] |= (1 << (cpuida % 64));
+                    ++cpuida;
+                }
+            } else {
+                cpumap[cpuida / 64] |= (1 << (cpuida % 64));
+            }
+        }
+    }
+    else {
+        memset(cpumap, -1, sizeof (uint64_t) * (physinfo.max_cpu_id + 1));
+    }
+
+    if (vcpuid != -1) {
+        if (libxl_set_vcpuaffinity(&ctx, domid, vcpuid,
+                                   cpumap, physinfo.max_cpu_id + 1) == -1) {
+            fprintf(stderr, "Could not set affinity for vcpu `%u'.\n", vcpuid);
+        }
+    }
+    else {
+        if (!(vcpuinfo = libxl_list_vcpu(&ctx, domid, &nb_vcpu, &cpusize))) {
+            fprintf(stderr, "libxl_list_vcpu failed.\n");
+            goto vcpupin_out;
+        }
+        for (; nb_vcpu > 0; --nb_vcpu, ++vcpuinfo) {
+            if (libxl_set_vcpuaffinity(&ctx, domid, vcpuinfo->vcpuid,
+                                       cpumap, physinfo.max_cpu_id + 1) == -1) 
{
+                fprintf(stderr, "libxl_list_vcpu failed on vcpu `%u'.\n", 
vcpuinfo->vcpuid);
+            }
+        }
+    }
+  vcpupin_out1:
+    free(cpumap);
+  vcpupin_out:
+    ;
+}
+
+int main_vcpupin(int argc, char **argv)
+{
+    int opt;
+
+    if (argc != 5) {
+        help("vcpu-pin");
+        exit(0);
+    }
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("vcpu-pin");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    vcpupin(argv[2], argv[3] , argv[4]);
+    exit(0);
+}
+
+void vcpuset(char *d, char* nr_vcpus)
+{
+    char *endptr;
+    unsigned int max_vcpus;
+
+    max_vcpus = strtoul(nr_vcpus, &endptr, 10);
+    if (nr_vcpus == endptr) {
+        fprintf(stderr, "Error: Invalid argument.\n");
+        return;
+    }
+
+    find_domain(d);
+
+    if (libxl_set_vcpucount(&ctx, domid, max_vcpus) == ERROR_INVAL) {
+        fprintf(stderr, "Error: Cannot set vcpus greater than max vcpus on 
running domain or lesser than 1.\n");
+    }
+}
+
+int main_vcpuset(int argc, char **argv)
+{
+    int opt;
+
+    if (argc != 4) {
+        help("vcpu-set");
+        exit(0);
+    }
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+        help("vcpu-set");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    vcpuset(argv[2], argv[3]);
+    exit(0);
+}
+
+static void output_xeninfo(void)
+{
+    const libxl_version_info *info;
+    int sched_id;
+
+    if (!(info = libxl_get_version_info(&ctx))) {
+        fprintf(stderr, "libxl_get_version_info failed.\n");
+        return;
+    }
+
+    if ((sched_id = libxl_get_sched_id(&ctx)) < 0) {
+        fprintf(stderr, "get_sched_id sysctl failed.\n");
+        return;
+    }
+
+    printf("xen_major              : %d\n", info->xen_version_major);
+    printf("xen_minor              : %d\n", info->xen_version_minor);
+    printf("xen_extra              : %s\n", info->xen_version_extra);
+    printf("xen_caps               : %s\n", info->capabilities);
+    printf("xen_scheduler          : %s\n",
+        sched_id == XEN_SCHEDULER_SEDF ? "sedf" : "credit");
+    printf("xen_pagesize           : %lu\n", info->pagesize);
+    printf("platform_params        : virt_start=0x%lx\n", info->virt_start);
+    printf("xen_changeset          : %s\n", info->changeset);
+    printf("xen_commandline        : %s\n", info->commandline);
+    printf("cc_compiler            : %s\n", info->compiler);
+    printf("cc_compile_by          : %s\n", info->compile_by);
+    printf("cc_compile_domain      : %s\n", info->compile_domain);
+    printf("cc_compile_date        : %s\n", info->compile_date);
+
+    return;
+}
+
+static void output_nodeinfo(void)
+{
+    struct utsname utsbuf;
+
+    if (uname(&utsbuf) < 0)
+        return;
+
+    printf("host                   : %s\n", utsbuf.nodename);
+    printf("release                : %s\n", utsbuf.release);
+    printf("version                : %s\n", utsbuf.version);
+    printf("machine                : %s\n", utsbuf.machine);
+}
+
+static void output_physinfo(void)
+{
+    struct libxl_physinfo info;
+    const libxl_version_info *vinfo;
+    unsigned int i;
+
+    if (libxl_get_physinfo(&ctx, &info) != 0) {
+        fprintf(stderr, "libxl_physinfo failed.\n");
+        return;
+    }
+
+    printf("nr_cpus                : %d\n", info.nr_cpus);
+    printf("cores_per_socket       : %d\n", info.cores_per_socket);
+    printf("threads_per_core       : %d\n", info.threads_per_core);
+    printf("cpu_mhz                : %d\n", info.cpu_khz / 1000);
+    printf("hw_caps                : ");
+    for (i = 0; i < 8; i++)
+        printf("%08x%c", info.hw_cap[i], i < 7 ? ':' : '\n');
+    printf("virt_caps              :");
+    if (info.phys_cap & XEN_SYSCTL_PHYSCAP_hvm)
+        printf(" hvm");
+    if (info.phys_cap & XEN_SYSCTL_PHYSCAP_hvm_directio)
+        printf(" hvm_directio");
+    printf("\n");
+    vinfo = libxl_get_version_info(&ctx);
+    if (vinfo) {
+        i = (1 << 20) / vinfo->pagesize;
+        printf("total_memory           : %"PRIu64"\n", info.total_pages / i);
+        printf("free_memory            : %"PRIu64"\n", info.free_pages / i);
+    }
+
+    return;
+}
+
+static void info(void)
+{
+    output_nodeinfo();
+
+    output_physinfo();
+
+    output_xeninfo();
+
+    printf("xend_config_format     : 4\n");
+
+    return;
+}
+
+int main_info(int argc, char **argv)
+{
+    int opt;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("info");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    info();
+    exit(0);
+}
+
+static int sched_credit_domain_get(
+    int domid, struct libxl_sched_credit *scinfo)
+{
+    int rc;
+
+    rc = libxl_sched_credit_domain_get(&ctx, domid, scinfo);
+    if (rc)
+        fprintf(stderr, "libxl_sched_credit_domain_get failed.\n");
+    
+    return rc;
+}
+
+static int sched_credit_domain_set(
+    int domid, struct libxl_sched_credit *scinfo)
+{
+    int rc;
+
+    rc = libxl_sched_credit_domain_set(&ctx, domid, scinfo);
+    if (rc)
+        fprintf(stderr, "libxl_sched_credit_domain_set failed.\n");
+
+    return rc;
+}
+
+static void sched_credit_domain_output(
+    int domid, struct libxl_sched_credit *scinfo)
+{
+    printf("%-33s %4d %6d %4d\n",
+        libxl_domid_to_name(&ctx, domid),
+        domid,
+        scinfo->weight,
+        scinfo->cap);
+}
+
+int main_sched_credit(int argc, char **argv)
+{
+    struct libxl_dominfo *info;
+    struct libxl_sched_credit scinfo;
+    int nb_domain, i;
+    char *dom = NULL;
+    int weight = 256, cap = 0, opt_w = 0, opt_c = 0;
+    int opt, rc;
+
+    while ((opt = getopt(argc, argv, "hd:w:c:")) != -1) {
+        switch (opt) {
+        case 'd':
+            dom = optarg;
+            break;
+        case 'w':
+            weight = strtol(optarg, NULL, 10);
+            opt_w = 1;
+            break;
+        case 'c':
+            cap = strtol(optarg, NULL, 10);
+            opt_c = 1;
+            break;
+        case 'h':
+            help("sched-credit");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    if (!dom && (opt_w || opt_c)) {
+        fprintf(stderr, "Must specify a domain.\n");
+        exit(1);
+    }
+
+    if (!dom) { /* list all domain's credit scheduler info */
+        info = libxl_list_domain(&ctx, &nb_domain);
+        if (!info) {
+            fprintf(stderr, "libxl_domain_infolist failed.\n");
+            exit(1);
+        }
+
+        printf("%-33s %4s %6s %4s\n", "Name", "ID", "Weight", "Cap");
+        for (i = 0; i < nb_domain; i++) {
+            rc = sched_credit_domain_get(info[i].domid, &scinfo);
+            if (rc)
+                exit(-rc);
+            sched_credit_domain_output(info[i].domid, &scinfo);
+        }
+    } else {
+        find_domain(dom);
+
+        rc = sched_credit_domain_get(domid, &scinfo);
+        if (rc)
+            exit(-rc);
+
+        if (!opt_w && !opt_c) { /* output credit scheduler info */
+            printf("%-33s %4s %6s %4s\n", "Name", "ID", "Weight", "Cap");
+            sched_credit_domain_output(domid, &scinfo);
+        } else { /* set credit scheduler paramaters */
+            if (opt_w)
+                scinfo.weight = weight;
+            if (opt_c)
+                scinfo.cap = cap;
+            rc = sched_credit_domain_set(domid, &scinfo);
+            if (rc)
+                exit(-rc);
+        }
+    }
+
+    exit(0);
+}
+
+int main_domid(int argc, char **argv)
+{
+    int opt;
+    char *domname = NULL;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("domid");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    domname = argv[optind];
+    if (!domname) {
+        fprintf(stderr, "Must specify a domain name.\n\n");
+        help("domid");
+        exit(1);
+    }
+
+    if (libxl_name_to_domid(&ctx, domname, &domid)) {
+        fprintf(stderr, "Can't get domid of domain name '%s', maybe this 
domain does not exist.\n", domname);
+        exit(1);
+    }
+
+    printf("%d\n", domid);
+
+    exit(0);
+}
+
+int main_domname(int argc, char **argv)
+{
+    int opt;
+    char *domname = NULL;
+    char *endptr = NULL;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("domname");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    if (!argv[optind]) {
+        fprintf(stderr, "Must specify a domain id.\n\n");
+        help("domname");
+        exit(1);
+    }
+    domid = strtol(argv[optind], &endptr, 10);
+    if (domid == 0 && !strcmp(endptr, argv[optind])) {
+        /*no digits at all*/
+        fprintf(stderr, "Invalid domain id.\n\n");
+        exit(1);
+    }
+
+    domname = libxl_domid_to_name(&ctx, domid);
+    if (!domname) {
+        fprintf(stderr, "Can't get domain name of domain id '%d', maybe this 
domain does not exist.\n", domid);
+        exit(1);
+    }
+
+    printf("%s\n", domname);
+
+    exit(0);
+}
+
+int main_rename(int argc, char **argv)
+{
+    int opt;
+    char *dom;
+    char *new_name;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("rename");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    dom = argv[optind++];
+    if (!dom || !argv[optind]) {
+        fprintf(stderr, "'xl rename' requires 2 arguments.\n\n");
+        help("rename");
+        exit(1);
+    }
+
+    find_domain(dom);
+    new_name = argv[optind];
+
+    if (libxl_domain_rename(&ctx, domid, common_domname, new_name, 0)) {
+        fprintf(stderr, "Can't rename domain '%s'.\n", dom);
+        exit(1);
+    }
+
+    exit(0);
+}
+
+int main_trigger(int argc, char **argv)
+{
+    int opt;
+    char *trigger_name = NULL;
+    char *endptr = NULL;
+    char *dom = NULL;
+    int vcpuid = 0;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("trigger");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    dom = argv[optind++];
+    if (!dom || !argv[optind]) {
+        fprintf(stderr, "'xl trigger' requires between 2 and 3 
arguments.\n\n");
+        help("trigger");
+        exit(1);
+    }
+
+    find_domain(dom);
+
+    trigger_name = argv[optind++];
+
+    if (argv[optind]) {
+        vcpuid = strtol(argv[optind], &endptr, 10);
+        if (vcpuid == 0 && !strcmp(endptr, argv[optind])) {
+            fprintf(stderr, "Invalid vcpuid, using default vcpuid=0.\n\n");
+        }
+    }
+
+    libxl_send_trigger(&ctx, domid, trigger_name, vcpuid);
+
+    exit(0);
+}
+
+
+int main_sysrq(int argc, char **argv)
+{
+    int opt;
+    char *sysrq = NULL;
+    char *dom = NULL;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("sysrq");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    dom = argv[optind++];
+    if (!dom || !argv[optind]) {
+        fprintf(stderr, "'xl sysrq' requires 2 arguments.\n\n");
+        help("sysrq");
+        exit(1);
+    }
+
+    find_domain(dom);
+
+    sysrq = argv[optind];
+
+    if (sysrq[1] != '\0') {
+        fprintf(stderr, "Invalid sysrq.\n\n");
+        help("sysrq");
+        exit(1);
+    }
+
+    libxl_send_sysrq(&ctx, domid, sysrq[0]);
+
+    exit(0);
+}
+
+int main_debug_keys(int argc, char **argv)
+{
+    int opt;
+    char *keys;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("debug-keys");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+    if (optind >= argc) {
+        help("debug-keys");
+        exit(2);
+    }
+
+    keys = argv[optind];
+
+    if (libxl_send_debug_keys(&ctx, keys)) {
+        fprintf(stderr, "cannot send debug keys: %s\n", keys);
+        exit(1);
+    }
+
+    exit(0);
+}
+
+int main_dmesg(int argc, char **argv)
+{
+    unsigned int clear = 0;
+    struct libxl_xen_console_reader *cr;
+    char *line;
+    int opt, ret = 1;
+
+    while ((opt = getopt(argc, argv, "hc")) != -1) {
+        switch (opt) {
+        case 'c':
+            clear = 1;
+            break;
+        case 'h':
+            help("dmesg");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+
+    cr = libxl_xen_console_read_start(&ctx, clear);
+    if (!cr)
+        goto finish;
+
+    while ((ret = libxl_xen_console_read_line(&ctx, cr, &line)) > 0)
+        printf("%s", line);
+
+finish:
+    libxl_xen_console_read_finish(&ctx, cr);
+    exit(ret);
+}
+
+int main_top(int argc, char **argv)
+{
+    int opt;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("top");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    exit(system("xentop"));
+}
+
+int main_networkattach(int argc, char **argv)
+{
+    int opt;
+    libxl_device_nic nic;
+    char *endptr, *tok;
+    int i;
+    unsigned int val;
+
+    if ((argc < 3) || (argc > 11)) {
+        help("network-attach");
+        exit(0);
+    }
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("network-attach");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    if (domain_qualifier_to_domid(argv[2], &domid, 0) < 0) {
+        fprintf(stderr, "%s is an invalid domain identifier\n", argv[2]);
+        exit(1);
+    }
+    init_nic_info(&nic, -1);
+    for (argv += 3, argc -= 3; argc > 0; ++argv, --argc) {
+        if (!strncmp("type=", *argv, 5)) {
+            if (!strncmp("vif", (*argv) + 5, 4)) {
+                nic.nictype = NICTYPE_VIF;
+            } else if (!strncmp("ioemu", (*argv) + 5, 5)) {
+                nic.nictype = NICTYPE_IOEMU;
+            } else {
+                fprintf(stderr, "Invalid parameter `type'.\n");
+                exit(1);
+            }
+        } else if (!strncmp("mac=", *argv, 4)) {
+            tok = strtok((*argv) + 4, ":");
+            for (i = 0; tok && i < 6; tok = strtok(NULL, ":"), ++i) {
+                val = strtoul(tok, &endptr, 16);
+                if ((tok == endptr) || (val > 255)) {
+                    fprintf(stderr, "Invalid parameter `mac'.\n");
+                    exit(1);
+                }
+                nic.mac[i] = val;
+            }
+        } else if (!strncmp("bridge=", *argv, 7)) {
+            nic.bridge = (*argv) + 7;
+        } else if (!strncmp("ip=", *argv, 3)) {
+            if (!inet_aton((*argv) + 3, &(nic.ip))) {
+                fprintf(stderr, "Invalid parameter `ip'.\n");
+                exit(1);
+            }
+        } else if (!strncmp("script=", *argv, 6)) {
+            nic.script = (*argv) + 6;
+        } else if (!strncmp("backend=", *argv, 8)) {
+            val = strtoul((*argv) + 8, &endptr, 10);
+            if (((*argv) + 8) == endptr) {
+                fprintf(stderr, "Invalid parameter `backend'.\n");
+                exit(1);
+            }
+            nic.backend_domid = val;
+        } else if (!strncmp("vifname=", *argv, 8)) {
+            nic.ifname = (*argv) + 8;
+        } else if (!strncmp("model=", *argv, 6)) {
+            nic.model = (*argv) + 6;
+        } else if (!strncmp("rate=", *argv, 5)) {
+        } else if (!strncmp("accel=", *argv, 6)) {
+        } else {
+            fprintf(stderr, "unrecognized argument `%s'\n", *argv);
+            exit(1);
+        }
+    }
+    nic.domid = domid;
+    if (libxl_device_nic_add(&ctx, domid, &nic)) {
+        fprintf(stderr, "libxl_device_nic_add failed.\n");
+        exit(1);
+    }
+    exit(0);
+}
+
+int main_networklist(int argc, char **argv)
+{
+    int opt;
+    libxl_nicinfo *nics;
+    unsigned int nb;
+
+    if (argc < 3) {
+        help("network-list");
+        exit(1);
+    }
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+            case 'h':
+                help("network-list");
+                exit(0);
+            default:
+                fprintf(stderr, "option `%c' not supported.\n", opt);
+                break;
+        }
+    }
+
+    /*      Idx  BE   MAC   Hdl  Sta  evch txr/rxr  BE-path */
+    printf("%-3s %-2s %-17s %-6s %-5s %-6s %5s/%-5s %-30s\n",
+           "Idx", "BE", "Mac Addr.", "handle", "state", "evt-ch", "tx-", 
"rx-ring-ref", "BE-path");
+    for (argv += 2, argc -= 2; argc > 0; --argc, ++argv) {
+        if (domain_qualifier_to_domid(*argv, &domid, 0) < 0) {
+            fprintf(stderr, "%s is an invalid domain identifier\n", *argv);
+            continue;
+        }
+        if (!(nics = libxl_list_nics(&ctx, domid, &nb))) {
+            continue;
+        }
+        for (; nb > 0; --nb, ++nics) {
+            /* Idx BE */
+            printf("%-3d %-2d ", nics->devid, nics->backend_id);
+            /* MAC */
+            printf("%02x:%02x:%02x:%02x:%02x:%02x ",
+                   nics->mac[0], nics->mac[1], nics->mac[2],
+                   nics->mac[3], nics->mac[4], nics->mac[5]);
+            /* Hdl  Sta  evch txr/rxr  BE-path */
+            printf("%6d %5d %6d %5d/%-11d %-30s\n",
+                   nics->devid, nics->state, nics->evtch,
+                   nics->rref_tx, nics->rref_rx, nics->backend);
+        }
+    }
+    exit(0);
+}
+
+int main_networkdetach(int argc, char **argv)
+{
+    int opt;
+    libxl_device_nic nic;
+
+    if (argc != 4) {
+        help("network-detach");
+        exit(0);
+    }
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("network-detach");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    if (domain_qualifier_to_domid(argv[2], &domid, 0) < 0) {
+        fprintf(stderr, "%s is an invalid domain identifier\n", argv[2]);
+        exit(1);
+    }
+
+    if (!strchr(argv[3], ':')) {
+        if (libxl_devid_to_device_nic(&ctx, domid, argv[3], &nic)) {
+            fprintf(stderr, "Unknown device %s.\n", argv[3]);
+            exit(1);
+        }
+    } else {
+        if (libxl_mac_to_device_nic(&ctx, domid, argv[3], &nic)) {
+            fprintf(stderr, "Unknown device %s.\n", argv[3]);
+            exit(1);
+        }
+    }
+    if (libxl_device_nic_del(&ctx, &nic, 1)) {
+        fprintf(stderr, "libxl_device_nic_del failed.\n");
+        exit(1);
+    }
+    exit(0);
+}
+
+int main_blockattach(int argc, char **argv)
+{
+    int opt;
+    char *tok;
+    uint32_t fe_domid, be_domid = 0;
+    libxl_device_disk disk = { 0 };
+
+    if ((argc < 5) || (argc > 7)) {
+        help("block-attach");
+        exit(0);
+    }
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("block-attach");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    tok = strtok(argv[3], ":");
+    if (!strcmp(tok, "phy")) {
+        disk.phystype = PHYSTYPE_PHY;
+    } else if (!strcmp(tok, "file")) {
+        disk.phystype = PHYSTYPE_FILE;
+    } else if (!strcmp(tok, "tap")) {
+        tok = strtok(NULL, ":");
+        if (!strcmp(tok, "aio")) {
+            disk.phystype = PHYSTYPE_AIO;
+        } else if (!strcmp(tok, "vhd")) {
+            disk.phystype = PHYSTYPE_VHD;
+        } else if (!strcmp(tok, "qcow")) {
+            disk.phystype = PHYSTYPE_QCOW;
+        } else if (!strcmp(tok, "qcow2")) {
+            disk.phystype = PHYSTYPE_QCOW2;
+        } else {
+            fprintf(stderr, "Error: `%s' is not a valid disk image.\n", tok);
+            exit(1);
+        }
+    } else {
+        fprintf(stderr, "Error: `%s' is not a valid block device.\n", tok);
+        exit(1);
+    }
+    disk.physpath = strtok(NULL, "\0");
+    if (!disk.physpath) {
+        fprintf(stderr, "Error: missing path to disk image.\n");
+        exit(1);
+    }
+    disk.virtpath = argv[4];
+    disk.unpluggable = 1;
+    disk.readwrite = ((argc <= 4) || (argv[5][0] == 'w'));
+
+    if (domain_qualifier_to_domid(argv[2], &fe_domid, 0) < 0) {
+        fprintf(stderr, "%s is an invalid domain identifier\n", argv[2]);
+        exit(1);
+    }
+    if (argc == 7) {
+        if (domain_qualifier_to_domid(argv[6], &be_domid, 0) < 0) {
+            fprintf(stderr, "%s is an invalid domain identifier\n", argv[6]);
+            exit(1);
+        }
+    }
+    disk.domid = fe_domid;
+    disk.backend_domid = be_domid;
+    if (libxl_device_disk_add(&ctx, fe_domid, &disk)) {
+        fprintf(stderr, "libxl_device_disk_add failed.\n");
+    }
+    exit(0);
+}
+
+int main_blocklist(int argc, char **argv)
+{
+    int opt;
+    int nb;
+    libxl_device_disk *disks;
+    libxl_diskinfo diskinfo;
+
+    if (argc < 3) {
+        help("block-list");
+        exit(0);
+    }
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("block-list");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    printf("%-5s %-3s %-6s %-5s %-6s %-8s %-30s\n",
+           "Vdev", "BE", "handle", "state", "evt-ch", "ring-ref", "BE-path");
+    for (argv += 2, argc -= 2; argc > 0; --argc, ++argv) {
+        if (domain_qualifier_to_domid(*argv, &domid, 0) < 0) {
+            fprintf(stderr, "%s is an invalid domain identifier\n", *argv);
+            continue;
+        }
+        disks = libxl_device_disk_list(&ctx, domid, &nb);
+        if (!disks) {
+            continue;
+        }
+        for (; nb > 0; --nb, ++disks) {
+            if (!libxl_device_disk_getinfo(&ctx, domid, disks, &diskinfo)) {
+                /*      Vdev BE   hdl  st   evch rref BE-path*/
+                printf("%-5d %-3d %-6d %-5d %-6d %-8d %-30s\n",
+                       diskinfo.devid, diskinfo.backend_id, 
diskinfo.frontend_id,
+                       diskinfo.state, diskinfo.evtch, diskinfo.rref, 
diskinfo.backend);
+            }
+        }
+    }
+    exit(0);
+}
+
+int main_blockdetach(int argc, char **argv)
+{
+    int opt;
+    libxl_device_disk disk;
+
+    if (argc != 4) {
+        help("block-detach");
+        exit(0);
+    }
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("block-detach");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    if (domain_qualifier_to_domid(argv[2], &domid, 0) < 0) {
+        fprintf(stderr, "%s is an invalid domain identifier\n", argv[2]);
+        exit(1);
+    }
+    if (libxl_devid_to_device_disk(&ctx, domid, argv[3], &disk)) {
+        fprintf(stderr, "Error: Device %s not connected.\n", argv[3]);
+        exit(1);
+    }
+    if (libxl_device_disk_del(&ctx, &disk, 1)) {
+        fprintf(stderr, "libxl_device_del failed.\n");
+    }
+    exit(0);
+}
+
+static char *uptime_to_string(unsigned long time, int short_mode)
+{
+    int sec, min, hour, day;
+    char *time_string;
+    int ret;
+
+    day = (int)(time / 86400);
+    time -= (day * 86400);
+    hour = (int)(time / 3600);
+    time -= (hour * 3600);
+    min = (int)(time / 60);
+    time -= (min * 60);
+    sec = time;
+
+    if (short_mode)
+        if (day > 1)
+            ret = asprintf(&time_string, "%d days, %2d:%02d", day, hour, min);
+        else if (day == 1)
+            ret = asprintf(&time_string, "%d day, %2d:%02d", day, hour, min);
+        else
+            ret = asprintf(&time_string, "%2d:%02d", hour, min);
+    else
+        if (day > 1)
+            ret = asprintf(&time_string, "%d days, %2d:%02d:%02d", day, hour, 
min, sec);
+        else if (day == 1)
+            ret = asprintf(&time_string, "%d day, %2d:%02d:%02d", day, hour, 
min, sec);
+        else
+            ret = asprintf(&time_string, "%2d:%02d:%02d", hour, min, sec);
+
+    if (ret < 0)
+        return NULL;
+    return time_string;
+}
+
+static char *current_time_to_string(time_t now)
+{
+    char now_str[100];
+    struct tm *tmp;
+
+    tmp = localtime(&now);
+    if (tmp == NULL) {
+        fprintf(stderr, "Get localtime error");
+        exit(-1);
+    }
+    if (strftime(now_str, sizeof(now_str), "%H:%M:%S", tmp) == 0) {
+        fprintf(stderr, "strftime returned 0");
+        exit(-1);
+    }
+    return strdup(now_str);
+}
+
+static void print_dom0_uptime(int short_mode, time_t now)
+{
+    int fd;
+    char buf[512];
+    uint32_t uptime = 0;
+    char *uptime_str = NULL;
+    char *now_str = NULL;
+
+    fd = open("/proc/uptime", O_RDONLY);
+    if (fd == -1)
+        goto err;
+
+    if (read(fd, buf, sizeof(buf)) == -1) {
+        close(fd);
+        goto err;
+    }
+    close(fd);
+
+    strtok(buf, " ");
+    uptime = strtoul(buf, NULL, 10);
+
+    if (short_mode)
+    {
+        now_str = current_time_to_string(now);
+        uptime_str = uptime_to_string(uptime, 1);
+        printf(" %s up %s, %s (%d)\n", now_str, uptime_str,
+               libxl_domid_to_name(&ctx, 0), 0);
+    }
+    else
+    {
+        uptime_str = uptime_to_string(uptime, 0);
+        printf("%-33s %4d %s\n", libxl_domid_to_name(&ctx, 0),
+               0, uptime_str);
+    }
+
+    if (now_str)
+        free(now_str);
+    if (uptime_str)
+        free(uptime_str);
+    return;
+err:
+    fprintf(stderr, "Can not get Dom0 uptime.\n");
+    exit(-1);
+}
+
+static void print_domU_uptime(uint32_t domuid, int short_mode, time_t now)
+{
+    uint32_t s_time = 0;
+    uint32_t uptime = 0;
+    char *uptime_str = NULL;
+    char *now_str = NULL;
+
+    s_time = libxl_vm_get_start_time(&ctx, domuid);
+    if (s_time == -1)
+        return;
+    uptime = now - s_time;
+    if (short_mode)
+    {
+        now_str = current_time_to_string(now);
+        uptime_str = uptime_to_string(uptime, 1);
+        printf(" %s up %s, %s (%d)\n", now_str, uptime_str,
+               libxl_domid_to_name(&ctx, domuid), domuid);
+    }
+    else
+    {
+        uptime_str = uptime_to_string(uptime, 0);
+        printf("%-33s %4d %s\n", libxl_domid_to_name(&ctx, domuid),
+               domuid, uptime_str);
+    }
+
+    if (now_str)
+        free(now_str);
+    if (uptime_str)
+        free(uptime_str);
+    return;
+}
+
+static void print_uptime(int short_mode, uint32_t doms[], int nb_doms)
+{
+    struct libxl_vminfo *info;
+    time_t now;
+    int nb_vm, i;
+
+    now = time(NULL);
+
+    if (!short_mode)
+        printf("%-33s %4s %s\n", "Name", "ID", "Uptime");
+
+    if (nb_doms == 0) {
+        print_dom0_uptime(short_mode, now);
+        info = libxl_list_vm(&ctx, &nb_vm);
+        for (i = 0; i < nb_vm; i++)
+            print_domU_uptime(info[i].domid, short_mode, now);
+    } else {
+        for (i = 0; i < nb_doms; i++) {
+            if (doms[i] == 0)
+                print_dom0_uptime(short_mode, now);
+            else
+                print_domU_uptime(doms[i], short_mode, now);
+        }
+    }
+}
+
+int main_uptime(int argc, char **argv)
+{
+    char *dom = NULL;
+    int short_mode = 0;
+    uint32_t domains[100];
+    int nb_doms = 0;
+    int opt;
+
+    while ((opt = getopt(argc, argv, "hs")) != -1) {
+        switch (opt) {
+        case 's':
+            short_mode = 1;
+            break;
+        case 'h':
+            help("uptime");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    for (;(dom = argv[optind]) != NULL; nb_doms++,optind++) {
+        find_domain(dom);
+        domains[nb_doms] = domid;
+    }
+
+    print_uptime(short_mode, domains, nb_doms);
+
+    exit(0);
+}
+
+int main_tmem_list(int argc, char **argv)
+{
+    char *dom = NULL;
+    char *buf = NULL;
+    int use_long = 0;
+    int all = 0;
+    int opt;
+
+    while ((opt = getopt(argc, argv, "alh")) != -1) {
+        switch (opt) {
+        case 'l':
+            use_long = 1;
+            break;
+        case 'a':
+            all = 1;
+            break;
+        case 'h':
+            help("tmem-list");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    dom = argv[optind];
+    if (!dom && all == 0) {
+        fprintf(stderr, "You must specify -a or a domain id.\n\n");
+        help("tmem-list");
+        exit(1);
+    }
+
+    if (all)
+        domid = -1;
+    else
+        find_domain(dom);
+
+    buf = libxl_tmem_list(&ctx, domid, use_long);
+    if (buf == NULL)
+        exit(-1);
+
+    printf("%s\n", buf);
+    free(buf);
+    exit(0);
+}
+
+int main_tmem_freeze(int argc, char **argv)
+{
+    char *dom = NULL;
+    int all = 0;
+    int opt;
+
+    while ((opt = getopt(argc, argv, "ah")) != -1) {
+        switch (opt) {
+        case 'a':
+            all = 1;
+            break;
+        case 'h':
+            help("tmem-freeze");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    dom = argv[optind];
+    if (!dom && all == 0) {
+        fprintf(stderr, "You must specify -a or a domain id.\n\n");
+        help("tmem-freeze");
+        exit(1);
+    }
+
+    if (all)
+        domid = -1;
+    else
+        find_domain(dom);
+
+    libxl_tmem_freeze(&ctx, domid);
+    exit(0);
+}
+
+int main_tmem_destroy(int argc, char **argv)
+{
+    char *dom = NULL;
+    int all = 0;
+    int opt;
+
+    while ((opt = getopt(argc, argv, "ah")) != -1) {
+        switch (opt) {
+        case 'a':
+            all = 1;
+            break;
+        case 'h':
+            help("tmem-destroy");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    dom = argv[optind];
+    if (!dom && all == 0) {
+        fprintf(stderr, "You must specify -a or a domain id.\n\n");
+        help("tmem-destroy");
+        exit(1);
+    }
+
+    if (all)
+        domid = -1;
+    else
+        find_domain(dom);
+
+    libxl_tmem_destroy(&ctx, domid);
+    exit(0);
+}
+
+int main_tmem_thaw(int argc, char **argv)
+{
+    char *dom = NULL;
+    int all = 0;
+    int opt;
+
+    while ((opt = getopt(argc, argv, "ah")) != -1) {
+        switch (opt) {
+        case 'a':
+            all = 1;
+            break;
+        case 'h':
+            help("tmem-thaw");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    dom = argv[optind];
+    if (!dom && all == 0) {
+        fprintf(stderr, "You must specify -a or a domain id.\n\n");
+        help("tmem-thaw");
+        exit(1);
+    }
+
+    if (all)
+        domid = -1;
+    else
+        find_domain(dom);
+
+    libxl_tmem_thaw(&ctx, domid);
+    exit(0);
+}
+
+int main_tmem_set(int argc, char **argv)
+{
+    char *dom = NULL;
+    uint32_t weight = 0, cap = 0, compress = 0;
+    int opt_w = 0, opt_c = 0, opt_p = 0;
+    int all = 0;
+    int opt;
+
+    while ((opt = getopt(argc, argv, "aw:c:p:h")) != -1) {
+        switch (opt) {
+        case 'a':
+            all = 1;
+            break;
+        case 'w':
+            weight = strtol(optarg, NULL, 10);
+            opt_w = 1;
+            break;
+        case 'c':
+            cap = strtol(optarg, NULL, 10);
+            opt_c = 1;
+            break;
+        case 'p':
+            compress = strtol(optarg, NULL, 10);
+            opt_p = 1;
+            break;
+        case 'h':
+            help("tmem-set");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    dom = argv[optind];
+    if (!dom && all == 0) {
+        fprintf(stderr, "You must specify -a or a domain id.\n\n");
+        help("tmem-set");
+        exit(1);
+    }
+
+    if (all)
+        domid = -1;
+    else
+        find_domain(dom);
+
+    if (!opt_w && !opt_c && !opt_p) {
+        fprintf(stderr, "No set value specified.\n\n");
+        help("tmem-set");
+        exit(1);
+    }
+
+    if (opt_w)
+        libxl_tmem_set(&ctx, domid, "weight", weight);
+    if (opt_c)
+        libxl_tmem_set(&ctx, domid, "cap", cap);
+    if (opt_p)
+        libxl_tmem_set(&ctx, domid, "compress", compress);
+
+    exit(0);
+}
+
+int main_tmem_shared_auth(int argc, char **argv)
+{
+    char *autharg = NULL;
+    char *endptr = NULL;
+    char *dom = NULL;
+    char *uuid = NULL;
+    int auth = -1;
+    int all = 0;
+    int opt;
+
+    while ((opt = getopt(argc, argv, "au:A:h")) != -1) {
+        switch (opt) {
+        case 'a':
+            all = 1;
+            break;
+        case 'u':
+            uuid = optarg;
+            break;
+        case 'A':
+            autharg = optarg;
+            break;
+        case 'h':
+            help("tmem-shared-auth");
+            exit(0);
+        default:
+            fprintf(stderr, "option `%c' not supported.\n", opt);
+            break;
+        }
+    }
+
+    dom = argv[optind];
+    if (!dom && all == 0) {
+        fprintf(stderr, "You must specify -a or a domain id.\n\n");
+        help("tmem-shared-auth");
+        exit(1);
+    }
+
+    if (all)
+        domid = -1;
+    else
+        find_domain(dom);
+
+    if (uuid == NULL || autharg == NULL) {
+        fprintf(stderr, "No uuid or auth specified.\n\n");
+        help("tmem-shared-auth");
+        exit(1);
+    }
+
+    auth = strtol(autharg, &endptr, 10);
+    if (*endptr != '\0') {
+        fprintf(stderr, "Invalid auth, valid auth are <0|1>.\n\n");
+        exit(1);
+    }
+
+    libxl_tmem_shared_auth(&ctx, domid, uuid, auth);
+
+    exit(0);
+}
+
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/libxl/xl_cmdtable.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxl/xl_cmdtable.c Mon Jul 05 12:19:50 2010 +0100
@@ -0,0 +1,322 @@
+/*
+ * Author Yang Hongyang <yanghy@xxxxxxxxxxxxxx>
+ *
+ * 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 "xl.h"
+
+struct cmd_spec cmd_table[] = {
+    { "create",
+      &main_create,
+      "Create a domain from config file <filename>",
+      "<ConfigFile> [options] [vars]",
+      "-h                      Print this help.\n"
+      "-p                      Leave the domain paused after it is created.\n"
+      "-c                      Connect to the console after the domain is 
created.\n"
+      "-d                      Enable debug messages.\n"
+      "-f=FILE, --defconfig=FILE\n                     Use the given 
configuration file.\n"
+      "-q, --quiet             Quiet.\n"
+      "-n, --dryrun            Dry run - prints the resulting configuration.\n"
+      "-d                      Enable debug messages.\n"
+      "-e                      Do not wait in the background for the death of 
the domain."
+    },
+    { "list",
+      &main_list,
+      "List information about all/some domains",
+      "[options] [Domain]\n",
+      "-l, --long                              Output all VM details"
+      "-v, --verbose                   Prints out UUIDs",
+    },
+    { "destroy",
+      &main_destroy,
+      "Terminate a domain immediately",
+      "<Domain>",
+    },
+    { "shutdown",
+      &main_shutdown,
+      "Issue a shutdown signal to a domain",
+      "<Domain>",
+    },
+    { "reboot",
+      &main_reboot,
+      "Issue a reboot signal to a domain",
+      "<Domain>",
+    }, 
+    { "pci-attach",
+      &main_pciattach,
+      "Insert a new pass-through pci device",
+      "<Domain> <BDF> [Virtual Slot]",
+    },
+    { "pci-detach",
+      &main_pcidetach,
+      "Remove a domain's pass-through pci device",
+      "<Domain> <BDF>",
+    },
+    { "pci-list",
+      &main_pcilist,
+      "List pass-through pci devices for a domain",
+      "<Domain>",
+    },
+    { "pause",
+      &main_pause,
+      "Pause execution of a domain",
+      "<Domain>",
+    },
+    { "unpause",
+      &main_unpause,
+      "Unpause a paused domain",
+      "<Domain>",
+    },
+    { "console",
+      &main_console,
+      "Attach to domain's console",
+      "<Domain>",
+    },
+    { "save",
+      &main_save,
+      "Save a domain state to restore later",
+      "[options] <Domain> <CheckpointFile> [<ConfigFile>]",
+      "-h  Print this help.\n"
+      "-c  Leave domain running after creating the snapshot."
+    },
+    { "migrate",
+      &main_migrate,
+      "Save a domain state to restore later",
+      "[options] <Domain> <host>",
+      "-h              Print this help.\n"
+      "-C <config>     Send <config> instead of config file from creation.\n"
+      "-s <sshcommand> Use <sshcommand> instead of ssh.  String will be 
passed\n"
+      "                to sh. If empty, run <host> instead of ssh <host> xl\n"
+      "                migrate-receive [-d -e]\n"
+      "-e              Do not wait in the background (on <host>) for the 
death\n"
+      "                of the domain."
+    },
+    { "restore",
+      &main_restore,
+      "Restore a domain from a saved state",
+      "[options] [<ConfigFile>] <CheckpointFile>",
+      "-h  Print this help.\n"
+      "-p  Do not unpause domain after restoring it.\n"
+      "-e  Do not wait in the background for the death of the domain.\n"
+      "-d  Enable debug messages."
+    },
+    { "migrate-receive",
+      &main_migrate_receive,
+      "Restore a domain from a saved state",
+      "- for internal use only",
+    },
+    { "cd-insert",
+      &main_cd_insert,
+      "Insert a cdrom into a guest's cd drive",
+      "<Domain> <VirtualDevice> <type:path>",
+    },
+    { "cd-eject",
+      &main_cd_eject,
+      "Eject a cdrom from a guest's cd drive",
+      "<Domain> <VirtualDevice>",
+    },
+    { "mem-max",
+      &main_memmax,
+      "Set the maximum amount reservation for a domain",
+      "<Domain> <MemMB['b'[bytes]|'k'[KB]|'m'[MB]|'g'[GB]|'t'[TB]]>",
+    },
+    { "mem-set",
+      &main_memset,
+      "Set the current memory usage for a domain",
+      "<Domain> <MemMB['b'[bytes]|'k'[KB]|'m'[MB]|'g'[GB]|'t'[TB]]>",
+    },
+    { "button-press",
+      &main_button_press,
+      "Indicate an ACPI button press to the domain",
+      "<Domain> <Button>",
+      "<Button> may be 'power' or 'sleep'."
+    },
+    { "vcpu-list",
+      &main_vcpulist,
+      "List the VCPUs for all/some domains",
+      "[Domain, ...]",
+    },
+    { "vcpu-pin",
+      &main_vcpupin,
+      "Set which CPUs a VCPU can use",
+      "<Domain> <VCPU|all> <CPUs|all>",
+    },
+    { "vcpu-set",
+      &main_vcpuset,
+      "Set the number of active VCPUs allowed for the domain",
+      "<Domain> <vCPUs>",
+    },
+    { "list-vm",
+      &main_list_vm,
+      "List the VMs,without DOM0",
+      "",
+    },
+    { "info",
+      &main_info,
+      "Get information about Xen host",
+      "",
+    },
+    { "sched-credit",
+      &main_sched_credit,
+      "Get/set credit scheduler parameters",
+      "[-d <Domain> [-w[=WEIGHT]|-c[=CAP]]]",
+      "-d DOMAIN, --domain=DOMAIN     Domain to modify\n"
+      "-w WEIGHT, --weight=WEIGHT     Weight (int)\n"
+      "-c CAP, --cap=CAP              Cap (int)"
+    },
+    { "domid",
+      &main_domid,
+      "Convert a domain name to domain id",
+      "<DomainName>",
+    },
+    { "domname",
+      &main_domname,
+      "Convert a domain id to domain name",
+      "<DomainId>",
+    },
+    { "rename",
+      &main_rename,
+      "Rename a domain",
+      "<Domain> <NewDomainName>",
+    },
+    { "trigger",
+      &main_trigger,
+      "Send a trigger to a domain",
+      "<Domain> <nmi|reset|init|power|sleep> [<VCPU>]",
+    },
+    { "sysrq",
+      &main_sysrq,
+      "Send a sysrq to a domain",
+      "<Domain> <letter>",
+    },
+    { "debug-keys",
+      &main_debug_keys,
+      "Send debug keys to Xen",
+      "<Keys>",
+    },
+    { "dmesg",
+      &main_dmesg,
+      "Read and/or clear dmesg buffer",
+      "[-c]",
+      "  -c                        Clear dmesg buffer as well as printing it",
+    },
+    { "top",
+      &main_top,
+      "Monitor a host and the domains in real time",
+      "",
+    },
+    { "network-attach",
+      &main_networkattach,
+      "Create a new virtual network device",
+      "<Domain> [type=<type>] [mac=<mac>] [bridge=<bridge>] "
+      "[ip=<ip>] [script=<script>] [backend=<BackDomain>] [vifname=<name>] "
+      "[rate=<rate>] [model=<model>][accel=<accel>]",
+    },
+    { "network-list",
+      &main_networklist,
+      "List virtual network interfaces for a domain",
+      "<Domain(s)>",
+    },
+    { "network-detach",
+      &main_networkdetach,
+      "Destroy a domain's virtual network device",
+      "<Domain> <DevId|mac>",
+    },
+    { "block-attach",
+      &main_blockattach,
+      "Create a new virtual block device",
+      "<Domain> <BackDev> <FrontDev> [<Mode>] [BackDomain]",
+    },
+    { "block-list",
+      &main_blocklist,
+      "List virtual block devices for a domain",
+      "<Domain(s)>",
+    },
+    { "block-detach",
+      &main_blockdetach,
+      "Destroy a domain's virtual block device",
+      "<Domain> <DevId>",
+    },
+    { "uptime",
+      &main_uptime,
+      "Print uptime for all/some domains",
+      "[-s] [Domain]",
+    },
+    { "tmem-list",
+      &main_tmem_list,
+      "List tmem pools",
+      "[-l] [<Domain>|-a]",
+      "  -l                             List tmem stats",
+    },
+    { "tmem-freeze",
+      &main_tmem_freeze,
+      "Freeze tmem pools",
+      "[<Domain>|-a]",
+      "  -a                             Freeze all tmem",
+    },
+    { "tmem-destroy",
+      &main_tmem_destroy,
+      "Destroy tmem pools",
+      "[<Domain>|-a]",
+      "  -a                             Destroy all tmem",
+    },
+    { "tmem-thaw",
+      &main_tmem_thaw,
+      "Thaw tmem pools",
+      "[<Domain>|-a]",
+      "  -a                             Thaw all tmem",
+    },
+    { "tmem-set",
+      &main_tmem_set,
+      "Change tmem settings",
+      "[<Domain>|-a] [-w[=WEIGHT]|-c[=CAP]|-p[=COMPRESS]]",
+      "  -a                             Operate on all tmem\n"
+      "  -w WEIGHT                      Weight (int)\n"
+      "  -c CAP                         Cap (int)\n"
+      "  -p COMPRESS                    Compress (int)",
+    },
+    { "tmem-shared-auth",
+      &main_tmem_shared_auth,
+      "De/authenticate shared tmem pool",
+      "[<Domain>|-a] [-u[=UUID] [-A[=AUTH]",
+      "  -a                             Authenticate for all tmem pools\n"
+      "  -u UUID                        Specify uuid\n"
+      "                                 
(abcdef01-2345-6789-1234-567890abcdef)\n"
+      "  -A AUTH                        0=auth,1=deauth",
+    },
+};
+
+int cmdtable_len = sizeof(cmd_table)/sizeof(struct cmd_spec);
+
+/* Look up a command in the table, allowing unambiguous truncation */
+struct cmd_spec *cmdtable_lookup(const char *s)
+{
+    struct cmd_spec *cmd = NULL;
+    size_t len;
+    int i, count = 0;
+
+    if (!s) 
+        return NULL;
+    len = strlen(s);
+    for (i = 0; i < cmdtable_len; i++) {
+        if (!strncmp(s, cmd_table[i].cmd_name, len)) {
+            cmd = &cmd_table[i];
+            /* Take an exact match, even if it also prefixes another command */
+            if (len == strlen(cmd->cmd_name))
+                return cmd;
+            count++;
+        }
+    }
+    return (count == 1) ? cmd : NULL;
+}
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/xenstore/xs.c
--- a/tools/xenstore/xs.c       Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/xenstore/xs.c       Mon Jul 05 12:19:50 2010 +0100
@@ -236,10 +236,39 @@
        return get_handle(xs_domain_dev());
 }
 
+static void close_free_msgs(struct xs_handle *h) {
+       struct xs_stored_msg *msg, *tmsg;
+
+       list_for_each_entry_safe(msg, tmsg, &h->reply_list, list) {
+               free(msg->body);
+               free(msg);
+       }
+
+       list_for_each_entry_safe(msg, tmsg, &h->watch_list, list) {
+               free(msg->body);
+               free(msg);
+       }
+}
+
+static void close_fds_free(struct xs_handle *h) {
+       if (h->watch_pipe[0] != -1) {
+               close(h->watch_pipe[0]);
+               close(h->watch_pipe[1]);
+       }
+
+       close(h->fd);
+
+       free(h);
+}
+
+void xs_daemon_destroy_postfork(struct xs_handle *h)
+{
+        close_free_msgs(h);
+        close_fds_free(h);
+}
+
 void xs_daemon_close(struct xs_handle *h)
 {
-       struct xs_stored_msg *msg, *tmsg;
-
 #ifdef USE_PTHREAD
        if (h->read_thr_exists) {
                pthread_cancel(h->read_thr);
@@ -251,28 +280,11 @@
        mutex_lock(&h->reply_mutex);
        mutex_lock(&h->watch_mutex);
 
-       list_for_each_entry_safe(msg, tmsg, &h->reply_list, list) {
-               free(msg->body);
-               free(msg);
-       }
-
-       list_for_each_entry_safe(msg, tmsg, &h->watch_list, list) {
-               free(msg->body);
-               free(msg);
-       }
+       close_free_msgs(h);
 
        mutex_unlock(&h->request_mutex);
        mutex_unlock(&h->reply_mutex);
        mutex_unlock(&h->watch_mutex);
-
-       if (h->watch_pipe[0] != -1) {
-               close(h->watch_pipe[0]);
-               close(h->watch_pipe[1]);
-       }
-
-       close(h->fd);
-
-       free(h);
 }
 
 static bool read_all(int fd, void *data, unsigned int len)
diff -r 7dcfdd45bc9e -r a047b47a54ee tools/xenstore/xs.h
--- a/tools/xenstore/xs.h       Tue Jun 22 07:31:14 2010 +0100
+++ b/tools/xenstore/xs.h       Mon Jul 05 12:19:50 2010 +0100
@@ -48,6 +48,9 @@
 /* Close the connection to the xs daemon. */
 void xs_daemon_close(struct xs_handle *);
 
+/* Throw away the connection to the xs daemon, for use after fork(). */
+void xs_daemon_destroy_postfork(struct xs_handle *);
+
 /* Get contents of a directory.
  * Returns a malloced array: call free() on it after use.
  * Num indicates size.





_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

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