diff --git a/ChangeLog b/ChangeLog index 8e332df7a1..f7d6bdd11f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Fri Jul 11 20:32:59 BST 2008 Daniel P. Berrange + + * src/qemu_conf.c, src/qemu_conf.h, src/qemu_driver.c: Switch + over to generic domain APIs + * src/bridge.c, src/bridge.h: Allocate tap device string on + demand. + * tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Update + to new APIs + * tests/qemuxml2argvdata/: Update data files to match new + XML generation format + Fri Jul 11 20:28:59 BST 2008 Daniel P. Berrange * src/domain_conf.c: Set state to SHUTOFF when loading domain @@ -8,15 +19,6 @@ Fri Jul 11 18:58:59 BST 2008 Daniel P. Berrange * src/network_conf.c, src/domain_conf.c: Use full path when opening XML files -Fri Jul 11 18:34:59 BST 2008 Daniel P. Berrange - - * src/qemu_conf.c, src/qemu_conf.h, src/qemu_driver.c: Switch - over to generic domain APIs - * tests/qemuxml2argvtest.c, tests/qemuxml2xmltest.c: Update - to new APIs - * tests/qemuxml2argvdata/: Update data files to match new - XML generation format - Fri Jul 11 18:32:59 BST 2008 Daniel P. Berrange * src/bridge.c, src/bridge.h, src/qemu_conf.c, src/qemu_conf.h, diff --git a/src/bridge.c b/src/bridge.c index 9a77f2b981..ea5d5ab8b6 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -281,7 +281,6 @@ brDeleteInterface(brControl *ctl ATTRIBUTE_UNUSED, * @ctl: bridge control pointer * @bridge: the bridge name * @ifname: the interface name (or name template) - * @maxlen: size of @ifname array * @tapfd: file descriptor return value for the new tap device * * This function creates a new tap device on a bridge. @ifname can be either @@ -294,8 +293,7 @@ brDeleteInterface(brControl *ctl ATTRIBUTE_UNUSED, int brAddTap(brControl *ctl, const char *bridge, - char *ifname, - int maxlen, + char **ifname, int *tapfd) { int id, subst, fd; @@ -305,7 +303,7 @@ brAddTap(brControl *ctl, subst = id = 0; - if (strstr(ifname, "%d")) + if (strstr(*ifname, "%d")) subst = 1; if ((fd = open("/dev/net/tun", O_RDWR)) < 0) @@ -320,19 +318,19 @@ brAddTap(brControl *ctl, try.ifr_flags = IFF_TAP|IFF_NO_PI; if (subst) { - len = snprintf(try.ifr_name, maxlen, ifname, id); - if (len >= maxlen) { + len = snprintf(try.ifr_name, BR_IFNAME_MAXLEN, *ifname, id); + if (len >= BR_IFNAME_MAXLEN) { errno = EADDRINUSE; goto error; } } else { - len = strlen(ifname); - if (len >= maxlen - 1) { + len = strlen(*ifname); + if (len >= BR_IFNAME_MAXLEN - 1) { errno = EINVAL; goto error; } - strncpy(try.ifr_name, ifname, len); + strncpy(try.ifr_name, *ifname, len); try.ifr_name[len] = '\0'; } @@ -341,8 +339,11 @@ brAddTap(brControl *ctl, goto error; if ((errno = brSetInterfaceUp(ctl, try.ifr_name, 1))) goto error; - if (ifname) - strncpy(ifname, try.ifr_name, maxlen); + VIR_FREE(*ifname); + if (!(*ifname = strdup(try.ifr_name))) { + errno = ENOMEM; + goto error; + } *tapfd = fd; return 0; } diff --git a/src/bridge.h b/src/bridge.h index ac4559b4b1..03076e3b7c 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -60,8 +60,7 @@ int brDeleteInterface (brControl *ctl, int brAddTap (brControl *ctl, const char *bridge, - char *ifname, - int maxlen, + char **ifname, int *tapfd); int brSetInterfaceUp (brControl *ctl, diff --git a/src/qemu_conf.c b/src/qemu_conf.c index d0fc777581..02b702e7de 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -37,16 +37,10 @@ #include #include -#include -#include -#include -#include - #if HAVE_NUMACTL #include #endif -#include "internal.h" #include "qemu_conf.h" #include "uuid.h" #include "buf.h" @@ -55,7 +49,15 @@ #include "memory.h" #include "verify.h" #include "c-ctype.h" -#include "xml.h" + +VIR_ENUM_DECL(virDomainDiskQEMUBus) +VIR_ENUM_IMPL(virDomainDiskQEMUBus, VIR_DOMAIN_DISK_BUS_LAST, + "ide", + "floppy", + "scsi", + "virtio", + "xen") + #define qemudLog(level, msg...) fprintf(stderr, msg) @@ -64,12 +66,12 @@ void qemudReportError(virConnectPtr conn, virNetworkPtr net, int code, const char *fmt, ...) { va_list args; - char errorMessage[QEMUD_MAX_ERROR_LEN]; + char errorMessage[1024]; const char *virerr; if (fmt) { va_start(args, fmt); - vsnprintf(errorMessage, QEMUD_MAX_ERROR_LEN-1, fmt, args); + vsnprintf(errorMessage, sizeof(errorMessage)-1, fmt, args); va_end(args); } else { errorMessage[0] = '\0'; @@ -86,7 +88,11 @@ int qemudLoadDriverConfig(struct qemud_driver *driver, virConfValuePtr p; /* Setup 2 critical defaults */ - strcpy(driver->vncListen, "127.0.0.1"); + if (!(driver->vncListen = strdup("127.0.0.1"))) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_MEMORY, + "%s", _("failed to allocate vncListen")); + return -1; + } if (!(driver->vncTLSx509certdir = strdup(SYSCONF_DIR "/pki/libvirt-vnc"))) { qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_MEMORY, "%s", _("failed to allocate vncTLSx509certdir")); @@ -133,105 +139,18 @@ int qemudLoadDriverConfig(struct qemud_driver *driver, p = virConfGetValue (conf, "vnc_listen"); CHECK_TYPE ("vnc_listen", VIR_CONF_STRING); if (p && p->str) { - strncpy(driver->vncListen, p->str, sizeof(driver->vncListen)); - driver->vncListen[sizeof(driver->vncListen)-1] = '\0'; + if (!(driver->vncListen = strdup(p->str))) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_MEMORY, + "%s", _("failed to allocate vncTLSx509certdir")); + virConfFree(conf); + return -1; + } } virConfFree (conf); return 0; } - -struct qemud_vm *qemudFindVMByID(const struct qemud_driver *driver, int id) { - struct qemud_vm *vm = driver->vms; - - while (vm) { - if (qemudIsActiveVM(vm) && vm->id == id) - return vm; - vm = vm->next; - } - - return NULL; -} - -struct qemud_vm *qemudFindVMByUUID(const struct qemud_driver *driver, - const unsigned char *uuid) { - struct qemud_vm *vm = driver->vms; - - while (vm) { - if (!memcmp(vm->def->uuid, uuid, VIR_UUID_BUFLEN)) - return vm; - vm = vm->next; - } - - return NULL; -} - -struct qemud_vm *qemudFindVMByName(const struct qemud_driver *driver, - const char *name) { - struct qemud_vm *vm = driver->vms; - - while (vm) { - if (STREQ(vm->def->name, name)) - return vm; - vm = vm->next; - } - - return NULL; -} - - -/* Free all memory associated with a struct qemud_vm object */ -void qemudFreeVMDef(struct qemud_vm_def *def) { - struct qemud_vm_disk_def *disk = def->disks; - struct qemud_vm_net_def *net = def->nets; - struct qemud_vm_input_def *input = def->inputs; - struct qemud_vm_chr_def *serial = def->serials; - struct qemud_vm_chr_def *parallel = def->parallels; - struct qemud_vm_sound_def *sound = def->sounds; - - while (disk) { - struct qemud_vm_disk_def *prev = disk; - disk = disk->next; - VIR_FREE(prev); - } - while (net) { - struct qemud_vm_net_def *prev = net; - net = net->next; - VIR_FREE(prev); - } - while (input) { - struct qemud_vm_input_def *prev = input; - input = input->next; - VIR_FREE(prev); - } - while (serial) { - struct qemud_vm_chr_def *prev = serial; - serial = serial->next; - VIR_FREE(prev); - } - while (parallel) { - struct qemud_vm_chr_def *prev = parallel; - parallel = parallel->next; - VIR_FREE(prev); - } - while (sound) { - struct qemud_vm_sound_def *prev = sound; - sound = sound->next; - VIR_FREE(prev); - } - xmlFree(def->keymap); - VIR_FREE(def); -} - -void qemudFreeVM(struct qemud_vm *vm) { - qemudFreeVMDef(vm->def); - if (vm->newDef) - qemudFreeVMDef(vm->newDef); - VIR_FREE(vm); -} - - /* The list of possible machine types for various architectures, as supported by QEMU - taken from 'qemu -M ?' for each arch */ static const char *const arch_info_hvm_x86_machines[] = { @@ -477,12 +396,14 @@ virCapsPtr qemudCapsInit(void) { } -static int qemudExtractVersionInfo(const char *qemu, int *version, int *flags) { +int qemudExtractVersionInfo(const char *qemu, int *version, int *flags) { pid_t child; int newstdout[2]; - *flags = 0; - *version = 0; + if (flags) + *flags = 0; + if (version) + *version = 0; if (pipe(newstdout) < 0) { return -1; @@ -517,6 +438,7 @@ static int qemudExtractVersionInfo(const char *qemu, int *version, int *flags) { char help[8192]; /* Ought to be enough to hold QEMU help screen */ int got = 0, ret = -1; int major, minor, micro; + int ver; if (close(newstdout[1]) < 0) goto cleanup2; @@ -538,19 +460,23 @@ static int qemudExtractVersionInfo(const char *qemu, int *version, int *flags) { goto cleanup2; } - *version = (major * 1000 * 1000) + (minor * 1000) + micro; - if (strstr(help, "-no-kqemu")) - *flags |= QEMUD_CMD_FLAG_KQEMU; - if (strstr(help, "-no-reboot")) - *flags |= QEMUD_CMD_FLAG_NO_REBOOT; - if (strstr(help, "-name")) - *flags |= QEMUD_CMD_FLAG_NAME; - if (strstr(help, "-drive")) - *flags |= QEMUD_CMD_FLAG_DRIVE; - if (strstr(help, "boot=on")) - *flags |= QEMUD_CMD_FLAG_DRIVE_BOOT; - if (*version >= 9000) - *flags |= QEMUD_CMD_FLAG_VNC_COLON; + ver = (major * 1000 * 1000) + (minor * 1000) + micro; + if (version) + *version = ver; + if (flags) { + if (strstr(help, "-no-kqemu")) + *flags |= QEMUD_CMD_FLAG_KQEMU; + if (strstr(help, "-no-reboot")) + *flags |= QEMUD_CMD_FLAG_NO_REBOOT; + if (strstr(help, "-name")) + *flags |= QEMUD_CMD_FLAG_NAME; + if (strstr(help, "-drive")) + *flags |= QEMUD_CMD_FLAG_DRIVE; + if (strstr(help, "boot=on")) + *flags |= QEMUD_CMD_FLAG_DRIVE_BOOT; + if (ver >= 9000) + *flags |= QEMUD_CMD_FLAG_VNC_COLON; + } ret = 0; qemudDebug("Version %d %d %d Cooked version: %d, with flags ? %d", @@ -612,1663 +538,53 @@ int qemudExtractVersion(virConnectPtr conn, return 0; } -/* Converts def->virtType to applicable string type - * @param type integer virt type - * @return string type on success, NULL on fail - */ -const char * qemudVirtTypeToString(int type) { - switch (type) { - case QEMUD_VIRT_QEMU: - return "qemu"; - case QEMUD_VIRT_KQEMU: - return "kqemu"; - case QEMUD_VIRT_KVM: - return "kvm"; - } - return NULL; -} - -/* Parse the XML definition for a disk - * @param disk pre-allocated & zero'd disk record - * @param node XML nodeset to parse for disk definition - * @return 0 on success, -1 on failure - */ -static int qemudParseDiskXML(virConnectPtr conn, - struct qemud_vm_disk_def *disk, - xmlNodePtr node) { - xmlNodePtr cur; - xmlChar *device = NULL; - xmlChar *source = NULL; - xmlChar *target = NULL; - xmlChar *type = NULL; - xmlChar *bus = NULL; - int typ = 0; - - type = xmlGetProp(node, BAD_CAST "type"); - if (type != NULL) { - if (xmlStrEqual(type, BAD_CAST "file")) - typ = QEMUD_DISK_FILE; - else if (xmlStrEqual(type, BAD_CAST "block")) - typ = QEMUD_DISK_BLOCK; - else { - 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"); - bus = xmlGetProp(cur, BAD_CAST "bus"); - } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) { - disk->readonly = 1; - } - } - cur = cur->next; - } - - if (source == NULL) { - /* There is a case without the source - * to the CD-ROM device - */ - if (!device || STRNEQ((const char *) device, "cdrom")) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SOURCE, - target ? "%s" : NULL, target); - goto error; - } - } - - if (target == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_TARGET, source ? "%s" : NULL, source); - goto error; - } - - if (device && - STREQ((const char *)device, "floppy") && - STRNEQ((const char *)target, "fda") && - STRNEQ((const char *)target, "fdb")) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("Invalid floppy device name: %s"), target); - goto error; - } - - if (device && - STREQ((const char *)device, "cdrom") && - STRNEQ((const char *)target, "hdc")) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("Invalid cdrom device name: %s"), target); - goto error; - } - - if (device && - STREQ((const char *)device, "cdrom")) - disk->readonly = 1; - - if ((!device || STREQ((const char *)device, "disk")) && - !STRPREFIX((const char *)target, "hd") && - !STRPREFIX((const char *)target, "sd") && - !STRPREFIX((const char *)target, "vd") && - !STRPREFIX((const char *)target, "xvd")) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("Invalid harddisk device name: %s"), target); - goto error; - } - - strncpy(disk->src, (source ? (const char *) source : "\0"), 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 (STREQ((const char *)device, "disk")) - disk->device = QEMUD_DISK_DISK; - else if (STREQ((const char *)device, "cdrom")) - disk->device = QEMUD_DISK_CDROM; - else if (STREQ((const char *)device, "floppy")) - disk->device = QEMUD_DISK_FLOPPY; - else { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("Invalid device type: %s"), device); - goto error; - } - - if (!bus) { - if (disk->device == QEMUD_DISK_FLOPPY) { - disk->bus = QEMUD_DISK_BUS_FDC; - } else { - if (STRPREFIX((const char *)target, "hd")) - disk->bus = QEMUD_DISK_BUS_IDE; - else if (STRPREFIX((const char *)target, "sd")) - disk->bus = QEMUD_DISK_BUS_SCSI; - else if (STRPREFIX((const char *)target, "vd")) - disk->bus = QEMUD_DISK_BUS_VIRTIO; - else if (STRPREFIX((const char *)target, "xvd")) - disk->bus = QEMUD_DISK_BUS_XEN; - else - disk->bus = QEMUD_DISK_BUS_IDE; - } - } else if (STREQ((const char *)bus, "ide")) - disk->bus = QEMUD_DISK_BUS_IDE; - else if (STREQ((const char *)bus, "fdc")) - disk->bus = QEMUD_DISK_BUS_FDC; - else if (STREQ((const char *)bus, "scsi")) - disk->bus = QEMUD_DISK_BUS_SCSI; - else if (STREQ((const char *)bus, "virtio")) - disk->bus = QEMUD_DISK_BUS_VIRTIO; - else if (STREQ((const char *)bus, "xen")) - disk->bus = QEMUD_DISK_BUS_XEN; - else { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("Invalid bus type: %s"), bus); - goto error; - } - - if (disk->device == QEMUD_DISK_FLOPPY && - disk->bus != QEMUD_DISK_BUS_FDC) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("Invalid bus type '%s' for floppy disk"), bus); - goto error; - } - - xmlFree(device); - xmlFree(target); - xmlFree(source); - xmlFree(bus); - - return 0; - - error: - xmlFree(bus); - xmlFree(type); - xmlFree(target); - xmlFree(source); - xmlFree(device); - return -1; -} - -static void qemudRandomMAC(struct qemud_vm_net_def *net) { - net->mac[0] = 0x52; - net->mac[1] = 0x54; - net->mac[2] = 0x00; - net->mac[3] = 1 + (int)(256*(rand()/(RAND_MAX+1.0))); - net->mac[4] = 1 + (int)(256*(rand()/(RAND_MAX+1.0))); - net->mac[5] = 1 + (int)(256*(rand()/(RAND_MAX+1.0))); -} - - -/* Parse the XML definition for a network interface - * @param net pre-allocated & zero'd net record - * @param node XML nodeset to parse for net definition - * @return 0 on success, -1 on failure - */ -static int qemudParseInterfaceXML(virConnectPtr conn, - struct qemud_vm_net_def *net, - xmlNodePtr node) { - xmlNodePtr cur; - xmlChar *macaddr = NULL; - xmlChar *type = NULL; - xmlChar *network = NULL; - xmlChar *bridge = NULL; - xmlChar *ifname = NULL; - xmlChar *script = NULL; - xmlChar *address = NULL; - xmlChar *port = NULL; - xmlChar *model = 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 "ethernet")) - net->type = QEMUD_NET_ETHERNET; - 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 "network")) - net->type = QEMUD_NET_NETWORK; - else if (xmlStrEqual(type, BAD_CAST "bridge")) - net->type = QEMUD_NET_BRIDGE; - 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"); - } else if ((network == NULL) && - (net->type == QEMUD_NET_NETWORK) && - (xmlStrEqual(cur->name, BAD_CAST "source"))) { - network = xmlGetProp(cur, BAD_CAST "network"); - } else if ((network == NULL) && - (net->type == QEMUD_NET_BRIDGE) && - (xmlStrEqual(cur->name, BAD_CAST "source"))) { - bridge = xmlGetProp(cur, BAD_CAST "bridge"); - } else if ((network == NULL) && - ((net->type == QEMUD_NET_SERVER) || - (net->type == QEMUD_NET_CLIENT) || - (net->type == QEMUD_NET_MCAST)) && - (xmlStrEqual(cur->name, BAD_CAST "source"))) { - address = xmlGetProp(cur, BAD_CAST "address"); - port = xmlGetProp(cur, BAD_CAST "port"); - } else if ((ifname == NULL) && - ((net->type == QEMUD_NET_NETWORK) || - (net->type == QEMUD_NET_ETHERNET) || - (net->type == QEMUD_NET_BRIDGE)) && - xmlStrEqual(cur->name, BAD_CAST "target")) { - ifname = xmlGetProp(cur, BAD_CAST "dev"); - if (STRPREFIX((const char*)ifname, "vnet")) { - /* An auto-generated target name, blank it out */ - xmlFree(ifname); - ifname = NULL; - } - } else if ((script == NULL) && - (net->type == QEMUD_NET_ETHERNET) && - xmlStrEqual(cur->name, BAD_CAST "script")) { - script = xmlGetProp(cur, BAD_CAST "path"); - } else if (xmlStrEqual (cur->name, BAD_CAST "model")) { - model = xmlGetProp (cur, BAD_CAST "type"); - } - } - cur = cur->next; - } - - if (macaddr) { - unsigned int mac[6]; - sscanf((const char *)macaddr, "%02x:%02x:%02x:%02x:%02x:%02x", - (unsigned int*)&mac[0], - (unsigned int*)&mac[1], - (unsigned int*)&mac[2], - (unsigned int*)&mac[3], - (unsigned int*)&mac[4], - (unsigned int*)&mac[5]); - net->mac[0] = mac[0]; - net->mac[1] = mac[1]; - net->mac[2] = mac[2]; - net->mac[3] = mac[3]; - net->mac[4] = mac[4]; - net->mac[5] = mac[5]; - - xmlFree(macaddr); - macaddr = NULL; - } else { - qemudRandomMAC(net); - } - - if (net->type == QEMUD_NET_NETWORK) { - int len; - - if (network == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("No 'network' attribute specified with ")); - goto error; - } else if ((len = xmlStrlen(network)) >= (QEMUD_MAX_NAME_LEN-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("Network name '%s' too long"), network); - goto error; - } else { - strncpy(net->dst.network.name, (char *)network, len); - net->dst.network.name[len] = '\0'; - } - - if (network) { - xmlFree(network); - network = NULL; - } - - if (ifname != NULL) { - if ((len = xmlStrlen(ifname)) >= (BR_IFNAME_MAXLEN-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("TAP interface name '%s' is too long"), - ifname); - goto error; - } else { - strncpy(net->dst.network.ifname, (char *)ifname, len); - net->dst.network.ifname[len] = '\0'; - } - xmlFree(ifname); - ifname = NULL; - } - } else if (net->type == QEMUD_NET_ETHERNET) { - int len; - - if (script != NULL) { - if ((len = xmlStrlen(script)) >= (PATH_MAX-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("TAP script path '%s' is too long"), script); - goto error; - } else { - strncpy(net->dst.ethernet.script, (char *)script, len); - net->dst.ethernet.script[len] = '\0'; - } - xmlFree(script); - script = NULL; - } - if (ifname != NULL) { - if ((len = xmlStrlen(ifname)) >= (BR_IFNAME_MAXLEN-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("TAP interface name '%s' is too long"), - ifname); - goto error; - } else { - strncpy(net->dst.ethernet.ifname, (char *)ifname, len); - net->dst.ethernet.ifname[len] = '\0'; - } - xmlFree(ifname); - } - } else if (net->type == QEMUD_NET_BRIDGE) { - int len; - - if (bridge == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("No 'dev' attribute specified with ")); - goto error; - } else if ((len = xmlStrlen(bridge)) >= (BR_IFNAME_MAXLEN-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("TAP bridge path '%s' is too long"), bridge); - goto error; - } else { - strncpy(net->dst.bridge.brname, (char *)bridge, len); - net->dst.bridge.brname[len] = '\0'; - } - - xmlFree(bridge); - bridge = NULL; - - if (ifname != NULL) { - if ((len = xmlStrlen(ifname)) >= (BR_IFNAME_MAXLEN-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("TAP interface name '%s' is too long"), ifname); - goto error; - } else { - strncpy(net->dst.bridge.ifname, (char *)ifname, len); - net->dst.bridge.ifname[len] = '\0'; - } - xmlFree(ifname); - } - } else if (net->type == QEMUD_NET_CLIENT || - net->type == QEMUD_NET_SERVER || - net->type == QEMUD_NET_MCAST) { - int len = 0; - char *ret; - - if (port == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("No 'port' attribute specified with socket interface")); - goto error; - } - if (!(net->dst.socket.port = strtol((char*)port, &ret, 10)) && - ret == (char*)port) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("Cannot parse 'port' attribute with socket interface")); - goto error; - } - xmlFree(port); - port = NULL; - - if (address == NULL) { - if (net->type == QEMUD_NET_CLIENT || - net->type == QEMUD_NET_MCAST) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("No 'address' attribute specified with socket interface")); - goto error; - } - } else if ((len = xmlStrlen(address)) >= (BR_INET_ADDR_MAXLEN)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("IP address '%s' is too long"), address); - goto error; - } - if (address == NULL) { - net->dst.socket.address[0] = '\0'; - } else { - strncpy(net->dst.socket.address, (char*)address,len); - net->dst.socket.address[len] = '\0'; - } - xmlFree(address); - } - - /* NIC model (see -net nic,model=?). We only check that it looks - * reasonable, not that it is a supported NIC type. FWIW kvm - * supports these types as of April 2008: - * i82551 i82557b i82559er ne2k_pci pcnet rtl8139 e1000 virtio - */ - if (model != NULL) { - int i, len; - - len = xmlStrlen (model); - if (len >= QEMUD_MODEL_MAX_LEN) { - qemudReportError (conn, NULL, NULL, VIR_ERR_INVALID_ARG, - _("Model name '%s' is too long"), model); - goto error; - } - for (i = 0; i < len; ++i) { - int char_ok = c_isalnum(model[i]) || model[i] == '_'; - if (!char_ok) { - qemudReportError (conn, NULL, NULL, VIR_ERR_INVALID_ARG, "%s", - _("Model name contains invalid characters")); - goto error; - } - } - strncpy (net->model, (const char*) model, len); - net->model[len] = '\0'; - - xmlFree (model); - model = NULL; - } else - net->model[0] = '\0'; - - return 0; - - error: - xmlFree(network); - xmlFree(address); - xmlFree(port); - xmlFree(ifname); - xmlFree(script); - xmlFree(bridge); - xmlFree(model); - return -1; -} - - -/* Parse the XML definition for a character device - * @param net pre-allocated & zero'd net record - * @param node XML nodeset to parse for net definition - * @return 0 on success, -1 on failure - * - * The XML we're dealing with looks like - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ -static int qemudParseCharXML(virConnectPtr conn, - struct qemud_vm_chr_def *chr, - int portNum, - xmlNodePtr node) { - xmlNodePtr cur; - xmlChar *type = NULL; - xmlChar *bindHost = NULL; - xmlChar *bindService = NULL; - xmlChar *connectHost = NULL; - xmlChar *connectService = NULL; - xmlChar *path = NULL; - xmlChar *mode = NULL; - xmlChar *protocol = NULL; - int ret = -1; - - chr->srcType = QEMUD_CHR_SRC_TYPE_PTY; - type = xmlGetProp(node, BAD_CAST "type"); - if (type != NULL) { - if (xmlStrEqual(type, BAD_CAST "null")) - chr->srcType = QEMUD_CHR_SRC_TYPE_NULL; - else if (xmlStrEqual(type, BAD_CAST "vc")) - chr->srcType = QEMUD_CHR_SRC_TYPE_VC; - else if (xmlStrEqual(type, BAD_CAST "pty")) - chr->srcType = QEMUD_CHR_SRC_TYPE_PTY; - else if (xmlStrEqual(type, BAD_CAST "dev")) - chr->srcType = QEMUD_CHR_SRC_TYPE_DEV; - else if (xmlStrEqual(type, BAD_CAST "file")) - chr->srcType = QEMUD_CHR_SRC_TYPE_FILE; - else if (xmlStrEqual(type, BAD_CAST "pipe")) - chr->srcType = QEMUD_CHR_SRC_TYPE_PIPE; - else if (xmlStrEqual(type, BAD_CAST "stdio")) - chr->srcType = QEMUD_CHR_SRC_TYPE_STDIO; - else if (xmlStrEqual(type, BAD_CAST "udp")) - chr->srcType = QEMUD_CHR_SRC_TYPE_UDP; - else if (xmlStrEqual(type, BAD_CAST "tcp")) - chr->srcType = QEMUD_CHR_SRC_TYPE_TCP; - else if (xmlStrEqual(type, BAD_CAST "unix")) - chr->srcType = QEMUD_CHR_SRC_TYPE_UNIX; - else - chr->srcType = QEMUD_CHR_SRC_TYPE_NULL; - } - - cur = node->children; - while (cur != NULL) { - if (cur->type == XML_ELEMENT_NODE) { - if (xmlStrEqual(cur->name, BAD_CAST "source")) { - if (mode == NULL) - mode = xmlGetProp(cur, BAD_CAST "mode"); - - switch (chr->srcType) { - case QEMUD_CHR_SRC_TYPE_PTY: - case QEMUD_CHR_SRC_TYPE_DEV: - case QEMUD_CHR_SRC_TYPE_FILE: - case QEMUD_CHR_SRC_TYPE_PIPE: - case QEMUD_CHR_SRC_TYPE_UNIX: - if (path == NULL) - path = xmlGetProp(cur, BAD_CAST "path"); - - break; - - case QEMUD_CHR_SRC_TYPE_UDP: - case QEMUD_CHR_SRC_TYPE_TCP: - if (mode == NULL || - STREQ((const char *)mode, "connect")) { - - if (connectHost == NULL) - connectHost = xmlGetProp(cur, BAD_CAST "host"); - if (connectService == NULL) - connectService = xmlGetProp(cur, BAD_CAST "service"); - } else { - if (bindHost == NULL) - bindHost = xmlGetProp(cur, BAD_CAST "host"); - if (bindService == NULL) - bindService = xmlGetProp(cur, BAD_CAST "service"); - } - - if (chr->srcType == QEMUD_CHR_SRC_TYPE_UDP) { - xmlFree(mode); - mode = NULL; - } - } - } else if (xmlStrEqual(cur->name, BAD_CAST "protocol")) { - if (protocol == NULL) - protocol = xmlGetProp(cur, BAD_CAST "type"); - } - } - cur = cur->next; - } - - - chr->dstPort = portNum; - - switch (chr->srcType) { - case QEMUD_CHR_SRC_TYPE_NULL: - /* Nada */ - break; - - case QEMUD_CHR_SRC_TYPE_VC: - break; - - case QEMUD_CHR_SRC_TYPE_PTY: - /* @path attribute is an output only property - pty is auto-allocted */ - break; - - case QEMUD_CHR_SRC_TYPE_DEV: - case QEMUD_CHR_SRC_TYPE_FILE: - case QEMUD_CHR_SRC_TYPE_PIPE: - if (path == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing source path attribute for char device")); - goto cleanup; - } - - strncpy(chr->srcData.file.path, (const char *)path, - sizeof(chr->srcData.file.path)); - NUL_TERMINATE(chr->srcData.file.path); - break; - - case QEMUD_CHR_SRC_TYPE_STDIO: - /* Nada */ - break; - - case QEMUD_CHR_SRC_TYPE_TCP: - if (mode == NULL || - STREQ((const char *)mode, "connect")) { - if (connectHost == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing source host attribute for char device")); - goto cleanup; - } - if (connectService == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing source service attribute for char device")); - goto cleanup; - } - - strncpy(chr->srcData.tcp.host, (const char *)connectHost, - sizeof(chr->srcData.tcp.host)); - NUL_TERMINATE(chr->srcData.tcp.host); - strncpy(chr->srcData.tcp.service, (const char *)connectService, - sizeof(chr->srcData.tcp.service)); - NUL_TERMINATE(chr->srcData.tcp.service); - - chr->srcData.tcp.listen = 0; - } else { - if (bindHost == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing source host attribute for char device")); - goto cleanup; - } - if (bindService == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing source service attribute for char device")); - goto cleanup; - } - - strncpy(chr->srcData.tcp.host, (const char *)bindHost, - sizeof(chr->srcData.tcp.host)); - NUL_TERMINATE(chr->srcData.tcp.host); - strncpy(chr->srcData.tcp.service, (const char *)bindService, - sizeof(chr->srcData.tcp.service)); - NUL_TERMINATE(chr->srcData.tcp.service); - - chr->srcData.tcp.listen = 1; - } - if (protocol != NULL && - STREQ((const char *)protocol, "telnet")) - chr->srcData.tcp.protocol = QEMUD_CHR_SRC_TCP_PROTOCOL_TELNET; - else - chr->srcData.tcp.protocol = QEMUD_CHR_SRC_TCP_PROTOCOL_RAW; - break; - - case QEMUD_CHR_SRC_TYPE_UDP: - if (connectService == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing source service attribute for char device")); - goto cleanup; - } - - if (connectHost != NULL) { - strncpy(chr->srcData.udp.connectHost, (const char *)connectHost, - sizeof(chr->srcData.udp.connectHost)); - NUL_TERMINATE(chr->srcData.udp.connectHost); - } - strncpy(chr->srcData.udp.connectService, (const char *)connectService, - sizeof(chr->srcData.udp.connectService)); - NUL_TERMINATE(chr->srcData.udp.connectService); - - if (bindHost != NULL) { - strncpy(chr->srcData.udp.bindHost, (const char *)bindHost, - sizeof(chr->srcData.udp.bindHost)); - NUL_TERMINATE(chr->srcData.udp.bindHost); - } - if (bindService != NULL) { - strncpy(chr->srcData.udp.bindService, (const char *)bindService, - sizeof(chr->srcData.udp.bindService)); - NUL_TERMINATE(chr->srcData.udp.bindService); - } - break; - - case QEMUD_CHR_SRC_TYPE_UNIX: - if (path == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing source path attribute for char device")); - goto cleanup; - } - - if (mode != NULL && - STRNEQ((const char *)mode, "connect")) - chr->srcData.nix.listen = 1; - else - chr->srcData.nix.listen = 0; - - strncpy(chr->srcData.nix.path, (const char *)path, - sizeof(chr->srcData.nix.path)); - NUL_TERMINATE(chr->srcData.nix.path); - break; - } - - ret = 0; - -cleanup: - xmlFree(mode); - xmlFree(protocol); - xmlFree(type); - xmlFree(bindHost); - xmlFree(bindService); - xmlFree(connectHost); - xmlFree(connectService); - xmlFree(path); - - return ret; -} - - -static int qemudParseCharXMLDevices(virConnectPtr conn, - xmlXPathContextPtr ctxt, - const char *xpath, - unsigned int *ndevs, - struct qemud_vm_chr_def **devs) -{ - xmlXPathObjectPtr obj; - int i, ret = -1; - - obj = xmlXPathEval(BAD_CAST xpath, ctxt); - if ((obj != NULL) && (obj->type == XPATH_NODESET) && - (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) { - struct qemud_vm_chr_def *prev = *devs; - if (ndevs == NULL && - obj->nodesetval->nodeNr > 1) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("too many character devices")); - goto cleanup; - } - - for (i = 0; i < obj->nodesetval->nodeNr; i++) { - struct qemud_vm_chr_def *chr; - if (VIR_ALLOC(chr) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, - "%s", - _("failed to allocate space for char device")); - goto cleanup; - } - - if (qemudParseCharXML(conn, chr, i, obj->nodesetval->nodeTab[i]) < 0) { - VIR_FREE(chr); - goto cleanup; - } - if (ndevs) - (*ndevs)++; - chr->next = NULL; - if (i == 0) { - *devs = chr; - } else { - prev->next = chr; - } - prev = chr; - } - } - - ret = 0; - -cleanup: - xmlXPathFreeObject(obj); - return ret; -} - - -/* Parse the XML definition for a network interface */ -static int qemudParseInputXML(virConnectPtr conn, - const struct qemud_vm_def *vm, - struct qemud_vm_input_def *input, - xmlNodePtr node) { - xmlChar *type = NULL; - xmlChar *bus = NULL; - - type = xmlGetProp(node, BAD_CAST "type"); - bus = xmlGetProp(node, BAD_CAST "bus"); - - if (!type) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("missing input device type")); - goto error; - } - - if (STREQ((const char *)type, "mouse")) { - input->type = QEMU_INPUT_TYPE_MOUSE; - } else if (STREQ((const char *)type, "tablet")) { - input->type = QEMU_INPUT_TYPE_TABLET; - } else { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("unsupported input device type %s"), - (const char*)type); - goto error; - } - - if (bus) { - if (STREQ(vm->os.type, "hvm")) { - if (STREQ((const char*)bus, "ps2")) { /* Only allow mouse */ - if (input->type != QEMU_INPUT_TYPE_MOUSE) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("ps2 bus does not support %s input device"), - (const char*)type); - goto error; - } - input->bus = QEMU_INPUT_BUS_PS2; - } else if (STREQ((const char *)bus, "usb")) { /* Allow mouse & tablet */ - input->bus = QEMU_INPUT_BUS_USB; - } else { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("unsupported input bus %s"), (const char*)bus); - goto error; - } - } else { - if (STREQ((const char *)bus, "xen")) { /* Allow mouse only */ - input->bus = QEMU_INPUT_BUS_XEN; - if (input->type != QEMU_INPUT_TYPE_MOUSE) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("xen bus does not support %s input device"), - (const char*)type); - goto error; - } - } else { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("unsupported input bus %s"), (const char*)bus); - goto error; - } - } - } else { - if (STREQ(vm->os.type, "hvm")) { - if (input->type == QEMU_INPUT_TYPE_MOUSE) - input->bus = QEMU_INPUT_BUS_PS2; - else - input->bus = QEMU_INPUT_BUS_USB; - } else { - input->bus = QEMU_INPUT_BUS_XEN; - } - } - - xmlFree(type); - xmlFree(bus); - - return 0; - - error: - xmlFree(type); - xmlFree(bus); - - return -1; -} - -static int qemudDiskCompare(const void *aptr, const void *bptr) { - struct qemud_vm_disk_def *a = (struct qemud_vm_disk_def *) aptr; - struct qemud_vm_disk_def *b = (struct qemud_vm_disk_def *) bptr; - if (a->bus == b->bus) - return virDiskNameToIndex(a->dst) - virDiskNameToIndex(b->dst); - else - return a->bus - b->bus; -} - -static const char *qemudBusIdToName(int busId, int qemuIF) { - const char *busnames[] = { "ide", - (qemuIF ? "floppy" : "fdc"), - "scsi", - "virtio", - "xen"}; - verify_true(ARRAY_CARDINALITY(busnames) == QEMUD_DISK_BUS_LAST); - - return busnames[busId]; -} - -/* Sound device helper functions */ -static int qemudSoundModelFromString(const char *model) { - if (STREQ(model, "sb16")) { - return QEMU_SOUND_SB16; - } else if (STREQ(model, "es1370")) { - return QEMU_SOUND_ES1370; - } else if (STREQ(model, "pcspk")) { - return QEMU_SOUND_PCSPK; - } - - return -1; -} - -static const char *qemudSoundModelToString(const int model) { - - if (model == QEMU_SOUND_SB16) { - return "sb16"; - } else if (model == QEMU_SOUND_ES1370) { - return "es1370"; - } else if (model == QEMU_SOUND_PCSPK) { - return "pcspk"; - } - - return NULL; -} - - -static int qemudParseSoundXML(virConnectPtr conn, - struct qemud_vm_sound_def *sound, - const xmlNodePtr node) { - - int err = -1; - xmlChar *model = NULL; - model = xmlGetProp(node, BAD_CAST "model"); - - if (!model) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("missing sound model")); - goto error; - } - if ((sound->model = qemudSoundModelFromString((char *) model)) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("invalid sound model '%s'"), (char *) model); - goto error; - } - - err = 0; - error: - xmlFree(model); - return err; -} - -/* - * Parses a libvirt XML definition of a guest, and populates the - * the qemud_vm struct with matching data about the guests config - */ -static struct qemud_vm_def *qemudParseXML(virConnectPtr conn, - struct qemud_driver *driver, - xmlDocPtr xml) { - xmlNodePtr root = NULL; - xmlChar *prop = NULL; - xmlXPathContextPtr ctxt = NULL; - xmlXPathObjectPtr obj = NULL; - char *conv = NULL; - int i; - struct qemud_vm_def *def; - - if (VIR_ALLOC(def) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, - "%s", _("failed to allocate space for xmlXPathContext")); - return NULL; - } - - /* Prepare parser / xpath context */ - root = xmlDocGetRootElement(xml); - if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "domain"))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("incorrect root element")); - goto error; - } - - ctxt = xmlXPathNewContext(xml); - if (ctxt == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, - "%s", _("failed to allocate space for xmlXPathContext")); - goto error; - } - - - /* Find out what type of QEMU virtualization to use */ - if (!(prop = xmlGetProp(root, BAD_CAST "type"))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("missing domain type attribute")); - goto error; - } - - if (STREQ((char *)prop, "qemu")) - def->virtType = QEMUD_VIRT_QEMU; - else if (STREQ((char *)prop, "kqemu")) - def->virtType = QEMUD_VIRT_KQEMU; - else if (STREQ((char *)prop, "kvm")) - def->virtType = QEMUD_VIRT_KVM; - else { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("invalid domain type attribute")); - goto error; - } - VIR_FREE(prop); - - - /* 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(conn, NULL, NULL, VIR_ERR_NO_NAME, NULL); - goto error; - } - if (strlen((const char *)obj->stringval) >= (QEMUD_MAX_NAME_LEN-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("domain name length too long")); - goto error; - } - strcpy(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)) { - int err; - if ((err = virUUIDGenerate(def->uuid))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("Failed to generate UUID: %s"), strerror(err)); - goto error; - } - } else if (virUUIDParse((const char *)obj->stringval, def->uuid) < 0) { - qemudReportError(conn, NULL, NULL, 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)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("missing memory element")); - goto error; - } else { - conv = NULL; - def->maxmem = strtoll((const char*)obj->stringval, &conv, 10); - if (conv == (const char*)obj->stringval) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("malformed memory information")); - goto error; - } - } - xmlXPathFreeObject(obj); - - - /* Extract domain memory */ - obj = xmlXPathEval(BAD_CAST "string(/domain/currentMemory[1])", ctxt); - if ((obj == NULL) || (obj->type != XPATH_STRING) || - (obj->stringval == NULL) || (obj->stringval[0] == 0)) { - def->memory = def->maxmem; - } else { - conv = NULL; - def->memory = strtoll((const char*)obj->stringval, &conv, 10); - if (def->memory > def->maxmem) - def->memory = def->maxmem; - if (conv == (const char*)obj->stringval) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("malformed memory information")); - goto error; - } - } - 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)) { - def->vcpus = 1; - } else { - conv = NULL; - def->vcpus = strtoll((const char*)obj->stringval, &conv, 10); - if (conv == (const char*)obj->stringval) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("malformed vcpu information")); - goto error; - } - } - xmlXPathFreeObject(obj); - - /* Extract domain vcpu info */ - obj = xmlXPathEval(BAD_CAST "string(/domain/vcpu[1]/@cpuset)", ctxt); - if ((obj == NULL) || (obj->type != XPATH_STRING) || - (obj->stringval == NULL) || (obj->stringval[0] == 0)) { - /* Allow use on all CPUS */ - memset(def->cpumask, 1, QEMUD_CPUMASK_LEN); - } else { - char *set = (char *)obj->stringval; - memset(def->cpumask, 0, QEMUD_CPUMASK_LEN); - if (virParseCpuSet(conn, (const char **)&set, - 0, def->cpumask, - QEMUD_CPUMASK_LEN) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("malformed vcpu mask information")); - goto error; - } - } - xmlXPathFreeObject(obj); - - /* See if ACPI feature is requested */ - obj = xmlXPathEval(BAD_CAST "/domain/features/acpi", ctxt); - if ((obj != NULL) && (obj->type == XPATH_NODESET) && - (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) { - def->features |= QEMUD_FEATURE_ACPI; - } - xmlXPathFreeObject(obj); - - - /* See if we disable reboots */ - obj = xmlXPathEval(BAD_CAST "string(/domain/on_reboot)", ctxt); - if ((obj == NULL) || (obj->type != XPATH_STRING) || - (obj->stringval == NULL) || (obj->stringval[0] == 0)) { - def->noReboot = 0; - } else { - if (STREQ((char*)obj->stringval, "destroy")) - def->noReboot = 1; - else - def->noReboot = 0; - } - xmlXPathFreeObject(obj); - - /* See if we set clock to localtime */ - obj = xmlXPathEval(BAD_CAST "string(/domain/clock/@offset)", ctxt); - if ((obj == NULL) || (obj->type != XPATH_STRING) || - (obj->stringval == NULL) || (obj->stringval[0] == 0)) { - def->localtime = 0; - } else { - if (STREQ((char*)obj->stringval, "localtime")) - def->localtime = 1; - else - def->localtime = 0; - } - xmlXPathFreeObject(obj); - - - /* Extract bootloader */ - obj = xmlXPathEval(BAD_CAST "string(/domain/bootloader)", ctxt); - if ((obj != NULL) && (obj->type == XPATH_STRING) && - (obj->stringval != NULL) && (obj->stringval[0] != 0)) { - strncpy(def->os.bootloader, (const char*)obj->stringval, sizeof(def->os.bootloader)); - NUL_TERMINATE(def->os.bootloader); - - /* Set a default OS type, since is optional with bootloader */ - strcpy(def->os.type, "xen"); - } - 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)) { - if (!def->os.type[0]) { - qemudReportError(conn, NULL, NULL, VIR_ERR_OS_TYPE, - "%s", _("no OS type")); - goto error; - } - } else { - strcpy(def->os.type, (const char *)obj->stringval); - } - xmlXPathFreeObject(obj); - obj = NULL; - - if (!virCapabilitiesSupportsGuestOSType(driver->caps, def->os.type)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_OS_TYPE, - "%s", def->os.type); - goto error; - } - - 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 = virCapabilitiesDefaultGuestArch(driver->caps, def->os.type); - if (defaultArch == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("unsupported architecture")); - goto error; - } - if (strlen(defaultArch) >= (QEMUD_OS_TYPE_MAX_LEN-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("architecture type too long")); - goto error; - } - strcpy(def->os.arch, defaultArch); - } else { - if (strlen((const char *)obj->stringval) >= (QEMUD_OS_TYPE_MAX_LEN-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("architecture type too long")); - goto error; - } - strcpy(def->os.arch, (const char *)obj->stringval); - } - 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 = virCapabilitiesDefaultGuestMachine(driver->caps, - def->os.type, - def->os.arch); - if (defaultMachine == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("unsupported architecture")); - goto error; - } - if (strlen(defaultMachine) >= (QEMUD_OS_MACHINE_MAX_LEN-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("machine type too long")); - goto error; - } - strcpy(def->os.machine, defaultMachine); - } else { - if (strlen((const char *)obj->stringval) >= (QEMUD_OS_MACHINE_MAX_LEN-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("architecture type too long")); - goto error; - } - strcpy(def->os.machine, (const char *)obj->stringval); - } - xmlXPathFreeObject(obj); - - - if (!def->os.bootloader[0]) { - obj = xmlXPathEval(BAD_CAST "string(/domain/os/kernel[1])", ctxt); - if ((obj != NULL) && (obj->type == XPATH_STRING) && - (obj->stringval != NULL) && (obj->stringval[0] != 0)) { - if (strlen((const char *)obj->stringval) >= (PATH_MAX-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("kernel path too long")); - goto error; - } - strcpy(def->os.kernel, (const char *)obj->stringval); - } - xmlXPathFreeObject(obj); - - - obj = xmlXPathEval(BAD_CAST "string(/domain/os/initrd[1])", ctxt); - if ((obj != NULL) && (obj->type == XPATH_STRING) && - (obj->stringval != NULL) && (obj->stringval[0] != 0)) { - if (strlen((const char *)obj->stringval) >= (PATH_MAX-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("initrd path too long")); - goto error; - } - strcpy(def->os.initrd, (const char *)obj->stringval); - } - xmlXPathFreeObject(obj); - - - obj = xmlXPathEval(BAD_CAST "string(/domain/os/cmdline[1])", ctxt); - if ((obj != NULL) && (obj->type == XPATH_STRING) && - (obj->stringval != NULL) && (obj->stringval[0] != 0)) { - if (strlen((const char *)obj->stringval) >= (PATH_MAX-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("cmdline arguments too long")); - goto error; - } - strcpy(def->os.cmdline, (const char *)obj->stringval); - } - xmlXPathFreeObject(obj); - - - /* analysis of the disk devices */ - obj = xmlXPathEval(BAD_CAST "/domain/os/boot", ctxt); - if ((obj != NULL) && (obj->type == XPATH_NODESET) && - (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) { - for (i = 0; i < obj->nodesetval->nodeNr && i < QEMUD_MAX_BOOT_DEVS ; i++) { - if (!(prop = xmlGetProp(obj->nodesetval->nodeTab[i], BAD_CAST "dev"))) - continue; - if (STREQ((char *)prop, "hd")) { - def->os.bootDevs[def->os.nBootDevs++] = QEMUD_BOOT_DISK; - } else if (STREQ((char *)prop, "fd")) { - def->os.bootDevs[def->os.nBootDevs++] = QEMUD_BOOT_FLOPPY; - } else if (STREQ((char *)prop, "cdrom")) { - def->os.bootDevs[def->os.nBootDevs++] = QEMUD_BOOT_CDROM; - } else if (STREQ((char *)prop, "network")) { - def->os.bootDevs[def->os.nBootDevs++] = QEMUD_BOOT_NET; - } else { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("unknown boot device \'%s\'"), (char*)prop); - goto error; - } - xmlFree(prop); - prop = NULL; - } - } - xmlXPathFreeObject(obj); - if (def->os.nBootDevs == 0) { - def->os.nBootDevs = 1; - def->os.bootDevs[0] = QEMUD_BOOT_DISK; - } - } - - obj = xmlXPathEval(BAD_CAST "string(/domain/devices/emulator[1])", ctxt); - if ((obj == NULL) || (obj->type != XPATH_STRING) || - (obj->stringval == NULL) || (obj->stringval[0] == 0)) { - const char *type = qemudVirtTypeToString(def->virtType); - if (!type) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("unknown virt type")); - goto error; - } - const char *emulator = virCapabilitiesDefaultGuestEmulator(driver->caps, - def->os.type, - def->os.arch, - type); - if (!emulator) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("unsupported guest type")); - goto error; - } - strcpy(def->os.binary, emulator); - } else { - if (strlen((const char *)obj->stringval) >= (PATH_MAX-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("emulator path too long")); - goto error; - } - strcpy(def->os.binary, (const char *)obj->stringval); - } - xmlXPathFreeObject(obj); - - obj = xmlXPathEval(BAD_CAST "/domain/devices/graphics", ctxt); - if ((obj == NULL) || (obj->type != XPATH_NODESET) || - (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) { - def->graphicsType = QEMUD_GRAPHICS_NONE; - } else if ((prop = xmlGetProp(obj->nodesetval->nodeTab[0], BAD_CAST "type"))) { - if (STREQ((char *)prop, "vnc")) { - xmlChar *vncport, *vnclisten; - def->graphicsType = QEMUD_GRAPHICS_VNC; - vncport = xmlGetProp(obj->nodesetval->nodeTab[0], BAD_CAST "port"); - if (vncport) { - conv = NULL; - def->vncPort = strtoll((const char*)vncport, &conv, 10); - } else { - def->vncPort = -1; - } - vnclisten = xmlGetProp(obj->nodesetval->nodeTab[0], BAD_CAST "listen"); - if (vnclisten && *vnclisten) - strncpy(def->vncListen, (char *)vnclisten, BR_INET_ADDR_MAXLEN-1); - else - strcpy(def->vncListen, driver->vncListen); - def->vncListen[BR_INET_ADDR_MAXLEN-1] = '\0'; - def->keymap = (char *) xmlGetProp(obj->nodesetval->nodeTab[0], BAD_CAST "keymap"); - xmlFree(vncport); - xmlFree(vnclisten); - } else if (STREQ((char *)prop, "sdl")) { - def->graphicsType = QEMUD_GRAPHICS_SDL; - } else { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("Unsupported graphics type %s"), prop); - goto error; - } - xmlFree(prop); - prop = NULL; - } - xmlXPathFreeObject(obj); - - /* 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 (i = 0; i < obj->nodesetval->nodeNr; i++) { - struct qemud_vm_disk_def *disk; - if (VIR_ALLOC(disk) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, - "%s", _("failed to allocate space for disk string")); - goto error; - } - if (qemudParseDiskXML(conn, disk, obj->nodesetval->nodeTab[i]) < 0) { - VIR_FREE(disk); - goto error; - } - def->ndisks++; - if (i == 0) { - disk->next = NULL; - def->disks = disk; - } else { - struct qemud_vm_disk_def *ptr = def->disks; - while (ptr) { - if (!ptr->next || qemudDiskCompare(disk, ptr->next) < 0) { - disk->next = ptr->next; - ptr->next = disk; - break; - } - ptr = ptr->next; - } - } - } - } - xmlXPathFreeObject(obj); - obj = NULL; - - /* analysis of the character devices */ - if (qemudParseCharXMLDevices(conn, ctxt, - "/domain/devices/parallel", - &def->nparallels, - &def->parallels) < 0) - goto error; - if (qemudParseCharXMLDevices(conn, ctxt, - "/domain/devices/serial", - &def->nserials, - &def->serials) < 0) - goto error; - - /* - * If no serial devices were listed, then look for console - * devices which is the legacy syntax for the same thing - */ - if (def->nserials == 0) { - obj = xmlXPathEval(BAD_CAST "/domain/devices/console", ctxt); - if ((obj != NULL) && (obj->type == XPATH_NODESET) && - (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) { - struct qemud_vm_chr_def *chr; - if (VIR_ALLOC(chr) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, - "%s", - _("failed to allocate space for char device")); - goto error; - } - - if (qemudParseCharXML(conn, chr, 0, obj->nodesetval->nodeTab[0]) < 0) { - VIR_FREE(chr); - goto error; - } - def->nserials = 1; - def->serials = chr; - } - 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)) { - struct qemud_vm_net_def *prev = NULL; - for (i = 0; i < obj->nodesetval->nodeNr; i++) { - struct qemud_vm_net_def *net; - if (VIR_ALLOC(net) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, - "%s", _("failed to allocate space for net string")); - goto error; - } - if (qemudParseInterfaceXML(conn, net, obj->nodesetval->nodeTab[i]) < 0) { - VIR_FREE(net); - goto error; - } - def->nnets++; - net->next = NULL; - if (i == 0) { - def->nets = net; - } else { - prev->next = net; - } - prev = net; - } - } - xmlXPathFreeObject(obj); - - /* analysis of the input devices */ - obj = xmlXPathEval(BAD_CAST "/domain/devices/input", ctxt); - if ((obj != NULL) && (obj->type == XPATH_NODESET) && - (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) { - struct qemud_vm_input_def *prev = NULL; - for (i = 0; i < obj->nodesetval->nodeNr; i++) { - struct qemud_vm_input_def *input; - if (VIR_ALLOC(input) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, - "%s", _("failed to allocate space for input string")); - goto error; - } - if (qemudParseInputXML(conn, def, input, obj->nodesetval->nodeTab[i]) < 0) { - VIR_FREE(input); - goto error; - } - /* Mouse + PS/2 is implicit with graphics, so don't store it */ - if (input->bus == QEMU_INPUT_BUS_PS2 && - input->type == QEMU_INPUT_TYPE_MOUSE) { - VIR_FREE(input); - continue; - } - def->ninputs++; - input->next = NULL; - if (def->inputs == NULL) { - def->inputs = input; - } else { - prev->next = input; - } - prev = input; - } - } - xmlXPathFreeObject(obj); - - /* Parse sound driver xml */ - obj = xmlXPathEval(BAD_CAST "/domain/devices/sound", ctxt); - if ((obj != NULL) && (obj->type == XPATH_NODESET) && - (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) { - struct qemud_vm_sound_def *prev = NULL; - for (i = 0; i < obj->nodesetval->nodeNr; i++) { - - struct qemud_vm_sound_def *sound; - struct qemud_vm_sound_def *check = def->sounds; - int collision = 0; - if (VIR_ALLOC(sound) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, - "%s", _("failed to allocate space for sound dev")); - goto error; - } - if (qemudParseSoundXML(conn, sound, - obj->nodesetval->nodeTab[i]) < 0) { - VIR_FREE(sound); - goto error; - } - - // Check that model type isn't already present in sound dev list - while(check) { - if (check->model == sound->model) { - collision = 1; - break; - } - check = check->next; - } - if (collision) { - VIR_FREE(sound); - continue; - } - - def->nsounds++; - sound->next = NULL; - if (def->sounds == NULL) { - def->sounds = sound; - } else { - prev->next = sound; - } - prev = sound; - } - } - xmlXPathFreeObject(obj); - obj = NULL; - - /* If graphics are enabled, there's an implicit PS2 mouse */ - if (def->graphicsType != QEMUD_GRAPHICS_NONE) { - int hasPS2mouse = 0; - struct qemud_vm_input_def *input = def->inputs; - while (input) { - if (input->type == QEMU_INPUT_TYPE_MOUSE && - input->bus == QEMU_INPUT_BUS_PS2) - hasPS2mouse = 1; - input = input->next; - } - - if (!hasPS2mouse) { - if (VIR_ALLOC(input) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, - "%s", _("failed to allocate space for input string")); - goto error; - } - input->type = QEMU_INPUT_TYPE_MOUSE; - input->bus = QEMU_INPUT_BUS_PS2; - input->next = def->inputs; - def->inputs = input; - def->ninputs++; - } - } - - xmlXPathFreeContext(ctxt); - - return def; - - error: - VIR_FREE(prop); - xmlXPathFreeObject(obj); - xmlXPathFreeContext(ctxt); - qemudFreeVMDef(def); - return NULL; -} - static char * qemudNetworkIfaceConnect(virConnectPtr conn, struct qemud_driver *driver, - struct qemud_vm *vm, - struct qemud_vm_net_def *net, + int **tapfds, + int *ntapfds, + virDomainNetDefPtr net, int vlan) { virNetworkObjPtr network = NULL; char *brname; - char *ifname; char tapfdstr[4+3+32+7]; char *retval = NULL; int err; int tapfd = -1; - if (net->type == QEMUD_NET_NETWORK) { - if (!(network = virNetworkFindByName(driver->networks, net->dst.network.name))) { + if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) { + if (!(network = virNetworkFindByName(driver->networks, net->data.network.name))) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("Network '%s' not found"), - net->dst.network.name); + net->data.network.name); goto error; } else if (network->def->bridge == NULL) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("Network '%s' not active"), - net->dst.network.name); + net->data.network.name); goto error; } brname = network->def->bridge; - if (net->dst.network.ifname[0] == '\0' || - STRPREFIX(net->dst.network.ifname, "vnet") || - strchr(net->dst.network.ifname, '%')) { - strcpy(net->dst.network.ifname, "vnet%d"); - } - ifname = net->dst.network.ifname; - } else if (net->type == QEMUD_NET_BRIDGE) { - brname = net->dst.bridge.brname; - if (net->dst.bridge.ifname[0] == '\0' || - STRPREFIX(net->dst.bridge.ifname, "vnet") || - strchr(net->dst.bridge.ifname, '%')) { - strcpy(net->dst.bridge.ifname, "vnet%d"); - } - ifname = net->dst.bridge.ifname; + } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) { + brname = net->data.bridge.brname; } else { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("Network type %d is not supported"), net->type); goto error; } + if (!net->ifname || + STRPREFIX(net->ifname, "vnet") || + strchr(net->ifname, '%')) { + VIR_FREE(net->ifname); + if (!(net->ifname = strdup("vnet%d"))) { + qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL); + goto error; + } + } + if (!driver->brctl && (err = brInit(&driver->brctl))) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("cannot initialize bridge support: %s"), @@ -2277,7 +593,7 @@ qemudNetworkIfaceConnect(virConnectPtr conn, } if ((err = brAddTap(driver->brctl, brname, - ifname, BR_IFNAME_MAXLEN, &tapfd))) { + &net->ifname, &tapfd))) { if (errno == ENOTSUP) { /* In this particular case, give a better diagnostic. */ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, @@ -2287,23 +603,22 @@ qemudNetworkIfaceConnect(virConnectPtr conn, qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("Failed to add tap interface '%s' " "to bridge '%s' : %s"), - ifname, brname, strerror(err)); + net->ifname, brname, strerror(err)); } goto error; } snprintf(tapfdstr, sizeof(tapfdstr), "tap,fd=%d,script=,vlan=%d,ifname=%s", - tapfd, vlan, ifname); + tapfd, vlan, net->ifname); if (!(retval = strdup(tapfdstr))) goto no_memory; - if (VIR_REALLOC_N(vm->tapfds, vm->ntapfds+2) < 0) + if (VIR_REALLOC_N(*tapfds, (*ntapfds)+1) < 0) goto no_memory; - vm->tapfds[vm->ntapfds++] = tapfd; - vm->tapfds[vm->ntapfds] = -1; + (*tapfds)[(*ntapfds)++] = tapfd; return retval; @@ -2317,71 +632,71 @@ qemudNetworkIfaceConnect(virConnectPtr conn, return NULL; } -static int qemudBuildCommandLineChrDevStr(struct qemud_vm_chr_def *dev, +static int qemudBuildCommandLineChrDevStr(virDomainChrDefPtr dev, char *buf, int buflen) { - switch (dev->srcType) { - case QEMUD_CHR_SRC_TYPE_NULL: + switch (dev->type) { + case VIR_DOMAIN_CHR_TYPE_NULL: strncpy(buf, "null", buflen); buf[buflen-1] = '\0'; break; - case QEMUD_CHR_SRC_TYPE_VC: + case VIR_DOMAIN_CHR_TYPE_VC: strncpy(buf, "vc", buflen); buf[buflen-1] = '\0'; break; - case QEMUD_CHR_SRC_TYPE_PTY: + case VIR_DOMAIN_CHR_TYPE_PTY: strncpy(buf, "pty", buflen); buf[buflen-1] = '\0'; break; - case QEMUD_CHR_SRC_TYPE_DEV: + case VIR_DOMAIN_CHR_TYPE_DEV: if (snprintf(buf, buflen, "%s", - dev->srcData.file.path) >= buflen) + dev->data.file.path) >= buflen) return -1; break; - case QEMUD_CHR_SRC_TYPE_FILE: + case VIR_DOMAIN_CHR_TYPE_FILE: if (snprintf(buf, buflen, "file:%s", - dev->srcData.file.path) >= buflen) + dev->data.file.path) >= buflen) return -1; break; - case QEMUD_CHR_SRC_TYPE_PIPE: + case VIR_DOMAIN_CHR_TYPE_PIPE: if (snprintf(buf, buflen, "pipe:%s", - dev->srcData.file.path) >= buflen) + dev->data.file.path) >= buflen) return -1; break; - case QEMUD_CHR_SRC_TYPE_STDIO: + case VIR_DOMAIN_CHR_TYPE_STDIO: strncpy(buf, "stdio", buflen); buf[buflen-1] = '\0'; break; - case QEMUD_CHR_SRC_TYPE_UDP: + case VIR_DOMAIN_CHR_TYPE_UDP: if (snprintf(buf, buflen, "udp:%s:%s@%s:%s", - dev->srcData.udp.connectHost, - dev->srcData.udp.connectService, - dev->srcData.udp.bindHost, - dev->srcData.udp.bindService) >= buflen) + dev->data.udp.connectHost, + dev->data.udp.connectService, + dev->data.udp.bindHost, + dev->data.udp.bindService) >= buflen) return -1; break; - case QEMUD_CHR_SRC_TYPE_TCP: + case VIR_DOMAIN_CHR_TYPE_TCP: if (snprintf(buf, buflen, "%s:%s:%s%s", - dev->srcData.tcp.protocol == QEMUD_CHR_SRC_TCP_PROTOCOL_TELNET ? "telnet" : "tcp", - dev->srcData.tcp.host, - dev->srcData.tcp.service, - dev->srcData.tcp.listen ? ",listen" : "") >= buflen) + dev->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET ? "telnet" : "tcp", + dev->data.tcp.host, + dev->data.tcp.service, + dev->data.tcp.listen ? ",listen" : "") >= buflen) return -1; break; - case QEMUD_CHR_SRC_TYPE_UNIX: + case VIR_DOMAIN_CHR_TYPE_UNIX: if (snprintf(buf, buflen, "unix:%s%s", - dev->srcData.nix.path, - dev->srcData.nix.listen ? ",listen" : "") >= buflen) + dev->data.nix.path, + dev->data.nix.listen ? ",listen" : "") >= buflen) return -1; break; } @@ -2395,30 +710,27 @@ static int qemudBuildCommandLineChrDevStr(struct qemud_vm_chr_def *dev, */ int qemudBuildCommandLine(virConnectPtr conn, struct qemud_driver *driver, - struct qemud_vm *vm, - char ***retargv) { + virDomainObjPtr vm, + int qemuCmdFlags, + char ***retargv, + int **tapfds, + int *ntapfds, + const char *migrateFrom) { int i; char memory[50]; char vcpus[50]; - char boot[QEMUD_MAX_BOOT_DEVS+1]; - struct qemud_vm_disk_def *disk = vm->def->disks; - struct qemud_vm_net_def *net = vm->def->nets; - struct qemud_vm_input_def *input = vm->def->inputs; - struct qemud_vm_sound_def *sound = vm->def->sounds; - struct qemud_vm_chr_def *serial = vm->def->serials; - struct qemud_vm_chr_def *parallel = vm->def->parallels; + char boot[VIR_DOMAIN_BOOT_LAST]; + virDomainDiskDefPtr disk = vm->def->disks; + virDomainNetDefPtr net = vm->def->nets; + virDomainInputDefPtr input = vm->def->inputs; + virDomainSoundDefPtr sound = vm->def->sounds; + virDomainChrDefPtr serial = vm->def->serials; + virDomainChrDefPtr parallel = vm->def->parallels; struct utsname ut; int disableKQEMU = 0; int qargc = 0, qarga = 0; char **qargv = NULL; - if (vm->qemuVersion == 0) { - if (qemudExtractVersionInfo(vm->def->os.binary, - &(vm->qemuVersion), - &(vm->qemuCmdFlags)) < 0) - return -1; - } - uname(&ut); /* Nasty hack make i?86 look like i686 to simplify next comparison */ @@ -2433,9 +745,9 @@ int qemudBuildCommandLine(virConnectPtr conn, * 2. Guest is 'qemu' * 3. The qemu binary has the -no-kqemu flag */ - if ((vm->qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU) && + if ((qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU) && STREQ(ut.machine, vm->def->os.arch) && - vm->def->virtType == QEMUD_VIRT_QEMU) + vm->def->virtType == VIR_DOMAIN_VIRT_QEMU) disableKQEMU = 1; #define ADD_ARG_SPACE \ @@ -2461,10 +773,10 @@ int qemudBuildCommandLine(virConnectPtr conn, } while (0) snprintf(memory, sizeof(memory), "%lu", vm->def->memory/1024); - snprintf(vcpus, sizeof(vcpus), "%d", vm->def->vcpus); + snprintf(vcpus, sizeof(vcpus), "%lu", vm->def->vcpus); - ADD_ARG_LIT(vm->def->os.binary); + ADD_ARG_LIT(vm->def->emulator); ADD_ARG_LIT("-S"); ADD_ARG_LIT("-M"); ADD_ARG_LIT(vm->def->os.machine); @@ -2475,7 +787,7 @@ int qemudBuildCommandLine(virConnectPtr conn, ADD_ARG_LIT("-smp"); ADD_ARG_LIT(vcpus); - if (vm->qemuCmdFlags & QEMUD_CMD_FLAG_NAME) { + if (qemuCmdFlags & QEMUD_CMD_FLAG_NAME) { ADD_ARG_LIT("-name"); ADD_ARG_LIT(vm->def->name); } @@ -2486,7 +798,7 @@ int qemudBuildCommandLine(virConnectPtr conn, * if you ask for nographic. So we have to make sure we override * these defaults ourselves... */ - if (vm->def->graphicsType == QEMUD_GRAPHICS_NONE) + if (!vm->def->graphics) ADD_ARG_LIT("-nographic"); ADD_ARG_LIT("-monitor"); @@ -2495,26 +807,26 @@ int qemudBuildCommandLine(virConnectPtr conn, if (vm->def->localtime) ADD_ARG_LIT("-localtime"); - if ((vm->qemuCmdFlags & QEMUD_CMD_FLAG_NO_REBOOT) && - vm->def->noReboot) + if ((qemuCmdFlags & QEMUD_CMD_FLAG_NO_REBOOT) && + vm->def->onReboot != VIR_DOMAIN_LIFECYCLE_RESTART) ADD_ARG_LIT("-no-reboot"); - if (!(vm->def->features & QEMUD_FEATURE_ACPI)) + if (!(vm->def->features & (1 << VIR_DOMAIN_FEATURE_ACPI))) ADD_ARG_LIT("-no-acpi"); - if (!vm->def->os.bootloader[0]) { + if (!vm->def->os.bootloader) { for (i = 0 ; i < vm->def->os.nBootDevs ; i++) { switch (vm->def->os.bootDevs[i]) { - case QEMUD_BOOT_CDROM: + case VIR_DOMAIN_BOOT_CDROM: boot[i] = 'd'; break; - case QEMUD_BOOT_FLOPPY: + case VIR_DOMAIN_BOOT_FLOPPY: boot[i] = 'a'; break; - case QEMUD_BOOT_DISK: + case VIR_DOMAIN_BOOT_DISK: boot[i] = 'c'; break; - case QEMUD_BOOT_NET: + case VIR_DOMAIN_BOOT_NET: boot[i] = 'n'; break; default: @@ -2526,15 +838,15 @@ int qemudBuildCommandLine(virConnectPtr conn, ADD_ARG_LIT("-boot"); ADD_ARG_LIT(boot); - if (vm->def->os.kernel[0]) { + if (vm->def->os.kernel) { ADD_ARG_LIT("-kernel"); ADD_ARG_LIT(vm->def->os.kernel); } - if (vm->def->os.initrd[0]) { + if (vm->def->os.initrd) { ADD_ARG_LIT("-initrd"); ADD_ARG_LIT(vm->def->os.initrd); } - if (vm->def->os.cmdline[0]) { + if (vm->def->os.cmdline) { ADD_ARG_LIT("-append"); ADD_ARG_LIT(vm->def->os.cmdline); } @@ -2544,20 +856,20 @@ int qemudBuildCommandLine(virConnectPtr conn, } /* If QEMU supports -drive param instead of old -hda, -hdb, -cdrom .. */ - if (vm->qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE) { + if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE) { int bootCD = 0, bootFloppy = 0, bootDisk = 0; /* If QEMU supports boot=on for -drive param... */ - if (vm->qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_BOOT) { + if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_BOOT) { for (i = 0 ; i < vm->def->os.nBootDevs ; i++) { switch (vm->def->os.bootDevs[i]) { - case QEMUD_BOOT_CDROM: + case VIR_DOMAIN_BOOT_CDROM: bootCD = 1; break; - case QEMUD_BOOT_FLOPPY: + case VIR_DOMAIN_BOOT_FLOPPY: bootFloppy = 1; break; - case QEMUD_BOOT_DISK: + case VIR_DOMAIN_BOOT_DISK: bootDisk = 1; break; } @@ -2569,6 +881,7 @@ int qemudBuildCommandLine(virConnectPtr conn, const char *media = NULL; int bootable = 0; int idx = virDiskNameToIndex(disk->dst); + const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus); if (idx < 0) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, @@ -2576,29 +889,30 @@ int qemudBuildCommandLine(virConnectPtr conn, goto error; } - if (disk->device == QEMUD_DISK_CDROM) + if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) media = "media=cdrom,"; switch (disk->device) { - case QEMUD_DISK_CDROM: + case VIR_DOMAIN_DISK_DEVICE_CDROM: bootable = bootCD; bootCD = 0; break; - case QEMUD_DISK_FLOPPY: + case VIR_DOMAIN_DISK_DEVICE_FLOPPY: bootable = bootFloppy; bootFloppy = 0; break; - case QEMUD_DISK_DISK: + case VIR_DOMAIN_DISK_DEVICE_DISK: bootable = bootDisk; bootDisk = 0; break; } snprintf(opt, PATH_MAX, "file=%s,if=%s,%sindex=%d%s", - disk->src, qemudBusIdToName(disk->bus, 1), + disk->src, bus, media ? media : "", idx, - bootable && disk->device == QEMUD_DISK_DISK + bootable && + disk->device == VIR_DOMAIN_DISK_DEVICE_DISK ? ",boot=on" : ""); ADD_ARG_LIT("-drive"); @@ -2611,8 +925,8 @@ int qemudBuildCommandLine(virConnectPtr conn, char file[PATH_MAX]; if (STREQ(disk->dst, "hdc") && - disk->device == QEMUD_DISK_CDROM) { - if (disk->src[0]) { + disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) { + if (disk->src) { snprintf(dev, NAME_MAX, "-%s", "cdrom"); } else { disk = disk->next; @@ -2652,7 +966,8 @@ int qemudBuildCommandLine(virConnectPtr conn, net->mac[2], net->mac[3], net->mac[4], net->mac[5], vlan, - (net->model[0] ? ",model=" : ""), net->model) >= sizeof(nic)) + (net->model ? ",model=" : ""), + (net->model ? net->model : "")) >= sizeof(nic)) goto error; ADD_ARG_LIT("-net"); @@ -2660,22 +975,24 @@ int qemudBuildCommandLine(virConnectPtr conn, ADD_ARG_LIT("-net"); switch (net->type) { - case QEMUD_NET_NETWORK: - case QEMUD_NET_BRIDGE: + case VIR_DOMAIN_NET_TYPE_NETWORK: + case VIR_DOMAIN_NET_TYPE_BRIDGE: { - char *tap = qemudNetworkIfaceConnect(conn, driver, vm, net, vlan); + char *tap = qemudNetworkIfaceConnect(conn, driver, + tapfds, ntapfds, + net, vlan); if (tap == NULL) goto error; ADD_ARG(tap); break; } - case QEMUD_NET_ETHERNET: + case VIR_DOMAIN_NET_TYPE_ETHERNET: { char arg[PATH_MAX]; if (snprintf(arg, PATH_MAX-1, "tap,ifname=%s,script=%s,vlan=%d", - net->dst.ethernet.ifname, - net->dst.ethernet.script, + net->ifname, + net->data.ethernet.script, vlan) >= (PATH_MAX-1)) goto error; @@ -2683,27 +1000,27 @@ int qemudBuildCommandLine(virConnectPtr conn, } break; - case QEMUD_NET_CLIENT: - case QEMUD_NET_SERVER: - case QEMUD_NET_MCAST: + case VIR_DOMAIN_NET_TYPE_CLIENT: + case VIR_DOMAIN_NET_TYPE_SERVER: + case VIR_DOMAIN_NET_TYPE_MCAST: { char arg[PATH_MAX]; const char *mode = NULL; switch (net->type) { - case QEMUD_NET_CLIENT: + case VIR_DOMAIN_NET_TYPE_CLIENT: mode = "connect"; break; - case QEMUD_NET_SERVER: + case VIR_DOMAIN_NET_TYPE_SERVER: mode = "listen"; break; - case QEMUD_NET_MCAST: + case VIR_DOMAIN_NET_TYPE_MCAST: mode = "mcast"; break; } if (snprintf(arg, PATH_MAX-1, "socket,%s=%s:%d,vlan=%d", mode, - net->dst.socket.address, - net->dst.socket.port, + net->data.socket.address, + net->data.socket.port, vlan) >= (PATH_MAX-1)) goto error; @@ -2711,7 +1028,7 @@ int qemudBuildCommandLine(virConnectPtr conn, } break; - case QEMUD_NET_USER: + case VIR_DOMAIN_NET_TYPE_USER: default: { char arg[PATH_MAX]; @@ -2763,19 +1080,20 @@ int qemudBuildCommandLine(virConnectPtr conn, ADD_ARG_LIT("-usb"); while (input) { - if (input->bus == QEMU_INPUT_BUS_USB) { + if (input->bus == VIR_DOMAIN_INPUT_BUS_USB) { ADD_ARG_LIT("-usbdevice"); - ADD_ARG_LIT(input->type == QEMU_INPUT_TYPE_MOUSE ? "mouse" : "tablet"); + ADD_ARG_LIT(input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ? "mouse" : "tablet"); } input = input->next; } - if (vm->def->graphicsType == QEMUD_GRAPHICS_VNC) { + if (vm->def->graphics && + vm->def->graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) { char vncdisplay[PATH_MAX]; int ret; - if (vm->qemuCmdFlags & QEMUD_CMD_FLAG_VNC_COLON) { + if (qemuCmdFlags & QEMUD_CMD_FLAG_VNC_COLON) { char options[PATH_MAX] = ""; if (driver->vncTLS) { strcat(options, ",tls"); @@ -2789,25 +1107,24 @@ int qemudBuildCommandLine(virConnectPtr conn, options[sizeof(options)-1] = '\0'; } ret = snprintf(vncdisplay, sizeof(vncdisplay), "%s:%d%s", - vm->def->vncListen, - vm->def->vncActivePort - 5900, + vm->def->graphics->data.vnc.listenAddr, + vm->def->graphics->data.vnc.port - 5900, options); } else { ret = snprintf(vncdisplay, sizeof(vncdisplay), "%d", - vm->def->vncActivePort - 5900); + vm->def->graphics->data.vnc.port - 5900); } if (ret < 0 || ret >= (int)sizeof(vncdisplay)) goto error; ADD_ARG_LIT("-vnc"); ADD_ARG_LIT(vncdisplay); - if (vm->def->keymap) { + if (vm->def->graphics->data.vnc.keymap) { ADD_ARG_LIT("-k"); - ADD_ARG_LIT(vm->def->keymap); + ADD_ARG_LIT(vm->def->graphics->data.vnc.keymap); } - } else if (vm->def->graphicsType == QEMUD_GRAPHICS_NONE) { - /* Nada - we added -nographic earlier in this function */ - } else { + } else if (vm->def->graphics && + vm->def->graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) { /* SDL is the default. no args needed */ } @@ -2819,7 +1136,7 @@ int qemudBuildCommandLine(virConnectPtr conn, goto no_memory; while(sound && size > 0) { - const char *model = qemudSoundModelToString(sound->model); + const char *model = virDomainSoundModelTypeToString(sound->model); if (!model) { VIR_FREE(modstr); qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, @@ -2836,9 +1153,9 @@ int qemudBuildCommandLine(virConnectPtr conn, ADD_ARG(modstr); } - if (vm->migrateFrom[0]) { + if (migrateFrom) { ADD_ARG_LIT("-incoming"); - ADD_ARG_LIT(vm->migrateFrom); + ADD_ARG_LIT(migrateFrom); } ADD_ARG(NULL); @@ -2850,12 +1167,12 @@ int qemudBuildCommandLine(virConnectPtr conn, qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "%s", _("failed to allocate space for argv string")); error: - if (vm->tapfds) { - for (i = 0; vm->tapfds[i] != -1; i++) - close(vm->tapfds[i]); - VIR_FREE(vm->tapfds); - vm->tapfds = NULL; - vm->ntapfds = 0; + if (tapfds && + *tapfds) { + for (i = 0; ntapfds; i++) + close((*tapfds)[i]); + VIR_FREE(*tapfds); + *ntapfds = 0; } if (qargv) { for (i = 0 ; i < qargc ; i++) @@ -2870,755 +1187,4 @@ int qemudBuildCommandLine(virConnectPtr conn, } -/* Save a guest's config data into a persistent file */ -static int qemudSaveConfig(virConnectPtr conn, - struct qemud_driver *driver, - struct qemud_vm *vm, - struct qemud_vm_def *def) { - char *xml; - int fd = -1, ret = -1; - int towrite; - - if (!(xml = qemudGenerateXML(conn, driver, vm, def, 0))) - return -1; - - if ((fd = open(vm->configFile, - O_WRONLY | O_CREAT | O_TRUNC, - S_IRUSR | S_IWUSR )) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("cannot create config file %s: %s"), - vm->configFile, strerror(errno)); - goto cleanup; - } - - towrite = strlen(xml); - if (safewrite(fd, xml, towrite) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("cannot write config file %s: %s"), - vm->configFile, strerror(errno)); - goto cleanup; - } - - if (close(fd) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("cannot save config file %s: %s"), - vm->configFile, strerror(errno)); - goto cleanup; - } - - ret = 0; - - cleanup: - if (fd != -1) - close(fd); - - VIR_FREE(xml); - - return ret; -} - -struct qemud_vm_device_def * -qemudParseVMDeviceDef(virConnectPtr conn, - const struct qemud_vm_def *def, - const char *xmlStr) -{ - xmlDocPtr xml; - xmlNodePtr node; - struct qemud_vm_device_def *dev; - - if (VIR_ALLOC(dev) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL); - return NULL; - } - - if (!(xml = xmlReadDoc(BAD_CAST xmlStr, "device.xml", NULL, - XML_PARSE_NOENT | XML_PARSE_NONET | - XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_XML_ERROR, NULL); - goto error; - } - - node = xmlDocGetRootElement(xml); - if (node == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_XML_ERROR, - "%s", _("missing root element")); - goto error; - } - if (xmlStrEqual(node->name, BAD_CAST "disk")) { - dev->type = QEMUD_DEVICE_DISK; - qemudParseDiskXML(conn, &(dev->data.disk), node); - } else if (xmlStrEqual(node->name, BAD_CAST "interface")) { - dev->type = QEMUD_DEVICE_NET; - qemudParseInterfaceXML(conn, &(dev->data.net), node); - } else if (xmlStrEqual(node->name, BAD_CAST "input")) { - dev->type = QEMUD_DEVICE_DISK; - qemudParseInputXML(conn, def, &(dev->data.input), node); - } else if (xmlStrEqual(node->name, BAD_CAST "sound")) { - dev->type = QEMUD_DEVICE_SOUND; - qemudParseSoundXML(conn, &(dev->data.sound), node); - } else { - qemudReportError(conn, NULL, NULL, VIR_ERR_XML_ERROR, - "%s", _("unknown device type")); - goto error; - } - - xmlFreeDoc(xml); - - return dev; - - error: - if (xml) xmlFreeDoc(xml); - VIR_FREE(dev); - return NULL; -} - -struct qemud_vm_def * -qemudParseVMDef(virConnectPtr conn, - struct qemud_driver *driver, - const char *xmlStr, - const char *displayName) { - xmlDocPtr xml; - struct qemud_vm_def *def = NULL; - - if (!(xml = xmlReadDoc(BAD_CAST xmlStr, displayName ? displayName : "domain.xml", NULL, - XML_PARSE_NOENT | XML_PARSE_NONET | - XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_XML_ERROR, NULL); - return NULL; - } - - def = qemudParseXML(conn, driver, xml); - - xmlFreeDoc(xml); - - return def; -} - -struct qemud_vm * -qemudAssignVMDef(virConnectPtr conn, - struct qemud_driver *driver, - struct qemud_vm_def *def) -{ - struct qemud_vm *vm = NULL; - - if ((vm = qemudFindVMByName(driver, def->name))) { - if (!qemudIsActiveVM(vm)) { - qemudFreeVMDef(vm->def); - vm->def = def; - } else { - if (vm->newDef) - qemudFreeVMDef(vm->newDef); - vm->newDef = def; - } - /* Reset version, because the emulator path might have changed */ - vm->qemuVersion = 0; - vm->qemuCmdFlags = 0; - return vm; - } - - if (VIR_ALLOC(vm) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, - "%s", _("failed to allocate space for vm string")); - return NULL; - } - - vm->stdin = -1; - vm->stdout = -1; - vm->stderr = -1; - vm->monitor = -1; - vm->pid = -1; - vm->id = -1; - vm->state = VIR_DOMAIN_SHUTOFF; - vm->def = def; - vm->next = driver->vms; - - driver->vms = vm; - driver->ninactivevms++; - - return vm; -} - -void -qemudRemoveInactiveVM(struct qemud_driver *driver, - struct qemud_vm *vm) -{ - struct qemud_vm *prev = NULL, *curr; - - curr = driver->vms; - while (curr != vm) { - prev = curr; - curr = curr->next; - } - - if (curr) { - if (prev) - prev->next = curr->next; - else - driver->vms = curr->next; - - driver->ninactivevms--; - } - - qemudFreeVM(vm); -} - -int -qemudSaveVMDef(virConnectPtr conn, - struct qemud_driver *driver, - struct qemud_vm *vm, - struct qemud_vm_def *def) { - if (vm->configFile[0] == '\0') { - int err; - - if ((err = virFileMakePath(driver->configDir))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("cannot create config directory %s: %s"), - driver->configDir, strerror(err)); - return -1; - } - - if (virFileBuildPath(driver->configDir, def->name, ".xml", - vm->configFile, PATH_MAX) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("cannot construct config file path")); - return -1; - } - - if (virFileBuildPath(driver->autostartDir, def->name, ".xml", - vm->autostartLink, PATH_MAX) < 0) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("cannot construct autostart link path")); - vm->configFile[0] = '\0'; - return -1; - } - } - - return qemudSaveConfig(conn, driver, vm, def); -} - - -static struct qemud_vm * -qemudLoadConfig(struct qemud_driver *driver, - const char *file, - const char *path, - const char *xml, - const char *autostartLink) { - struct qemud_vm_def *def; - struct qemud_vm *vm; - - if (!(def = qemudParseVMDef(NULL, driver, xml, file))) { - virErrorPtr err = virGetLastError(); - qemudLog(QEMUD_WARN, _("Error parsing QEMU guest config '%s' : %s"), - path, (err ? err->message : - _("BUG: unknown error - please report it\n"))); - return NULL; - } - - if (!virFileMatchesNameSuffix(file, def->name, ".xml")) { - qemudLog(QEMUD_WARN, - _("QEMU guest config filename '%s'" - " does not match guest name '%s'"), - path, def->name); - qemudFreeVMDef(def); - return NULL; - } - - if (!(vm = qemudAssignVMDef(NULL, driver, def))) { - qemudLog(QEMUD_WARN, - _("Failed to load QEMU guest config '%s': out of memory"), - path); - qemudFreeVMDef(def); - return NULL; - } - - strncpy(vm->configFile, path, PATH_MAX); - vm->configFile[PATH_MAX-1] = '\0'; - - strncpy(vm->autostartLink, autostartLink, PATH_MAX); - vm->autostartLink[PATH_MAX-1] = '\0'; - - vm->autostart = virFileLinkPointsTo(vm->autostartLink, vm->configFile); - - return vm; -} - -static -int qemudScanConfigDir(struct qemud_driver *driver, - const char *configDir, - const char *autostartDir) { - DIR *dir; - struct dirent *entry; - - if (!(dir = opendir(configDir))) { - if (errno == ENOENT) - return 0; - qemudLog(QEMUD_ERR, _("Failed to open dir '%s': %s"), - configDir, strerror(errno)); - return -1; - } - - while ((entry = readdir(dir))) { - char *xml; - char path[PATH_MAX]; - char autostartLink[PATH_MAX]; - - if (entry->d_name[0] == '.') - continue; - - if (!virFileHasSuffix(entry->d_name, ".xml")) - continue; - - if (virFileBuildPath(configDir, entry->d_name, NULL, path, PATH_MAX) < 0) { - qemudLog(QEMUD_WARN, _("Config filename '%s/%s' is too long"), - configDir, entry->d_name); - continue; - } - - if (virFileBuildPath(autostartDir, entry->d_name, NULL, - autostartLink, PATH_MAX) < 0) { - qemudLog(QEMUD_WARN, _("Autostart link path '%s/%s' is too long"), - autostartDir, entry->d_name); - continue; - } - - if (virFileReadAll(path, QEMUD_MAX_XML_LEN, &xml) < 0) - continue; - - qemudLoadConfig(driver, entry->d_name, path, xml, autostartLink); - - VIR_FREE(xml); - } - - closedir(dir); - - return 0; -} - -/* Scan for all guest and network config files */ -int qemudScanConfigs(struct qemud_driver *driver) { - if (qemudScanConfigDir(driver, driver->configDir, driver->autostartDir) < 0) - return -1; - - return 0; -} - -static int qemudGenerateXMLChar(virBufferPtr buf, - const struct qemud_vm_chr_def *dev, - const char *type) -{ - const char *const types[] = { - "null", - "vc", - "pty", - "dev", - "file", - "pipe", - "stdio", - "udp", - "tcp", - "unix" - }; - verify_true(ARRAY_CARDINALITY(types) == QEMUD_CHR_SRC_TYPE_LAST); - - /* Compat with legacy syntax */ - if (STREQ(type, "console") && - dev->srcType == QEMUD_CHR_SRC_TYPE_PTY && - dev->srcData.file.path[0] != '\0') { - virBufferVSprintf(buf, " <%s type='%s' tty='%s'>\n", - type, types[dev->srcType], - dev->srcData.file.path); - } else { - virBufferVSprintf(buf, " <%s type='%s'>\n", - type, types[dev->srcType]); - } - - switch (dev->srcType) { - case QEMUD_CHR_SRC_TYPE_NULL: - case QEMUD_CHR_SRC_TYPE_VC: - case QEMUD_CHR_SRC_TYPE_STDIO: - /* nada */ - break; - - case QEMUD_CHR_SRC_TYPE_PTY: - case QEMUD_CHR_SRC_TYPE_DEV: - case QEMUD_CHR_SRC_TYPE_FILE: - case QEMUD_CHR_SRC_TYPE_PIPE: - if (dev->srcType != QEMUD_CHR_SRC_TYPE_PTY || - dev->srcData.file.path[0]) { - virBufferVSprintf(buf, " \n", - dev->srcData.file.path); - } - break; - - case QEMUD_CHR_SRC_TYPE_UDP: - if (dev->srcData.udp.bindService[0] != '\0' && - dev->srcData.udp.bindHost[0] != '\0') { - virBufferVSprintf(buf, " \n", - dev->srcData.udp.bindHost, - dev->srcData.udp.bindService); - } else if (dev->srcData.udp.bindHost[0] !='\0') { - virBufferVSprintf(buf, " \n", - dev->srcData.udp.bindHost); - } else if (dev->srcData.udp.bindService[0] != '\0') { - virBufferVSprintf(buf, " \n", - dev->srcData.udp.bindService); - } - - if (dev->srcData.udp.connectService[0] != '\0' && - dev->srcData.udp.connectHost[0] != '\0') { - virBufferVSprintf(buf, " \n", - dev->srcData.udp.connectHost, - dev->srcData.udp.connectService); - } else if (dev->srcData.udp.connectHost[0] != '\0') { - virBufferVSprintf(buf, " \n", - dev->srcData.udp.connectHost); - } else if (dev->srcData.udp.connectService[0] != '\0') { - virBufferVSprintf(buf, " \n", - dev->srcData.udp.connectService); - } - break; - - case QEMUD_CHR_SRC_TYPE_TCP: - virBufferVSprintf(buf, " \n", - dev->srcData.tcp.listen ? "bind" : "connect", - dev->srcData.tcp.host, - dev->srcData.tcp.service); - virBufferVSprintf(buf, " \n", - dev->srcData.tcp.protocol == QEMUD_CHR_SRC_TCP_PROTOCOL_TELNET - ? "telnet" : "raw"); - break; - - case QEMUD_CHR_SRC_TYPE_UNIX: - virBufferVSprintf(buf, " \n", - dev->srcData.nix.listen ? "bind" : "connect", - dev->srcData.nix.path); - break; - } - - virBufferVSprintf(buf, " \n", - dev->dstPort); - - virBufferVSprintf(buf, " \n", - type); - - return 0; -} - - -/* Generate an XML document describing the guest's configuration */ -char *qemudGenerateXML(virConnectPtr conn, - struct qemud_driver *driver ATTRIBUTE_UNUSED, - struct qemud_vm *vm, - struct qemud_vm_def *def, - int live) { - virBuffer buf = VIR_BUFFER_INITIALIZER; - unsigned char *uuid; - char uuidstr[VIR_UUID_STRING_BUFLEN]; - const struct qemud_vm_disk_def *disk; - const struct qemud_vm_net_def *net; - const struct qemud_vm_input_def *input; - const struct qemud_vm_sound_def *sound; - const struct qemud_vm_chr_def *chr; - const char *type = NULL, *tmp; - int n, allones = 1; - - if (!(type = qemudVirtTypeToString(def->virtType))) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("unexpected domain type %d"), def->virtType); - goto cleanup; - } - - if (qemudIsActiveVM(vm) && live) - virBufferVSprintf(&buf, "\n", type, vm->id); - else - virBufferVSprintf(&buf, "\n", type); - - virBufferVSprintf(&buf, " %s\n", def->name); - - uuid = def->uuid; - virUUIDFormat(uuid, uuidstr); - virBufferVSprintf(&buf, " %s\n", uuidstr); - - virBufferVSprintf(&buf, " %lu\n", def->maxmem); - virBufferVSprintf(&buf, " %lu\n", def->memory); - - for (n = 0 ; n < QEMUD_CPUMASK_LEN ; n++) - if (def->cpumask[n] != 1) - allones = 0; - - if (allones) { - virBufferVSprintf(&buf, " %d\n", def->vcpus); - } else { - char *cpumask = NULL; - if ((cpumask = virSaveCpuSet(conn, def->cpumask, QEMUD_CPUMASK_LEN)) == NULL) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, - "%s", _("allocating cpu mask")); - goto cleanup; - } - virBufferVSprintf(&buf, " %d\n", cpumask, def->vcpus); - VIR_FREE(cpumask); - } - - if (def->os.bootloader[0]) - virBufferVSprintf(&buf, " %s\n", def->os.bootloader); - virBufferAddLit(&buf, " \n"); - - if (def->virtType == QEMUD_VIRT_QEMU) - virBufferVSprintf(&buf, " %s\n", - def->os.arch, def->os.machine, def->os.type); - else - virBufferVSprintf(&buf, " %s\n", def->os.type); - - if (!def->os.bootloader[0]) { - if (def->os.kernel[0]) - virBufferVSprintf(&buf, " %s\n", def->os.kernel); - if (def->os.initrd[0]) - virBufferVSprintf(&buf, " %s\n", def->os.initrd); - if (def->os.cmdline[0]) - virBufferVSprintf(&buf, " %s\n", def->os.cmdline); - - for (n = 0 ; n < def->os.nBootDevs ; n++) { - const char *boottype = "hd"; - switch (def->os.bootDevs[n]) { - case QEMUD_BOOT_FLOPPY: - boottype = "fd"; - break; - case QEMUD_BOOT_DISK: - boottype = "hd"; - break; - case QEMUD_BOOT_CDROM: - boottype = "cdrom"; - break; - case QEMUD_BOOT_NET: - boottype = "network"; - break; - } - virBufferVSprintf(&buf, " \n", boottype); - } - } - - virBufferAddLit(&buf, " \n"); - - if (def->features & QEMUD_FEATURE_ACPI) { - virBufferAddLit(&buf, " \n"); - virBufferAddLit(&buf, " \n"); - virBufferAddLit(&buf, " \n"); - } - - virBufferVSprintf(&buf, " \n", def->localtime ? "localtime" : "utc"); - - virBufferAddLit(&buf, " destroy\n"); - if (def->noReboot) - virBufferAddLit(&buf, " destroy\n"); - else - virBufferAddLit(&buf, " restart\n"); - - virBufferAddLit(&buf, " destroy\n"); - virBufferAddLit(&buf, " \n"); - - virBufferVSprintf(&buf, " %s\n", def->os.binary); - - disk = def->disks; - while (disk) { - const char *types[] = { - "block", - "file", - }; - const char *typeAttrs[] = { - "dev", - "file", - }; - const char *devices[] = { - "disk", - "cdrom", - "floppy", - }; - virBufferVSprintf(&buf, " \n", - types[disk->type], devices[disk->device]); - - if (disk->src[0]) - virBufferVSprintf(&buf, " \n", - typeAttrs[disk->type], disk->src); - - virBufferVSprintf(&buf, " \n", - disk->dst, qemudBusIdToName(disk->bus, 0)); - - if (disk->readonly) - virBufferAddLit(&buf, " \n"); - - virBufferAddLit(&buf, " \n"); - - disk = disk->next; - } - - net = def->nets; - while (net) { - const char *types[] = { - "user", - "ethernet", - "server", - "client", - "mcast", - "network", - "bridge", - }; - virBufferVSprintf(&buf, " \n", - types[net->type]); - - virBufferVSprintf(&buf, " \n", - net->mac[0], net->mac[1], net->mac[2], - net->mac[3], net->mac[4], net->mac[5]); - - switch (net->type) { - case QEMUD_NET_NETWORK: - virBufferVSprintf(&buf, " \n", net->dst.network.name); - - if (net->dst.network.ifname[0] != '\0') - virBufferVSprintf(&buf, " \n", net->dst.network.ifname); - break; - - case QEMUD_NET_ETHERNET: - if (net->dst.ethernet.ifname[0] != '\0') - virBufferVSprintf(&buf, " \n", net->dst.ethernet.ifname); - if (net->dst.ethernet.script[0] != '\0') - virBufferVSprintf(&buf, "