qemu-option.c 30.3 KB
Newer Older
K
Kevin Wolf 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * Commandline option parsing functions
 *
 * Copyright (c) 2003-2008 Fabrice Bellard
 * Copyright (c) 2009 Kevin Wolf <kwolf@redhat.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

P
Peter Maydell 已提交
26
#include "qemu/osdep.h"
K
Kevin Wolf 已提交
27

28
#include "qapi/error.h"
K
Kevin Wolf 已提交
29
#include "qemu-common.h"
30
#include "qemu/error-report.h"
M
Markus Armbruster 已提交
31 32
#include "qapi/qmp/qbool.h"
#include "qapi/qmp/qdict.h"
33
#include "qapi/qmp/qnum.h"
M
Markus Armbruster 已提交
34
#include "qapi/qmp/qstring.h"
35
#include "qapi/qmp/qerror.h"
36
#include "qemu/option_int.h"
37 38 39
#include "qemu/cutils.h"
#include "qemu/id.h"
#include "qemu/help_option.h"
K
Kevin Wolf 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

/*
 * Extracts the name of an option from the parameter string (p points at the
 * first byte of the option name)
 *
 * The option name is delimited by delim (usually , or =) or the string end
 * and is copied into buf. If the option name is longer than buf_size, it is
 * truncated. buf is always zero terminated.
 *
 * The return value is the position of the delimiter/zero byte after the option
 * name in p.
 */
const char *get_opt_name(char *buf, int buf_size, const char *p, char delim)
{
    char *q;

    q = buf;
    while (*p != '\0' && *p != delim) {
        if (q && (q - buf) < buf_size - 1)
            *q++ = *p;
        p++;
    }
    if (q)
        *q = '\0';

    return p;
}

/*
 * Extracts the value of an option from the parameter string p (p points at the
 * first byte of the option value)
 *
 * This function is comparable to get_opt_name with the difference that the
 * delimiter is fixed to be comma which starts a new option. To specify an
 * option value that contains commas, double each comma.
 */
const char *get_opt_value(char *buf, int buf_size, const char *p)
{
    char *q;

    q = buf;
    while (*p != '\0') {
        if (*p == ',') {
            if (*(p + 1) != ',')
                break;
            p++;
        }
        if (q && (q - buf) < buf_size - 1)
            *q++ = *p;
        p++;
    }
    if (q)
        *q = '\0';

    return p;
}

97 98
static void parse_option_bool(const char *name, const char *value, bool *ret,
                              Error **errp)
99
{
100
    if (!strcmp(value, "on")) {
101
        *ret = 1;
102 103 104 105 106
    } else if (!strcmp(value, "off")) {
        *ret = 0;
    } else {
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                   name, "'on' or 'off'");
107 108 109
    }
}

110 111
static void parse_option_number(const char *name, const char *value,
                                uint64_t *ret, Error **errp)
112 113
{
    uint64_t number;
114
    int err;
115

116 117 118 119 120 121 122
    err = qemu_strtou64(value, NULL, 0, &number);
    if (err == -ERANGE) {
        error_setg(errp, "Value '%s' is too large for parameter '%s'",
                   value, name);
        return;
    }
    if (err) {
123
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number");
124
        return;
125
    }
126
    *ret = number;
127 128
}

129 130 131 132 133 134 135 136 137 138 139 140 141 142
static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc,
                                            const char *name)
{
    int i;

    for (i = 0; desc[i].name != NULL; i++) {
        if (strcmp(desc[i].name, name) == 0) {
            return &desc[i];
        }
    }

    return NULL;
}

143 144
void parse_option_size(const char *name, const char *value,
                       uint64_t *ret, Error **errp)
145
{
146 147
    uint64_t size;
    int err;
148

149 150
    err = qemu_strtosz(value, NULL, &size);
    if (err == -ERANGE) {
151
        error_setg(errp, "Value '%s' is out of range for parameter '%s'",
152
                   value, name);
153 154
        return;
    }
155 156 157 158 159 160
    if (err) {
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name,
                   "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");
161
        return;
162
    }
163
    *ret = size;
164 165
}

166 167 168
bool has_help_option(const char *param)
{
    size_t buflen = strlen(param) + 1;
169
    char *buf = g_malloc(buflen);
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
    const char *p = param;
    bool result = false;

    while (*p) {
        p = get_opt_value(buf, buflen, p);
        if (*p) {
            p++;
        }

        if (is_help_option(buf)) {
            result = true;
            goto out;
        }
    }

out:
186
    g_free(buf);
187 188 189 190 191 192
    return result;
}

bool is_valid_option_list(const char *param)
{
    size_t buflen = strlen(param) + 1;
193
    char *buf = g_malloc(buflen);
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
    const char *p = param;
    bool result = true;

    while (*p) {
        p = get_opt_value(buf, buflen, p);
        if (*p && !*++p) {
            result = false;
            goto out;
        }

        if (!*buf || *buf == ',') {
            result = false;
            goto out;
        }
    }

out:
211
    g_free(buf);
212 213 214
    return result;
}

215 216 217 218 219 220 221 222 223 224 225 226 227
void qemu_opts_print_help(QemuOptsList *list)
{
    QemuOptDesc *desc;

    assert(list);
    desc = list->desc;
    printf("Supported options:\n");
    while (desc && desc->name) {
        printf("%-16s %s\n", desc->name,
               desc->help ? desc->help : "No description available");
        desc++;
    }
}
228 229
/* ------------------------------------------------------------------ */

C
Chunyan Liu 已提交
230
QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name)
231 232 233
{
    QemuOpt *opt;

M
Mark McLoughlin 已提交
234
    QTAILQ_FOREACH_REVERSE(opt, &opts->head, QemuOptHead, next) {
235 236 237 238 239 240 241
        if (strcmp(opt->name, name) != 0)
            continue;
        return opt;
    }
    return NULL;
}

242 243 244 245 246 247 248 249
static void qemu_opt_del(QemuOpt *opt)
{
    QTAILQ_REMOVE(&opt->opts->head, opt, next);
    g_free(opt->name);
    g_free(opt->str);
    g_free(opt);
}

250 251 252 253 254 255 256 257 258 259 260 261 262 263
/* qemu_opt_set allows many settings for the same option.
 * This function deletes all settings for an option.
 */
static void qemu_opt_del_all(QemuOpts *opts, const char *name)
{
    QemuOpt *opt, *next_opt;

    QTAILQ_FOREACH_SAFE(opt, &opts->head, next, next_opt) {
        if (!strcmp(opt->name, name)) {
            qemu_opt_del(opt);
        }
    }
}

264 265
const char *qemu_opt_get(QemuOpts *opts, const char *name)
{
266 267 268 269 270
    QemuOpt *opt;

    if (opts == NULL) {
        return NULL;
    }
271

272
    opt = qemu_opt_find(opts, name);
273 274 275 276 277 278
    if (!opt) {
        const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name);
        if (desc && desc->def_value_str) {
            return desc->def_value_str;
        }
    }
279 280 281
    return opt ? opt->str : NULL;
}

282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
void qemu_opt_iter_init(QemuOptsIter *iter, QemuOpts *opts, const char *name)
{
    iter->opts = opts;
    iter->opt = QTAILQ_FIRST(&opts->head);
    iter->name = name;
}

const char *qemu_opt_iter_next(QemuOptsIter *iter)
{
    QemuOpt *ret = iter->opt;
    if (iter->name) {
        while (ret && !g_str_equal(iter->name, ret->name)) {
            ret = QTAILQ_NEXT(ret, next);
        }
    }
    iter->opt = ret ? QTAILQ_NEXT(ret, next) : NULL;
    return ret ? ret->str : NULL;
}

301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
/* Get a known option (or its default) and remove it from the list
 * all in one action. Return a malloced string of the option value.
 * Result must be freed by caller with g_free().
 */
char *qemu_opt_get_del(QemuOpts *opts, const char *name)
{
    QemuOpt *opt;
    const QemuOptDesc *desc;
    char *str = NULL;

    if (opts == NULL) {
        return NULL;
    }

    opt = qemu_opt_find(opts, name);
    if (!opt) {
        desc = find_desc_by_name(opts->list->desc, name);
        if (desc && desc->def_value_str) {
            str = g_strdup(desc->def_value_str);
        }
        return str;
    }
    str = opt->str;
    opt->str = NULL;
    qemu_opt_del_all(opts, name);
    return str;
}

329 330 331 332 333 334 335 336 337 338 339 340
bool qemu_opt_has_help_opt(QemuOpts *opts)
{
    QemuOpt *opt;

    QTAILQ_FOREACH_REVERSE(opt, &opts->head, QemuOptHead, next) {
        if (is_help_option(opt->name)) {
            return true;
        }
    }
    return false;
}

341 342
static bool qemu_opt_get_bool_helper(QemuOpts *opts, const char *name,
                                     bool defval, bool del)
343
{
344
    QemuOpt *opt;
345
    bool ret = defval;
346

347 348 349 350 351
    if (opts == NULL) {
        return ret;
    }

    opt = qemu_opt_find(opts, name);
352 353 354
    if (opt == NULL) {
        const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name);
        if (desc && desc->def_value_str) {
355
            parse_option_bool(name, desc->def_value_str, &ret, &error_abort);
356
        }
357
        return ret;
358
    }
359
    assert(opt->desc && opt->desc->type == QEMU_OPT_BOOL);
360 361 362 363 364
    ret = opt->value.boolean;
    if (del) {
        qemu_opt_del_all(opts, name);
    }
    return ret;
365 366
}

367 368 369 370 371 372 373 374 375 376 377 378
bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval)
{
    return qemu_opt_get_bool_helper(opts, name, defval, false);
}

bool qemu_opt_get_bool_del(QemuOpts *opts, const char *name, bool defval)
{
    return qemu_opt_get_bool_helper(opts, name, defval, true);
}

static uint64_t qemu_opt_get_number_helper(QemuOpts *opts, const char *name,
                                           uint64_t defval, bool del)
379
{
380
    QemuOpt *opt;
381
    uint64_t ret = defval;
382

383 384 385 386 387
    if (opts == NULL) {
        return ret;
    }

    opt = qemu_opt_find(opts, name);
388 389 390
    if (opt == NULL) {
        const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name);
        if (desc && desc->def_value_str) {
391
            parse_option_number(name, desc->def_value_str, &ret, &error_abort);
392
        }
393
        return ret;
394
    }
395
    assert(opt->desc && opt->desc->type == QEMU_OPT_NUMBER);
396 397 398 399 400
    ret = opt->value.uint;
    if (del) {
        qemu_opt_del_all(opts, name);
    }
    return ret;
401 402
}

403 404 405 406 407 408 409 410 411 412 413 414 415
uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval)
{
    return qemu_opt_get_number_helper(opts, name, defval, false);
}

uint64_t qemu_opt_get_number_del(QemuOpts *opts, const char *name,
                                 uint64_t defval)
{
    return qemu_opt_get_number_helper(opts, name, defval, true);
}

static uint64_t qemu_opt_get_size_helper(QemuOpts *opts, const char *name,
                                         uint64_t defval, bool del)
416
{
417
    QemuOpt *opt;
418
    uint64_t ret = defval;
419

420 421 422 423 424
    if (opts == NULL) {
        return ret;
    }

    opt = qemu_opt_find(opts, name);
425 426 427
    if (opt == NULL) {
        const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name);
        if (desc && desc->def_value_str) {
428
            parse_option_size(name, desc->def_value_str, &ret, &error_abort);
429
        }
430
        return ret;
431
    }
432
    assert(opt->desc && opt->desc->type == QEMU_OPT_SIZE);
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
    ret = opt->value.uint;
    if (del) {
        qemu_opt_del_all(opts, name);
    }
    return ret;
}

uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval)
{
    return qemu_opt_get_size_helper(opts, name, defval, false);
}

uint64_t qemu_opt_get_size_del(QemuOpts *opts, const char *name,
                               uint64_t defval)
{
    return qemu_opt_get_size_helper(opts, name, defval, true);
449 450
}

451
static void qemu_opt_parse(QemuOpt *opt, Error **errp)
452 453
{
    if (opt->desc == NULL)
454
        return;
455

456 457 458
    switch (opt->desc->type) {
    case QEMU_OPT_STRING:
        /* nothing */
459
        return;
460
    case QEMU_OPT_BOOL:
461
        parse_option_bool(opt->name, opt->str, &opt->value.boolean, errp);
462
        break;
463
    case QEMU_OPT_NUMBER:
464
        parse_option_number(opt->name, opt->str, &opt->value.uint, errp);
465
        break;
466
    case QEMU_OPT_SIZE:
467
        parse_option_size(opt->name, opt->str, &opt->value.uint, errp);
468
        break;
469 470 471 472 473
    default:
        abort();
    }
}

474 475 476 477 478
static bool opts_accepts_any(const QemuOpts *opts)
{
    return opts->list->desc[0].name == NULL;
}

K
Kevin Wolf 已提交
479 480 481 482 483 484 485 486 487 488 489 490 491 492
int qemu_opt_unset(QemuOpts *opts, const char *name)
{
    QemuOpt *opt = qemu_opt_find(opts, name);

    assert(opts_accepts_any(opts));

    if (opt == NULL) {
        return -1;
    } else {
        qemu_opt_del(opt);
        return 0;
    }
}

493 494 495 496 497 498 499 500 501
static void opt_set(QemuOpts *opts, const char *name, const char *value,
                    bool prepend, Error **errp)
{
    QemuOpt *opt;
    const QemuOptDesc *desc;
    Error *local_err = NULL;

    desc = find_desc_by_name(opts->list->desc, name);
    if (!desc && !opts_accepts_any(opts)) {
502
        error_setg(errp, QERR_INVALID_PARAMETER, name);
503
        return;
504
    }
M
Mark McLoughlin 已提交
505

506 507
    opt = g_malloc0(sizeof(*opt));
    opt->name = g_strdup(name);
M
Mark McLoughlin 已提交
508
    opt->opts = opts;
509 510 511 512 513
    if (prepend) {
        QTAILQ_INSERT_HEAD(&opts->head, opt, next);
    } else {
        QTAILQ_INSERT_TAIL(&opts->head, opt, next);
    }
514
    opt->desc = desc;
515
    opt->str = g_strdup(value);
516
    assert(opt->str);
517
    qemu_opt_parse(opt, &local_err);
518
    if (local_err) {
519
        error_propagate(errp, local_err);
520 521 522 523
        qemu_opt_del(opt);
    }
}

524 525
void qemu_opt_set(QemuOpts *opts, const char *name, const char *value,
                  Error **errp)
526 527 528 529
{
    opt_set(opts, name, value, false, errp);
}

530 531
void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val,
                       Error **errp)
532 533 534 535
{
    QemuOpt *opt;
    const QemuOptDesc *desc = opts->list->desc;

536 537 538
    opt = g_malloc0(sizeof(*opt));
    opt->desc = find_desc_by_name(desc, name);
    if (!opt->desc && !opts_accepts_any(opts)) {
539
        error_setg(errp, QERR_INVALID_PARAMETER, name);
540
        g_free(opt);
541
        return;
542 543 544 545 546
    }

    opt->name = g_strdup(name);
    opt->opts = opts;
    opt->value.boolean = !!val;
547 548
    opt->str = g_strdup(val ? "on" : "off");
    QTAILQ_INSERT_TAIL(&opts->head, opt, next);
549 550
}

551 552
void qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val,
                         Error **errp)
553 554 555 556 557 558 559
{
    QemuOpt *opt;
    const QemuOptDesc *desc = opts->list->desc;

    opt = g_malloc0(sizeof(*opt));
    opt->desc = find_desc_by_name(desc, name);
    if (!opt->desc && !opts_accepts_any(opts)) {
560
        error_setg(errp, QERR_INVALID_PARAMETER, name);
561
        g_free(opt);
562
        return;
563 564 565 566 567 568 569 570 571
    }

    opt->name = g_strdup(name);
    opt->opts = opts;
    opt->value.uint = val;
    opt->str = g_strdup_printf("%" PRId64, val);
    QTAILQ_INSERT_TAIL(&opts->head, opt, next);
}

572
/**
573 574
 * For each member of @opts, call @func(@opaque, name, value, @errp).
 * @func() may store an Error through @errp, but must return non-zero then.
575 576 577
 * When @func() returns non-zero, break the loop and return that value.
 * Return zero when the loop completes.
 */
578 579
int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
                     Error **errp)
G
Gerd Hoffmann 已提交
580 581
{
    QemuOpt *opt;
582
    int rc;
G
Gerd Hoffmann 已提交
583

B
Blue Swirl 已提交
584
    QTAILQ_FOREACH(opt, &opts->head, next) {
585
        rc = func(opaque, opt->name, opt->str, errp);
586 587 588
        if (rc) {
            return rc;
        }
589
        assert(!errp || !*errp);
G
Gerd Hoffmann 已提交
590
    }
591
    return 0;
G
Gerd Hoffmann 已提交
592 593
}

594 595 596 597
QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id)
{
    QemuOpts *opts;

B
Blue Swirl 已提交
598
    QTAILQ_FOREACH(opts, &list->head, next) {
599 600
        if (!opts->id && !id) {
            return opts;
601
        }
602 603
        if (opts->id && id && !strcmp(opts->id, id)) {
            return opts;
604 605 606 607 608
        }
    }
    return NULL;
}

609 610
QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id,
                           int fail_if_exists, Error **errp)
611 612 613 614
{
    QemuOpts *opts = NULL;

    if (id) {
615
        if (!id_wellformed(id)) {
616 617
            error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "id",
                       "an identifier");
618
            error_append_hint(errp, "Identifiers consist of letters, digits, "
619
                              "'-', '.', '_', starting with a letter.\n");
620 621
            return NULL;
        }
622 623
        opts = qemu_opts_find(list, id);
        if (opts != NULL) {
624
            if (fail_if_exists && !list->merge_lists) {
625
                error_setg(errp, "Duplicate ID '%s' for %s", id, list->name);
626 627 628 629 630
                return NULL;
            } else {
                return opts;
            }
        }
631 632 633 634 635
    } else if (list->merge_lists) {
        opts = qemu_opts_find(list, NULL);
        if (opts) {
            return opts;
        }
636
    }
637
    opts = g_malloc0(sizeof(*opts));
638
    opts->id = g_strdup(id);
639
    opts->list = list;
640
    loc_save(&opts->loc);
B
Blue Swirl 已提交
641 642
    QTAILQ_INIT(&opts->head);
    QTAILQ_INSERT_TAIL(&list->head, opts, next);
643 644 645
    return opts;
}

646 647 648 649 650 651 652 653 654
void qemu_opts_reset(QemuOptsList *list)
{
    QemuOpts *opts, *next_opts;

    QTAILQ_FOREACH_SAFE(opts, &list->head, next, next_opts) {
        qemu_opts_del(opts);
    }
}

655 656 657 658 659
void qemu_opts_loc_restore(QemuOpts *opts)
{
    loc_restore(&opts->loc);
}

660 661
void qemu_opts_set(QemuOptsList *list, const char *id,
                   const char *name, const char *value, Error **errp)
662 663
{
    QemuOpts *opts;
664
    Error *local_err = NULL;
665

666
    opts = qemu_opts_create(list, id, 1, &local_err);
667
    if (local_err) {
668 669
        error_propagate(errp, local_err);
        return;
670
    }
671
    qemu_opt_set(opts, name, value, errp);
672 673
}

G
Gerd Hoffmann 已提交
674 675 676 677 678
const char *qemu_opts_id(QemuOpts *opts)
{
    return opts->id;
}

679 680 681 682 683 684
/* The id string will be g_free()d by qemu_opts_del */
void qemu_opts_set_id(QemuOpts *opts, char *id)
{
    opts->id = id;
}

685 686 687 688
void qemu_opts_del(QemuOpts *opts)
{
    QemuOpt *opt;

689 690 691 692
    if (opts == NULL) {
        return;
    }

693
    for (;;) {
B
Blue Swirl 已提交
694
        opt = QTAILQ_FIRST(&opts->head);
695 696 697 698
        if (opt == NULL)
            break;
        qemu_opt_del(opt);
    }
B
Blue Swirl 已提交
699
    QTAILQ_REMOVE(&opts->list->head, opts, next);
700 701
    g_free(opts->id);
    g_free(opts);
702 703
}

704 705 706 707 708 709 710 711 712 713 714 715 716 717
/* print value, escaping any commas in value */
static void escaped_print(const char *value)
{
    const char *ptr;

    for (ptr = value; *ptr; ++ptr) {
        if (*ptr == ',') {
            putchar(',');
        }
        putchar(*ptr);
    }
}

void qemu_opts_print(QemuOpts *opts, const char *separator)
718 719
{
    QemuOpt *opt;
720
    QemuOptDesc *desc = opts->list->desc;
721 722 723 724 725 726
    const char *sep = "";

    if (opts->id) {
        printf("id=%s", opts->id); /* passed id_wellformed -> no commas */
        sep = separator;
    }
727

728 729
    if (desc[0].name == NULL) {
        QTAILQ_FOREACH(opt, &opts->head, next) {
730 731 732
            printf("%s%s=", sep, opt->name);
            escaped_print(opt->str);
            sep = separator;
733 734 735 736 737
        }
        return;
    }
    for (; desc && desc->name; desc++) {
        const char *value;
738
        opt = qemu_opt_find(opts, desc->name);
739 740 741 742 743 744

        value = opt ? opt->str : desc->def_value_str;
        if (!value) {
            continue;
        }
        if (desc->type == QEMU_OPT_STRING) {
745 746
            printf("%s%s=", sep, desc->name);
            escaped_print(value);
747 748
        } else if ((desc->type == QEMU_OPT_SIZE ||
                    desc->type == QEMU_OPT_NUMBER) && opt) {
749
            printf("%s%s=%" PRId64, sep, desc->name, opt->value.uint);
750
        } else {
751
            printf("%s%s=%s", sep, desc->name, value);
752
        }
753
        sep = separator;
754 755 756
    }
}

757 758
static void opts_do_parse(QemuOpts *opts, const char *params,
                          const char *firstname, bool prepend, Error **errp)
759
{
760
    char option[128], value[1024];
761
    const char *p,*pe,*pc;
762
    Error *local_err = NULL;
763

764
    for (p = params; *p != '\0'; p++) {
765 766 767 768 769 770 771 772 773 774 775
        pe = strchr(p, '=');
        pc = strchr(p, ',');
        if (!pe || (pc && pc < pe)) {
            /* found "foo,more" */
            if (p == params && firstname) {
                /* implicitly named first option */
                pstrcpy(option, sizeof(option), firstname);
                p = get_opt_value(value, sizeof(value), p);
            } else {
                /* option without value, probably a flag */
                p = get_opt_name(option, sizeof(option), p, ',');
776
                if (strncmp(option, "no", 2) == 0) {
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
                    memmove(option, option+2, strlen(option+2)+1);
                    pstrcpy(value, sizeof(value), "off");
                } else {
                    pstrcpy(value, sizeof(value), "on");
                }
            }
        } else {
            /* found "foo=bar,more" */
            p = get_opt_name(option, sizeof(option), p, '=');
            if (*p != '=') {
                break;
            }
            p++;
            p = get_opt_value(value, sizeof(value), p);
        }
        if (strcmp(option, "id") != 0) {
            /* store and parse */
794
            opt_set(opts, option, value, prepend, &local_err);
795
            if (local_err) {
796 797
                error_propagate(errp, local_err);
                return;
798 799 800 801 802 803
            }
        }
        if (*p != ',') {
            break;
        }
    }
804 805
}

806 807 808 809 810 811 812 813
/**
 * Store options parsed from @params into @opts.
 * If @firstname is non-null, the first key=value in @params may omit
 * key=, and is treated as if key was @firstname.
 * On error, store an error object through @errp if non-null.
 */
void qemu_opts_do_parse(QemuOpts *opts, const char *params,
                       const char *firstname, Error **errp)
814
{
815
    opts_do_parse(opts, params, firstname, false, errp);
816 817 818
}

static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
819
                            bool permit_abbrev, bool defaults, Error **errp)
820
{
821
    const char *firstname;
822
    char value[1024], *id = NULL;
823 824
    const char *p;
    QemuOpts *opts;
825
    Error *local_err = NULL;
826

827 828 829
    assert(!permit_abbrev || list->implied_opt_name);
    firstname = permit_abbrev ? list->implied_opt_name : NULL;

830 831
    if (strncmp(params, "id=", 3) == 0) {
        get_opt_value(value, sizeof(value), params+3);
J
Jan Kiszka 已提交
832
        id = value;
833 834
    } else if ((p = strstr(params, ",id=")) != NULL) {
        get_opt_value(value, sizeof(value), p+4);
J
Jan Kiszka 已提交
835
        id = value;
836
    }
837 838 839 840 841 842 843 844 845

    /*
     * This code doesn't work for defaults && !list->merge_lists: when
     * params has no id=, and list has an element with !opts->id, it
     * appends a new element instead of returning the existing opts.
     * However, we got no use for this case.  Guard against possible
     * (if unlikely) future misuse:
     */
    assert(!defaults || list->merge_lists);
846
    opts = qemu_opts_create(list, id, !defaults, &local_err);
847
    if (opts == NULL) {
848
        error_propagate(errp, local_err);
849
        return NULL;
850
    }
851

852 853
    opts_do_parse(opts, params, firstname, defaults, &local_err);
    if (local_err) {
854
        error_propagate(errp, local_err);
855 856 857 858
        qemu_opts_del(opts);
        return NULL;
    }

859 860 861
    return opts;
}

862 863 864 865
/**
 * Create a QemuOpts in @list and with options parsed from @params.
 * If @permit_abbrev, the first key=value in @params may omit key=,
 * and is treated as if key was @list->implied_opt_name.
866
 * On error, store an error object through @errp if non-null.
867 868
 * Return the new QemuOpts on success, null pointer on error.
 */
869
QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884
                          bool permit_abbrev, Error **errp)
{
    return opts_parse(list, params, permit_abbrev, false, errp);
}

/**
 * Create a QemuOpts in @list and with options parsed from @params.
 * If @permit_abbrev, the first key=value in @params may omit key=,
 * and is treated as if key was @list->implied_opt_name.
 * Report errors with error_report_err().  This is inappropriate in
 * QMP context.  Do not use this function there!
 * Return the new QemuOpts on success, null pointer on error.
 */
QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
                                  bool permit_abbrev)
885
{
886 887 888 889
    Error *err = NULL;
    QemuOpts *opts;

    opts = opts_parse(list, params, permit_abbrev, false, &err);
890 891
    if (err) {
        error_report_err(err);
892 893
    }
    return opts;
894 895 896 897 898 899 900
}

void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
                            int permit_abbrev)
{
    QemuOpts *opts;

901
    opts = opts_parse(list, params, permit_abbrev, true, NULL);
902 903 904
    assert(opts);
}

905 906 907 908 909
typedef struct OptsFromQDictState {
    QemuOpts *opts;
    Error **errp;
} OptsFromQDictState;

910 911
static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque)
{
912
    OptsFromQDictState *state = opaque;
913
    char buf[32], *tmp = NULL;
914 915
    const char *value;

916
    if (!strcmp(key, "id") || *state->errp) {
917 918 919 920 921 922 923
        return;
    }

    switch (qobject_type(obj)) {
    case QTYPE_QSTRING:
        value = qstring_get_str(qobject_to_qstring(obj));
        break;
924 925 926
    case QTYPE_QNUM:
        tmp = qnum_to_string(qobject_to_qnum(obj));
        value = tmp;
927 928
        break;
    case QTYPE_QBOOL:
B
Blue Swirl 已提交
929
        pstrcpy(buf, sizeof(buf),
E
Eric Blake 已提交
930
                qbool_get_bool(qobject_to_qbool(obj)) ? "on" : "off");
931 932 933 934 935
        value = buf;
        break;
    default:
        return;
    }
936

937
    qemu_opt_set(state->opts, key, value, state->errp);
938
    g_free(tmp);
939 940 941 942
}

/*
 * Create QemuOpts from a QDict.
943 944 945
 * Use value of key "id" as ID if it exists and is a QString.  Only
 * QStrings, QNums and QBools are copied.  Entries with other types
 * are silently ignored.
946
 */
947 948
QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
                               Error **errp)
949
{
950
    OptsFromQDictState state;
951
    Error *local_err = NULL;
952
    QemuOpts *opts;
953

954 955
    opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1,
                            &local_err);
956
    if (local_err) {
957
        error_propagate(errp, local_err);
958
        return NULL;
959
    }
960

961
    assert(opts != NULL);
962 963 964 965

    state.errp = &local_err;
    state.opts = opts;
    qdict_iter(qdict, qemu_opts_from_qdict_1, &state);
966
    if (local_err) {
967 968 969 970 971
        error_propagate(errp, local_err);
        qemu_opts_del(opts);
        return NULL;
    }

972 973 974
    return opts;
}

975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996
/*
 * Adds all QDict entries to the QemuOpts that can be added and removes them
 * from the QDict. When this function returns, the QDict contains only those
 * entries that couldn't be added to the QemuOpts.
 */
void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp)
{
    const QDictEntry *entry, *next;

    entry = qdict_first(qdict);

    while (entry != NULL) {
        Error *local_err = NULL;
        OptsFromQDictState state = {
            .errp = &local_err,
            .opts = opts,
        };

        next = qdict_next(qdict, entry);

        if (find_desc_by_name(opts->list->desc, entry->key)) {
            qemu_opts_from_qdict_1(entry->key, entry->value, &state);
997
            if (local_err) {
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
                error_propagate(errp, local_err);
                return;
            } else {
                qdict_del(qdict, entry->key);
            }
        }

        entry = next;
    }
}

1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
/*
 * Convert from QemuOpts to QDict.
 * The QDict values are of type QString.
 * TODO We'll want to use types appropriate for opt->desc->type, but
 * this is enough for now.
 */
QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
{
    QemuOpt *opt;

    if (!qdict) {
        qdict = qdict_new();
    }
    if (opts->id) {
1023
        qdict_put_str(qdict, "id", opts->id);
1024 1025
    }
    QTAILQ_FOREACH(opt, &opts->head, next) {
1026
        qdict_put_str(qdict, opt->name, opt->str);
1027 1028 1029 1030
    }
    return qdict;
}

1031 1032 1033
/* Validate parsed opts against descriptions where no
 * descriptions were provided in the QemuOptsList.
 */
1034
void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp)
1035 1036
{
    QemuOpt *opt;
1037
    Error *local_err = NULL;
1038

1039
    assert(opts_accepts_any(opts));
1040 1041

    QTAILQ_FOREACH(opt, &opts->head, next) {
1042 1043
        opt->desc = find_desc_by_name(desc, opt->name);
        if (!opt->desc) {
1044
            error_setg(errp, QERR_INVALID_PARAMETER, opt->name);
1045
            return;
1046 1047
        }

1048
        qemu_opt_parse(opt, &local_err);
1049
        if (local_err) {
1050 1051
            error_propagate(errp, local_err);
            return;
1052 1053 1054 1055
        }
    }
}

1056
/**
1057
 * For each member of @list, call @func(@opaque, member, @errp).
1058
 * Call it with the current location temporarily set to the member's.
1059
 * @func() may store an Error through @errp, but must return non-zero then.
1060 1061 1062 1063
 * When @func() returns non-zero, break the loop and return that value.
 * Return zero when the loop completes.
 */
int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func,
1064
                      void *opaque, Error **errp)
1065
{
1066
    Location loc;
1067
    QemuOpts *opts;
1068
    int rc = 0;
1069

1070
    loc_push_none(&loc);
B
Blue Swirl 已提交
1071
    QTAILQ_FOREACH(opts, &list->head, next) {
1072
        loc_restore(&opts->loc);
1073
        rc = func(opaque, opts, errp);
1074
        if (rc) {
1075
            break;
1076
        }
1077
        assert(!errp || !*errp);
1078
    }
1079
    loc_pop(&loc);
1080
    return rc;
1081
}
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104

static size_t count_opts_list(QemuOptsList *list)
{
    QemuOptDesc *desc = NULL;
    size_t num_opts = 0;

    if (!list) {
        return 0;
    }

    desc = list->desc;
    while (desc && desc->name) {
        num_opts++;
        desc++;
    }

    return num_opts;
}

void qemu_opts_free(QemuOptsList *list)
{
    g_free(list);
}
1105

C
Chunyan Liu 已提交
1106 1107
/* Realloc dst option list and append options from an option list (list)
 * to it. dst could be NULL or a malloced list.
1108 1109
 * The lifetime of dst must be shorter than the input list because the
 * QemuOptDesc->name, ->help, and ->def_value_str strings are shared.
1110 1111
 */
QemuOptsList *qemu_opts_append(QemuOptsList *dst,
C
Chunyan Liu 已提交
1112
                               QemuOptsList *list)
1113 1114 1115 1116
{
    size_t num_opts, num_dst_opts;
    QemuOptDesc *desc;
    bool need_init = false;
1117
    bool need_head_update;
1118

C
Chunyan Liu 已提交
1119
    if (!list) {
1120 1121 1122 1123 1124 1125 1126 1127
        return dst;
    }

    /* If dst is NULL, after realloc, some area of dst should be initialized
     * before adding options to it.
     */
    if (!dst) {
        need_init = true;
1128 1129 1130 1131 1132 1133
        need_head_update = true;
    } else {
        /* Moreover, even if dst is not NULL, the realloc may move it to a
         * different address in which case we may get a stale tail pointer
         * in dst->head. */
        need_head_update = QTAILQ_EMPTY(&dst->head);
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145
    }

    num_opts = count_opts_list(dst);
    num_dst_opts = num_opts;
    num_opts += count_opts_list(list);
    dst = g_realloc(dst, sizeof(QemuOptsList) +
                    (num_opts + 1) * sizeof(QemuOptDesc));
    if (need_init) {
        dst->name = NULL;
        dst->implied_opt_name = NULL;
        dst->merge_lists = false;
    }
1146 1147 1148
    if (need_head_update) {
        QTAILQ_INIT(&dst->head);
    }
1149 1150 1151 1152 1153 1154 1155
    dst->desc[num_dst_opts].name = NULL;

    /* append list->desc to dst->desc */
    if (list) {
        desc = list->desc;
        while (desc && desc->name) {
            if (find_desc_by_name(dst->desc, desc->name) == NULL) {
1156
                dst->desc[num_dst_opts++] = *desc;
1157 1158 1159 1160 1161 1162 1163 1164
                dst->desc[num_dst_opts].name = NULL;
            }
            desc++;
        }
    }

    return dst;
}