[libvirt] [PATCH] esx: Replace scanf with STRSKIP and strtok_r

Matthias Bolte matthias.bolte at googlemail.com
Thu Apr 15 00:34:44 UTC 2010


This also fixes a portability problem with the %a format modifier.
%a is not portable and made esxDomainDumpXML fail at runtime in
MinGW builds.

Pull in strtok_r from gnulib, because MinGW lacks it.
---
 bootstrap.conf       |    1 +
 src/esx/esx_driver.c |   19 +++--------------
 src/esx/esx_util.c   |   53 +++++++++++++++++++++++++------------------------
 src/esx/esx_vi.c     |   50 +++++++++++++++++++++++++++++++++++++++++++++++
 src/esx/esx_vi.h     |   12 +++++++++++
 src/esx/esx_vmx.c    |   16 +++++++++++---
 6 files changed, 106 insertions(+), 45 deletions(-)

diff --git a/bootstrap.conf b/bootstrap.conf
index d807e40..785489b 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -54,6 +54,7 @@ strndup
 strerror
 strptime
 strsep
+strtok_r
 sys_stat
 time_r
 timegm
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index a2fc85c..f22634e 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -60,8 +60,8 @@ esxSupportsLongMode(esxPrivate *priv)
     esxVI_DynamicProperty *dynamicProperty = NULL;
     esxVI_HostCpuIdInfo *hostCpuIdInfoList = NULL;
     esxVI_HostCpuIdInfo *hostCpuIdInfo = NULL;
+    esxVI_ParsedHostCpuIdInfo parsedHostCpuIdInfo;
     char edxLongModeBit = '?';
-    char edxFirstBit = '?';
 
     if (priv->supportsLongMode != esxVI_Boolean_Undefined) {
         return priv->supportsLongMode;
@@ -96,23 +96,12 @@ esxSupportsLongMode(esxPrivate *priv)
             for (hostCpuIdInfo = hostCpuIdInfoList; hostCpuIdInfo != NULL;
                  hostCpuIdInfo = hostCpuIdInfo->_next) {
                 if (hostCpuIdInfo->level->value == -2147483647) { /* 0x80000001 */
-#define _SKIP4 "%*c%*c%*c%*c"
-#define _SKIP12 _SKIP4":"_SKIP4":"_SKIP4
-
-                    /* Expected format: "--X-:----:----:----:----:----:----:----" */
-                    if (sscanf(hostCpuIdInfo->edx,
-                               "%*c%*c%c%*c:"_SKIP12":"_SKIP12":%*c%*c%*c%c",
-                               &edxLongModeBit, &edxFirstBit) != 2) {
-                        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
-                                  _("HostSystem property 'hardware.cpuFeature[].edx' "
-                                    "with value '%s' doesn't have expected format "
-                                    "'----:----:----:----:----:----:----:----'"),
-                                  hostCpuIdInfo->edx);
+                    if (esxVI_ParseHostCpuIdInfo(&parsedHostCpuIdInfo,
+                                                 hostCpuIdInfo) < 0) {
                         goto failure;
                     }
 
-#undef _SKIP4
-#undef _SKIP12
+                    edxLongModeBit = parsedHostCpuIdInfo.edx[29];
 
                     if (edxLongModeBit == '1') {
                         priv->supportsLongMode = esxVI_Boolean_True;
diff --git a/src/esx/esx_util.c b/src/esx/esx_util.c
index 963f52e..91d19e9 100644
--- a/src/esx/esx_util.c
+++ b/src/esx/esx_util.c
@@ -203,6 +203,10 @@ esxUtil_ParseDatastoreRelatedPath(const char *datastoreRelatedPath,
                                   char **directoryName, char **fileName)
 {
     int result = 0;
+    char *copyOfDatastoreRelatedPath = NULL;
+    char *tmp = NULL;
+    char *saveptr = NULL;
+    char *preliminaryDatastoreName = NULL;
     char *directoryAndFileName = NULL;
     char *separator = NULL;
 
@@ -213,37 +217,34 @@ esxUtil_ParseDatastoreRelatedPath(const char *datastoreRelatedPath,
         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) {
+    if (esxVI_String_DeepCopyValue(&copyOfDatastoreRelatedPath,
+                                   datastoreRelatedPath) < 0) {
+        goto failure;
+    }
+
+    /* Expected format: '[<datastore>] <path>' */
+    if ((tmp = STRSKIP(copyOfDatastoreRelatedPath, "[")) == NULL ||
+        (preliminaryDatastoreName = strtok_r(tmp, "]", &saveptr)) == NULL ||
+        (directoryAndFileName = strtok_r(NULL, "", &saveptr)) == NULL) {
         ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                   _("Datastore related path '%s' doesn't have expected format "
                     "'[<datastore>] <path>'"), datastoreRelatedPath);
         goto failure;
     }
 
+    if (esxVI_String_DeepCopyValue(datastoreName,
+                                   preliminaryDatastoreName) < 0) {
+        goto failure;
+    }
+
+    directoryAndFileName += strspn(directoryAndFileName, " ");
+
     /* 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"),
@@ -251,19 +252,19 @@ esxUtil_ParseDatastoreRelatedPath(const char *datastoreRelatedPath,
             goto failure;
         }
 
-        *fileName = strdup(separator);
-
-        if (*fileName == NULL) {
-            virReportOOMError();
+        if (esxVI_String_DeepCopyValue(directoryName,
+                                       directoryAndFileName) < 0 ||
+            esxVI_String_DeepCopyValue(fileName, separator) < 0) {
             goto failure;
         }
     } else {
-        *fileName = directoryAndFileName;
-        directoryAndFileName = NULL;
+        if (esxVI_String_DeepCopyValue(fileName, directoryAndFileName) < 0) {
+            goto failure;
+        }
     }
 
   cleanup:
-    VIR_FREE(directoryAndFileName);
+    VIR_FREE(copyOfDatastoreRelatedPath);
 
     return result;
 
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index 4318ff1..db8c927 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -2886,3 +2886,53 @@ esxVI_WaitForTaskCompletion(esxVI_Context *ctx,
 
     goto cleanup;
 }
+
+
+
+int
+esxVI_ParseHostCpuIdInfo(esxVI_ParsedHostCpuIdInfo *parsedhostCpuIdInfo,
+                         esxVI_HostCpuIdInfo *hostCpuIdInfo)
+{
+    int expectedLength = 39; /* = strlen("----:----:----:----:----:----:----:----"); */
+    char *input[4] = { hostCpuIdInfo->eax, hostCpuIdInfo->ebx,
+                       hostCpuIdInfo->ecx, hostCpuIdInfo->edx };
+    char *output[4] = { parsedhostCpuIdInfo->eax, parsedhostCpuIdInfo->ebx,
+                        parsedhostCpuIdInfo->ecx, parsedhostCpuIdInfo->edx };
+    const char *name[4] = { "eax", "ebx", "ecx", "edx" };
+    int r, i, o;
+
+    memset(parsedhostCpuIdInfo, 0, sizeof (esxVI_ParsedHostCpuIdInfo));
+
+    parsedhostCpuIdInfo->level = hostCpuIdInfo->level->value;
+
+    for (r = 0; r < 4; ++r) {
+        if (strlen(input[r]) != expectedLength) {
+            ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+                         _("HostCpuIdInfo register '%s' has an unexpected length"),
+                         name[r]);
+            goto failure;
+        }
+
+        /* Strip the ':' and invert the "bit" order from 31..0 to 0..31 */
+        for (i = 0, o = 31; i < expectedLength; i += 5, o -= 4) {
+            output[r][o] = input[r][i];
+            output[r][o - 1] = input[r][i + 1];
+            output[r][o - 2] = input[r][i + 2];
+            output[r][o - 3] = input[r][i + 3];
+
+            if (i + 4 < expectedLength && input[r][i + 4] != ':') {
+                ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+                             _("HostCpuIdInfo register '%s' has an unexpected format"),
+                             name[r]);
+                goto failure;
+            }
+        }
+    }
+
+    return 0;
+
+  failure:
+    memset(parsedhostCpuIdInfo, 0, sizeof (esxVI_ParsedHostCpuIdInfo));
+
+    return -1;
+}
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index a8d4cc3..45b83f5 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -43,6 +43,7 @@
 typedef enum _esxVI_APIVersion esxVI_APIVersion;
 typedef enum _esxVI_ProductVersion esxVI_ProductVersion;
 typedef enum _esxVI_Occurrence esxVI_Occurrence;
+typedef struct _esxVI_ParsedHostCpuIdInfo esxVI_ParsedHostCpuIdInfo;
 typedef struct _esxVI_Context esxVI_Context;
 typedef struct _esxVI_Response esxVI_Response;
 typedef struct _esxVI_Enumeration esxVI_Enumeration;
@@ -76,6 +77,14 @@ enum _esxVI_Occurrence {
     esxVI_Occurrence_None
 };
 
+struct _esxVI_ParsedHostCpuIdInfo {
+    int level;
+    char eax[32];
+    char ebx[32];
+    char ecx[32];
+    char edx[32];
+};
+
 
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
@@ -313,4 +322,7 @@ int esxVI_WaitForTaskCompletion(esxVI_Context *ctx,
                                 esxVI_Boolean autoAnswer,
                                 esxVI_TaskInfoState *finalState);
 
+int esxVI_ParseHostCpuIdInfo(esxVI_ParsedHostCpuIdInfo *parsedhostCpuIdInfo,
+                             esxVI_HostCpuIdInfo *hostCpuIdInfo);
+
 #endif /* __ESX_VI_H__ */
diff --git a/src/esx/esx_vmx.c b/src/esx/esx_vmx.c
index c965e00..c2e9be6 100644
--- a/src/esx/esx_vmx.c
+++ b/src/esx/esx_vmx.c
@@ -589,6 +589,9 @@ char *
 esxVMX_AbsolutePathToDatastoreRelatedPath(esxVI_Context *ctx,
                                           const char *absolutePath)
 {
+    char *copyOfAbsolutePath = NULL;
+    char *tmp = NULL;
+    char *saveptr = NULL;
     char *datastoreRelatedPath = NULL;
     char *preliminaryDatastoreName = NULL;
     char *directoryAndFileName = NULL;
@@ -596,8 +599,14 @@ esxVMX_AbsolutePathToDatastoreRelatedPath(esxVI_Context *ctx,
     esxVI_ObjectContent *datastore = NULL;
     const char *datastoreName = NULL;
 
-    if (sscanf(absolutePath, "/vmfs/volumes/%a[^/]/%a[^\n]",
-               &preliminaryDatastoreName, &directoryAndFileName) != 2) {
+    if (esxVI_String_DeepCopyValue(&copyOfAbsolutePath, absolutePath) < 0) {
+        goto failure;
+    }
+
+    /* Expected format: '/vmfs/volumes/<datastore>/<path>' */
+    if ((tmp = STRSKIP(copyOfAbsolutePath, "/vmfs/volumes/")) == NULL ||
+        (preliminaryDatastoreName = strtok_r(tmp, "/", &saveptr)) == NULL ||
+        (directoryAndFileName = strtok_r(NULL, "", &saveptr)) == NULL) {
         ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                   _("Absolute path '%s' doesn't have expected format "
                     "'/vmfs/volumes/<datastore>/<path>'"), absolutePath);
@@ -652,8 +661,7 @@ esxVMX_AbsolutePathToDatastoreRelatedPath(esxVI_Context *ctx,
     /* FIXME: Check if referenced path/file really exists */
 
   cleanup:
-    VIR_FREE(preliminaryDatastoreName);
-    VIR_FREE(directoryAndFileName);
+    VIR_FREE(copyOfAbsolutePath);
     esxVI_ObjectContent_Free(&datastore);
 
     return datastoreRelatedPath;
-- 
1.6.3.3




More information about the libvir-list mailing list