[libvirt] [PATCH 03/10] Refactor major.minor.micro version parsing into a function

Matthias Bolte matthias.bolte at googlemail.com
Tue Mar 30 16:20:27 UTC 2010


virParseVersionString uses virStrToLong_ui instead of sscanf.

This also fixes a bug in the UML driver, that always returned 0
as version number.
---
 src/esx/esx_driver.c       |   31 ++++++-------------------------
 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            |   37 +++++++++++++++++++++++++++++++++++++
 src/util/util.h            |    1 +
 src/vbox/vbox_tmpl.c       |   14 ++++----------
 src/xenapi/xenapi_driver.c |   21 ++++++++++-----------
 10 files changed, 81 insertions(+), 69 deletions(-)

diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index bbe8a51..f745f9a 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -684,36 +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;
-
-    /* Expecting 'major.minor.release' format */
-    if (virStrToLong_ui(temp, &temp, 10, &major) < 0 || temp == NULL ||
-        *temp != '.') {
-        goto failure;
-    }
-
-    if (virStrToLong_ui(temp + 1, &temp, 10, &minor) < 0 || temp == NULL ||
-        *temp != '.') {
-        goto failure;
-    }
+    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);
 
-    if (virStrToLong_ui(temp + 1, NULL, 10, &release) < 0) {
-        goto failure;
+        return -1;
     }
 
-    *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/libvirt_private.syms b/src/libvirt_private.syms
index cc943f8..edb23c2 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 7ebc7ae..9caefa1 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 3713a45..a580ff0 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,16 @@ openvzExtractVersionInfo(const char *cmd, int *retversion)
     if (len < 0)
         goto cleanup2;
 
-    if (sscanf(help, "vzctl version %u.%u.%u",
-               &major, &minor, &micro) != 3) {
+    tmp = help;
+
+    /* expected format: vzctl version <major>.<minor>.<micro> */
+    if (! STRPREFIX(tmp, "vzctl version "))
         goto cleanup2;
-    }
 
-    version = (major * 1000 * 1000) + (minor * 1000) + micro;
+    tmp += 14; /* = strlen("vzctl version ") */
+
+    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 70c3f7d..4d434e1 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 835e5d4..08fbf93 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, &micro) != 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 62dc5f1..a669d17 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -2074,6 +2074,43 @@ 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 = (char *)str;
+
+    if (virStrToLong_ui(tmp, &tmp, 10, &major) < 0 || tmp == NULL ||
+        *tmp != '.')
+        return -1;
+
+    if (virStrToLong_ui(tmp + 1, &tmp, 10, &minor) < 0 || tmp == NULL ||
+        *tmp != '.')
+        return -1;
+
+    if (virStrToLong_ui(tmp + 1, &tmp, 10, &micro) < 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 24dfbfc..c256117 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 f7a9b9f..05b075f 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, &micro) == 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 6e1183d..7988601 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,17 +277,17 @@ xenapiGetVersion (virConnectPtr conn, unsigned long *hvVer)
             }
         }
         if (version) {
-            if (sscanf(version, "%ld.%ld.%ld", &major, &minor, &release) != 3) {
-                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);
+            if (virParseVersionString(version, hvVer) < 0)
+                xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR,
+                                          "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;
 }
-- 
1.6.3.3




More information about the libvir-list mailing list