From 56bac4a2215dbadddee3fbbbb6bdb16e11e41115 Mon Sep 17 00:00:00 2001 From: Matthias Bolte Date: Tue, 30 Mar 2010 16:15:13 +0200 Subject: [PATCH] Refactor major.minor.micro version parsing into a function virParseVersionString uses virStrToLong_ui instead of sscanf. This also fixes a bug in the UML driver, that always returned 0 as version number. Introduce STRSKIP to check if a string has a certain prefix and to skip this prefix. --- src/esx/esx_driver.c | 29 ++++++----------------------- src/internal.h | 1 + src/libvirt_private.syms | 1 + src/lxc/lxc_driver.c | 10 ++-------- src/openvz/openvz_conf.c | 16 +++++++++------- src/uml/uml_conf.h | 2 +- src/uml/uml_driver.c | 17 +++++++++-------- src/util/util.c | 35 +++++++++++++++++++++++++++++++++++ src/util/util.h | 1 + src/vbox/vbox_tmpl.c | 14 ++++---------- src/xenapi/xenapi_driver.c | 20 +++++++++----------- 11 files changed, 78 insertions(+), 68 deletions(-) diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 20376e926d..7a92c4dc4b 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -684,34 +684,17 @@ static int esxGetVersion(virConnectPtr conn, unsigned long *version) { esxPrivate *priv = conn->privateData; - char *temp; - unsigned int major, minor, release; - temp = (char *)priv->host->service->about->version; + if (virParseVersionString(priv->host->service->about->version, + version) < 0) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, + "Could not parse version number from '%s'", + priv->host->service->about->version); - /* Expecting 'major.minor.release' format */ - if (virStrToLong_ui(temp, &temp, 10, &major) < 0 || *temp != '.') { - goto failure; + return -1; } - if (virStrToLong_ui(temp + 1, &temp, 10, &minor) < 0 || *temp != '.') { - goto failure; - } - - if (virStrToLong_ui(temp + 1, NULL, 10, &release) < 0) { - goto failure; - } - - *version = 1000000 * major + 1000 * minor + release; - return 0; - - failure: - ESX_ERROR(VIR_ERR_INTERNAL_ERROR, - "Expecting version to match 'major.minor.release', but got '%s'", - priv->host->service->about->version); - - return -1; } diff --git a/src/internal.h b/src/internal.h index f82fbd2533..807288b868 100644 --- a/src/internal.h +++ b/src/internal.h @@ -57,6 +57,7 @@ # define STRNEQLEN(a,b,n) (strncmp(a,b,n) != 0) # define STRCASENEQLEN(a,b,n) (strncasecmp(a,b,n) != 0) # define STRPREFIX(a,b) (strncmp(a,b,strlen(b)) == 0) +# define STRSKIP(a,b) (STRPREFIX(a,b) ? (a) + strlen(b) : NULL) # define STREQ_NULLABLE(a, b) \ ((!(a) && !(b)) || ((a) && (b) && STREQ((a), (b)))) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index cc943f821b..edb23c2273 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -648,6 +648,7 @@ virFilePid; virFileReadPid; virFileLinkPointsTo; virParseNumber; +virParseVersionString; virPipeReadUntilEOF; virAsprintf; virRun; diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 7ebc7ae9d1..9caefa13a4 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -1951,20 +1951,14 @@ lxcActive(void) { static int lxcVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *version) { struct utsname ver; - int maj; - int min; - int rev; uname(&ver); - if (sscanf(ver.release, "%i.%i.%i", &maj, &min, &rev) != 3) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Unknown release: %s"), ver.release); + if (virParseVersionString(ver.release, version) < 0) { + lxcError(VIR_ERR_INTERNAL_ERROR, _("Unknown release: %s"), ver.release); return -1; } - *version = (maj * 1000 * 1000) + (min * 1000) + rev; - return 0; } diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c index 3713a458df..7fc3cd10e4 100644 --- a/src/openvz/openvz_conf.c +++ b/src/openvz/openvz_conf.c @@ -78,8 +78,8 @@ openvzExtractVersionInfo(const char *cmd, int *retversion) pid_t child; int newstdout = -1; int ret = -1, status; - unsigned int major, minor, micro; - unsigned int version; + unsigned long version; + char *tmp; if (retversion) *retversion = 0; @@ -93,12 +93,14 @@ openvzExtractVersionInfo(const char *cmd, int *retversion) if (len < 0) goto cleanup2; - if (sscanf(help, "vzctl version %u.%u.%u", - &major, &minor, µ) != 3) { - goto cleanup2; - } + tmp = help; - version = (major * 1000 * 1000) + (minor * 1000) + micro; + /* expected format: vzctl version .. */ + if ((tmp = STRSKIP(tmp, "vzctl version ")) == NULL) + goto cleanup2; + + if (virParseVersionString(tmp, &version) < 0) + goto cleanup2; if (retversion) *retversion = version; diff --git a/src/uml/uml_conf.h b/src/uml/uml_conf.h index 70c3f7df2f..4d434e1b7a 100644 --- a/src/uml/uml_conf.h +++ b/src/uml/uml_conf.h @@ -44,7 +44,7 @@ struct uml_driver { int privileged; - unsigned int umlVersion; + unsigned long umlVersion; int nextvmid; virDomainObjList domains; diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 835e5d4ca3..08fbf930bd 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -1225,17 +1225,18 @@ cleanup: static int umlGetVersion(virConnectPtr conn, unsigned long *version) { struct uml_driver *driver = conn->privateData; struct utsname ut; - int major, minor, micro; int ret = -1; - uname(&ut); - umlDriverLock(driver); - if (sscanf(ut.release, "%u.%u.%u", - &major, &minor, µ) != 3) { - umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("cannot parse version %s"), ut.release); - goto cleanup; + + if (driver->umlVersion == 0) { + uname(&ut); + + if (virParseVersionString(ut.release, &driver->umlVersion) < 0) { + umlReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot parse version %s"), ut.release); + goto cleanup; + } } *version = driver->umlVersion; diff --git a/src/util/util.c b/src/util/util.c index 62dc5f191e..28a3c7ed09 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -2074,6 +2074,41 @@ virParseNumber(const char **str) return (ret); } + +/** + * virParseVersionString: + * @str: const char pointer to the version string + * @version: unsigned long pointer to output the version number + * + * Parse an unsigned version number from a version string. Expecting + * 'major.minor.micro' format, ignoring an optional suffix. + * + * The major, minor and micro numbers are encoded into a single version number: + * + * 1000000 * major + 1000 * minor + micro + * + * Returns the 0 for success, -1 for error. + */ +int +virParseVersionString(const char *str, unsigned long *version) +{ + unsigned int major, minor, micro; + char *tmp; + + if (virStrToLong_ui(str, &tmp, 10, &major) < 0 || *tmp != '.') + return -1; + + if (virStrToLong_ui(tmp + 1, &tmp, 10, &minor) < 0 || *tmp != '.') + return -1; + + if (virStrToLong_ui(tmp + 1, &tmp, 10, µ) < 0) + return -1; + + *version = 1000000 * major + 1000 * minor + micro; + + return 0; +} + /** * virAsprintf * diff --git a/src/util/util.h b/src/util/util.h index 24dfbfc3ee..c25611763e 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -189,6 +189,7 @@ int virMacAddrCompare (const char *mac1, const char *mac2); void virSkipSpaces(const char **str); int virParseNumber(const char **str); +int virParseVersionString(const char *str, unsigned long *version); int virAsprintf(char **strp, const char *fmt, ...) ATTRIBUTE_FMT_PRINTF(2, 3); char *virStrncpy(char *dest, const char *src, size_t n, size_t destbytes) ATTRIBUTE_RETURN_CHECK; diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index f7a9b9fee3..05b075fddd 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -157,7 +157,7 @@ if (strUtf16) {\ typedef struct { virMutex lock; - int version; + unsigned long version; virCapsPtr caps; @@ -713,10 +713,7 @@ cleanup: } static int vboxExtractVersion(virConnectPtr conn, vboxGlobalData *data) { - unsigned int major = 0; - unsigned int minor = 0; - unsigned int micro = 0; - int ret = -1; + int ret = -1; PRUnichar *versionUtf16 = NULL; nsresult rc; @@ -729,20 +726,17 @@ static int vboxExtractVersion(virConnectPtr conn, vboxGlobalData *data) { VBOX_UTF16_TO_UTF8(versionUtf16, &vboxVersion); - if (sscanf(vboxVersion, "%u.%u.%u", &major, &minor, µ) == 3) + if (virParseVersionString(vboxVersion, &data->version) >= 0) ret = 0; VBOX_UTF8_FREE(vboxVersion); VBOX_COM_UNALLOC_MEM(versionUtf16); - } else { - ret = -1; } - data->version = (major * 1000 * 1000) + (minor * 1000) + micro; - if (ret != 0) vboxError(conn, VIR_ERR_INTERNAL_ERROR,"%s", "Cound not extract VirtualBox version"); + return ret; } diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index d48bb4da25..dcfdc1e083 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -253,9 +253,8 @@ xenapiGetVersion (virConnectPtr conn, unsigned long *hvVer) xen_host host; xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session; xen_string_string_map *result = NULL; - int i; + int i, ret = -1; char *version = NULL; - unsigned long major = 0, minor = 0, release = 0; if (!(xen_session_get_this_host(session, &host, session))) { xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL); return -1; @@ -278,18 +277,17 @@ xenapiGetVersion (virConnectPtr conn, unsigned long *hvVer) } } if (version) { - if (sscanf(version, "%ld.%ld.%ld", &major, &minor, &release) != 3) { + if (virParseVersionString(version, hvVer) < 0) xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, - _("Couldn't get version info")); - xen_string_string_map_free(result); - VIR_FREE(version); - return -1; - } - *hvVer = major * 1000000 + minor * 1000 + release; - VIR_FREE(version); + _("Couldn't parse version info")); + else + ret = 0; xen_string_string_map_free(result); - return 0; + VIR_FREE(version); + return ret; } + xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, + _("Couldn't get version info")); } return -1; }