[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-4.0-testing] libxl: Backported stuff from unstable
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1278431341 -3600 # Node ID b1321a50f62668ad8d3d9e721d38a10627e92d44 # Parent 1952867c5c92e7e4eef9ba4205995973de01aae0 libxl: Backported stuff from unstable Signed-off-by: Gianni Tedesco <gianni.tedesco@xxxxxxxxxx> --- tools/libxl/Makefile | 28 tools/libxl/bash-completion | 21 tools/libxl/libxl.c | 1038 +++++++++- tools/libxl/libxl.h | 193 + tools/libxl/libxl_device.c | 78 tools/libxl/libxl_dom.c | 194 + tools/libxl/libxl_exec.c | 34 tools/libxl/libxl_internal.c | 13 tools/libxl/libxl_internal.h | 24 tools/libxl/libxl_paths.c | 61 tools/libxl/libxl_utils.c | 297 ++- tools/libxl/libxl_utils.h | 45 tools/libxl/libxl_xshelp.c | 6 tools/libxl/libxlu_cfg.c | 37 tools/libxl/libxlutil.h | 3 tools/libxl/xenguest.c | 18 tools/libxl/xl.c | 1749 ----------------- tools/libxl/xl.h | 81 tools/libxl/xl_cmdimpl.c | 4243 +++++++++++++++++++++++++++++++++++++++++++ tools/libxl/xl_cmdtable.c | 322 +++ tools/xenstore/xs.c | 52 tools/xenstore/xs.h | 3 22 files changed, 6561 insertions(+), 1979 deletions(-) diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/Makefile --- a/tools/libxl/Makefile Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/libxl/Makefile Tue Jul 06 16:49:01 2010 +0100 @@ -11,13 +11,13 @@ XLUMAJOR = 1.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 @@ -42,6 +42,15 @@ all: $(CLIENTS) libxenlight.so libxenlig %.c: %.l $(FLEX) --header-file=$*.h --outfile=$@ $< + +genpath-target = $(call buildmakevars2file,_libxl_paths.h) +$(eval $(genpath-target)) + +_libxl_paths.h: genpath + sed -e "s/\([^=]*\)=\(.*\)/#define \1 \2/g" $@ >_$@ + mv _$@ $@ + +libxl_paths.c: _libxl_paths.h libxenlight.so: libxenlight.so.$(MAJOR) ln -sf $< $@ @@ -70,11 +79,21 @@ xl.o: xl.c 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 -r 1952867c5c92 -r b1321a50f626 tools/libxl/bash-completion --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/libxl/bash-completion Tue Jul 06 16:49:01 2010 +0100 @@ -0,0 +1,21 @@ +#!/bin/bash +# Copy this file to /etc/bash_completion.d/xl.sh + +_xl() +{ + local IFS=$'\n,' + + local cur opts xl + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + xl=xl + + if [[ $COMP_CWORD == 1 ]] ; then + opts=`${xl} help 2>/dev/null | sed '1,4d' | awk '{print $1}' | sed 's/$/ ,/g'` && COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + fi + + return 0 +} + +complete -F _xl -o nospace -o default xl diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/libxl.c --- a/tools/libxl/libxl.c Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/libxl/libxl.c Tue Jul 06 16:49:01 2010 +0100 @@ -45,6 +45,7 @@ int libxl_ctx_init(struct libxl_ctx *ctx 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_domain_make(struct libxl_ctx * 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 * 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_ct 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_ct 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_ct 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 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,27 +418,29 @@ struct libxl_dominfo * libxl_list_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. */ @@ -345,11 +473,11 @@ int libxl_domain_suspend(struct libxl_ct { 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_c shutdown_path = libxl_sprintf(ctx, "%s/control/shutdown", dom_path); xs_write(ctx->xsh, XBT_NULL, shutdown_path, req_table[req], strlen(req_table[req])); - if (/* hvm */ 0) { + if (is_hvm(ctx,domid)) { unsigned long acpi_s_state = 0; unsigned long pvdriver = 0; xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_ACPI_S_STATE, &acpi_s_state); xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_CALLBACK_IRQ, &pvdriver); - if (!pvdriver && acpi_s_state != 0) + if (!pvdriver || acpi_s_state != 0) xc_domain_shutdown(ctx->xch, domid, req); } return 0; @@ -420,7 +548,8 @@ int libxl_wait_for_domain_death(struct l 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 li 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_ct 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_ct 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_ 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_ 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_ 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)); @@ -719,6 +854,14 @@ static char ** libxl_build_device_model_ } 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) { @@ -733,7 +876,13 @@ static char ** libxl_build_device_model_ 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) { @@ -763,7 +912,8 @@ void dm_xenstore_record_pid(void *for_sp /* 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 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 l 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 lib 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 lib 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 lib 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 l 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_c 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_c 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_ct unsigned int boffset = 0; unsigned int foffset = 0; libxl_device device; + char *dompath, **l; + unsigned int nb; front = flexarray_make(16, 1); if (!front) @@ -1269,6 +1442,19 @@ int libxl_device_nic_add(struct libxl_ct back = flexarray_make(16, 1); 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; @@ -1289,6 +1475,8 @@ int libxl_device_nic_add(struct libxl_ct 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)); @@ -1331,6 +1519,66 @@ int libxl_device_nic_del(struct libxl_ct return libxl_device_del(ctx, &device, wait); } + +libxl_nicinfo *libxl_list_nics(struct libxl_ctx *ctx, uint32_t domid, unsigned int *nb) +{ + char *dompath, *nic_path_fe; + char **l; + char *val, *tok; + unsigned int nb_nics, i; + libxl_nicinfo *res, *nics; + + dompath = libxl_xs_get_dompath(ctx, domid); + if (!dompath) { + return NULL; + } + l = libxl_xs_directory(ctx, XBT_NULL, + libxl_sprintf(ctx, "%s/device/vif", dompath), &nb_nics); + if (!l) { + return NULL; + } + res = libxl_calloc(ctx, nb_nics, sizeof (libxl_device_nic)); + if (!res) { + libxl_free(ctx, l); + return NULL; + } + nics = res; + for (*nb = nb_nics; nb_nics > 0; --nb_nics, ++l, ++nics) { + nic_path_fe = libxl_sprintf(ctx, "%s/device/vif/%s", dompath, *l); + + nics->backend = libxl_xs_read(ctx, XBT_NULL, + libxl_sprintf(ctx, "%s/backend", nic_path_fe)); + val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend-id", nic_path_fe)); + nics->backend_id = val ? strtoul(val, NULL, 10) : -1; + + nics->devid = strtoul(*l, NULL, 10); + val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/state", nic_path_fe)); + nics->state = val ? strtoul(val, NULL, 10) : -1; + val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/mac", nic_path_fe)); + for (i = 0, tok = strtok(val, ":"); tok && (i < 6); + ++i, tok = strtok(NULL, ":")) { + nics->mac[i] = strtoul(tok, NULL, 16); + } + val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/event-channel", nic_path_fe)); + nics->evtch = val ? strtol(val, NULL, 10) : -1; + val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/tx-ring-ref", nic_path_fe)); + nics->rref_tx = val ? strtol(val, NULL, 10) : -1; + val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/rx-ring-ref", nic_path_fe)); + nics->rref_rx = val ? strtol(val, NULL, 10) : -1; + nics->frontend = libxl_xs_read(ctx, XBT_NULL, + libxl_sprintf(ctx, "%s/frontend", nics->backend)); + val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/frontend-id", nics->backend)); + nics->frontend_id = val ? strtoul(val, NULL, 10) : -1; + nics->script = libxl_xs_read(ctx, XBT_NULL, + libxl_sprintf(ctx, "%s/script", nics->backend)); + + libxl_free(ctx, nic_path_fe); + } + + libxl_free(ctx, l); + return res; +} + /******************************************************************************/ int libxl_device_console_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_console *console) @@ -1470,57 +1718,90 @@ libxl_device_disk *libxl_device_disk_lis 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"); - } - free(l); - } - l = libxl_xs_directory(ctx, XBT_NULL, be_path_tap, &numl); + 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"); + } + libxl_free(ctx, b); + } + 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"); - } - free(l); - } - *num = num_disks; - return disks; + 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"); + } + 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; + } + 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(s 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(s } 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_ct 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_ct /* 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_ct 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_ct 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_ct 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 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 lib 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 return rc; } + +int libxl_get_physinfo(struct libxl_ctx *ctx, struct libxl_physinfo *physinfo) +{ + xc_physinfo_t xcphysinfo = { 0 }; + int rc; + + rc = xc_physinfo(ctx->xch, &xcphysinfo); + if (rc != 0) { + return rc; + } + physinfo->threads_per_core = xcphysinfo.threads_per_core; + physinfo->cores_per_socket = xcphysinfo.cores_per_socket; + physinfo->max_cpu_id = xcphysinfo.max_cpu_id; + physinfo->nr_cpus = xcphysinfo.nr_cpus; + physinfo->cpu_khz = xcphysinfo.cpu_khz; + physinfo->total_pages = xcphysinfo.total_pages; + physinfo->free_pages = xcphysinfo.free_pages; + physinfo->scrub_pages = xcphysinfo.scrub_pages; + memcpy(physinfo->hw_cap,xcphysinfo.hw_cap, sizeof(physinfo->hw_cap)); + physinfo->phys_cap = xcphysinfo.capabilities; + + return 0; +} + +const libxl_version_info* libxl_get_version_info(struct libxl_ctx *ctx) +{ + union { + xen_extraversion_t xen_extra; + xen_compile_info_t xen_cc; + xen_changeset_info_t xen_chgset; + xen_capabilities_info_t xen_caps; + xen_platform_parameters_t p_parms; + xen_commandline_t xen_commandline; + } u; + long xen_version; + libxl_version_info *info = &ctx->version_info; + + if (info->xen_version_extra != NULL) + return info; + + xen_version = xc_version(ctx->xch, XENVER_version, NULL); + info->xen_version_major = xen_version >> 16; + info->xen_version_minor = xen_version & 0xFF; + xc_version(ctx->xch, XENVER_extraversion, &u.xen_extra); + info->xen_version_extra = libxl_sprintf(ctx, "%s", u.xen_extra); + + xc_version(ctx->xch, XENVER_compile_info, &u.xen_cc); + info->compiler = libxl_sprintf(ctx, "%s", u.xen_cc.compiler); + info->compile_by = libxl_sprintf(ctx, "%s", u.xen_cc.compile_by); + info->compile_domain = libxl_sprintf(ctx, "%s", u.xen_cc.compile_domain); + info->compile_date = libxl_sprintf(ctx, "%s", u.xen_cc.compile_date); + + xc_version(ctx->xch, XENVER_capabilities, &u.xen_caps); + info->capabilities = libxl_sprintf(ctx, "%s", u.xen_caps); + + xc_version(ctx->xch, XENVER_changeset, &u.xen_chgset); + info->changeset = libxl_sprintf(ctx, "%s", u.xen_chgset); + + xc_version(ctx->xch, XENVER_platform_parameters, &u.p_parms); + info->virt_start = u.p_parms.virt_start; + + info->pagesize = xc_version(ctx->xch, XENVER_pagesize, NULL); + + xc_version(ctx->xch, XENVER_commandline, &u.xen_commandline); + info->commandline = libxl_sprintf(ctx, "%s", u.xen_commandline); + + return info; +} + +struct libxl_vcpuinfo *libxl_list_vcpu(struct libxl_ctx *ctx, uint32_t domid, + int *nb_vcpu, int *cpusize) +{ + struct libxl_vcpuinfo *ptr, *ret; + xc_domaininfo_t domaininfo; + xc_vcpuinfo_t vcpuinfo; + xc_physinfo_t physinfo = { 0 }; + + if (xc_domain_getinfolist(ctx->xch, domid, 1, &domaininfo) != 1) { + return NULL; + } + if (xc_physinfo(ctx->xch, &physinfo) == -1) { + return NULL; + } + *cpusize = physinfo.max_cpu_id + 1; + ptr = libxl_calloc(ctx, domaininfo.max_vcpu_id + 1, sizeof (struct libxl_vcpuinfo)); + if (!ptr) { + return NULL; + } + + ret = ptr; + for (*nb_vcpu = 0; *nb_vcpu <= domaininfo.max_vcpu_id; ++*nb_vcpu, ++ptr) { + ptr->cpumap = libxl_calloc(ctx, (*cpusize + 63) / 64, sizeof (uint64_t)); + if (!ptr->cpumap) { + return NULL; + } + if (xc_vcpu_getinfo(ctx->xch, domid, *nb_vcpu, &vcpuinfo) == -1) { + return NULL; + } + if (xc_vcpu_getaffinity(ctx->xch, domid, *nb_vcpu, ptr->cpumap, *cpusize) == -1) { + return NULL; + } + ptr->vcpuid = *nb_vcpu; + ptr->cpu = vcpuinfo.cpu; + ptr->online = !!vcpuinfo.online; + ptr->blocked = !!vcpuinfo.blocked; + ptr->running = !!vcpuinfo.running; + ptr->vcpu_time = vcpuinfo.cpu_time; + } + return ret; +} + +int libxl_set_vcpuaffinity(struct libxl_ctx *ctx, uint32_t domid, uint32_t vcpuid, + uint64_t *cpumap, int cpusize) +{ + return (xc_vcpu_setaffinity(ctx->xch, domid, vcpuid, cpumap, cpusize)); +} + +int libxl_set_vcpucount(struct libxl_ctx *ctx, uint32_t domid, uint32_t count) +{ + xc_domaininfo_t domaininfo; + char *dompath; + int i; + + if (xc_domain_getinfolist(ctx->xch, domid, 1, &domaininfo) != 1) { + return ERROR_FAIL; + } + if (!count || ((domaininfo.max_vcpu_id + 1) < count)) { + return ERROR_INVAL; + } + if (!(dompath = libxl_xs_get_dompath(ctx, domid))) + return ERROR_FAIL; + + for (i = 0; i <= domaininfo.max_vcpu_id; ++i) { + libxl_xs_write(ctx, XBT_NULL, + libxl_sprintf(ctx, "%s/cpu/%u/availability", dompath, i), + "%s", ((1 << i) & ((1 << count) - 1)) ? "online" : "offline"); + } + return 0; +} + +/* + * returns one of the XEN_SCHEDULER_* constants from public/domctl.h + * or -1 if an error occured. + */ +int libxl_get_sched_id(struct libxl_ctx *ctx) +{ + int sched, ret; + + if ((ret = xc_sched_id(ctx->xch, &sched)) != 0) + return ret; + return sched; +} + +int libxl_sched_credit_domain_get(struct libxl_ctx *ctx, uint32_t domid, struct libxl_sched_credit *scinfo) +{ + struct xen_domctl_sched_credit sdom; + int rc; + + rc = xc_sched_credit_domain_get(ctx->xch, domid, &sdom); + if (rc != 0) + return rc; + + scinfo->weight = sdom.weight; + scinfo->cap = sdom.cap; + + return 0; +} + +int libxl_sched_credit_domain_set(struct libxl_ctx *ctx, uint32_t domid, struct libxl_sched_credit *scinfo) +{ + struct xen_domctl_sched_credit sdom; + xc_domaininfo_t domaininfo; + int rc; + + rc = xc_domain_getinfolist(ctx->xch, domid, 1, &domaininfo); + if (rc != 1 || domaininfo.domain != domid) + return rc; + + + if (scinfo->weight < 1 || scinfo->weight > 65535) { + XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, + "Cpu weight out of range, valid values are within range from 1 to 65535"); + return -1; + } + + if (scinfo->cap < 0 || scinfo->cap > (domaininfo.max_vcpu_id + 1) * 100) { + XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, + "Cpu cap out of range, valid range is from 0 to %d for specified number of vcpus", + ((domaininfo.max_vcpu_id + 1) * 100)); + return -1; + } + + sdom.weight = scinfo->weight; + sdom.cap = scinfo->cap; + + rc = xc_sched_credit_domain_set(ctx->xch, domid, &sdom); + if (rc != 0) + return rc; + + return 0; +} + +static int trigger_type_from_string(char *trigger_name) +{ + if (!strcmp(trigger_name, "nmi")) + return XEN_DOMCTL_SENDTRIGGER_NMI; + else if (!strcmp(trigger_name, "reset")) + return XEN_DOMCTL_SENDTRIGGER_RESET; + else if (!strcmp(trigger_name, "init")) + return XEN_DOMCTL_SENDTRIGGER_INIT; + else if (!strcmp(trigger_name, "power")) + return XEN_DOMCTL_SENDTRIGGER_POWER; + else if (!strcmp(trigger_name, "sleep")) + return XEN_DOMCTL_SENDTRIGGER_SLEEP; + else + return -1; +} + +int libxl_send_trigger(struct libxl_ctx *ctx, uint32_t domid, char *trigger_name, uint32_t vcpuid) +{ + int rc = -1; + int trigger_type = trigger_type_from_string(trigger_name); + + if (trigger_type == -1) { + XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, -1, + "Invalid trigger, valid triggers are <nmi|reset|init|power|sleep>"); + return -1; + } + + rc = xc_domain_send_trigger(ctx->xch, domid, trigger_type, vcpuid); + if (rc != 0) + XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, + "Send trigger '%s' failed", trigger_name); + + return rc; +} + +int libxl_send_sysrq(struct libxl_ctx *ctx, uint32_t domid, char sysrq) +{ + char *dompath = libxl_xs_get_dompath(ctx, domid); + + libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/control/sysrq", dompath), "%c", sysrq); + + return 0; +} + +int libxl_send_debug_keys(struct libxl_ctx *ctx, char *keys) +{ + return xc_send_debug_keys(ctx->xch, keys); +} + +struct libxl_xen_console_reader * + libxl_xen_console_read_start(struct libxl_ctx *ctx, int clear) +{ + struct libxl_xen_console_reader *cr; + unsigned int size = 16384; + char *buf = malloc(size); + + if (!buf) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "cannot malloc buffer for libxl_xen_console_reader," + " size is %u", size); + return NULL; + } + + cr = malloc(sizeof(struct libxl_xen_console_reader)); + if (!cr) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "cannot malloc libxl_xen_console_reader"); + return NULL; + } + + memset(cr, 0, sizeof(struct libxl_xen_console_reader)); + cr->buffer = buf; + cr->size = size; + cr->count = size; + cr->clear = clear; + cr->incremental = 1; + + return cr; +} + +/* return values: *line_r + * 1 success, whole line obtained from buffer non-0 + * 0 no more lines available right now 0 + * negative error code ERROR_* 0 + * On success *line_r is updated to point to a nul-terminated + * string which is valid until the next call on the same console + * reader. The libxl caller may overwrite parts of the string + * if it wishes. */ +int libxl_xen_console_read_line(struct libxl_ctx *ctx, + struct libxl_xen_console_reader *cr, + char **line_r) +{ + int ret; + + memset(cr->buffer, 0, cr->size); + ret = xc_readconsolering(ctx->xch, &cr->buffer, &cr->count, + cr->clear, cr->incremental, &cr->index); + if (!ret) { + if (cr->count) { + *line_r = cr->buffer; + ret = 1; + } else { + *line_r = NULL; + ret = 0; + } + } + + return ret; +} + +void libxl_xen_console_read_finish(struct libxl_ctx *ctx, + struct libxl_xen_console_reader *cr) +{ + free(cr->buffer); + free(cr); +} + +uint32_t libxl_vm_get_start_time(struct libxl_ctx *ctx, uint32_t domid) +{ + char *dompath = libxl_xs_get_dompath(ctx, domid); + char *vm_path, *start_time; + + vm_path = libxl_xs_read( + ctx, XBT_NULL, libxl_sprintf(ctx, "%s/vm", dompath)); + start_time = libxl_xs_read( + ctx, XBT_NULL, libxl_sprintf(ctx, "%s/start_time", vm_path)); + if (start_time == NULL) { + XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, -1, + "Can't get start time of domain '%d'", domid); + return -1; + } + + return strtoul(start_time, NULL, 10); +} + +char *libxl_tmem_list(struct libxl_ctx *ctx, uint32_t domid, int use_long) +{ + int rc; + char _buf[32768]; + + rc = xc_tmem_control(ctx->xch, -1, TMEMC_LIST, domid, 32768, use_long, + 0, _buf); + if (rc < 0) { + XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, + "Can not get tmem list"); + return NULL; + } + + return strdup(_buf); +} + +int libxl_tmem_freeze(struct libxl_ctx *ctx, uint32_t domid) +{ + int rc; + + rc = xc_tmem_control(ctx->xch, -1, TMEMC_FREEZE, domid, 0, 0, + 0, NULL); + if (rc < 0) { + XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, + "Can not freeze tmem pools"); + return -1; + } + + return rc; +} + +int libxl_tmem_destroy(struct libxl_ctx *ctx, uint32_t domid) +{ + int rc; + + rc = xc_tmem_control(ctx->xch, -1, TMEMC_DESTROY, domid, 0, 0, + 0, NULL); + if (rc < 0) { + XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, + "Can not destroy tmem pools"); + return -1; + } + + return rc; +} + +int libxl_tmem_thaw(struct libxl_ctx *ctx, uint32_t domid) +{ + int rc; + + rc = xc_tmem_control(ctx->xch, -1, TMEMC_THAW, domid, 0, 0, + 0, NULL); + if (rc < 0) { + XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, + "Can not thaw tmem pools"); + return -1; + } + + return rc; +} + +static int32_t tmem_setop_from_string(char *set_name) +{ + if (!strcmp(set_name, "weight")) + return TMEMC_SET_WEIGHT; + else if (!strcmp(set_name, "cap")) + return TMEMC_SET_CAP; + else if (!strcmp(set_name, "compress")) + return TMEMC_SET_COMPRESS; + else + return -1; +} + +int libxl_tmem_set(struct libxl_ctx *ctx, uint32_t domid, char* name, uint32_t set) +{ + int rc; + int32_t subop = tmem_setop_from_string(name); + + if (subop == -1) { + XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, -1, + "Invalid set, valid sets are <weight|cap|compress>"); + return -1; + } + rc = xc_tmem_control(ctx->xch, -1, subop, domid, set, 0, 0, NULL); + if (rc < 0) { + XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, + "Can not set tmem %s", name); + return -1; + } + + return rc; +} + +int libxl_tmem_shared_auth(struct libxl_ctx *ctx, uint32_t domid, + char* uuid, int auth) +{ + int rc; + + rc = xc_tmem_auth(ctx->xch, domid, uuid, auth); + if (rc < 0) { + XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, + "Can not set tmem shared auth"); + return -1; + } + + return rc; +} + diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/libxl.h --- a/tools/libxl/libxl.h Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/libxl/libxl.h Tue Jul 06 16:49:01 2010 +0100 @@ -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 @@ int libxl_ctx_init(struct libxl_ctx *ctx int libxl_ctx_init(struct libxl_ctx *ctx, int version); int libxl_ctx_free(struct libxl_ctx *ctx); int libxl_ctx_set_log(struct libxl_ctx *ctx, libxl_log_callback log_callback, void *log_data); +int libxl_ctx_postfork(struct libxl_ctx *ctx); /* domain related functions */ int libxl_domain_make(struct libxl_ctx *ctx, libxl_domain_create_info *info, uint32_t *domid); @@ -262,6 +289,9 @@ int libxl_domain_shutdown(struct libxl_c int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req); int libxl_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force); +char *libxl_uuid2string(struct libxl_ctx *ctx, uint8_t uuid[16]); + /* 0 means ERROR_ENOMEM, which we have logged */ + /* events handling */ typedef enum { @@ -296,15 +326,24 @@ int libxl_event_get_domain_death_info(st 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 lib 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_p 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 -r 1952867c5c92 -r b1321a50f626 tools/libxl/libxl_device.c --- a/tools/libxl/libxl_device.c Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/libxl/libxl_device.c Tue Jul 06 16:49:01 2010 +0100 @@ -22,6 +22,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> +#include <fcntl.h> #include "libxl.h" #include "libxl_internal.h" @@ -301,7 +302,7 @@ int libxl_devices_destroy(struct libxl_c 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 *c 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 l 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 l tv.tv_sec = LIBXL_DEVICE_MODEL_START_TIMEOUT; tv.tv_usec = 0; nfds = xs_fileno(xsh) + 1; - while (tv.tv_sec > 0) { + while (rc > 0 || (!rc && tv.tv_sec > 0)) { + p = xs_read(xsh, XBT_NULL, path, &len); + if (p && (!state || !strcmp(state, p))) { + free(p); + xs_unwatch(xsh, path, path); + xs_daemon_close(xsh); + if (check_callback) { + rc = check_callback(ctx, check_callback_userdata); + if (rc) return rc; + } + return 0; + } + free(p); +again: FD_ZERO(&rfds); FD_SET(xs_fileno(xsh), &rfds); - if (select(nfds, &rfds, NULL, NULL, &tv) > 0) { + rc = select(nfds, &rfds, NULL, NULL, &tv); + if (rc > 0) { l = xs_read_watch(xsh, &num); - if (l != NULL) { + if (l != NULL) free(l); - p = xs_read(xsh, XBT_NULL, path, &len); - if (!p) - continue; - if (!state || !strcmp(state, p)) { - free(p); - xs_unwatch(xsh, path, path); - xs_daemon_close(xsh); - if (check_callback) { - rc = check_callback(ctx, check_callback_userdata); - if (rc) return rc; - } - return 0; - } - free(p); - } + else + goto again; } } xs_unwatch(xsh, path, path); diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/libxl_dom.c --- a/tools/libxl/libxl_dom.c Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/libxl/libxl_dom.c Tue Jul 06 16:49:01 2010 +0100 @@ -16,6 +16,8 @@ #include "libxl_osdeps.h" #include <stdio.h> +#include <assert.h> +#include <glob.h> #include <inttypes.h> #include <string.h> #include <sys/time.h> /* for struct timeval */ @@ -72,6 +74,7 @@ int build_pre(struct libxl_ctx *ctx, uin 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, ui 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, uin { 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 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 * libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid), "save", strlen("save")); libxl_wait_for_device_model(ctx, domid, "paused", NULL, NULL); - write(fd, QEMU_SIGNATURE, strlen(QEMU_SIGNATURE)); + c = libxl_write_exactly(ctx, fd, QEMU_SIGNATURE, strlen(QEMU_SIGNATURE), + "saved-state file", "qemu signature"); + if (c) + return c; fd2 = open(filename, O_RDONLY); while ((c = read(fd2, buf, sizeof(buf))) != 0) { - write(fd, buf, c); + if (c < 0) { + if (errno == EINTR) + continue; + return errno; + } + c = libxl_write_exactly( + ctx, fd, buf, c, "saved-state file", "qemu state"); + if (c) + return c; } close(fd2); unlink(filename); return 0; } + +char *libxl_uuid2string(struct libxl_ctx *ctx, uint8_t uuid[16]) { + char *s = string_of_uuid(ctx, uuid); + if (!s) XL_LOG(ctx, XL_LOG_ERROR, "cannot allocate for uuid"); + return s; +} + +static const char *userdata_path(struct libxl_ctx *ctx, uint32_t domid, + const char *userdata_userid, + const char *wh) { + char *path, *uuid_string; + struct libxl_dominfo info; + int rc; + + rc = libxl_domain_info(ctx, &info, domid); + if (rc) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "unable to find domain info" + " for domain %"PRIu32, domid); + return 0; + } + uuid_string = string_of_uuid(ctx, info.uuid); + + path = libxl_sprintf(ctx, "/var/lib/xen/" + "userdata-%s.%s.%s", + wh, uuid_string, userdata_userid); + if (!path) + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "unable to allocate for" + " userdata path"); + return path; +} + +static int userdata_delete(struct libxl_ctx *ctx, const char *path) { + int r; + r = unlink(path); + if (r) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "remove failed for %s", path); + return errno; + } + return 0; +} + +void libxl__userdata_destroyall(struct libxl_ctx *ctx, uint32_t domid) { + const char *pattern; + glob_t gl; + int r, i; + + pattern = userdata_path(ctx, domid, "*", "?"); + if (!pattern) return; + + gl.gl_pathc = 0; + gl.gl_pathv = 0; + gl.gl_offs = 0; + r = glob(pattern, GLOB_ERR|GLOB_NOSORT|GLOB_MARK, 0, &gl); + if (r == GLOB_NOMATCH) return; + if (r) XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "glob failed for %s", pattern); + + for (i=0; i<gl.gl_pathc; i++) { + userdata_delete(ctx, gl.gl_pathv[i]); + } + globfree(&gl); +} + +int libxl_userdata_store(struct libxl_ctx *ctx, uint32_t domid, + const char *userdata_userid, + const uint8_t *data, int datalen) { + const char *filename; + const char *newfilename; + int e; + int fd = -1; + FILE *f = 0; + size_t rs; + + filename = userdata_path(ctx, domid, userdata_userid, "d"); + if (!filename) return ENOMEM; + + if (!datalen) + return userdata_delete(ctx, filename); + + newfilename = userdata_path(ctx, domid, userdata_userid, "n"); + if (!newfilename) return ENOMEM; + + fd= open(newfilename, O_RDWR|O_CREAT|O_TRUNC, 0600); + if (fd<0) goto xe; + + f= fdopen(fd, "wb"); + if (!f) goto xe; + fd = -1; + + rs = fwrite(data, 1, datalen, f); + if (rs != datalen) { assert(ferror(f)); goto xe; } + + if (fclose(f)) goto xe; + f = 0; + + if (rename(newfilename,filename)) goto xe; + + return 0; + + xe: + e = errno; + if (f) fclose(f); + if (fd>=0) close(fd); + + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "cannot write %s for %s", + newfilename, filename); + return e; +} + +int libxl_userdata_retrieve(struct libxl_ctx *ctx, uint32_t domid, + const char *userdata_userid, + uint8_t **data_r, int *datalen_r) { + const char *filename; + int e; + int datalen = 0; + void *data = 0; + + filename = userdata_path(ctx, domid, userdata_userid, "d"); + if (!filename) return ENOMEM; + + e = libxl_read_file_contents(ctx, filename, data_r ? &data : 0, &datalen); + + if (!e && !datalen) { + XL_LOG(ctx, XL_LOG_ERROR, "userdata file %s is empty", filename); + if (data_r) assert(!*data_r); + return EPROTO; + } + + if (data_r) *data_r = data; + if (datalen_r) *datalen_r = datalen; + return 0; +} diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/libxl_exec.c --- a/tools/libxl/libxl_exec.c Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/libxl/libxl_exec.c Tue Jul 06 16:49:01 2010 +0100 @@ -30,19 +30,6 @@ #include "libxl.h" #include "libxl_internal.h" -static pid_t libxl_fork(struct libxl_ctx *ctx) -{ - pid_t pid; - - pid = fork(); - if (pid == -1) { - XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "fork failed"); - return -1; - } - - return pid; -} - static int call_waitpid(pid_t (*waitpid_cb)(pid_t, int *, int), pid_t pid, int *status, int options) { return (waitpid_cb) ? waitpid_cb(pid, status, options) : waitpid(pid, status, options); @@ -61,38 +48,41 @@ void libxl_exec(int stdinfd, int stdoutf 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_st char *intermediate_what = libxl_sprintf(ctx, "%s intermediate process (startup monitor)", for_spawn->what); - libxl_report_child_exitstatus(ctx, intermediate_what, + libxl_report_child_exitstatus(ctx, XL_LOG_ERROR, intermediate_what, for_spawn->intermediate, status); } } diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/libxl_internal.c --- a/tools/libxl/libxl_internal.c Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/libxl/libxl_internal.c Tue Jul 06 16:49:01 2010 +0100 @@ -156,10 +156,12 @@ void xl_logv(struct libxl_ctx *ctx, int { 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 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 l xl_logv(ctx, loglevel, errnoval, file, line, func, fmt, ap); va_end(ap); } + +char *libxl_abs_path(struct libxl_ctx *ctx, char *s, const char *path) +{ + if (!s || s[0] == '/') + return s; + return libxl_sprintf(ctx, "%s/%s", path, s); +} + diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/libxl_internal.h --- a/tools/libxl/libxl_internal.h Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/libxl/libxl_internal.h Tue Jul 06 16:49:01 2010 +0100 @@ -41,21 +41,18 @@ #ifdef XL_LOGGING_ENABLED #define XL_LOG(ctx, loglevel, _f, _a...) xl_log(ctx, loglevel, -1, __FILE__, __LINE__, __func__, _f, ##_a) #define XL_LOG_ERRNO(ctx, loglevel, _f, _a...) xl_log(ctx, loglevel, errno, __FILE__, __LINE__, __func__, _f, ##_a) -#define XL_LOG_ERRNOVAL(ctx, errnoval, loglevel, _f, _a...) xl_log(ctx, loglevel, errnoval, __FILE__, __LINE__, __func__, _f, ##_a) +#define XL_LOG_ERRNOVAL(ctx, loglevel, errnoval, _f, _a...) xl_log(ctx, loglevel, errnoval, __FILE__, __LINE__, __func__, _f, ##_a) #else #define XL_LOG(ctx, loglevel, _f, _a...) #define XL_LOG_ERRNO(ctx, loglevel, _f, _a...) #define XL_LOG_ERRNOVAL(ctx, loglevel, errnoval, _f, _a...) #endif - -#define XL_LOG_DEBUG 3 -#define XL_LOG_INFO 2 -#define XL_LOG_WARNING 1 -#define XL_LOG_ERROR 0 + /* all of these macros preserve errno (saving and restoring) */ /* logging */ void xl_logv(struct libxl_ctx *ctx, int errnoval, int loglevel, const char *file, int line, const char *func, char *fmt, va_list al); void xl_log(struct libxl_ctx *ctx, int errnoval, int loglevel, const char *file, int line, const char *func, char *fmt, ...); + /* these functions preserve errno (saving and restoring) */ typedef enum { @@ -133,6 +130,7 @@ int restore_common(struct libxl_ctx *ctx 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 l 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 * void (*intermediate_hook)(void *for_spawn, pid_t innerchild)); /* Logs errors. A copy of "what" is taken. Return values: * < 0 error, for_spawn need not be detached - * +1 caller is now the inner child, should probably call libxl_exec - * 0 caller is the parent, must call detach on *for_spawn eventually + * +1 caller is the parent, must call detach on *for_spawn eventually + * 0 caller is now the inner child, should probably call libxl_exec * Caller, may pass 0 for for_spawn, in which case no need to detach. */ int libxl_spawn_detach(struct libxl_ctx *ctx, @@ -204,5 +202,7 @@ void libxl_log_child_exitstatus(struct l void libxl_log_child_exitstatus(struct libxl_ctx *ctx, const char *what, pid_t pid, int status); +char *libxl_abs_path(struct libxl_ctx *ctx, char *s, const char *path); + #endif diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/libxl_paths.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/libxl/libxl_paths.c Tue Jul 06 16:49:01 2010 +0100 @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010 Citrix Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; version 2.1 only. with the special + * exception on linking described in file LICENSE. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +#include "_libxl_paths.h" + +const char *libxl_sbindir_path(void) +{ + return SBINDIR; +} + +const char *libxl_bindir_path(void) +{ + return BINDIR; +} + +const char *libxl_libexec_path(void) +{ + return LIBEXEC; +} + +const char *libxl_libdir_path(void) +{ + return LIBDIR; +} + +const char *libxl_sharedir_path(void) +{ + return SHAREDIR; +} + +const char *libxl_private_bindir_path(void) +{ + return PRIVATE_BINDIR; +} + +const char *libxl_xenfirmwaredir_path(void) +{ + return XENFIRMWAREDIR; +} + +const char *libxl_xen_config_dir_path(void) +{ + return XEN_CONFIG_DIR; +} + +const char *libxl_xen_script_dir_path(void) +{ + return XEN_SCRIPT_DIR; +} + diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/libxl_utils.c --- a/tools/libxl/libxl_utils.c Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/libxl/libxl_utils.c Tue Jul 06 16:49:01 2010 +0100 @@ -26,6 +26,7 @@ #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> +#include <assert.h> #include "libxl_utils.h" #include "libxl_internal.h" @@ -54,7 +55,8 @@ char *libxl_domid_to_name(struct libxl_c 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; @@ -74,6 +76,20 @@ int libxl_name_to_domid(struct libxl_ctx } } 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) @@ -101,11 +117,25 @@ int libxl_is_stubdom(struct libxl_ctx *c 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_ct 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 -r 1952867c5c92 -r b1321a50f626 tools/libxl/libxl_utils.h --- a/tools/libxl/libxl_utils.h Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/libxl/libxl_utils.h Tue Jul 06 16:49:01 2010 +0100 @@ -19,12 +19,55 @@ #include "libxl.h" unsigned long libxl_get_required_shadow_memory(unsigned long maxmem_kb, unsigned int smp_cpus); -int libxl_name_to_domid(struct libxl_ctx *ctx, char *name, uint32_t *domid); +int libxl_name_to_domid(struct libxl_ctx *ctx, const char *name, uint32_t *domid); char *libxl_domid_to_name(struct libxl_ctx *ctx, uint32_t domid); +int libxl_name_to_poolid(struct libxl_ctx *ctx, const char *name, uint32_t *poolid); +char *libxl_poolid_to_name(struct libxl_ctx *ctx, uint32_t poolid); int libxl_get_stubdom_id(struct libxl_ctx *ctx, int guest_domid); int libxl_is_stubdom(struct libxl_ctx *ctx, uint32_t domid, uint32_t *target_domid); int libxl_create_logfile(struct libxl_ctx *ctx, char *name, char **full_name); int libxl_string_to_phystype(struct libxl_ctx *ctx, char *s, libxl_disk_phystype *phystype); +int libxl_read_file_contents(struct libxl_ctx *ctx, const char *filename, + void **data_r, int *datalen_r); + /* Reads the contents of the plain file filename into a mallocd + * buffer. Returns 0 or errno. Any errors other than ENOENT are logged. + * If the file is empty, *data_r and *datalen_r are set to 0. + * On error, *data_r and *datalen_r are undefined. + * data_r and/or datalen_r may be 0. + */ + +int libxl_read_exactly(struct libxl_ctx *ctx, int fd, void *data, ssize_t sz, + const char *filename, const char *what); +int libxl_write_exactly(struct libxl_ctx *ctx, int fd, const void *data, + ssize_t sz, const char *filename, const char *what); + /* Returns 0 or errno. If file is truncated on reading, returns + * EPROTO and you have no way to tell how much was read. Errors are + * logged using filename (which is only used for logging) and what + * (which may be 0). */ + +pid_t libxl_fork(struct libxl_ctx *ctx); +int libxl_pipe(struct libxl_ctx *ctx, int pipes[2]); + /* Just like fork(2), pipe(2), but log errors. */ + +void libxl_report_child_exitstatus(struct libxl_ctx *ctx, int level, + const char *what, pid_t pid, int status); + /* treats all exit statuses as errors; if that's not what you want, + * check status yourself first */ + +int libxl_mac_to_device_nic(struct libxl_ctx *ctx, uint32_t domid, + const char *mac, libxl_device_nic *nic); +int libxl_devid_to_device_nic(struct libxl_ctx *ctx, uint32_t domid, + const char *devid, libxl_device_nic *nic); + +int libxl_devid_to_device_disk(struct libxl_ctx *ctx, uint32_t domid, + const char *devid, libxl_device_disk *disk); + +/* log levels: */ +#define XL_LOG_DEBUG 3 +#define XL_LOG_INFO 2 +#define XL_LOG_WARNING 1 +#define XL_LOG_ERROR 0 + #endif diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/libxl_xshelp.c --- a/tools/libxl/libxl_xshelp.c Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/libxl/libxl_xshelp.c Tue Jul 06 16:49:01 2010 +0100 @@ -19,6 +19,7 @@ #include <stddef.h> #include <stdio.h> #include <stdarg.h> +#include <inttypes.h> #include "libxl.h" #include "libxl_internal.h" @@ -32,7 +33,8 @@ int xs_writev(struct xs_handle *xsh, xs_ 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_ { char *s = xs_get_domain_path(ctx->xsh, domid); if (!s) { - XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to get dompath for %lu", + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to get dompath for %" PRIu32, domid); return NULL; } diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/libxlu_cfg.c --- a/tools/libxl/libxlu_cfg.c Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/libxl/libxlu_cfg.c Tue Jul 06 16:49:01 2010 +0100 @@ -49,6 +49,43 @@ int xlu_cfg_readfile(XLU_Config *cfg, co xlu__cfg_yylex_destroy(ctx.scanner); fclose(f); + + 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; } diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/libxlutil.h --- a/tools/libxl/libxlutil.h Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/libxl/libxlutil.h Tue Jul 06 16:49:01 2010 +0100 @@ -30,7 +30,8 @@ XLU_Config *xlu_cfg_init(FILE *report, c * until the Config is destroyed. */ int xlu_cfg_readfile(XLU_Config*, const char *real_filename); - /* If this fails, then it is undefined behaviour to call xlu_cfg_get_... +int xlu_cfg_readdata(XLU_Config*, const char *data, int length); + /* If these fail, then it is undefined behaviour to call xlu_cfg_get_... * functions. You have to just xlu_cfg_destroy. */ void xlu_cfg_destroy(XLU_Config*); diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/xenguest.c --- a/tools/libxl/xenguest.c Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/libxl/xenguest.c Tue Jul 06 16:49:01 2010 +0100 @@ -17,10 +17,13 @@ #include <xenguest.h> #include <sys/mman.h> #include <xen/hvm/hvm_info_table.h> +#include <string.h> + +#include "libxl.h" int hvm_build_set_params(int handle, uint32_t domid, - int apic, int acpi, int pae, int nx, int viridian, - int vcpus, int store_evtchn, unsigned long *store_mfn) + libxl_domain_build_info *info, + int store_evtchn, unsigned long *store_mfn) { struct hvm_info_table *va_hvm; uint8_t *va_map, sum; @@ -33,18 +36,19 @@ int hvm_build_set_params(int handle, uin return -1; va_hvm = (struct hvm_info_table *)(va_map + HVM_INFO_OFFSET); - va_hvm->acpi_enabled = acpi; - va_hvm->apic_mode = apic; - va_hvm->nr_vcpus = vcpus; + va_hvm->acpi_enabled = info->u.hvm.acpi; + va_hvm->apic_mode = info->u.hvm.apic; + va_hvm->nr_vcpus = info->max_vcpus; + memcpy(va_hvm->vcpu_online, &info->cur_vcpus, sizeof(info->cur_vcpus)); for (i = 0, sum = 0; i < va_hvm->length; i++) sum += ((uint8_t *) va_hvm)[i]; va_hvm->checksum -= sum; munmap(va_map, XC_PAGE_SIZE); xc_get_hvm_param(handle, domid, HVM_PARAM_STORE_PFN, store_mfn); - xc_set_hvm_param(handle, domid, HVM_PARAM_PAE_ENABLED, pae); + xc_set_hvm_param(handle, domid, HVM_PARAM_PAE_ENABLED, info->u.hvm.pae); #if defined(__i386__) || defined(__x86_64__) - xc_set_hvm_param(handle, domid, HVM_PARAM_VIRIDIAN, viridian); + xc_set_hvm_param(handle, domid, HVM_PARAM_VIRIDIAN, info->u.hvm.viridian); #endif xc_set_hvm_param(handle, domid, HVM_PARAM_STORE_EVTCHN, store_evtchn); return 0; diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/xl.c --- a/tools/libxl/xl.c Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/libxl/xl.c Tue Jul 06 16:49:01 2010 +0100 @@ -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); -} - -int main_pcidetach(int argc, char **argv) -{ - int opt; - char *domname = NULL, *bdf = NULL; - - while ((opt = getopt(argc, argv, "h")) != -1) { - switch (opt) { - case 'h': - help("pci-attach"); - exit(0); - default: - fprintf(stderr, "option not supported\n"); - break; - } - } - if (optind >= argc - 1) { - help("pci-detach"); - exit(2); - } - - domname = argv[optind]; - bdf = argv[optind + 1]; - - pcidetach(domname, bdf); - exit(0); -} -void pciattach(char *dom, char *bdf, char *vs) -{ - struct libxl_ctx ctx; - uint32_t domid; - libxl_device_pci pcidev; - unsigned int domain, bus, dev, func; - - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - - if (domain_qualifier_to_domid(&ctx, dom, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", dom); - exit(2); - } - memset(&pcidev, 0x00, sizeof(pcidev)); - sscanf(bdf, PCI_BDF, &domain, &bus, &dev, &func); - libxl_device_pci_init(&pcidev, domain, bus, dev, func, 0); - libxl_device_pci_add(&ctx, domid, &pcidev); -} - -int main_pciattach(int argc, char **argv) -{ - int opt; - char *domname = NULL, *bdf = NULL, *vs = NULL; - - while ((opt = getopt(argc, argv, "h")) != -1) { - switch (opt) { - case 'h': - help("pci-attach"); - exit(0); - default: - fprintf(stderr, "option not supported\n"); - break; - } - } - if (optind >= argc - 1) { - help("pci-attach"); - exit(2); - } - - domname = argv[optind]; - bdf = argv[optind + 1]; - - if (optind + 1 < argc) - vs = argv[optind + 2]; - - pciattach(domname, bdf, vs); - exit(0); -} - -void pause_domain(char *p) -{ - struct libxl_ctx ctx; - uint32_t domid; - - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - - if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", p); - exit(2); - } - libxl_domain_pause(&ctx, domid); -} - -void unpause_domain(char *p) -{ - struct libxl_ctx ctx; - uint32_t domid; - - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - - if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", p); - exit(2); - } - libxl_domain_unpause(&ctx, domid); -} - -void destroy_domain(char *p) -{ - struct libxl_ctx ctx; - uint32_t domid; - - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - - if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", p); - exit(2); - } - libxl_domain_destroy(&ctx, domid, 0); -} - -void list_domains(void) -{ - struct libxl_ctx ctx; - struct libxl_dominfo *info; - int nb_domain, i; - - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - - info = libxl_list_domain(&ctx, &nb_domain); - - if (info < 0) { - fprintf(stderr, "libxl_domain_infolist failed.\n"); - exit(1); - } - printf("Name ID Mem VCPUs\tState\tTime(s)\n"); - for (i = 0; i < nb_domain; i++) { - printf("%-40s %5d %5lu %5d %c%c%c %8.1f\n", - libxl_domid_to_name(&ctx, info[i].domid), - info[i].domid, - (unsigned long) (info[i].max_memkb / 1024), - info[i].vcpu_online, - info[i].running ? 'r' : '-', - info[i].paused ? 'p' : '-', - info[i].dying ? 'd' : '-', - ((float)info[i].cpu_time / 1e9)); - } - free(info); -} - -void list_vm(void) -{ - struct libxl_ctx ctx; - struct libxl_vminfo *info; - int nb_vm, i; - - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - return; - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - - info = libxl_list_vm(&ctx, &nb_vm); - - if (info < 0) { - fprintf(stderr, "libxl_domain_infolist failed.\n"); - exit(1); - } - printf("UUID ID name\n"); - for (i = 0; i < nb_vm; i++) { - printf(UUID_FMT " %d %-30s\n", - info[i].uuid[0], info[i].uuid[1], info[i].uuid[2], info[i].uuid[3], - info[i].uuid[4], info[i].uuid[5], info[i].uuid[6], info[i].uuid[7], - info[i].uuid[8], info[i].uuid[9], info[i].uuid[10], info[i].uuid[11], - info[i].uuid[12], info[i].uuid[13], info[i].uuid[14], info[i].uuid[15], - info[i].domid, libxl_domid_to_name(&ctx, info[i].domid)); - } - free(info); -} - -int save_domain(char *p, char *filename, int checkpoint) -{ - struct libxl_ctx ctx; - uint32_t domid; - int fd; - - if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { - fprintf(stderr, "cannot init xl context\n"); - exit(2); - } - libxl_ctx_set_log(&ctx, log_callback, NULL); - - if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", p); - exit(2); - } - fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644); - if (fd < 0) { - fprintf(stderr, "Failed to open temp file %s for writing\n", filename); - exit(2); - } - libxl_domain_suspend(&ctx, NULL, domid, fd); - close(fd); - - if (checkpoint) - libxl_domain_unpause(&ctx, domid); - else - libxl_domain_destroy(&ctx, domid, 0); - - exit(0); -} - -int main_restore(int argc, char **argv) -{ - char *checkpoint_file = NULL; - char *config_file = NULL; - int paused = 0, debug = 0, daemonize = 1; - int opt; - - while ((opt = getopt(argc, argv, "hpde")) != -1) { - switch (opt) { - case 'p': - paused = 1; - break; - case 'd': - debug = 1; - break; - case 'e': - daemonize = 0; - break; - case 'h': - help("restore"); - exit(0); - default: - fprintf(stderr, "option not supported\n"); - break; - } - } - - if (optind >= argc - 1) { - help("restore"); - exit(2); - } - - config_file = argv[optind]; - checkpoint_file = argv[optind + 1]; - create_domain(debug, daemonize, config_file, checkpoint_file, paused); - exit(0); -} - -int main_save(int argc, char **argv) -{ - char *filename = NULL, *p = NULL; - int checkpoint = 0; - int opt; - - while ((opt = getopt(argc, argv, "hc")) != -1) { - switch (opt) { - case 'c': - checkpoint = 1; - break; - case 'h': - help("save"); - exit(0); - default: - fprintf(stderr, "option not supported\n"); - break; - } - } - - if (optind >= argc - 1) { - help("save"); - exit(2); - } - - p = argv[optind]; - filename = argv[optind + 1]; - save_domain(p, filename, checkpoint); - exit(0); -} - -int main_pause(int argc, char **argv) -{ - int opt; - char *p; - - - while ((opt = getopt(argc, argv, "h")) != -1) { - switch (opt) { - case 'h': - help("pause"); - exit(0); - default: - fprintf(stderr, "option not supported\n"); - break; - } - } - if (optind >= argc) { - help("pause"); - exit(2); - } - - p = argv[optind]; - - pause_domain(p); - exit(0); -} - -int main_unpause(int argc, char **argv) -{ - int opt; - char *p; - - - while ((opt = getopt(argc, argv, "h")) != -1) { - switch (opt) { - case 'h': - help("unpause"); - exit(0); - default: - fprintf(stderr, "option not supported\n"); - break; - } - } - if (optind >= argc) { - help("unpause"); - exit(2); - } - - p = argv[optind]; - - unpause_domain(p); - exit(0); -} - -int main_destroy(int argc, char **argv) -{ - int opt; - char *p; - - while ((opt = getopt(argc, argv, "h")) != -1) { - switch (opt) { - case 'h': - help("destroy"); - exit(0); - default: - fprintf(stderr, "option not supported\n"); - break; - } - } - if (optind >= argc) { - help("destroy"); - exit(2); - } - - p = argv[optind]; - - destroy_domain(p); - exit(0); -} - -int main_list(int argc, char **argv) -{ - int opt; - - while ((opt = getopt(argc, argv, "h")) != -1) { - switch (opt) { - case 'h': - help("list"); - exit(0); - default: - fprintf(stderr, "option not supported\n"); - break; - } - } - - list_domains(); - exit(0); -} - -int main_list_vm(int argc, char **argv) -{ - int opt; - - while ((opt = getopt(argc, argv, "h")) != -1) { - switch (opt) { - case 'h': - help("list-vm"); - exit(0); - default: - fprintf(stderr, "option not supported\n"); - break; - } - } - - list_vm(); - exit(0); -} - -int main_create(int argc, char **argv) -{ - char *filename = NULL; - int debug = 0, daemonize = 1; - int opt; - - while ((opt = getopt(argc, argv, "hde")) != -1) { - switch (opt) { - case 'd': - debug = 1; - break; - case 'e': - daemonize = 0; - break; - case 'h': - help("create"); - exit(0); - default: - fprintf(stderr, "option not supported\n"); - break; - } - } - - if (optind >= argc) { - help("create"); - exit(2); - } - - filename = argv[optind]; - create_domain(debug, daemonize, filename, NULL, 0); - exit(0); -} - -void button_press(char *p, char *b) -{ - struct libxl_ctx ctx; - uint32_t domid; - libxl_button button; - - libxl_ctx_init(&ctx, LIBXL_VERSION); - libxl_ctx_set_log(&ctx, log_callback, NULL); - - if (domain_qualifier_to_domid(&ctx, p, &domid) < 0) { - fprintf(stderr, "%s is an invalid domain identifier\n", p); - exit(2); - } - - if (!strcmp(b, "power")) { - button = POWER_BUTTON; - } else if (!strcmp(b, "sleep")) { - button = SLEEP_BUTTON; - } else { - fprintf(stderr, "%s is an invalid button identifier\n", b); - exit(2); - } - - libxl_button_press(&ctx, domid, button); -} - -int main_button_press(int argc, char **argv) -{ - int opt; - char *p; - char *b; - - while ((opt = getopt(argc, argv, "h")) != -1) { - switch (opt) { - case 'h': - help("button-press"); - exit(0); - default: - fprintf(stderr, "option not supported\n"); - break; - } - } - if (optind >= argc - 1) { - help("button-press"); - exit(2); - } - - p = argv[optind]; - b = argv[optind + 1]; - - button_press(p, b); - exit(0); + snprintf(str, sizeof(str), "[%d] %s:%d:%s: %s\n", + loglevel, file, line, func, s); + libxl_write_exactly(NULL, logfile, str, strlen(str), NULL, NULL); } int main(int argc, char **argv) { + struct cmd_spec *cspec; + if (argc < 2) { help(NULL); exit(1); } + if (libxl_ctx_init(&ctx, LIBXL_VERSION)) { + fprintf(stderr, "cannot init xl context\n"); + exit(1); + } + if (libxl_ctx_set_log(&ctx, log_callback, NULL)) { + fprintf(stderr, "cannot set xl log callback\n"); + exit(-ERROR_FAIL); + } + srand(time(0)); - if (!strcmp(argv[1], "create")) { - main_create(argc - 1, argv + 1); - } else if (!strcmp(argv[1], "list")) { - main_list(argc - 1, argv + 1); - } else if (!strcmp(argv[1], "list-vm")) { - main_list_vm(argc - 1, argv + 1); - } else if (!strcmp(argv[1], "destroy")) { - main_destroy(argc - 1, argv + 1); - } else if (!strcmp(argv[1], "pci-attach")) { - main_pciattach(argc - 1, argv + 1); - } else if (!strcmp(argv[1], "pci-detach")) { - main_pcidetach(argc - 1, argv + 1); - } else if (!strcmp(argv[1], "pci-list")) { - main_pcilist(argc - 1, argv + 1); - } else if (!strcmp(argv[1], "pause")) { - main_pause(argc - 1, argv + 1); - } else if (!strcmp(argv[1], "unpause")) { - main_unpause(argc - 1, argv + 1); - } else if (!strcmp(argv[1], "console")) { - main_console(argc - 1, argv + 1); - } else if (!strcmp(argv[1], "save")) { - main_save(argc - 1, argv + 1); - } else if (!strcmp(argv[1], "restore")) { - main_restore(argc - 1, argv + 1); - } else if (!strcmp(argv[1], "cd-insert")) { - main_cd_insert(argc - 1, argv + 1); - } else if (!strcmp(argv[1], "cd-eject")) { - main_cd_eject(argc - 1, argv + 1); - } else if (!strcmp(argv[1], "mem-set")) { - main_memset(argc - 1, argv + 1); - } else if (!strcmp(argv[1], "button-press")) { - main_button_press(argc - 1, argv + 1); - } else if (!strcmp(argv[1], "help")) { - if (argc > 2) - help(argv[2]); - else - help(NULL); + cspec = cmdtable_lookup(argv[1]); + if (cspec) + return cspec->cmd_impl(argc, argv); + else if (!strcmp(argv[1], "help")) { + help(argv[optind]); exit(0); } else { fprintf(stderr, "command not implemented\n"); diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/xl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/libxl/xl.h Tue Jul 06 16:49:01 2010 +0100 @@ -0,0 +1,81 @@ +/* + * Author Yang Hongyang <yanghy@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; version 2.1 only. with the special + * exception on linking described in file LICENSE. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +#ifndef XL_H +#define XL_H + +struct cmd_spec { + char *cmd_name; + int (*cmd_impl)(int argc, char **argv); + char *cmd_desc; + char *cmd_usage; + char *cmd_option; +}; + +int main_vcpulist(int argc, char **argv); +int main_info(int argc, char **argv); +int main_cd_eject(int argc, char **argv); +int main_cd_insert(int argc, char **argv); +int main_console(int argc, char **argv); +int main_pcilist(int argc, char **argv); +int main_pcidetach(int argc, char **argv); +int main_pciattach(int argc, char **argv); +int main_restore(int argc, char **argv); +int main_migrate_receive(int argc, char **argv); +int main_save(int argc, char **argv); +int main_migrate(int argc, char **argv); +int main_pause(int argc, char **argv); +int main_unpause(int argc, char **argv); +int main_destroy(int argc, char **argv); +int main_shutdown(int argc, char **argv); +int main_reboot(int argc, char **argv); +int main_list(int argc, char **argv); +int main_list_vm(int argc, char **argv); +int main_create(int argc, char **argv); +int main_button_press(int argc, char **argv); +int main_vcpupin(int argc, char **argv); +int main_vcpuset(int argc, char **argv); +int main_memmax(int argc, char **argv); +int main_memset(int argc, char **argv); +int main_sched_credit(int argc, char **argv); +int main_domid(int argc, char **argv); +int main_domname(int argc, char **argv); +int main_rename(int argc, char **argv); +int main_trigger(int argc, char **argv); +int main_sysrq(int argc, char **argv); +int main_debug_keys(int argc, char **argv); +int main_dmesg(int argc, char **argv); +int main_top(int argc, char **argv); +int main_networkattach(int argc, char **argv); +int main_networklist(int argc, char **argv); +int main_networkdetach(int argc, char **argv); +int main_blockattach(int argc, char **argv); +int main_blocklist(int argc, char **argv); +int main_blockdetach(int argc, char **argv); +int main_uptime(int argc, char **argv); +int main_tmem_list(int argc, char **argv); +int main_tmem_freeze(int argc, char **argv); +int main_tmem_destroy(int argc, char **argv); +int main_tmem_thaw(int argc, char **argv); +int main_tmem_set(int argc, char **argv); +int main_tmem_shared_auth(int argc, char **argv); + +void help(char *command); + +/* Look up a command in the table, allowing unambiguous truncation */ +struct cmd_spec *cmdtable_lookup(const char *s); +extern struct cmd_spec cmd_table[]; +extern int cmdtable_len; + +#endif /* XL_H */ diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/xl_cmdimpl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/libxl/xl_cmdimpl.c Tue Jul 06 16:49:01 2010 +0100 @@ -0,0 +1,4243 @@ +/* + * Copyright (C) 2009 Citrix Ltd. + * Author Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx> + * Author Vincent Hanquez <vincent.hanquez@xxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; version 2.1 only. with the special + * exception on linking described in file LICENSE. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +#include "libxl_osdeps.h" + +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> /* for time */ +#include <getopt.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <arpa/inet.h> +#include <sys/utsname.h> /* for utsname in xl info */ +#include <xenctrl.h> +#include <ctype.h> +#include <inttypes.h> + +#include "libxl.h" +#include "libxl_utils.h" +#include "libxlutil.h" +#include "xl.h" + +#define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" + +#define CHK_ERRNO( call ) ({ \ + int chk_errno = (call); \ + if (chk_errno < 0) { \ + fprintf(stderr,"xl: fatal error: %s:%d: %s: %s\n", \ + __FILE__,__LINE__, strerror(chk_errno), #call); \ + exit(-ERROR_FAIL); \ + } \ + }) + +#define MUST( call ) ({ \ + int must_rc = (call); \ + if (must_rc < 0) { \ + fprintf(stderr,"xl: fatal error: %s:%d, rc=%d: %s\n", \ + __FILE__,__LINE__, must_rc, #call); \ + exit(-must_rc); \ + } \ + }) + + +int logfile = 2; + +/* every libxl action in xl uses this same libxl context */ +struct libxl_ctx ctx; + +/* when we operate on a domain, it is this one: */ +static uint32_t domid; +static const char *common_domname; + + +static const char savefileheader_magic[32]= + "Xen saved domain, xl format\n \0 \r"; + +static const char migrate_receiver_banner[]= + "xl migration receiver ready, send binary domain data.\n"; +static const char migrate_receiver_ready[]= + "domain received, ready to unpause"; +static const char migrate_permission_to_go[]= + "domain is yours, you are cleared to unpause"; +static const char migrate_report[]= + "my copy unpause results are as follows"; + /* followed by one byte: + * 0: everything went well, domain is running + * next thing is we all exit + * non-0: things went badly + * next thing should be a migrate_permission_to_go + * from target to source + */ + +struct save_file_header { + char magic[32]; /* savefileheader_magic */ + /* All uint32_ts are in domain's byte order. */ + uint32_t byteorder; /* SAVEFILE_BYTEORDER_VALUE */ + uint32_t mandatory_flags; /* unknown flags => reject restore */ + uint32_t optional_flags; /* unknown flags => reject restore */ + uint32_t optional_data_len; /* skip, or skip tail, if not understood */ +}; + +/* Optional data, in order: + * 4 bytes uint32_t config file size + * n bytes config file in Unix text file format + */ + +#define SAVEFILE_BYTEORDER_VALUE ((uint32_t)0x01020304UL) + +static int qualifier_to_id(const char *p, uint32_t *id_r) +{ + int i, alldigit; + + alldigit = 1; + for (i = 0; p[i]; i++) { + if (!isdigit((uint8_t)p[i])) { + alldigit = 0; + break; + } + } + + if (i > 0 && alldigit) { + *id_r = strtoul(p, NULL, 10); + return 0; + } else { + /* check here if it's a uuid and do proper conversion */ + } + return 1; +} + +static int domain_qualifier_to_domid(const char *p, uint32_t *domid_r, + int *was_name_r) +{ + int was_name; + + was_name = qualifier_to_id(p, domid_r); + if (was_name_r) *was_name_r = was_name; + return was_name ? libxl_name_to_domid(&ctx, p, domid_r) : 0; +} + +static void find_domain(const char *p) +{ + int rc, was_name; + + rc = domain_qualifier_to_domid(p, &domid, &was_name); + if (rc) { + fprintf(stderr, "%s is an invalid domain identifier (rc=%d)\n", p, rc); + exit(2); + } + common_domname = was_name ? p : libxl_domid_to_name(&ctx, domid); +} + +#define LOG(_f, _a...) dolog(__FILE__, __LINE__, __func__, _f "\n", ##_a) + +void dolog(const char *file, int line, const char *func, char *fmt, ...) +{ + va_list ap; + char *s; + int rc; + + va_start(ap, fmt); + rc = vasprintf(&s, fmt, ap); + va_end(ap); + if (rc >= 0) + libxl_write_exactly(NULL, logfile, s, rc, NULL, NULL); +} + +static void init_create_info(libxl_domain_create_info *c_info) +{ + memset(c_info, '\0', sizeof(*c_info)); + c_info->xsdata = NULL; + c_info->platformdata = NULL; + c_info->hap = 1; + c_info->hvm = 1; + c_info->oos = 1; + c_info->ssidref = 0; +} + +static void init_build_info(libxl_domain_build_info *b_info, libxl_domain_create_info *c_info) +{ + memset(b_info, '\0', sizeof(*b_info)); + b_info->timer_mode = -1; + b_info->hpet = 1; + b_info->vpt_align = -1; + b_info->max_vcpus = 1; + b_info->max_memkb = 32 * 1024; + b_info->target_memkb = b_info->max_memkb; + if (c_info->hvm) { + b_info->shadow_memkb = 0; /* Set later */ + b_info->video_memkb = 8 * 1024; + b_info->kernel = "hvmloader"; + b_info->hvm = 1; + b_info->u.hvm.pae = 1; + b_info->u.hvm.apic = 1; + b_info->u.hvm.acpi = 1; + b_info->u.hvm.nx = 1; + b_info->u.hvm.viridian = 0; + } else { + b_info->u.pv.slack_memkb = 8 * 1024; + } +} + +static void init_dm_info(libxl_device_model_info *dm_info, + libxl_domain_create_info *c_info, libxl_domain_build_info *b_info) +{ + int i; + memset(dm_info, '\0', sizeof(*dm_info)); + + for (i = 0; i < 16; i++) { + dm_info->uuid[i] = rand(); + } + + dm_info->dom_name = c_info->name; + dm_info->device_model = "qemu-dm"; + dm_info->videoram = b_info->video_memkb / 1024; + dm_info->apic = b_info->u.hvm.apic; + dm_info->vcpus = b_info->max_vcpus; + dm_info->vcpu_avail = b_info->cur_vcpus; + + dm_info->stdvga = 0; + dm_info->vnc = 1; + dm_info->vnclisten = "127.0.0.1"; + dm_info->vncdisplay = 0; + dm_info->vncunused = 1; + dm_info->keymap = NULL; + dm_info->sdl = 0; + dm_info->opengl = 0; + dm_info->nographic = 0; + dm_info->serial = NULL; + dm_info->boot = "cda"; + dm_info->usb = 0; + dm_info->usbdevice = NULL; + dm_info->xen_platform_pci = 1; +} + +static void init_nic_info(libxl_device_nic *nic_info, int devnum) +{ + memset(nic_info, '\0', sizeof(*nic_info)); + + nic_info->backend_domid = 0; + nic_info->domid = 0; + nic_info->devid = devnum; + nic_info->mtu = 1492; + nic_info->model = "e1000"; + nic_info->mac[0] = 0x00; + nic_info->mac[1] = 0x16; + nic_info->mac[2] = 0x3e; + nic_info->mac[3] = 1 + (int) (0x7f * (rand() / (RAND_MAX + 1.0))); + nic_info->mac[4] = 1 + (int) (0xff * (rand() / (RAND_MAX + 1.0))); + nic_info->mac[5] = 1 + (int) (0xff * (rand() / (RAND_MAX + 1.0))); + nic_info->ifname = NULL; + nic_info->bridge = "xenbr0"; + CHK_ERRNO( asprintf(&nic_info->script, "%s/vif-bridge", + libxl_xen_script_dir_path()) ); + nic_info->nictype = NICTYPE_IOEMU; +} + +static void init_vfb_info(libxl_device_vfb *vfb, int dev_num) +{ + memset(vfb, 0x00, sizeof(libxl_device_vfb)); + vfb->devid = dev_num; + vfb->vnc = 1; + vfb->vnclisten = "127.0.0.1"; + vfb->vncdisplay = 0; + vfb->vncunused = 1; + vfb->keymap = NULL; + vfb->sdl = 0; + vfb->opengl = 0; +} + +static void init_vkb_info(libxl_device_vkb *vkb, int dev_num) +{ + memset(vkb, 0x00, sizeof(libxl_device_vkb)); + vkb->devid = dev_num; +} + +static void init_console_info(libxl_device_console *console, int dev_num, libxl_domain_build_state *state) +{ + memset(console, 0x00, sizeof(libxl_device_console)); + console->devid = dev_num; + console->constype = CONSTYPE_XENCONSOLED; + if (state) + console->build_state = state; +} + +static void printf_info(int domid, + libxl_domain_create_info *c_info, + libxl_domain_build_info *b_info, + libxl_device_disk *disks, + int num_disks, + libxl_device_nic *vifs, + int num_vifs, + libxl_device_pci *pcidevs, + int num_pcidevs, + libxl_device_vfb *vfbs, + int num_vfbs, + libxl_device_vkb *vkb, + int num_vkbs, + libxl_device_model_info *dm_info) +{ + int i; + printf("(domain\n\t(domid %d)\n", domid); + printf("\t(domain_create_info)\n"); + printf("\t(hvm %d)\n", c_info->hvm); + printf("\t(hap %d)\n", c_info->hap); + printf("\t(oos %d)\n", c_info->oos); + printf("\t(ssidref %d)\n", c_info->ssidref); + printf("\t(name %s)\n", c_info->name); + printf("\t(uuid " UUID_FMT ")\n", + (c_info->uuid)[0], (c_info->uuid)[1], (c_info->uuid)[2], (c_info->uuid)[3], + (c_info->uuid)[4], (c_info->uuid)[5], (c_info->uuid)[6], (c_info->uuid)[7], + (c_info->uuid)[8], (c_info->uuid)[9], (c_info->uuid)[10], (c_info->uuid)[11], + (c_info->uuid)[12], (c_info->uuid)[13], (c_info->uuid)[14], (c_info->uuid)[15]); + if (c_info->xsdata) + printf("\t(xsdata contains data)\n"); + else + printf("\t(xsdata (null))\n"); + if (c_info->platformdata) + printf("\t(platformdata contains data)\n"); + else + printf("\t(platformdata (null))\n"); + + + printf("\t(domain_build_info)\n"); + printf("\t(timer_mode %d)\n", b_info->timer_mode); + printf("\t(hpet %d)\n", b_info->hpet); + printf("\t(vpt_align %d)\n", b_info->vpt_align); + printf("\t(max_vcpus %d)\n", b_info->max_vcpus); + printf("\t(tsc_mode %d)\n", b_info->tsc_mode); + printf("\t(max_memkb %d)\n", b_info->max_memkb); + printf("\t(target_memkb %d)\n", b_info->target_memkb); + + printf("\t(image\n"); + if (c_info->hvm) { + printf("\t\t(hvm\n"); + printf("\t\t\t(loader %s)\n", b_info->kernel); + printf("\t\t\t(video_memkb %d)\n", b_info->video_memkb); + printf("\t\t\t(shadow_memkb %d)\n", b_info->shadow_memkb); + printf("\t\t\t(pae %d)\n", b_info->u.hvm.pae); + printf("\t\t\t(apic %d)\n", b_info->u.hvm.apic); + printf("\t\t\t(acpi %d)\n", b_info->u.hvm.acpi); + printf("\t\t\t(nx %d)\n", b_info->u.hvm.nx); + printf("\t\t\t(viridian %d)\n", b_info->u.hvm.viridian); + + printf("\t\t\t(device_model %s)\n", dm_info->device_model); + printf("\t\t\t(videoram %d)\n", dm_info->videoram); + printf("\t\t\t(stdvga %d)\n", dm_info->stdvga); + printf("\t\t\t(vnc %d)\n", dm_info->vnc); + printf("\t\t\t(vnclisten %s)\n", dm_info->vnclisten); + printf("\t\t\t(vncdisplay %d)\n", dm_info->vncdisplay); + printf("\t\t\t(vncunused %d)\n", dm_info->vncunused); + printf("\t\t\t(keymap %s)\n", dm_info->keymap); + printf("\t\t\t(sdl %d)\n", dm_info->sdl); + printf("\t\t\t(opengl %d)\n", dm_info->opengl); + printf("\t\t\t(nographic %d)\n", dm_info->nographic); + printf("\t\t\t(serial %s)\n", dm_info->serial); + printf("\t\t\t(boot %s)\n", dm_info->boot); + printf("\t\t\t(usb %d)\n", dm_info->usb); + printf("\t\t\t(usbdevice %s)\n", dm_info->usbdevice); + printf("\t\t\t(apic %d)\n", dm_info->apic); + printf("\t\t)\n"); + } else { + printf("\t\t(linux %d)\n", b_info->hvm); + printf("\t\t\t(kernel %s)\n", b_info->kernel); + printf("\t\t\t(cmdline %s)\n", b_info->u.pv.cmdline); + printf("\t\t\t(ramdisk %s)\n", b_info->u.pv.ramdisk); + printf("\t\t)\n"); + } + printf("\t)\n"); + + for (i = 0; i < num_disks; i++) { + printf("\t(device\n"); + printf("\t\t(tap\n"); + printf("\t\t\t(backend_domid %d)\n", disks[i].backend_domid); + printf("\t\t\t(domid %d)\n", disks[i].domid); + printf("\t\t\t(physpath %s)\n", disks[i].physpath); + printf("\t\t\t(phystype %d)\n", disks[i].phystype); + printf("\t\t\t(virtpath %s)\n", disks[i].virtpath); + printf("\t\t\t(unpluggable %d)\n", disks[i].unpluggable); + printf("\t\t\t(readwrite %d)\n", disks[i].readwrite); + printf("\t\t\t(is_cdrom %d)\n", disks[i].is_cdrom); + printf("\t\t)\n"); + printf("\t)\n"); + } + + for (i = 0; i < num_vifs; i++) { + printf("\t(device\n"); + printf("\t\t(vif\n"); + printf("\t\t\t(backend_domid %d)\n", vifs[i].backend_domid); + printf("\t\t\t(domid %d)\n", vifs[i].domid); + printf("\t\t\t(devid %d)\n", vifs[i].devid); + printf("\t\t\t(mtu %d)\n", vifs[i].mtu); + printf("\t\t\t(model %s)\n", vifs[i].model); + printf("\t\t\t(mac %02x%02x%02x%02x%02x%02x)\n", vifs[i].mac[0], vifs[i].mac[1], vifs[i].mac[2], vifs[i].mac[3], vifs[i].mac[4], vifs[i].mac[5]); + printf("\t\t)\n"); + printf("\t)\n"); + } + + for (i = 0; i < num_pcidevs; i++) { + printf("\t(device\n"); + printf("\t\t(pci\n"); + printf("\t\t\t(pci dev "PCI_BDF_VDEVFN")\n", pcidevs[i].domain, pcidevs[i].bus, pcidevs[i].dev, pcidevs[i].func, pcidevs[i].vdevfn); + printf("\t\t\t(opts msitranslate %d power_mgmt %d)\n", pcidevs[i].msitranslate, pcidevs[i].power_mgmt); + printf("\t\t)\n"); + printf("\t)\n"); + } + + for (i = 0; i < num_vfbs; i++) { + printf("\t(device\n"); + printf("\t\t(vfb\n"); + printf("\t\t\t(backend_domid %d)\n", vfbs[i].backend_domid); + printf("\t\t\t(domid %d)\n", vfbs[i].domid); + printf("\t\t\t(devid %d)\n", vfbs[i].devid); + printf("\t\t\t(vnc %d)\n", vfbs[i].vnc); + printf("\t\t\t(vnclisten %s)\n", vfbs[i].vnclisten); + printf("\t\t\t(vncdisplay %d)\n", vfbs[i].vncdisplay); + printf("\t\t\t(vncunused %d)\n", vfbs[i].vncunused); + printf("\t\t\t(keymap %s)\n", vfbs[i].keymap); + printf("\t\t\t(sdl %d)\n", vfbs[i].sdl); + printf("\t\t\t(opengl %d)\n", vfbs[i].opengl); + printf("\t\t\t(display %s)\n", vfbs[i].display); + printf("\t\t\t(xauthority %s)\n", vfbs[i].xauthority); + printf("\t\t)\n"); + printf("\t)\n"); + } + printf(")\n"); +} + +static void parse_config_data(const char *configfile_filename_report, + const char *configfile_data, + int configfile_len, + libxl_domain_create_info *c_info, + libxl_domain_build_info *b_info, + libxl_device_disk **disks, + int *num_disks, + libxl_device_nic **vifs, + int *num_vifs, + libxl_device_pci **pcidevs, + int *num_pcidevs, + libxl_device_vfb **vfbs, + int *num_vfbs, + libxl_device_vkb **vkbs, + int *num_vkbs, + libxl_device_model_info *dm_info) +{ + const char *buf; + long l; + XLU_Config *config; + XLU_ConfigList *vbds, *nics, *pcis, *cvfbs; + int pci_power_mgmt = 0; + int pci_msitranslate = 1; + int i, e; + + config= xlu_cfg_init(stderr, configfile_filename_report); + if (!config) { + fprintf(stderr, "Failed to allocate for configuration\n"); + exit(1); + } + + e= xlu_cfg_readdata(config, configfile_data, configfile_len); + if (e) { + fprintf(stderr, "Failed to parse config file: %s\n", strerror(e)); + exit(1); + } + + init_create_info(c_info); + + c_info->hvm = 0; + if (!xlu_cfg_get_string (config, "builder", &buf) && + !strncmp(buf, "hvm", strlen(buf))) + c_info->hvm = 1; + + if (!xlu_cfg_get_long (config, "hap", &l)) + c_info->hap = l; + + if (!xlu_cfg_get_string (config, "name", &buf)) + c_info->name = strdup(buf); + else + c_info->name = "test"; + for (i = 0; i < 16; i++) { + c_info->uuid[i] = rand(); + } + + if (!xlu_cfg_get_long(config, "oos", &l)) + c_info->oos = l; + + init_build_info(b_info, c_info); + + /* the following is the actual config parsing with overriding values in the structures */ + if (!xlu_cfg_get_long (config, "vcpus", &l)) { + b_info->max_vcpus = l; + b_info->cur_vcpus = (1 << l) - 1; + } + + if (!xlu_cfg_get_long (config, "memory", &l)) { + b_info->max_memkb = l * 1024; + b_info->target_memkb = b_info->max_memkb; + } + + /* libxl_get_required_shadow_memory() must be called after final values + * (default or specified) for vcpus and memory are set, because the + * calculation depends on those values. */ + b_info->shadow_memkb = !xlu_cfg_get_long(config, "shadow_memory", &l) + ? l * 1024 + : libxl_get_required_shadow_memory(b_info->max_memkb, + b_info->max_vcpus); + + if (!xlu_cfg_get_long(config, "tsc_mode", &l)) + b_info->tsc_mode = l; + + if (!xlu_cfg_get_long (config, "videoram", &l)) + b_info->video_memkb = l * 1024; + + if (!xlu_cfg_get_string (config, "kernel", &buf)) + b_info->kernel = strdup(buf); + + if (c_info->hvm == 1) { + if (!xlu_cfg_get_long (config, "pae", &l)) + b_info->u.hvm.pae = l; + if (!xlu_cfg_get_long (config, "apic", &l)) + b_info->u.hvm.apic = l; + if (!xlu_cfg_get_long (config, "acpi", &l)) + b_info->u.hvm.acpi = l; + if (!xlu_cfg_get_long (config, "nx", &l)) + b_info->u.hvm.nx = l; + if (!xlu_cfg_get_long (config, "viridian", &l)) + b_info->u.hvm.viridian = l; + } else { + char *cmdline = NULL; + const char *root = NULL, *extra = ""; + + xlu_cfg_get_string (config, "root", &root); + xlu_cfg_get_string (config, "extra", &extra); + + if (root) { + if (asprintf(&cmdline, "root=%s %s", root, extra) == -1) + cmdline = NULL; + } else { + cmdline = strdup(extra); + } + + if ((root || extra) && !cmdline) { + fprintf(stderr, "Failed to allocate memory for cmdline\n"); + exit(1); + } + + b_info->u.pv.cmdline = cmdline; + if (!xlu_cfg_get_string (config, "ramdisk", &buf)) + b_info->u.pv.ramdisk = strdup(buf); + } + + if (!xlu_cfg_get_list (config, "disk", &vbds, 0)) { + *num_disks = 0; + *disks = NULL; + while ((buf = xlu_cfg_get_listitem (vbds, *num_disks)) != NULL) { + char *buf2 = strdup(buf); + char *p, *p2; + *disks = (libxl_device_disk *) realloc(*disks, sizeof (libxl_device_disk) * ((*num_disks) + 1)); + (*disks)[*num_disks].backend_domid = 0; + (*disks)[*num_disks].domid = 0; + (*disks)[*num_disks].unpluggable = 0; + p = strtok(buf2, ",:"); + while (*p == ' ') + p++; + if (!strcmp(p, "phy")) { + (*disks)[*num_disks].phystype = PHYSTYPE_PHY; + } else if (!strcmp(p, "file")) { + (*disks)[*num_disks].phystype = PHYSTYPE_FILE; + } else if (!strcmp(p, "tap")) { + p = strtok(NULL, ":"); + if (!strcmp(p, "aio")) { + (*disks)[*num_disks].phystype = PHYSTYPE_AIO; + } else if (!strcmp(p, "vhd")) { + (*disks)[*num_disks].phystype = PHYSTYPE_VHD; + } else if (!strcmp(p, "qcow")) { + (*disks)[*num_disks].phystype = PHYSTYPE_QCOW; + } else if (!strcmp(p, "qcow2")) { + (*disks)[*num_disks].phystype = PHYSTYPE_QCOW2; + } + } + p = strtok(NULL, ","); + while (*p == ' ') + p++; + (*disks)[*num_disks].physpath= strdup(p); + p = strtok(NULL, ","); + while (*p == ' ') + p++; + p2 = strchr(p, ':'); + if (p2 == NULL) { + (*disks)[*num_disks].virtpath = strdup(p); + (*disks)[*num_disks].is_cdrom = 0; + (*disks)[*num_disks].unpluggable = 1; + } else { + *p2 = '\0'; + (*disks)[*num_disks].virtpath = strdup(p); + if (!strcmp(p2 + 1, "cdrom")) { + (*disks)[*num_disks].is_cdrom = 1; + (*disks)[*num_disks].unpluggable = 1; + } else + (*disks)[*num_disks].is_cdrom = 0; + } + p = strtok(NULL, ","); + while (*p == ' ') + p++; + (*disks)[*num_disks].readwrite = (p[0] == 'w') ? 1 : 0; + free(buf2); + *num_disks = (*num_disks) + 1; + } + } + + if (!xlu_cfg_get_list (config, "vif", &nics, 0)) { + *num_vifs = 0; + *vifs = NULL; + while ((buf = xlu_cfg_get_listitem (nics, *num_vifs)) != NULL) { + char *buf2 = strdup(buf); + char *p, *p2; + *vifs = (libxl_device_nic *) realloc(*vifs, sizeof (libxl_device_nic) * ((*num_vifs) + 1)); + init_nic_info((*vifs) + (*num_vifs), (*num_vifs) + 1); + p = strtok(buf2, ","); + if (!p) + goto skip; + do { + while (*p == ' ') + p++; + if ((p2 = strchr(p, '=')) == NULL) + break; + *p2 = '\0'; + if (!strcmp(p, "model")) { + (*vifs)[*num_vifs].model = strdup(p2 + 1); + } else if (!strcmp(p, "mac")) { + char *p3 = p2 + 1; + *(p3 + 2) = '\0'; + (*vifs)[*num_vifs].mac[0] = strtol(p3, NULL, 16); + p3 = p3 + 3; + *(p3 + 2) = '\0'; + (*vifs)[*num_vifs].mac[1] = strtol(p3, NULL, 16); + p3 = p3 + 3; + *(p3 + 2) = '\0'; + (*vifs)[*num_vifs].mac[2] = strtol(p3, NULL, 16); + p3 = p3 + 3; + *(p3 + 2) = '\0'; + (*vifs)[*num_vifs].mac[3] = strtol(p3, NULL, 16); + p3 = p3 + 3; + *(p3 + 2) = '\0'; + (*vifs)[*num_vifs].mac[4] = strtol(p3, NULL, 16); + p3 = p3 + 3; + *(p3 + 2) = '\0'; + (*vifs)[*num_vifs].mac[5] = strtol(p3, NULL, 16); + } else if (!strcmp(p, "bridge")) { + (*vifs)[*num_vifs].bridge = strdup(p2 + 1); + } else if (!strcmp(p, "type")) { + if (!strcmp(p2 + 1, "ioemu")) + (*vifs)[*num_vifs].nictype = NICTYPE_IOEMU; + else + (*vifs)[*num_vifs].nictype = NICTYPE_VIF; + } else if (!strcmp(p, "ip")) { + inet_pton(AF_INET, p2 + 1, &((*vifs)[*num_vifs].ip)); + } else if (!strcmp(p, "script")) { + (*vifs)[*num_vifs].script = strdup(p2 + 1); + } else if (!strcmp(p, "vifname")) { + (*vifs)[*num_vifs].ifname = strdup(p2 + 1); + } else if (!strcmp(p, "rate")) { + fprintf(stderr, "the rate parameter for vifs is currently not supported\n"); + } else if (!strcmp(p, "accel")) { + fprintf(stderr, "the accel parameter for vifs is currently not supported\n"); + } + } while ((p = strtok(NULL, ",")) != NULL); +skip: + free(buf2); + *num_vifs = (*num_vifs) + 1; + } + } + + if (!xlu_cfg_get_list (config, "vfb", &cvfbs, 0)) { + *num_vfbs = 0; + *num_vkbs = 0; + *vfbs = NULL; + *vkbs = NULL; + while ((buf = xlu_cfg_get_listitem (cvfbs, *num_vfbs)) != NULL) { + char *buf2 = strdup(buf); + char *p, *p2; + *vfbs = (libxl_device_vfb *) realloc(*vfbs, sizeof(libxl_device_vfb) * ((*num_vfbs) + 1)); + init_vfb_info((*vfbs) + (*num_vfbs), (*num_vfbs)); + + *vkbs = (libxl_device_vkb *) realloc(*vkbs, sizeof(libxl_device_vkb) * ((*num_vkbs) + 1)); + init_vkb_info((*vkbs) + (*num_vkbs), (*num_vkbs)); + + p = strtok(buf2, ","); + if (!p) + goto skip_vfb; + do { + while (*p == ' ') + p++; + if ((p2 = strchr(p, '=')) == NULL) + break; + *p2 = '\0'; + if (!strcmp(p, "vnc")) { + (*vfbs)[*num_vfbs].vnc = atoi(p2 + 1); + } else if (!strcmp(p, "vnclisten")) { + (*vfbs)[*num_vfbs].vnclisten = strdup(p2 + 1); + } else if (!strcmp(p, "vncpasswd")) { + (*vfbs)[*num_vfbs].vncpasswd = strdup(p2 + 1); + } else if (!strcmp(p, "vncdisplay")) { + (*vfbs)[*num_vfbs].vncdisplay = atoi(p2 + 1); + } else if (!strcmp(p, "vncunused")) { + (*vfbs)[*num_vfbs].vncunused = atoi(p2 + 1); + } else if (!strcmp(p, "keymap")) { + (*vfbs)[*num_vfbs].keymap = strdup(p2 + 1); + } else if (!strcmp(p, "sdl")) { + (*vfbs)[*num_vfbs].sdl = atoi(p2 + 1); + } else if (!strcmp(p, "opengl")) { + (*vfbs)[*num_vfbs].opengl = atoi(p2 + 1); + } else if (!strcmp(p, "display")) { + (*vfbs)[*num_vfbs].display = strdup(p2 + 1); + } else if (!strcmp(p, "xauthority")) { + (*vfbs)[*num_vfbs].xauthority = strdup(p2 + 1); + } + } while ((p = strtok(NULL, ",")) != NULL); +skip_vfb: + free(buf2); + *num_vfbs = (*num_vfbs) + 1; + *num_vkbs = (*num_vkbs) + 1; + } + } + + if (!xlu_cfg_get_long (config, "pci_msitranslate", &l)) + pci_msitranslate = l; + + if (!xlu_cfg_get_long (config, "pci_power_mgmt", &l)) + pci_power_mgmt = l; + + if (!xlu_cfg_get_list (config, "pci", &pcis, 0)) { + *num_pcidevs = 0; + *pcidevs = NULL; + while ((buf = xlu_cfg_get_listitem (pcis, *num_pcidevs)) != NULL) { + unsigned int domain = 0, bus = 0, dev = 0, func = 0, vdevfn = 0; + char *buf2 = strdup(buf); + char *p; + *pcidevs = (libxl_device_pci *) realloc(*pcidevs, sizeof (libxl_device_pci) * ((*num_pcidevs) + 1)); + memset(*pcidevs + *num_pcidevs, 0x00, sizeof(libxl_device_pci)); + p = strtok(buf2, ","); + if (!p) + goto skip_pci; + if (!sscanf(p, PCI_BDF_VDEVFN, &domain, &bus, &dev, &func, &vdevfn)) { + sscanf(p, "%02x:%02x.%01x@%02x", &bus, &dev, &func, &vdevfn); + domain = 0; + } + libxl_device_pci_init(*pcidevs + *num_pcidevs, domain, bus, dev, func, vdevfn); + (*pcidevs)[*num_pcidevs].msitranslate = pci_msitranslate; + (*pcidevs)[*num_pcidevs].power_mgmt = pci_power_mgmt; + while ((p = strtok(NULL, ",=")) != NULL) { + while (*p == ' ') + p++; + if (!strcmp(p, "msitranslate")) { + p = strtok(NULL, ",="); + (*pcidevs)[*num_pcidevs].msitranslate = atoi(p); + } else if (!strcmp(p, "power_mgmt")) { + p = strtok(NULL, ",="); + (*pcidevs)[*num_pcidevs].power_mgmt = atoi(p); + } + } + *num_pcidevs = (*num_pcidevs) + 1; +skip_pci: + free(buf2); + } + } + + if (c_info->hvm == 1) { + /* init dm from c and b */ + init_dm_info(dm_info, c_info, b_info); + + /* then process config related to dm */ + if (!xlu_cfg_get_string (config, "device_model", &buf)) + dm_info->device_model = strdup(buf); + if (!xlu_cfg_get_long (config, "stdvga", &l)) + dm_info->stdvga = l; + if (!xlu_cfg_get_long (config, "vnc", &l)) + dm_info->vnc = l; + if (!xlu_cfg_get_string (config, "vnclisten", &buf)) + dm_info->vnclisten = strdup(buf); + if (!xlu_cfg_get_string (config, "vncpasswd", &buf)) + dm_info->vncpasswd = strdup(buf); + if (!xlu_cfg_get_long (config, "vncdisplay", &l)) + dm_info->vncdisplay = l; + if (!xlu_cfg_get_long (config, "vncunused", &l)) + dm_info->vncunused = l; + if (!xlu_cfg_get_string (config, "keymap", &buf)) + dm_info->keymap = strdup(buf); + if (!xlu_cfg_get_long (config, "sdl", &l)) + dm_info->sdl = l; + if (!xlu_cfg_get_long (config, "opengl", &l)) + dm_info->opengl = l; + if (!xlu_cfg_get_long (config, "nographic", &l)) + dm_info->nographic = l; + if (!xlu_cfg_get_string (config, "serial", &buf)) + dm_info->serial = strdup(buf); + if (!xlu_cfg_get_string (config, "boot", &buf)) + dm_info->boot = strdup(buf); + if (!xlu_cfg_get_long (config, "usb", &l)) + dm_info->usb = l; + if (!xlu_cfg_get_string (config, "usbdevice", &buf)) + dm_info->usbdevice = strdup(buf); + if (!xlu_cfg_get_long (config, "xen_platform_pci", &l)) + dm_info->xen_platform_pci = l; + } + + dm_info->type = c_info->hvm ? XENFV : XENPV; + + xlu_cfg_destroy(config); +} + +static void *xmalloc(size_t sz) { + void *r; + r = malloc(sz); + if (!r) { fprintf(stderr,"xl: Unable to malloc %lu bytes.\n", + (unsigned long)sz); exit(-ERROR_FAIL); } + return r; +} + +static void *xrealloc(void *ptr, size_t sz) { + void *r; + if (!sz) { free(ptr); return 0; } + /* realloc(non-0, 0) has a useless return value; + * but xrealloc(anything, 0) is like free + */ + r = realloc(ptr, sz); + if (!r) { fprintf(stderr,"xl: Unable to realloc to %lu bytes.\n", + (unsigned long)sz); exit(-ERROR_FAIL); } + return r; +} + +struct domain_create { + int debug; + int daemonize; + int paused; + int dryrun; + int quiet; + const char *config_file; + const char *extra_config; /* extra config string */ + const char *restore_file; + int migrate_fd; /* -1 means none */ + char **migration_domname_r; +}; + +static int create_domain(struct domain_create *dom_info) +{ + libxl_domain_create_info info1; + libxl_domain_build_info info2; + libxl_domain_build_state state; + libxl_device_model_info dm_info; + libxl_device_disk *disks = NULL; + libxl_device_nic *vifs = NULL; + libxl_device_pci *pcidevs = NULL; + libxl_device_vfb *vfbs = NULL; + libxl_device_vkb *vkbs = NULL; + libxl_device_console console; + + int debug = dom_info->debug; + int daemonize = dom_info->daemonize; + int paused = dom_info->paused; + const char *config_file = dom_info->config_file; + const char *extra_config = dom_info->extra_config; + const char *restore_file = dom_info->restore_file; + int migrate_fd = dom_info->migrate_fd; + char **migration_domname_r = dom_info->migration_domname_r; + + int num_disks = 0, num_vifs = 0, num_pcidevs = 0, num_vfbs = 0, num_vkbs = 0; + int i, fd; + int need_daemon = 1; + int ret, rc; + libxl_device_model_starting *dm_starting = 0; + libxl_waiter *w1 = NULL, *w2 = NULL; + void *config_data = 0; + int config_len = 0; + int restore_fd = -1; + struct save_file_header hdr; + + memset(&dm_info, 0x00, sizeof(dm_info)); + + if (restore_file) { + uint8_t *optdata_begin = 0; + const uint8_t *optdata_here = 0; + union { uint32_t u32; char b[4]; } u32buf; + uint32_t badflags; + + restore_fd = migrate_fd >= 0 ? migrate_fd : + open(restore_file, O_RDONLY); + + CHK_ERRNO( libxl_read_exactly(&ctx, restore_fd, &hdr, + sizeof(hdr), restore_file, "header") ); + if (memcmp(hdr.magic, savefileheader_magic, sizeof(hdr.magic))) { + fprintf(stderr, "File has wrong magic number -" + " corrupt or for a different tool?\n"); + return ERROR_INVAL; + } + if (hdr.byteorder != SAVEFILE_BYTEORDER_VALUE) { + fprintf(stderr, "File has wrong byte order\n"); + return ERROR_INVAL; + } + fprintf(stderr, "Loading new save file %s" + " (new xl fmt info" + " 0x%"PRIx32"/0x%"PRIx32"/%"PRIu32")\n", + restore_file, hdr.mandatory_flags, hdr.optional_flags, + hdr.optional_data_len); + + badflags = hdr.mandatory_flags & ~( 0 /* none understood yet */ ); + if (badflags) { + fprintf(stderr, "Savefile has mandatory flag(s) 0x%"PRIx32" " + "which are not supported; need newer xl\n", + badflags); + return ERROR_INVAL; + } + if (hdr.optional_data_len) { + optdata_begin = xmalloc(hdr.optional_data_len); + CHK_ERRNO( libxl_read_exactly(&ctx, restore_fd, optdata_begin, + hdr.optional_data_len, restore_file, "optdata") ); + } + +#define OPTDATA_LEFT (hdr.optional_data_len - (optdata_here - optdata_begin)) +#define WITH_OPTDATA(amt, body) \ + if (OPTDATA_LEFT < (amt)) { \ + fprintf(stderr, "Savefile truncated.\n"); \ + return ERROR_INVAL; \ + } else { \ + body; \ + optdata_here += (amt); \ + } + + optdata_here = optdata_begin; + + if (OPTDATA_LEFT) { + fprintf(stderr, " Savefile contains xl domain config\n"); + WITH_OPTDATA(4, { + memcpy(u32buf.b, optdata_here, 4); + config_len = u32buf.u32; + }); + WITH_OPTDATA(config_len, { + config_data = xmalloc(config_len); + memcpy(config_data, optdata_here, config_len); + }); + } + + } + + if (config_file) { + free(config_data); config_data = 0; + ret = libxl_read_file_contents(&ctx, config_file, + &config_data, &config_len); + if (ret) { fprintf(stderr, "Failed to read config file: %s: %s\n", + config_file, strerror(errno)); return ERROR_FAIL; } + if (!restore_file && extra_config + && strlen(extra_config)) { + if (config_len > INT_MAX - (strlen(extra_config) + 2)) { + fprintf(stderr, "Failed to attach extra configration\n"); + return ERROR_FAIL; + } + config_data = realloc(config_data, config_len + + strlen(extra_config) + 2); + if (!config_data) { + fprintf(stderr, "Failed to realloc config_data\n"); + return ERROR_FAIL; + } + strcat(config_data, "\n"); + strcat(config_data, extra_config); + strcat(config_data, "\n"); + config_len += (strlen(extra_config) + 2); + } + } else { + if (!config_data) { + fprintf(stderr, "Config file not specified and" + " none in save file\n"); + return ERROR_INVAL; + } + config_file = "<saved>"; + } + + if (!dom_info->quiet) + printf("Parsing config file %s\n", config_file); + + parse_config_data(config_file, config_data, config_len, &info1, &info2, &disks, &num_disks, &vifs, &num_vifs, &pcidevs, &num_pcidevs, &vfbs, &num_vfbs, &vkbs, &num_vkbs, &dm_info); + + if (dom_info->dryrun) + return 0; + + if (migrate_fd >= 0) { + if (info1.name) { + /* when we receive a domain we get its name from the config + * file; and we receive it to a temporary name */ + assert(!common_domname); + common_domname = info1.name; + if (asprintf(migration_domname_r, "%s--incoming", info1.name) < 0) { + fprintf(stderr, "Failed to allocate memory in asprintf\n"); + exit(1); + } + info1.name = *migration_domname_r; + } + } + + if (debug) + printf_info(-1, &info1, &info2, disks, num_disks, vifs, num_vifs, pcidevs, num_pcidevs, vfbs, num_vfbs, vkbs, num_vkbs, &dm_info); + +start: + domid = 0; + + ret = libxl_domain_make(&ctx, &info1, &domid); + if (ret) { + fprintf(stderr, "cannot make domain: %d\n", ret); + ret = ERROR_FAIL; + goto error_out; + } + + ret = libxl_userdata_store(&ctx, domid, "xl", + config_data, config_len); + if (ret) { + perror("cannot save config file"); + ret = ERROR_FAIL; + goto error_out; + } + + if (!restore_file || !need_daemon) { + if (dm_info.saved_state) { + free(dm_info.saved_state); + dm_info.saved_state = NULL; + } + ret = libxl_domain_build(&ctx, &info2, domid, &state); + } else { + ret = libxl_domain_restore(&ctx, &info2, domid, restore_fd, &state, &dm_info); + } + + if (ret) { + fprintf(stderr, "cannot (re-)build domain: %d\n", ret); + ret = ERROR_FAIL; + goto error_out; + } + + for (i = 0; i < num_disks; i++) { + disks[i].domid = domid; + ret = libxl_device_disk_add(&ctx, domid, &disks[i]); + if (ret) { + fprintf(stderr, "cannot add disk %d to domain: %d\n", i, ret); + ret = ERROR_FAIL; + goto error_out; + } + } + for (i = 0; i < num_vifs; i++) { + vifs[i].domid = domid; + ret = libxl_device_nic_add(&ctx, domid, &vifs[i]); + if (ret) { + fprintf(stderr, "cannot add nic %d to domain: %d\n", i, ret); + ret = ERROR_FAIL; + goto error_out; + } + } + if (info1.hvm) { + dm_info.domid = domid; + MUST( libxl_create_device_model(&ctx, &dm_info, disks, num_disks, + vifs, num_vifs, &dm_starting) ); + } else { + for (i = 0; i < num_vfbs; i++) { + vfbs[i].domid = domid; + libxl_device_vfb_add(&ctx, domid, &vfbs[i]); + vkbs[i].domid = domid; + libxl_device_vkb_add(&ctx, domid, &vkbs[i]); + } + init_console_info(&console, 0, &state); + console.domid = domid; + if (num_vfbs) + console.constype = CONSTYPE_IOEMU; + libxl_device_console_add(&ctx, domid, &console); + if (num_vfbs) + libxl_create_xenpv_qemu(&ctx, vfbs, 1, &console, &dm_starting); + } + + if (dm_starting) + MUST( libxl_confirm_device_model_startup(&ctx, dm_starting) ); + for (i = 0; i < num_pcidevs; i++) + libxl_device_pci_add(&ctx, domid, &pcidevs[i]); + + if (!paused) + libxl_domain_unpause(&ctx, domid); + + if (!daemonize) + return domid; /* caller gets success in parent */ + + if (need_daemon) { + char *fullname, *name; + pid_t child1, got_child; + int nullfd; + + child1 = libxl_fork(&ctx); + if (child1) { + int status; + for (;;) { + got_child = waitpid(child1, &status, 0); + if (got_child == child1) break; + assert(got_child == -1); + if (errno != EINTR) { + perror("failed to wait for daemonizing child"); + ret = ERROR_FAIL; + goto error_out; + } + } + if (status) { + libxl_report_child_exitstatus(&ctx, XL_LOG_ERROR, + "daemonizing child", child1, status); + ret = ERROR_FAIL; + goto error_out; + } + return domid; /* caller gets success in parent */ + } + + rc = libxl_ctx_postfork(&ctx); + if (rc) { + LOG("failed to reinitialise context after fork"); + exit(-1); + } + + if (asprintf(&name, "xl-%s", info1.name) < 0) { + LOG("Failed to allocate memory in asprintf"); + exit(1); + } + rc = libxl_create_logfile(&ctx, name, &fullname); + if (rc) { + LOG("failed to open logfile %s",fullname,strerror(errno)); + exit(-1); + } + + CHK_ERRNO(( logfile = open(fullname, O_WRONLY|O_CREAT, 0644) )<0); + free(fullname); + free(name); + + CHK_ERRNO(( nullfd = open("/dev/null", O_RDONLY) )<0); + dup2(nullfd, 0); + dup2(logfile, 1); + dup2(logfile, 2); + + CHK_ERRNO(daemon(0, 1) < 0); + need_daemon = 0; + } + LOG("Waiting for domain %s (domid %d) to die [pid %ld]", + info1.name, domid, (long)getpid()); + w1 = (libxl_waiter*) xmalloc(sizeof(libxl_waiter) * num_disks); + w2 = (libxl_waiter*) xmalloc(sizeof(libxl_waiter)); + libxl_wait_for_disk_ejects(&ctx, domid, disks, num_disks, w1); + libxl_wait_for_domain_death(&ctx, domid, w2); + libxl_get_wait_fd(&ctx, &fd); + while (1) { + int ret; + fd_set rfds; + xc_domaininfo_t info; + libxl_event event; + libxl_device_disk disk; + memset(&info, 0x00, sizeof(xc_domaininfo_t)); + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + ret = select(fd + 1, &rfds, NULL, NULL, NULL); + if (!ret) + continue; + libxl_get_event(&ctx, &event); + switch (event.type) { + case DOMAIN_DEATH: + if (libxl_event_get_domain_death_info(&ctx, domid, &event, &info)) { + LOG("Domain %d is dead", domid); + if (info.flags & XEN_DOMINF_dying || (info.flags & XEN_DOMINF_shutdown && (((info.flags >> XEN_DOMINF_shutdownshift) & XEN_DOMINF_shutdownmask) != SHUTDOWN_suspend))) { + LOG("Domain %d needs to be clean: destroying the domain", domid); + libxl_domain_destroy(&ctx, domid, 0); + if (info.flags & XEN_DOMINF_shutdown && + (((info.flags >> XEN_DOMINF_shutdownshift) & XEN_DOMINF_shutdownmask) == SHUTDOWN_reboot)) { + libxl_free_waiter(w1); + libxl_free_waiter(w2); + free(w1); + free(w2); + LOG("Done. Rebooting now"); + /* + * XXX FIXME: If this sleep is not there then + * domain re-creation fails sometimes. + */ + sleep(2); + goto start; + } + LOG("Done. Exiting now"); + } + LOG("Domain %d does not need to be clean, exiting now", domid); + exit(0); + } + break; + case DISK_EJECT: + if (libxl_event_get_disk_eject_info(&ctx, domid, &event, &disk)) + libxl_cdrom_insert(&ctx, domid, &disk); + break; + } + libxl_free_event(&event); + } + + close(logfile); + exit(0); + +error_out: + if (domid) + libxl_domain_destroy(&ctx, domid, 0); + return ret; +} + +void help(char *command) +{ + int i; + struct cmd_spec *cmd; + + if (!command || !strcmp(command, "help")) { + printf("Usage xl [-v] <subcommand> [args]\n\n"); + printf("xl full list of subcommands:\n\n"); + for (i = 0; i < cmdtable_len; i++) + printf(" %-20s%s\n", + cmd_table[i].cmd_name, cmd_table[i].cmd_desc); + } else { + cmd = cmdtable_lookup(command); + if (cmd) { + printf("Usage: xl [-v] %s %s\n\n%s.\n\n", + cmd->cmd_name, + cmd->cmd_usage, + cmd->cmd_desc); + if (cmd->cmd_option) + printf("Options:\n\n%s\n", cmd->cmd_option); + } + else { + printf("command \"%s\" not implemented\n", command); + } + } +} + +static int64_t parse_mem_size_kb(char *mem) +{ + char *endptr; + int64_t kbytes; + + kbytes = strtoll(mem, &endptr, 10); + + if (strlen(endptr) > 1) + return -1; + + switch (tolower((uint8_t)*endptr)) { + case 't': + kbytes <<= 10; + case 'g': + kbytes <<= 10; + case '\0': + case 'm': + kbytes <<= 10; + case 'k': + break; + case 'b': + kbytes >>= 10; + break; + default: + return -1; + } + + return kbytes; +} + +int set_memory_max(char *p, char *mem) +{ + int64_t memorykb; + int rc; + + find_domain(p); + + memorykb = parse_mem_size_kb(mem); + if (memorykb == -1) { + fprintf(stderr, "invalid memory size: %s\n", mem); + exit(3); + } + + rc = libxl_domain_setmaxmem(&ctx, domid, memorykb); + + return rc; +} + +int main_memmax(int argc, char **argv) +{ + int opt = 0; + char *p = NULL, *mem; + int rc; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("mem-max"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + if (optind >= argc - 1) { + help("mem-max"); + exit(2); + } + + p = argv[optind]; + mem = argv[optind + 1]; + + rc = set_memory_max(p, mem); + if (rc) { + fprintf(stderr, "cannot set domid %d static max memory to : %s\n", domid, mem); + exit(1); + } + + exit(0); +} + +void set_memory_target(char *p, char *mem) +{ + long long int memorykb; + + find_domain(p); + + memorykb = parse_mem_size_kb(mem); + if (memorykb == -1) { + fprintf(stderr, "invalid memory size: %s\n", mem); + exit(3); + } + + libxl_set_memory_target(&ctx, domid, memorykb, /* enforce */ 1); +} + +int main_memset(int argc, char **argv) +{ + int opt = 0; + char *p = NULL, *mem; + + while ((opt = getopt(argc, argv, "h:")) != -1) { + switch (opt) { + case 'h': + help("mem-set"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + if (optind >= argc - 1) { + help("mem-set"); + exit(2); + } + + p = argv[optind]; + mem = argv[optind + 1]; + + set_memory_target(p, mem); + exit(0); +} + +void console(char *p, int cons_num) +{ + find_domain(p); + libxl_console_attach(&ctx, domid, cons_num); +} + +void cd_insert(char *dom, char *virtdev, char *phys) +{ + libxl_device_disk disk; + char *p; + + find_domain(dom); + + disk.backend_domid = 0; + disk.domid = domid; + if (phys) { + p = strchr(phys, ':'); + if (!p) { + fprintf(stderr, "No type specified, "); + disk.physpath = phys; + if (!strncmp(phys, "/dev", 4)) { + fprintf(stderr, "assuming phy:\n"); + disk.phystype = PHYSTYPE_PHY; + } else { + fprintf(stderr, "assuming file:\n"); + disk.phystype = PHYSTYPE_FILE; + } + } else { + *p = '\0'; + p++; + disk.physpath = p; + libxl_string_to_phystype(&ctx, phys, &disk.phystype); + } + } else { + disk.physpath = NULL; + disk.phystype = 0; + } + disk.virtpath = virtdev; + disk.unpluggable = 1; + disk.readwrite = 0; + disk.is_cdrom = 1; + + libxl_cdrom_insert(&ctx, domid, &disk); +} + +int main_cd_eject(int argc, char **argv) +{ + int opt = 0; + char *p = NULL, *virtdev; + + while ((opt = getopt(argc, argv, "hn:")) != -1) { + switch (opt) { + case 'h': + help("cd-eject"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + if (optind >= argc - 1) { + help("cd-eject"); + exit(2); + } + + p = argv[optind]; + virtdev = argv[optind + 1]; + + cd_insert(p, virtdev, NULL); + exit(0); +} + +int main_cd_insert(int argc, char **argv) +{ + int opt = 0; + char *p = NULL, *file = NULL, *virtdev; + + while ((opt = getopt(argc, argv, "hn:")) != -1) { + switch (opt) { + case 'h': + help("cd-insert"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + if (optind >= argc - 2) { + help("cd-insert"); + exit(2); + } + + p = argv[optind]; + virtdev = argv[optind + 1]; + file = argv[optind + 2]; + + cd_insert(p, virtdev, file); + exit(0); +} + +int main_console(int argc, char **argv) +{ + int opt = 0, cons_num = 0; + char *p = NULL; + + while ((opt = getopt(argc, argv, "hn:")) != -1) { + switch (opt) { + case 'h': + help("console"); + exit(0); + case 'n': + if (optarg) { + cons_num = strtol(optarg, NULL, 10); + } + break; + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + if (optind >= argc) { + help("console"); + exit(2); + } + + p = argv[optind]; + + console(p, cons_num); + exit(0); +} + +void pcilist(char *dom) +{ + libxl_device_pci *pcidevs; + int num, i; + + find_domain(dom); + + pcidevs = libxl_device_pci_list(&ctx, domid, &num); + if (!num) + return; + printf("VFn domain bus slot func\n"); + for (i = 0; i < num; i++) { + printf("0x%02x 0x%04x 0x%02x 0x%02x 0x%01x\n", pcidevs[i].vdevfn, pcidevs[i].domain, pcidevs[i].bus, pcidevs[i].dev, pcidevs[i].func); + } + free(pcidevs); +} + +int main_pcilist(int argc, char **argv) +{ + int opt; + char *domname = NULL; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("pci-list"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + if (optind >= argc) { + help("pci-list"); + exit(2); + } + + domname = argv[optind]; + + pcilist(domname); + exit(0); +} + +void pcidetach(char *dom, char *bdf) +{ + libxl_device_pci pcidev; + unsigned int domain, bus, dev, func; + + find_domain(dom); + + memset(&pcidev, 0x00, sizeof(pcidev)); + if (sscanf(bdf, PCI_BDF, &domain, &bus, &dev, &func) != 4) { + fprintf(stderr, "pci-detach: malformed BDF specification \"%s\"\n", bdf); + exit(2); + } + libxl_device_pci_init(&pcidev, domain, bus, dev, func, 0); + libxl_device_pci_remove(&ctx, domid, &pcidev); +} + +int main_pcidetach(int argc, char **argv) +{ + int opt; + char *domname = NULL, *bdf = NULL; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("pci-detach"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + if (optind >= argc - 1) { + help("pci-detach"); + exit(2); + } + + domname = argv[optind]; + bdf = argv[optind + 1]; + + pcidetach(domname, bdf); + exit(0); +} +void pciattach(char *dom, char *bdf, char *vs) +{ + libxl_device_pci pcidev; + unsigned int domain, bus, dev, func; + + find_domain(dom); + + memset(&pcidev, 0x00, sizeof(pcidev)); + if (sscanf(bdf, PCI_BDF, &domain, &bus, &dev, &func) != 4) { + fprintf(stderr, "pci-attach: malformed BDF specification \"%s\"\n", bdf); + exit(2); + } + libxl_device_pci_init(&pcidev, domain, bus, dev, func, 0); + libxl_device_pci_add(&ctx, domid, &pcidev); +} + +int main_pciattach(int argc, char **argv) +{ + int opt; + char *domname = NULL, *bdf = NULL, *vs = NULL; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("pci-attach"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + if (optind >= argc - 1) { + help("pci-attach"); + exit(2); + } + + domname = argv[optind]; + bdf = argv[optind + 1]; + + if (optind + 1 < argc) + vs = argv[optind + 2]; + + pciattach(domname, bdf, vs); + exit(0); +} + +void pause_domain(char *p) +{ + find_domain(p); + libxl_domain_pause(&ctx, domid); +} + +void unpause_domain(char *p) +{ + find_domain(p); + libxl_domain_unpause(&ctx, domid); +} + +void destroy_domain(char *p) +{ + int rc; + find_domain(p); + if (domid == 0) { + fprintf(stderr, "Cannot destroy privileged domain 0.\n\n"); + exit(-1); + } + rc = libxl_domain_destroy(&ctx, domid, 0); + if (rc) { fprintf(stderr,"destroy failed (rc=%d)\n.",rc); exit(-1); } +} + +void shutdown_domain(char *p) +{ + int rc; + find_domain(p); + rc=libxl_domain_shutdown(&ctx, domid, 0); + if (rc) { fprintf(stderr,"shutdown failed (rc=%d)\n.",rc);exit(-1); } +} + +void reboot_domain(char *p) +{ + int rc; + find_domain(p); + rc=libxl_domain_shutdown(&ctx, domid, 1); + if (rc) { fprintf(stderr,"reboot failed (rc=%d)\n.",rc);exit(-1); } +} + +void list_domains_details(void) +{ + struct libxl_dominfo *info; + char *config_file; + uint8_t *data; + int nb_domain, i, len, rc; + int num_disks = 0, num_vifs = 0, num_pcidevs = 0, num_vfbs = 0, num_vkbs = 0; + libxl_domain_create_info info1; + libxl_domain_build_info info2; + libxl_device_model_info dm_info; + libxl_device_disk *disks = NULL; + libxl_device_nic *vifs = NULL; + + libxl_device_pci *pcidevs = NULL; + libxl_device_vfb *vfbs = NULL; + libxl_device_vkb *vkbs = NULL; + + info = libxl_list_domain(&ctx, &nb_domain); + + if (!info) { + fprintf(stderr, "libxl_domain_infolist failed.\n"); + exit(1); + } + for (i = 0; i < nb_domain; i++) { + rc = libxl_userdata_retrieve(&ctx, info[i].domid, "xl", &data, &len); + if (rc) + continue; + CHK_ERRNO(asprintf(&config_file, "<domid %d data>", info[i].domid)); + parse_config_data(config_file, (char *)data, len, &info1, &info2, &disks, &num_disks, &vifs, &num_vifs, &pcidevs, &num_pcidevs, &vfbs, &num_vfbs, &vkbs, &num_vkbs, &dm_info); + printf_info(info[i].domid, &info1, &info2, disks, num_disks, vifs, num_vifs, pcidevs, num_pcidevs, vfbs, num_vfbs, vkbs, num_vkbs, &dm_info); + free(data); + free(config_file); + } + free(info); +} + +void list_domains(int verbose) +{ + struct libxl_dominfo *info; + int nb_domain, i; + + info = libxl_list_domain(&ctx, &nb_domain); + + if (!info) { + fprintf(stderr, "libxl_domain_infolist failed.\n"); + exit(1); + } + printf("Name ID Mem VCPUs\tState\tTime(s)\n"); + for (i = 0; i < nb_domain; i++) { + printf("%-40s %5d %5lu %5d %c%c%c %8.1f", + libxl_domid_to_name(&ctx, info[i].domid), + info[i].domid, + (unsigned long) (info[i].max_memkb / 1024), + info[i].vcpu_online, + info[i].running ? 'r' : '-', + info[i].paused ? 'p' : '-', + info[i].dying ? 'd' : '-', + ((float)info[i].cpu_time / 1e9)); + if (verbose) { + char *uuid = libxl_uuid2string(&ctx, info[i].uuid); + printf(" %s", uuid); + } + putchar('\n'); + } + free(info); +} + +void list_vm(void) +{ + struct libxl_vminfo *info; + int nb_vm, i; + + info = libxl_list_vm(&ctx, &nb_vm); + + if (info < 0) { + fprintf(stderr, "libxl_domain_infolist failed.\n"); + exit(1); + } + printf("UUID ID name\n"); + for (i = 0; i < nb_vm; i++) { + printf(UUID_FMT " %d %-30s\n", + info[i].uuid[0], info[i].uuid[1], info[i].uuid[2], info[i].uuid[3], + info[i].uuid[4], info[i].uuid[5], info[i].uuid[6], info[i].uuid[7], + info[i].uuid[8], info[i].uuid[9], info[i].uuid[10], info[i].uuid[11], + info[i].uuid[12], info[i].uuid[13], info[i].uuid[14], info[i].uuid[15], + info[i].domid, libxl_domid_to_name(&ctx, info[i].domid)); + } + free(info); +} + +static void save_domain_core_begin(char *domain_spec, + const char *override_config_file, + uint8_t **config_data_r, + int *config_len_r) +{ + int rc; + + find_domain(domain_spec); + + /* configuration file in optional data: */ + + if (override_config_file) { + void *config_v = 0; + rc = libxl_read_file_contents(&ctx, override_config_file, + &config_v, config_len_r); + *config_data_r = config_v; + } else { + rc = libxl_userdata_retrieve(&ctx, domid, "xl", + config_data_r, config_len_r); + } + if (rc) { + fputs("Unable to get config file\n",stderr); + exit(2); + } +} + +void save_domain_core_writeconfig(int fd, const char *filename, + const uint8_t *config_data, int config_len) +{ + struct save_file_header hdr; + uint8_t *optdata_begin; + union { uint32_t u32; char b[4]; } u32buf; + + memset(&hdr, 0, sizeof(hdr)); + memcpy(hdr.magic, savefileheader_magic, sizeof(hdr.magic)); + hdr.byteorder = SAVEFILE_BYTEORDER_VALUE; + + optdata_begin= 0; + +#define ADD_OPTDATA(ptr, len) ({ \ + if ((len)) { \ + hdr.optional_data_len += (len); \ + optdata_begin = xrealloc(optdata_begin, hdr.optional_data_len); \ + memcpy(optdata_begin + hdr.optional_data_len - (len), \ + (ptr), (len)); \ + } \ + }) + + u32buf.u32 = config_len; + ADD_OPTDATA(u32buf.b, 4); + ADD_OPTDATA(config_data, config_len); + + /* that's the optional data */ + + CHK_ERRNO( libxl_write_exactly(&ctx, fd, + &hdr, sizeof(hdr), filename, "header") ); + CHK_ERRNO( libxl_write_exactly(&ctx, fd, + optdata_begin, hdr.optional_data_len, filename, "header") ); + + fprintf(stderr, "Saving to %s new xl format (info" + " 0x%"PRIx32"/0x%"PRIx32"/%"PRIu32")\n", + filename, hdr.mandatory_flags, hdr.optional_flags, + hdr.optional_data_len); +} + +int save_domain(char *p, char *filename, int checkpoint, + const char *override_config_file) +{ + int fd; + uint8_t *config_data; + int config_len; + + save_domain_core_begin(p, override_config_file, &config_data, &config_len); + + if (!config_len) { + fputs(" Savefile will not contain xl domain config\n", stderr); + } + + fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (fd < 0) { + fprintf(stderr, "Failed to open temp file %s for writing\n", filename); + exit(2); + } + + save_domain_core_writeconfig(fd, filename, config_data, config_len); + + CHK_ERRNO(libxl_domain_suspend(&ctx, NULL, domid, fd)); + close(fd); + + if (checkpoint) + libxl_domain_unpause(&ctx, domid); + else + libxl_domain_destroy(&ctx, domid, 0); + + exit(0); +} + +static int migrate_read_fixedmessage(int fd, const void *msg, int msgsz, + const char *what, const char *rune) { + char buf[msgsz]; + const char *stream; + int rc; + + stream = rune ? "migration receiver stream" : "migration stream"; + rc = libxl_read_exactly(&ctx, fd, buf, msgsz, stream, what); + if (rc) return ERROR_FAIL; + + if (memcmp(buf, msg, msgsz)) { + fprintf(stderr, "%s contained unexpected data instead of %s\n", + stream, what); + if (rune) + fprintf(stderr, "(command run was: %s )\n", rune); + return ERROR_FAIL; + } + return 0; +} + +static void migration_child_report(pid_t migration_child, int recv_fd) { + pid_t child; + int status, sr; + struct timeval now, waituntil, timeout; + static const struct timeval pollinterval = { 0, 1000 }; /* 1ms */ + + if (!migration_child) return; + + CHK_ERRNO( gettimeofday(&waituntil, 0) ); + waituntil.tv_sec += 2; + + for (;;) { + child = waitpid(migration_child, &status, WNOHANG); + + if (child == migration_child) { + if (status) + libxl_report_child_exitstatus(&ctx, XL_LOG_INFO, + "migration target process", + migration_child, status); + break; + } + if (child == -1) { + if (errno == EINTR) continue; + fprintf(stderr, "wait for migration child [%ld] failed: %s\n", + (long)migration_child, strerror(errno)); + break; + } + assert(child == 0); + + CHK_ERRNO( gettimeofday(&now, 0) ); + if (timercmp(&now, &waituntil, >)) { + fprintf(stderr, "migration child [%ld] not exiting, no longer" + " waiting (exit status will be unreported)\n", + (long)migration_child); + break; + } + timersub(&waituntil, &now, &timeout); + + if (recv_fd >= 0) { + fd_set readfds, exceptfds; + FD_ZERO(&readfds); + FD_ZERO(&exceptfds); + FD_SET(recv_fd, &readfds); + FD_SET(recv_fd, &exceptfds); + sr = select(recv_fd+1, &readfds,0,&exceptfds, &timeout); + } else { + if (timercmp(&timeout, &pollinterval, >)) + timeout = pollinterval; + sr = select(0,0,0,0, &timeout); + } + if (sr > 0) { + recv_fd = -1; + } else if (sr == 0) { + } else if (sr == -1) { + if (errno != EINTR) { + fprintf(stderr, "migration child [%ld] exit wait select" + " failed unexpectedly: %s\n", + (long)migration_child, strerror(errno)); + break; + } + } + } + migration_child = 0; +} + +static void migrate_domain(char *domain_spec, const char *rune, + const char *override_config_file) +{ + pid_t child = -1; + int rc; + int sendpipe[2], recvpipe[2]; + int send_fd, recv_fd; + libxl_domain_suspend_info suspinfo; + char *away_domname; + char rc_buf; + uint8_t *config_data; + int config_len; + + save_domain_core_begin(domain_spec, override_config_file, + &config_data, &config_len); + + if (!config_len) { + fprintf(stderr, "No config file stored for running domain and " + "none supplied - cannot migrate.\n"); + exit(1); + } + + MUST( libxl_pipe(&ctx, sendpipe) ); + MUST( libxl_pipe(&ctx, recvpipe) ); + + child = libxl_fork(&ctx); + if (child==-1) exit(1); + + if (!child) { + dup2(sendpipe[0], 0); + dup2(recvpipe[1], 1); + close(sendpipe[0]); close(sendpipe[1]); + close(recvpipe[0]); close(recvpipe[1]); + execlp("sh","sh","-c",rune,(char*)0); + perror("failed to exec sh"); + exit(-1); + } + + close(sendpipe[0]); + close(recvpipe[1]); + send_fd = sendpipe[1]; + recv_fd = recvpipe[0]; + + signal(SIGPIPE, SIG_IGN); + /* if receiver dies, we get an error and can clean up + rather than just dying */ + + rc = migrate_read_fixedmessage(recv_fd, migrate_receiver_banner, + sizeof(migrate_receiver_banner)-1, + "banner", rune); + if (rc) { + close(send_fd); + migration_child_report(child, recv_fd); + exit(-rc); + } + + save_domain_core_writeconfig(send_fd, "migration stream", + config_data, config_len); + + memset(&suspinfo, 0, sizeof(suspinfo)); + suspinfo.flags |= XL_SUSPEND_LIVE; + rc = libxl_domain_suspend(&ctx, &suspinfo, domid, send_fd); + if (rc) { + fprintf(stderr, "migration sender: libxl_domain_suspend failed" + " (rc=%d)\n", rc); + goto failed_resume; + } + + //fprintf(stderr, "migration sender: Transfer complete.\n"); + // Should only be printed when debugging as it's a bit messy with + // progress indication. + + rc = migrate_read_fixedmessage(recv_fd, migrate_receiver_ready, + sizeof(migrate_receiver_ready), + "ready message", rune); + if (rc) goto failed_resume; + + + + /* right, at this point we are about give the destination + * permission to rename and resume, so we must first rename the + * domain away ourselves */ + + fprintf(stderr, "migration sender: Target has acknowledged transfer.\n"); + + if (common_domname) { + if (asprintf(&away_domname, "%s--migratedaway", common_domname) < 0) + goto failed_resume; + rc = libxl_domain_rename(&ctx, domid, + common_domname, away_domname, 0); + if (rc) goto failed_resume; + } + + /* point of no return - as soon as we have tried to say + * "go" to the receiver, it's not safe to carry on. We leave + * the domain renamed to %s--migratedaway in case that's helpful. + */ + + fprintf(stderr, "migration sender: Giving target permission to start.\n"); + + rc = libxl_write_exactly(&ctx, send_fd, + migrate_permission_to_go, + sizeof(migrate_permission_to_go), + "migration stream", "GO message"); + if (rc) goto failed_badly; + + rc = migrate_read_fixedmessage(recv_fd, migrate_report, + sizeof(migrate_report), + "success/failure report message", rune); + if (rc) goto failed_badly; + + rc = libxl_read_exactly(&ctx, recv_fd, + &rc_buf, 1, + "migration ack stream", "success/failure status"); + if (rc) goto failed_badly; + + if (rc_buf) { + fprintf(stderr, "migration sender: Target reports startup failure" + " (status code %d).\n", rc_buf); + + rc = migrate_read_fixedmessage(recv_fd, migrate_permission_to_go, + sizeof(migrate_permission_to_go), + "permission for sender to resume", + rune); + if (rc) goto failed_badly; + + fprintf(stderr, "migration sender: Trying to resume at our end.\n"); + + if (common_domname) { + libxl_domain_rename(&ctx, domid, + away_domname, common_domname, 0); + } + rc = libxl_domain_resume(&ctx, domid); + if (!rc) fprintf(stderr, "migration sender: Resumed OK.\n"); + + fprintf(stderr, "Migration failed due to problems at target.\n"); + exit(-ERROR_FAIL); + } + + fprintf(stderr, "migration sender: Target reports successful startup.\n"); + libxl_domain_destroy(&ctx, domid, 1); /* bang! */ + fprintf(stderr, "Migration successful.\n"); + exit(0); + + failed_resume: + close(send_fd); + migration_child_report(child, recv_fd); + fprintf(stderr, "Migration failed, resuming at sender.\n"); + libxl_domain_resume(&ctx, domid); + exit(-ERROR_FAIL); + + failed_badly: + fprintf(stderr, + "** Migration failed during final handshake **\n" + "Domain state is now undefined !\n" + "Please CHECK AT BOTH ENDS for running instances, before renaming and\n" + " resuming at most one instance. Two simultaneous instances of the domain\n" + " would probably result in SEVERE DATA LOSS and it is now your\n" + " responsibility to avoid that. Sorry.\n"); + + close(send_fd); + migration_child_report(child, recv_fd); + exit(-ERROR_BADFAIL); +} + +static void migrate_receive(int debug, int daemonize) +{ + int rc, rc2; + char rc_buf; + char *migration_domname; + struct domain_create dom_info; + + signal(SIGPIPE, SIG_IGN); + /* if we get SIGPIPE we'd rather just have it as an error */ + + fprintf(stderr, "migration target: Ready to receive domain.\n"); + + CHK_ERRNO( libxl_write_exactly(&ctx, 1, + migrate_receiver_banner, + sizeof(migrate_receiver_banner)-1, + "migration ack stream", + "banner") ); + + memset(&dom_info, 0, sizeof(dom_info)); + dom_info.debug = debug; + dom_info.daemonize = daemonize; + dom_info.paused = 1; + dom_info.restore_file = "incoming migration stream"; + dom_info.migration_domname_r = &migration_domname; + + rc = create_domain(&dom_info); + if (rc < 0) { + fprintf(stderr, "migration target: Domain creation failed" + " (code %d).\n", rc); + exit(-rc); + } + + fprintf(stderr, "migration target: Transfer complete," + " requesting permission to start domain.\n"); + + rc = libxl_write_exactly(&ctx, 1, + migrate_receiver_ready, + sizeof(migrate_receiver_ready), + "migration ack stream", "ready message"); + if (rc) exit(-rc); + + rc = migrate_read_fixedmessage(0, migrate_permission_to_go, + sizeof(migrate_permission_to_go), + "GO message", 0); + if (rc) goto perhaps_destroy_notify_rc; + + fprintf(stderr, "migration target: Got permission, starting domain.\n"); + + if (migration_domname) { + rc = libxl_domain_rename(&ctx, domid, + migration_domname, common_domname, 0); + if (rc) goto perhaps_destroy_notify_rc; + } + + rc = libxl_domain_unpause(&ctx, domid); + if (rc) goto perhaps_destroy_notify_rc; + + fprintf(stderr, "migration target: Domain started successsfully.\n"); + rc = 0; + + perhaps_destroy_notify_rc: + rc2 = libxl_write_exactly(&ctx, 1, + migrate_report, sizeof(migrate_report), + "migration ack stream", + "success/failure report"); + if (rc2) exit(-ERROR_BADFAIL); + + rc_buf = -rc; + assert(!!rc_buf == !!rc); + rc2 = libxl_write_exactly(&ctx, 1, &rc_buf, 1, + "migration ack stream", + "success/failure code"); + if (rc2) exit(-ERROR_BADFAIL); + + if (rc) { + fprintf(stderr, "migration target: Failure, destroying our copy.\n"); + + rc2 = libxl_domain_destroy(&ctx, domid, 1); + if (rc2) { + fprintf(stderr, "migration target: Failed to destroy our copy" + " (code %d).\n", rc2); + exit(-ERROR_BADFAIL); + } + + fprintf(stderr, "migration target: Cleanup OK, granting sender" + " permission to resume.\n"); + + rc2 = libxl_write_exactly(&ctx, 1, + migrate_permission_to_go, + sizeof(migrate_permission_to_go), + "migration ack stream", + "permission to sender to have domain back"); + if (rc2) exit(-ERROR_BADFAIL); + } + + exit(0); +} + +int main_restore(int argc, char **argv) +{ + char *checkpoint_file = NULL; + char *config_file = NULL; + struct domain_create dom_info; + int paused = 0, debug = 0, daemonize = 1; + int opt, rc; + + while ((opt = getopt(argc, argv, "hpde")) != -1) { + switch (opt) { + case 'p': + paused = 1; + break; + case 'd': + debug = 1; + break; + case 'e': + daemonize = 0; + break; + case 'h': + help("restore"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + + if (argc-optind == 1) { + checkpoint_file = argv[optind]; + } else if (argc-optind == 2) { + config_file = argv[optind]; + checkpoint_file = argv[optind + 1]; + } else { + help("restore"); + exit(2); + } + + memset(&dom_info, 0, sizeof(dom_info)); + dom_info.debug = debug; + dom_info.daemonize = daemonize; + dom_info.paused = paused; + dom_info.config_file = config_file; + dom_info.restore_file = checkpoint_file; + dom_info.migrate_fd = -1; + + rc = create_domain(&dom_info); + if (rc < 0) + exit(-rc); + + exit(0); +} + +int main_migrate_receive(int argc, char **argv) +{ + int debug = 0, daemonize = 1; + int opt; + + while ((opt = getopt(argc, argv, "hed")) != -1) { + switch (opt) { + case 'h': + help("migrate-receive"); + exit(2); + break; + case 'e': + daemonize = 0; + break; + case 'd': + debug = 1; + break; + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + + if (argc-optind != 0) { + help("migrate-receive"); + exit(2); + } + migrate_receive(debug, daemonize); + exit(0); +} + +int main_save(int argc, char **argv) +{ + char *filename = NULL, *p = NULL; + const char *config_filename; + int checkpoint = 0; + int opt; + + while ((opt = getopt(argc, argv, "hc")) != -1) { + switch (opt) { + case 'c': + checkpoint = 1; + break; + case 'h': + help("save"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + + if (argc-optind < 1 || argc-optind > 3) { + help("save"); + exit(2); + } + + p = argv[optind]; + filename = argv[optind + 1]; + config_filename = argv[optind + 2]; + save_domain(p, filename, checkpoint, config_filename); + exit(0); +} + +int main_migrate(int argc, char **argv) +{ + char *p = NULL; + const char *config_filename = NULL; + const char *ssh_command = "ssh"; + char *rune = NULL; + char *host; + int opt, daemonize = 1, debug = 0; + + while ((opt = getopt(argc, argv, "hC:s:ed")) != -1) { + switch (opt) { + case 'h': + help("migrate"); + exit(0); + case 'C': + config_filename = optarg; + break; + case 's': + ssh_command = optarg; + break; + case 'e': + daemonize = 0; + break; + case 'd': + debug = 1; + break; + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + + if (argc-optind < 2 || argc-optind > 2) { + help("migrate"); + exit(2); + } + + p = argv[optind]; + host = argv[optind + 1]; + + if (!ssh_command[0]) { + rune= host; + } else { + if (asprintf(&rune, "exec %s %s xl migrate-receive%s%s", + ssh_command, host, + daemonize ? "" : " -e", + debug ? " -d" : "") < 0) + exit(1); + } + + migrate_domain(p, rune, config_filename); + exit(0); +} + +int main_pause(int argc, char **argv) +{ + int opt; + char *p; + + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("pause"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + if (optind >= argc) { + help("pause"); + exit(2); + } + + p = argv[optind]; + + pause_domain(p); + exit(0); +} + +int main_unpause(int argc, char **argv) +{ + int opt; + char *p; + + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("unpause"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + if (optind >= argc) { + help("unpause"); + exit(2); + } + + p = argv[optind]; + + unpause_domain(p); + exit(0); +} + +int main_destroy(int argc, char **argv) +{ + int opt; + char *p; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("destroy"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + if (optind >= argc) { + help("destroy"); + exit(2); + } + + p = argv[optind]; + + destroy_domain(p); + exit(0); +} + +int main_shutdown(int argc, char **argv) +{ + int opt; + char *p; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("shutdown"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + if (optind >= argc) { + help("shutdown"); + exit(2); + } + + p = argv[optind]; + + shutdown_domain(p); + exit(0); +} + +int main_reboot(int argc, char **argv) +{ + int opt; + char *p; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("reboot"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + if (optind >= argc) { + help("reboot"); + exit(2); + } + + p = argv[optind]; + + reboot_domain(p); + exit(0); +} +int main_list(int argc, char **argv) +{ + int opt, verbose = 0; + int details = 0; + int option_index = 0; + static struct option long_options[] = { + {"long", 0, 0, 'l'}, + {"help", 0, 0, 'h'}, + {"verbose", 0, 0, 'v'}, + {0, 0, 0, 0} + }; + + while (1) { + opt = getopt_long(argc, argv, "lvh", long_options, &option_index); + if (opt == -1) + break; + + switch (opt) { + case 'l': + details = 1; + break; + case 'h': + help("list"); + exit(0); + case 'v': + verbose = 1; + break; + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + + if (details) + list_domains_details(); + else + list_domains(verbose); + exit(0); +} + +int main_list_vm(int argc, char **argv) +{ + int opt; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("list-vm"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + + list_vm(); + exit(0); +} + +int main_create(int argc, char **argv) +{ + char *filename = NULL; + char *p, extra_config[1024]; + struct domain_create dom_info; + char dom[10]; /* long enough */ + int paused = 0, debug = 0, daemonize = 1, console_autoconnect = 0, + dryrun = 0, quite = 0; + int opt, rc; + int option_index = 0; + static struct option long_options[] = { + {"dryrun", 0, 0, 'n'}, + {"quiet", 0, 0, 'q'}, + {"help", 0, 0, 'h'}, + {"defconfig", 1, 0, 'f'}, + {0, 0, 0, 0} + }; + + while (1) { + opt = getopt_long(argc, argv, "hnqf:pcde", long_options, &option_index); + if (opt == -1) + break; + + switch (opt) { + case 'f': + filename = optarg; + break; + case 'p': + paused = 1; + break; + case 'c': + console_autoconnect = 1; + break; + case 'd': + debug = 1; + break; + case 'e': + daemonize = 0; + break; + case 'h': + help("create"); + exit(0); + case 'n': + dryrun = 1; + break; + case 'q': + quite = 1; + break; + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + + memset(extra_config, 0, sizeof(extra_config)); + while (optind < argc) { + if ((p = strchr(argv[optind], '='))) { + if (strlen(extra_config) + 1 < sizeof(extra_config)) { + if (strlen(extra_config)) + strcat(extra_config, "\n"); + strcat(extra_config, argv[optind]); + } + } else if (!filename) { + filename = argv[optind]; + } else { + help("create"); + exit(2); + } + optind++; + } + + memset(&dom_info, 0, sizeof(dom_info)); + dom_info.debug = debug; + dom_info.daemonize = daemonize; + dom_info.paused = paused; + dom_info.dryrun = dryrun; + dom_info.quiet = quite; + dom_info.config_file = filename; + dom_info.extra_config = extra_config; + dom_info.migrate_fd = -1; + + rc = create_domain(&dom_info); + if (rc < 0) + exit(-rc); + + if (console_autoconnect) { + snprintf(dom, sizeof(dom), "%d", rc); + console(dom, 0); + } + + exit(0); +} + +void button_press(char *p, char *b) +{ + libxl_button button; + + find_domain(p); + + if (!strcmp(b, "power")) { + button = POWER_BUTTON; + } else if (!strcmp(b, "sleep")) { + button = SLEEP_BUTTON; + } else { + fprintf(stderr, "%s is an invalid button identifier\n", b); + exit(2); + } + + libxl_button_press(&ctx, domid, button); +} + +int main_button_press(int argc, char **argv) +{ + int opt; + char *p; + char *b; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("button-press"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + if (optind >= argc - 1) { + help("button-press"); + exit(2); + } + + p = argv[optind]; + b = argv[optind + 1]; + + button_press(p, b); + exit(0); +} + +static void print_vcpuinfo(uint32_t tdomid, + const struct libxl_vcpuinfo *vcpuinfo, + uint32_t nr_cpus) +{ + int i, l; + uint64_t *cpumap; + uint64_t pcpumap; + + /* NAME ID VCPU */ + printf("%-32s %5u %5u", + libxl_domid_to_name(&ctx, tdomid), tdomid, vcpuinfo->vcpuid); + if (!vcpuinfo->online) { + /* CPU STA */ + printf("%5c %3c%cp ", '-', '-', '-'); + } else { + /* CPU STA */ + printf("%5u %3c%c- ", vcpuinfo->cpu, + vcpuinfo->running ? 'r' : '-', + vcpuinfo->blocked ? 'b' : '-'); + } + /* TIM */ + printf("%9.1f ", ((float)vcpuinfo->vcpu_time / 1e9)); + /* CPU AFFINITY */ + pcpumap = nr_cpus > 64 ? -1 : ((1 << nr_cpus) - 1); + for (cpumap = vcpuinfo->cpumap; nr_cpus; ++cpumap) { + if (*cpumap < pcpumap) { + break; + } + if (nr_cpus > 64) { + pcpumap = -1; + nr_cpus -= 64; + } else { + pcpumap = ((1 << nr_cpus) - 1); + nr_cpus = 0; + } + } + if (!nr_cpus) { + printf("any cpu\n"); + } else { + for (cpumap = vcpuinfo->cpumap; nr_cpus; ++cpumap) { + pcpumap = *cpumap; + for (i = 0; !(pcpumap & 1); ++i, pcpumap >>= 1) + ; + printf("%u", i); + for (l = i, pcpumap = (pcpumap >> 1); (pcpumap & 1); ++i, pcpumap >>= 1) + ; + if (l < i) { + printf("-%u", i); + } + for (++i; pcpumap; ++i, pcpumap >>= 1) { + if (pcpumap & 1) { + printf(",%u", i); + for (l = i, pcpumap = (pcpumap >> 1); (pcpumap & 1); ++i, pcpumap >>= 1) + ; + if (l < i) { + printf("-%u", i); + } + ++i; + } + } + printf("\n"); + nr_cpus = nr_cpus > 64 ? nr_cpus - 64 : 0; + } + } +} + +void vcpulist(int argc, char **argv) +{ + struct libxl_dominfo *dominfo; + struct libxl_vcpuinfo *vcpuinfo; + struct libxl_physinfo physinfo; + int nb_vcpu, nb_domain, cpusize; + + if (libxl_get_physinfo(&ctx, &physinfo) != 0) { + fprintf(stderr, "libxl_physinfo failed.\n"); + goto vcpulist_out; + } + printf("%-32s %5s %5s %5s %5s %9s %s\n", + "Name", "ID", "VCPU", "CPU", "State", "Time(s)", "CPU Affinity"); + if (!argc) { + if (!(dominfo = libxl_list_domain(&ctx, &nb_domain))) { + fprintf(stderr, "libxl_list_domain failed.\n"); + goto vcpulist_out; + } + for (; nb_domain > 0; --nb_domain, ++dominfo) { + if (!(vcpuinfo = libxl_list_vcpu(&ctx, dominfo->domid, &nb_vcpu, &cpusize))) { + fprintf(stderr, "libxl_list_vcpu failed.\n"); + goto vcpulist_out; + } + for (; nb_vcpu > 0; --nb_vcpu, ++vcpuinfo) { + print_vcpuinfo(dominfo->domid, vcpuinfo, physinfo.nr_cpus); + } + } + } else { + for (; argc > 0; ++argv, --argc) { + if (domain_qualifier_to_domid(*argv, &domid, 0) < 0) { + fprintf(stderr, "%s is an invalid domain identifier\n", *argv); + } + if (!(vcpuinfo = libxl_list_vcpu(&ctx, domid, &nb_vcpu, &cpusize))) { + fprintf(stderr, "libxl_list_vcpu failed.\n"); + goto vcpulist_out; + } + for (; nb_vcpu > 0; --nb_vcpu, ++vcpuinfo) { + print_vcpuinfo(domid, vcpuinfo, physinfo.nr_cpus); + } + } + } + vcpulist_out: + ; +} + +int main_vcpulist(int argc, char **argv) +{ + int opt; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("vcpu-list"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + vcpulist(argc - 2, argv + 2); + exit(0); +} + +void vcpupin(char *d, const char *vcpu, char *cpu) +{ + struct libxl_vcpuinfo *vcpuinfo; + struct libxl_physinfo physinfo; + uint64_t *cpumap = NULL; + + uint32_t vcpuid, cpuida, cpuidb; + char *endptr, *toka, *tokb; + int i, nb_vcpu, cpusize; + + vcpuid = strtoul(vcpu, &endptr, 10); + if (vcpu == endptr) { + if (strcmp(vcpu, "all")) { + fprintf(stderr, "Error: Invalid argument.\n"); + return; + } + vcpuid = -1; + } + + find_domain(d); + + if (libxl_get_physinfo(&ctx, &physinfo) != 0) { + fprintf(stderr, "libxl_get_physinfo failed.\n"); + goto vcpupin_out1; + } + + cpumap = calloc(physinfo.max_cpu_id + 1, sizeof (uint64_t)); + if (!cpumap) { + goto vcpupin_out1; + } + if (strcmp(cpu, "all")) { + for (toka = strtok(cpu, ","), i = 0; toka; toka = strtok(NULL, ","), ++i) { + cpuida = strtoul(toka, &endptr, 10); + if (toka == endptr) { + fprintf(stderr, "Error: Invalid argument.\n"); + goto vcpupin_out; + } + if (*endptr == '-') { + tokb = endptr + 1; + cpuidb = strtoul(tokb, &endptr, 10); + if ((tokb == endptr) || (cpuida > cpuidb)) { + fprintf(stderr, "Error: Invalid argument.\n"); + goto vcpupin_out; + } + while (cpuida <= cpuidb) { + cpumap[cpuida / 64] |= (1 << (cpuida % 64)); + ++cpuida; + } + } else { + cpumap[cpuida / 64] |= (1 << (cpuida % 64)); + } + } + } + else { + memset(cpumap, -1, sizeof (uint64_t) * (physinfo.max_cpu_id + 1)); + } + + if (vcpuid != -1) { + if (libxl_set_vcpuaffinity(&ctx, domid, vcpuid, + cpumap, physinfo.max_cpu_id + 1) == -1) { + fprintf(stderr, "Could not set affinity for vcpu `%u'.\n", vcpuid); + } + } + else { + if (!(vcpuinfo = libxl_list_vcpu(&ctx, domid, &nb_vcpu, &cpusize))) { + fprintf(stderr, "libxl_list_vcpu failed.\n"); + goto vcpupin_out; + } + for (; nb_vcpu > 0; --nb_vcpu, ++vcpuinfo) { + if (libxl_set_vcpuaffinity(&ctx, domid, vcpuinfo->vcpuid, + cpumap, physinfo.max_cpu_id + 1) == -1) { + fprintf(stderr, "libxl_list_vcpu failed on vcpu `%u'.\n", vcpuinfo->vcpuid); + } + } + } + vcpupin_out1: + free(cpumap); + vcpupin_out: + ; +} + +int main_vcpupin(int argc, char **argv) +{ + int opt; + + if (argc != 5) { + help("vcpu-pin"); + exit(0); + } + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("vcpu-pin"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + vcpupin(argv[2], argv[3] , argv[4]); + exit(0); +} + +void vcpuset(char *d, char* nr_vcpus) +{ + char *endptr; + unsigned int max_vcpus; + + max_vcpus = strtoul(nr_vcpus, &endptr, 10); + if (nr_vcpus == endptr) { + fprintf(stderr, "Error: Invalid argument.\n"); + return; + } + + find_domain(d); + + if (libxl_set_vcpucount(&ctx, domid, max_vcpus) == ERROR_INVAL) { + fprintf(stderr, "Error: Cannot set vcpus greater than max vcpus on running domain or lesser than 1.\n"); + } +} + +int main_vcpuset(int argc, char **argv) +{ + int opt; + + if (argc != 4) { + help("vcpu-set"); + exit(0); + } + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("vcpu-set"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + vcpuset(argv[2], argv[3]); + exit(0); +} + +static void output_xeninfo(void) +{ + const libxl_version_info *info; + int sched_id; + + if (!(info = libxl_get_version_info(&ctx))) { + fprintf(stderr, "libxl_get_version_info failed.\n"); + return; + } + + if ((sched_id = libxl_get_sched_id(&ctx)) < 0) { + fprintf(stderr, "get_sched_id sysctl failed.\n"); + return; + } + + printf("xen_major : %d\n", info->xen_version_major); + printf("xen_minor : %d\n", info->xen_version_minor); + printf("xen_extra : %s\n", info->xen_version_extra); + printf("xen_caps : %s\n", info->capabilities); + printf("xen_scheduler : %s\n", + sched_id == XEN_SCHEDULER_SEDF ? "sedf" : "credit"); + printf("xen_pagesize : %lu\n", info->pagesize); + printf("platform_params : virt_start=0x%lx\n", info->virt_start); + printf("xen_changeset : %s\n", info->changeset); + printf("xen_commandline : %s\n", info->commandline); + printf("cc_compiler : %s\n", info->compiler); + printf("cc_compile_by : %s\n", info->compile_by); + printf("cc_compile_domain : %s\n", info->compile_domain); + printf("cc_compile_date : %s\n", info->compile_date); + + return; +} + +static void output_nodeinfo(void) +{ + struct utsname utsbuf; + + if (uname(&utsbuf) < 0) + return; + + printf("host : %s\n", utsbuf.nodename); + printf("release : %s\n", utsbuf.release); + printf("version : %s\n", utsbuf.version); + printf("machine : %s\n", utsbuf.machine); +} + +static void output_physinfo(void) +{ + struct libxl_physinfo info; + const libxl_version_info *vinfo; + unsigned int i; + + if (libxl_get_physinfo(&ctx, &info) != 0) { + fprintf(stderr, "libxl_physinfo failed.\n"); + return; + } + + printf("nr_cpus : %d\n", info.nr_cpus); + printf("cores_per_socket : %d\n", info.cores_per_socket); + printf("threads_per_core : %d\n", info.threads_per_core); + printf("cpu_mhz : %d\n", info.cpu_khz / 1000); + printf("hw_caps : "); + for (i = 0; i < 8; i++) + printf("%08x%c", info.hw_cap[i], i < 7 ? ':' : '\n'); + printf("virt_caps :"); + if (info.phys_cap & XEN_SYSCTL_PHYSCAP_hvm) + printf(" hvm"); + if (info.phys_cap & XEN_SYSCTL_PHYSCAP_hvm_directio) + printf(" hvm_directio"); + printf("\n"); + vinfo = libxl_get_version_info(&ctx); + if (vinfo) { + i = (1 << 20) / vinfo->pagesize; + printf("total_memory : %"PRIu64"\n", info.total_pages / i); + printf("free_memory : %"PRIu64"\n", info.free_pages / i); + } + + return; +} + +static void info(void) +{ + output_nodeinfo(); + + output_physinfo(); + + output_xeninfo(); + + printf("xend_config_format : 4\n"); + + return; +} + +int main_info(int argc, char **argv) +{ + int opt; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("info"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + info(); + exit(0); +} + +static int sched_credit_domain_get( + int domid, struct libxl_sched_credit *scinfo) +{ + int rc; + + rc = libxl_sched_credit_domain_get(&ctx, domid, scinfo); + if (rc) + fprintf(stderr, "libxl_sched_credit_domain_get failed.\n"); + + return rc; +} + +static int sched_credit_domain_set( + int domid, struct libxl_sched_credit *scinfo) +{ + int rc; + + rc = libxl_sched_credit_domain_set(&ctx, domid, scinfo); + if (rc) + fprintf(stderr, "libxl_sched_credit_domain_set failed.\n"); + + return rc; +} + +static void sched_credit_domain_output( + int domid, struct libxl_sched_credit *scinfo) +{ + printf("%-33s %4d %6d %4d\n", + libxl_domid_to_name(&ctx, domid), + domid, + scinfo->weight, + scinfo->cap); +} + +int main_sched_credit(int argc, char **argv) +{ + struct libxl_dominfo *info; + struct libxl_sched_credit scinfo; + int nb_domain, i; + char *dom = NULL; + int weight = 256, cap = 0, opt_w = 0, opt_c = 0; + int opt, rc; + + while ((opt = getopt(argc, argv, "hd:w:c:")) != -1) { + switch (opt) { + case 'd': + dom = optarg; + break; + case 'w': + weight = strtol(optarg, NULL, 10); + opt_w = 1; + break; + case 'c': + cap = strtol(optarg, NULL, 10); + opt_c = 1; + break; + case 'h': + help("sched-credit"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + if (!dom && (opt_w || opt_c)) { + fprintf(stderr, "Must specify a domain.\n"); + exit(1); + } + + if (!dom) { /* list all domain's credit scheduler info */ + info = libxl_list_domain(&ctx, &nb_domain); + if (!info) { + fprintf(stderr, "libxl_domain_infolist failed.\n"); + exit(1); + } + + printf("%-33s %4s %6s %4s\n", "Name", "ID", "Weight", "Cap"); + for (i = 0; i < nb_domain; i++) { + rc = sched_credit_domain_get(info[i].domid, &scinfo); + if (rc) + exit(-rc); + sched_credit_domain_output(info[i].domid, &scinfo); + } + } else { + find_domain(dom); + + rc = sched_credit_domain_get(domid, &scinfo); + if (rc) + exit(-rc); + + if (!opt_w && !opt_c) { /* output credit scheduler info */ + printf("%-33s %4s %6s %4s\n", "Name", "ID", "Weight", "Cap"); + sched_credit_domain_output(domid, &scinfo); + } else { /* set credit scheduler paramaters */ + if (opt_w) + scinfo.weight = weight; + if (opt_c) + scinfo.cap = cap; + rc = sched_credit_domain_set(domid, &scinfo); + if (rc) + exit(-rc); + } + } + + exit(0); +} + +int main_domid(int argc, char **argv) +{ + int opt; + char *domname = NULL; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("domid"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + domname = argv[optind]; + if (!domname) { + fprintf(stderr, "Must specify a domain name.\n\n"); + help("domid"); + exit(1); + } + + if (libxl_name_to_domid(&ctx, domname, &domid)) { + fprintf(stderr, "Can't get domid of domain name '%s', maybe this domain does not exist.\n", domname); + exit(1); + } + + printf("%d\n", domid); + + exit(0); +} + +int main_domname(int argc, char **argv) +{ + int opt; + char *domname = NULL; + char *endptr = NULL; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("domname"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + if (!argv[optind]) { + fprintf(stderr, "Must specify a domain id.\n\n"); + help("domname"); + exit(1); + } + domid = strtol(argv[optind], &endptr, 10); + if (domid == 0 && !strcmp(endptr, argv[optind])) { + /*no digits at all*/ + fprintf(stderr, "Invalid domain id.\n\n"); + exit(1); + } + + domname = libxl_domid_to_name(&ctx, domid); + if (!domname) { + fprintf(stderr, "Can't get domain name of domain id '%d', maybe this domain does not exist.\n", domid); + exit(1); + } + + printf("%s\n", domname); + + exit(0); +} + +int main_rename(int argc, char **argv) +{ + int opt; + char *dom; + char *new_name; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("rename"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + dom = argv[optind++]; + if (!dom || !argv[optind]) { + fprintf(stderr, "'xl rename' requires 2 arguments.\n\n"); + help("rename"); + exit(1); + } + + find_domain(dom); + new_name = argv[optind]; + + if (libxl_domain_rename(&ctx, domid, common_domname, new_name, 0)) { + fprintf(stderr, "Can't rename domain '%s'.\n", dom); + exit(1); + } + + exit(0); +} + +int main_trigger(int argc, char **argv) +{ + int opt; + char *trigger_name = NULL; + char *endptr = NULL; + char *dom = NULL; + int vcpuid = 0; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("trigger"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + dom = argv[optind++]; + if (!dom || !argv[optind]) { + fprintf(stderr, "'xl trigger' requires between 2 and 3 arguments.\n\n"); + help("trigger"); + exit(1); + } + + find_domain(dom); + + trigger_name = argv[optind++]; + + if (argv[optind]) { + vcpuid = strtol(argv[optind], &endptr, 10); + if (vcpuid == 0 && !strcmp(endptr, argv[optind])) { + fprintf(stderr, "Invalid vcpuid, using default vcpuid=0.\n\n"); + } + } + + libxl_send_trigger(&ctx, domid, trigger_name, vcpuid); + + exit(0); +} + + +int main_sysrq(int argc, char **argv) +{ + int opt; + char *sysrq = NULL; + char *dom = NULL; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("sysrq"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + dom = argv[optind++]; + if (!dom || !argv[optind]) { + fprintf(stderr, "'xl sysrq' requires 2 arguments.\n\n"); + help("sysrq"); + exit(1); + } + + find_domain(dom); + + sysrq = argv[optind]; + + if (sysrq[1] != '\0') { + fprintf(stderr, "Invalid sysrq.\n\n"); + help("sysrq"); + exit(1); + } + + libxl_send_sysrq(&ctx, domid, sysrq[0]); + + exit(0); +} + +int main_debug_keys(int argc, char **argv) +{ + int opt; + char *keys; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("debug-keys"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + if (optind >= argc) { + help("debug-keys"); + exit(2); + } + + keys = argv[optind]; + + if (libxl_send_debug_keys(&ctx, keys)) { + fprintf(stderr, "cannot send debug keys: %s\n", keys); + exit(1); + } + + exit(0); +} + +int main_dmesg(int argc, char **argv) +{ + unsigned int clear = 0; + struct libxl_xen_console_reader *cr; + char *line; + int opt, ret = 1; + + while ((opt = getopt(argc, argv, "hc")) != -1) { + switch (opt) { + case 'c': + clear = 1; + break; + case 'h': + help("dmesg"); + exit(0); + default: + fprintf(stderr, "option not supported\n"); + break; + } + } + + cr = libxl_xen_console_read_start(&ctx, clear); + if (!cr) + goto finish; + + while ((ret = libxl_xen_console_read_line(&ctx, cr, &line)) > 0) + printf("%s", line); + +finish: + libxl_xen_console_read_finish(&ctx, cr); + exit(ret); +} + +int main_top(int argc, char **argv) +{ + int opt; + + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("top"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + exit(system("xentop")); +} + +int main_networkattach(int argc, char **argv) +{ + int opt; + libxl_device_nic nic; + char *endptr, *tok; + int i; + unsigned int val; + + if ((argc < 3) || (argc > 11)) { + help("network-attach"); + exit(0); + } + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("network-attach"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + if (domain_qualifier_to_domid(argv[2], &domid, 0) < 0) { + fprintf(stderr, "%s is an invalid domain identifier\n", argv[2]); + exit(1); + } + init_nic_info(&nic, -1); + for (argv += 3, argc -= 3; argc > 0; ++argv, --argc) { + if (!strncmp("type=", *argv, 5)) { + if (!strncmp("vif", (*argv) + 5, 4)) { + nic.nictype = NICTYPE_VIF; + } else if (!strncmp("ioemu", (*argv) + 5, 5)) { + nic.nictype = NICTYPE_IOEMU; + } else { + fprintf(stderr, "Invalid parameter `type'.\n"); + exit(1); + } + } else if (!strncmp("mac=", *argv, 4)) { + tok = strtok((*argv) + 4, ":"); + for (i = 0; tok && i < 6; tok = strtok(NULL, ":"), ++i) { + val = strtoul(tok, &endptr, 16); + if ((tok == endptr) || (val > 255)) { + fprintf(stderr, "Invalid parameter `mac'.\n"); + exit(1); + } + nic.mac[i] = val; + } + } else if (!strncmp("bridge=", *argv, 7)) { + nic.bridge = (*argv) + 7; + } else if (!strncmp("ip=", *argv, 3)) { + if (!inet_aton((*argv) + 3, &(nic.ip))) { + fprintf(stderr, "Invalid parameter `ip'.\n"); + exit(1); + } + } else if (!strncmp("script=", *argv, 6)) { + nic.script = (*argv) + 6; + } else if (!strncmp("backend=", *argv, 8)) { + val = strtoul((*argv) + 8, &endptr, 10); + if (((*argv) + 8) == endptr) { + fprintf(stderr, "Invalid parameter `backend'.\n"); + exit(1); + } + nic.backend_domid = val; + } else if (!strncmp("vifname=", *argv, 8)) { + nic.ifname = (*argv) + 8; + } else if (!strncmp("model=", *argv, 6)) { + nic.model = (*argv) + 6; + } else if (!strncmp("rate=", *argv, 5)) { + } else if (!strncmp("accel=", *argv, 6)) { + } else { + fprintf(stderr, "unrecognized argument `%s'\n", *argv); + exit(1); + } + } + nic.domid = domid; + if (libxl_device_nic_add(&ctx, domid, &nic)) { + fprintf(stderr, "libxl_device_nic_add failed.\n"); + exit(1); + } + exit(0); +} + +int main_networklist(int argc, char **argv) +{ + int opt; + libxl_nicinfo *nics; + unsigned int nb; + + if (argc < 3) { + help("network-list"); + exit(1); + } + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("network-list"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + /* Idx BE MAC Hdl Sta evch txr/rxr BE-path */ + printf("%-3s %-2s %-17s %-6s %-5s %-6s %5s/%-5s %-30s\n", + "Idx", "BE", "Mac Addr.", "handle", "state", "evt-ch", "tx-", "rx-ring-ref", "BE-path"); + for (argv += 2, argc -= 2; argc > 0; --argc, ++argv) { + if (domain_qualifier_to_domid(*argv, &domid, 0) < 0) { + fprintf(stderr, "%s is an invalid domain identifier\n", *argv); + continue; + } + if (!(nics = libxl_list_nics(&ctx, domid, &nb))) { + continue; + } + for (; nb > 0; --nb, ++nics) { + /* Idx BE */ + printf("%-3d %-2d ", nics->devid, nics->backend_id); + /* MAC */ + printf("%02x:%02x:%02x:%02x:%02x:%02x ", + nics->mac[0], nics->mac[1], nics->mac[2], + nics->mac[3], nics->mac[4], nics->mac[5]); + /* Hdl Sta evch txr/rxr BE-path */ + printf("%6d %5d %6d %5d/%-11d %-30s\n", + nics->devid, nics->state, nics->evtch, + nics->rref_tx, nics->rref_rx, nics->backend); + } + } + exit(0); +} + +int main_networkdetach(int argc, char **argv) +{ + int opt; + libxl_device_nic nic; + + if (argc != 4) { + help("network-detach"); + exit(0); + } + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("network-detach"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + if (domain_qualifier_to_domid(argv[2], &domid, 0) < 0) { + fprintf(stderr, "%s is an invalid domain identifier\n", argv[2]); + exit(1); + } + + if (!strchr(argv[3], ':')) { + if (libxl_devid_to_device_nic(&ctx, domid, argv[3], &nic)) { + fprintf(stderr, "Unknown device %s.\n", argv[3]); + exit(1); + } + } else { + if (libxl_mac_to_device_nic(&ctx, domid, argv[3], &nic)) { + fprintf(stderr, "Unknown device %s.\n", argv[3]); + exit(1); + } + } + if (libxl_device_nic_del(&ctx, &nic, 1)) { + fprintf(stderr, "libxl_device_nic_del failed.\n"); + exit(1); + } + exit(0); +} + +int main_blockattach(int argc, char **argv) +{ + int opt; + char *tok; + uint32_t fe_domid, be_domid = 0; + libxl_device_disk disk = { 0 }; + + if ((argc < 5) || (argc > 7)) { + help("block-attach"); + exit(0); + } + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("block-attach"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + tok = strtok(argv[3], ":"); + if (!strcmp(tok, "phy")) { + disk.phystype = PHYSTYPE_PHY; + } else if (!strcmp(tok, "file")) { + disk.phystype = PHYSTYPE_FILE; + } else if (!strcmp(tok, "tap")) { + tok = strtok(NULL, ":"); + if (!strcmp(tok, "aio")) { + disk.phystype = PHYSTYPE_AIO; + } else if (!strcmp(tok, "vhd")) { + disk.phystype = PHYSTYPE_VHD; + } else if (!strcmp(tok, "qcow")) { + disk.phystype = PHYSTYPE_QCOW; + } else if (!strcmp(tok, "qcow2")) { + disk.phystype = PHYSTYPE_QCOW2; + } else { + fprintf(stderr, "Error: `%s' is not a valid disk image.\n", tok); + exit(1); + } + } else { + fprintf(stderr, "Error: `%s' is not a valid block device.\n", tok); + exit(1); + } + disk.physpath = strtok(NULL, "\0"); + if (!disk.physpath) { + fprintf(stderr, "Error: missing path to disk image.\n"); + exit(1); + } + disk.virtpath = argv[4]; + disk.unpluggable = 1; + disk.readwrite = ((argc <= 4) || (argv[5][0] == 'w')); + + if (domain_qualifier_to_domid(argv[2], &fe_domid, 0) < 0) { + fprintf(stderr, "%s is an invalid domain identifier\n", argv[2]); + exit(1); + } + if (argc == 7) { + if (domain_qualifier_to_domid(argv[6], &be_domid, 0) < 0) { + fprintf(stderr, "%s is an invalid domain identifier\n", argv[6]); + exit(1); + } + } + disk.domid = fe_domid; + disk.backend_domid = be_domid; + if (libxl_device_disk_add(&ctx, fe_domid, &disk)) { + fprintf(stderr, "libxl_device_disk_add failed.\n"); + } + exit(0); +} + +int main_blocklist(int argc, char **argv) +{ + int opt; + int nb; + libxl_device_disk *disks; + libxl_diskinfo diskinfo; + + if (argc < 3) { + help("block-list"); + exit(0); + } + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("block-list"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + printf("%-5s %-3s %-6s %-5s %-6s %-8s %-30s\n", + "Vdev", "BE", "handle", "state", "evt-ch", "ring-ref", "BE-path"); + for (argv += 2, argc -= 2; argc > 0; --argc, ++argv) { + if (domain_qualifier_to_domid(*argv, &domid, 0) < 0) { + fprintf(stderr, "%s is an invalid domain identifier\n", *argv); + continue; + } + disks = libxl_device_disk_list(&ctx, domid, &nb); + if (!disks) { + continue; + } + for (; nb > 0; --nb, ++disks) { + if (!libxl_device_disk_getinfo(&ctx, domid, disks, &diskinfo)) { + /* Vdev BE hdl st evch rref BE-path*/ + printf("%-5d %-3d %-6d %-5d %-6d %-8d %-30s\n", + diskinfo.devid, diskinfo.backend_id, diskinfo.frontend_id, + diskinfo.state, diskinfo.evtch, diskinfo.rref, diskinfo.backend); + } + } + } + exit(0); +} + +int main_blockdetach(int argc, char **argv) +{ + int opt; + libxl_device_disk disk; + + if (argc != 4) { + help("block-detach"); + exit(0); + } + while ((opt = getopt(argc, argv, "h")) != -1) { + switch (opt) { + case 'h': + help("block-detach"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + if (domain_qualifier_to_domid(argv[2], &domid, 0) < 0) { + fprintf(stderr, "%s is an invalid domain identifier\n", argv[2]); + exit(1); + } + if (libxl_devid_to_device_disk(&ctx, domid, argv[3], &disk)) { + fprintf(stderr, "Error: Device %s not connected.\n", argv[3]); + exit(1); + } + if (libxl_device_disk_del(&ctx, &disk, 1)) { + fprintf(stderr, "libxl_device_del failed.\n"); + } + exit(0); +} + +static char *uptime_to_string(unsigned long time, int short_mode) +{ + int sec, min, hour, day; + char *time_string; + int ret; + + day = (int)(time / 86400); + time -= (day * 86400); + hour = (int)(time / 3600); + time -= (hour * 3600); + min = (int)(time / 60); + time -= (min * 60); + sec = time; + + if (short_mode) + if (day > 1) + ret = asprintf(&time_string, "%d days, %2d:%02d", day, hour, min); + else if (day == 1) + ret = asprintf(&time_string, "%d day, %2d:%02d", day, hour, min); + else + ret = asprintf(&time_string, "%2d:%02d", hour, min); + else + if (day > 1) + ret = asprintf(&time_string, "%d days, %2d:%02d:%02d", day, hour, min, sec); + else if (day == 1) + ret = asprintf(&time_string, "%d day, %2d:%02d:%02d", day, hour, min, sec); + else + ret = asprintf(&time_string, "%2d:%02d:%02d", hour, min, sec); + + if (ret < 0) + return NULL; + return time_string; +} + +static char *current_time_to_string(time_t now) +{ + char now_str[100]; + struct tm *tmp; + + tmp = localtime(&now); + if (tmp == NULL) { + fprintf(stderr, "Get localtime error"); + exit(-1); + } + if (strftime(now_str, sizeof(now_str), "%H:%M:%S", tmp) == 0) { + fprintf(stderr, "strftime returned 0"); + exit(-1); + } + return strdup(now_str); +} + +static void print_dom0_uptime(int short_mode, time_t now) +{ + int fd; + char buf[512]; + uint32_t uptime = 0; + char *uptime_str = NULL; + char *now_str = NULL; + + fd = open("/proc/uptime", O_RDONLY); + if (fd == -1) + goto err; + + if (read(fd, buf, sizeof(buf)) == -1) { + close(fd); + goto err; + } + close(fd); + + strtok(buf, " "); + uptime = strtoul(buf, NULL, 10); + + if (short_mode) + { + now_str = current_time_to_string(now); + uptime_str = uptime_to_string(uptime, 1); + printf(" %s up %s, %s (%d)\n", now_str, uptime_str, + libxl_domid_to_name(&ctx, 0), 0); + } + else + { + uptime_str = uptime_to_string(uptime, 0); + printf("%-33s %4d %s\n", libxl_domid_to_name(&ctx, 0), + 0, uptime_str); + } + + if (now_str) + free(now_str); + if (uptime_str) + free(uptime_str); + return; +err: + fprintf(stderr, "Can not get Dom0 uptime.\n"); + exit(-1); +} + +static void print_domU_uptime(uint32_t domuid, int short_mode, time_t now) +{ + uint32_t s_time = 0; + uint32_t uptime = 0; + char *uptime_str = NULL; + char *now_str = NULL; + + s_time = libxl_vm_get_start_time(&ctx, domuid); + if (s_time == -1) + return; + uptime = now - s_time; + if (short_mode) + { + now_str = current_time_to_string(now); + uptime_str = uptime_to_string(uptime, 1); + printf(" %s up %s, %s (%d)\n", now_str, uptime_str, + libxl_domid_to_name(&ctx, domuid), domuid); + } + else + { + uptime_str = uptime_to_string(uptime, 0); + printf("%-33s %4d %s\n", libxl_domid_to_name(&ctx, domuid), + domuid, uptime_str); + } + + if (now_str) + free(now_str); + if (uptime_str) + free(uptime_str); + return; +} + +static void print_uptime(int short_mode, uint32_t doms[], int nb_doms) +{ + struct libxl_vminfo *info; + time_t now; + int nb_vm, i; + + now = time(NULL); + + if (!short_mode) + printf("%-33s %4s %s\n", "Name", "ID", "Uptime"); + + if (nb_doms == 0) { + print_dom0_uptime(short_mode, now); + info = libxl_list_vm(&ctx, &nb_vm); + for (i = 0; i < nb_vm; i++) + print_domU_uptime(info[i].domid, short_mode, now); + } else { + for (i = 0; i < nb_doms; i++) { + if (doms[i] == 0) + print_dom0_uptime(short_mode, now); + else + print_domU_uptime(doms[i], short_mode, now); + } + } +} + +int main_uptime(int argc, char **argv) +{ + char *dom = NULL; + int short_mode = 0; + uint32_t domains[100]; + int nb_doms = 0; + int opt; + + while ((opt = getopt(argc, argv, "hs")) != -1) { + switch (opt) { + case 's': + short_mode = 1; + break; + case 'h': + help("uptime"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + for (;(dom = argv[optind]) != NULL; nb_doms++,optind++) { + find_domain(dom); + domains[nb_doms] = domid; + } + + print_uptime(short_mode, domains, nb_doms); + + exit(0); +} + +int main_tmem_list(int argc, char **argv) +{ + char *dom = NULL; + char *buf = NULL; + int use_long = 0; + int all = 0; + int opt; + + while ((opt = getopt(argc, argv, "alh")) != -1) { + switch (opt) { + case 'l': + use_long = 1; + break; + case 'a': + all = 1; + break; + case 'h': + help("tmem-list"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + dom = argv[optind]; + if (!dom && all == 0) { + fprintf(stderr, "You must specify -a or a domain id.\n\n"); + help("tmem-list"); + exit(1); + } + + if (all) + domid = -1; + else + find_domain(dom); + + buf = libxl_tmem_list(&ctx, domid, use_long); + if (buf == NULL) + exit(-1); + + printf("%s\n", buf); + free(buf); + exit(0); +} + +int main_tmem_freeze(int argc, char **argv) +{ + char *dom = NULL; + int all = 0; + int opt; + + while ((opt = getopt(argc, argv, "ah")) != -1) { + switch (opt) { + case 'a': + all = 1; + break; + case 'h': + help("tmem-freeze"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + dom = argv[optind]; + if (!dom && all == 0) { + fprintf(stderr, "You must specify -a or a domain id.\n\n"); + help("tmem-freeze"); + exit(1); + } + + if (all) + domid = -1; + else + find_domain(dom); + + libxl_tmem_freeze(&ctx, domid); + exit(0); +} + +int main_tmem_destroy(int argc, char **argv) +{ + char *dom = NULL; + int all = 0; + int opt; + + while ((opt = getopt(argc, argv, "ah")) != -1) { + switch (opt) { + case 'a': + all = 1; + break; + case 'h': + help("tmem-destroy"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + dom = argv[optind]; + if (!dom && all == 0) { + fprintf(stderr, "You must specify -a or a domain id.\n\n"); + help("tmem-destroy"); + exit(1); + } + + if (all) + domid = -1; + else + find_domain(dom); + + libxl_tmem_destroy(&ctx, domid); + exit(0); +} + +int main_tmem_thaw(int argc, char **argv) +{ + char *dom = NULL; + int all = 0; + int opt; + + while ((opt = getopt(argc, argv, "ah")) != -1) { + switch (opt) { + case 'a': + all = 1; + break; + case 'h': + help("tmem-thaw"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + dom = argv[optind]; + if (!dom && all == 0) { + fprintf(stderr, "You must specify -a or a domain id.\n\n"); + help("tmem-thaw"); + exit(1); + } + + if (all) + domid = -1; + else + find_domain(dom); + + libxl_tmem_thaw(&ctx, domid); + exit(0); +} + +int main_tmem_set(int argc, char **argv) +{ + char *dom = NULL; + uint32_t weight = 0, cap = 0, compress = 0; + int opt_w = 0, opt_c = 0, opt_p = 0; + int all = 0; + int opt; + + while ((opt = getopt(argc, argv, "aw:c:p:h")) != -1) { + switch (opt) { + case 'a': + all = 1; + break; + case 'w': + weight = strtol(optarg, NULL, 10); + opt_w = 1; + break; + case 'c': + cap = strtol(optarg, NULL, 10); + opt_c = 1; + break; + case 'p': + compress = strtol(optarg, NULL, 10); + opt_p = 1; + break; + case 'h': + help("tmem-set"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + dom = argv[optind]; + if (!dom && all == 0) { + fprintf(stderr, "You must specify -a or a domain id.\n\n"); + help("tmem-set"); + exit(1); + } + + if (all) + domid = -1; + else + find_domain(dom); + + if (!opt_w && !opt_c && !opt_p) { + fprintf(stderr, "No set value specified.\n\n"); + help("tmem-set"); + exit(1); + } + + if (opt_w) + libxl_tmem_set(&ctx, domid, "weight", weight); + if (opt_c) + libxl_tmem_set(&ctx, domid, "cap", cap); + if (opt_p) + libxl_tmem_set(&ctx, domid, "compress", compress); + + exit(0); +} + +int main_tmem_shared_auth(int argc, char **argv) +{ + char *autharg = NULL; + char *endptr = NULL; + char *dom = NULL; + char *uuid = NULL; + int auth = -1; + int all = 0; + int opt; + + while ((opt = getopt(argc, argv, "au:A:h")) != -1) { + switch (opt) { + case 'a': + all = 1; + break; + case 'u': + uuid = optarg; + break; + case 'A': + autharg = optarg; + break; + case 'h': + help("tmem-shared-auth"); + exit(0); + default: + fprintf(stderr, "option `%c' not supported.\n", opt); + break; + } + } + + dom = argv[optind]; + if (!dom && all == 0) { + fprintf(stderr, "You must specify -a or a domain id.\n\n"); + help("tmem-shared-auth"); + exit(1); + } + + if (all) + domid = -1; + else + find_domain(dom); + + if (uuid == NULL || autharg == NULL) { + fprintf(stderr, "No uuid or auth specified.\n\n"); + help("tmem-shared-auth"); + exit(1); + } + + auth = strtol(autharg, &endptr, 10); + if (*endptr != '\0') { + fprintf(stderr, "Invalid auth, valid auth are <0|1>.\n\n"); + exit(1); + } + + libxl_tmem_shared_auth(&ctx, domid, uuid, auth); + + exit(0); +} + diff -r 1952867c5c92 -r b1321a50f626 tools/libxl/xl_cmdtable.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/libxl/xl_cmdtable.c Tue Jul 06 16:49:01 2010 +0100 @@ -0,0 +1,322 @@ +/* + * Author Yang Hongyang <yanghy@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; version 2.1 only. with the special + * exception on linking described in file LICENSE. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +#include <string.h> + +#include "xl.h" + +struct cmd_spec cmd_table[] = { + { "create", + &main_create, + "Create a domain from config file <filename>", + "<ConfigFile> [options] [vars]", + "-h Print this help.\n" + "-p Leave the domain paused after it is created.\n" + "-c Connect to the console after the domain is created.\n" + "-d Enable debug messages.\n" + "-f=FILE, --defconfig=FILE\n Use the given configuration file.\n" + "-q, --quiet Quiet.\n" + "-n, --dryrun Dry run - prints the resulting configuration.\n" + "-d Enable debug messages.\n" + "-e Do not wait in the background for the death of the domain." + }, + { "list", + &main_list, + "List information about all/some domains", + "[options] [Domain]\n", + "-l, --long Output all VM details" + "-v, --verbose Prints out UUIDs", + }, + { "destroy", + &main_destroy, + "Terminate a domain immediately", + "<Domain>", + }, + { "shutdown", + &main_shutdown, + "Issue a shutdown signal to a domain", + "<Domain>", + }, + { "reboot", + &main_reboot, + "Issue a reboot signal to a domain", + "<Domain>", + }, + { "pci-attach", + &main_pciattach, + "Insert a new pass-through pci device", + "<Domain> <BDF> [Virtual Slot]", + }, + { "pci-detach", + &main_pcidetach, + "Remove a domain's pass-through pci device", + "<Domain> <BDF>", + }, + { "pci-list", + &main_pcilist, + "List pass-through pci devices for a domain", + "<Domain>", + }, + { "pause", + &main_pause, + "Pause execution of a domain", + "<Domain>", + }, + { "unpause", + &main_unpause, + "Unpause a paused domain", + "<Domain>", + }, + { "console", + &main_console, + "Attach to domain's console", + "<Domain>", + }, + { "save", + &main_save, + "Save a domain state to restore later", + "[options] <Domain> <CheckpointFile> [<ConfigFile>]", + "-h Print this help.\n" + "-c Leave domain running after creating the snapshot." + }, + { "migrate", + &main_migrate, + "Save a domain state to restore later", + "[options] <Domain> <host>", + "-h Print this help.\n" + "-C <config> Send <config> instead of config file from creation.\n" + "-s <sshcommand> Use <sshcommand> instead of ssh. String will be passed\n" + " to sh. If empty, run <host> instead of ssh <host> xl\n" + " migrate-receive [-d -e]\n" + "-e Do not wait in the background (on <host>) for the death\n" + " of the domain." + }, + { "restore", + &main_restore, + "Restore a domain from a saved state", + "[options] [<ConfigFile>] <CheckpointFile>", + "-h Print this help.\n" + "-p Do not unpause domain after restoring it.\n" + "-e Do not wait in the background for the death of the domain.\n" + "-d Enable debug messages." + }, + { "migrate-receive", + &main_migrate_receive, + "Restore a domain from a saved state", + "- for internal use only", + }, + { "cd-insert", + &main_cd_insert, + "Insert a cdrom into a guest's cd drive", + "<Domain> <VirtualDevice> <type:path>", + }, + { "cd-eject", + &main_cd_eject, + "Eject a cdrom from a guest's cd drive", + "<Domain> <VirtualDevice>", + }, + { "mem-max", + &main_memmax, + "Set the maximum amount reservation for a domain", + "<Domain> <MemMB['b'[bytes]|'k'[KB]|'m'[MB]|'g'[GB]|'t'[TB]]>", + }, + { "mem-set", + &main_memset, + "Set the current memory usage for a domain", + "<Domain> <MemMB['b'[bytes]|'k'[KB]|'m'[MB]|'g'[GB]|'t'[TB]]>", + }, + { "button-press", + &main_button_press, + "Indicate an ACPI button press to the domain", + "<Domain> <Button>", + "<Button> may be 'power' or 'sleep'." + }, + { "vcpu-list", + &main_vcpulist, + "List the VCPUs for all/some domains", + "[Domain, ...]", + }, + { "vcpu-pin", + &main_vcpupin, + "Set which CPUs a VCPU can use", + "<Domain> <VCPU|all> <CPUs|all>", + }, + { "vcpu-set", + &main_vcpuset, + "Set the number of active VCPUs allowed for the domain", + "<Domain> <vCPUs>", + }, + { "list-vm", + &main_list_vm, + "List the VMs,without DOM0", + "", + }, + { "info", + &main_info, + "Get information about Xen host", + "", + }, + { "sched-credit", + &main_sched_credit, + "Get/set credit scheduler parameters", + "[-d <Domain> [-w[=WEIGHT]|-c[=CAP]]]", + "-d DOMAIN, --domain=DOMAIN Domain to modify\n" + "-w WEIGHT, --weight=WEIGHT Weight (int)\n" + "-c CAP, --cap=CAP Cap (int)" + }, + { "domid", + &main_domid, + "Convert a domain name to domain id", + "<DomainName>", + }, + { "domname", + &main_domname, + "Convert a domain id to domain name", + "<DomainId>", + }, + { "rename", + &main_rename, + "Rename a domain", + "<Domain> <NewDomainName>", + }, + { "trigger", + &main_trigger, + "Send a trigger to a domain", + "<Domain> <nmi|reset|init|power|sleep> [<VCPU>]", + }, + { "sysrq", + &main_sysrq, + "Send a sysrq to a domain", + "<Domain> <letter>", + }, + { "debug-keys", + &main_debug_keys, + "Send debug keys to Xen", + "<Keys>", + }, + { "dmesg", + &main_dmesg, + "Read and/or clear dmesg buffer", + "[-c]", + " -c Clear dmesg buffer as well as printing it", + }, + { "top", + &main_top, + "Monitor a host and the domains in real time", + "", + }, + { "network-attach", + &main_networkattach, + "Create a new virtual network device", + "<Domain> [type=<type>] [mac=<mac>] [bridge=<bridge>] " + "[ip=<ip>] [script=<script>] [backend=<BackDomain>] [vifname=<name>] " + "[rate=<rate>] [model=<model>][accel=<accel>]", + }, + { "network-list", + &main_networklist, + "List virtual network interfaces for a domain", + "<Domain(s)>", + }, + { "network-detach", + &main_networkdetach, + "Destroy a domain's virtual network device", + "<Domain> <DevId|mac>", + }, + { "block-attach", + &main_blockattach, + "Create a new virtual block device", + "<Domain> <BackDev> <FrontDev> [<Mode>] [BackDomain]", + }, + { "block-list", + &main_blocklist, + "List virtual block devices for a domain", + "<Domain(s)>", + }, + { "block-detach", + &main_blockdetach, + "Destroy a domain's virtual block device", + "<Domain> <DevId>", + }, + { "uptime", + &main_uptime, + "Print uptime for all/some domains", + "[-s] [Domain]", + }, + { "tmem-list", + &main_tmem_list, + "List tmem pools", + "[-l] [<Domain>|-a]", + " -l List tmem stats", + }, + { "tmem-freeze", + &main_tmem_freeze, + "Freeze tmem pools", + "[<Domain>|-a]", + " -a Freeze all tmem", + }, + { "tmem-destroy", + &main_tmem_destroy, + "Destroy tmem pools", + "[<Domain>|-a]", + " -a Destroy all tmem", + }, + { "tmem-thaw", + &main_tmem_thaw, + "Thaw tmem pools", + "[<Domain>|-a]", + " -a Thaw all tmem", + }, + { "tmem-set", + &main_tmem_set, + "Change tmem settings", + "[<Domain>|-a] [-w[=WEIGHT]|-c[=CAP]|-p[=COMPRESS]]", + " -a Operate on all tmem\n" + " -w WEIGHT Weight (int)\n" + " -c CAP Cap (int)\n" + " -p COMPRESS Compress (int)", + }, + { "tmem-shared-auth", + &main_tmem_shared_auth, + "De/authenticate shared tmem pool", + "[<Domain>|-a] [-u[=UUID] [-A[=AUTH]", + " -a Authenticate for all tmem pools\n" + " -u UUID Specify uuid\n" + " (abcdef01-2345-6789-1234-567890abcdef)\n" + " -A AUTH 0=auth,1=deauth", + }, +}; + +int cmdtable_len = sizeof(cmd_table)/sizeof(struct cmd_spec); + +/* Look up a command in the table, allowing unambiguous truncation */ +struct cmd_spec *cmdtable_lookup(const char *s) +{ + struct cmd_spec *cmd = NULL; + size_t len; + int i, count = 0; + + if (!s) + return NULL; + len = strlen(s); + for (i = 0; i < cmdtable_len; i++) { + if (!strncmp(s, cmd_table[i].cmd_name, len)) { + cmd = &cmd_table[i]; + /* Take an exact match, even if it also prefixes another command */ + if (len == strlen(cmd->cmd_name)) + return cmd; + count++; + } + } + return (count == 1) ? cmd : NULL; +} diff -r 1952867c5c92 -r b1321a50f626 tools/xenstore/xs.c --- a/tools/xenstore/xs.c Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/xenstore/xs.c Tue Jul 06 16:49:01 2010 +0100 @@ -236,10 +236,39 @@ struct xs_handle *xs_domain_open(void) return get_handle(xs_domain_dev()); } +static void close_free_msgs(struct xs_handle *h) { + struct xs_stored_msg *msg, *tmsg; + + list_for_each_entry_safe(msg, tmsg, &h->reply_list, list) { + free(msg->body); + free(msg); + } + + list_for_each_entry_safe(msg, tmsg, &h->watch_list, list) { + free(msg->body); + free(msg); + } +} + +static void close_fds_free(struct xs_handle *h) { + if (h->watch_pipe[0] != -1) { + close(h->watch_pipe[0]); + close(h->watch_pipe[1]); + } + + close(h->fd); + + free(h); +} + +void xs_daemon_destroy_postfork(struct xs_handle *h) +{ + close_free_msgs(h); + close_fds_free(h); +} + void xs_daemon_close(struct xs_handle *h) { - struct xs_stored_msg *msg, *tmsg; - #ifdef USE_PTHREAD if (h->read_thr_exists) { pthread_cancel(h->read_thr); @@ -251,28 +280,11 @@ void xs_daemon_close(struct xs_handle *h mutex_lock(&h->reply_mutex); mutex_lock(&h->watch_mutex); - list_for_each_entry_safe(msg, tmsg, &h->reply_list, list) { - free(msg->body); - free(msg); - } - - list_for_each_entry_safe(msg, tmsg, &h->watch_list, list) { - free(msg->body); - free(msg); - } + close_free_msgs(h); mutex_unlock(&h->request_mutex); mutex_unlock(&h->reply_mutex); mutex_unlock(&h->watch_mutex); - - if (h->watch_pipe[0] != -1) { - close(h->watch_pipe[0]); - close(h->watch_pipe[1]); - } - - close(h->fd); - - free(h); } static bool read_all(int fd, void *data, unsigned int len) diff -r 1952867c5c92 -r b1321a50f626 tools/xenstore/xs.h --- a/tools/xenstore/xs.h Mon Jul 05 12:11:38 2010 +0100 +++ b/tools/xenstore/xs.h Tue Jul 06 16:49:01 2010 +0100 @@ -47,6 +47,9 @@ struct xs_handle *xs_daemon_open_readonl /* 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. _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |