libvirt/src/esx/esx_util.c

520 lines
13 KiB
C
Raw Normal View History

/*
* esx_util.c: utility functions for the VMware ESX driver
*
build: consistently use C99 varargs macros Prior to this patch, there was an inconsistent mix between GNU and C99. For consistency, and potential portability to other compilers, stick with the C99 vararg macro syntax. * src/conf/cpu_conf.c (virCPUReportError): Use C99 rather than GNU vararg macro syntax. * src/conf/domain_conf.c (virDomainReportError): Likewise. * src/conf/domain_event.c (eventReportError): Likewise. * src/conf/interface_conf.c (virInterfaceReportError): Likewise. * src/conf/network_conf.c (virNetworkReportError): Likewise. * src/conf/node_device_conf.h (virNodeDeviceReportError): Likewise. * src/conf/secret_conf.h (virSecretReportError): Likewise. * src/conf/storage_conf.h (virStorageReportError): Likewise. * src/esx/esx_device_monitor.c (ESX_ERROR): Use C99 rather than GNU vararg macro syntax. * src/esx/esx_driver.c (ESX_ERROR): Likewise. * src/esx/esx_interface_driver.c (ESX_ERROR): Likewise. * src/esx/esx_network_driver.c (ESX_ERROR): Likewise. * src/esx/esx_secret_driver.c (ESX_ERROR): Likewise. * src/esx/esx_storage_driver.c (ESX_ERROR): Likewise. * src/esx/esx_util.c (ESX_ERROR): Likewise. * src/esx/esx_vi.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vi_methods.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vi_types.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vmx.c (ESX_ERROR): Likewise. * src/util/hostusb.c (usbReportError): Use C99 rather than GNU vararg macro syntax. * src/util/json.c (virJSONError): Likewise. * src/util/macvtap.c (ReportError): Likewise. * src/util/pci.c (pciReportError): Likewise. * src/util/stats_linux.c (virStatsError): Likewise. * src/util/util.c (virUtilError): Likewise. * src/util/xml.c (virXMLError): Likewise. * src/xen/proxy_internal.c (virProxyError): Use C99 rather than GNU vararg macro syntax. * src/xen/sexpr.c (virSexprError): Likewise. * src/xen/xen_driver.c (xenUnifiedError): Likewise. * src/xen/xen_hypervisor.c (virXenError): Likewise. * src/xen/xen_inotify.c (virXenInotifyError): Likewise. * src/xen/xend_internal.c (virXendError): Likewise. * src/xen/xm_internal.c (xenXMError): Likewise. * src/xen/xs_internal.c (virXenStoreError): Likewise. * src/cpu/cpu.h (virCPUReportError): Use C99 rather than GNU vararg macro syntax. * src/datatypes.c (virLibConnError): Likewise. * src/interface/netcf_driver.c (interfaceReportError): Likewise. * src/libvirt.c (virLibStreamError): Likewise. * src/lxc/lxc_conf.h (lxcError): Likewise. * src/network/bridge_driver.c (networkReportError): Likewise. * src/nodeinfo.c (nodeReportError): Likewise. * src/opennebula/one_conf.h (oneError): Likewise. * src/openvz/openvz_conf.h (openvzError): Likewise. * src/phyp/phyp_driver.c (PHYP_ERROR): Likewise. * src/qemu/qemu_conf.h (qemuReportError): Likewise. * src/remote/remote_driver.c (errorf): Likewise. * src/security/security_driver.h (virSecurityReportError): Likewise. * src/test/test_driver.c (testError): Likewise. * src/uml/uml_conf.h (umlReportError): Likewise. * src/vbox/vbox_driver.c (vboxError): Likewise. * src/vbox/vbox_tmpl.c (vboxError): Likewise.
2010-03-01 23:38:28 +00:00
* Copyright (C) 2010 Red Hat, Inc.
* Copyright (C) 2009 Matthias Bolte <matthias.bolte@googlemail.com>
* Copyright (C) 2009 Maximilian Wilhelm <max@rfc2324.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <config.h>
#include <netdb.h>
#include "internal.h"
#include "datatypes.h"
#include "qparams.h"
#include "util.h"
#include "memory.h"
#include "logging.h"
#include "uuid.h"
#include "esx_private.h"
#include "esx_util.h"
#define VIR_FROM_THIS VIR_FROM_ESX
/* AI_ADDRCONFIG is missing on some systems. */
#ifndef AI_ADDRCONFIG
# define AI_ADDRCONFIG 0
#endif
int
esxUtil_ParseQuery(xmlURIPtr uri, char **transport, char **vCenter,
int *noVerify, int *autoAnswer)
{
int result = 0;
int i;
struct qparam_set *queryParamSet = NULL;
struct qparam *queryParam = NULL;
if (transport != NULL) {
*transport = NULL;
}
if (vCenter != NULL) {
*vCenter = NULL;
}
if (noVerify != NULL) {
*noVerify = 0;
}
if (autoAnswer != NULL) {
*autoAnswer = 0;
}
#ifdef HAVE_XMLURI_QUERY_RAW
queryParamSet = qparam_query_parse(uri->query_raw);
#else
queryParamSet = qparam_query_parse(uri->query);
#endif
if (queryParamSet == NULL) {
goto failure;
}
for (i = 0; i < queryParamSet->n; i++) {
queryParam = &queryParamSet->p[i];
if (STRCASEEQ(queryParam->name, "transport")) {
if (transport == NULL) {
continue;
}
*transport = strdup(queryParam->value);
if (*transport == NULL) {
virReportOOMError();
goto failure;
}
if (STRNEQ(*transport, "http") && STRNEQ(*transport, "https")) {
ESX_ERROR(VIR_ERR_INVALID_ARG,
_("Query parameter 'transport' has unexpected value "
"'%s' (should be http|https)"), *transport);
goto failure;
}
} else if (STRCASEEQ(queryParam->name, "vcenter")) {
if (vCenter == NULL) {
continue;
}
*vCenter = strdup(queryParam->value);
if (*vCenter == NULL) {
virReportOOMError();
goto failure;
}
} else if (STRCASEEQ(queryParam->name, "no_verify")) {
if (noVerify == NULL) {
continue;
}
if (virStrToLong_i(queryParam->value, NULL, 10, noVerify) < 0 ||
(*noVerify != 0 && *noVerify != 1)) {
ESX_ERROR(VIR_ERR_INVALID_ARG,
_("Query parameter 'no_verify' has unexpected value "
"'%s' (should be 0 or 1)"), queryParam->value);
goto failure;
}
} else if (STRCASEEQ(queryParam->name, "auto_answer")) {
if (autoAnswer == NULL) {
continue;
}
if (virStrToLong_i(queryParam->value, NULL, 10, autoAnswer) < 0 ||
(*autoAnswer != 0 && *autoAnswer != 1)) {
ESX_ERROR(VIR_ERR_INVALID_ARG,
_("Query parameter 'auto_answer' has unexpected "
"value '%s' (should be 0 or 1)"), queryParam->value);
goto failure;
}
} else {
VIR_WARN("Ignoring unexpected query parameter '%s'",
queryParam->name);
}
}
if (transport != NULL && *transport == NULL) {
*transport = strdup("https");
if (*transport == NULL) {
virReportOOMError();
goto failure;
}
}
cleanup:
if (queryParamSet != NULL) {
free_qparam_set(queryParamSet);
}
return result;
failure:
if (transport != NULL) {
VIR_FREE(*transport);
}
if (vCenter != NULL) {
VIR_FREE(*vCenter);
}
result = -1;
goto cleanup;
}
int
esxUtil_ParseVirtualMachineIDString(const char *id_string, int *id)
{
/* Try to parse an integer from the complete string. */
if (virStrToLong_i(id_string, NULL, 10, id) == 0) {
return 0;
}
/*
* If that fails try to parse an integer from the string tail
* assuming the naming scheme Virtual Center seems to use.
*/
if (STRPREFIX(id_string, "vm-")) {
if (virStrToLong_i(id_string + 3, NULL, 10, id) == 0) {
return 0;
}
}
return -1;
}
int
esxUtil_ParseDatastoreRelatedPath(const char *datastoreRelatedPath,
char **datastoreName,
char **directoryName, char **fileName)
{
int result = 0;
char *directoryAndFileName = NULL;
char *separator = NULL;
if (datastoreName == NULL || *datastoreName != NULL ||
directoryName == NULL || *directoryName != NULL ||
fileName == NULL || *fileName != NULL) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
return -1;
}
/*
* Parse string as '[<datastore>] <path>'. '%as' is similar to '%s', but
* sscanf() will allocate the memory for the string, so the caller doesn't
* need to preallocate a buffer that's large enough.
*
* The s in '%as' can be replaced with a character set, e.g. [a-z].
*
* '%a[^]%]' matches <datastore>. '[^]%]' excludes ']' from the accepted
* characters, otherwise sscanf() wont match what it should.
*
* '%a[^\n]' matches <path>. '[^\n]' excludes '\n' from the accepted
* characters, otherwise sscanf() would only match up to the first space,
* but spaces are valid in <path>.
*/
if (sscanf(datastoreRelatedPath, "[%a[^]%]] %a[^\n]", datastoreName,
&directoryAndFileName) != 2) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Datastore related path '%s' doesn't have expected format "
"'[<datastore>] <path>'"), datastoreRelatedPath);
goto failure;
}
/* Split <path> into <directory>/<file>, where <directory> is optional */
separator = strrchr(directoryAndFileName, '/');
if (separator != NULL) {
*separator++ = '\0';
*directoryName = directoryAndFileName;
directoryAndFileName = NULL;
if (*separator == '\0') {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Datastore related path '%s' doesn't reference a file"),
datastoreRelatedPath);
goto failure;
}
*fileName = strdup(separator);
if (*fileName == NULL) {
virReportOOMError();
goto failure;
}
} else {
*fileName = directoryAndFileName;
directoryAndFileName = NULL;
}
cleanup:
VIR_FREE(directoryAndFileName);
return result;
failure:
VIR_FREE(*datastoreName);
VIR_FREE(*directoryName);
VIR_FREE(*fileName);
result = -1;
goto cleanup;
}
int
esxUtil_ResolveHostname(const char *hostname,
char *ipAddress, size_t ipAddress_length)
{
struct addrinfo hints;
struct addrinfo *result = NULL;
int errcode;
2009-09-23 12:37:26 +00:00
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_flags = AI_ADDRCONFIG;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
errcode = getaddrinfo(hostname, NULL, &hints, &result);
if (errcode != 0) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("IP address lookup for host '%s' failed: %s"), hostname,
gai_strerror(errcode));
return -1;
}
if (result == NULL) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("No IP address for host '%s' found: %s"), hostname,
gai_strerror(errcode));
return -1;
}
errcode = getnameinfo(result->ai_addr, result->ai_addrlen, ipAddress,
ipAddress_length, NULL, 0, NI_NUMERICHOST);
if (errcode != 0) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Formating IP address for host '%s' failed: %s"), hostname,
gai_strerror(errcode));
freeaddrinfo(result);
return -1;
}
freeaddrinfo(result);
return 0;
}
int
esxUtil_GetConfigString(virConfPtr conf, const char *name, char **string,
int optional)
{
virConfValuePtr value;
*string = NULL;
value = virConfGetValue(conf, name);
if (value == NULL) {
if (optional) {
return 0;
}
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Missing essential config entry '%s'"), name);
return -1;
}
if (value->type != VIR_CONF_STRING) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Config entry '%s' must be a string"), name);
return -1;
}
if (value->str == NULL) {
if (optional) {
return 0;
}
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Missing essential config entry '%s'"), name);
return -1;
}
*string = strdup(value->str);
if (*string == NULL) {
virReportOOMError();
return -1;
}
return 0;
}
int
esxUtil_GetConfigUUID(virConfPtr conf, const char *name, unsigned char *uuid,
int optional)
{
virConfValuePtr value;
value = virConfGetValue(conf, name);
if (value == NULL) {
if (optional) {
return 0;
} else {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Missing essential config entry '%s'"), name);
return -1;
}
}
if (value->type != VIR_CONF_STRING) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Config entry '%s' must be a string"), name);
return -1;
}
if (value->str == NULL) {
if (optional) {
return 0;
} else {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Missing essential config entry '%s'"), name);
return -1;
}
}
if (virUUIDParse(value->str, uuid) < 0) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Could not parse UUID from string '%s'"), value->str);
return -1;
}
return 0;
}
int
esxUtil_GetConfigLong(virConfPtr conf, const char *name, long long *number,
long long default_, int optional)
{
virConfValuePtr value;
*number = default_;
value = virConfGetValue(conf, name);
if (value == NULL) {
if (optional) {
return 0;
} else {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Missing essential config entry '%s'"), name);
return -1;
}
}
if (value->type == VIR_CONF_STRING) {
if (value->str == NULL) {
if (optional) {
return 0;
} else {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Missing essential config entry '%s'"), name);
return -1;
}
}
if (STREQ(value->str, "unlimited")) {
*number = -1;
} else if (virStrToLong_ll(value->str, NULL, 10, number) < 0) {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Config entry '%s' must represent an integer value"),
name);
return -1;
}
} else {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Config entry '%s' must be a string"), name);
return -1;
}
return 0;
}
int
esxUtil_GetConfigBoolean(virConfPtr conf, const char *name, int *boolean_,
int default_, int optional)
{
virConfValuePtr value;
2009-09-23 12:37:26 +00:00
*boolean_ = default_;
value = virConfGetValue(conf, name);
if (value == NULL) {
if (optional) {
return 0;
} else {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Missing essential config entry '%s'"), name);
return -1;
}
}
if (value->type == VIR_CONF_STRING) {
if (value->str == NULL) {
if (optional) {
return 0;
} else {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Missing essential config entry '%s'"), name);
return -1;
}
}
if (STRCASEEQ(value->str, "true")) {
2009-09-23 12:37:26 +00:00
*boolean_ = 1;
} else if (STRCASEEQ(value->str, "false")) {
2009-09-23 12:37:26 +00:00
*boolean_ = 0;
} else {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Config entry '%s' must represent a boolean value "
"(true|false)"), name);
return -1;
}
} else {
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
_("Config entry '%s' must be a string"), name);
return -1;
}
return 0;
}