aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2010-07-06 16:49:01 +0100
committerKeir Fraser <keir.fraser@citrix.com>2010-07-06 16:49:01 +0100
commit8052af351e301fd0040aa3223a846e43a854b487 (patch)
treef58004910f6f5c4f759498e1d5a07dedf20d182b
parent87a31ef2dba39e7ce779a8c86fc50e055a85145b (diff)
downloadxen-8052af351e301fd0040aa3223a846e43a854b487.tar.gz
xen-8052af351e301fd0040aa3223a846e43a854b487.tar.bz2
xen-8052af351e301fd0040aa3223a846e43a854b487.zip
libxl: Backported stuff from unstable
Signed-off-by: Gianni Tedesco <gianni.tedesco@citrix.com>
-rw-r--r--tools/libxl/Makefile28
-rw-r--r--tools/libxl/bash-completion21
-rw-r--r--tools/libxl/libxl.c1030
-rw-r--r--tools/libxl/libxl.h191
-rw-r--r--tools/libxl/libxl_device.c78
-rw-r--r--tools/libxl/libxl_dom.c194
-rw-r--r--tools/libxl/libxl_exec.c34
-rw-r--r--tools/libxl/libxl_internal.c13
-rw-r--r--tools/libxl/libxl_internal.h24
-rw-r--r--tools/libxl/libxl_paths.c61
-rw-r--r--tools/libxl/libxl_utils.c297
-rw-r--r--tools/libxl/libxl_utils.h45
-rw-r--r--tools/libxl/libxl_xshelp.c6
-rw-r--r--tools/libxl/libxlu_cfg.c37
-rw-r--r--tools/libxl/libxlutil.h3
-rw-r--r--tools/libxl/xenguest.c18
-rw-r--r--tools/libxl/xl.c1741
-rw-r--r--tools/libxl/xl.h81
-rw-r--r--tools/libxl/xl_cmdimpl.c4243
-rw-r--r--tools/libxl/xl_cmdtable.c322
-rw-r--r--tools/xenstore/xs.c46
-rw-r--r--tools/xenstore/xs.h3
22 files changed, 6549 insertions, 1967 deletions
diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 75ac02aa47..53bc909cf0 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -11,13 +11,13 @@ MINOR = 0
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 @@ $(LIBXLU_OBJS): $(AUTOINCS)
%.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 @@ libxlutil.a: $(LIBXLU_OBJS)
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 @@ install: all
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 --git a/tools/libxl/bash-completion b/tools/libxl/bash-completion
new file mode 100644
index 0000000000..b184f7494d
--- /dev/null
+++ b/tools/libxl/bash-completion
@@ -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 --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 0b1b6dba31..e9669f20af 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -45,6 +45,7 @@ int libxl_ctx_init(struct libxl_ctx *ctx, int version)
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 @@ int libxl_ctx_free(struct libxl_ctx *ctx)
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_ctx_set_log(struct libxl_ctx *ctx, libxl_log_callback log_callback, vo
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 @@ int libxl_domain_make(struct libxl_ctx *ctx, libxl_domain_create_info *info,
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 @@ retry_transaction:
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 @@ retry_transaction:
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 @@ int libxl_domain_restore(struct libxl_ctx *ctx, libxl_domain_build_info *info,
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 @@ int libxl_domain_restore(struct libxl_ctx *ctx, libxl_domain_build_info *info,
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 @@ int libxl_domain_restore(struct libxl_ctx *ctx, libxl_domain_build_info *info,
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 @@ int libxl_domain_resume(struct libxl_ctx *ctx, uint32_t domid)
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 @@ struct libxl_dominfo * libxl_list_domain(struct libxl_ctx *ctx, int *nb_domain)
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 libxl_domain_suspend(struct libxl_ctx *ctx, libxl_domain_suspend_info *info,
{
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 @@ int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req)
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_get_wait_fd(struct libxl_ctx *ctx, int *fd)
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 @@ int libxl_wait_for_disk_ejects(struct libxl_ctx *ctx, uint32_t guest_domid, libx
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 @@ int libxl_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force)
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_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force)
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 @@ static char ** libxl_build_device_model_args(struct libxl_ctx *ctx,
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 @@ static char ** libxl_build_device_model_args(struct libxl_ctx *ctx,
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 @@ static char ** libxl_build_device_model_args(struct libxl_ctx *ctx,
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 @@ static char ** libxl_build_device_model_args(struct libxl_ctx *ctx,
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 @@ static char ** libxl_build_device_model_args(struct libxl_ctx *ctx,
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 @@ void dm_xenstore_record_pid(void *for_spawn, pid_t innerchild)
/* 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 @@ static int libxl_vfb_and_vkb_from_device_model_info(struct libxl_ctx *ctx,
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 @@ static int libxl_create_stubdom(struct libxl_ctx *ctx,
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 libxl_create_device_model(struct libxl_ctx *ctx,
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 @@ int libxl_create_device_model(struct libxl_ctx *ctx,
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 @@ int libxl_create_device_model(struct libxl_ctx *ctx,
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 @@ static char *get_blktap2_device(struct libxl_ctx *ctx, char *name, char *type)
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 @@ int libxl_device_disk_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_di
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 @@ int libxl_device_disk_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_di
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 @@ int libxl_device_nic_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_nic
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 @@ int libxl_device_nic_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_nic
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 @@ int libxl_device_nic_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_nic
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 @@ int libxl_device_nic_del(struct libxl_ctx *ctx,
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 @@ int libxl_device_vkb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
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);
+ }
+ 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;
}
- *num = num_disks;
- return disks;
+ 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 @@ static int libxl_build_xenpv_qemu_args(struct libxl_ctx *ctx,
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 @@ static int libxl_build_xenpv_qemu_args(struct libxl_ctx *ctx,
}
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 @@ int libxl_device_vfb_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_vfb
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 @@ int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci
/* 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 @@ int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci
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 @@ int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci
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 @@ int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci
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 @@ int libxl_device_pci_remove(struct libxl_ctx *ctx, uint32_t domid, libxl_device_
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 @@ skip1:
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 @@ skip1:
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 @@ int libxl_device_pci_shutdown(struct libxl_ctx *ctx, uint32_t domid)
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 @@ int libxl_button_press(struct libxl_ctx *ctx, uint32_t domid, libxl_button butto
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 --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 84e412a0c6..1065b002b4 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -41,6 +41,21 @@ struct libxl_vminfo {
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 @@ struct libxl_ctx {
* 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 @@ typedef struct {
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 @@ typedef struct {
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 @@ typedef struct {
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 @@ typedef struct {
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 @@ enum {
ERROR_NI = -3,
ERROR_NOMEM = -4,
ERROR_INVAL = -5,
+ ERROR_BADFAIL = -6,
};
#define LIBXL_VERSION 0
@@ -249,6 +275,7 @@ enum {
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_resume(struct libxl_ctx *ctx, uint32_t domid);
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_free_waiter(libxl_waiter *waiter);
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 @@ int libxl_detach_device_model(struct libxl_ctx *ctx,
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 @@ int libxl_device_pci_init(libxl_device_pci *pcidev, unsigned int domain,
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 @@ typedef enum {
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 --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 9fdd0b477a..7eeea1eb1a 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -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 @@ int libxl_devices_destroy(struct libxl_ctx *ctx, uint32_t domid, int force)
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 @@ int libxl_device_del(struct libxl_ctx *ctx, libxl_device *dev, int wait)
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;
-
- fd = fopen(do_flr, "w");
- if (fd != NULL) {
- fprintf(fd, PCI_BDF, domain, bus, dev, func);
- fclose(fd);
- return 0;
+ char *reset = "/sys/bus/pci/drivers/pciback/do_flr";
+ int fd, rc;
+
+ 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 @@ int libxl_wait_for_device_model(struct libxl_ctx *ctx,
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 @@ int libxl_wait_for_device_model(struct libxl_ctx *ctx,
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 --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
index 7196aa869e..7cfffa0e53 100644
--- a/tools/libxl/libxl_dom.c
+++ b/tools/libxl/libxl_dom.c
@@ -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 @@ int build_pre(struct libxl_ctx *ctx, uint32_t domid,
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 @@ int build_post(struct libxl_ctx *ctx, uint32_t domid,
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 build_hvm(struct libxl_ctx *ctx, uint32_t domid,
{
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 restore_common(struct libxl_ctx *ctx, uint32_t domid,
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 @@ int save_device_model(struct libxl_ctx *ctx, uint32_t domid, int fd)
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 --git a/tools/libxl/libxl_exec.c b/tools/libxl/libxl_exec.c
index e8cc74c7da..52dda97f5b 100644
--- a/tools/libxl/libxl_exec.c
+++ b/tools/libxl/libxl_exec.c
@@ -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 @@ void libxl_exec(int stdinfd, int stdoutfd, int stderrfd, char *arg0, char **args
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 @@ static void report_spawn_intermediate_status(struct libxl_ctx *ctx,
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 --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c
index f48e9eb109..ea16ad84ed 100644
--- a/tools/libxl/libxl_internal.c
+++ b/tools/libxl/libxl_internal.c
@@ -156,11 +156,13 @@ void xl_logv(struct libxl_ctx *ctx, int loglevel, int errnoval,
{
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 @@ void xl_logv(struct libxl_ctx *ctx, int loglevel, int errnoval,
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 @@ void xl_log(struct libxl_ctx *ctx, int loglevel, int errnoval,
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 --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 300c108bb4..e98e52dc37 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -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 @@ int restore_common(struct libxl_ctx *ctx, uint32_t domid,
libxl_domain_build_info *info, libxl_domain_build_state *state, int fd);
int core_suspend(struct libxl_ctx *ctx, uint32_t domid, int fd, int hvm, int live, int debug);
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 @@ int libxl_wait_for_device_model(struct libxl_ctx *ctx,
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 @@ int libxl_spawn_spawn(struct libxl_ctx *ctx,
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_exec(int stdinfd, int stdoutfd, int stderrfd, char *arg0, char **args
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 --git a/tools/libxl/libxl_paths.c b/tools/libxl/libxl_paths.c
new file mode 100644
index 0000000000..ceb1d73265
--- /dev/null
+++ b/tools/libxl/libxl_paths.c
@@ -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 --git a/tools/libxl/libxl_utils.c b/tools/libxl/libxl_utils.c
index 1ba9431459..dfef434202 100644
--- a/tools/libxl/libxl_utils.c
+++ b/tools/libxl/libxl_utils.c
@@ -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 @@ char *libxl_domid_to_name(struct libxl_ctx *ctx, uint32_t domid)
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 @@ int libxl_name_to_domid(struct libxl_ctx *ctx, char *name, uint32_t *domid)
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 @@ int libxl_is_stubdom(struct libxl_ctx *ctx, uint32_t domid, uint32_t *target_dom
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 @@ int libxl_create_logfile(struct libxl_ctx *ctx, char *name, char **full_name)
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 @@ out:
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 --git a/tools/libxl/libxl_utils.h b/tools/libxl/libxl_utils.h
index 05fa4e368f..b026c47713 100644
--- a/tools/libxl/libxl_utils.h
+++ b/tools/libxl/libxl_utils.h
@@ -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 --git a/tools/libxl/libxl_xshelp.c b/tools/libxl/libxl_xshelp.c
index 66de589c36..b5c6dbfccb 100644
--- a/tools/libxl/libxl_xshelp.c
+++ b/tools/libxl/libxl_xshelp.c
@@ -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 @@ int xs_writev(struct xs_handle *xsh, xs_transaction_t t, char *dir, char *kvs[])
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 *libxl_xs_get_dompath(struct libxl_ctx *ctx, uint32_t domid)
{
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 --git a/tools/libxl/libxlu_cfg.c b/tools/libxl/libxlu_cfg.c
index 632c371cf5..69a6b24b2d 100644
--- a/tools/libxl/libxlu_cfg.c
+++ b/tools/libxl/libxlu_cfg.c
@@ -53,6 +53,43 @@ int xlu_cfg_readfile(XLU_Config *cfg, const char *real_filename) {
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 --git a/tools/libxl/libxlutil.h b/tools/libxl/libxlutil.h
index 97b16aa134..0262e55eef 100644
--- a/tools/libxl/libxlutil.h
+++ b/tools/libxl/libxlutil.h
@@ -30,7 +30,8 @@ XLU_Config *xlu_cfg_init(FILE *report, const char *report_filename);
* 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 --git a/tools/libxl/xenguest.c b/tools/libxl/xenguest.c
index b30744d885..ddeabfa3c5 100644
--- a/tools/libxl/xenguest.c
+++ b/tools/libxl/xenguest.c
@@ -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 @@ int hvm_build_set_params(int handle, uint32_t domid,
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 --git a/tools/libxl/xl.c b/tools/libxl/xl.c
index 8518e8fd0e..462e1f6fa9 100644
--- a/tools/libxl/xl.c
+++ b/tools/libxl/xl.c
@@ -21,1752 +21,55 @@
#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);
+ 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_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)
+int main(int argc, char **argv)
{
- 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);
+ struct cmd_spec *cspec;
- info = libxl_list_domain(&ctx, &nb_domain);
-
- if (info < 0) {
- fprintf(stderr, "libxl_domain_infolist failed.\n");
+ if (argc < 2) {
+ help(NULL);
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);
-}
-
-int main(int argc, char **argv)
-{
- if (argc < 2) {
- help(NULL);
- 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");
diff --git a/tools/libxl/xl.h b/tools/libxl/xl.h
new file mode 100644
index 0000000000..ff1150ba52
--- /dev/null
+++ b/tools/libxl/xl.h
@@ -0,0 +1,81 @@
+/*
+ * Author Yang Hongyang <yanghy@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ */
+
+#ifndef 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 --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
new file mode 100644
index 0000000000..b84f33795e
--- /dev/null
+++ b/tools/libxl/xl_cmdimpl.c
@@ -0,0 +1,4243 @@
+/*
+ * Copyright (C) 2009 Citrix Ltd.
+ * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ */
+
+#include "libxl_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 --git a/tools/libxl/xl_cmdtable.c b/tools/libxl/xl_cmdtable.c
new file mode 100644
index 0000000000..611f5e4654
--- /dev/null
+++ b/tools/libxl/xl_cmdtable.c
@@ -0,0 +1,322 @@
+/*
+ * Author Yang Hongyang <yanghy@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ */
+
+#include <string.h>
+
+#include "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 --git a/tools/xenstore/xs.c b/tools/xenstore/xs.c
index 6dbdfd703a..2edabee4d0 100644
--- a/tools/xenstore/xs.c
+++ b/tools/xenstore/xs.c
@@ -236,21 +236,9 @@ struct xs_handle *xs_domain_open(void)
return get_handle(xs_domain_dev());
}
-void xs_daemon_close(struct xs_handle *h)
-{
+static void close_free_msgs(struct xs_handle *h) {
struct xs_stored_msg *msg, *tmsg;
-#ifdef USE_PTHREAD
- if (h->read_thr_exists) {
- pthread_cancel(h->read_thr);
- pthread_join(h->read_thr, NULL);
- }
-#endif
-
- mutex_lock(&h->request_mutex);
- 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);
@@ -260,11 +248,9 @@ void xs_daemon_close(struct xs_handle *h)
free(msg->body);
free(msg);
}
+}
- mutex_unlock(&h->request_mutex);
- mutex_unlock(&h->reply_mutex);
- mutex_unlock(&h->watch_mutex);
-
+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]);
@@ -275,6 +261,32 @@ void xs_daemon_close(struct xs_handle *h)
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)
+{
+#ifdef USE_PTHREAD
+ if (h->read_thr_exists) {
+ pthread_cancel(h->read_thr);
+ pthread_join(h->read_thr, NULL);
+ }
+#endif
+
+ mutex_lock(&h->request_mutex);
+ mutex_lock(&h->reply_mutex);
+ mutex_lock(&h->watch_mutex);
+
+ close_free_msgs(h);
+
+ mutex_unlock(&h->request_mutex);
+ mutex_unlock(&h->reply_mutex);
+ mutex_unlock(&h->watch_mutex);
+}
+
static bool read_all(int fd, void *data, unsigned int len)
{
while (len) {
diff --git a/tools/xenstore/xs.h b/tools/xenstore/xs.h
index bd36a0b350..4dae5944ae 100644
--- a/tools/xenstore/xs.h
+++ b/tools/xenstore/xs.h
@@ -48,6 +48,9 @@ struct xs_handle *xs_daemon_open_readonly(void);
/* 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.