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