Introduce strtosz() library function to convert a string to a byte count.

strtosz() returns -1 on error. It now supports human unit formats in
eg. 1.0G, with better error handling.

The following suffixes are supported:
B/b = bytes
K/k = KB
M/m = MB
G/g = GB
T/t = TB

This patch changes -numa and -m input to use strtosz().

Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Jes Sorensen 2010-10-21 17:15:46 +02:00 committed by Anthony Liguori
parent 7d72e76228
commit 9f9b17a4f0
3 changed files with 98 additions and 20 deletions

View File

@ -23,6 +23,7 @@
*/
#include "qemu-common.h"
#include "host-utils.h"
#include <math.h>
void pstrcpy(char *buf, int buf_size, const char *str)
{
@ -283,3 +284,90 @@ int fcntl_setfl(int fd, int flag)
}
#endif
/*
* Convert string to bytes, allowing either B/b for bytes, K/k for KB,
* M/m for MB, G/g for GB or T/t for TB. Default without any postfix
* is MB. End pointer will be returned in *end, if not NULL. A valid
* value must be terminated by whitespace, ',' or '\0'. Return -1 on
* error.
*/
ssize_t strtosz(const char *nptr, char **end)
{
ssize_t retval = -1;
char *endptr, c;
int mul_required = 0;
double val, mul, integral, fraction;
errno = 0;
val = strtod(nptr, &endptr);
if (isnan(val) || endptr == nptr || errno != 0) {
goto fail;
}
integral = modf(val, &fraction);
if (integral != 0) {
mul_required = 1;
}
/*
* Any whitespace character is fine for terminating the number,
* in addition we accept ',' to handle strings where the size is
* part of a multi token argument.
*/
c = *endptr;
if (isspace(c) || c == '\0' || c == ',') {
c = 0;
}
switch (c) {
case 'B':
case 'b':
mul = 1;
if (mul_required) {
goto fail;
}
break;
case 'K':
case 'k':
mul = 1 << 10;
break;
case 0:
if (mul_required) {
goto fail;
}
case 'M':
case 'm':
mul = 1ULL << 20;
break;
case 'G':
case 'g':
mul = 1ULL << 30;
break;
case 'T':
case 't':
mul = 1ULL << 40;
break;
default:
goto fail;
}
/*
* If not terminated by whitespace, ',', or \0, increment endptr
* to point to next character, then check that we are terminated
* by an appropriate separating character, ie. whitespace, ',', or
* \0. If not, we are seeing trailing garbage, thus fail.
*/
if (c != 0) {
endptr++;
if (!isspace(*endptr) && *endptr != ',' && *endptr != 0) {
goto fail;
}
}
if ((val * mul >= ~(size_t)0) || val < 0) {
goto fail;
}
retval = val * mul;
fail:
if (end) {
*end = endptr;
}
return retval;
}

View File

@ -149,6 +149,7 @@ time_t mktimegm(struct tm *tm);
int qemu_fls(int i);
int qemu_fdatasync(int fd);
int fcntl_setfl(int fd, int flag);
ssize_t strtosz(const char *nptr, char **end);
/* path.c */
void init_paths(const char *prefix);

29
vl.c
View File

@ -710,16 +710,13 @@ static void numa_add(const char *optarg)
if (get_param_value(option, 128, "mem", optarg) == 0) {
node_mem[nodenr] = 0;
} else {
value = strtoull(option, &endptr, 0);
switch (*endptr) {
case 0: case 'M': case 'm':
value <<= 20;
break;
case 'G': case 'g':
value <<= 30;
break;
ssize_t sval;
sval = strtosz(option, NULL);
if (sval < 0) {
fprintf(stderr, "qemu: invalid numa mem size: %s\n", optarg);
exit(1);
}
node_mem[nodenr] = value;
node_mem[nodenr] = sval;
}
if (get_param_value(option, 128, "cpus", optarg) == 0) {
node_cpumask[nodenr] = 0;
@ -2139,18 +2136,10 @@ int main(int argc, char **argv, char **envp)
exit(0);
break;
case QEMU_OPTION_m: {
uint64_t value;
char *ptr;
ssize_t value;
value = strtoul(optarg, &ptr, 10);
switch (*ptr) {
case 0: case 'M': case 'm':
value <<= 20;
break;
case 'G': case 'g':
value <<= 30;
break;
default:
value = strtosz(optarg, NULL);
if (value < 0) {
fprintf(stderr, "qemu: invalid ram size: %s\n", optarg);
exit(1);
}