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:
parent
7d72e76228
commit
9f9b17a4f0
88
cutils.c
88
cutils.c
@ -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;
|
||||
}
|
||||
|
@ -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
29
vl.c
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user