--- src/libvirt-php.c | 246 +++++++++++++++++++++++++---------------------------- 1 file changed, 114 insertions(+), 132 deletions(-) diff --git a/src/libvirt-php.c b/src/libvirt-php.c index 0b8345a..24e8606 100644 --- a/src/libvirt-php.c +++ b/src/libvirt-php.c @@ -4232,11 +4232,12 @@ PHP_FUNCTION(libvirt_domain_change_boot_devices) Since version: 0.4.2 Description: Function is used to add the disk to the virtual machine using set of API functions to make it as simple as possible for the user Arguments: @res [resource]: libvirt domain resource - @img [string]: string for the image file on the host system + @path [string]: string for the image file or device node on the system @dev [string]: string for the device to be presented to the guest (e.g. hda) @typ [string]: bus type for the device in the guest, usually 'ide' or 'scsi' - @driver [string]: driver type to be specified, like 'raw' or 'qcow2' - @flags [int]: flags for getting the XML description + @driver [string]: driver type to be specified, like 'raw' or 'qcow2' + @cache [string]: cache mode, can be 'default', 'none', 'writeback' or 'writethrough' + @io [string]: io mode, can be 'default', 'native' or 'threads' Returns: new domain resource */ PHP_FUNCTION(libvirt_domain_disk_add) @@ -4244,46 +4245,40 @@ PHP_FUNCTION(libvirt_domain_disk_add) php_libvirt_domain *domain=NULL; zval *zdomain; char *tmp1 = NULL; - char *tmp2 = NULL; char *xml; - char *img = NULL; - int img_len; + char *path = NULL; + int path_len; char *dev = NULL; int dev_len; char *driver = NULL; int driver_len; char *typ = NULL; int typ_len; - char *new_xml = NULL; - int new_len; + char *cache = "default"; + int cache_len; + char *io = "default"; + int io_len; char new[4096] = { 0 }; - long xflags = 0; int retval = -1; - int pos = -1; - php_libvirt_domain *res_domain = NULL; - php_libvirt_connection *conn = NULL; - virDomainPtr dom=NULL; + int block_device = 0; // whether the path leads to a block device (1) or to an image (0) + char cache_attr[32] = ""; // store the complete cache attribute, or an empty string to denote default + char io_attr[32] = ""; // store the complete io attribute, or an empty string to denote default - GET_DOMAIN_FROM_ARGS("rssss|l",&zdomain,&img,&img_len,&dev,&dev_len,&typ,&typ_len,&driver,&driver_len,&xflags); + GET_DOMAIN_FROM_ARGS("rssss|ss",&zdomain,&path,&path_len,&dev,&dev_len,&typ,&typ_len,&driver,&driver_len,&cache,&cache_len,&io,&io_len); - DPRINTF("%s: Domain %p, device = %s, image = %s, type = %s, driver = %s\n", PHPFUNC, - domain->domain, dev, img, typ, driver); + DPRINTF("%s: Domain %p, device = %s, path = %s, type = %s, driver = %s, cache = %s, io = %s\n", PHPFUNC, + domain->domain, dev, path, typ, driver, cache, io); - xml=virDomainGetXMLDesc(domain->domain,xflags); + // check whether the path leads to a block device + if (strncmp(path, "/dev/", 5) == 0) + block_device = 1; + + xml=virDomainGetXMLDesc(domain->domain, 0); if (xml==NULL) { set_error_if_unset("Cannot get the XML description" TSRMLS_CC); RETURN_FALSE; } - snprintf(new, sizeof(new), "//domain/devices/disk/source[@file=\"%s\"]/./@file", img); - tmp1 = get_string_from_xpath(xml, new, NULL, &retval); - if (tmp1 != NULL) { - free(tmp1); - snprintf(new, sizeof(new), "Domain already has image <i>%s</i> connected", img); - set_error(new TSRMLS_CC); - RETURN_FALSE; - } - snprintf(new, sizeof(new), "//domain/devices/disk/target[@dev='%s']/./@dev", dev); tmp1 = get_string_from_xpath(xml, new, NULL, &retval); if (tmp1 != NULL) { @@ -4293,58 +4288,72 @@ PHP_FUNCTION(libvirt_domain_disk_add) RETURN_FALSE; } - if (access(img, R_OK) != 0) { - snprintf(new, sizeof(new), "Image file <i>%s</i> doesn't exist", img); - set_error(new TSRMLS_CC); - RETURN_FALSE; - } - - snprintf(new, sizeof(new), - " <disk type='file' device='disk'>\n" - " <driver name='qemu' type='%s'/>\n" - " <source file='%s'/>\n" - " <target dev='%s' bus='%s'/>\n" - " </disk>", driver, img, dev, typ); - tmp1 = strstr(xml, "</emulator>") + strlen("</emulator>"); - pos = strlen(xml) - strlen(tmp1); + // do we want to use a non-default cache mode? + if (strncmp(cache, "default", 7) != 0) + snprintf(cache_attr, sizeof(cache_attr), "cache='%s'", cache); - tmp2 = emalloc( ( pos + 1 )* sizeof(char) ); - memset(tmp2, 0, pos + 1); - memcpy(tmp2, xml, pos); + // or a non-default io mode perhaps? + if (strncmp(io, "default", 7) != 0) + snprintf(io_attr, sizeof(io_attr), "io='%s'", io); - new_len = strlen(tmp1) + strlen(tmp2) + strlen(new) + 2; - new_xml = emalloc( new_len * sizeof(char) ); - snprintf(new_xml, new_len, "%s\n%s%s", tmp2, new, tmp1); - - conn = domain->conn; + // check for valid image file or device node + if (block_device == 0) { + // check whether the image already appears in the xml + snprintf(new, sizeof(new), "//domain/devices/disk/source[@file=\"%s\"]/./@file", path); + tmp1 = get_string_from_xpath(xml, new, NULL, &retval); + if (tmp1 != NULL) { + free(tmp1); + snprintf(new, sizeof(new), "Domain already has image <i>%s</i> connected", path); + set_error(new TSRMLS_CC); + RETURN_FALSE; + } - virDomainUndefine(domain->domain); - virDomainFree(domain->domain); + if (access(path, R_OK) != 0) { + snprintf(new, sizeof(new), "Image file <i>%s</i> doesn't exist", path); + set_error(new TSRMLS_CC); + RETURN_FALSE; + } - retval = virDomainFree(domain->domain); - if (retval != 0) { - DPRINTF("%s: Cannot free domain %p, error code = %d (%s)\n", PHPFUNC, domain->domain, retval, LIBVIRT_G(last_error)); - } + // create the xml to add the device + snprintf(new, sizeof(new), + " <disk type='file' device='disk'>\n" + " <driver name='qemu' type='%s' %s %s/>\n" + " <source file='%s'/>\n" + " <target dev='%s' bus='%s'/>\n" + " </disk>", driver, cache_attr, io_attr, path, dev, typ); + } else { - resource_change_counter(INT_RESOURCE_DOMAIN, conn->conn, domain->domain, 0 TSRMLS_CC); - DPRINTF("%s: Domain %p freed\n", PHPFUNC, domain->domain); - } - - dom=virDomainDefineXML(conn->conn, new_xml); - if (dom==NULL) { - DPRINTF("%s: Function failed, restoring original XML\n", PHPFUNC); - dom=virDomainDefineXML(conn->conn, xml); - if (dom == NULL) + // check whether the device already appears in the xml + snprintf(new, sizeof(new), "//domain/devices/disk/source[@dev=\"%s\"]/./@dev", path); + tmp1 = get_string_from_xpath(xml, new, NULL, &retval); + if (tmp1 != NULL) { + free(tmp1); + snprintf(new, sizeof(new), "Domain already has device <i>%s</i> connected", path); + set_error(new TSRMLS_CC); RETURN_FALSE; + } + + // create the xml to add the device + snprintf(new, sizeof(new), + " <disk type='block' device='disk'>\n" + " <driver name='qemu' type='%s' %s %s/>\n" + " <source dev='%s'/>\n" + " <target dev='%s' bus='%s'/>\n" + " </disk>", driver, cache_attr, io_attr, path, dev, typ); } - res_domain = emalloc(sizeof(php_libvirt_domain)); - res_domain->domain = dom; - res_domain->conn = conn; + // attach the disk to the domain + retval = virDomainAttachDeviceFlags(domain->domain, new, VIR_DOMAIN_AFFECT_CURRENT); + if (retval != 0) { + snprintf(new, sizeof(new), "%s: Cannot add device to domain %p, error code = %d (%s)\n", PHPFUNC, domain->domain, retval, LIBVIRT_G(last_error)); + set_error(new TSRMLS_CC); + RETURN_FALSE; + } - DPRINTF("%s: returning %p\n", PHPFUNC, res_domain->domain); - resource_change_counter(INT_RESOURCE_DOMAIN, conn->conn, res_domain->domain, 1 TSRMLS_CC); - ZEND_REGISTER_RESOURCE(return_value, res_domain, le_libvirt_domain); + // the disk was successfully added + DPRINTF("%s: returning %p\n", PHPFUNC, domain->domain); + zend_list_addref(Z_LVAL_P(zdomain)); + RETURN_RESOURCE(Z_LVAL_P(zdomain)); } /* @@ -4360,96 +4369,69 @@ PHP_FUNCTION(libvirt_domain_disk_remove) { php_libvirt_domain *domain=NULL; zval *zdomain; - char *tmp1 = NULL; - char *tmp2 = NULL; + char *type = NULL; + char *path = NULL; + char *source = NULL; char *xml; char *dev = NULL; int dev_len; char *new_xml = NULL; int new_len; char new[4096] = { 0 }; - long xflags = 0; int retval = -1; - int pos = -1; - int i, idx = 0; - php_libvirt_domain *res_domain=NULL; - php_libvirt_connection *conn = NULL; - virDomainPtr dom = NULL; - GET_DOMAIN_FROM_ARGS("rs|l",&zdomain,&dev,&dev_len,&xflags); + GET_DOMAIN_FROM_ARGS("rs|l",&zdomain,&dev,&dev_len); DPRINTF("%s: Trying to remove %s from domain %p\n", PHPFUNC, dev, domain->domain); - xml=virDomainGetXMLDesc(domain->domain,xflags); + xml=virDomainGetXMLDesc(domain->domain, 0); if (xml==NULL) { set_error_if_unset("Cannot get the XML description" TSRMLS_CC); RETURN_FALSE; } - snprintf(new, sizeof(new), "//domain/devices/disk/target[@dev='%s']/./@dev", dev); - tmp1 = get_string_from_xpath(xml, new, NULL, &retval); - if (tmp1 == NULL) { + // check for the type, if no result is found, the disk does not exist + snprintf(new, sizeof(new), "//domain/devices/disk/target[@dev='%s']/../@type", dev); + type = get_string_from_xpath(xml, new, NULL, &retval); + if (type == NULL) { snprintf(new, sizeof(new), "Device <i>%s</i> is not connected to the guest", dev); set_error(new TSRMLS_CC); RETURN_FALSE; } - free(tmp1); - - snprintf(new, sizeof(new), "<target dev='%s'", dev); - tmp1 = strstr(xml, new) + strlen(new); - pos = strlen(xml) - strlen(tmp1); - - tmp2 = emalloc( ( pos + 1 )* sizeof(char) ); - memset(tmp2, 0, pos + 1); - memcpy(tmp2, xml, pos); - - for (i = strlen(tmp2) - 5; i > 0; i--) - if ((tmp2[i] == '<') && (tmp2[i+1] == 'd') - && (tmp2[i+2] == 'i') && (tmp2[i+3] == 's') - && (tmp2[i+4] == 'k')) { - tmp2[i-5] = 0; - break; - } + // are we dealing with a file or a block device? + if (strcmp(type, "file") == 0) + source = "file"; + else + source = "dev"; - for (i = 0; i < strlen(tmp1) - 7; i++) - if ((tmp1[i] == '<') && (tmp1[i+1] == '/') - && (tmp1[i+2] == 'd') && (tmp1[i+3] == 'i') - && (tmp1[i+4] == 's') && (tmp1[i+5] == 'k') - && (tmp1[i+6] == '>')) { - idx = i + 6; - break; - } + // retrieve the device or file + snprintf(new, sizeof(new), "//domain/devices/disk/target[@dev='%s']/../source/@%s", dev, source); + path = get_string_from_xpath(xml, new, NULL, &retval); - new_len = strlen(tmp2) + (strlen(tmp1) - idx); - new_xml = emalloc( new_len * sizeof(char) ); - memset(new_xml, 0, new_len); - strcpy(new_xml, tmp2); - for (i = idx; i < strlen(tmp1) - 1; i++) - new_xml[ strlen(tmp2) + i - idx ] = tmp1[i]; + // define the xml to remove the device + snprintf(new, sizeof(new), + " <disk type='%s' device='disk'>" + " <source %s='%s'/>" + " <target dev='%s'/>" + " </disk>", type, source, path, dev); - conn = domain->conn; - virDomainUndefine(domain->domain); + // cleanup temporary resources + free(type); + free(path); - retval = virDomainFree(domain->domain); + // remove the disk from the domain + retval = virDomainDetachDeviceFlags(domain->domain, new, VIR_DOMAIN_AFFECT_CURRENT); if (retval != 0) { - DPRINTF("%s: Cannot free domain %p, error code = %d (%s)\n", PHPFUNC, domain->domain, retval, LIBVIRT_G(last_error)); - } - else { - resource_change_counter(INT_RESOURCE_DOMAIN, conn->conn, domain->domain, 0 TSRMLS_CC); - DPRINTF("%s: Domain %p freed\n", PHPFUNC, domain->domain); + snprintf(new, sizeof(new), "%s: Cannot remove device from domain %p, error code = %d (%s)\n", PHPFUNC, domain->domain, retval, LIBVIRT_G(last_error)); + set_error(new TSRMLS_CC); + RETURN_FALSE; } - dom=virDomainDefineXML(conn->conn,new_xml); - if (dom==NULL) RETURN_FALSE; - - res_domain = emalloc(sizeof(php_libvirt_domain)); - res_domain->domain = dom; - res_domain->conn = conn; - - DPRINTF("%s: returning %p\n", PHPFUNC, res_domain->domain); - resource_change_counter(INT_RESOURCE_DOMAIN, conn->conn, res_domain->domain, 1 TSRMLS_CC); - ZEND_REGISTER_RESOURCE(return_value, res_domain, le_libvirt_domain); + // the disk was successfully removed + DPRINTF("%s: returning %p\n", PHPFUNC, domain->domain); + zend_list_addref(Z_LVAL_P(zdomain)); + RETURN_RESOURCE(Z_LVAL_P(zdomain)); } /* @@ -5172,7 +5154,7 @@ PHP_FUNCTION(libvirt_domain_get_block_info) { GET_DOMAIN_FROM_ARGS("rs",&zdomain,&dev,&dev_len); /* Get XML for the domain */ - xml=virDomainGetXMLDesc(domain->domain, VIR_DOMAIN_XML_INACTIVE); + xml=virDomainGetXMLDesc(domain->domain, 0); if (xml==NULL) { set_error("Cannot get domain XML" TSRMLS_CC); RETURN_FALSE; -- 1.7.9.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list