Attached is the patch for the qemu driver & daemon process Since there is no scalable way to determine active standalone QEMU instances, or access their monitor connection, the backend implements a management daemon - called 'qemud' - which takes care of managing the complete lifecycle of QEMU virtual machines. The libvirt driver is a thin shim which talks to qemud via a UNIX domain socket - the wire protocol is modelled after the protocol used for libvirt_proxy, but obviously contains alot more functions since its full read/write, not just read-only. There is intended to be one qemud instance per UNIX user - the so called 'session' instance, and optionally one system global instance runing as root (or a system daemon account?) - the so called 'system' instance. When using libvirt, the URIs for each are 'qemu:///session' and 'qemu:///system' respectively. The UNIX socket for session instances is $HOME/.qemud and is chmod 0700 - no support is provided for users connecting to each other's instances. Although we could trivially extend to create a read-only socket $HOME/.qemud-ro if desired. The system instance is currently not finished but intended to run in /var/run/qemud or some such. The backend code is in src/qemu_internal.h, src/qemu_internal.c, the daemon code is in qemud/* with qemud/protocol.h defining the network wire protocol. This latter header file is also included by src/qemu_internal.c - qemud.c - the main daemon management code - handles all network I/O and forking / cleanup of QEMU processes. The implementation is poll() based & completely non-blocking. All requests/replies from a single client are, however, serialized. - dispatch.c - takes care of serializing/de-serializing requests/replies from/to libvirt - called from qemud.c when a complete message is available. - driver.c - the implementation of each request from libvirt - called from dispatch.c - config.c - manages reading & writing of XML files for inactive domains in the $HOME/.qemud.d/*.xml. Also takes care of generating a suitable command line for execing qemu. In terms of hardware, there is support for - harddisk - floppy, cdrom, harddisk - graphics - VNC - memory - virtual CPUs In particular no support for - networking - sound - non-native CPU types - boot order But its enough to demonstrate the practice. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/configure.in libvirt-new/configure.in --- libvirt-orig/configure.in 2006-08-24 17:46:28.000000000 -0400 +++ libvirt-new/configure.in 2006-08-27 17:05:39.000000000 -0400 @@ -256,5 +256,6 @@ libvirt.pc libvirt.spec \ include/libvirt/Makefile include/libvirt/libvirt.h \ python/Makefile python/tests/Makefile \ + qemud/Makefile \ tests/Makefile proxy/Makefile \ tests/virshdata/Makefile) diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/Makefile.am libvirt-new/Makefile.am --- libvirt-orig/Makefile.am 2006-06-28 14:19:13.000000000 -0400 +++ libvirt-new/Makefile.am 2006-08-27 17:05:39.000000000 -0400 @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -SUBDIRS = src include docs @PYTHON_SUBDIR@ tests proxy +SUBDIRS = src include docs @PYTHON_SUBDIR@ tests proxy qemud EXTRA_DIST = libvirt.spec.in libvirt.spec COPYING.LIB \ libvirt.pc.in libvirt.pc TODO AUTHORS ChangeLog \ diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/qemud/config.c libvirt-new/qemud/config.c --- libvirt-orig/qemud/config.c 1969-12-31 19:00:00.000000000 -0500 +++ libvirt-new/qemud/config.c 2006-08-27 18:13:33.000000000 -0400 @@ -0,0 +1,730 @@ + +#include <dirent.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> + +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <libxml/uri.h> + +#include "protocol.h" +#include "internal.h" +#include "config.h" +#include "driver.h" + +static int qemudParseUUID(const char *uuid, + unsigned char *rawuuid) { + const char *cur; + int i; + + /* + * do a liberal scan allowing '-' and ' ' anywhere between character + * pairs as long as there is 32 of them in the end. + */ + cur = uuid; + for (i = 0;i < 16;) { + rawuuid[i] = 0; + if (*cur == 0) + goto error; + if ((*cur == '-') || (*cur == ' ')) { + cur++; + continue; + } + if ((*cur >= '0') && (*cur <= '9')) + rawuuid[i] = *cur - '0'; + else if ((*cur >= 'a') && (*cur <= 'f')) + rawuuid[i] = *cur - 'a' + 10; + else if ((*cur >= 'A') && (*cur <= 'F')) + rawuuid[i] = *cur - 'A' + 10; + else + goto error; + rawuuid[i] *= 16; + cur++; + if (*cur == 0) + goto error; + if ((*cur >= '0') && (*cur <= '9')) + rawuuid[i] += *cur - '0'; + else if ((*cur >= 'a') && (*cur <= 'f')) + rawuuid[i] += *cur - 'a' + 10; + else if ((*cur >= 'A') && (*cur <= 'F')) + rawuuid[i] += *cur - 'A' + 10; + else + goto error; + i++; + cur++; + } + + return 0; + +error: + return -1; +} + +static struct qemud_vm_disk_def *qemudParseDiskXML(xmlNodePtr node) { + struct qemud_vm_disk_def *disk = calloc(1, sizeof(struct qemud_vm_disk_def)); + xmlNodePtr cur; + xmlChar *device = NULL; + xmlChar *source = NULL; + xmlChar *target = NULL; + xmlChar *type = NULL; + int typ = 0; + + type = xmlGetProp(node, BAD_CAST "type"); + if (type != NULL) { + if (xmlStrEqual(type, BAD_CAST "file")) + typ = QEMUD_DISK_FILE; + else if (xmlStrEqual(type, BAD_CAST "block")) + typ = QEMUD_DISK_BLOCK; + else + goto error; + xmlFree(type); + type = NULL; + } + + device = xmlGetProp(node, BAD_CAST "device"); + + cur = node->children; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) { + if ((source == NULL) && + (xmlStrEqual(cur->name, BAD_CAST "source"))) { + + if (typ == QEMUD_DISK_FILE) + source = xmlGetProp(cur, BAD_CAST "file"); + else + source = xmlGetProp(cur, BAD_CAST "dev"); + } else if ((target == NULL) && + (xmlStrEqual(cur->name, BAD_CAST "target"))) { + target = xmlGetProp(cur, BAD_CAST "dev"); + } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) { + disk->readonly = 1; + } + } + cur = cur->next; + } + + if (source == NULL) { + //virXMLError(VIR_ERR_NO_SOURCE, (const char *) target, 0); + goto error; + } + if (target == NULL) { + //virXMLError(VIR_ERR_NO_TARGET, (const char *) source, 0); + goto error; + } + + if (device && + !strcmp((const char *)device, "floppy") && + strcmp((const char *)target, "fda") && + strcmp((const char *)target, "fdb")) { + printf("Bogus floppy\n"); + goto error; + } + + if (device && + !strcmp((const char *)device, "cdrom") && + strcmp((const char *)target, "hdc")) { + printf("Bogus cdomr\n"); + goto error; + } + + if (device && + !strcmp((const char *)device, "cdrom")) + disk->readonly = 1; + + if ((!device || !strcmp((const char *)device, "disk")) && + strcmp((const char *)target, "hda") && + strcmp((const char *)target, "hdb") && + strcmp((const char *)target, "hdc") && + strcmp((const char *)target, "hdd")) { + printf("alse %s %s\n", device, target); + goto error; + } + + strncpy(disk->src, (const char *)source, NAME_MAX-1); + disk->src[NAME_MAX-1] = '\0'; + + strncpy(disk->dst, (const char *)target, NAME_MAX-1); + disk->dst[NAME_MAX-1] = '\0'; + disk->type = typ; + + if (!device) + disk->device = QEMUD_DISK_DISK; + else if (!strcmp((const char *)device, "disk")) + disk->device = QEMUD_DISK_DISK; + else if (!strcmp((const char *)device, "cdrom")) + disk->device = QEMUD_DISK_CDROM; + else if (!strcmp((const char *)device, "floppy")) + disk->device = QEMUD_DISK_FLOPPY; + else + goto error; + + xmlFree(target); + xmlFree(source); + + return disk; + + error: + if (type) + xmlFree(type); + if (target) + xmlFree(target); + if (source) + xmlFree(source); + free(disk); + return NULL; +} + + +static int qemudParseXML(xmlDocPtr xml, + struct qemud_vm *vm) { + xmlNodePtr root = NULL; + xmlChar *prop = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlXPathObjectPtr obj = NULL; + char *conv = NULL; + + root = xmlDocGetRootElement(xml); + if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "domain"))) { + goto error; + } + + if (!(prop = xmlGetProp(root, BAD_CAST "type")) || + strcmp((char *)prop, "qemu")) + goto error; + free(prop); + prop = NULL; + + ctxt = xmlXPathNewContext(xml); + if (ctxt == NULL) { + goto error; + } + + obj = xmlXPathEval(BAD_CAST "string(/domain/name[1])", ctxt); + if ((obj == NULL) || (obj->type != XPATH_STRING) || + (obj->stringval == NULL) || (obj->stringval[0] == 0)) { + goto error; + } + if (strlen((const char *)obj->stringval) >= QEMUD_MAX_NAME_LEN) + goto error; + strcpy(vm->def.name, (const char *)obj->stringval); + xmlXPathFreeObject(obj); + + obj = xmlXPathEval(BAD_CAST "string(/domain/uuid[1])", ctxt); + if ((obj == NULL) || (obj->type != XPATH_STRING) || + (obj->stringval == NULL) || (obj->stringval[0] == 0)) { + goto error; + } + if (qemudParseUUID((const char *)obj->stringval, vm->def.uuid) < 0) { + goto error; + } + xmlXPathFreeObject(obj); + + + obj = xmlXPathEval(BAD_CAST "string(/domain/memory[1])", ctxt); + if ((obj == NULL) || (obj->type != XPATH_STRING) || + (obj->stringval == NULL) || (obj->stringval[0] == 0)) { + //testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "missing memory element on domain"); + goto error; + } + conv = NULL; + vm->def.memory = strtoll((const char*)obj->stringval, &conv, 10); + if (conv == (const char*)obj->stringval) { + //testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "malformed memory value for domain"); + goto error; + } + xmlXPathFreeObject(obj); + obj = NULL; + + obj = xmlXPathEval(BAD_CAST "string(/domain/vcpu[1])", ctxt); + if ((obj == NULL) || (obj->type != XPATH_STRING) || + (obj->stringval == NULL) || (obj->stringval[0] == 0)) { + vm->def.vcpus = 1; + } else { + conv = NULL; + vm->def.vcpus = strtoll((const char*)obj->stringval, &conv, 10); + if (conv == (const char*)obj->stringval) { + //testError(conn, NULL, VIR_ERR_INTERNAL_ERROR, "malformed memory value for domain"); + goto error; + } + } + if (obj) { + xmlXPathFreeObject(obj); + obj = NULL; + } + + obj = xmlXPathEval(BAD_CAST "/domain/devices/graphics", ctxt); + if ((obj == NULL) || (obj->type != XPATH_NODESET) || + (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) { + vm->def.graphicsType = QEMUD_GRAPHICS_NONE; + } else { + prop = xmlGetProp(obj->nodesetval->nodeTab[0], BAD_CAST "type"); + if (!strcmp((char *)prop, "vnc")) { + vm->def.graphicsType = QEMUD_GRAPHICS_VNC; + prop = xmlGetProp(obj->nodesetval->nodeTab[0], BAD_CAST "port"); + if (prop) { + conv = NULL; + vm->def.vncPort = strtoll((const char*)prop, &conv, 10); + } else { + vm->def.vncPort = 0; + } + } + } + + /* analyze of the devices */ + obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt); + if ((obj != NULL) && (obj->type == XPATH_NODESET) && + (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) { + for (int i = 0; i < obj->nodesetval->nodeNr; i++) { + struct qemud_vm_disk_def *disk; + if (!(disk = qemudParseDiskXML(obj->nodesetval->nodeTab[i]))) { + goto error; + } + vm->def.ndisks++; + disk->next = vm->def.disks; + vm->def.disks = disk; + } + } + xmlXPathFreeObject(obj); + + + + return 0; + + error: + if (prop) + free(prop); + if (obj) + xmlXPathFreeObject(obj); + return -1; +} + + +int qemudBuildCommandLine(struct qemud_vm *vm, + char ***argv, + int *argc) { + int n = 0; + char memory[50]; + char vcpus[50]; + struct qemud_vm_disk_def *disk = vm->def.disks; + + *argc = 1 + /* qemu */ + 2 * vm->def.ndisks + /* disks*/ + 2 + /* memory*/ + 2 + /* cpus */ + (vm->def.graphicsType == QEMUD_GRAPHICS_VNC ? 2 : 0) + /* graphics */ + 1; /* NULL */ + + sprintf(memory, "%d", vm->def.memory/1024); + sprintf(vcpus, "%d", vm->def.vcpus); + + if (!(*argv = malloc(sizeof(char *) * *argc))) + return -1; + (*argv)[n++] = strdup("qemu"); + (*argv)[n++] = strdup("-m"); + (*argv)[n++] = strdup(memory); + (*argv)[n++] = strdup("-smp"); + (*argv)[n++] = strdup(vcpus); + + while (disk) { + char dev[NAME_MAX]; + char file[PATH_MAX]; + if (!strcmp(disk->dst, "hdc") && + disk->device == QEMUD_DISK_CDROM) + snprintf(dev, NAME_MAX, "-%s", "cdrom"); + else + snprintf(dev, NAME_MAX, "-%s", disk->dst); + snprintf(file, PATH_MAX, "%s", disk->src); + + (*argv)[n++] = strdup(dev); + (*argv)[n++] = strdup(file); + + disk = disk->next; + } + + if (vm->def.graphicsType == QEMUD_GRAPHICS_VNC) { + char port[10]; + snprintf(port, 10, "%d", vm->def.vncPort - 5900); + (*argv)[n++] = strdup("-vnc"); + (*argv)[n++] = strdup(port); + } + + (*argv)[n++] = NULL; + + return 0; +} + +void qemudFreeVM(struct qemud_vm *vm) { + struct qemud_vm_disk_def *disk = vm->def.disks; + struct qemud_vm_net_def *net = vm->def.nets; + + while (disk) { + struct qemud_vm_disk_def *prev = disk; + disk = disk->next; + free(prev); + } + while (net) { + struct qemud_vm_net_def *prev = net; + net = net->next; + free(prev); + } + + free(vm); +} + +static +int qemudMakeConfigPath(struct qemud_server *server, + const char *name, + const char *ext, + char *buf, + unsigned int buflen) { + if ((strlen(server->configDir) + 1 + strlen(name) + (ext ? strlen(ext) : 0) + 1) > buflen) + return -1; + + strcpy(buf, server->configDir); + strcat(buf, "/"); + strcat(buf, name); + if (ext) + strcat(buf, ext); + return 0; +} + +static int qemudSaveConfig(struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_vm *vm) { + char *xml; + int fd, ret = -1; + int towrite; + struct stat sb; + + if (!(xml = qemudGenerateXML(vm))) { + return -1; + } + + printf("Save VM %s\n", vm->configFile); + + if (stat(server->configDir, &sb) < 0) { + if (errno == ENOENT) { + if (mkdir(server->configDir, 0700) < 0) + return -1; + } else { + return -1; + } + } else if (!S_ISDIR(sb.st_mode)) { + return -1; + } + + if ((fd = open(vm->configFile, + O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR )) < 0) + goto cleanup; + + towrite = strlen(xml); + if (write(fd, xml, towrite) != towrite) + goto cleanup; + + if (close(fd) < 0) + goto cleanup; + + ret = 0; + + cleanup: + + free(xml); + + return ret; +} + + +struct qemud_vm *qemudLoadConfigXML(struct qemud_server *server, + const char *file, + const char *doc, + int save) { + struct qemud_vm *vm = NULL; + xmlDocPtr xml; + + printf("Load VM %s\n", file); + if (!(xml = xmlReadDoc(BAD_CAST doc, file ? file : "domain.xml", NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) { + printf("malformed\n"); + return NULL; + } + + if (!(vm = calloc(1, sizeof(struct qemud_vm)))) + return NULL; + + vm->stdout = -1; + vm->stderr = -1; + vm->monitor = -1; + vm->pid = -1; + vm->def.id = -1; + + if (qemudParseXML(xml, vm) < 0) { + xmlFreeDoc(xml); + qemudFreeVM(vm); + printf("bad parse\n"); + return NULL; + } + xmlFreeDoc(xml); + + if (qemudFindVMByUUID(server, vm->def.uuid)) { + qemudFreeVM(vm); + printf("Duplicate domains, discarding %s\n", file); + return NULL; + } + + if (qemudFindVMByName(server, vm->def.name)) { + qemudFreeVM(vm); + printf("Duplicate domains, discarding %s\n", file); + return NULL; + } + + if (file) { + strncpy(vm->configFile, file, PATH_MAX); + vm->configFile[PATH_MAX-1] = '\0'; + } else { + if (save) { + if (qemudMakeConfigPath(server, vm->def.name, ".xml", vm->configFile, PATH_MAX) < 0) { + qemudFreeVM(vm); + return NULL; + } + + if (qemudSaveConfig(server, vm) < 0) { + qemudFreeVM(vm); + return NULL; + } + } else { + vm->configFile[0] = '\0'; + } + } + + return vm; +} + + +static void qemudLoadConfig(struct qemud_server *server, + const char *file) { + FILE *fh; + struct stat st; + struct qemud_vm *vm; + char xml[QEMUD_MAX_XML_LEN]; + int ret; + + if (!(fh = fopen(file, "r"))) { + return; + } + + if (fstat(fileno(fh), &st) < 0) + goto cleanup; + + if (st.st_size >= QEMUD_MAX_XML_LEN) + goto cleanup; + + if ((ret = fread(xml, st.st_size, 1, fh)) != 1) { + printf("Couldn't read %d\n", ret); + goto cleanup; + } + xml[st.st_size] = '\0'; + + if ((vm = qemudLoadConfigXML(server, file, xml, 1))) { + vm->next = server->inactivevms; + server->inactivevms = vm; + server->ninactivevms++; + } + + cleanup: + fclose(fh); +} + +int qemudScanConfigs(struct qemud_server *server) { + DIR *dir; + struct dirent *entry; + + if (!(dir = opendir(server->configDir))) { + if (errno == ENOENT) + return 0; + return -1; + } + + while ((entry = readdir(dir))) { + char file[PATH_MAX]; + if (entry->d_name[0] == '.') + continue; + + if (qemudMakeConfigPath(server, entry->d_name, NULL, file, PATH_MAX) < 0) + continue; + + qemudLoadConfig(server, file); + } + + closedir(dir); + + return 0; +} + + +struct qemudBuffer { + char *data; + int len; + int used; +}; + +static +int qemudBufferAdd(struct qemudBuffer *buf, const char *str) { + int need = strlen(str); + + if ((need+1) > (buf->len-buf->used)) { + return -1; + } + + memcpy(buf->data + buf->used, str, need+1); + buf->used += need; + + return 0; +} + + +static +int qemudBufferPrintf(struct qemudBuffer *buf, + const char *format, ...) { + int size, count; + va_list locarg, argptr; + + if ((format == NULL) || (buf == NULL)) { + return -1; + } + size = buf->len - buf->used - 1; + va_start(argptr, format); + va_copy(locarg, argptr); + + if ((count = vsnprintf(&buf->data[buf->used], + size, + format, + locarg)) >= size) { + return -1; + } + va_end(locarg); + buf->used += count; + + buf->data[buf->used] = '\0'; + return 0; +} + +char *qemudGenerateXML(struct qemud_vm *vm) { + struct qemudBuffer buf; + unsigned char *uuid; + struct qemud_vm_disk_def *disk; + struct qemud_vm_net_def *net; + + buf.len = QEMUD_MAX_XML_LEN; + buf.used = 0; + buf.data = malloc(buf.len); + + if (vm->def.id >= 0) { + if (qemudBufferPrintf(&buf, "<domain type='qemu' id='%d'>\n", vm->def.id) < 0) + goto cleanup; + } else { + if (qemudBufferAdd(&buf, "<domain type='qemu'>\n") < 0) + goto cleanup; + } + + if (qemudBufferPrintf(&buf, " <name>%s</name>\n", vm->def.name) < 0) + goto cleanup; + + uuid = vm->def.uuid; + if (qemudBufferPrintf(&buf, " <uuid>%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x</uuid>\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]) < 0) + goto cleanup; + if (qemudBufferPrintf(&buf, " <memory>%d</memory>\n", vm->def.memory) < 0) + goto cleanup; + if (qemudBufferPrintf(&buf, " <vcpu>%d</vcpu>\n", vm->def.vcpus) < 0) + goto cleanup; + + if (qemudBufferAdd(&buf, " <devices>\n") < 0) + goto cleanup; + + disk = vm->def.disks; + while (disk) { + const char *types[] = { + "block", + "file", + }; + const char *typeAttrs[] = { + "dev", + "file", + }; + const char *devices[] = { + "disk", + "cdrom", + "floppy", + }; + if (qemudBufferPrintf(&buf, " <disk type='%s' device='%s'>\n", + types[disk->type], devices[disk->device]) < 0) + goto cleanup; + + if (qemudBufferPrintf(&buf, " <source %s='%s'/>\n", typeAttrs[disk->type], disk->src) < 0) + goto cleanup; + + if (qemudBufferPrintf(&buf, " <target dev='%s'/>\n", disk->dst) < 0) + goto cleanup; + + if (disk->readonly) + if (qemudBufferAdd(&buf, " <readonly/>\n") < 0) + goto cleanup; + + if (qemudBufferPrintf(&buf, " </disk>\n") < 0) + goto cleanup; + + disk = disk->next; + } + + net = vm->def.nets; + + if (vm->def.graphicsType == QEMUD_GRAPHICS_VNC) { + if (vm->def.vncPort) { + qemudBufferPrintf(&buf, " <graphics type='vnc' port='%d'/>\n", vm->def.vncPort); + } else { + qemudBufferPrintf(&buf, " <graphics type='vnc'/>\n"); + } + } + + if (qemudBufferAdd(&buf, " </devices>\n") < 0) + goto cleanup; + + + if (qemudBufferAdd(&buf, "</domain>\n") < 0) + goto cleanup; + + + + + return buf.data; + + cleanup: + printf("Fail\n"); + free(buf.data); + return NULL; +} + + +int qemudDeleteConfigXML(struct qemud_vm *vm) { + if (!vm->configFile[0]) + return -1; + + printf("Delete VM %s\n", vm->configFile); + + if (unlink(vm->configFile) < 0) + return -1; + + vm->configFile[0] = '\0'; + + return 0; +} diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/qemud/config.h libvirt-new/qemud/config.h --- libvirt-orig/qemud/config.h 1969-12-31 19:00:00.000000000 -0500 +++ libvirt-new/qemud/config.h 2006-08-27 18:10:25.000000000 -0400 @@ -0,0 +1,22 @@ + +#ifndef __QEMUD_CONFIG_H +#define __QEMUD_CONFIG_H + +#include "internal.h" + +int qemudBuildCommandLine(struct qemud_vm *vm, + char ***argv, + int *argc); + +void qemudFreeVM(struct qemud_vm *vm); +struct qemud_vm *qemudLoadConfigXML(struct qemud_server *server, + const char *file, + const char *doc, + int persist); +int qemudScanConfigs(struct qemud_server *server); +char *qemudGenerateXML(struct qemud_vm *vm); + +int qemudDeleteConfigXML(struct qemud_vm *vm); + + +#endif diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/qemud/dispatch.c libvirt-new/qemud/dispatch.c --- libvirt-orig/qemud/dispatch.c 1969-12-31 19:00:00.000000000 -0500 +++ libvirt-new/qemud/dispatch.c 2006-08-27 17:05:39.000000000 -0400 @@ -0,0 +1,442 @@ + +#include <limits.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <libvirt/virterror.h> + +#include "internal.h" +#include "driver.h" +#include "dispatch.h" + + +static int qemudDispatchFailure(struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + struct qemud_packet *out) { + out->header.type = QEMUD_PKT_FAILURE; + out->header.dataSize = sizeof(out->data.failureReply); + /* XXX add code/message */ + out->data.failureReply.code = -1; + out->data.failureReply.message[0] = '\0'; + return 0; +} + +static int qemudDispatchGetProtocolVersion(struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != 0) + return -1; + + out->header.type = QEMUD_PKT_GET_PROTOCOL_VERSION; + out->header.dataSize = sizeof(out->data.getProtocolVersionReply); + out->data.getProtocolVersionReply.version = QEMUD_PROTOCOL_VERSION; + return 0; +} + +static int qemudDispatchGetVersion(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != 0) + return -1; + + int version = qemudGetVersion(server); + if (version < 0) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_GET_VERSION; + out->header.dataSize = sizeof(out->data.getVersionReply); + out->data.getVersionReply.version = version; + } + return 0; +} +static int qemudDispatchListDomains(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != 0) + return -1; + + int ndomains = qemudListDomains(server, + out->data.listDomainsReply.domains, + QEMUD_MAX_NUM_DOMAINS); + if (ndomains < 0) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_LIST_DOMAINS; + out->header.dataSize = sizeof(out->data.listDomainsReply); + out->data.listDomainsReply.numDomains = ndomains; + } + return 0; +} +static int qemudDispatchNumDomains(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != 0) + return -1; + + int ndomains = qemudNumDomains(server); + if (ndomains < 0) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_NUM_DOMAINS; + out->header.dataSize = sizeof(out->data.numDomainsReply); + out->data.numDomainsReply.numDomains = ndomains; + } + return 0; +} +static int qemudDispatchDomainCreate(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != sizeof(in->data.domainCreateRequest)) + return -1; + + in->data.domainCreateRequest.xml[QEMUD_MAX_XML_LEN-1] ='\0'; + + struct qemud_vm *vm = qemudDomainCreate(server, in->data.domainCreateRequest.xml); + if (!vm) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_DOMAIN_CREATE; + out->header.dataSize = sizeof(out->data.domainCreateReply); + out->data.domainCreateReply.id = vm->def.id; + memcpy(out->data.domainCreateReply.uuid, vm->def.uuid, QEMUD_UUID_RAW_LEN); + strncpy(out->data.domainCreateReply.name, vm->def.name, QEMUD_MAX_NAME_LEN-1); + out->data.domainCreateReply.name[QEMUD_MAX_NAME_LEN-1] = '\0'; + } + return 0; +} +static int qemudDispatchDomainLookupByID(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != sizeof(in->data.domainLookupByIDRequest)) + return -1; + + struct qemud_vm *vm = qemudFindVMByID(server, in->data.domainLookupByIDRequest.id); + if (!vm) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_DOMAIN_LOOKUP_BY_ID; + out->header.dataSize = sizeof(out->data.domainLookupByIDReply); + memcpy(out->data.domainLookupByIDReply.uuid, vm->def.uuid, QEMUD_UUID_RAW_LEN); + strncpy(out->data.domainLookupByIDReply.name, vm->def.name, QEMUD_MAX_NAME_LEN-1); + out->data.domainLookupByIDReply.name[QEMUD_MAX_NAME_LEN-1] = '\0'; + } + return 0; +} +static int qemudDispatchDomainLookupByUUID(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != sizeof(in->data.domainLookupByUUIDRequest)) + return -1; + + struct qemud_vm *vm = qemudFindVMByUUID(server, in->data.domainLookupByUUIDRequest.uuid); + if (!vm) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_DOMAIN_LOOKUP_BY_UUID; + out->header.dataSize = sizeof(out->data.domainLookupByUUIDReply); + out->data.domainLookupByUUIDReply.id = vm->def.id; + strncpy(out->data.domainLookupByUUIDReply.name, vm->def.name, QEMUD_MAX_NAME_LEN-1); + out->data.domainLookupByUUIDReply.name[QEMUD_MAX_NAME_LEN-1] = '\0'; + } + return 0; +} +static int qemudDispatchDomainLookupByName(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != sizeof(in->data.domainLookupByNameRequest)) + return -1; + + /* Paranoia NULL termination */ + in->data.domainLookupByNameRequest.name[QEMUD_MAX_NAME_LEN-1] = '\0'; + struct qemud_vm *vm = qemudFindVMByName(server, in->data.domainLookupByNameRequest.name); + if (!vm) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_DOMAIN_LOOKUP_BY_NAME; + out->header.dataSize = sizeof(out->data.domainLookupByNameReply); + out->data.domainLookupByNameReply.id = vm->def.id; + memcpy(out->data.domainLookupByNameReply.uuid, vm->def.uuid, QEMUD_UUID_RAW_LEN); + } + return 0; +} +static int qemudDispatchDomainSuspend(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != sizeof(in->data.domainSuspendRequest)) + return -1; + + int ret = qemudDomainSuspend(server, in->data.domainSuspendRequest.id); + if (ret < 0) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_DOMAIN_SUSPEND; + out->header.dataSize = 0; + } + return 0; +} +static int qemudDispatchDomainResume(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != sizeof(in->data.domainResumeRequest)) + return -1; + + int ret = qemudDomainResume(server, in->data.domainResumeRequest.id); + if (ret < 0) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_DOMAIN_RESUME; + out->header.dataSize =0; + } + return 0; +} +static int qemudDispatchDomainDestroy(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != sizeof(in->data.domainDestroyRequest)) + return -1; + + int ret = qemudDomainDestroy(server, in->data.domainDestroyRequest.id); + if (ret < 0) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_DOMAIN_DESTROY; + out->header.dataSize = 0; + } + return 0; +} +static int qemudDispatchDomainGetInfo(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != sizeof(in->data.domainGetInfoRequest)) + return -1; + + int ret = qemudDomainGetInfo(server, in->data.domainGetInfoRequest.uuid, + &out->data.domainGetInfoReply.runstate, + &out->data.domainGetInfoReply.cpuTime, + &out->data.domainGetInfoReply.memory, + &out->data.domainGetInfoReply.nrVirtCpu); + if (ret < 0) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_DOMAIN_GET_INFO; + out->header.dataSize = sizeof(out->data.domainGetInfoReply); + } + return 0; +} +static int qemudDispatchDomainSave(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != sizeof(in->data.domainSaveRequest)) + return -1; + + /* Paranoia NULL termination */ + in->data.domainSaveRequest.file[PATH_MAX-1] ='\0'; + + int ret = qemudDomainSave(server, + in->data.domainSaveRequest.id, + in->data.domainSaveRequest.file); + if (ret < 0) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_DOMAIN_SAVE; + out->header.dataSize = 0; + } + return 0; +} +static int qemudDispatchDomainRestore(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != sizeof(in->data.domainRestoreRequest)) + return -1; + + /* Paranoia null termination */ + in->data.domainRestoreRequest.file[PATH_MAX-1] ='\0'; + + int id = qemudDomainRestore(server, in->data.domainRestoreRequest.file); + if (id < 0) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_DOMAIN_RESTORE; + out->header.dataSize = sizeof(out->data.domainRestoreReply); + out->data.domainRestoreReply.id = id; + } + return 0; +} +static int qemudDispatchDumpXML(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != sizeof(in->data.domainDumpXMLRequest)) + return -1; + + int ret = qemudDomainDumpXML(server, in->data.domainDumpXMLRequest.uuid, + out->data.domainDumpXMLReply.xml, QEMUD_MAX_XML_LEN); + if (ret < 0) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_DUMP_XML; + out->header.dataSize = sizeof(out->data.domainDumpXMLReply); + } + return 0; +} +static int qemudDispatchListDefinedDomains(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + char **names; + int i; + if (in->header.dataSize != 0) + return -1; + + if (!(names = malloc(sizeof(char *)*QEMUD_MAX_NUM_DOMAINS))) + return -1; + + for (i = 0 ; i < QEMUD_MAX_NUM_DOMAINS ; i++) { + names[i] = out->data.listDefinedDomainsReply.domains[i]; + } + + int ndomains = qemudListDefinedDomains(server, + names, + QEMUD_MAX_NUM_DOMAINS); + free(names); + if (ndomains < 0) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_LIST_DEFINED_DOMAINS; + out->header.dataSize = sizeof(out->data.listDefinedDomainsReply); + out->data.listDefinedDomainsReply.numDomains = ndomains; + } + return 0; +} +static int qemudDispatchNumDefinedDomains(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != 0) + return -1; + + int ndomains = qemudNumDefinedDomains(server); + if (ndomains < 0) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_NUM_DEFINED_DOMAINS; + out->header.dataSize = sizeof(out->data.numDefinedDomainsReply); + out->data.numDefinedDomainsReply.numDomains = ndomains; + } + return 0; +} +static int qemudDispatchDomainStart(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != sizeof(in->data.domainStartRequest)) + return -1; + + struct qemud_vm *vm = qemudFindVMByUUID(server, in->data.domainStartRequest.uuid); + if (!vm || qemudDomainStart(server, vm) < 0) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_DOMAIN_START; + out->header.dataSize = sizeof(out->data.domainStartReply); + out->data.domainStartReply.id = vm->def.id; + } + return 0; +} +static int qemudDispatchDomainDefine(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != sizeof(in->data.domainDefineRequest)) + return -1; + + in->data.domainDefineRequest.xml[QEMUD_MAX_XML_LEN-1] ='\0'; + + struct qemud_vm *vm = qemudDomainDefine(server, in->data.domainDefineRequest.xml); + if (!vm) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_DOMAIN_DEFINE; + out->header.dataSize = sizeof(out->data.domainDefineReply); + memcpy(out->data.domainDefineReply.uuid, vm->def.uuid, QEMUD_UUID_RAW_LEN); + strncpy(out->data.domainDefineReply.name, vm->def.name, QEMUD_MAX_NAME_LEN-1); + out->data.domainDefineReply.name[QEMUD_MAX_NAME_LEN-1] = '\0'; + } + return 0; +} +static int qemudDispatchDomainUndefine(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + if (in->header.dataSize != sizeof(in->data.domainUndefineRequest)) + return -1; + + int ret = qemudDomainUndefine(server, in->data.domainUndefineRequest.uuid); + if (ret < 0) { + if (qemudDispatchFailure(server, client, out) < 0) + return -1; + } else { + out->header.type = QEMUD_PKT_DOMAIN_UNDEFINE; + out->header.dataSize = 0; + } + return 0; +} + + +typedef int (*clientFunc)(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out); + + +/* One per message type recorded in qemud_packet_type enum */ +clientFunc funcs[] = { + NULL, /* FAILURE code */ + qemudDispatchGetProtocolVersion, + qemudDispatchGetVersion, + qemudDispatchListDomains, + qemudDispatchNumDomains, + qemudDispatchDomainCreate, + qemudDispatchDomainLookupByID, + qemudDispatchDomainLookupByUUID, + qemudDispatchDomainLookupByName, + qemudDispatchDomainSuspend, + qemudDispatchDomainResume, + qemudDispatchDomainDestroy, + qemudDispatchDomainGetInfo, + qemudDispatchDomainSave, + qemudDispatchDomainRestore, + qemudDispatchDumpXML, + qemudDispatchListDefinedDomains, + qemudDispatchNumDefinedDomains, + qemudDispatchDomainStart, + qemudDispatchDomainDefine, + qemudDispatchDomainUndefine +}; + +/* + * Returns -1 if message processing failed - eg, illegal header sizes, + * a memory error dealing with stuff, or any other bad stuff which + * should trigger immediate client disconnect + * + * Return 0 if message processing succeeded. NB, this does not mean + * the operation itself succeeded - success/failure of the operation + * is recorded by the return message type - either it matches the + * incoming type, or is QEMUD_PKT_FAILURE + */ +int qemudDispatch(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out) { + printf("> Dispatching request %d\n", in->header.type); + + memset(out, 0, sizeof(struct qemud_packet)); + + if (in->header.type >= (sizeof(funcs)/sizeof(clientFunc))) { + printf("Illegal request type\n"); + return -1; + } + + if (in->header.type == QEMUD_PKT_FAILURE) { + printf("Illegal request type\n"); + return -1; + } + + if ((funcs[in->header.type])(server, client, in, out) < 0) { + printf("Dispatch failed\n"); + return -1; + } + + printf("< Returning reply %d (%d bytes)\n", + out->header.type, out->header.dataSize); + + return 0; +} diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/qemud/dispatch.h libvirt-new/qemud/dispatch.h --- libvirt-orig/qemud/dispatch.h 1969-12-31 19:00:00.000000000 -0500 +++ libvirt-new/qemud/dispatch.h 2006-08-27 17:05:39.000000000 -0400 @@ -0,0 +1,11 @@ + +#ifndef QEMUD_DISPATCH_H +#define QEMUD_DISPATCH_H + +#include "internal.h" + + +int qemudDispatch(struct qemud_server *server, struct qemud_client *client, + struct qemud_packet *in, struct qemud_packet *out); + +#endif diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/qemud/driver.c libvirt-new/qemud/driver.c --- libvirt-orig/qemud/driver.c 1969-12-31 19:00:00.000000000 -0500 +++ libvirt-new/qemud/driver.c 2006-08-27 17:05:39.000000000 -0400 @@ -0,0 +1,267 @@ + +#include <sys/types.h> +#include <dirent.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> + +#include "internal.h" +#include "driver.h" +#include "config.h" + +struct qemud_vm *qemudFindVMByID(const struct qemud_server *server, int id) { + struct qemud_vm *vm = server->activevms; + + while (vm) { + if (vm->def.id == id) + return vm; + vm = vm->next; + } + + return NULL; +} + +struct qemud_vm *qemudFindVMByUUID(const struct qemud_server *server, + const unsigned char *uuid) { + struct qemud_vm *vm = server->activevms; + + while (vm) { + if (!memcmp(vm->def.uuid, uuid, QEMUD_UUID_RAW_LEN)) + return vm; + vm = vm->next; + } + + vm = server->inactivevms; + while (vm) { + if (!memcmp(vm->def.uuid, uuid, QEMUD_UUID_RAW_LEN)) + return vm; + vm = vm->next; + } + + return NULL; +} + +struct qemud_vm *qemudFindVMByName(const struct qemud_server *server, + const char *name) { + struct qemud_vm *vm = server->activevms; + + while (vm) { + if (!strcmp(vm->def.name, name)) + return vm; + vm = vm->next; + } + + vm = server->inactivevms; + while (vm) { + if (!strcmp(vm->def.name, name)) + return vm; + vm = vm->next; + } + + return NULL; +} + +int qemudGetVersion(struct qemud_server *server) { + return server->qemuVersion; +} + +int qemudListDomains(struct qemud_server *server, int *ids, int nids) { + struct qemud_vm *vm = server->activevms; + int got = 0; + while (vm && got < nids) { + ids[got] = vm->def.id; + vm = vm->next; + got++; + } + return got; +} +int qemudNumDomains(struct qemud_server *server) { + return server->nactivevms; +} +struct qemud_vm *qemudDomainCreate(struct qemud_server *server, const char *xml) { + struct qemud_vm *vm; + + if (!(vm = qemudLoadConfigXML(server, NULL, xml, 0))) { + return NULL; + } + + if (qemudStartVMDaemon(server, vm) < 0) { + qemudFreeVM(vm); + return NULL; + } + + vm->next = server->activevms; + server->activevms = vm; + server->nactivevms++; + server->nvmfds += 2; + + return vm; +} + +int qemudDomainSuspend(struct qemud_server *server, int id) { + struct qemud_vm *vm = qemudFindVMByID(server, id); + if (!vm) + return -1; + if (vm->pid == -1) + return -1; + return -1; +} + +int qemudDomainResume(struct qemud_server *server, int id) { + struct qemud_vm *vm = qemudFindVMByID(server, id); + if (!vm) + return -1; + if (vm->pid == -1) + return -1; + return -1; +} + +int qemudDomainDestroy(struct qemud_server *server, int id) { + struct qemud_vm *vm = qemudFindVMByID(server, id); + if (!vm) + return -1; + if (vm->pid == -1) + return -1; + + if (qemudShutdownVMDaemon(server, vm) < 0) + return -1; + return 0; +} + +int qemudDomainGetInfo(struct qemud_server *server, const unsigned char *uuid, + int *runstate, + unsigned long long *cputime, + unsigned long *memory, + unsigned int *nrVirtCpu) { + struct qemud_vm *vm = qemudFindVMByUUID(server, uuid); + if (!vm) + return -1; + + if (vm->pid == -1) { + *runstate = QEMUD_STATE_STOPPED; + } else { + /* XXX in future need to add PAUSED */ + *runstate = QEMUD_STATE_RUNNING; + } + + *cputime = 0; + *memory = vm->def.memory; + *nrVirtCpu = vm->def.vcpus; + return 0; +} +int qemudDomainSave(struct qemud_server *server, int id, + const char *path ATTRIBUTE_UNUSED) { + struct qemud_vm *vm = qemudFindVMByID(server, id); + if (!vm) + return -1; + if (vm->pid == -1) + return -1; + return -1; +} +int qemudDomainRestore(struct qemud_server *server ATTRIBUTE_UNUSED, + const char *path ATTRIBUTE_UNUSED) { + + return -1; +} +int qemudDomainDumpXML(struct qemud_server *server, const unsigned char *uuid, char *xml, int xmllen) { + struct qemud_vm *vm = qemudFindVMByUUID(server, uuid); + char *vmxml; + if (!vm) + return -1; + + vmxml = qemudGenerateXML(vm); + if (!vmxml) + return -1; + + strncpy(xml, vmxml, xmllen); + xml[xmllen-1] = '\0'; + + return 0; +} +int qemudListDefinedDomains(struct qemud_server *server, char *const*names, int nnames) { + struct qemud_vm *vm = server->inactivevms; + int got = 0; + while (vm && got < nnames) { + strncpy(names[got], vm->def.name, QEMUD_MAX_NAME_LEN-1); + names[got][QEMUD_MAX_NAME_LEN-1] = '\0'; + vm = vm->next; + got++; + } + return got; +} +int qemudNumDefinedDomains(struct qemud_server *server) { + return server->ninactivevms; +} +int qemudDomainStart(struct qemud_server *server, struct qemud_vm *vm) { + struct qemud_vm *prev = NULL, *curr = server->inactivevms; + if (qemudStartVMDaemon(server, vm) < 0) { + return 1; + } + + while (curr) { + if (curr == vm) { + if (prev) + prev->next = curr->next; + else + server->inactivevms = curr->next; + server->ninactivevms--; + break; + } + prev = curr; + curr = curr->next; + } + + vm->next = server->activevms; + server->activevms = vm; + server->nactivevms++; + server->nvmfds += 2; + + return 0; +} + +struct qemud_vm *qemudDomainDefine(struct qemud_server *server, const char *xml) { + struct qemud_vm *vm; + + if (!(vm = qemudLoadConfigXML(server, NULL, xml, 1))) { + return NULL; + } + + vm->next = server->inactivevms; + server->inactivevms = vm; + server->ninactivevms++; + + return vm; +} + +int qemudDomainUndefine(struct qemud_server *server, const unsigned char *uuid) { + struct qemud_vm *vm = qemudFindVMByUUID(server, uuid); + struct qemud_vm *prev = NULL, *curr = server->inactivevms; + + if (!vm) + return -1; + + if (vm->pid != -1) + return -1; + + if (qemudDeleteConfigXML(vm) < 0) + return -1; + + while (curr) { + if (curr == vm) { + if (prev) { + prev->next = curr->next; + } else { + server->inactivevms = curr->next; + } + server->ninactivevms--; + break; + } + + prev = curr; + curr = curr->next; + } + + qemudFreeVM(vm); + + return 0; +} diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/qemud/driver.h libvirt-new/qemud/driver.h --- libvirt-orig/qemud/driver.h 1969-12-31 19:00:00.000000000 -0500 +++ libvirt-new/qemud/driver.h 2006-08-27 17:05:39.000000000 -0400 @@ -0,0 +1,53 @@ + +#ifndef QEMUD_DRIVER_H +#define QEMUD_DRIVER_H + +#include "internal.h" + +struct qemud_vm *qemudFindVMByID(const struct qemud_server *server, + int id); +struct qemud_vm *qemudFindVMByUUID(const struct qemud_server *server, + const unsigned char *uuid); +struct qemud_vm *qemudFindVMByName(const struct qemud_server *server, + const char *name); + +int qemudGetVersion(struct qemud_server *server); +int qemudListDomains(struct qemud_server *server, + int *ids, + int nids); +int qemudNumDomains(struct qemud_server *server); +struct qemud_vm *qemudDomainCreate(struct qemud_server *server, + const char *xml); +int qemudDomainSuspend(struct qemud_server *server, + int id); +int qemudDomainResume(struct qemud_server *server, + int id); +int qemudDomainDestroy(struct qemud_server *server, + int id); +int qemudDomainGetInfo(struct qemud_server *server, + const unsigned char *uuid, + int *runstate, + unsigned long long *cputime, + unsigned long *memory, + unsigned int *nrVirtCpu); +int qemudDomainSave(struct qemud_server *server, + int id, + const char *path); +int qemudDomainRestore(struct qemud_server *server, + const char *path); +int qemudDomainDumpXML(struct qemud_server *server, + const unsigned char *uuid, + char *xml, + int xmllen); +int qemudListDefinedDomains(struct qemud_server *server, + char *const*names, + int nnames); +int qemudNumDefinedDomains(struct qemud_server *server); +int qemudDomainStart(struct qemud_server *server, + struct qemud_vm *vm); +struct qemud_vm *qemudDomainDefine(struct qemud_server *server, + const char *xml); +int qemudDomainUndefine(struct qemud_server *server, + const unsigned char *uuid); + +#endif diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/qemud/internal.h libvirt-new/qemud/internal.h --- libvirt-orig/qemud/internal.h 1969-12-31 19:00:00.000000000 -0500 +++ libvirt-new/qemud/internal.h 2006-08-27 17:58:39.000000000 -0400 @@ -0,0 +1,161 @@ + +#ifndef QEMUD_INTERNAL_H__ +#define QEMUD_INTERNAL_H__ + +#include <sys/socket.h> +#include <netinet/in.h> + +#include "protocol.h" + +#ifdef __GNUC__ +#ifdef HAVE_ANSIDECL_H +#include <ansidecl.h> +#endif +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED __attribute__((unused)) +#endif +#else +#define ATTRIBUTE_UNUSED +#endif + + +#define UUID_LEN 16 + +struct qemud_client { + int fd; + int readonly; + struct qemud_packet incoming; + unsigned int incomingReceived; + struct qemud_packet outgoing; + unsigned int outgoingSent; + int tx; + struct qemud_client *next; +}; + + +enum qmeud_vm_disk_type { + QEMUD_DISK_BLOCK, + QEMUD_DISK_FILE +}; + +enum qemud_vm_disk_device { + QEMUD_DISK_DISK, + QEMUD_DISK_CDROM, + QEMUD_DISK_FLOPPY, +}; + +struct qemud_vm_disk_def { + int type; + int device; + char src[PATH_MAX]; + char dst[NAME_MAX]; + int readonly; + + struct qemud_vm_disk_def *next; +}; + +#define QEMUD_MAC_ADDRESS_LEN 6 + +enum qemud_vm_net_type { + QEMUD_NET_USER, + QEMUD_NET_TAP, + QEMUD_NET_SERVER, + QEMUD_NET_CLIENT, + QEMUD_NET_MCAST, + QEMUD_NET_VDE +}; + +struct qemud_vm_net_def { + int type; + int vlan; + unsigned char mac[QEMUD_MAC_ADDRESS_LEN]; + union { + struct { + char ifname[NAME_MAX]; + char script[PATH_MAX]; + } tap; + struct { + struct sockaddr_in listen; + int port; + } server; + struct { + struct sockaddr_in connect; + int port; + } client; + struct { + struct sockaddr_in group; + int port; + } mcast; + struct { + char vlan[PATH_MAX]; + } vde; + } dst; + + struct qemud_vm_net_def *next; +}; + +enum qemud_vm_boot_order { + QEMUD_BOOT_FLOPPY, + QEMUD_BOOT_CDROM, + QEMUD_BOOT_DISK +}; + +enum qemud_vm_grapics_type { + QEMUD_GRAPHICS_NONE, + QEMUD_GRAPHICS_VNC +}; + +struct qemud_vm_def { + int id; + unsigned char uuid[QEMUD_UUID_RAW_LEN]; + char name[QEMUD_MAX_NAME_LEN]; + + int memory; + int vcpus; + + int bootOrder[3]; + + int graphicsType; + int vncPort; + + int ndisks; + struct qemud_vm_disk_def *disks; + + int nnets; + struct qemud_vm_net_def *nets; +}; + +struct qemud_vm { + int stdout; + int stderr; + int monitor; + int pid; + + char configFile[PATH_MAX]; + + struct qemud_vm_def def; + + struct qemud_vm *next; +}; + +struct qemud_server { + int fd; + int qemuVersion; + int nclients; + struct qemud_client *clients; + int nvmfds; + int nactivevms; + struct qemud_vm *activevms; + int ninactivevms; + struct qemud_vm *inactivevms; + int nextvmid; + char configDir[PATH_MAX]; +}; + +int qemudStartVMDaemon(struct qemud_server *server, + struct qemud_vm *vm); + +int qemudShutdownVMDaemon(struct qemud_server *server, + struct qemud_vm *vm); + +#endif diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/qemud/Makefile.am libvirt-new/qemud/Makefile.am --- libvirt-orig/qemud/Makefile.am 1969-12-31 19:00:00.000000000 -0500 +++ libvirt-new/qemud/Makefile.am 2006-08-27 17:54:39.000000000 -0400 @@ -0,0 +1,17 @@ +## Process this file with automake to produce Makefile.in + +INCLUDES = @LIBXML_CFLAGS@ + +libexec_PROGRAMS = qemud + +qemud_SOURCES = qemud.c internal.h protocol.h \ + driver.c driver.h \ + dispatch.c dispatch.h \ + config.c config.h +qemud_CFLAGS = -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_POSIX_C_SOURCE=199506L -std=c99 \ + -I$(top_srcdir)/include -I$(top_builddir)/include $(LIBXML_CFLAGS) \ + -Werror -Wall -Wextra +qemud_LDFLAGS = $(LIBXML_LIBS) +qemud_DEPENDENCIES = +qemud_LDADD = + diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/qemud/protocol.h libvirt-new/qemud/protocol.h --- libvirt-orig/qemud/protocol.h 1969-12-31 19:00:00.000000000 -0500 +++ libvirt-new/qemud/protocol.h 2006-08-27 17:05:39.000000000 -0400 @@ -0,0 +1,166 @@ + +#ifndef QEMUD_PROTOCOL_H__ +#define QEMUD_PROTOCOL_H__ + +enum { + QEMUD_PKT_FAILURE, + QEMUD_PKT_GET_PROTOCOL_VERSION, + QEMUD_PKT_GET_VERSION, + QEMUD_PKT_LIST_DOMAINS, + QEMUD_PKT_NUM_DOMAINS, + QEMUD_PKT_DOMAIN_CREATE, + QEMUD_PKT_DOMAIN_LOOKUP_BY_ID, + QEMUD_PKT_DOMAIN_LOOKUP_BY_UUID, + QEMUD_PKT_DOMAIN_LOOKUP_BY_NAME, + QEMUD_PKT_DOMAIN_SUSPEND, + QEMUD_PKT_DOMAIN_RESUME, + QEMUD_PKT_DOMAIN_DESTROY, + QEMUD_PKT_DOMAIN_GET_INFO, + QEMUD_PKT_DOMAIN_SAVE, + QEMUD_PKT_DOMAIN_RESTORE, + QEMUD_PKT_DUMP_XML, + QEMUD_PKT_LIST_DEFINED_DOMAINS, + QEMUD_PKT_NUM_DEFINED_DOMAINS, + QEMUD_PKT_DOMAIN_START, + QEMUD_PKT_DOMAIN_DEFINE, + QEMUD_PKT_DOMAIN_UNDEFINE, + QEMUD_PKT_MAX +} qemud_packet_type; + + +#define QEMUD_PROTOCOL_VERSION 1 +#define QEMUD_UUID_RAW_LEN 16 +#define QEMUD_MAX_NAME_LEN 50 +#define QEMUD_MAX_XML_LEN 4096 +#define QEMUD_MAX_NUM_DOMAINS 100 +#define QEMUD_MAX_ERROR_LEN 1024 + +enum { + QEMUD_STATE_RUNNING = 1, + QEMUD_STATE_PAUSED, + QEMUD_STATE_STOPPED, +} qemud_domain_runstate; + +struct qemud_packet_header { + unsigned int type; + /* Stores the size of the data struct matching + the type arg. + Must be <= sizeof(union qemudPacketData) */ + unsigned int dataSize; +}; + +union qemud_packet_data { + struct { + int code; + char message[QEMUD_MAX_ERROR_LEN]; + } failureReply; + struct { + int version; + } getProtocolVersionReply; + struct { + int version; + } getVersionReply; + struct { + int numDomains; + int domains[QEMUD_MAX_NUM_DOMAINS]; + } listDomainsReply; + struct { + int numDomains; + } numDomainsReply; + struct { + char xml[QEMUD_MAX_XML_LEN]; + } domainCreateRequest; + struct { + int id; + unsigned char uuid[QEMUD_UUID_RAW_LEN]; + char name[QEMUD_MAX_NAME_LEN]; + } domainCreateReply; + struct { + int id; + } domainLookupByIDRequest; + struct { + unsigned char uuid[QEMUD_UUID_RAW_LEN]; + char name[QEMUD_MAX_NAME_LEN]; + } domainLookupByIDReply; + struct { + char name[QEMUD_MAX_NAME_LEN]; + } domainLookupByNameRequest; + struct { + int id; + unsigned char uuid[QEMUD_UUID_RAW_LEN]; + } domainLookupByNameReply; + struct { + unsigned char uuid[QEMUD_UUID_RAW_LEN]; + } domainLookupByUUIDRequest; + struct { + int id; + char name[QEMUD_MAX_NAME_LEN]; + } domainLookupByUUIDReply; + struct { + int id; + } domainSuspendRequest; + struct { + int id; + } domainResumeRequest; + struct { + } domainResumeReply; + struct { + int id; + } domainDestroyRequest; + struct { + unsigned char uuid[QEMUD_UUID_RAW_LEN]; + } domainGetInfoRequest; + struct { + int runstate; + unsigned long long cpuTime; + unsigned long memory; + unsigned int nrVirtCpu; + } domainGetInfoReply; + struct { + int id; + char file[PATH_MAX]; + } domainSaveRequest; + struct { + char file[PATH_MAX]; + } domainRestoreRequest; + struct { + int id; + } domainRestoreReply; + struct { + unsigned char uuid[QEMUD_UUID_RAW_LEN]; + } domainDumpXMLRequest; + struct { + char xml[QEMUD_MAX_XML_LEN]; + } domainDumpXMLReply; + struct { + int numDomains; + char domains[QEMUD_MAX_NUM_DOMAINS][QEMUD_MAX_NAME_LEN]; + } listDefinedDomainsReply; + struct { + int numDomains; + } numDefinedDomainsReply; + struct { + unsigned char uuid[QEMUD_UUID_RAW_LEN]; + } domainStartRequest; + struct { + int id; + } domainStartReply; + struct { + char xml[QEMUD_MAX_XML_LEN]; + } domainDefineRequest; + struct { + unsigned char uuid[QEMUD_UUID_RAW_LEN]; + char name[QEMUD_MAX_NAME_LEN]; + } domainDefineReply; + struct { + unsigned char uuid[QEMUD_UUID_RAW_LEN]; + } domainUndefineRequest; +}; + +struct qemud_packet { + struct qemud_packet_header header; + union qemud_packet_data data; +}; + + +#endif diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/qemud/qemud.c libvirt-new/qemud/qemud.c --- libvirt-orig/qemud/qemud.c 1969-12-31 19:00:00.000000000 -0500 +++ libvirt-new/qemud/qemud.c 2006-08-27 17:54:02.000000000 -0400 @@ -0,0 +1,685 @@ + +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <paths.h> +#include <limits.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/poll.h> +#include <stdlib.h> +#include <pwd.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include "internal.h" +#include "dispatch.h" +#include "config.h" + +static void reapchild(int sig ATTRIBUTE_UNUSED) { + /* We explicitly waitpid the child later */ +} + +static int qemudSetCloseExec(int fd) { + int flags; + if ((flags = fcntl(fd, F_GETFD)) < 0) { + return -1; + } + flags |= FD_CLOEXEC; + if ((fcntl(fd, F_SETFD, flags)) < 0) { + return -1; + } + return 0; +} + + +static int qemudSetNonBlock(int fd) { + int flags; + if ((flags = fcntl(fd, F_GETFL)) < 0) { + return -1; + } + flags |= O_NONBLOCK; + if ((fcntl(fd, F_SETFL, flags)) < 0) { + return -1; + } + return 0; +} + +static int qemudGoDaemon(void) { + int pid = fork(); + switch (pid) { + case 0: + { + int stdinfd = -1; + int stdoutfd = -1; + if ((stdinfd = open(_PATH_DEVNULL, O_RDONLY)) < 0) + goto cleanup; + if ((stdoutfd = open(_PATH_DEVNULL, O_WRONLY)) < 0) + goto cleanup; + if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO) + goto cleanup; + if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO) + goto cleanup; + if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO) + goto cleanup; + if (close(stdinfd) < 0) + goto cleanup; + stdinfd = -1; + if (close(stdoutfd) < 0) + goto cleanup; + stdoutfd = -1; + + int open_max = sysconf (_SC_OPEN_MAX); + for (int i = 0; i < open_max; i++) + if (i != STDIN_FILENO && + i != STDOUT_FILENO && + i != STDERR_FILENO) + close(i); + + if (setsid() < 0) + goto cleanup; + + int nextpid = fork(); + switch (nextpid) { + case 0: + return 0; + case -1: + return -1; + default: + return nextpid; + } + + cleanup: + if (stdoutfd != -1) + close(stdoutfd); + if (stdinfd != -1) + close(stdinfd); + return -1; + + } + + case -1: + return -1; + + default: + { + int got, status = 0; + /* We wait to make sure the next child forked + successfully */ + if ((got = waitpid(pid, &status, 0)) < 0 || + got != pid || + status != 0) { + return -1; + } + + return pid; + } + } +} + +static struct qemud_server *qemudInitialize(void) { + struct qemud_server *server; + struct passwd *pw; + int uid, ret; + char path[PATH_MAX]; + struct sockaddr_un addr; + + if (!(server = calloc(1, sizeof(struct qemud_server)))) + return NULL; + + server->fd = -1; + /* XXX extract actual lversion */ + server->qemuVersion = (0*1000000)+(8*1000)+(0); + /* We don't have a dom-0, so start from 1 */ + server->nextvmid = 1; + + if ((uid = geteuid()) < 0) { + goto cleanup; + } + if (!(pw = getpwuid(uid))) { + goto cleanup; + } + + if ((ret = snprintf(path, PATH_MAX, "%s/.qemud", pw->pw_dir)) > PATH_MAX) { + goto cleanup; + } + + if ((ret = snprintf(server->configDir, PATH_MAX, "%s/.qemud.d", pw->pw_dir)) > PATH_MAX) { + goto cleanup; + } + + if ((server->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + goto cleanup; + } + + if (qemudSetCloseExec(server->fd) < 0) + goto cleanup; + if (qemudSetNonBlock(server->fd) < 0) + goto cleanup; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + addr.sun_path[0] = '\0'; + strncpy(&addr.sun_path[1], path, (sizeof(addr)-4)-2); + + if (bind(server->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + goto cleanup; + } + if (fchmod(server->fd, S_IRUSR | S_IWUSR) < 0) + goto cleanup; + + if (listen(server->fd, 30) < 0) { + goto cleanup; + } + + if (qemudScanConfigs(server) < 0) { + goto cleanup; + } + + return server; + + cleanup: + if (server->fd != -1) + close(server->fd); + if (server) + free(server); + return NULL; +} + + +static int qemudDispatchServer(struct qemud_server *server) { + int fd; + struct sockaddr_un addr; + unsigned int addrlen = sizeof(addr); + struct qemud_client *client; + + if ((fd = accept(server->fd, (struct sockaddr *)&addr, &addrlen)) < 0) { + if (errno == EAGAIN) + return 0; + return -1; + } + + if (qemudSetCloseExec(fd) < 0) { + close(fd); + return -1; + } + + if (qemudSetNonBlock(fd) < 0) { + close(fd); + return -1; + } + + client = calloc(1, sizeof(struct qemud_client)); + client->fd = fd; + client->next = server->clients; + server->clients = client; + server->nclients++; + + return 0; +} + + +int qemudStartVMDaemon(struct qemud_server *server, + struct qemud_vm *vm) { + char **argv = NULL; + int argc = 0; + int pid; + int i, ret = -1; + int pipeout[2] = {-1,-1}; + int pipeerr[2] = {-1,-1}; + + if (qemudBuildCommandLine(vm, &argv, &argc) < 0) + return -1; + + printf("Spawn QEMU '"); + for (i = 0 ; i < argc; i++) { + printf("%s", argv[i]); + if (i == (argc-1)) + printf("'\n"); + else + printf(" "); + } + + + if (pipe(pipeout) < 0) + goto cleanup; + + if (pipe(pipeerr) < 0) + goto cleanup; + + if ((pid = fork()) < 0) + goto cleanup; + + if (pid) { + close(pipeout[1]); + close(pipeerr[1]); + qemudSetNonBlock(pipeout[0]); + qemudSetNonBlock(pipeerr[0]); + vm->def.id = server->nextvmid++; + vm->pid = pid; + vm->stdout = pipeout[0]; + vm->stderr = pipeerr[0]; + + } else { + int null; + if ((null = open(_PATH_DEVNULL, O_RDONLY)) < 0) + _exit(1); + + if (close(pipeout[0]) < 0) + _exit(1); + if (close(pipeerr[0]) < 0) + _exit(1); + + if (dup2(pipeout[1], STDOUT_FILENO) < 0) + _exit(1); + if (dup2(pipeerr[1], STDERR_FILENO) < 0) + _exit(1); + + int open_max = sysconf (_SC_OPEN_MAX); + for (i = 0; i < open_max; i++) + if (i != STDOUT_FILENO && + i != STDERR_FILENO && + i != STDIN_FILENO) + close(i); + + execvp(argv[0], argv); + + _exit(1); + } + + ret = 0; + + cleanup: + + for (i = 0 ; i < argc ; i++) { + free(argv[i]); + } + free(argv); + + return ret; +} + + +static void qemudDispatchClientFailure(struct qemud_server *server, struct qemud_client *client) { + struct qemud_client *tmp = server->clients; + struct qemud_client *prev = NULL; + while (tmp) { + if (tmp == client) { + if (prev == NULL) + server->clients = client->next; + else + prev->next = client->next; + server->nclients--; + break; + } + prev = tmp; + tmp = tmp->next; + } + close(client->fd); + free(client); +} + + +static int qemudDispatchClientRequest(struct qemud_server *server, struct qemud_client *client) { + if (qemudDispatch(server, + client, + &client->incoming, + &client->outgoing) < 0) { + return -1; + } + + client->outgoingSent = 0; + client->tx = 1; + client->incomingReceived = 0; + + return 0; +} + +static void qemudDispatchClientRead(struct qemud_server *server, struct qemud_client *client) { + char *data = (char *)&client->incoming; + unsigned int got = client->incomingReceived; + int want; + int ret; + + restart: + if (got >= sizeof(struct qemud_packet_header)) { + want = sizeof(struct qemud_packet_header) + client->incoming.header.dataSize - got; + } else { + want = sizeof(struct qemud_packet_header) - got; + } + + if ((ret = read(client->fd, data+got, want)) <= 0) { + if (errno != EAGAIN) { + qemudDispatchClientFailure(server, client); + return; + } + return; + } + got += ret; + client->incomingReceived += ret; + + /* If we've finished header, move onto body */ + if (client->incomingReceived == sizeof(struct qemud_packet_header)) { + /* Client lied about dataSize */ + if (client->incoming.header.dataSize > sizeof(union qemud_packet_data)) { + printf("Bogus data size %u\n", client->incoming.header.dataSize); + qemudDispatchClientFailure(server, client); + return; + } + if (client->incoming.header.dataSize) { + printf("- Restarting recv to process body (%d bytes)\n", client->incoming.header.dataSize); + goto restart; + } + } + + /* If we've finished body, dispatch the request */ + if (ret == want) { + if (qemudDispatchClientRequest(server, client) < 0) + qemudDispatchClientFailure(server, client); + } +} + +static void qemudDispatchClientWrite(struct qemud_server *server, struct qemud_client *client) { + char *data = (char *)&client->outgoing; + int sent = client->outgoingSent; + int todo = sizeof(struct qemud_packet_header) + client->outgoing.header.dataSize - sent; + int ret; + if ((ret = write(client->fd, data+sent, todo)) < 0) { + if (errno != EAGAIN) { + qemudDispatchClientFailure(server, client); + return; + } + return; + } + client->outgoingSent += ret; + + if (todo == ret) { + client->tx = 0; + } +} + +static int qemudVMData(struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_vm *vm, int fd) { + char buf[4096]; + if (vm->pid < 0) + return 0; + + for (;;) { + int ret = read(fd, buf, 4096); + if (ret < 0) { + if (errno == EAGAIN) + return 0; + return -1; + } + if (ret == 0) { + return 0; + } + write(STDOUT_FILENO, "[", 1); + write(STDOUT_FILENO, buf, ret); + write(STDOUT_FILENO, "]", 1); + } +} + +int qemudShutdownVMDaemon(struct qemud_server *server, struct qemud_vm *vm) { + struct qemud_vm *prev = NULL, *curr = server->activevms; + + /* Already cleanup */ + if (vm->pid < 0) + return 0; + + printf("Do VM cleanup\n"); + kill(vm->pid, SIGTERM); + + while (curr) { + if (curr == vm) { + if (prev) { + prev->next = curr->next; + } else { + server->activevms = curr->next; + } + server->nactivevms--; + + if (vm->configFile[0]) { + curr->next = server->inactivevms; + server->inactivevms = curr; + server->ninactivevms++; + } + break; + } + prev = curr; + curr = curr->next; + } + + qemudVMData(server, vm, curr->stdout); + qemudVMData(server, vm, curr->stderr); + close(curr->stdout); + close(curr->stderr); + curr->stdout = -1; + curr->stderr = -1; + server->nvmfds -= 2; + + if (waitpid(vm->pid, NULL, WNOHANG) != vm->pid) { + kill(vm->pid, SIGKILL); + if (waitpid(vm->pid, NULL, 0) != vm->pid) { + return -1; + } + } + + vm->pid = -1; + vm->def.id = -1; + + if (!vm->configFile[0]) { + qemudFreeVM(vm); + } + + return 0; +} + +static int qemudDispatchVMLog(struct qemud_server *server, struct qemud_vm *vm, int fd) { + if (qemudVMData(server, vm, fd) < 0) + if (qemudShutdownVMDaemon(server, vm) < 0) + return -1; + return 0; +} +static int qemudDispatchVMMonitor(struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_vm *vm ATTRIBUTE_UNUSED) { + return -1; +} +static int qemudDispatchVMFailure(struct qemud_server *server, struct qemud_vm *vm, + int fd ATTRIBUTE_UNUSED) { + if (qemudShutdownVMDaemon(server, vm) < 0) + return -1; + return 0; +} + + +static int qemudDispatchPoll(struct qemud_server *server, struct pollfd *fds) { + struct qemud_client *client = server->clients; + struct qemud_vm *vm = server->activevms; + int ret = 0; + int fd = 0; + if (fds[fd].revents) + if (qemudDispatchServer(server) < 0) + return -1; + fd++; + + while (client) { + struct qemud_client *next = client->next; + if (fds[fd].revents) { + if (fds[fd].revents == POLLOUT) + qemudDispatchClientWrite(server, client); + else if (fds[fd].revents == POLLIN) + qemudDispatchClientRead(server, client); + else + qemudDispatchClientFailure(server, client); + } + fd++; + client = next; + } + while (vm) { + struct qemud_vm *next = vm->next; + int failed = 0, + stdoutfd = vm->stdout, + stderrfd = vm->stderr, + monitorfd = vm->monitor; + if (stdoutfd != -1) { + if (fds[fd].revents) { + if (fds[fd].revents == POLLIN) { + if (qemudDispatchVMLog(server, vm, fds[fd].fd) < 0) + failed = 1; + } else { + if (qemudDispatchVMFailure(server, vm, fds[fd].fd) < 0) + failed = 1; + } + } + fd++; + } + if (stderrfd != -1) { + if (!failed) { + if (fds[fd].revents) { + if (fds[fd].revents == POLLIN) { + if (qemudDispatchVMLog(server, vm, fds[fd].fd) < 0) + failed = 1; + } else { + if (qemudDispatchVMFailure(server, vm, fds[fd].fd) < 0) + failed = 1; + } + } + } + fd++; + } + if (monitorfd != -1) { + if (!failed) { + if (fds[fd].revents) { + if (fds[fd].revents == POLLIN) { + if (qemudDispatchVMMonitor(server, vm) < 0) + failed = 1; + } else { + if (qemudDispatchVMFailure(server, vm, fds[fd].fd) < 0) + failed = 1; + } + } + } + fd++; + } + vm = next; + if (failed) + ret = -1; + } + return ret; +} + +static void qemudPreparePoll(struct qemud_server *server, struct pollfd *fds) { + int fd = 0; + + fds[fd].fd = server->fd; + fds[fd].events = POLLIN; + fd++; + + for (struct qemud_client *client = server->clients ; client ; client = client->next) { + fds[fd].fd = client->fd; + /* Refuse to read more from client if tx is pending to + rate limit */ + if (client->tx) + fds[fd].events = POLLOUT | POLLERR | POLLHUP; + else + fds[fd].events = POLLIN | POLLERR | POLLHUP; + fd++; + } + for (struct qemud_vm *vm = server->activevms ; vm ; vm = vm->next) { + if (vm->stdout != -1) { + fds[fd].fd = vm->stdout; + fds[fd].events = POLLIN | POLLERR | POLLHUP; + fd++; + } + if (vm->stderr != -1) { + fds[fd].fd = vm->stderr; + fds[fd].events = POLLIN | POLLERR | POLLHUP; + fd++; + } + if (vm->monitor != -1) { + fds[fd].fd = vm->monitor; + fds[fd].events = POLLIN | POLLERR | POLLHUP; + fd++; + } + } +} + + + +static int qemudOneLoop(struct qemud_server *server) { + int nfds = 1 + server->nclients + server->nvmfds; + struct pollfd fds[nfds]; + int timeout = -1; + int ret; + + if (!server->nclients && + !server->nactivevms) + timeout = 30; + + qemudPreparePoll(server, fds); + + retry: + + if ((ret = poll(fds, nfds, timeout * 1000)) < 0) { + if (errno == EINTR) { + goto retry; + } + return -1; + } + + if (ret == 0) + return -1; + + if (qemudDispatchPoll(server, fds) < 0) + return -1; + + + return 0; +} + +static int qemudRunLoop(struct qemud_server *server) { + int ret; + + while ((ret = qemudOneLoop(server)) == 0) + ; + + return ret == -1 ? -1 : 0; +} + +static void qemudCleanup(struct qemud_server *server) { + close(server->fd); + free(server); +} + + +int main(void) { + int godaemon = 0; + + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) + return 3; + if (signal(SIGCHLD, reapchild) == SIG_ERR) + return 3; + + if (godaemon) { + int pid = qemudGoDaemon(); + if (pid < 0) + return 1; + if (pid > 0) + return 0; + } + + struct qemud_server *server = qemudInitialize(); + + if (!server) + return 2; + + qemudRunLoop(server); + + qemudCleanup(server); + + return 0; +} diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/src/driver.h libvirt-new/src/driver.h --- libvirt-orig/src/driver.h 2006-08-09 11:21:16.000000000 -0400 +++ libvirt-new/src/driver.h 2006-08-27 17:05:39.000000000 -0400 @@ -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_QEMU = 6 } virDrvNo; diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/src/internal.h libvirt-new/src/internal.h --- libvirt-orig/src/internal.h 2006-06-28 14:19:13.000000000 -0400 +++ libvirt-new/src/internal.h 2006-08-27 17:05:39.000000000 -0400 @@ -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 diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/src/libvirt.c libvirt-new/src/libvirt.c --- libvirt-orig/src/libvirt.c 2006-08-16 12:29:46.000000000 -0400 +++ libvirt-new/src/libvirt.c 2006-08-27 17:05:39.000000000 -0400 @@ -31,6 +31,7 @@ #include "proxy_internal.h" #include "xml.h" #include "test.h" +#include "qemu_internal.h" /* * TODO: @@ -74,6 +75,7 @@ xenDaemonRegister(); xenStoreRegister(); testRegister(); + qemuRegister(); return(0); } @@ -432,6 +434,7 @@ return(0); } } + return (-1); } diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/src/Makefile.am libvirt-new/src/Makefile.am --- libvirt-orig/src/Makefile.am 2006-06-29 18:12:47.000000000 -0400 +++ libvirt-new/src/Makefile.am 2006-08-27 17:54:34.000000000 -0400 @@ -1,6 +1,8 @@ ## Process this file with automake to produce Makefile.in INCLUDES = -I$(top_builddir)/include -I@top_srcdir@/include @LIBXML_CFLAGS@ \ + -I$(top_srcdir)/qemud \ + -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_POSIX_C_SOURCE=199506L \ -DBINDIR=\""$(libexecdir)"\" DEPS = libvirt.la LDADDS = @STATIC_BINARIES@ libvirt.la @@ -25,6 +27,7 @@ sexpr.c sexpr.h \ virterror.c \ driver.h \ + qemu_internal.c qemu_internal.h \ proxy_internal.c proxy_internal.h bin_PROGRAMS = virsh diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/src/qemu_internal.c libvirt-new/src/qemu_internal.c --- libvirt-orig/src/qemu_internal.c 1969-12-31 19:00:00.000000000 -0500 +++ libvirt-new/src/qemu_internal.c 2006-08-27 17:54:51.000000000 -0400 @@ -0,0 +1,746 @@ +/* + * test.c: A "mock" hypervisor for use by application unit tests + * + * Copyright (C) 2006 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + * + * Daniel Berrange <berrange@xxxxxxxxxx> + */ + +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <sys/types.h> +#include <pwd.h> +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <libxml/uri.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <limits.h> +#include <paths.h> + +#include "internal.h" +#include "qemu_internal.h" +#include "xml.h" +#include "protocol.h" + +static virDriver qemuDriver = { + VIR_DRV_QEMU, + "QEMU", + LIBVIR_VERSION_NUMBER, + NULL, /* init */ + qemuOpen, /* open */ + qemuClose, /* close */ + NULL, /* type */ + qemuGetVersion, /* version */ + qemuNodeGetInfo, /* nodeGetInfo */ + qemuListDomains, /* listDomains */ + qemuNumOfDomains, /* numOfDomains */ + qemuDomainCreateLinux, /* domainCreateLinux */ + qemuLookupDomainByID, /* domainLookupByID */ + qemuLookupDomainByUUID, /* domainLookupByUUID */ + qemuLookupDomainByName, /* domainLookupByName */ + qemuPauseDomain, /* domainSuspend */ + qemuResumeDomain, /* domainResume */ + qemuShutdownDomain, /* domainShutdown */ + NULL, /* domainReboot */ + qemuDestroyDomain, /* domainDestroy */ + NULL, /* domainFree */ + NULL, /* domainGetName */ + NULL, /* domainGetID */ + NULL, /* domainGetUUID */ + NULL, /* domainGetOSType */ + NULL, /* domainGetMaxMemory */ + NULL, /* domainSetMaxMemory */ + NULL, /* domainSetMemory */ + qemuGetDomainInfo, /* domainGetInfo */ + qemuSaveDomain, /* domainSave */ + qemuRestoreDomain, /* domainRestore */ + NULL, /* domainSetVcpus */ + NULL, /* domainPinVcpu */ + NULL, /* domainGetVcpus */ + qemuDomainDumpXML, /* domainDumpXML */ + qemuListDefinedDomains, /* listDomains */ + qemuNumOfDefinedDomains, /* numOfDomains */ + qemuDomainCreate, /* domainCreate */ + qemuDomainDefineXML, /* domainDefineXML */ + qemuUndefine, /* domainUndefine */ +}; + + +static void +qemuError(virConnectPtr con, + virDomainPtr dom, + virErrorNumber error, + const char *info) +{ + const char *errmsg; + + if (error == VIR_ERR_OK) + return; + + errmsg = __virErrorMsg(error, info); + __virRaiseError(con, dom, VIR_FROM_XEN, error, VIR_ERR_ERROR, + errmsg, info, NULL, 0, 0, errmsg, info, 0); +} + +static void qemuPacketError(virConnectPtr con, + virDomainPtr dom, + struct qemud_packet *pkt) { + if (!pkt) { + qemuError(con, dom, VIR_ERR_INTERNAL_ERROR, "Malformed data packet"); + return; + } + if (pkt->header.type == QEMUD_PKT_FAILURE) { + /* Paranoia in case remote side didn't terminate it */ + if (pkt->data.failureReply.message[0]) + pkt->data.failureReply.message[QEMUD_MAX_ERROR_LEN-1] = '\0'; + + qemuError(con, dom, pkt->data.failureReply.code, + pkt->data.failureReply.message[0] ? + pkt->data.failureReply.message : NULL); + } else { + qemuError(con, dom, VIR_ERR_INTERNAL_ERROR, "Incorrect reply type"); + } +} + +void qemuRegister(void) { + virRegisterDriver(&qemuDriver); +} + +/** + * qemuFindServerPath: + * + * Tries to find the path to the qemud binary. + * + * Returns path on success or NULL in case of error. + */ +static const char * +qemuFindServerPath(void) +{ + static const char *serverPaths[] = { + BINDIR "/qemud", + BINDIR "/qemud_dbg", + NULL + }; + int i; + const char *debugQemuD = getenv("QEMU_DEBUG_SERVER"); + + if (debugQemuD) + return(debugQemuD); + + for (i = 0; serverPaths[i]; i++) { + if (access(serverPaths[i], X_OK | R_OK) == 0) { + return serverPaths[i]; + } + } + return NULL; +} + + +/** + * qemuForkServer: + * + * Forks and try to launch the qemu server + * + * Returns 0 in case of success or -1 in case of detected error. + */ +static int +qemuForkServer(void) +{ + const char *proxyPath = qemuFindServerPath(); + int ret, pid, status; + + if (!proxyPath) { + fprintf(stderr, "failed to find qemud\n"); + return(-1); + } + + /* Become a daemon */ + pid = fork(); + if (pid == 0) { + int stdinfd = -1; + int stdoutfd = -1; + int i; + if ((stdinfd = open(_PATH_DEVNULL, O_RDONLY)) < 0) + goto cleanup; + if ((stdoutfd = open(_PATH_DEVNULL, O_WRONLY)) < 0) + goto cleanup; + if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO) + goto cleanup; + if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO) + goto cleanup; + if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO) + goto cleanup; + if (close(stdinfd) < 0) + goto cleanup; + stdinfd = -1; + if (close(stdoutfd) < 0) + goto cleanup; + stdoutfd = -1; + + int open_max = sysconf (_SC_OPEN_MAX); + for (i = 0; i < open_max; i++) + if (i != STDIN_FILENO && + i != STDOUT_FILENO && + i != STDERR_FILENO) + close(i); + + setsid(); + if (fork() == 0) { + execl(proxyPath, proxyPath, NULL); + fprintf(stderr, "failed to exec %s\n", proxyPath); + } + /* + * calling exit() generate troubles for termination handlers + */ + _exit(0); + + cleanup: + if (stdoutfd != -1) + close(stdoutfd); + if (stdinfd != -1) + close(stdinfd); + _exit(-1); + } + + /* + * do a waitpid on the intermediate process to avoid zombies. + */ +retry_wait: + ret = waitpid(pid, &status, 0); + if (ret < 0) { + if (errno == EINTR) + goto retry_wait; + } + + return (0); +} + +/** + * qemuOpenClientSocket: + * @path: the fileame for the socket + * + * try to connect to the socket open by qemud + * + * Returns the associated file descriptor or -1 in case of failure + */ +static int +qemuOpenClientSocket(const char *path) { + int fd; + struct sockaddr_un addr; + int trials = 0; + +retry: + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + return(-1); + } + + /* + * Abstract socket do not hit the filesystem, way more secure and + * garanteed to be atomic + */ + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + addr.sun_path[0] = '\0'; + strncpy(&addr.sun_path[1], path, (sizeof(addr) - 4) - 2); + + /* + * now bind the socket to that address and listen on it + */ + if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close(fd); + if (trials < 3) { + if (qemuForkServer() < 0) + return(-1); + trials++; + usleep(5000 * trials * trials); + goto retry; + } + return (-1); + } + + return (fd); +} + +static int qemuProcessRequest(virConnectPtr conn, + virDomainPtr dom, + struct qemud_packet *req, + struct qemud_packet *reply) { + char *out = (char *)req; + int outDone = 0; + int outLeft = sizeof(struct qemud_packet_header) + req->header.dataSize; + char *in = (char *)reply; + int inGot = 0; + int inLeft = sizeof(struct qemud_packet_header); + + //printf("Send request %d\n", req->header.type); + + // Block sending entire outgoing packet + while (outLeft) { + int got = write(conn->handle, out+outDone, outLeft); + if (got < 0) { + return -1; + } + outDone += got; + outLeft -= got; + } + + /* Block waiting for header to come back */ + while (inLeft) { + int done = read(conn->handle, in+inGot, inLeft); + if (done <= 0) { + return -1; + } + inGot += done; + inLeft -= done; + } + + /* Validate header isn't bogus (bigger than + maximum defined packet size) */ + if (reply->header.dataSize > sizeof(union qemud_packet_data)) { + printf("Got type %ds body %d (max %ld)\n", reply->header.type, reply->header.dataSize, sizeof(union qemud_packet_data)); + printf("%ld == %ld + %ld\n", sizeof(struct qemud_packet), sizeof(struct qemud_packet_header), sizeof(union qemud_packet_data)); + qemuPacketError(conn, dom, NULL); + return -1; + } + + /* Now block reading in body */ + inLeft = reply->header.dataSize; + while (inLeft) { + int done = read(conn->handle, in+inGot, inLeft); + if (done <= 0) { + return -1; + } + inGot += done; + inLeft -= done; + } + + if (reply->header.type != req->header.type) { + qemuPacketError(conn, dom, reply); + return -1; + } + + return 0; +} + +static int qemuOpenConnection(const char *uri) { + struct passwd *pw; + int uid; + char path[PATH_MAX]; + + if (!strcmp(uri, "/system")) { + uid = 0; + } else if (!strcmp(uri, "/session")) { + if ((uid = geteuid()) < 0) { + return -1; + } + } else { + return -1; + } + + if (!(pw = getpwuid(uid))) + return -1; + + if (snprintf(path, PATH_MAX, "%s/.qemud", pw->pw_dir) == PATH_MAX) { + return -1; + } + + return qemuOpenClientSocket(path); +} + +int qemuOpen(virConnectPtr conn, + const char *name, + int flags){ + xmlURIPtr uri; + int fd; + + if (!name) { + return -1; + } + + uri = xmlParseURI(name); + if (uri == NULL) { + if (!(flags & VIR_DRV_OPEN_QUIET)) + qemuError(conn, NULL, VIR_ERR_NO_SUPPORT, name); + return(-1); + } + + if (!uri->scheme || + strcmp(uri->scheme, "qemu") || + !uri->path) { + xmlFreeURI(uri); + return -1; + } + + fd = qemuOpenConnection(uri->path); + xmlFreeURI(uri); + + if (fd < 0) { + return -1; + } + + conn->handle = fd; + + return 0; +} + +int qemuClose (virConnectPtr conn) { + if (conn->handle != -1) { + close(conn->handle); + conn->handle = -1; + } + return 0; +} + +int qemuGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED, + unsigned long *hvVer){ + struct qemud_packet req, reply; + + req.header.type = QEMUD_PKT_GET_VERSION; + req.header.dataSize = 0; + + if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) { + return -1; + } + + *hvVer = reply.data.getVersionReply.version; + return 0; +} +int qemuNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, + virNodeInfoPtr info){ + info->cores = 1; + info->threads = 1; + info->sockets = 1; + info->nodes = 1; + strcpy(info->model, "i686"); + info->mhz = 6000; + info->cpus = 1; + info->memory = 1024*1024; + return 0; +} + +int qemuNumOfDomains(virConnectPtr conn){ + struct qemud_packet req, reply; + + req.header.type = QEMUD_PKT_NUM_DOMAINS; + req.header.dataSize = 0; + + if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) { + return -1; + } + + return reply.data.numDomainsReply.numDomains; +} + +int qemuListDomains(virConnectPtr conn, + int *ids, + int maxids){ + struct qemud_packet req, reply; + + req.header.type = QEMUD_PKT_LIST_DOMAINS; + req.header.dataSize = 0; + + if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) { + return -1; + } + + if (reply.data.listDomainsReply.numDomains > maxids) + return -1; + + memmove(ids, + reply.data.listDomainsReply.domains, + sizeof(int)*reply.data.listDomainsReply.numDomains); + + return reply.data.listDomainsReply.numDomains; +} +virDomainPtr +qemuDomainCreateLinux(virConnectPtr conn, const char *xmlDesc, + unsigned int flags ATTRIBUTE_UNUSED){ + struct qemud_packet req, reply; + virDomainPtr dom; + int len = strlen(xmlDesc); + + if (len > (QEMUD_MAX_XML_LEN-1)) { + return NULL; + } + + req.header.type = QEMUD_PKT_DOMAIN_CREATE; + req.header.dataSize = sizeof(req.data.domainCreateRequest); + strcpy(req.data.domainCreateRequest.xml, xmlDesc); + req.data.domainCreateRequest.xml[QEMUD_MAX_XML_LEN-1] = '\0'; + + if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) { + return NULL; + } + + reply.data.domainCreateReply.name[QEMUD_MAX_NAME_LEN-1] = '\0'; + + if (!(dom = virGetDomain(conn, + reply.data.domainCreateReply.name, + reply.data.domainCreateReply.uuid))) + return NULL; + + dom->handle = reply.data.domainCreateReply.id; + return dom; +} + +virDomainPtr qemuLookupDomainByID(virConnectPtr conn, + int id){ + struct qemud_packet req, reply; + virDomainPtr dom; + + req.header.type = QEMUD_PKT_DOMAIN_LOOKUP_BY_ID; + req.header.dataSize = sizeof(req.data.domainLookupByIDRequest); + req.data.domainLookupByIDRequest.id = id; + + if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) { + return NULL; + } + + reply.data.domainLookupByIDReply.name[QEMUD_MAX_NAME_LEN-1] = '\0'; + + if (!(dom = virGetDomain(conn, + reply.data.domainLookupByIDReply.name, + reply.data.domainLookupByIDReply.uuid))) + return NULL; + + dom->handle = id; + return dom; +} + +virDomainPtr qemuLookupDomainByUUID(virConnectPtr conn, + const unsigned char *uuid){ + struct qemud_packet req, reply; + virDomainPtr dom; + + req.header.type = QEMUD_PKT_DOMAIN_LOOKUP_BY_UUID; + req.header.dataSize = sizeof(req.data.domainLookupByUUIDRequest); + memmove(req.data.domainLookupByUUIDRequest.uuid, uuid, QEMUD_UUID_RAW_LEN); + + if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) { + return NULL; + } + + reply.data.domainLookupByUUIDReply.name[QEMUD_MAX_NAME_LEN-1] = '\0'; + + if (!(dom = virGetDomain(conn, + reply.data.domainLookupByUUIDReply.name, + uuid))) + return NULL; + + dom->handle = reply.data.domainLookupByUUIDReply.id; + return dom; +} +virDomainPtr qemuLookupDomainByName(virConnectPtr conn, + const char *name){ + struct qemud_packet req, reply; + virDomainPtr dom; + + if (strlen(name) > (QEMUD_MAX_NAME_LEN-1)) + return NULL; + + req.header.type = QEMUD_PKT_DOMAIN_LOOKUP_BY_NAME; + req.header.dataSize = sizeof(req.data.domainLookupByNameRequest); + strcpy(req.data.domainLookupByNameRequest.name, name); + + if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) { + return NULL; + } + + if (!(dom = virGetDomain(conn, + name, + reply.data.domainLookupByNameReply.uuid))) + return NULL; + + dom->handle = reply.data.domainLookupByNameReply.id; + return dom; +} +int qemuShutdownDomain(virDomainPtr domain){ + return qemuDestroyDomain(domain); +} +int qemuDestroyDomain(virDomainPtr domain){ + struct qemud_packet req, reply; + + req.header.type = QEMUD_PKT_DOMAIN_DESTROY; + req.header.dataSize = sizeof(req.data.domainDestroyRequest); + req.data.domainDestroyRequest.id = domain->handle; + + if (qemuProcessRequest(domain->conn, NULL, &req, &reply) < 0) { + return -1; + } + + return 0; +} +int qemuResumeDomain(virDomainPtr domain ATTRIBUTE_UNUSED){ + return -1; +} +int qemuPauseDomain(virDomainPtr domain ATTRIBUTE_UNUSED){ + return -1; +} +int qemuGetDomainInfo(virDomainPtr domain, + virDomainInfoPtr info){ + struct qemud_packet req, reply; + + req.header.type = QEMUD_PKT_DOMAIN_GET_INFO; + req.header.dataSize = sizeof(req.data.domainGetInfoRequest); + memmove(req.data.domainGetInfoRequest.uuid, domain->uuid, QEMUD_UUID_RAW_LEN); + + if (qemuProcessRequest(domain->conn, NULL, &req, &reply) < 0) { + return -1; + } + + memset(info, 0, sizeof(virDomainInfo)); + switch (reply.data.domainGetInfoReply.runstate) { + case QEMUD_STATE_RUNNING: + info->state = VIR_DOMAIN_RUNNING; + break; + + case QEMUD_STATE_PAUSED: + info->state = VIR_DOMAIN_PAUSED; + break; + + case QEMUD_STATE_STOPPED: + info->state = VIR_DOMAIN_SHUTOFF; + break; + + default: + return -1; + } + info->maxMem = reply.data.domainGetInfoReply.memory; + info->memory = reply.data.domainGetInfoReply.memory; + info->nrVirtCpu = reply.data.domainGetInfoReply.nrVirtCpu; + info->cpuTime = reply.data.domainGetInfoReply.cpuTime; + + return 0; +} +char * qemuDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED){ + struct qemud_packet req, reply; + + req.header.type = QEMUD_PKT_DUMP_XML; + req.header.dataSize = sizeof(req.data.domainDumpXMLRequest); + memmove(req.data.domainDumpXMLRequest.uuid, domain->uuid, QEMUD_UUID_RAW_LEN); + + if (qemuProcessRequest(domain->conn, NULL, &req, &reply) < 0) { + return NULL; + } + + reply.data.domainDumpXMLReply.xml[QEMUD_MAX_XML_LEN-1] = '\0'; + + return strdup(reply.data.domainDumpXMLReply.xml); +} + +int qemuSaveDomain(virDomainPtr domain ATTRIBUTE_UNUSED, const char *file ATTRIBUTE_UNUSED){ + return -1; +} +int qemuRestoreDomain(virConnectPtr conn ATTRIBUTE_UNUSED, const char *file ATTRIBUTE_UNUSED){ + return -1; +} +int qemuNumOfDefinedDomains(virConnectPtr conn){ + struct qemud_packet req, reply; + + req.header.type = QEMUD_PKT_NUM_DEFINED_DOMAINS; + req.header.dataSize = 0; + + if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) { + return -1; + } + + return reply.data.numDefinedDomainsReply.numDomains; +} + +int qemuListDefinedDomains(virConnectPtr conn, + const char **names, + int maxnames){ + struct qemud_packet req, reply; + int i; + + req.header.type = QEMUD_PKT_LIST_DEFINED_DOMAINS; + req.header.dataSize = 0; + + if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) { + return -1; + } + + if (reply.data.listDefinedDomainsReply.numDomains > maxnames) + return -1; + + for (i = 0 ; i < reply.data.listDefinedDomainsReply.numDomains ; i++) { + reply.data.listDefinedDomainsReply.domains[i][QEMUD_MAX_NAME_LEN-1] = '\0'; + names[i] = strdup(reply.data.listDefinedDomainsReply.domains[i]); + } + + return reply.data.listDefinedDomainsReply.numDomains; +} +int qemuDomainCreate(virDomainPtr dom) { + struct qemud_packet req, reply; + + req.header.type = QEMUD_PKT_DOMAIN_START; + req.header.dataSize = sizeof(req.data.domainStartRequest); + memcpy(req.data.domainStartRequest.uuid, dom->uuid, QEMUD_UUID_RAW_LEN); + + if (qemuProcessRequest(dom->conn, NULL, &req, &reply) < 0) { + return -1; + } + + dom->handle = reply.data.domainStartReply.id; + + return 0; +} + +virDomainPtr qemuDomainDefineXML(virConnectPtr conn, const char *xml) { + struct qemud_packet req, reply; + virDomainPtr dom; + int len = strlen(xml); + + if (len > (QEMUD_MAX_XML_LEN-1)) { + return NULL; + } + + req.header.type = QEMUD_PKT_DOMAIN_DEFINE; + req.header.dataSize = sizeof(req.data.domainDefineRequest); + strcpy(req.data.domainDefineRequest.xml, xml); + req.data.domainDefineRequest.xml[QEMUD_MAX_XML_LEN-1] = '\0'; + + if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) { + return NULL; + } + + reply.data.domainDefineReply.name[QEMUD_MAX_NAME_LEN-1] = '\0'; + + if (!(dom = virGetDomain(conn, + reply.data.domainDefineReply.name, + reply.data.domainDefineReply.uuid))) + return NULL; + + dom->handle = -1; + return dom; +} + +int qemuUndefine(virDomainPtr dom) { + struct qemud_packet req, reply; + int ret = 0; + + req.header.type = QEMUD_PKT_DOMAIN_UNDEFINE; + req.header.dataSize = sizeof(req.data.domainUndefineRequest); + memcpy(req.data.domainUndefineRequest.uuid, dom->uuid, QEMUD_UUID_RAW_LEN); + + if (qemuProcessRequest(dom->conn, NULL, &req, &reply) < 0) { + ret = -1; + goto cleanup; + } + + cleanup: + if (virFreeDomain(dom->conn, dom) < 0) + ret = -1; + + return ret; +} diff --exclude docs --exclude .deps --exclude CVS -ruN libvirt-orig/src/qemu_internal.h libvirt-new/src/qemu_internal.h --- libvirt-orig/src/qemu_internal.h 1969-12-31 19:00:00.000000000 -0500 +++ libvirt-new/src/qemu_internal.h 2006-08-27 17:05:39.000000000 -0400 @@ -0,0 +1,62 @@ +/* + * qemu_internal.h: A backend for managing QEMU machines + * + * Copyright (C) 2006 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + * + * Daniel Berrange <berrange@xxxxxxxxxx> + */ + +#ifndef __VIR_QEMU_INTERNAL_H__ +#define __VIR_QEMU_INTERNAL_H__ + +#include <libvirt/virterror.h> + +#ifdef __cplusplus +extern "C" { +#endif + + void qemuRegister(void); + int qemuOpen(virConnectPtr conn, + const char *name, + int flags); + int qemuClose (virConnectPtr conn); + int qemuGetVersion(virConnectPtr conn, + unsigned long *hvVer); + int qemuNodeGetInfo(virConnectPtr conn, + virNodeInfoPtr info); + int qemuNumOfDomains(virConnectPtr conn); + int qemuListDomains(virConnectPtr conn, + int *ids, + int maxids); + int qemuNumOfDefinedDomains(virConnectPtr conn); + int qemuListDefinedDomains(virConnectPtr conn, + const char **names, + int maxnames); + virDomainPtr + qemuDomainCreateLinux(virConnectPtr conn, const char *xmlDesc, + unsigned int flags); + virDomainPtr qemuLookupDomainByID(virConnectPtr conn, + int id); + virDomainPtr qemuLookupDomainByUUID(virConnectPtr conn, + const unsigned char *uuid); + virDomainPtr qemuLookupDomainByName(virConnectPtr conn, + const char *name); + int qemuShutdownDomain(virDomainPtr domain); + int qemuDestroyDomain(virDomainPtr domain); + int qemuResumeDomain(virDomainPtr domain); + int qemuPauseDomain(virDomainPtr domain); + int qemuGetDomainInfo(virDomainPtr domain, + virDomainInfoPtr info); + char * qemuDomainDumpXML(virDomainPtr domain, int flags); + int qemuSaveDomain(virDomainPtr domain, const char *file); + int qemuRestoreDomain(virConnectPtr conn, const char *file); + int qemuDomainCreate(virDomainPtr conn); + virDomainPtr qemuDomainDefineXML(virConnectPtr conn, const char *xml); + int qemuUndefine(virDomainPtr dom); + +#ifdef __cplusplus +} +#endif +#endif /* __VIR_QEMU_INTERNAL_H__ */