From 3a7f2fc3b2417dec406f0cc7a300dd072b36f17f Mon Sep 17 00:00:00 2001 From: Matthias Bolte Date: Wed, 14 Apr 2010 00:03:12 +0200 Subject: [PATCH] esx: Replace scanf with STRSKIP and strtok_r This also fixes a portability problem with the %a format modifier. %a is not portable and made esxDomainDumpXML fail at runtime in MinGW builds. --- 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 +++++++++---- 5 files changed, 105 insertions(+), 45 deletions(-) diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index a2fc85cf1f..f22634e73e 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 963f52ea39..91d19e9725 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 '[] '. '%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 . '[^]%]' excludes ']' from the accepted - * characters, otherwise sscanf() wont match what it should. - * - * '%a[^\n]' matches . '[^\n]' excludes '\n' from the accepted - * characters, otherwise sscanf() would only match up to the first space, - * but spaces are valid in . - */ - if (sscanf(datastoreRelatedPath, "[%a[^]%]] %a[^\n]", datastoreName, - &directoryAndFileName) != 2) { + if (esxVI_String_DeepCopyValue(©OfDatastoreRelatedPath, + datastoreRelatedPath) < 0) { + goto failure; + } + + /* Expected format: '[] ' */ + 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 " "'[] '"), datastoreRelatedPath); goto failure; } + if (esxVI_String_DeepCopyValue(datastoreName, + preliminaryDatastoreName) < 0) { + goto failure; + } + + directoryAndFileName += strspn(directoryAndFileName, " "); + /* Split into /, where 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 4318ff174c..37270fea0a 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 (*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 (*parsedHostCpuIdInfo)); + + return -1; +} diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h index a8d4cc3670..a3d9363ce5 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 c965e00179..c2e9be6c20 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(©OfAbsolutePath, absolutePath) < 0) { + goto failure; + } + + /* Expected format: '/vmfs/volumes//' */ + 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//'"), 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; -- GitLab