Index: src/Makefile.am =================================================================== RCS file: /data/cvs/libvirt/src/Makefile.am,v retrieving revision 1.27 diff -u -r1.27 Makefile.am --- src/Makefile.am 29 Aug 2006 22:27:07 -0000 1.27 +++ src/Makefile.am 4 Sep 2006 01:15:07 -0000 @@ -26,7 +26,8 @@ virterror.c \ driver.h \ proxy_internal.c proxy_internal.h \ - conf.c conf.h + conf.c conf.h \ + xm_internal.c xm_internal.h bin_PROGRAMS = virsh Index: src/driver.h =================================================================== RCS file: /data/cvs/libvirt/src/driver.h,v retrieving revision 1.12 diff -u -r1.12 driver.h --- src/driver.h 30 Aug 2006 14:21:03 -0000 1.12 +++ src/driver.h 4 Sep 2006 01:15:07 -0000 @@ -21,7 +21,8 @@ VIR_DRV_XEN_STORE = 2, VIR_DRV_XEN_DAEMON = 3, VIR_DRV_TEST = 4, - VIR_DRV_XEN_PROXY = 5 + VIR_DRV_XEN_PROXY = 5, + VIR_DRV_XEN_XM = 6 } virDrvNo; Index: src/internal.h =================================================================== RCS file: /data/cvs/libvirt/src/internal.h,v retrieving revision 1.23 diff -u -r1.23 internal.h --- src/internal.h 28 Jun 2006 18:19:13 -0000 1.23 +++ src/internal.h 4 Sep 2006 01:15:07 -0000 @@ -79,7 +79,7 @@ #define VIR_IS_DOMAIN(obj) ((obj) && (obj)->magic==VIR_DOMAIN_MAGIC) #define VIR_IS_CONNECTED_DOMAIN(obj) (VIR_IS_DOMAIN(obj) && VIR_IS_CONNECT((obj)->conn)) -#define MAX_DRIVERS 5 +#define MAX_DRIVERS 10 /* * Flags for Xen connections Index: src/libvirt.c =================================================================== RCS file: /data/cvs/libvirt/src/libvirt.c,v retrieving revision 1.45 diff -u -r1.45 libvirt.c --- src/libvirt.c 30 Aug 2006 14:21:03 -0000 1.45 +++ src/libvirt.c 4 Sep 2006 01:15:08 -0000 @@ -28,6 +28,7 @@ #include "xen_internal.h" #include "xend_internal.h" #include "xs_internal.h" +#include "xm_internal.h" #include "proxy_internal.h" #include "xml.h" #include "test.h" @@ -73,6 +74,7 @@ xenProxyRegister(); xenDaemonRegister(); xenStoreRegister(); + xenXMRegister(); testRegister(); return(0); } Index: src/xm_internal.c =================================================================== RCS file: src/xm_internal.c diff -N src/xm_internal.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/xm_internal.c 4 Sep 2006 01:15:11 -0000 @@ -0,0 +1,1176 @@ +/* + * xm_internal.h: helper routines for dealing with inactive domains + * + * Copyright (C) 2006 + * + * Daniel Berrange + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file COPYING.LIB in the main directory of this + * archive for more details. + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + + +#include "xm_internal.h" +#include "xend_internal.h" +#include "conf.h" +#include "hash.h" +#include "internal.h" +#include "xml.h" + +typedef struct xenXMConfCache *xenXMConfCachePtr; +typedef struct xenXMConfCache { + time_t refreshedAt; + char filename[PATH_MAX]; + virConfPtr conf; +} xenXMConfCache; + +static virHashTablePtr configCache = NULL; +static int nconnections = 0; +static time_t lastRefresh = 0; + +#define XM_REFRESH_INTERVAL 10 + +#define XM_CONFIG_DIR "/etc/xen" +#define XM_EXAMPLE_PREFIX "xmexample" +#define XEND_CONFIG_FILE "xend-config.sxp" +#define QEMU_IF_SCRIPT "qemu-ifup" + +static virDriver xenXMDriver = { + VIR_DRV_XEN_XM, + "XenXM", + (DOM0_INTERFACE_VERSION >> 24) * 1000000 + + ((DOM0_INTERFACE_VERSION >> 16) & 0xFF) * 1000 + + (DOM0_INTERFACE_VERSION & 0xFFFF), + NULL, /* init */ + xenXMOpen, /* open */ + xenXMClose, /* close */ + xenXMGetType, /* type */ + NULL, /* version */ + NULL, /* nodeGetInfo */ + NULL, /* listDomains */ + NULL, /* numOfDomains */ + NULL, /* domainCreateLinux */ + NULL, /* domainLookupByID */ + xenXMDomainLookupByUUID, /* domainLookupByUUID */ + xenXMDomainLookupByName, /* domainLookupByName */ + NULL, /* domainSuspend */ + NULL, /* domainResume */ + NULL, /* domainShutdown */ + NULL, /* domainReboot */ + NULL, /* domainDestroy */ + NULL, /* domainFree */ + NULL, /* domainGetName */ + NULL, /* domainGetID */ + NULL, /* domainGetUUID */ + NULL, /* domainGetOSType */ + xenXMDomainGetMaxMemory, /* domainGetMaxMemory */ + xenXMDomainSetMaxMemory, /* domainSetMaxMemory */ + xenXMDomainSetMemory, /* domainMaxMemory */ + xenXMDomainGetInfo, /* domainGetInfo */ + NULL, /* domainSave */ + NULL, /* domainRestore */ + xenXMDomainSetVcpus, /* domainSetVcpus */ + NULL, /* domainPinVcpu */ + NULL, /* domainGetVcpus */ + xenXMDomainDumpXML, /* domainDumpXML */ + xenXMListDefinedDomains, /* listDefinedDomains */ + xenXMNumOfDefinedDomains, /* numOfDefinedDomains */ + xenXMDomainCreate, /* domainCreate */ + xenXMDomainDefineXML, /* domainDefineXML */ + xenXMDomainUndefine, /* domainUndefine */ +}; + +static void +xenXMError(virConnectPtr conn, virErrorNumber error, const char *info) +{ + const char *errmsg; + + if (error == VIR_ERR_OK) + return; + + errmsg = __virErrorMsg(error, info); + __virRaiseError(conn, NULL, VIR_FROM_XEND, error, VIR_ERR_ERROR, + errmsg, info, NULL, 0, 0, errmsg, info); +} + +void xenXMRegister(void) +{ + virRegisterDriver(&xenXMDriver); +} + + +static int xenXMConfigReaper(const void *payload, const char *key ATTRIBUTE_UNUSED, const void *data) { + time_t now = *(const time_t *)data; + xenXMConfCachePtr entry = (xenXMConfCachePtr)payload; + printf("Testing %s\n", key); + if (entry->refreshedAt != now) + return 1; + return 0; +} + +static void xenXMConfigFree(void *payload, const char *key ATTRIBUTE_UNUSED) { + xenXMConfCachePtr entry = (xenXMConfCachePtr)payload; + virConfFree(entry->conf); + free(entry); +} + +static int xenXMConfigCacheRefresh(void) { + DIR *dh; + struct dirent *ent; + time_t now = time(NULL); + int ret = -1; + + if (now == ((time_t)-1)) { + return -1; + } + + if ((now - lastRefresh) < XM_REFRESH_INTERVAL) + return 0; + + lastRefresh = now; + + if (!(dh = opendir(XM_CONFIG_DIR))) { + return -1; + } + + while ((ent = readdir(dh))) { + xenXMConfCachePtr entry; + struct stat st; + int newborn = 0; + char path[PATH_MAX]; + + /* Skip a bunch of cruft */ + if (!strncmp(ent->d_name, ".", 1)) + continue; + if (!strncmp(ent->d_name, XEND_CONFIG_FILE, strlen(XEND_CONFIG_FILE))) + continue; + if (!strncmp(ent->d_name, XM_EXAMPLE_PREFIX, strlen(XM_EXAMPLE_PREFIX))) + continue; + if (!strncmp(ent->d_name, QEMU_IF_SCRIPT, strlen(QEMU_IF_SCRIPT))) + continue; + /* Editor backups */ + if (ent->d_name[0] == '#') + continue; + if (ent->d_name[strlen(ent->d_name)-1] == '~') + continue; + + /* Build the full file path */ + if ((strlen(XM_CONFIG_DIR) + 1 + strlen(ent->d_name) + 1) > PATH_MAX) + continue; + strcpy(path, XM_CONFIG_DIR); + strcat(path, "/"); + strcat(path, ent->d_name); + + if ((stat(path, &st) < 0) || + !S_ISREG(st.st_mode)) { + continue; + } + + /* If we already have a matching entry and its not + modified, then carry on */ + if ((entry = virHashLookup(configCache, ent->d_name))) { + if (entry->refreshedAt >= st.st_mtime) { + entry->refreshedAt = now; + continue; + } + } + + if (entry) { /* Needs refresh */ + virConfFree(entry->conf); + entry->conf = NULL; + } else { /* New entry */ + newborn = 1; + if (!(entry = malloc(sizeof(xenXMConfCache)))) { + goto cleanup; + } + memcpy(entry->filename, path, PATH_MAX); + } + entry->refreshedAt = now; + + if (!(entry->conf = virConfReadFile(entry->filename))) { + if (!newborn) { + virHashRemoveEntry(configCache, ent->d_name, NULL); + } + free(entry); + continue; + } + + if (newborn) { + if (virHashAddEntry(configCache, ent->d_name, entry) < 0) { + virConfFree(entry->conf); + free(entry); + goto cleanup; + } + } + } + + virHashRemoveSet(configCache, xenXMConfigReaper, xenXMConfigFree, (const void*) &now); + ret = 0; + + cleanup: + if (dh) + closedir(dh); + + return ret; +} + + +static int xenXMConfigGetInt(virConfPtr conf, const char *name, long *value) { + virConfValuePtr val; + if (!value || !name || !conf) + return -1; + + if (!(val = virConfGetValue(conf, name))) { + return -1; + } + + if (val->type == VIR_CONF_LONG) { + *value = val->l; + } else if (val->type == VIR_CONF_STRING) { + char *ret; + if (!val->str) + return -1; + *value = strtol(val->str, &ret, 10); + if (ret == val->str) + return -1; + } else { + return -1; + } + return 0; +} + + +static int xenXMConfigGetString(virConfPtr conf, const char *name, const char **value) { + virConfValuePtr val; + if (!value || !name || !conf) + return -1; + *value = NULL; + if (!(val = virConfGetValue(conf, name))) { + return -1; + } + if (val->type != VIR_CONF_STRING) + return -1; + if (!val->str) + return -1; + *value = val->str; + return 0; +} + + +static int xenXMConfigGetUUID(virConfPtr conf, const char *name, unsigned char *uuid) { + virConfValuePtr val; + char *rawuuid = (char *)uuid; + if (!uuid || !name || !conf) + return -1; + if (!(val = virConfGetValue(conf, name))) { + return -1; + } + + if (val->type != VIR_CONF_STRING) + return -1; + if (!val->str) + return -1; + + if (!virParseUUID(&rawuuid, val->str)) + return -1; + + return 0; +} + + +int xenXMOpen(virConnectPtr conn ATTRIBUTE_UNUSED, const char *name, int flags ATTRIBUTE_UNUSED) { + if (name && + strcasecmp(name, "xen")) { + return -1; + } + + if (nconnections == 0) { + configCache = virHashCreate(50); + if (!configCache) + return -1; + } + nconnections++; + + return 0; +} + +int xenXMClose(virConnectPtr conn ATTRIBUTE_UNUSED) { + if (!nconnections--) { + virHashFree(configCache, xenXMConfigFree); + configCache = NULL; + } + return 0; +} +const char *xenXMGetType(virConnectPtr conn ATTRIBUTE_UNUSED) { + return "XenXM"; +} +int xenXMDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) { + xenXMConfCachePtr entry; + long vcpus; + long mem; + if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) { + xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG, + __FUNCTION__); + return(-1); + } + + if (domain->handle != -1) + return (-1); + + if (!(entry = virHashLookup(configCache, domain->name))) + return (-1); + + memset(info, 0, sizeof(virDomainInfo)); + if (xenXMConfigGetInt(entry->conf, "memory", &mem) < 0 || + mem < 0) + info->memory = 64 * 1024; + else + info->memory = (unsigned long)mem * 1024; + if (xenXMConfigGetInt(entry->conf, "maxmem", &mem) < 0 || + mem < 0) + info->maxMem = info->memory; + else + info->maxMem = (unsigned long)mem * 1024; + + if (xenXMConfigGetInt(entry->conf, "vcpus", &vcpus) < 0 || + vcpus < 0) + info->nrVirtCpu = 1; + else + info->nrVirtCpu = (unsigned short)vcpus; + info->state = VIR_DOMAIN_SHUTOFF; + info->cpuTime = 0; + + return 0; + +} + +char *xenXMDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED) { + virBufferPtr buf; + xenXMConfCachePtr entry; + char *xml; + const char *name; + unsigned char uuid[16]; + const char *str; + int hvm = 0; + long val; + virConfValuePtr list; + + if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) { + xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG, + __FUNCTION__); + return(NULL); + } + if (domain->handle != -1) + return (NULL); + if (!(entry = virHashLookup(configCache, domain->name))) + return(NULL); + + if (xenXMConfigGetString(entry->conf, "name", &name) < 0) + return(NULL); + if (xenXMConfigGetUUID(entry->conf, "uuid", uuid) < 0) + return(NULL); + + buf = virBufferNew(4096); + + virBufferAdd(buf, "\n", -1); + virBufferVSprintf(buf, " %s\n", name); + virBufferVSprintf(buf, + " %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + 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]); + + if ((xenXMConfigGetString(entry->conf, "builder", &str) == 0) && + !strcmp(str, "hvm")) + hvm = 1; + + if (hvm) { + virBufferAdd(buf, " \n", -1); + virBufferAdd(buf, " hvm\n", -1); + if (xenXMConfigGetString(entry->conf, "kernel", &str) == 0) + virBufferVSprintf(buf, " %s\n", str); + virBufferAdd(buf, " \n", -1); + } else { + + if (xenXMConfigGetString(entry->conf, "bootloader", &str) == 0) + virBufferVSprintf(buf, " %s\n", str); + if (xenXMConfigGetString(entry->conf, "kernel", &str) == 0) { + virBufferAdd(buf, " \n", -1); + virBufferAdd(buf, " linux\n", -1); + virBufferVSprintf(buf, " %s\n", str); + if (xenXMConfigGetString(entry->conf, "ramdisk", &str) == 0) + virBufferVSprintf(buf, " %s\n", str); + if (xenXMConfigGetString(entry->conf, "extra", &str) == 0) + virBufferVSprintf(buf, " %s\n", str); + virBufferAdd(buf, " \n", -1); + } + } + + if (xenXMConfigGetInt(entry->conf, "memory", &val) < 0) + val = 64; + virBufferVSprintf(buf, " %ld\n", val * 1024); + + if (xenXMConfigGetInt(entry->conf, "vcpus", &val) < 0) + val = 1; + virBufferVSprintf(buf, " %ld\n", val); + + + + if (xenXMConfigGetString(entry->conf, "on_poweroff", &str) < 0) + str = "destroy"; + virBufferVSprintf(buf, " %s\n", str); + + if (xenXMConfigGetString(entry->conf, "on_reboot", &str) < 0) + str = "restart"; + virBufferVSprintf(buf, " %s\n", str); + + if (xenXMConfigGetString(entry->conf, "on_crash", &str) < 0) + str = "restart"; + virBufferVSprintf(buf, " %s\n", str); + + + if (hvm) { + virBufferAdd(buf, " \n", -1); + if (xenXMConfigGetInt(entry->conf, "pae", &val) == 0 && + val) + virBufferAdd(buf, " \n", -1); + if (xenXMConfigGetInt(entry->conf, "acpi", &val) == 0 && + val) + virBufferAdd(buf, " \n", -1); + if (xenXMConfigGetInt(entry->conf, "apic", &val) == 0 && + val) + virBufferAdd(buf, " \n", -1); + virBufferAdd(buf, " \n", -1); + } + + virBufferAdd(buf, " \n", -1); + + list = virConfGetValue(entry->conf, "disk"); + while (list && list->type == VIR_CONF_LIST) { + virConfValuePtr el = list->list; + int block = 0; + char dev[NAME_MAX]; + char src[PATH_MAX]; + char *type; + char *mode; + if ((el== NULL) || (el->type != VIR_CONF_STRING) || (el->str == NULL)) + goto skipdisk; + + if (!(type = index(el->str, ',')) || type[0] == '\0') + goto skipdisk; + type++; + if (!(mode = index(type, ',')) || mode[0] == '\0') + goto skipdisk; + mode++; + + if (!strncmp(el->str, "phy:", 4)) { + int len = (type - el->str)-1; + if (len > (PATH_MAX-1)) + goto skipdisk; + strncpy(src, el->str+4, len-4); + src[len-4] = '\0'; + block = 1; + } else if (!strncmp(el->str, "file:", 5)) { + int len = (type - el->str)-1; + if (len > (PATH_MAX-1)) + goto skipdisk; + strncpy(src, el->str+5, len-5); + src[len-5] = '\0'; + block = 0; + } else { + goto skipdisk; + } + + if ((mode-type-1) > (NAME_MAX-1)) { + goto skipdisk; + } + strncpy(dev, type, (mode-type-1)); + dev[(mode-type-1)] = '\0'; + + virBufferVSprintf(buf, " \n", block ? "block" : "file"); + virBufferVSprintf(buf, " \n", block ? "device" : "file", src); + virBufferVSprintf(buf, " \n", dev); + if (*mode == 'r') + virBufferAdd(buf, " \n", -1); + virBufferAdd(buf, " \n", -1); + + skipdisk: + list = list->next; + } + + list = virConfGetValue(entry->conf, "vif"); + while (list && list->type == VIR_CONF_LIST) { + virConfValuePtr el = list->list; + int type = -1; + char script[PATH_MAX]; + char mac[18]; + char *key; + + mac[0] = '\0'; + script[0] = '\0'; + + if ((el== NULL) || (el->type != VIR_CONF_STRING) || (el->str == NULL)) + goto skipnic; + + key = el->str; + while (key) { + char *data; + char *nextkey = index(key, ','); + if (!(data = index(key, '=')) || (data[0] == '\0')) + goto skipnic; + data++; + + if (!strncmp(key, "mac=", 4)) { + int len = nextkey ? (nextkey - data) : 17; + if (len > 17) + len = 17; + strncpy(mac, data, len); + mac[len] = '\0'; + } else if (!strncmp(key, "bridge=", 7)) { + type = 1; + } else if (!strncmp(key, "script=", 7)) { + int len = nextkey ? (nextkey - data) : PATH_MAX-1; + if (len > (PATH_MAX-1)) + len = PATH_MAX-1; + strncpy(script, data, len); + script[len] = '\0'; + } + + if (nextkey && nextkey[0]) + nextkey++; + key = nextkey; + } + + /* XXX Forcing to pretend its a bridge */ + if (type == -1) { + type = 1; + } + + virBufferAdd(buf, " \n", -1); + if (mac[0]) + virBufferVSprintf(buf, " \n", mac); + if (script[0]) + virBufferVSprintf(buf, "