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@xxxxxxxxxx> > + */ > + > +#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@xxxxxxxxxx> > + */ > + > +#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@xxxxxxxxxx> > + */ > + > +#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@xxxxxxxxxx> > + */ > + > + > +#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@xxxxxxxxxx> > + */ > + > +#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@xxxxxxxxxx> > + */ > + > + > +#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@xxxxxxxxxx> > + */ > + > + > +#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@xxxxxxxxxx> > + */ > + > + > +#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@xxxxxxxxxx> > + */ > + > +#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@xxxxxxxxxx > https://www.redhat.com/mailman/listinfo/libvir-list -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@xxxxxxxxxx | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/