On Fri, Jan 05, 2007 at 09:16:54PM +0000, Daniel P. Berrange wrote:
The attached patch provides the QEMU daemon for managing the QEMU
instances
and providing a network protocol for the libvirt driver to talk to over
UNIX domain sockets or IPv4/6.
Okay, the size of the patch is big :-) I have tried to review it fully
but certainly didn't grasped all of it ! Still I found a few things...
comments in context inside.
Daniel
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 -ruN libvirt/qemud/config.c libvirt-qemu/qemud/config.c
--- libvirt/qemud/config.c 1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/config.c 2007-01-04 12:11:49.000000000 -0500
@@ -0,0 +1,1234 @@
+/*
+ * config.c: VM configuration management
+ *
+ * Copyright (C) 2006, 2007 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#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 <libvirt/virterror.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;
+}
+
need to go in lib/
+struct qemu_arch_info {
+ const char *arch;
+ const char **machines;
+ const char *binary;
+};
+
+/* The list of possible machine types for various architectures,
+ as supported by QEMU - taken from 'qemu -M ?' for each arch */
+static const char *arch_info_x86_machines[] = {
+ "pc", "isapc"
+};
+static const char *arch_info_mips_machines[] = {
+ "mips"
+};
+static const char *arch_info_sparc_machines[] = {
+ "sun4m"
+};
+static const char *arch_info_ppc_machines[] = {
+ "g3bw", "mac99", "prep"
+};
Hum, I wonder how we are gonna keep the sync :-)
+/* The archicture tables for supported QEMU archs */
+static struct qemu_arch_info archs[] = {
+ { "i686", arch_info_x86_machines, "qemu" },
+ { "x86_64", arch_info_x86_machines, "qemu-system-x86_64" },
+ { "mips", arch_info_mips_machines, "qemu-system-mips" },
+ { "mipsel", arch_info_mips_machines, "qemu-system-mipsel" },
+ { "sparc", arch_info_sparc_machines, "qemu-system-sparc" },
+ { "ppc", arch_info_ppc_machines, "qemu-system-ppc" },
+};
+
+/* Return the default architecture if none is explicitly requested*/
+static const char *qemudDefaultArch(void) {
+ return archs[0].arch;
+}
+
+/* Return the default machine type for a given architecture */
+static const char *qemudDefaultMachineForArch(const char *arch) {
+ int i;
+
+ for (i = 0 ; i < (int)(sizeof(archs) / sizeof(struct qemu_arch_info)) ; i++) {
+ if (!strcmp(archs[i].arch, arch)) {
+ return archs[i].machines[0];
+ }
+ }
+
+ return NULL;
+}
+
+/* Return the default binary name for a particular architecture */
+static const char *qemudDefaultBinaryForArch(const char *arch) {
+ int i;
+
+ for (i = 0 ; i < (int)(sizeof(archs) / sizeof(struct qemu_arch_info)) ; i++) {
+ if (!strcmp(archs[i].arch, arch)) {
+ return archs[i].binary;
+ }
+ }
+
+ return NULL;
+}
+
+/* Find the fully qualified path to the binary for an architecture */
+static char *qemudLocateBinaryForArch(struct qemud_server *server,
+ int virtType, const char *arch) {
+ const char *name;
+ char *path;
+
+ if (virtType == QEMUD_VIRT_KVM)
+ name = "qemu-kvm";
+ else
+ name = qemudDefaultBinaryForArch(arch);
+
+ if (!name) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot determin binary
for architecture %s", arch);
+ return NULL;
+ }
+
+ /* XXX lame. should actually use $PATH ... */
+ path = malloc(strlen(name) + strlen("/usr/bin/") + 1);
+ if (!path) {
+ qemudReportError(server, VIR_ERR_NO_MEMORY, "path");
+ return NULL;
+ }
+ strcpy(path, "/usr/bin/");
+ strcat(path, name);
+ return path;
+}
Shouldn't we walk $PATH to look up ?
+/* Parse the XML definition for a disk */
+static struct qemud_vm_disk_def *qemudParseDiskXML(struct qemud_server *server,
+ 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;
+
+ if (!disk) {
+ qemudReportError(server, VIR_ERR_NO_MEMORY, "disk");
+ return NULL;
+ }
+
+ 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 {
+ typ = QEMUD_DISK_FILE;
+ }
+ 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) {
+ qemudReportError(server, VIR_ERR_NO_SOURCE, target ? "%s" : NULL,
target);
+ goto error;
+ }
+ if (target == NULL) {
+ qemudReportError(server, VIR_ERR_NO_TARGET, source ? "%s" : NULL,
source);
+ goto error;
+ }
+
+ if (device &&
+ !strcmp((const char *)device, "floppy") &&
+ strcmp((const char *)target, "fda") &&
+ strcmp((const char *)target, "fdb")) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "Invalid floppy device
name: %s", target);
+ goto error;
+ }
+
+ if (device &&
+ !strcmp((const char *)device, "cdrom") &&
+ strcmp((const char *)target, "hdc")) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "Invalid cdrom device
name: %s", target);
+ 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")) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "Invalid harddisk device
name: %s", 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 {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "Invalid device type:
%s", device);
+ goto error;
+ }
+
+ xmlFree(device);
+ xmlFree(target);
+ xmlFree(source);
+
+ return disk;
+
+ error:
+ if (type)
+ xmlFree(type);
+ if (target)
+ xmlFree(target);
+ if (source)
+ xmlFree(source);
+ if (device)
+ xmlFree(device);
+ free(disk);
+ return NULL;
+}
+
+
+/* Parse the XML definition for a network interface */
+static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *server,
+ xmlNodePtr node) {
+ struct qemud_vm_net_def *net = calloc(1, sizeof(struct qemud_vm_net_def));
+ xmlNodePtr cur;
+ xmlChar *macaddr = NULL;
+ xmlChar *type = NULL;
+
+ if (!net) {
+ qemudReportError(server, VIR_ERR_NO_MEMORY, "net");
+ return NULL;
+ }
+
+ net->type = QEMUD_NET_USER;
+
+ type = xmlGetProp(node, BAD_CAST "type");
+ if (type != NULL) {
+ if (xmlStrEqual(type, BAD_CAST "user"))
+ net->type = QEMUD_NET_USER;
+ else if (xmlStrEqual(type, BAD_CAST "tap"))
+ net->type = QEMUD_NET_TAP;
+ else if (xmlStrEqual(type, BAD_CAST "server"))
+ net->type = QEMUD_NET_SERVER;
+ else if (xmlStrEqual(type, BAD_CAST "client"))
+ net->type = QEMUD_NET_CLIENT;
+ else if (xmlStrEqual(type, BAD_CAST "mcast"))
+ net->type = QEMUD_NET_MCAST;
+ /*
+ else if (xmlStrEqual(type, BAD_CAST "vde"))
+ typ = QEMUD_NET_VDE;
+ */
+ else
+ net->type = QEMUD_NET_USER;
+ xmlFree(type);
+ type = NULL;
+ }
+
+ cur = node->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if ((macaddr == NULL) &&
+ (xmlStrEqual(cur->name, BAD_CAST "mac"))) {
+ macaddr = xmlGetProp(cur, BAD_CAST "address");
+ }
+ }
+ cur = cur->next;
+ }
+
+ net->vlan = 0;
+
+ if (macaddr) {
+ sscanf((const char *)macaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
+ (unsigned int*)&net->mac[0],
+ (unsigned int*)&net->mac[1],
+ (unsigned int*)&net->mac[2],
+ (unsigned int*)&net->mac[3],
+ (unsigned int*)&net->mac[4],
+ (unsigned int*)&net->mac[5]);
+ }
+
+ xmlFree(macaddr);
+
+ return net;
+
+ /*
+ error:
+ if (macaddr)
+ xmlFree(macaddr);
+ free(net);
+ return NULL;
+ */
+}
+
+
+/*
+ * Parses a libvirt XML definition of a guest, and populates the
+ * the qemud_vm struct with matching data about the guests config
+ */
+static int qemudParseXML(struct qemud_server *server,
+ xmlDocPtr xml,
+ struct qemud_vm *vm) {
+ xmlNodePtr root = NULL;
+ xmlChar *prop = NULL;
+ xmlXPathContextPtr ctxt = NULL;
+ xmlXPathObjectPtr obj = NULL;
+ char *conv = NULL;
+
+ /* Prepare parser / xpath context */
+ root = xmlDocGetRootElement(xml);
+ if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "domain"))) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "incorrect
root element");
+ goto error;
+ }
+
+ ctxt = xmlXPathNewContext(xml);
+ if (ctxt == NULL) {
+ qemudReportError(server, VIR_ERR_NO_MEMORY, "xmlXPathContext");
+ goto error;
+ }
+
+
+ /* Find out what type of QEMU virtualization to use */
+ if (!(prop = xmlGetProp(root, BAD_CAST "type"))) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "missing
domain type attribute");
+ goto error;
+ }
+
+ if (!strcmp((char *)prop, "qemu"))
+ vm->def.virtType = QEMUD_VIRT_QEMU;
+ else if (!strcmp((char *)prop, "kqemu"))
+ vm->def.virtType = QEMUD_VIRT_KQEMU;
+ else if (!strcmp((char *)prop, "kvm"))
+ vm->def.virtType = QEMUD_VIRT_KVM;
+ else {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "invalid
domain type attribute");
+ goto error;
+ }
+ free(prop);
+ prop = NULL;
+
+
+ /* Extract domain name */
+ obj = xmlXPathEval(BAD_CAST "string(/domain/name[1])", ctxt);
+ if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+ (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+ qemudReportError(server, VIR_ERR_NO_NAME, NULL);
+ goto error;
+ }
+ if (strlen((const char *)obj->stringval) >= (QEMUD_MAX_NAME_LEN-1)) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "domain
name length too long");
+ goto error;
+ }
+ strcpy(vm->def.name, (const char *)obj->stringval);
+ xmlXPathFreeObject(obj);
+
+
+ /* Extract domain uuid */
+ obj = xmlXPathEval(BAD_CAST "string(/domain/uuid[1])", ctxt);
+ if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+ (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+ /* XXX auto-generate a UUID */
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "missing
uuid element");
+ goto error;
+ }
+ if (qemudParseUUID((const char *)obj->stringval, vm->def.uuid) < 0) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "malformed
uuid element");
+ goto error;
+ }
+ xmlXPathFreeObject(obj);
+
+
+ /* Extract domain memory */
+ obj = xmlXPathEval(BAD_CAST "string(/domain/memory[1])", ctxt);
+ if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+ (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+ vm->def.memory = 131072; /* 128 MB of ram */
+ } else {
+ conv = NULL;
+ vm->def.memory = strtoll((const char*)obj->stringval, &conv, 10);
+ if (conv == (const char*)obj->stringval) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s",
"malformed memory information");
+ goto error;
+ }
+ }
+ if (obj)
+ xmlXPathFreeObject(obj);
+
+
+ /* Extract domain vcpu info */
+ 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) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s",
"malformed vcpu information");
+ goto error;
+ }
+ }
+ if (obj)
+ xmlXPathFreeObject(obj);
+
+
+ /* Extract OS type info */
+ obj = xmlXPathEval(BAD_CAST "string(/domain/os/type[1])", ctxt);
+ if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+ (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+ qemudReportError(server, VIR_ERR_OS_TYPE, NULL);
+ goto error;
+ }
+ if (strcmp((const char *)obj->stringval, "hvm")) {
+ qemudReportError(server, VIR_ERR_OS_TYPE, "%s", obj->stringval);
+ goto error;
+ }
+ strcpy(vm->def.os.type, (const char *)obj->stringval);
+ xmlXPathFreeObject(obj);
+
+
+ obj = xmlXPathEval(BAD_CAST "string(/domain/os/type[1]/@arch)", ctxt);
+ if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+ (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+ const char *defaultArch = qemudDefaultArch();
+ if (strlen(defaultArch) >= (QEMUD_OS_TYPE_MAX_LEN-1)) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s",
"architecture type too long");
+ goto error;
+ }
+ strcpy(vm->def.os.arch, defaultArch);
+ } else {
+ if (strlen((const char *)obj->stringval) >= (QEMUD_OS_TYPE_MAX_LEN-1)) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s",
"architecture type too long");
+ goto error;
+ }
+ strcpy(vm->def.os.arch, (const char *)obj->stringval);
+ }
+ if (obj)
+ xmlXPathFreeObject(obj);
+
+ obj = xmlXPathEval(BAD_CAST "string(/domain/os/type[1]/@machine)", ctxt);
+ if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+ (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+ const char *defaultMachine = qemudDefaultMachineForArch(vm->def.os.arch);
+ if (strlen(defaultMachine) >= (QEMUD_OS_MACHINE_MAX_LEN-1)) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s",
"machine type too long");
+ goto error;
+ }
+ strcpy(vm->def.os.machine, defaultMachine);
+ } else {
+ if (strlen((const char *)obj->stringval) >= (QEMUD_OS_MACHINE_MAX_LEN-1))
{
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s",
"architecture type too long");
+ goto error;
+ }
+ strcpy(vm->def.os.machine, (const char *)obj->stringval);
+ }
+ if (obj)
+ xmlXPathFreeObject(obj);
+
+ obj = xmlXPathEval(BAD_CAST "string(/domain/devices/emulator[1])", ctxt);
+ if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+ (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+ char *tmp = qemudLocateBinaryForArch(server, vm->def.virtType,
vm->def.os.arch);
+ if (!tmp) {
+ goto error;
+ }
+ strcpy(vm->def.os.binary, tmp);
+ free(tmp);
+ } else {
+ if (strlen((const char *)obj->stringval) >= (PATH_MAX-1)) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s",
"emulator path too long");
+ goto error;
+ }
+ strcpy(vm->def.os.binary, (const char *)obj->stringval);
+ }
+ if (obj)
+ xmlXPathFreeObject(obj);
+
+ 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 = -1;
+ }
+ } else if (!strcmp((char *)prop, "sdl")) {
+ vm->def.graphicsType = QEMUD_GRAPHICS_SDL;
+ } else {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "Unsupported graphics
type %s", prop);
+ goto error;
+ }
+ }
+
+ /* analysis of the disk 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(server, obj->nodesetval->nodeTab[i])))
{
+ goto error;
+ }
+ vm->def.ndisks++;
+ disk->next = vm->def.disks;
+ vm->def.disks = disk;
+ }
+ }
+ xmlXPathFreeObject(obj);
+
+
+ /* analysis of the network devices */
+ obj = xmlXPathEval(BAD_CAST "/domain/devices/interface", 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_net_def *net;
+ if (!(net = qemudParseInterfaceXML(server,
obj->nodesetval->nodeTab[i]))) {
+ goto error;
+ }
+ vm->def.nnets++;
+ net->next = vm->def.nets;
+ vm->def.nets = net;
+ }
+ }
+ xmlXPathFreeObject(obj);
+
+ return 0;
+
+ error:
+ /* XXX free all the stuff in the qemud_vm struct, or leave it upto
+ the caller ? */
+ if (prop)
+ free(prop);
+ if (obj)
+ xmlXPathFreeObject(obj);
+ return -1;
+}
+
Hum, there is a lot of duplication in the parsing, at least I should try to
provide libxml2 XPath lookup based functions instead of duplicating
xmlXPathEval all over the place with relatively complex cleanup etc...
+/*
+ * Constructs a argv suitable for launching qemu with config defined
+ * for a given virtual machine.
+ */
+int qemudBuildCommandLine(struct qemud_server *server,
+ struct qemud_vm *vm,
+ char ***argv,
+ int *argc) {
+ int n = -1;
+ char memory[50];
+ char vcpus[50];
+ struct qemud_vm_disk_def *disk = vm->def.disks;
+ struct qemud_vm_net_def *net = vm->def.nets;
+
+ *argc = 1 + /* qemu */
+ 2 + /* machine type */
+ (vm->def.virtType == QEMUD_VIRT_QEMU ? 1 : 0) + /* Disable kqemu */
+ 2 * vm->def.ndisks + /* disks*/
+ (vm->def.nnets > 0 ? (4 * vm->def.nnets) : 2) + /* networks */
+ 2 + /* memory*/
+ 2 + /* cpus */
+ (vm->def.graphicsType == QEMUD_GRAPHICS_VNC ? 2 :
+ (vm->def.graphicsType == QEMUD_GRAPHICS_SDL ? 0 : 1)); /* graphics */
+
+ sprintf(memory, "%d", vm->def.memory/1024);
+ sprintf(vcpus, "%d", vm->def.vcpus);
+
+ if (!(*argv = malloc(sizeof(char *) * (*argc +1))))
+ goto no_memory;
+ if (!((*argv)[++n] = strdup(vm->def.os.binary)))
+ goto no_memory;
+ if (!((*argv)[++n] = strdup("-M")))
+ goto no_memory;
+ if (!((*argv)[++n] = strdup(vm->def.os.machine)))
+ goto no_memory;
+ if (vm->def.virtType == QEMUD_VIRT_QEMU) {
+ if (!((*argv)[++n] = strdup("-no-kqemu")))
+ goto no_memory;
+ }
+ if (!((*argv)[++n] = strdup("-m")))
+ goto no_memory;
+ if (!((*argv)[++n] = strdup(memory)))
+ goto no_memory;
+ if (!((*argv)[++n] = strdup("-smp")))
+ goto no_memory;
+ if (!((*argv)[++n] = strdup(vcpus)))
+ goto no_memory;
+
+ 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);
+
+ if (!((*argv)[++n] = strdup(dev)))
+ goto no_memory;
+ if (!((*argv)[++n] = strdup(file)))
+ goto no_memory;
+
+ disk = disk->next;
+ }
+
+ if (!net) {
+ if (!((*argv)[++n] = strdup("-net")))
+ goto no_memory;
+ if (!((*argv)[++n] = strdup("none")))
+ goto no_memory;
+ } else {
+ while (net) {
+ char nic[3+1+7+1+17+1];
+ sprintf(nic, "nic,macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
+ net->mac[0], net->mac[1],
+ net->mac[2], net->mac[3],
+ net->mac[4], net->mac[5]);
+
+ if (!((*argv)[++n] = strdup("-net")))
+ goto no_memory;
+ if (!((*argv)[++n] = strdup(nic)))
+ goto no_memory;
+ if (!((*argv)[++n] = strdup("-net")))
+ goto no_memory;
+ /* XXX don't hardcode user */
+ if (!((*argv)[++n] = strdup("user")))
+ goto no_memory;
+
+ net = net->next;
+ }
+ }
+
+ if (vm->def.graphicsType == QEMUD_GRAPHICS_VNC) {
+ char port[10];
+ snprintf(port, 10, "%d", vm->def.vncActivePort - 5900);
+ if (!((*argv)[++n] = strdup("-vnc")))
+ goto no_memory;
+ if (!((*argv)[++n] = strdup(port)))
+ goto no_memory;
+ } else if (vm->def.graphicsType == QEMUD_GRAPHICS_NONE) {
+ if (!((*argv)[++n] = strdup("-nographic")))
+ goto no_memory;
+ } else {
+ /* SDL is the default. no args needed */
+ }
+
+ (*argv)[++n] = NULL;
+
+ return 0;
+
+ no_memory:
+ if (argv) {
+ int i; > + for (i = 0 ; i < n ; i++)
+ free(argv[i]);
+ free(argv);
+ }
+ qemudReportError(server, VIR_ERR_NO_MEMORY, "argv");
+ return -1;
+}
+
+/* Free all memory associated with a struct qemud_vm object */
+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);
+}
+
+/* Build up a fully qualfiied path for a config file to be
qualified :-)
Can we try to keep the fuction comments in line
/**
* funcname:
* @arg1: ...
*
* ....
*
* Returns ....
*/
even for internal ones, don't block commiting for that but I will probably
make a pass over this once commited, that will force me to get deeper
understanding of the code
+ * associated with a persistent guest */
+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;
+}
+
+
+/* Save a guest's config data into a persistent file */
+static int qemudSaveConfig(struct qemud_server *server,
+ struct qemud_vm *vm) {
+ char *xml;
+ int fd, ret = -1;
+ int towrite;
+ struct stat sb;
+
+ if (!(xml = qemudGenerateXML(server, vm))) {
+ return -1;
+ }
+
+ if (stat(server->configDir, &sb) < 0) {
+ if (errno == ENOENT) {
+ if (mkdir(server->configDir, 0700) < 0) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot create
config directory %s", server->configDir);
+ return -1;
+ }
+ } else {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot stat config
directory %s", server->configDir);
+ return -1;
+ }
+ } else if (!S_ISDIR(sb.st_mode)) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "config directory %s is
not a directory", server->configDir);
+ return -1;
+ }
+
+ if ((fd = open(vm->configFile,
+ O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR )) < 0) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot create config file
%s", vm->configFile);
+ goto cleanup;
+ }
+
+ towrite = strlen(xml);
+ if (write(fd, xml, towrite) != towrite) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot write config file
%s", vm->configFile);
+ goto cleanup;
+ }
+
+ if (close(fd) < 0) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot save config file
%s", vm->configFile);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
Shouldn't it close fd if write() fails ?
+ free(xml);
+
+ return ret;
+}
+
+
+/* Create a qemud_vm instance, populating it based on the data
+ * in a libvirt XML document describing the guest */
+struct qemud_vm *qemudLoadConfigXML(struct qemud_server *server,
+ const char *file,
+ const char *doc,
+ int save) {
+ struct qemud_vm *vm = NULL;
+ xmlDocPtr xml;
+
+ if (!(xml = xmlReadDoc(BAD_CAST doc, file ? file : "domain.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
+ qemudReportError(server, VIR_ERR_XML_ERROR, NULL);
+ return NULL;
+ }
+
+ if (!(vm = calloc(1, sizeof(struct qemud_vm)))) {
+ qemudReportError(server, VIR_ERR_NO_MEMORY, "vm");
+ return NULL;
+ }
+
+ vm->stdout = -1;
+ vm->stderr = -1;
+ vm->monitor = -1;
+ vm->pid = -1;
+ vm->def.id = -1;
+
+ if (qemudParseXML(server, xml, vm) < 0) {
+ xmlFreeDoc(xml);
+ qemudFreeVM(vm);
+ return NULL;
+ }
+ xmlFreeDoc(xml);
+
+ if (qemudFindVMByUUID(server, vm->def.uuid)) {
+ qemudReportError(server, VIR_ERR_DOM_EXIST, vm->def.name);
+ qemudFreeVM(vm);
+ return NULL;
+ }
+
+ if (qemudFindVMByName(server, vm->def.name)) {
+ qemudReportError(server, VIR_ERR_DOM_EXIST, vm->def.name);
+ qemudFreeVM(vm);
+ 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) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot construct
config file path");
+ qemudFreeVM(vm);
+ return NULL;
+ }
+
+ if (qemudSaveConfig(server, vm) < 0) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot save
config file for guest");
+ qemudFreeVM(vm);
+ return NULL;
+ }
+ } else {
+ vm->configFile[0] = '\0';
+ }
+ }
+
+ return vm;
+}
+
+
+/* Load a guest from its persistent config file */
+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"))) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot open guest config
file %s", file);
+ return;
+ }
+
+ if (fstat(fileno(fh), &st) < 0) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot stat config file
%s", file);
+ goto cleanup;
+ }
+
+ if (st.st_size >= QEMUD_MAX_XML_LEN) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "guest config too large in
file %s", file);
+ goto cleanup;
+ }
+
+ if ((ret = fread(xml, st.st_size, 1, fh)) != 1) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot read config file
%s", file);
+ 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);
+}
+
+
+/* Scan for all guest config files */
+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;
+}
+
[...]
+
+/* Generate an XML document describing the guest's configuration */
+char *qemudGenerateXML(struct qemud_server *server, struct qemud_vm *vm) {
+ struct qemudBuffer buf;
+ unsigned char *uuid;
+ struct qemud_vm_disk_def *disk;
+ struct qemud_vm_net_def *net;
+ const char *type = NULL;
+
+ buf.len = QEMUD_MAX_XML_LEN;
+ buf.used = 0;
+ buf.data = malloc(buf.len);
+
+ switch (vm->def.virtType) {
+ case QEMUD_VIRT_QEMU:
+ type = "qemu";
+ break;
+ case QEMUD_VIRT_KQEMU:
+ type = "kqemu";
+ break;
+ case QEMUD_VIRT_KVM:
+ type = "kvm";
+ break;
+ }
+ if (!type) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "unexpected domain type
%d", vm->def.virtType);
+ goto cleanup;
+ }
+
+ if (vm->def.id >= 0) {
+ if (qemudBufferPrintf(&buf, "<domain type='%s'
id='%d'>\n", type, vm->def.id) < 0)
+ goto no_memory;
+ } else {
+ if (qemudBufferPrintf(&buf, "<domain type='%s'>\n",
type) < 0)
+ goto no_memory;
+ }
+
+ if (qemudBufferPrintf(&buf, " <name>%s</name>\n",
vm->def.name) < 0)
+ goto no_memory;
+
+ 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)
Hum, do we really want to use the format with '-' and not just the raw
hex dump by default, I'm still wondering what this brings...
+ goto no_memory;
+ if (qemudBufferPrintf(&buf, " <memory>%d</memory>\n",
vm->def.memory) < 0)
+ goto no_memory;
+ if (qemudBufferPrintf(&buf, " <vcpu>%d</vcpu>\n",
vm->def.vcpus) < 0)
+ goto no_memory;
+
+ if (qemudBufferAdd(&buf, " <os>\n") < 0)
+ goto no_memory;
+
+ if (vm->def.virtType == QEMUD_VIRT_QEMU) {
+ if (qemudBufferPrintf(&buf, " <type arch='%s'
machine='%s'>%s</type>\n", vm->def.os.arch,
vm->def.os.machine, vm->def.os.type) < 0)
+ goto no_memory;
+ } else {
+ if (qemudBufferPrintf(&buf, " <type>%s</type>\n",
vm->def.os.type) < 0)
+ goto no_memory;
+ }
+
+ if (vm->def.os.kernel[0])
+ if (qemudBufferPrintf(&buf, "
<kernel>%s</kernel>\n", vm->def.os.kernel) < 0)
+ goto no_memory;
+ if (vm->def.os.initrd[0])
+ if (qemudBufferPrintf(&buf, "
<initrd>%s</initrd>\n", vm->def.os.initrd) < 0)
+ goto no_memory;
+ if (vm->def.os.cmdline[0])
+ if (qemudBufferPrintf(&buf, "
<cmdline>%s</cmdline>\n", vm->def.os.cmdline) < 0)
+ goto no_memory;
+
+ if (qemudBufferAdd(&buf, " </os>\n") < 0)
+ goto no_memory;
+
+ if (qemudBufferAdd(&buf, " <devices>\n") < 0)
+ goto no_memory;
+
+ if (qemudBufferPrintf(&buf, "
<emulator>%s</emulator>\n", vm->def.os.binary) < 0)
+ goto no_memory;
+
+ 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 no_memory;
+
+ if (qemudBufferPrintf(&buf, " <source
%s='%s'/>\n", typeAttrs[disk->type], disk->src) < 0)
+ goto no_memory;
+
+ if (qemudBufferPrintf(&buf, " <target
dev='%s'/>\n", disk->dst) < 0)
+ goto no_memory;
+
+ if (disk->readonly)
+ if (qemudBufferAdd(&buf, " <readonly/>\n") < 0)
+ goto no_memory;
+
+ if (qemudBufferPrintf(&buf, " </disk>\n") < 0)
+ goto no_memory;
+
+ disk = disk->next;
+ }
+
+ net = vm->def.nets;
+ disk = vm->def.disks;
+ while (disk) {
+ const char *types[] = {
+ "user",
+ "tap",
+ "server",
+ "client",
+ "mcast",
+ "vde",
+ };
+ if (qemudBufferPrintf(&buf, " <interface
type='%s'>\n",
+ types[net->type]) < 0)
+ goto no_memory;
+
+ if (qemudBufferPrintf(&buf, " <mac
address='%02x:%02x:%02x:%02x:%02x:%02x'/>\n",
+ net->mac[0], net->mac[1], net->mac[2],
+ net->mac[3], net->mac[4], net->mac[5]) < 0)
+ goto no_memory;
+
+ if (qemudBufferPrintf(&buf, " </interface>\n") < 0)
+ goto no_memory;
+
+ disk = disk->next;
+ }
+
+ if (vm->def.graphicsType == QEMUD_GRAPHICS_VNC) {
+ if (vm->def.vncPort) {
+ qemudBufferPrintf(&buf, " <graphics type='vnc'
port='%d'/>\n",
+ vm->def.id == -1 ? vm->def.vncPort :
vm->def.vncActivePort);
+ } else {
+ qemudBufferPrintf(&buf, " <graphics
type='vnc'/>\n");
+ }
+ }
+
+ if (qemudBufferAdd(&buf, " </devices>\n") < 0)
+ goto no_memory;
+
+
+ if (qemudBufferAdd(&buf, "</domain>\n") < 0)
+ goto no_memory;
+
+ return buf.data;
+
+ no_memory:
+ qemudReportError(server, VIR_ERR_NO_MEMORY, "xml");
+ cleanup:
+ free(buf.data);
+ return NULL;
+}
+
+
+int qemudDeleteConfigXML(struct qemud_server *server, struct qemud_vm *vm) {
+ if (!vm->configFile[0]) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "no config file for guest
%s", vm->def.name);
+ return -1;
+ }
+
+ if (unlink(vm->configFile) < 0) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot remove config for
guest %s", vm->def.name);
+ return -1;
+ }
+
+ vm->configFile[0] = '\0';
+
+ return 0;
+}
+
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -ruN libvirt/qemud/config.h libvirt-qemu/qemud/config.h
--- libvirt/qemud/config.h 1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/config.h 2007-01-04 11:23:23.000000000 -0500
@@ -0,2 +1,58 @@
+/*
+ * config.h: VM configuration management
+ *
+ * Copyright (C) 2006, 2007 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#ifndef __QEMUD_CONFIG_H
+#define __QEMUD_CONFIG_H
+
+#include "internal.h"
+
+int qemudBuildCommandLine(struct qemud_server *server,
+ 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_server *server,
+ struct qemud_vm *vm);
+
+int qemudDeleteConfigXML(struct qemud_server *server,
+ struct qemud_vm *vm);
+
+
+#endif
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -ruN libvirt/qemud/dispatch.c libvirt-qemu/qemud/dispatch.c
--- libvirt/qemud/dispatch.c 1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/dispatch.c 2007-01-04 19:31:56.000000000 -0500
@@ -0,0 +1,511 @@
+/*
+ * dispatch.c: (De-)marshall wire messages to driver functions.
+ *
+ * Copyright (C) 2006, 2007 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#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);
+ out->data.failureReply.code = server->errorCode;
+ strcpy(out->data.failureReply.message, server->errorMessage);
+ 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;
+}
Hum, when qemudDomainCreate returns, we get a new vm, is that a new structure
which is gonna be ref-counted and cleaned up at some point ? I'm a bit lost
there, is that exactly the same scheme as for Xen domain instances ?
+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 funcsRW[] = {
+ NULL, /* FAILURE code */
+ qemudDispatchGetProtocolVersion,
+ qemudDispatchGetVersion,
+ qemudDispatchListDomains,
+ qemudDispatchNumDomains,
+ qemudDispatchDomainCreate,
+ qemudDispatchDomainLookupByID,
+ qemudDispatchDomainLookupByUUID,
+ qemudDispatchDomainLookupByName,
+ qemudDispatchDomainSuspend,
+ qemudDispatchDomainResume,
+ qemudDispatchDomainDestroy,
+ qemudDispatchDomainGetInfo,
+ qemudDispatchDomainSave,
+ qemudDispatchDomainRestore,
+ qemudDispatchDumpXML,
+ qemudDispatchListDefinedDomains,
+ qemudDispatchNumDefinedDomains,
+ qemudDispatchDomainStart,
+ qemudDispatchDomainDefine,
+ qemudDispatchDomainUndefine
+};
+
+clientFunc funcsRO[] = {
+ NULL, /* FAILURE code */
+ qemudDispatchGetProtocolVersion,
+ qemudDispatchGetVersion,
+ qemudDispatchListDomains,
+ qemudDispatchNumDomains,
+ NULL,
+ qemudDispatchDomainLookupByID,
+ qemudDispatchDomainLookupByUUID,
+ qemudDispatchDomainLookupByName,
+ NULL,
+ NULL,
+ NULL,
+ qemudDispatchDomainGetInfo,
+ NULL,
+ NULL,
+ qemudDispatchDumpXML,
+ qemudDispatchListDefinedDomains,
+ qemudDispatchNumDefinedDomains,
+ NULL,
+ NULL,
+ NULL,
+};
+
+/*
+ * 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) {
+ clientFunc *funcs;
+ printf("> Dispatching request %d readonly ? %d\n", in->header.type,
client->readonly);
+
+ server->errorCode = 0;
+ server->errorMessage[0] = '\0';
+
+ memset(out, 0, sizeof(struct qemud_packet));
+
+ if (in->header.type >= (sizeof(funcsRW)/sizeof(clientFunc))) {
+ printf("Illegal request type\n");
+ return -1;
+ }
+
+ if (in->header.type == QEMUD_PKT_FAILURE) {
+ printf("Illegal request type\n");
+ return -1;
+ }
+
+ if (client->readonly)
+ funcs = funcsRO;
+ else
+ funcs = funcsRW;
+
+ if (!funcs[in->header.type]) {
+ qemudReportError(server, VIR_ERR_OPERATION_DENIED, NULL);
+ qemudDispatchFailure(server, client, out);
+ } else {
+ 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;
+}
+
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -ruN libvirt/qemud/dispatch.h libvirt-qemu/qemud/dispatch.h
--- libvirt/qemud/dispatch.h 1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/dispatch.h 2007-01-04 08:37:59.000000000 -0500
@@ -0,0 +1,43 @@
+/*
+ * dispatch.h: (De-)marshall wire messages to driver functions.
+ *
+ * Copyright (C) 2006, 2007 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+
+#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
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -ruN libvirt/qemud/driver.c libvirt-qemu/qemud/driver.c
--- libvirt/qemud/driver.c 1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/driver.c 2007-01-04 12:21:02.000000000 -0500
@@ -0,0 +1,359 @@
+/*
+ * driver.c: core driver methods for managing qemu guests
+ *
+ * Copyright (C) 2006, 2007 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <libvirt/virterror.h>
+
+#include "internal.h"
+#include "driver.h"
+#include "config.h"
+
+void qemudReportError(struct qemud_server *server,
+ int code, const char *fmt, ...) {
+ va_list args;
+ server->errorCode = code;
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(server->errorMessage, QEMUD_MAX_ERROR_LEN-1, fmt, args);
+ va_end(args);
+ } else {
+ server->errorMessage[0] = '\0';
+ }
+}
+
+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) {
+ qemudReportError(server, VIR_ERR_INVALID_DOMAIN, "no domain with matching
id %d", id);
+ return -1;
+ }
+ if (vm->pid == -1) {
+ qemudReportError(server, VIR_ERR_OPERATION_FAILED, "domain is not
running");
+ return -1;
+ }
+ qemudReportError(server, VIR_ERR_OPERATION_FAILED, "suspend is not
supported");
+ return -1;
+}
+
+
+int qemudDomainResume(struct qemud_server *server, int id) {
+ struct qemud_vm *vm = qemudFindVMByID(server, id);
+ if (!vm) {
+ qemudReportError(server, VIR_ERR_INVALID_DOMAIN, "no domain with matching
id %d", id);
+ return -1;
+ }
+ if (vm->pid == -1) {
+ qemudReportError(server, VIR_ERR_OPERATION_FAILED, "domain is not
running");
+ return -1;
+ }
+ qemudReportError(server, VIR_ERR_OPERATION_FAILED, "resume is not
supported");
+ return -1;
+}
+
+
+int qemudDomainDestroy(struct qemud_server *server, int id) {
+ struct qemud_vm *vm = qemudFindVMByID(server, id);
+ if (!vm) {
+ qemudReportError(server, VIR_ERR_INVALID_DOMAIN, "no domain with matching
id %d", id);
+ return -1;
+ }
+ if (vm->pid == -1) {
+ qemudReportError(server, VIR_ERR_OPERATION_FAILED, "domain is not
running");
+ 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) {
+ qemudReportError(server, VIR_ERR_INVALID_DOMAIN, "no domain with matching
uuid");
+ 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) {
+ qemudReportError(server, VIR_ERR_INVALID_DOMAIN, "no domain with matching
id %d", id);
+ return -1;
+ }
+ if (vm->pid == -1) {
+ qemudReportError(server, VIR_ERR_OPERATION_FAILED, "domain is not
running");
+ return -1;
+ }
+ qemudReportError(server, VIR_ERR_OPERATION_FAILED, "save is not
supported");
+ return -1;
+}
+
+
+int qemudDomainRestore(struct qemud_server *server,
+ const char *path ATTRIBUTE_UNUSED) {
+ qemudReportError(server, VIR_ERR_OPERATION_FAILED, "restore is not
supported");
+ 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) {
+ qemudReportError(server, VIR_ERR_INVALID_DOMAIN, "no domain with matching
uuid");
+ return -1;
+ }
+
+ vmxml = qemudGenerateXML(server, 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) {
+ qemudReportError(server, VIR_ERR_INVALID_DOMAIN, "no domain with matching
uuid");
+ return -1;
+ }
+
+ if (vm->pid != -1) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot delete active
domain");
+ return -1;
+ }
+
+ if (qemudDeleteConfigXML(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;
+ }
+
+ qemudFreeVM(vm);
+
+ return 0;
+}
+
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -ruN libvirt/qemud/driver.h libvirt-qemu/qemud/driver.h
--- libvirt/qemud/driver.h 1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/driver.h 2007-01-04 08:38:07.000000000 -0500
@@ -0,0 +1,89 @@
+/*
+ * driver.h: core driver methods for managing qemu guests
+ *
+ * Copyright (C) 2006, 2007 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+
+#ifndef QEMUD_DRIVER_H
+#define QEMUD_DRIVER_H
+
+#include "internal.h"
+
+void qemudReportError(struct qemud_server *server,
+ int code, const char *fmt, ...);
+
+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
+
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -ruN libvirt/qemud/internal.h libvirt-qemu/qemud/internal.h
--- libvirt/qemud/internal.h 1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/internal.h 2007-01-04 20:29:22.000000000 -0500
@@ -0,0 +1,239 @@
+/*
+ * internal.h: daemon data structure definitions
+ *
+ * Copyright (C) 2006, 2007 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+
+#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
+
+/* Different types of QEMU acceleration possible */
+enum qemud_vm_virt_type {
+ QEMUD_VIRT_QEMU,
+ QEMUD_VIRT_KQEMU,
+ QEMUD_VIRT_KVM,
+};
+
+/* Stores the per-client connection state */
+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;
+};
+
+
+/* Two types of disk backends */
+enum qemud_vm_disk_type {
+ QEMUD_DISK_BLOCK,
+ QEMUD_DISK_FILE
+};
+
+/* Three types of disk frontend */
+enum qemud_vm_disk_device {
+ QEMUD_DISK_DISK,
+ QEMUD_DISK_CDROM,
+ QEMUD_DISK_FLOPPY,
+};
+
+/* Stores the virtual disk configuration */
+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
+#define QEMUD_OS_TYPE_MAX_LEN 10
+#define QEMUD_OS_ARCH_MAX_LEN 10
+#define QEMUD_OS_MACHINE_MAX_LEN 10
+
+/* 5 different types of networking config */
+enum qemud_vm_net_type {
+ QEMUD_NET_USER,
+ QEMUD_NET_TAP,
+ QEMUD_NET_SERVER,
+ QEMUD_NET_CLIENT,
+ QEMUD_NET_MCAST,
+ /* QEMUD_NET_VDE*/
+};
+
+/* Stores the virtual network interface configuration */
+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;
+};
+
+/* 3 possible boot devices */
+enum qemud_vm_boot_order {
+ QEMUD_BOOT_FLOPPY,
+ QEMUD_BOOT_CDROM,
+ QEMUD_BOOT_DISK
+};
+
+/* 3 possible graphics console modes */
+enum qemud_vm_grapics_type {
+ QEMUD_GRAPHICS_NONE,
+ QEMUD_GRAPHICS_SDL,
+ QEMUD_GRAPHICS_VNC,
+};
+
+/* Operating system configuration data & machine / arch */
+struct qemud_vm_os_def {
+ char type[QEMUD_OS_TYPE_MAX_LEN];
+ char arch[QEMUD_OS_ARCH_MAX_LEN];
+ char machine[QEMUD_OS_MACHINE_MAX_LEN];
+ int bootOrder[3];
+ char kernel[PATH_MAX];
+ char initrd[PATH_MAX];
+ char cmdline[PATH_MAX];
+ char binary[PATH_MAX];
+};
+
+/* Guest VM main configuration */
+struct qemud_vm_def {
+ int id;
+ int virtType;
+ unsigned char uuid[QEMUD_UUID_RAW_LEN];
+ char name[QEMUD_MAX_NAME_LEN];
+
+ int memory;
+ int vcpus;
+
+ struct qemud_vm_os_def os;
+
+ int graphicsType;
+ int vncPort;
+ int vncActivePort;
+
+ int ndisks;
+ struct qemud_vm_disk_def *disks;
+
+ int nnets;
+ struct qemud_vm_net_def *nets;
+};
+
+/* Guest VM runtime state */
+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_socket {
+ int fd;
+ int readonly;
+ struct qemud_socket *next;
+};
+
+/* Main server state */
+struct qemud_server {
+ int nsockets;
+ struct qemud_socket *sockets;
+ 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];
+ char errorMessage[QEMUD_MAX_ERROR_LEN];
+ int errorCode;
+};
+
+int qemudStartVMDaemon(struct qemud_server *server,
+ struct qemud_vm *vm);
+
+int qemudShutdownVMDaemon(struct qemud_server *server,
+ struct qemud_vm *vm);
+
+
+#endif
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -ruN libvirt/qemud/Makefile libvirt-qemu/qemud/Makefile
diff -ruN libvirt/qemud/Makefile.am libvirt-qemu/qemud/Makefile.am
--- libvirt/qemud/Makefile.am 1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/Makefile.am 2007-01-04 07:34:31.000000000 -0500
@@ -0,0 +1,17 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = @LIBXML_CFLAGS@
+
+libexec_PROGRAMS = libvirt_qemud
+
+libvirt_qemud_SOURCES = qemud.c internal.h protocol.h \
+ driver.c driver.h \
+ dispatch.c dispatch.h \
+ config.c config.h
+libvirt_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
+libvirt_qemud_LDFLAGS = $(LIBXML_LIBS)
+libvirt_qemud_DEPENDENCIES =
+libvirt_qemud_LDADD =
+
diff -ruN libvirt/qemud/protocol.h libvirt-qemu/qemud/protocol.h
--- libvirt/qemud/protocol.h 1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/protocol.h 2007-01-04 20:32:08.000000000 -0500
@@ -0,0 +1,206 @@
+/*
+ * protocol.h: wire protocol message format & data structures
+ *
+ * Copyright (C) 2006, 2007 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+
+#ifndef QEMUD_PROTOCOL_H__
+#define QEMUD_PROTOCOL_H__
+
+/* List of different packet types which can be sent */
+enum {
+ QEMUD_PKT_FAILURE,
+ QEMUD_PKT_GET_PROTOCOL_VERSION,
I always feel safer to initialize at least the first values in an enum.
for example QEMUD_PKT_FAILURE = 0, not strictly necessary but for client/server
stuff values I feel just better ... somehow I don't trust the way compilers
allocate enums .
+ 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_DEFAULT_PORT_STR "8123"
+
+#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
+
+/* Possible guest VM states */
+enum {
+ QEMUD_STATE_RUNNING = 1,
+ QEMUD_STATE_PAUSED,
+ QEMUD_STATE_STOPPED,
+} qemud_domain_runstate;
+
+/* Each packets has at least a fixed size header */
+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;
+};
+
+/* Most packets also have some message specific data */
+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;
+};
As suggested better to stick with predefined types with size here.
+/* Each packet has header & data */
+struct qemud_packet {
+ struct qemud_packet_header header;
+ union qemud_packet_data data;
+};
+
+
+#endif
+
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -ruN libvirt/qemud/qemud.c libvirt-qemu/qemud/qemud.c
--- libvirt/qemud/qemud.c 1969-12-31 19:00:00.000000000 -0500
+++ libvirt-qemu/qemud/qemud.c 2007-01-04 20:55:25.000000000 -0500
@@ -0,0 +1,946 @@
+/*
+ * qemud.c: daemon start of day, guest process & i/o management
+ *
+ * Copyright (C) 2006, 2007 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#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 <netinet/in.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include <libvirt/virterror.h>
+
+#include "internal.h"
+#include "dispatch.h"
+#include "driver.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 int qemudListenUnix(struct qemud_server *server,
+ const char *path, int readonly) {
+ struct qemud_socket *sock = calloc(1, sizeof(struct qemud_socket));
+ struct sockaddr_un addr;
+ mode_t oldmask;
+
+ if (!sock)
+ return -1;
+
+ sock->readonly = readonly;
+ sock->next = server->sockets;
+ server->sockets = sock;
+ server->nsockets++;
+
+ if ((sock->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
+ return -1;
+
+ if (qemudSetCloseExec(sock->fd) < 0)
+ return -1;
+ if (qemudSetNonBlock(sock->fd) < 0)
+ return -1;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1);
+ /* Use '@' to indicate abstract socket namespace */
+ if (path[0] == '@') {
+ addr.sun_path[0] = '\0';
+ } else {
+ unlink(addr.sun_path);
+ }
+
+ if (readonly)
+ oldmask = umask(~(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH));
+ else
+ oldmask = umask(~(S_IRUSR | S_IWUSR));
+ if (bind(sock->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
sock is not freed here, it's still linked in the server sockets list,
rather bizarre, no ?
+ return -1;
+ umask(oldmask);
+
+ if (listen(sock->fd, 30) < 0)
Same here, I don't understand the error handling :-)
+ return -1;
+
+ return 0;
+}
+
+static int qemudListenAddr(struct qemud_server *server,
+ const char *addr, int readonly) {
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ struct addrinfo *tmp;
+ char *node, *offset;
+ const char *service;
+
+ node = strdup(addr);
+ if (!node)
+ return -1;
+
+ if (!(offset = strstr(node, ","))) {
+ service = QEMUD_DEFAULT_PORT_STR;
+ } else {
+ offset[0] = '\0';
+ service = offset + 1;
+ }
+
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_NUMERICSERV;
+ hints.ai_socktype = SOCK_STREAM;
+ if (getaddrinfo (node, service, &hints, &ai) < 0) {
+ free(node);
+ return -1;
+ }
+ free(node);
+
+ tmp = ai;
+ while (tmp != NULL) {
+ int opt = 1;
+ struct qemud_socket *sock = calloc(1, sizeof(struct qemud_socket));
+ if (!sock)
+ goto error;
+
+ sock->readonly = readonly;
+ sock->next = server->sockets;
+ server->sockets = sock;
+ server->nsockets++;
+
+ if ((sock->fd = socket (tmp->ai_family, tmp->ai_socktype,
+ tmp->ai_protocol)) < 0)
+ goto error;
+
+ if (qemudSetCloseExec(sock->fd) < 0)
+ goto error;
+
+ if (qemudSetNonBlock(sock->fd) < 0)
+ goto error;
+
+ if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR,
+ &opt, sizeof (opt)) < 0)
+ goto error;
+
+ if (bind (sock->fd, tmp->ai_addr, tmp->ai_addrlen) < 0)
+ goto error;
+
+ if (listen (sock->fd, SOMAXCONN) < 0)
+ goto error;
+
+ tmp = tmp->ai_next;
+ }
+
+ freeaddrinfo (ai);
+ return 0;
+
+ error:
+ freeaddrinfo (ai);
+ return -1;
+}
+
+static int qemudListen(struct qemud_server *server,
+ const char *listenAddr) {
+ int readonly = 0;
+
+ if (!strncmp(listenAddr, "ro:", 3)) {
+ readonly = 1;
+ listenAddr += 3;
+ }
wouldn't "ro-" (or ro+ or ro.) be cleaner, allowing to stick it in front
of any URI and still keeping it URI-valid ?
+ if (listenAddr[0] == '/' ||
+ (listenAddr[0] == '@' && listenAddr[1] == '/')) {
+ if (qemudListenUnix(server, listenAddr, readonly) < 0)
+ return -1;
+ } else {
+ if (qemudListenAddr(server, listenAddr, readonly) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct qemud_server *qemudInitialize(char **listenAddrs,
+ int naddrs) {
+ struct qemud_server *server;
+ int i;
+ char path[PATH_MAX];
+ struct passwd *pw;
+ int uid, ret;
+
+ if (!(server = calloc(1, sizeof(struct qemud_server))))
+ return NULL;
+
+ /* 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;
+ }
Hum, at some point the directory modes and ownership should be tested and
possibly created, and I guess the sooner the better, why not there ? But I
may have missed the check (or not gone there yet :-)
+ for (i = 0 ; i < naddrs ; i++) {
+ if (qemudListen(server, listenAddrs[i]) < 0)
+ goto cleanup;
+ }
+
+ if (qemudScanConfigs(server) < 0) {
+ goto cleanup;
+ }
+
+ return server;
+
+ cleanup:
+ if (server) {
+ struct qemud_socket *sock = server->sockets;
+ while (sock) {
+ close(sock->fd);
+ sock = sock->next;
+ }
+
+ free(server);
+ }
+ return NULL;
+}
+
+
+static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket *sock)
{
+ int fd;
+ struct sockaddr_storage addr;
+ unsigned int addrlen = sizeof(addr);
+ struct qemud_client *client;
+
+ if ((fd = accept(sock->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));
calloc return check missing, close of fd in that case
+ client->fd = fd;
+ client->next = server->clients;
+ client->readonly = sock->readonly;
+ 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 stdinfd = -1;
+ int pipeout[2] = {-1,-1};
+ int pipeerr[2] = {-1,-1};
+
+ if (vm->def.vncPort < 0)
+ vm->def.vncActivePort = 5900 + server->nextvmid;
+ else
+ vm->def.vncActivePort = vm->def.vncPort;
+
+ if (qemudBuildCommandLine(server, vm, &argv, &argc) < 0)
+ return -1;
+
+ if (1) { /* XXX debug stuff */
+ printf("Spawn QEMU '");
+ for (i = 0 ; i < argc; i++) {
+ printf("%s", argv[i]);
+ if (i == (argc-1))
+ printf("'\n");
+ else
+ printf(" ");
+ }
+ }
+
+ if ((stdinfd = open(_PATH_DEVNULL, O_RDONLY)) < 0) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot open %s",
_PATH_DEVNULL);
+ goto cleanup;
+ }
+
+ if (pipe(pipeout) < 0) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot create
pipe");
+ goto cleanup;
+ }
+
+ if (pipe(pipeerr) < 0) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot create
pipe");
+ goto cleanup;
+ }
+
+ if ((pid = fork()) < 0) {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot fork child
process");
+ goto cleanup;
+ }
+
+ if (pid) { /* parent */
+ close(stdinfd);
+ 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 { /* child */
+ 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(stdinfd, STDIN_FILENO) < 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 cleaned-up */
+ if (vm->pid < 0)
+ return 0;
+
+ kill(vm->pid, SIGTERM);
+
+ /* Move it to inactive vm list */
+ while (curr) {
+ if (curr == vm) {
+ if (prev) {
+ prev->next = curr->next;
+ } else {
+ server->activevms = curr->next;
+ }
+ server->nactivevms--;
+
+ 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) {
+ printf("Got unexpected pid, damn\n");
+ }
+ }
+
+ vm->pid = -1;
+ vm->def.id = -1;
+
+ 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_socket *sock = server->sockets;
+ struct qemud_client *client = server->clients;
+ struct qemud_vm *vm = server->activevms;
+ struct qemud_vm *tmp;
+ int ret = 0;
+ int fd = 0;
+
+ while (sock) {
+ struct qemud_socket *next = sock->next;
+ if (fds[fd].revents)
+ if (qemudDispatchServer(server, sock) < 0)
+ return -1;
+ fd++;
+ sock = next;
+ }
+
+ 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;
+ }
+
+ /* Cleanup any VMs which shutdown & dont have an associated
+ config file */
+ vm = server->inactivevms;
+ tmp = NULL;
+ while (vm) {
+ if (!vm->configFile[0]) {
+ struct qemud_vm *next = vm->next;
+ if (tmp) {
+ tmp->next = next;
+ } else {
+ server->inactivevms = next;
+ }
+ qemudFreeVM(vm);
+ vm = next;
+ } else {
+ tmp = vm;
+ vm = vm->next;
+ }
+ }
+
+ return ret;
+}
+
+static void qemudPreparePoll(struct qemud_server *server, struct pollfd *fds) {
+ int fd = 0;
+
+ for (struct qemud_socket *sock = server->sockets ; sock ; sock = sock->next)
{
+ fds[fd].fd = sock->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 timeout) {
+ int nfds = server->nsockets + server->nclients + server->nvmfds;
+ struct pollfd fds[nfds];
+ int thistimeout = -1;
+ int ret;
+
+ /* If we have no clients or vms, then timeout after
+ 30 seconds, letting daemon exit */
+ if (timeout > 0 &&
+ !server->nclients &&
+ !server->nactivevms)
+ thistimeout = timeout;
+
+ qemudPreparePoll(server, fds);
+
+ retry:
+
+ if ((ret = poll(fds, nfds, thistimeout * 1000)) < 0) {
+ if (errno == EINTR) {
+ goto retry;
+ }
+ return -1;
+ }
+
+ /* Must have timed out */
+ if (ret == 0)
+ return -1;
+
+ if (qemudDispatchPoll(server, fds) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int qemudRunLoop(struct qemud_server *server, int timeout) {
+ int ret;
+
+ while ((ret = qemudOneLoop(server, timeout)) == 0)
+ ;
+
+ return ret == -1 ? -1 : 0;
+}
+
+static void qemudCleanup(struct qemud_server *server) {
+ struct qemud_socket *sock = server->sockets;
+ while (sock) {
+ close(sock->fd);
+ sock = sock->next;
+ }
+ free(server);
+}
+
+#define MAX_LISTEN 5
+int main(int argc, char **argv) {
+ int daemon = 0;
+ int verbose = 0;
+ int timeout = -1;
+ char *listenAddrs[MAX_LISTEN];
+ int naddrs = 0;
+
+ struct option opts[] = {
+ { "verbose", no_argument, &verbose, 1},
+ { "daemon", no_argument, &daemon, 1},
+ { "timeout", required_argument, 0, 't'},
+ { "listen", required_argument, 0, 'l' },
+ {0, 0, 0, 0}
+ };
+
+ while (1) {
+ int optidx = 0;
+ int c;
+ char *tmp;
+
+ c = getopt_long(argc, argv, "vdt:u:U:l:L:", opts, &optidx);
+
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 0:
+ /* Got one of the flags */
+ break;
+ case 't':
+ timeout = strtol(optarg, &tmp, 10);
+ if (!tmp)
+ timeout = -1;
+ if (timeout <= 0)
+ timeout = -1;
+ break;
+ case 'l':
+ if (naddrs >= MAX_LISTEN)
+ abort();
+ if (!(listenAddrs[naddrs] = strdup(optarg)))
+ abort();
+ naddrs++;
+ break;
+ case '?':
+ /* getopt_long already printed error message */
+ break;
+ default:
+ abort();
+ }
+ }
+
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+ return 3;
+ if (signal(SIGCHLD, reapchild) == SIG_ERR)
+ return 3;
+
+ if (daemon) {
+ int pid = qemudGoDaemon();
+ if (pid < 0)
+ return 1;
+ if (pid > 0)
+ return 0;
+ }
+
+ struct qemud_server *server = qemudInitialize(listenAddrs, naddrs);
+
+ if (!server)
+ return 2;
+
+ qemudRunLoop(server, timeout);
+
+ qemudCleanup(server);
+
+ return 0;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
--
Libvir-list mailing list
Libvir-list(a)redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
--
Red Hat Virtualization group
http://redhat.com/virtualization/
Daniel Veillard | virtualization library
http://libvirt.org/
veillard(a)redhat.com | libxml GNOME XML XSLT toolkit
http://xmlsoft.org/
http://veillard.com/ | Rpmfind RPM search engine
http://rpmfind.net/