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.
This commit is contained in:
Matthias Bolte 2010-03-30 16:15:13 +02:00
parent ea54570efb
commit 56bac4a221
11 changed files with 78 additions and 68 deletions

View File

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

View File

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

View File

@ -648,6 +648,7 @@ virFilePid;
virFileReadPid;
virFileLinkPointsTo;
virParseNumber;
virParseVersionString;
virPipeReadUntilEOF;
virAsprintf;
virRun;

View File

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

View File

@ -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, &micro) != 3) {
goto cleanup2;
}
tmp = help;
version = (major * 1000 * 1000) + (minor * 1000) + micro;
/* expected format: vzctl version <major>.<minor>.<micro> */
if ((tmp = STRSKIP(tmp, "vzctl version ")) == NULL)
goto cleanup2;
if (virParseVersionString(tmp, &version) < 0)
goto cleanup2;
if (retversion)
*retversion = version;

View File

@ -44,7 +44,7 @@ struct uml_driver {
int privileged;
unsigned int umlVersion;
unsigned long umlVersion;
int nextvmid;
virDomainObjList domains;

View File

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

View File

@ -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, &micro) < 0)
return -1;
*version = 1000000 * major + 1000 * minor + micro;
return 0;
}
/**
* virAsprintf
*

View File

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

View File

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

View File

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