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.
This commit is contained in:
Matthias Bolte 2010-04-14 00:03:12 +02:00
parent 7ca6a0996d
commit 3a7f2fc3b2
5 changed files with 105 additions and 45 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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;