option cutils: Fix and clean up number conversions
-----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJYrzrdAAoJEDhwtADrkYZTjJIP/0pjdtvdCdIq855DSgHO6jdm xM3W1DngCHt78LPXKutqRX8le2tFuY7uXQG2PqTXtirni5WKB9MB4wdOzeucrXvW NIpb8AC1GM0ToOwQvrc8T840QfdGFFE8X2DIAPPYcBivQWAlRi6tqbGY8KwvWFYC vSjUIJbIu8mOUt49Q5LfhaH2UPJlcNlED/oUmDLorz9Rz6E75EHP5pKPrr7Y0JkX 4wjxSE18yM4z0wXwIfRiW5zKDs7JuvHwLSVX75ZwpS5GpWgGsyc4EeyAQb5Xi97s /S3a4SFj/kOvDeuw8uy7BkuPknYF2hHD6XUkoIWr2hiyjatjeAM9USO18N2HwoIg rO3Icw1HADC8Z/RrXjKecaLAA+gKNFGAMgmrYH0GImg6QfC24VQdHNXm3v+i1i27 1p6AnSdtzG26DPk8pJODn2UbxngoeHUy0PPjra7ZEMDK7Igkw8x0oFBL887jPxkd oyBA5S4dOUCYXo86hYjjrhRXrQ7j5oIx45myX8jX6RoQLEq1XrUiVN59t1WXW5Vv EiZc7YB/QSPMZe/q0DiWvif4DH+YLAqD9k7OeQ2HjINBf5sKqIn3lGO0zloL2W+8 mQ9+HLryP4j+PRbtpQavnAYg6Mo7Qzg9y5ZkABAj0fdyPJFZ8ZZ7gH0+atF1CjlP Vvv+VdyWpzKfFam752Hk =o8eA -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/armbru/tags/pull-util-2017-02-23' into staging option cutils: Fix and clean up number conversions # gpg: Signature made Thu 23 Feb 2017 19:41:17 GMT # gpg: using RSA key 0x3870B400EB918653 # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * remotes/armbru/tags/pull-util-2017-02-23: (24 commits) option: Fix checking of sizes for overflow and trailing crap util/cutils: Change qemu_strtosz*() from int64_t to uint64_t util/cutils: Return qemu_strtosz*() error and value separately util/cutils: Let qemu_strtosz*() optionally reject trailing crap qemu-img: Wrap cvtnum() around qemu_strtosz() test-cutils: Drop suffix from test_qemu_strtosz_simple() test-cutils: Use qemu_strtosz() more often util/cutils: Drop QEMU_STRTOSZ_DEFSUFFIX_* macros util/cutils: New qemu_strtosz() util/cutils: Rename qemu_strtosz() to qemu_strtosz_MiB() util/cutils: New qemu_strtosz_metric() test-cutils: Cover qemu_strtosz() around range limits test-cutils: Cover qemu_strtosz() with trailing crap test-cutils: Cover qemu_strtosz() invalid input test-cutils: Add missing qemu_strtosz()... endptr checks option: Fix to reject invalid and overflowing numbers util/cutils: Clean up control flow around qemu_strtol() a bit util/cutils: Clean up variable names around qemu_strtol() util/cutils: Rename qemu_strtoll(), qemu_strtoull() util/cutils: Rewrite documentation of qemu_strtol() & friends ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
						commit
						d7941f4eed
					
				
							
								
								
									
										11
									
								
								hmp.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								hmp.c
									
									
									
									
									
								
							@ -1344,12 +1344,11 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    const char *param = qdict_get_str(qdict, "parameter");
 | 
					    const char *param = qdict_get_str(qdict, "parameter");
 | 
				
			||||||
    const char *valuestr = qdict_get_str(qdict, "value");
 | 
					    const char *valuestr = qdict_get_str(qdict, "value");
 | 
				
			||||||
    int64_t valuebw = 0;
 | 
					    uint64_t valuebw = 0;
 | 
				
			||||||
    long valueint = 0;
 | 
					    long valueint = 0;
 | 
				
			||||||
    char *endp;
 | 
					 | 
				
			||||||
    Error *err = NULL;
 | 
					    Error *err = NULL;
 | 
				
			||||||
    bool use_int_value = false;
 | 
					    bool use_int_value = false;
 | 
				
			||||||
    int i;
 | 
					    int i, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) {
 | 
					    for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) {
 | 
				
			||||||
        if (strcmp(param, MigrationParameter_lookup[i]) == 0) {
 | 
					        if (strcmp(param, MigrationParameter_lookup[i]) == 0) {
 | 
				
			||||||
@ -1385,9 +1384,9 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
 | 
				
			|||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case MIGRATION_PARAMETER_MAX_BANDWIDTH:
 | 
					            case MIGRATION_PARAMETER_MAX_BANDWIDTH:
 | 
				
			||||||
                p.has_max_bandwidth = true;
 | 
					                p.has_max_bandwidth = true;
 | 
				
			||||||
                valuebw = qemu_strtosz(valuestr, &endp);
 | 
					                ret = qemu_strtosz_MiB(valuestr, NULL, &valuebw);
 | 
				
			||||||
                if (valuebw < 0 || (size_t)valuebw != valuebw
 | 
					                if (ret < 0 || valuebw > INT64_MAX
 | 
				
			||||||
                    || *endp != '\0') {
 | 
					                    || (size_t)valuebw != valuebw) {
 | 
				
			||||||
                    error_setg(&err, "Invalid size %s", valuestr);
 | 
					                    error_setg(&err, "Invalid size %s", valuestr);
 | 
				
			||||||
                    goto cleanup;
 | 
					                    goto cleanup;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
				
			|||||||
@ -1267,10 +1267,11 @@ static void ivshmem_realize(PCIDevice *dev, Error **errp)
 | 
				
			|||||||
    if (s->sizearg == NULL) {
 | 
					    if (s->sizearg == NULL) {
 | 
				
			||||||
        s->legacy_size = 4 << 20; /* 4 MB default */
 | 
					        s->legacy_size = 4 << 20; /* 4 MB default */
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        char *end;
 | 
					        int ret;
 | 
				
			||||||
        int64_t size = qemu_strtosz(s->sizearg, &end);
 | 
					        uint64_t size;
 | 
				
			||||||
        if (size < 0 || (size_t)size != size || *end != '\0'
 | 
					
 | 
				
			||||||
            || !is_power_of_2(size)) {
 | 
					        ret = qemu_strtosz_MiB(s->sizearg, NULL, &size);
 | 
				
			||||||
 | 
					        if (ret < 0 || (size_t)size != size || !is_power_of_2(size)) {
 | 
				
			||||||
            error_setg(errp, "Invalid size %s", s->sizearg);
 | 
					            error_setg(errp, "Invalid size %s", s->sizearg);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -130,34 +130,19 @@ int qemu_strtol(const char *nptr, const char **endptr, int base,
 | 
				
			|||||||
                long *result);
 | 
					                long *result);
 | 
				
			||||||
int qemu_strtoul(const char *nptr, const char **endptr, int base,
 | 
					int qemu_strtoul(const char *nptr, const char **endptr, int base,
 | 
				
			||||||
                 unsigned long *result);
 | 
					                 unsigned long *result);
 | 
				
			||||||
int qemu_strtoll(const char *nptr, const char **endptr, int base,
 | 
					int qemu_strtoi64(const char *nptr, const char **endptr, int base,
 | 
				
			||||||
                  int64_t *result);
 | 
					                  int64_t *result);
 | 
				
			||||||
int qemu_strtoull(const char *nptr, const char **endptr, int base,
 | 
					int qemu_strtou64(const char *nptr, const char **endptr, int base,
 | 
				
			||||||
                  uint64_t *result);
 | 
					                  uint64_t *result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int parse_uint(const char *s, unsigned long long *value, char **endptr,
 | 
					int parse_uint(const char *s, unsigned long long *value, char **endptr,
 | 
				
			||||||
               int base);
 | 
					               int base);
 | 
				
			||||||
int parse_uint_full(const char *s, unsigned long long *value, int base);
 | 
					int parse_uint_full(const char *s, unsigned long long *value, int base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					int qemu_strtosz(const char *nptr, char **end, uint64_t *result);
 | 
				
			||||||
 * qemu_strtosz() suffixes used to specify the default treatment of an
 | 
					int qemu_strtosz_MiB(const char *nptr, char **end, uint64_t *result);
 | 
				
			||||||
 * argument passed to qemu_strtosz() without an explicit suffix.
 | 
					int qemu_strtosz_metric(const char *nptr, char **end, uint64_t *result);
 | 
				
			||||||
 * These should be defined using upper case characters in the range
 | 
					
 | 
				
			||||||
 * A-Z, as qemu_strtosz() will use qemu_toupper() on the given argument
 | 
					 | 
				
			||||||
 * prior to comparison.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#define QEMU_STRTOSZ_DEFSUFFIX_EB 'E'
 | 
					 | 
				
			||||||
#define QEMU_STRTOSZ_DEFSUFFIX_PB 'P'
 | 
					 | 
				
			||||||
#define QEMU_STRTOSZ_DEFSUFFIX_TB 'T'
 | 
					 | 
				
			||||||
#define QEMU_STRTOSZ_DEFSUFFIX_GB 'G'
 | 
					 | 
				
			||||||
#define QEMU_STRTOSZ_DEFSUFFIX_MB 'M'
 | 
					 | 
				
			||||||
#define QEMU_STRTOSZ_DEFSUFFIX_KB 'K'
 | 
					 | 
				
			||||||
#define QEMU_STRTOSZ_DEFSUFFIX_B 'B'
 | 
					 | 
				
			||||||
int64_t qemu_strtosz(const char *nptr, char **end);
 | 
					 | 
				
			||||||
int64_t qemu_strtosz_suffix(const char *nptr, char **end,
 | 
					 | 
				
			||||||
                            const char default_suffix);
 | 
					 | 
				
			||||||
int64_t qemu_strtosz_suffix_unit(const char *nptr, char **end,
 | 
					 | 
				
			||||||
                            const char default_suffix, int64_t unit);
 | 
					 | 
				
			||||||
#define K_BYTE     (1ULL << 10)
 | 
					#define K_BYTE     (1ULL << 10)
 | 
				
			||||||
#define M_BYTE     (1ULL << 20)
 | 
					#define M_BYTE     (1ULL << 20)
 | 
				
			||||||
#define G_BYTE     (1ULL << 30)
 | 
					#define G_BYTE     (1ULL << 30)
 | 
				
			||||||
 | 
				
			|||||||
@ -2799,7 +2799,8 @@ static QDict *monitor_parse_arguments(Monitor *mon,
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case 'o':
 | 
					        case 'o':
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                int64_t val;
 | 
					                int ret;
 | 
				
			||||||
 | 
					                uint64_t val;
 | 
				
			||||||
                char *end;
 | 
					                char *end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                while (qemu_isspace(*p)) {
 | 
					                while (qemu_isspace(*p)) {
 | 
				
			||||||
@ -2811,8 +2812,8 @@ static QDict *monitor_parse_arguments(Monitor *mon,
 | 
				
			|||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                val = qemu_strtosz(p, &end);
 | 
					                ret = qemu_strtosz_MiB(p, &end, &val);
 | 
				
			||||||
                if (val < 0) {
 | 
					                if (ret < 0 || val > INT64_MAX) {
 | 
				
			||||||
                    monitor_printf(mon, "invalid size\n");
 | 
					                    monitor_printf(mon, "invalid size\n");
 | 
				
			||||||
                    goto fail;
 | 
					                    goto fail;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
				
			|||||||
@ -481,23 +481,20 @@ opts_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    OptsVisitor *ov = to_ov(v);
 | 
					    OptsVisitor *ov = to_ov(v);
 | 
				
			||||||
    const QemuOpt *opt;
 | 
					    const QemuOpt *opt;
 | 
				
			||||||
    int64_t val;
 | 
					    int err;
 | 
				
			||||||
    char *endptr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    opt = lookup_scalar(ov, name, errp);
 | 
					    opt = lookup_scalar(ov, name, errp);
 | 
				
			||||||
    if (!opt) {
 | 
					    if (!opt) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val = qemu_strtosz_suffix(opt->str ? opt->str : "", &endptr,
 | 
					    err = qemu_strtosz(opt->str ? opt->str : "", NULL, obj);
 | 
				
			||||||
                         QEMU_STRTOSZ_DEFSUFFIX_B);
 | 
					    if (err < 0) {
 | 
				
			||||||
    if (val < 0 || *endptr) {
 | 
					 | 
				
			||||||
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name,
 | 
					        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name,
 | 
				
			||||||
                   "a size value representible as a non-negative int64");
 | 
					                   "a size value");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    *obj = val;
 | 
					 | 
				
			||||||
    processed(ov, name);
 | 
					    processed(ov, name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										62
									
								
								qemu-img.c
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								qemu-img.c
									
									
									
									
									
								
							@ -368,6 +368,21 @@ static int add_old_style_options(const char *fmt, QemuOpts *opts,
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int64_t cvtnum(const char *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int err;
 | 
				
			||||||
 | 
					    uint64_t value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    err = qemu_strtosz(s, NULL, &value);
 | 
				
			||||||
 | 
					    if (err < 0) {
 | 
				
			||||||
 | 
					        return err;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (value > INT64_MAX) {
 | 
				
			||||||
 | 
					        return -ERANGE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int img_create(int argc, char **argv)
 | 
					static int img_create(int argc, char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int c;
 | 
					    int c;
 | 
				
			||||||
@ -461,10 +476,9 @@ static int img_create(int argc, char **argv)
 | 
				
			|||||||
    /* Get image size, if specified */
 | 
					    /* Get image size, if specified */
 | 
				
			||||||
    if (optind < argc) {
 | 
					    if (optind < argc) {
 | 
				
			||||||
        int64_t sval;
 | 
					        int64_t sval;
 | 
				
			||||||
        char *end;
 | 
					
 | 
				
			||||||
        sval = qemu_strtosz_suffix(argv[optind++], &end,
 | 
					        sval = cvtnum(argv[optind++]);
 | 
				
			||||||
                                   QEMU_STRTOSZ_DEFSUFFIX_B);
 | 
					        if (sval < 0) {
 | 
				
			||||||
        if (sval < 0 || *end) {
 | 
					 | 
				
			||||||
            if (sval == -ERANGE) {
 | 
					            if (sval == -ERANGE) {
 | 
				
			||||||
                error_report("Image size must be less than 8 EiB!");
 | 
					                error_report("Image size must be less than 8 EiB!");
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
@ -1864,9 +1878,9 @@ static int img_convert(int argc, char **argv)
 | 
				
			|||||||
        case 'S':
 | 
					        case 'S':
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            int64_t sval;
 | 
					            int64_t sval;
 | 
				
			||||||
            char *end;
 | 
					
 | 
				
			||||||
            sval = qemu_strtosz_suffix(optarg, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
 | 
					            sval = cvtnum(optarg);
 | 
				
			||||||
            if (sval < 0 || *end) {
 | 
					            if (sval < 0) {
 | 
				
			||||||
                error_report("Invalid minimum zero buffer size for sparse output specified");
 | 
					                error_report("Invalid minimum zero buffer size for sparse output specified");
 | 
				
			||||||
                ret = -1;
 | 
					                ret = -1;
 | 
				
			||||||
                goto fail_getopt;
 | 
					                goto fail_getopt;
 | 
				
			||||||
@ -3651,11 +3665,8 @@ static int img_bench(int argc, char **argv)
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case 'o':
 | 
					        case 'o':
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            char *end;
 | 
					            offset = cvtnum(optarg);
 | 
				
			||||||
            errno = 0;
 | 
					            if (offset < 0) {
 | 
				
			||||||
            offset = qemu_strtosz_suffix(optarg, &end,
 | 
					 | 
				
			||||||
                                         QEMU_STRTOSZ_DEFSUFFIX_B);
 | 
					 | 
				
			||||||
            if (offset < 0|| *end) {
 | 
					 | 
				
			||||||
                error_report("Invalid offset specified");
 | 
					                error_report("Invalid offset specified");
 | 
				
			||||||
                return 1;
 | 
					                return 1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -3668,10 +3679,9 @@ static int img_bench(int argc, char **argv)
 | 
				
			|||||||
        case 's':
 | 
					        case 's':
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            int64_t sval;
 | 
					            int64_t sval;
 | 
				
			||||||
            char *end;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            sval = qemu_strtosz_suffix(optarg, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
 | 
					            sval = cvtnum(optarg);
 | 
				
			||||||
            if (sval < 0 || sval > INT_MAX || *end) {
 | 
					            if (sval < 0 || sval > INT_MAX) {
 | 
				
			||||||
                error_report("Invalid buffer size specified");
 | 
					                error_report("Invalid buffer size specified");
 | 
				
			||||||
                return 1;
 | 
					                return 1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -3682,10 +3692,9 @@ static int img_bench(int argc, char **argv)
 | 
				
			|||||||
        case 'S':
 | 
					        case 'S':
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            int64_t sval;
 | 
					            int64_t sval;
 | 
				
			||||||
            char *end;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            sval = qemu_strtosz_suffix(optarg, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
 | 
					            sval = cvtnum(optarg);
 | 
				
			||||||
            if (sval < 0 || sval > INT_MAX || *end) {
 | 
					            if (sval < 0 || sval > INT_MAX) {
 | 
				
			||||||
                error_report("Invalid step size specified");
 | 
					                error_report("Invalid step size specified");
 | 
				
			||||||
                return 1;
 | 
					                return 1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -3844,12 +3853,11 @@ static int img_dd_bs(const char *arg,
 | 
				
			|||||||
                     struct DdIo *in, struct DdIo *out,
 | 
					                     struct DdIo *in, struct DdIo *out,
 | 
				
			||||||
                     struct DdInfo *dd)
 | 
					                     struct DdInfo *dd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char *end;
 | 
					 | 
				
			||||||
    int64_t res;
 | 
					    int64_t res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    res = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
 | 
					    res = cvtnum(arg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (res <= 0 || res > INT_MAX || *end) {
 | 
					    if (res <= 0 || res > INT_MAX) {
 | 
				
			||||||
        error_report("invalid number: '%s'", arg);
 | 
					        error_report("invalid number: '%s'", arg);
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -3862,11 +3870,9 @@ static int img_dd_count(const char *arg,
 | 
				
			|||||||
                        struct DdIo *in, struct DdIo *out,
 | 
					                        struct DdIo *in, struct DdIo *out,
 | 
				
			||||||
                        struct DdInfo *dd)
 | 
					                        struct DdInfo *dd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char *end;
 | 
					    dd->count = cvtnum(arg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dd->count = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
 | 
					    if (dd->count < 0) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (dd->count < 0 || *end) {
 | 
					 | 
				
			||||||
        error_report("invalid number: '%s'", arg);
 | 
					        error_report("invalid number: '%s'", arg);
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -3896,11 +3902,9 @@ static int img_dd_skip(const char *arg,
 | 
				
			|||||||
                       struct DdIo *in, struct DdIo *out,
 | 
					                       struct DdIo *in, struct DdIo *out,
 | 
				
			||||||
                       struct DdInfo *dd)
 | 
					                       struct DdInfo *dd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char *end;
 | 
					    in->offset = cvtnum(arg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    in->offset = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
 | 
					    if (in->offset < 0) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (in->offset < 0 || *end) {
 | 
					 | 
				
			||||||
        error_report("invalid number: '%s'", arg);
 | 
					        error_report("invalid number: '%s'", arg);
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -137,15 +137,17 @@ static char **breakline(char *input, int *count)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static int64_t cvtnum(const char *s)
 | 
					static int64_t cvtnum(const char *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char *end;
 | 
					    int err;
 | 
				
			||||||
    int64_t ret;
 | 
					    uint64_t value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = qemu_strtosz_suffix(s, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
 | 
					    err = qemu_strtosz(s, NULL, &value);
 | 
				
			||||||
    if (*end != '\0') {
 | 
					    if (err < 0) {
 | 
				
			||||||
        /* Detritus at the end of the string */
 | 
					        return err;
 | 
				
			||||||
        return -EINVAL;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return ret;
 | 
					    if (value > INT64_MAX) {
 | 
				
			||||||
 | 
					        return -ERANGE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return value;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void print_cvtnum_err(int64_t rc, const char *arg)
 | 
					static void print_cvtnum_err(int64_t rc, const char *arg)
 | 
				
			||||||
 | 
				
			|||||||
@ -743,7 +743,7 @@ static int qdict_is_list(QDict *maybe_list, Error **errp)
 | 
				
			|||||||
    for (ent = qdict_first(maybe_list); ent != NULL;
 | 
					    for (ent = qdict_first(maybe_list); ent != NULL;
 | 
				
			||||||
         ent = qdict_next(maybe_list, ent)) {
 | 
					         ent = qdict_next(maybe_list, ent)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (qemu_strtoll(ent->key, NULL, 10, &val) == 0) {
 | 
					        if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) {
 | 
				
			||||||
            if (is_list == -1) {
 | 
					            if (is_list == -1) {
 | 
				
			||||||
                is_list = 1;
 | 
					                is_list = 1;
 | 
				
			||||||
            } else if (!is_list) {
 | 
					            } else if (!is_list) {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										34
									
								
								qtest.c
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								qtest.c
									
									
									
									
									
								
							@ -373,8 +373,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
 | 
				
			|||||||
        uint64_t value;
 | 
					        uint64_t value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        g_assert(words[1] && words[2]);
 | 
					        g_assert(words[1] && words[2]);
 | 
				
			||||||
        g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
 | 
					        g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
 | 
				
			||||||
        g_assert(qemu_strtoull(words[2], NULL, 0, &value) == 0);
 | 
					        g_assert(qemu_strtou64(words[2], NULL, 0, &value) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (words[0][5] == 'b') {
 | 
					        if (words[0][5] == 'b') {
 | 
				
			||||||
            uint8_t data = value;
 | 
					            uint8_t data = value;
 | 
				
			||||||
@ -402,7 +402,7 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
 | 
				
			|||||||
        uint64_t value = UINT64_C(-1);
 | 
					        uint64_t value = UINT64_C(-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        g_assert(words[1]);
 | 
					        g_assert(words[1]);
 | 
				
			||||||
        g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
 | 
					        g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (words[0][4] == 'b') {
 | 
					        if (words[0][4] == 'b') {
 | 
				
			||||||
            uint8_t data;
 | 
					            uint8_t data;
 | 
				
			||||||
@ -428,8 +428,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
 | 
				
			|||||||
        char *enc;
 | 
					        char *enc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        g_assert(words[1] && words[2]);
 | 
					        g_assert(words[1] && words[2]);
 | 
				
			||||||
        g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
 | 
					        g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
 | 
				
			||||||
        g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0);
 | 
					        g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0);
 | 
				
			||||||
        /* We'd send garbage to libqtest if len is 0 */
 | 
					        /* We'd send garbage to libqtest if len is 0 */
 | 
				
			||||||
        g_assert(len);
 | 
					        g_assert(len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -452,8 +452,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
 | 
				
			|||||||
        gchar *b64_data;
 | 
					        gchar *b64_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        g_assert(words[1] && words[2]);
 | 
					        g_assert(words[1] && words[2]);
 | 
				
			||||||
        g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
 | 
					        g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
 | 
				
			||||||
        g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0);
 | 
					        g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data = g_malloc(len);
 | 
					        data = g_malloc(len);
 | 
				
			||||||
        cpu_physical_memory_read(addr, data, len);
 | 
					        cpu_physical_memory_read(addr, data, len);
 | 
				
			||||||
@ -469,8 +469,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
 | 
				
			|||||||
        size_t data_len;
 | 
					        size_t data_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        g_assert(words[1] && words[2] && words[3]);
 | 
					        g_assert(words[1] && words[2] && words[3]);
 | 
				
			||||||
        g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
 | 
					        g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
 | 
				
			||||||
        g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0);
 | 
					        g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data_len = strlen(words[3]);
 | 
					        data_len = strlen(words[3]);
 | 
				
			||||||
        if (data_len < 3) {
 | 
					        if (data_len < 3) {
 | 
				
			||||||
@ -498,8 +498,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
 | 
				
			|||||||
        unsigned long pattern;
 | 
					        unsigned long pattern;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        g_assert(words[1] && words[2] && words[3]);
 | 
					        g_assert(words[1] && words[2] && words[3]);
 | 
				
			||||||
        g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
 | 
					        g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
 | 
				
			||||||
        g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0);
 | 
					        g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0);
 | 
				
			||||||
        g_assert(qemu_strtoul(words[3], NULL, 0, &pattern) == 0);
 | 
					        g_assert(qemu_strtoul(words[3], NULL, 0, &pattern) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (len) {
 | 
					        if (len) {
 | 
				
			||||||
@ -518,8 +518,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
 | 
				
			|||||||
        gsize out_len;
 | 
					        gsize out_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        g_assert(words[1] && words[2] && words[3]);
 | 
					        g_assert(words[1] && words[2] && words[3]);
 | 
				
			||||||
        g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
 | 
					        g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
 | 
				
			||||||
        g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0);
 | 
					        g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        data_len = strlen(words[3]);
 | 
					        data_len = strlen(words[3]);
 | 
				
			||||||
        if (data_len < 3) {
 | 
					        if (data_len < 3) {
 | 
				
			||||||
@ -552,9 +552,9 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
 | 
				
			|||||||
        unsigned long nargs, nret;
 | 
					        unsigned long nargs, nret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        g_assert(qemu_strtoul(words[2], NULL, 0, &nargs) == 0);
 | 
					        g_assert(qemu_strtoul(words[2], NULL, 0, &nargs) == 0);
 | 
				
			||||||
        g_assert(qemu_strtoull(words[3], NULL, 0, &args) == 0);
 | 
					        g_assert(qemu_strtou64(words[3], NULL, 0, &args) == 0);
 | 
				
			||||||
        g_assert(qemu_strtoul(words[4], NULL, 0, &nret) == 0);
 | 
					        g_assert(qemu_strtoul(words[4], NULL, 0, &nret) == 0);
 | 
				
			||||||
        g_assert(qemu_strtoull(words[5], NULL, 0, &ret) == 0);
 | 
					        g_assert(qemu_strtou64(words[5], NULL, 0, &ret) == 0);
 | 
				
			||||||
        res = qtest_rtas_call(words[1], nargs, args, nret, ret);
 | 
					        res = qtest_rtas_call(words[1], nargs, args, nret, ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        qtest_send_prefix(chr);
 | 
					        qtest_send_prefix(chr);
 | 
				
			||||||
@ -564,7 +564,7 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
 | 
				
			|||||||
        int64_t ns;
 | 
					        int64_t ns;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (words[1]) {
 | 
					        if (words[1]) {
 | 
				
			||||||
            g_assert(qemu_strtoll(words[1], NULL, 0, &ns) == 0);
 | 
					            g_assert(qemu_strtoi64(words[1], NULL, 0, &ns) == 0);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
 | 
					            ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -576,7 +576,7 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
 | 
				
			|||||||
        int64_t ns;
 | 
					        int64_t ns;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        g_assert(words[1]);
 | 
					        g_assert(words[1]);
 | 
				
			||||||
        g_assert(qemu_strtoll(words[1], NULL, 0, &ns) == 0);
 | 
					        g_assert(qemu_strtoi64(words[1], NULL, 0, &ns) == 0);
 | 
				
			||||||
        qtest_clock_warp(ns);
 | 
					        qtest_clock_warp(ns);
 | 
				
			||||||
        qtest_send_prefix(chr);
 | 
					        qtest_send_prefix(chr);
 | 
				
			||||||
        qtest_sendf(chr, "OK %"PRIi64"\n",
 | 
					        qtest_sendf(chr, "OK %"PRIi64"\n",
 | 
				
			||||||
 | 
				
			|||||||
@ -2033,12 +2033,11 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        /* Special case: */
 | 
					        /* Special case: */
 | 
				
			||||||
        if (!strcmp(name, "tsc-freq")) {
 | 
					        if (!strcmp(name, "tsc-freq")) {
 | 
				
			||||||
            int64_t tsc_freq;
 | 
					            int ret;
 | 
				
			||||||
            char *err;
 | 
					            uint64_t tsc_freq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            tsc_freq = qemu_strtosz_suffix_unit(val, &err,
 | 
					            ret = qemu_strtosz_metric(val, NULL, &tsc_freq);
 | 
				
			||||||
                                           QEMU_STRTOSZ_DEFSUFFIX_B, 1000);
 | 
					            if (ret < 0 || tsc_freq > INT64_MAX) {
 | 
				
			||||||
            if (tsc_freq < 0 || *err) {
 | 
					 | 
				
			||||||
                error_setg(errp, "bad numerical value %s", val);
 | 
					                error_setg(errp, "bad numerical value %s", val);
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -8,6 +8,7 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "qemu/osdep.h"
 | 
					#include "qemu/osdep.h"
 | 
				
			||||||
 | 
					#include "qemu/cutils.h"
 | 
				
			||||||
#include "qapi/error.h"
 | 
					#include "qapi/error.h"
 | 
				
			||||||
#include "qapi/qmp/qstring.h"
 | 
					#include "qapi/qmp/qstring.h"
 | 
				
			||||||
#include "qemu/config-file.h"
 | 
					#include "qemu/config-file.h"
 | 
				
			||||||
@ -29,6 +30,9 @@ static QemuOptsList opts_list_01 = {
 | 
				
			|||||||
        },{
 | 
					        },{
 | 
				
			||||||
            .name = "number1",
 | 
					            .name = "number1",
 | 
				
			||||||
            .type = QEMU_OPT_NUMBER,
 | 
					            .type = QEMU_OPT_NUMBER,
 | 
				
			||||||
 | 
					        },{
 | 
				
			||||||
 | 
					            .name = "number2",
 | 
				
			||||||
 | 
					            .type = QEMU_OPT_NUMBER,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        { /* end of list */ }
 | 
					        { /* end of list */ }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@ -41,15 +45,24 @@ static QemuOptsList opts_list_02 = {
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            .name = "str1",
 | 
					            .name = "str1",
 | 
				
			||||||
            .type = QEMU_OPT_STRING,
 | 
					            .type = QEMU_OPT_STRING,
 | 
				
			||||||
        },{
 | 
					 | 
				
			||||||
            .name = "bool1",
 | 
					 | 
				
			||||||
            .type = QEMU_OPT_BOOL,
 | 
					 | 
				
			||||||
        },{
 | 
					        },{
 | 
				
			||||||
            .name = "str2",
 | 
					            .name = "str2",
 | 
				
			||||||
            .type = QEMU_OPT_STRING,
 | 
					            .type = QEMU_OPT_STRING,
 | 
				
			||||||
 | 
					        },{
 | 
				
			||||||
 | 
					            .name = "bool1",
 | 
				
			||||||
 | 
					            .type = QEMU_OPT_BOOL,
 | 
				
			||||||
 | 
					        },{
 | 
				
			||||||
 | 
					            .name = "bool2",
 | 
				
			||||||
 | 
					            .type = QEMU_OPT_BOOL,
 | 
				
			||||||
        },{
 | 
					        },{
 | 
				
			||||||
            .name = "size1",
 | 
					            .name = "size1",
 | 
				
			||||||
            .type = QEMU_OPT_SIZE,
 | 
					            .type = QEMU_OPT_SIZE,
 | 
				
			||||||
 | 
					        },{
 | 
				
			||||||
 | 
					            .name = "size2",
 | 
				
			||||||
 | 
					            .type = QEMU_OPT_SIZE,
 | 
				
			||||||
 | 
					        },{
 | 
				
			||||||
 | 
					            .name = "size3",
 | 
				
			||||||
 | 
					            .type = QEMU_OPT_SIZE,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        { /* end of list */ }
 | 
					        { /* end of list */ }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@ -57,6 +70,7 @@ static QemuOptsList opts_list_02 = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static QemuOptsList opts_list_03 = {
 | 
					static QemuOptsList opts_list_03 = {
 | 
				
			||||||
    .name = "opts_list_03",
 | 
					    .name = "opts_list_03",
 | 
				
			||||||
 | 
					    .implied_opt_name = "implied",
 | 
				
			||||||
    .head = QTAILQ_HEAD_INITIALIZER(opts_list_03.head),
 | 
					    .head = QTAILQ_HEAD_INITIALIZER(opts_list_03.head),
 | 
				
			||||||
    .desc = {
 | 
					    .desc = {
 | 
				
			||||||
        /* no elements => accept any params */
 | 
					        /* no elements => accept any params */
 | 
				
			||||||
@ -421,6 +435,308 @@ static void test_qemu_opts_set(void)
 | 
				
			|||||||
    g_assert(opts == NULL);
 | 
					    g_assert(opts == NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int opts_count_iter(void *opaque, const char *name, const char *value,
 | 
				
			||||||
 | 
					                           Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    (*(size_t *)opaque)++;
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static size_t opts_count(QemuOpts *opts)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    size_t n = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qemu_opt_foreach(opts, opts_count_iter, &n, NULL);
 | 
				
			||||||
 | 
					    return n;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_opts_parse(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Error *err = NULL;
 | 
				
			||||||
 | 
					    QemuOpts *opts;
 | 
				
			||||||
 | 
					    char long_key[129];
 | 
				
			||||||
 | 
					    char *params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Nothing */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_03, "", false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Empty key */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_03, "=val", false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 1);
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Long key */
 | 
				
			||||||
 | 
					    memset(long_key, 'a', 127);
 | 
				
			||||||
 | 
					    long_key[127] = 'z';
 | 
				
			||||||
 | 
					    long_key[128] = 0;
 | 
				
			||||||
 | 
					    params = g_strdup_printf("%s=v", long_key);
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_03, params + 1, NULL, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 1);
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, long_key + 1), ==, "v");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Overlong key gets truncated */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_03, params, NULL, &error_abort);
 | 
				
			||||||
 | 
					    g_assert(opts_count(opts) == 1);
 | 
				
			||||||
 | 
					    long_key[127] = 0;
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, long_key), ==, "v");
 | 
				
			||||||
 | 
					    g_free(params);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Multiple keys, last one wins */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_03, "a=1,b=2,,x,a=3",
 | 
				
			||||||
 | 
					                           false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 3);
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, "a"), ==, "3");
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, "b"), ==, "2,x");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Except when it doesn't */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_03, "id=foo,id=bar",
 | 
				
			||||||
 | 
					                           false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 0);
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opts_id(opts), ==, "foo");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* TODO Cover low-level access to repeated keys */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Trailing comma is ignored */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_03, "x=y,", false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 1);
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, "y");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Except when it isn't */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_03, ",", false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 1);
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "on");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Duplicate ID */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_03, "x=y,id=foo", false, &err);
 | 
				
			||||||
 | 
					    error_free_or_abort(&err);
 | 
				
			||||||
 | 
					    g_assert(!opts);
 | 
				
			||||||
 | 
					    /* TODO Cover .merge_lists = true */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Buggy ID recognition */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_03, "x=,,id=bar", false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 1);
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opts_id(opts), ==, "bar"); /* BUG */
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, ",id=bar");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Anti-social ID */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_01, "id=666", false, &err);
 | 
				
			||||||
 | 
					    error_free_or_abort(&err);
 | 
				
			||||||
 | 
					    g_assert(!opts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Implied value */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=",
 | 
				
			||||||
 | 
					                           false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 3);
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, "an"), ==, "on");
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off");
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Implied key */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=", true,
 | 
				
			||||||
 | 
					                           &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 3);
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, "an");
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off");
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Implied key with empty value */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_03, ",", true, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 1);
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Implied key with comma value */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_03, ",,,a=1", true, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 2);
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, ",");
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, "a"), ==, "1");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Empty key is not an implied key */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_03, "=val", true, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 1);
 | 
				
			||||||
 | 
					    g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Unknown key */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_01, "nonexistent=", false, &err);
 | 
				
			||||||
 | 
					    error_free_or_abort(&err);
 | 
				
			||||||
 | 
					    g_assert(!opts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qemu_opts_reset(&opts_list_01);
 | 
				
			||||||
 | 
					    qemu_opts_reset(&opts_list_03);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_opts_parse_bool(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Error *err = NULL;
 | 
				
			||||||
 | 
					    QemuOpts *opts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_02, "bool1=on,bool2=off",
 | 
				
			||||||
 | 
					                           false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 2);
 | 
				
			||||||
 | 
					    g_assert(qemu_opt_get_bool(opts, "bool1", false));
 | 
				
			||||||
 | 
					    g_assert(!qemu_opt_get_bool(opts, "bool2", true));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_02, "bool1=offer", false, &err);
 | 
				
			||||||
 | 
					    error_free_or_abort(&err);
 | 
				
			||||||
 | 
					    g_assert(!opts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qemu_opts_reset(&opts_list_02);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_opts_parse_number(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Error *err = NULL;
 | 
				
			||||||
 | 
					    QemuOpts *opts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Lower limit zero */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_01, "number1=0", false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 1);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Upper limit 2^64-1 */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_01,
 | 
				
			||||||
 | 
					                           "number1=18446744073709551615,number2=-1",
 | 
				
			||||||
 | 
					                           false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 2);
 | 
				
			||||||
 | 
					    g_assert_cmphex(qemu_opt_get_number(opts, "number1", 1), ==, UINT64_MAX);
 | 
				
			||||||
 | 
					    g_assert_cmphex(qemu_opt_get_number(opts, "number2", 0), ==, UINT64_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Above upper limit */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_01, "number1=18446744073709551616",
 | 
				
			||||||
 | 
					                           false, &err);
 | 
				
			||||||
 | 
					    error_free_or_abort(&err);
 | 
				
			||||||
 | 
					    g_assert(!opts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Below lower limit */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_01, "number1=-18446744073709551616",
 | 
				
			||||||
 | 
					                           false, &err);
 | 
				
			||||||
 | 
					    error_free_or_abort(&err);
 | 
				
			||||||
 | 
					    g_assert(!opts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Hex and octal */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_01, "number1=0x2a,number2=052",
 | 
				
			||||||
 | 
					                           false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 2);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 42);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(qemu_opt_get_number(opts, "number2", 0), ==, 42);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Invalid */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_01, "number1=", false, &err);
 | 
				
			||||||
 | 
					    error_free_or_abort(&err);
 | 
				
			||||||
 | 
					    g_assert(!opts);
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_01, "number1=eins", false, &err);
 | 
				
			||||||
 | 
					    error_free_or_abort(&err);
 | 
				
			||||||
 | 
					    g_assert(!opts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Leading whitespace */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_01, "number1= \t42",
 | 
				
			||||||
 | 
					                           false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 1);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 42);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Trailing crap */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_01, "number1=3.14", false, &err);
 | 
				
			||||||
 | 
					    error_free_or_abort(&err);
 | 
				
			||||||
 | 
					    g_assert(!opts);
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_01, "number1=08", false, &err);
 | 
				
			||||||
 | 
					    error_free_or_abort(&err);
 | 
				
			||||||
 | 
					    g_assert(!opts);
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_01, "number1=0 ", false, &err);
 | 
				
			||||||
 | 
					    error_free_or_abort(&err);
 | 
				
			||||||
 | 
					    g_assert(!opts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qemu_opts_reset(&opts_list_01);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_opts_parse_size(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Error *err = NULL;
 | 
				
			||||||
 | 
					    QemuOpts *opts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Lower limit zero */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_02, "size1=0", false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 1);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(qemu_opt_get_size(opts, "size1", 1), ==, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Note: precision is 53 bits since we're parsing with strtod() */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Around limit of precision: 2^53-1, 2^53, 2^54 */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_02,
 | 
				
			||||||
 | 
					                           "size1=9007199254740991,"
 | 
				
			||||||
 | 
					                           "size2=9007199254740992,"
 | 
				
			||||||
 | 
					                           "size3=9007199254740993",
 | 
				
			||||||
 | 
					                           false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 3);
 | 
				
			||||||
 | 
					    g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1),
 | 
				
			||||||
 | 
					                     ==, 0x1fffffffffffff);
 | 
				
			||||||
 | 
					    g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1),
 | 
				
			||||||
 | 
					                     ==, 0x20000000000000);
 | 
				
			||||||
 | 
					    g_assert_cmphex(qemu_opt_get_size(opts, "size3", 1),
 | 
				
			||||||
 | 
					                     ==, 0x20000000000000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Close to signed upper limit 0x7ffffffffffffc00 (53 msbs set) */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_02,
 | 
				
			||||||
 | 
					                           "size1=9223372036854774784," /* 7ffffffffffffc00 */
 | 
				
			||||||
 | 
					                           "size2=9223372036854775295", /* 7ffffffffffffdff */
 | 
				
			||||||
 | 
					                           false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 2);
 | 
				
			||||||
 | 
					    g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1),
 | 
				
			||||||
 | 
					                     ==, 0x7ffffffffffffc00);
 | 
				
			||||||
 | 
					    g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1),
 | 
				
			||||||
 | 
					                     ==, 0x7ffffffffffffc00);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Close to actual upper limit 0xfffffffffffff800 (53 msbs set) */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_02,
 | 
				
			||||||
 | 
					                           "size1=18446744073709549568," /* fffffffffffff800 */
 | 
				
			||||||
 | 
					                           "size2=18446744073709550591", /* fffffffffffffbff */
 | 
				
			||||||
 | 
					                           false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 2);
 | 
				
			||||||
 | 
					    g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1),
 | 
				
			||||||
 | 
					                     ==, 0xfffffffffffff800);
 | 
				
			||||||
 | 
					    g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1),
 | 
				
			||||||
 | 
					                     ==, 0xfffffffffffff800);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Beyond limits */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_02, "size1=-1", false, &err);
 | 
				
			||||||
 | 
					    error_free_or_abort(&err);
 | 
				
			||||||
 | 
					    g_assert(!opts);
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_02,
 | 
				
			||||||
 | 
					                           "size1=18446744073709550592", /* fffffffffffffc00 */
 | 
				
			||||||
 | 
					                           false, &err);
 | 
				
			||||||
 | 
					    error_free_or_abort(&err);
 | 
				
			||||||
 | 
					    g_assert(!opts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Suffixes */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_02, "size1=8b,size2=1.5k,size3=2M",
 | 
				
			||||||
 | 
					                           false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 3);
 | 
				
			||||||
 | 
					    g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, 8);
 | 
				
			||||||
 | 
					    g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0), ==, 1536);
 | 
				
			||||||
 | 
					    g_assert_cmphex(qemu_opt_get_size(opts, "size3", 0), ==, 2 * M_BYTE);
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_02, "size1=0.1G,size2=16777215T",
 | 
				
			||||||
 | 
					                           false, &error_abort);
 | 
				
			||||||
 | 
					    g_assert_cmpuint(opts_count(opts), ==, 2);
 | 
				
			||||||
 | 
					    g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, G_BYTE / 10);
 | 
				
			||||||
 | 
					    g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0),
 | 
				
			||||||
 | 
					                     ==, 16777215 * T_BYTE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Beyond limit with suffix */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_02, "size1=16777216T",
 | 
				
			||||||
 | 
					                           false, &err);
 | 
				
			||||||
 | 
					    error_free_or_abort(&err);
 | 
				
			||||||
 | 
					    g_assert(!opts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Trailing crap */
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_02, "size1=16E", false, &err);
 | 
				
			||||||
 | 
					    error_free_or_abort(&err);
 | 
				
			||||||
 | 
					    g_assert(!opts);
 | 
				
			||||||
 | 
					    opts = qemu_opts_parse(&opts_list_02, "size1=16Gi", false, &err);
 | 
				
			||||||
 | 
					    error_free_or_abort(&err);
 | 
				
			||||||
 | 
					    g_assert(!opts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qemu_opts_reset(&opts_list_02);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char *argv[])
 | 
					int main(int argc, char *argv[])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    register_opts();
 | 
					    register_opts();
 | 
				
			||||||
@ -435,6 +751,10 @@ int main(int argc, char *argv[])
 | 
				
			|||||||
    g_test_add_func("/qemu-opts/opt_unset", test_qemu_opt_unset);
 | 
					    g_test_add_func("/qemu-opts/opt_unset", test_qemu_opt_unset);
 | 
				
			||||||
    g_test_add_func("/qemu-opts/opts_reset", test_qemu_opts_reset);
 | 
					    g_test_add_func("/qemu-opts/opts_reset", test_qemu_opts_reset);
 | 
				
			||||||
    g_test_add_func("/qemu-opts/opts_set", test_qemu_opts_set);
 | 
					    g_test_add_func("/qemu-opts/opts_set", test_qemu_opts_set);
 | 
				
			||||||
 | 
					    g_test_add_func("/qemu-opts/opts_parse/general", test_opts_parse);
 | 
				
			||||||
 | 
					    g_test_add_func("/qemu-opts/opts_parse/bool", test_opts_parse_bool);
 | 
				
			||||||
 | 
					    g_test_add_func("/qemu-opts/opts_parse/number", test_opts_parse_number);
 | 
				
			||||||
 | 
					    g_test_add_func("/qemu-opts/opts_parse/size", test_opts_parse_size);
 | 
				
			||||||
    g_test_run();
 | 
					    g_test_run();
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										223
									
								
								util/cutils.c
									
									
									
									
									
								
							
							
						
						
									
										223
									
								
								util/cutils.c
									
									
									
									
									
								
							@ -181,19 +181,19 @@ int fcntl_setfl(int fd, int flag)
 | 
				
			|||||||
static int64_t suffix_mul(char suffix, int64_t unit)
 | 
					static int64_t suffix_mul(char suffix, int64_t unit)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    switch (qemu_toupper(suffix)) {
 | 
					    switch (qemu_toupper(suffix)) {
 | 
				
			||||||
    case QEMU_STRTOSZ_DEFSUFFIX_B:
 | 
					    case 'B':
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    case QEMU_STRTOSZ_DEFSUFFIX_KB:
 | 
					    case 'K':
 | 
				
			||||||
        return unit;
 | 
					        return unit;
 | 
				
			||||||
    case QEMU_STRTOSZ_DEFSUFFIX_MB:
 | 
					    case 'M':
 | 
				
			||||||
        return unit * unit;
 | 
					        return unit * unit;
 | 
				
			||||||
    case QEMU_STRTOSZ_DEFSUFFIX_GB:
 | 
					    case 'G':
 | 
				
			||||||
        return unit * unit * unit;
 | 
					        return unit * unit * unit;
 | 
				
			||||||
    case QEMU_STRTOSZ_DEFSUFFIX_TB:
 | 
					    case 'T':
 | 
				
			||||||
        return unit * unit * unit * unit;
 | 
					        return unit * unit * unit * unit;
 | 
				
			||||||
    case QEMU_STRTOSZ_DEFSUFFIX_PB:
 | 
					    case 'P':
 | 
				
			||||||
        return unit * unit * unit * unit * unit;
 | 
					        return unit * unit * unit * unit * unit;
 | 
				
			||||||
    case QEMU_STRTOSZ_DEFSUFFIX_EB:
 | 
					    case 'E':
 | 
				
			||||||
        return unit * unit * unit * unit * unit * unit;
 | 
					        return unit * unit * unit * unit * unit * unit;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
@ -205,10 +205,11 @@ static int64_t suffix_mul(char suffix, int64_t unit)
 | 
				
			|||||||
 * in *end, if not NULL. Return -ERANGE on overflow, Return -EINVAL on
 | 
					 * in *end, if not NULL. Return -ERANGE on overflow, Return -EINVAL on
 | 
				
			||||||
 * other error.
 | 
					 * other error.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int64_t qemu_strtosz_suffix_unit(const char *nptr, char **end,
 | 
					static int do_strtosz(const char *nptr, char **end,
 | 
				
			||||||
                            const char default_suffix, int64_t unit)
 | 
					                      const char default_suffix, int64_t unit,
 | 
				
			||||||
 | 
					                      uint64_t *result)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int64_t retval = -EINVAL;
 | 
					    int retval;
 | 
				
			||||||
    char *endptr;
 | 
					    char *endptr;
 | 
				
			||||||
    unsigned char c;
 | 
					    unsigned char c;
 | 
				
			||||||
    int mul_required = 0;
 | 
					    int mul_required = 0;
 | 
				
			||||||
@ -217,7 +218,8 @@ int64_t qemu_strtosz_suffix_unit(const char *nptr, char **end,
 | 
				
			|||||||
    errno = 0;
 | 
					    errno = 0;
 | 
				
			||||||
    val = strtod(nptr, &endptr);
 | 
					    val = strtod(nptr, &endptr);
 | 
				
			||||||
    if (isnan(val) || endptr == nptr || errno != 0) {
 | 
					    if (isnan(val) || endptr == nptr || errno != 0) {
 | 
				
			||||||
        goto fail;
 | 
					        retval = -EINVAL;
 | 
				
			||||||
 | 
					        goto out;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fraction = modf(val, &integral);
 | 
					    fraction = modf(val, &integral);
 | 
				
			||||||
    if (fraction != 0) {
 | 
					    if (fraction != 0) {
 | 
				
			||||||
@ -232,181 +234,204 @@ int64_t qemu_strtosz_suffix_unit(const char *nptr, char **end,
 | 
				
			|||||||
        assert(mul >= 0);
 | 
					        assert(mul >= 0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (mul == 1 && mul_required) {
 | 
					    if (mul == 1 && mul_required) {
 | 
				
			||||||
        goto fail;
 | 
					        retval = -EINVAL;
 | 
				
			||||||
 | 
					        goto out;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if ((val * mul >= INT64_MAX) || val < 0) {
 | 
					    /*
 | 
				
			||||||
 | 
					     * Values >= 0xfffffffffffffc00 overflow uint64_t after their trip
 | 
				
			||||||
 | 
					     * through double (53 bits of precision).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if ((val * mul >= 0xfffffffffffffc00) || val < 0) {
 | 
				
			||||||
        retval = -ERANGE;
 | 
					        retval = -ERANGE;
 | 
				
			||||||
        goto fail;
 | 
					        goto out;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    retval = val * mul;
 | 
					    *result = val * mul;
 | 
				
			||||||
 | 
					    retval = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fail:
 | 
					out:
 | 
				
			||||||
    if (end) {
 | 
					    if (end) {
 | 
				
			||||||
        *end = endptr;
 | 
					        *end = endptr;
 | 
				
			||||||
 | 
					    } else if (*endptr) {
 | 
				
			||||||
 | 
					        retval = -EINVAL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return retval;
 | 
					    return retval;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int64_t qemu_strtosz_suffix(const char *nptr, char **end,
 | 
					int qemu_strtosz(const char *nptr, char **end, uint64_t *result)
 | 
				
			||||||
                            const char default_suffix)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return qemu_strtosz_suffix_unit(nptr, end, default_suffix, 1024);
 | 
					    return do_strtosz(nptr, end, 'B', 1024, result);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int64_t qemu_strtosz(const char *nptr, char **end)
 | 
					int qemu_strtosz_MiB(const char *nptr, char **end, uint64_t *result)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return qemu_strtosz_suffix(nptr, end, QEMU_STRTOSZ_DEFSUFFIX_MB);
 | 
					    return do_strtosz(nptr, end, 'M', 1024, result);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int qemu_strtosz_metric(const char *nptr, char **end, uint64_t *result)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return do_strtosz(nptr, end, 'B', 1000, result);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Helper function for qemu_strto*l() functions.
 | 
					 * Helper function for error checking after strtol() and the like
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int check_strtox_error(const char *p, char *endptr, const char **next,
 | 
					static int check_strtox_error(const char *nptr, char *ep,
 | 
				
			||||||
                              int err)
 | 
					                              const char **endptr, int libc_errno)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /* If no conversion was performed, prefer BSD behavior over glibc
 | 
					    if (endptr) {
 | 
				
			||||||
     * behavior.
 | 
					        *endptr = ep;
 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    if (err == 0 && endptr == p) {
 | 
					 | 
				
			||||||
        err = EINVAL;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (!next && *endptr) {
 | 
					
 | 
				
			||||||
 | 
					    /* Turn "no conversion" into an error */
 | 
				
			||||||
 | 
					    if (libc_errno == 0 && ep == nptr) {
 | 
				
			||||||
        return -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (next) {
 | 
					
 | 
				
			||||||
        *next = endptr;
 | 
					    /* Fail when we're expected to consume the string, but didn't */
 | 
				
			||||||
 | 
					    if (!endptr && *ep) {
 | 
				
			||||||
 | 
					        return -EINVAL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return -err;
 | 
					
 | 
				
			||||||
 | 
					    return -libc_errno;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * QEMU wrappers for strtol(), strtoll(), strtoul(), strotull() C functions.
 | 
					 * Convert string @nptr to a long integer, and store it in @result.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Convert ASCII string @nptr to a long integer value
 | 
					 * This is a wrapper around strtol() that is harder to misuse.
 | 
				
			||||||
 * from the given @base. Parameters @nptr, @endptr, @base
 | 
					 * Semantics of @nptr, @endptr, @base match strtol() with differences
 | 
				
			||||||
 * follows same semantics as strtol() C function.
 | 
					 * noted below.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Unlike from strtol() function, if @endptr is not NULL, this
 | 
					 * @nptr may be null, and no conversion is performed then.
 | 
				
			||||||
 * function will return -EINVAL whenever it cannot fully convert
 | 
					 | 
				
			||||||
 * the string in @nptr with given @base to a long. This function returns
 | 
					 | 
				
			||||||
 * the result of the conversion only through the @result parameter.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * If NULL is passed in @endptr, then the whole string in @ntpr
 | 
					 * If no conversion is performed, store @nptr in *@endptr and return
 | 
				
			||||||
 * is a number otherwise it returns -EINVAL.
 | 
					 * -EINVAL.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * RETURN VALUE
 | 
					 * If @endptr is null, and the string isn't fully converted, return
 | 
				
			||||||
 * Unlike from strtol() function, this wrapper returns either
 | 
					 * -EINVAL.  This is the case when the pointer that would be stored in
 | 
				
			||||||
 * -EINVAL or the errno set by strtol() function (e.g -ERANGE).
 | 
					 * a non-null @endptr points to a character other than '\0'.
 | 
				
			||||||
 * If the conversion overflows, -ERANGE is returned, and @result
 | 
					 *
 | 
				
			||||||
 * is set to the max value of the desired type
 | 
					 * If the conversion overflows @result, store LONG_MAX in @result,
 | 
				
			||||||
 * (e.g. LONG_MAX, LLONG_MAX, ULONG_MAX, ULLONG_MAX). If the case
 | 
					 * and return -ERANGE.
 | 
				
			||||||
 * of underflow, -ERANGE is returned, and @result is set to the min
 | 
					 *
 | 
				
			||||||
 * value of the desired type. For strtol(), strtoll(), @result is set to
 | 
					 * If the conversion underflows @result, store LONG_MIN in @result,
 | 
				
			||||||
 * LONG_MIN, LLONG_MIN, respectively, and for strtoul(), strtoull() it
 | 
					 * and return -ERANGE.
 | 
				
			||||||
 * is set to 0.
 | 
					 *
 | 
				
			||||||
 | 
					 * Else store the converted value in @result, and return zero.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int qemu_strtol(const char *nptr, const char **endptr, int base,
 | 
					int qemu_strtol(const char *nptr, const char **endptr, int base,
 | 
				
			||||||
                long *result)
 | 
					                long *result)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char *p;
 | 
					    char *ep;
 | 
				
			||||||
    int err = 0;
 | 
					
 | 
				
			||||||
    if (!nptr) {
 | 
					    if (!nptr) {
 | 
				
			||||||
        if (endptr) {
 | 
					        if (endptr) {
 | 
				
			||||||
            *endptr = nptr;
 | 
					            *endptr = nptr;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        err = -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        errno = 0;
 | 
					 | 
				
			||||||
        *result = strtol(nptr, &p, base);
 | 
					 | 
				
			||||||
        err = check_strtox_error(nptr, p, endptr, errno);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return err;
 | 
					
 | 
				
			||||||
 | 
					    errno = 0;
 | 
				
			||||||
 | 
					    *result = strtol(nptr, &ep, base);
 | 
				
			||||||
 | 
					    return check_strtox_error(nptr, ep, endptr, errno);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Converts ASCII string to an unsigned long integer.
 | 
					 * Convert string @nptr to an unsigned long, and store it in @result.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * If string contains a negative number, value will be converted to
 | 
					 * This is a wrapper around strtoul() that is harder to misuse.
 | 
				
			||||||
 * the unsigned representation of the signed value, unless the original
 | 
					 * Semantics of @nptr, @endptr, @base match strtoul() with differences
 | 
				
			||||||
 * (nonnegated) value would overflow, in this case, it will set @result
 | 
					 * noted below.
 | 
				
			||||||
 * to ULONG_MAX, and return ERANGE.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The same behavior holds, for qemu_strtoull() but sets @result to
 | 
					 * @nptr may be null, and no conversion is performed then.
 | 
				
			||||||
 * ULLONG_MAX instead of ULONG_MAX.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * See qemu_strtol() documentation for more info.
 | 
					 * If no conversion is performed, store @nptr in *@endptr and return
 | 
				
			||||||
 | 
					 * -EINVAL.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If @endptr is null, and the string isn't fully converted, return
 | 
				
			||||||
 | 
					 * -EINVAL.  This is the case when the pointer that would be stored in
 | 
				
			||||||
 | 
					 * a non-null @endptr points to a character other than '\0'.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If the conversion overflows @result, store ULONG_MAX in @result,
 | 
				
			||||||
 | 
					 * and return -ERANGE.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Else store the converted value in @result, and return zero.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note that a number with a leading minus sign gets converted without
 | 
				
			||||||
 | 
					 * the minus sign, checked for overflow (see above), then negated (in
 | 
				
			||||||
 | 
					 * @result's type).  This is exactly how strtoul() works.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int qemu_strtoul(const char *nptr, const char **endptr, int base,
 | 
					int qemu_strtoul(const char *nptr, const char **endptr, int base,
 | 
				
			||||||
                 unsigned long *result)
 | 
					                 unsigned long *result)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char *p;
 | 
					    char *ep;
 | 
				
			||||||
    int err = 0;
 | 
					
 | 
				
			||||||
    if (!nptr) {
 | 
					    if (!nptr) {
 | 
				
			||||||
        if (endptr) {
 | 
					        if (endptr) {
 | 
				
			||||||
            *endptr = nptr;
 | 
					            *endptr = nptr;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        err = -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    } else {
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    errno = 0;
 | 
					    errno = 0;
 | 
				
			||||||
        *result = strtoul(nptr, &p, base);
 | 
					    *result = strtoul(nptr, &ep, base);
 | 
				
			||||||
    /* Windows returns 1 for negative out-of-range values.  */
 | 
					    /* Windows returns 1 for negative out-of-range values.  */
 | 
				
			||||||
    if (errno == ERANGE) {
 | 
					    if (errno == ERANGE) {
 | 
				
			||||||
        *result = -1;
 | 
					        *result = -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
        err = check_strtox_error(nptr, p, endptr, errno);
 | 
					    return check_strtox_error(nptr, ep, endptr, errno);
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return err;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Converts ASCII string to a long long integer.
 | 
					 * Convert string @nptr to an int64_t.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * See qemu_strtol() documentation for more info.
 | 
					 * Works like qemu_strtol(), except it stores INT64_MAX on overflow,
 | 
				
			||||||
 | 
					 * and INT_MIN on underflow.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int qemu_strtoll(const char *nptr, const char **endptr, int base,
 | 
					int qemu_strtoi64(const char *nptr, const char **endptr, int base,
 | 
				
			||||||
                 int64_t *result)
 | 
					                 int64_t *result)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char *p;
 | 
					    char *ep;
 | 
				
			||||||
    int err = 0;
 | 
					
 | 
				
			||||||
    if (!nptr) {
 | 
					    if (!nptr) {
 | 
				
			||||||
        if (endptr) {
 | 
					        if (endptr) {
 | 
				
			||||||
            *endptr = nptr;
 | 
					            *endptr = nptr;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        err = -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        errno = 0;
 | 
					 | 
				
			||||||
        *result = strtoll(nptr, &p, base);
 | 
					 | 
				
			||||||
        err = check_strtox_error(nptr, p, endptr, errno);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return err;
 | 
					
 | 
				
			||||||
 | 
					    errno = 0;
 | 
				
			||||||
 | 
					    /* FIXME This assumes int64_t is long long */
 | 
				
			||||||
 | 
					    *result = strtoll(nptr, &ep, base);
 | 
				
			||||||
 | 
					    return check_strtox_error(nptr, ep, endptr, errno);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Converts ASCII string to an unsigned long long integer.
 | 
					 * Convert string @nptr to an uint64_t.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * See qemu_strtol() documentation for more info.
 | 
					 * Works like qemu_strtoul(), except it stores UINT64_MAX on overflow.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int qemu_strtoull(const char *nptr, const char **endptr, int base,
 | 
					int qemu_strtou64(const char *nptr, const char **endptr, int base,
 | 
				
			||||||
                  uint64_t *result)
 | 
					                  uint64_t *result)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char *p;
 | 
					    char *ep;
 | 
				
			||||||
    int err = 0;
 | 
					
 | 
				
			||||||
    if (!nptr) {
 | 
					    if (!nptr) {
 | 
				
			||||||
        if (endptr) {
 | 
					        if (endptr) {
 | 
				
			||||||
            *endptr = nptr;
 | 
					            *endptr = nptr;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        err = -EINVAL;
 | 
					        return -EINVAL;
 | 
				
			||||||
    } else {
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    errno = 0;
 | 
					    errno = 0;
 | 
				
			||||||
        *result = strtoull(nptr, &p, base);
 | 
					    /* FIXME This assumes uint64_t is unsigned long long */
 | 
				
			||||||
 | 
					    *result = strtoull(nptr, &ep, base);
 | 
				
			||||||
    /* Windows returns 1 for negative out-of-range values.  */
 | 
					    /* Windows returns 1 for negative out-of-range values.  */
 | 
				
			||||||
    if (errno == ERANGE) {
 | 
					    if (errno == ERANGE) {
 | 
				
			||||||
        *result = -1;
 | 
					        *result = -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
        err = check_strtox_error(nptr, p, endptr, errno);
 | 
					    return check_strtox_error(nptr, ep, endptr, errno);
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return err;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 | 
				
			|||||||
@ -183,13 +183,13 @@ void qemu_set_dfilter_ranges(const char *filter_spec, Error **errp)
 | 
				
			|||||||
            goto out;
 | 
					            goto out;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (qemu_strtoull(r, &e, 0, &r1val)
 | 
					        if (qemu_strtou64(r, &e, 0, &r1val)
 | 
				
			||||||
            || e != range_op) {
 | 
					            || e != range_op) {
 | 
				
			||||||
            error_setg(errp, "Invalid number to the left of %.*s",
 | 
					            error_setg(errp, "Invalid number to the left of %.*s",
 | 
				
			||||||
                       (int)(r2 - range_op), range_op);
 | 
					                       (int)(r2 - range_op), range_op);
 | 
				
			||||||
            goto out;
 | 
					            goto out;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (qemu_strtoull(r2, NULL, 0, &r2val)) {
 | 
					        if (qemu_strtou64(r2, NULL, 0, &r2val)) {
 | 
				
			||||||
            error_setg(errp, "Invalid number to the right of %.*s",
 | 
					            error_setg(errp, "Invalid number to the right of %.*s",
 | 
				
			||||||
                       (int)(r2 - range_op), range_op);
 | 
					                       (int)(r2 - range_op), range_op);
 | 
				
			||||||
            goto out;
 | 
					            goto out;
 | 
				
			||||||
 | 
				
			|||||||
@ -128,7 +128,6 @@ int get_param_value(char *buf, int buf_size,
 | 
				
			|||||||
static void parse_option_bool(const char *name, const char *value, bool *ret,
 | 
					static void parse_option_bool(const char *name, const char *value, bool *ret,
 | 
				
			||||||
                              Error **errp)
 | 
					                              Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (value != NULL) {
 | 
					 | 
				
			||||||
    if (!strcmp(value, "on")) {
 | 
					    if (!strcmp(value, "on")) {
 | 
				
			||||||
        *ret = 1;
 | 
					        *ret = 1;
 | 
				
			||||||
    } else if (!strcmp(value, "off")) {
 | 
					    } else if (!strcmp(value, "off")) {
 | 
				
			||||||
@ -137,27 +136,25 @@ static void parse_option_bool(const char *name, const char *value, bool *ret,
 | 
				
			|||||||
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
 | 
					        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
 | 
				
			||||||
                   name, "'on' or 'off'");
 | 
					                   name, "'on' or 'off'");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        *ret = 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void parse_option_number(const char *name, const char *value,
 | 
					static void parse_option_number(const char *name, const char *value,
 | 
				
			||||||
                                uint64_t *ret, Error **errp)
 | 
					                                uint64_t *ret, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char *postfix;
 | 
					 | 
				
			||||||
    uint64_t number;
 | 
					    uint64_t number;
 | 
				
			||||||
 | 
					    int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (value != NULL) {
 | 
					    err = qemu_strtou64(value, NULL, 0, &number);
 | 
				
			||||||
        number = strtoull(value, &postfix, 0);
 | 
					    if (err == -ERANGE) {
 | 
				
			||||||
        if (*postfix != '\0') {
 | 
					        error_setg(errp, "Value '%s' is too large for parameter '%s'",
 | 
				
			||||||
 | 
					                   value, name);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (err) {
 | 
				
			||||||
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number");
 | 
					        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    *ret = number;
 | 
					    *ret = number;
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc,
 | 
					static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc,
 | 
				
			||||||
@ -177,43 +174,24 @@ static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc,
 | 
				
			|||||||
void parse_option_size(const char *name, const char *value,
 | 
					void parse_option_size(const char *name, const char *value,
 | 
				
			||||||
                       uint64_t *ret, Error **errp)
 | 
					                       uint64_t *ret, Error **errp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char *postfix;
 | 
					    uint64_t size;
 | 
				
			||||||
    double sizef;
 | 
					    int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (value != NULL) {
 | 
					    err = qemu_strtosz(value, NULL, &size);
 | 
				
			||||||
        sizef = strtod(value, &postfix);
 | 
					    if (err == -ERANGE) {
 | 
				
			||||||
        if (sizef < 0 || sizef > UINT64_MAX) {
 | 
					        error_setg(errp, "Value '%s' is too large for parameter '%s'",
 | 
				
			||||||
 | 
					                   value, name);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (err) {
 | 
				
			||||||
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name,
 | 
					        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name,
 | 
				
			||||||
                   "a non-negative number below 2^64");
 | 
					                   "a non-negative number below 2^64");
 | 
				
			||||||
 | 
					        error_append_hint(errp, "Optional suffix k, M, G, T, P or E means"
 | 
				
			||||||
 | 
					                          " kilo-, mega-, giga-, tera-, peta-\n"
 | 
				
			||||||
 | 
					                          "and exabytes, respectively.\n");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
        switch (*postfix) {
 | 
					    *ret = size;
 | 
				
			||||||
        case 'T':
 | 
					 | 
				
			||||||
            sizef *= 1024;
 | 
					 | 
				
			||||||
            /* fall through */
 | 
					 | 
				
			||||||
        case 'G':
 | 
					 | 
				
			||||||
            sizef *= 1024;
 | 
					 | 
				
			||||||
            /* fall through */
 | 
					 | 
				
			||||||
        case 'M':
 | 
					 | 
				
			||||||
            sizef *= 1024;
 | 
					 | 
				
			||||||
            /* fall through */
 | 
					 | 
				
			||||||
        case 'K':
 | 
					 | 
				
			||||||
        case 'k':
 | 
					 | 
				
			||||||
            sizef *= 1024;
 | 
					 | 
				
			||||||
            /* fall through */
 | 
					 | 
				
			||||||
        case 'b':
 | 
					 | 
				
			||||||
        case '\0':
 | 
					 | 
				
			||||||
            *ret = (uint64_t) sizef;
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        default:
 | 
					 | 
				
			||||||
            error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a size");
 | 
					 | 
				
			||||||
            error_append_hint(errp, "You may use k, M, G or T suffixes for "
 | 
					 | 
				
			||||||
                    "kilobytes, megabytes, gigabytes and terabytes.\n");
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a size");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool has_help_option(const char *param)
 | 
					bool has_help_option(const char *param)
 | 
				
			||||||
@ -566,6 +544,7 @@ static void opt_set(QemuOpts *opts, const char *name, const char *value,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    opt->desc = desc;
 | 
					    opt->desc = desc;
 | 
				
			||||||
    opt->str = g_strdup(value);
 | 
					    opt->str = g_strdup(value);
 | 
				
			||||||
 | 
					    assert(opt->str);
 | 
				
			||||||
    qemu_opt_parse(opt, &local_err);
 | 
					    qemu_opt_parse(opt, &local_err);
 | 
				
			||||||
    if (local_err) {
 | 
					    if (local_err) {
 | 
				
			||||||
        error_propagate(errp, local_err);
 | 
					        error_propagate(errp, local_err);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user