qemu

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

26
#include "qemu/osdep.h"
27

28
#include "qapi/error.h"
29
#include "qemu/error-report.h"
30
#include "qapi/qmp/qbool.h"
31
#include "qapi/qmp/qdict.h"
32
#include "qapi/qmp/qnum.h"
33
#include "qapi/qmp/qstring.h"
34
#include "qapi/qmp/qerror.h"
35
#include "qemu/option_int.h"
36
#include "qemu/cutils.h"
37
#include "qemu/id.h"
38
#include "qemu/help_option.h"
39

40
/*
41
 * Extracts the name of an option from the parameter string (@p points at the
42
 * first byte of the option name)
43
 *
44
 * The option name is @len characters long and is copied into @option. The
45
 * caller is responsible for free'ing @option when no longer required.
46
 *
47
 * The return value is the position of the delimiter/zero byte after the option
48
 * name in @p.
49
 */
50
static const char *get_opt_name(const char *p, char **option, size_t len)
51
{
52
    *option = g_strndup(p, len);
53
    return p + len;
54
}
55

56
/*
57
 * Extracts the value of an option from the parameter string p (p points at the
58
 * first byte of the option value)
59
 *
60
 * This function is comparable to get_opt_name with the difference that the
61
 * delimiter is fixed to be comma which starts a new option. To specify an
62
 * option value that contains commas, double each comma.
63
 */
64
const char *get_opt_value(const char *p, char **value)
65
{
66
    size_t capacity = 0, length;
67
    const char *offset;
68

69
    *value = NULL;
70
    while (1) {
71
        offset = qemu_strchrnul(p, ',');
72
        length = offset - p;
73
        if (*offset != '\0' && *(offset + 1) == ',') {
74
            length++;
75
        }
76
        *value = g_renew(char, *value, capacity + length + 1);
77
        strncpy(*value + capacity, p, length);
78
        (*value)[capacity + length] = '\0';
79
        capacity += length;
80
        if (*offset == '\0' ||
81
            *(offset + 1) != ',') {
82
            break;
83
        }
84

85
        p += (offset - p) + 2;
86
    }
87

88
    return offset;
89
}
90

91
static bool parse_option_number(const char *name, const char *value,
92
                                uint64_t *ret, Error **errp)
93
{
94
    uint64_t number;
95
    int err;
96

97
    err = qemu_strtou64(value, NULL, 0, &number);
98
    if (err == -ERANGE) {
99
        error_setg(errp, "Value '%s' is too large for parameter '%s'",
100
                   value, name);
101
        return false;
102
    }
103
    if (err) {
104
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number");
105
        return false;
106
    }
107
    *ret = number;
108
    return true;
109
}
110

111
static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc,
112
                                            const char *name)
113
{
114
    int i;
115

116
    for (i = 0; desc[i].name != NULL; i++) {
117
        if (strcmp(desc[i].name, name) == 0) {
118
            return &desc[i];
119
        }
120
    }
121

122
    return NULL;
123
}
124

125
static const char *find_default_by_name(QemuOpts *opts, const char *name)
126
{
127
    const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name);
128

129
    return desc ? desc->def_value_str : NULL;
130
}
131

132
bool parse_option_size(const char *name, const char *value,
133
                       uint64_t *ret, Error **errp)
134
{
135
    uint64_t size;
136
    int err;
137

138
    err = qemu_strtosz(value, NULL, &size);
139
    if (err == -ERANGE) {
140
        error_setg(errp, "Value '%s' is out of range for parameter '%s'",
141
                   value, name);
142
        return false;
143
    }
144
    if (err) {
145
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name,
146
                   "a non-negative number below 2^64");
147
        error_append_hint(errp, "Optional suffix k, M, G, T, P or E means"
148
                          " kilo-, mega-, giga-, tera-, peta-\n"
149
                          "and exabytes, respectively.\n");
150
        return false;
151
    }
152
    *ret = size;
153
    return true;
154
}
155

156
static const char *opt_type_to_string(enum QemuOptType type)
157
{
158
    switch (type) {
159
    case QEMU_OPT_STRING:
160
        return "str";
161
    case QEMU_OPT_BOOL:
162
        return "bool (on/off)";
163
    case QEMU_OPT_NUMBER:
164
        return "num";
165
    case QEMU_OPT_SIZE:
166
        return "size";
167
    }
168

169
    g_assert_not_reached();
170
}
171

172
/**
173
 * Print the list of options available in the given list.  If
174
 * @print_caption is true, a caption (including the list name, if it
175
 * exists) is printed.  The options itself will be indented, so
176
 * @print_caption should only be set to false if the caller prints its
177
 * own custom caption (so that the indentation makes sense).
178
 */
179
void qemu_opts_print_help(QemuOptsList *list, bool print_caption)
180
{
181
    QemuOptDesc *desc;
182
    int i;
183
    GPtrArray *array = g_ptr_array_new();
184

185
    assert(list);
186
    desc = list->desc;
187
    while (desc && desc->name) {
188
        GString *str = g_string_new(NULL);
189
        g_string_append_printf(str, "  %s=<%s>", desc->name,
190
                               opt_type_to_string(desc->type));
191
        if (desc->help) {
192
            if (str->len < 24) {
193
                g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
194
            }
195
            g_string_append_printf(str, " - %s", desc->help);
196
        }
197
        g_ptr_array_add(array, g_string_free(str, false));
198
        desc++;
199
    }
200

201
    g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
202
    if (print_caption && array->len > 0) {
203
        if (list->name) {
204
            printf("%s options:\n", list->name);
205
        } else {
206
            printf("Options:\n");
207
        }
208
    } else if (array->len == 0) {
209
        if (list->name) {
210
            printf("There are no options for %s.\n", list->name);
211
        } else {
212
            printf("No options available.\n");
213
        }
214
    }
215
    for (i = 0; i < array->len; i++) {
216
        printf("%s\n", (char *)array->pdata[i]);
217
    }
218
    g_ptr_array_set_free_func(array, g_free);
219
    g_ptr_array_free(array, true);
220

221
}
222
/* ------------------------------------------------------------------ */
223

224
QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name)
225
{
226
    QemuOpt *opt;
227

228
    QTAILQ_FOREACH_REVERSE(opt, &opts->head, next) {
229
        if (strcmp(opt->name, name) != 0)
230
            continue;
231
        return opt;
232
    }
233
    return NULL;
234
}
235

236
static void qemu_opt_del(QemuOpt *opt)
237
{
238
    QTAILQ_REMOVE(&opt->opts->head, opt, next);
239
    g_free(opt->name);
240
    g_free(opt->str);
241
    g_free(opt);
242
}
243

244
/* qemu_opt_set allows many settings for the same option.
245
 * This function deletes all settings for an option.
246
 */
247
static void qemu_opt_del_all(QemuOpts *opts, const char *name)
248
{
249
    QemuOpt *opt, *next_opt;
250

251
    QTAILQ_FOREACH_SAFE(opt, &opts->head, next, next_opt) {
252
        if (!strcmp(opt->name, name)) {
253
            qemu_opt_del(opt);
254
        }
255
    }
256
}
257

258
const char *qemu_opt_get(QemuOpts *opts, const char *name)
259
{
260
    QemuOpt *opt;
261

262
    if (opts == NULL) {
263
        return NULL;
264
    }
265

266
    opt = qemu_opt_find(opts, name);
267
    if (!opt) {
268
        return find_default_by_name(opts, name);
269
    }
270

271
    return opt->str;
272
}
273

274
void qemu_opt_iter_init(QemuOptsIter *iter, QemuOpts *opts, const char *name)
275
{
276
    iter->opts = opts;
277
    iter->opt = QTAILQ_FIRST(&opts->head);
278
    iter->name = name;
279
}
280

281
const char *qemu_opt_iter_next(QemuOptsIter *iter)
282
{
283
    QemuOpt *ret = iter->opt;
284
    if (iter->name) {
285
        while (ret && !g_str_equal(iter->name, ret->name)) {
286
            ret = QTAILQ_NEXT(ret, next);
287
        }
288
    }
289
    iter->opt = ret ? QTAILQ_NEXT(ret, next) : NULL;
290
    return ret ? ret->str : NULL;
291
}
292

293
/* Get a known option (or its default) and remove it from the list
294
 * all in one action. Return a malloced string of the option value.
295
 * Result must be freed by caller with g_free().
296
 */
297
char *qemu_opt_get_del(QemuOpts *opts, const char *name)
298
{
299
    QemuOpt *opt;
300
    char *str;
301

302
    if (opts == NULL) {
303
        return NULL;
304
    }
305

306
    opt = qemu_opt_find(opts, name);
307
    if (!opt) {
308
        return g_strdup(find_default_by_name(opts, name));
309
    }
310
    str = opt->str;
311
    opt->str = NULL;
312
    qemu_opt_del_all(opts, name);
313
    return str;
314
}
315

316
bool qemu_opt_has_help_opt(QemuOpts *opts)
317
{
318
    QemuOpt *opt;
319

320
    QTAILQ_FOREACH_REVERSE(opt, &opts->head, next) {
321
        if (is_help_option(opt->name)) {
322
            return true;
323
        }
324
    }
325
    return false;
326
}
327

328
static bool qemu_opt_get_bool_helper(QemuOpts *opts, const char *name,
329
                                     bool defval, bool del)
330
{
331
    QemuOpt *opt;
332
    const char *def_val;
333
    bool ret = defval;
334

335
    if (opts == NULL) {
336
        return ret;
337
    }
338

339
    opt = qemu_opt_find(opts, name);
340
    if (opt == NULL) {
341
        def_val = find_default_by_name(opts, name);
342
        if (def_val) {
343
            qapi_bool_parse(name, def_val, &ret, &error_abort);
344
        }
345
        return ret;
346
    }
347
    assert(opt->desc && opt->desc->type == QEMU_OPT_BOOL);
348
    ret = opt->value.boolean;
349
    if (del) {
350
        qemu_opt_del_all(opts, name);
351
    }
352
    return ret;
353
}
354

355
bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval)
356
{
357
    return qemu_opt_get_bool_helper(opts, name, defval, false);
358
}
359

360
bool qemu_opt_get_bool_del(QemuOpts *opts, const char *name, bool defval)
361
{
362
    return qemu_opt_get_bool_helper(opts, name, defval, true);
363
}
364

365
static uint64_t qemu_opt_get_number_helper(QemuOpts *opts, const char *name,
366
                                           uint64_t defval, bool del)
367
{
368
    QemuOpt *opt;
369
    const char *def_val;
370
    uint64_t ret = defval;
371

372
    if (opts == NULL) {
373
        return ret;
374
    }
375

376
    opt = qemu_opt_find(opts, name);
377
    if (opt == NULL) {
378
        def_val = find_default_by_name(opts, name);
379
        if (def_val) {
380
            parse_option_number(name, def_val, &ret, &error_abort);
381
        }
382
        return ret;
383
    }
384
    assert(opt->desc && opt->desc->type == QEMU_OPT_NUMBER);
385
    ret = opt->value.uint;
386
    if (del) {
387
        qemu_opt_del_all(opts, name);
388
    }
389
    return ret;
390
}
391

392
uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval)
393
{
394
    return qemu_opt_get_number_helper(opts, name, defval, false);
395
}
396

397
uint64_t qemu_opt_get_number_del(QemuOpts *opts, const char *name,
398
                                 uint64_t defval)
399
{
400
    return qemu_opt_get_number_helper(opts, name, defval, true);
401
}
402

403
static uint64_t qemu_opt_get_size_helper(QemuOpts *opts, const char *name,
404
                                         uint64_t defval, bool del)
405
{
406
    QemuOpt *opt;
407
    const char *def_val;
408
    uint64_t ret = defval;
409

410
    if (opts == NULL) {
411
        return ret;
412
    }
413

414
    opt = qemu_opt_find(opts, name);
415
    if (opt == NULL) {
416
        def_val = find_default_by_name(opts, name);
417
        if (def_val) {
418
            parse_option_size(name, def_val, &ret, &error_abort);
419
        }
420
        return ret;
421
    }
422
    assert(opt->desc && opt->desc->type == QEMU_OPT_SIZE);
423
    ret = opt->value.uint;
424
    if (del) {
425
        qemu_opt_del_all(opts, name);
426
    }
427
    return ret;
428
}
429

430
uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval)
431
{
432
    return qemu_opt_get_size_helper(opts, name, defval, false);
433
}
434

435
uint64_t qemu_opt_get_size_del(QemuOpts *opts, const char *name,
436
                               uint64_t defval)
437
{
438
    return qemu_opt_get_size_helper(opts, name, defval, true);
439
}
440

441
static bool qemu_opt_parse(QemuOpt *opt, Error **errp)
442
{
443
    if (opt->desc == NULL)
444
        return true;
445

446
    switch (opt->desc->type) {
447
    case QEMU_OPT_STRING:
448
        /* nothing */
449
        return true;
450
    case QEMU_OPT_BOOL:
451
        return qapi_bool_parse(opt->name, opt->str, &opt->value.boolean, errp);
452
    case QEMU_OPT_NUMBER:
453
        return parse_option_number(opt->name, opt->str, &opt->value.uint,
454
                                   errp);
455
    case QEMU_OPT_SIZE:
456
        return parse_option_size(opt->name, opt->str, &opt->value.uint,
457
                                 errp);
458
    default:
459
        abort();
460
    }
461
}
462

463
static bool opts_accepts_any(const QemuOptsList *list)
464
{
465
    return list->desc[0].name == NULL;
466
}
467

468
int qemu_opt_unset(QemuOpts *opts, const char *name)
469
{
470
    QemuOpt *opt = qemu_opt_find(opts, name);
471

472
    assert(opts_accepts_any(opts->list));
473

474
    if (opt == NULL) {
475
        return -1;
476
    } else {
477
        qemu_opt_del(opt);
478
        return 0;
479
    }
480
}
481

482
static QemuOpt *opt_create(QemuOpts *opts, const char *name, char *value)
483
{
484
    QemuOpt *opt = g_malloc0(sizeof(*opt));
485

486
    opt->name = g_strdup(name);
487
    opt->str = value;
488
    opt->opts = opts;
489
    QTAILQ_INSERT_TAIL(&opts->head, opt, next);
490

491
    return opt;
492
}
493

494
static bool opt_validate(QemuOpt *opt, Error **errp)
495
{
496
    const QemuOptDesc *desc;
497
    const QemuOptsList *list = opt->opts->list;
498

499
    desc = find_desc_by_name(list->desc, opt->name);
500
    if (!desc && !opts_accepts_any(list)) {
501
        error_setg(errp, "Invalid parameter '%s'", opt->name);
502
        return false;
503
    }
504

505
    opt->desc = desc;
506
    if (!qemu_opt_parse(opt, errp)) {
507
        return false;
508
    }
509

510
    return true;
511
}
512

513
bool qemu_opt_set(QemuOpts *opts, const char *name, const char *value,
514
                  Error **errp)
515
{
516
    QemuOpt *opt = opt_create(opts, name, g_strdup(value));
517

518
    if (!opt_validate(opt, errp)) {
519
        qemu_opt_del(opt);
520
        return false;
521
    }
522
    return true;
523
}
524

525
bool qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val,
526
                       Error **errp)
527
{
528
    QemuOpt *opt;
529
    const QemuOptDesc *desc;
530
    const QemuOptsList *list = opts->list;
531

532
    desc = find_desc_by_name(list->desc, name);
533
    if (!desc && !opts_accepts_any(list)) {
534
        error_setg(errp, "Invalid parameter '%s'", name);
535
        return false;
536
    }
537

538
    opt = g_malloc0(sizeof(*opt));
539
    opt->name = g_strdup(name);
540
    opt->opts = opts;
541
    opt->desc = desc;
542
    opt->value.boolean = !!val;
543
    opt->str = g_strdup(val ? "on" : "off");
544
    QTAILQ_INSERT_TAIL(&opts->head, opt, next);
545
    return true;
546
}
547

548
bool qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val,
549
                         Error **errp)
550
{
551
    QemuOpt *opt;
552
    const QemuOptDesc *desc;
553
    const QemuOptsList *list = opts->list;
554

555
    desc = find_desc_by_name(list->desc, name);
556
    if (!desc && !opts_accepts_any(list)) {
557
        error_setg(errp, "Invalid parameter '%s'", name);
558
        return false;
559
    }
560

561
    opt = g_malloc0(sizeof(*opt));
562
    opt->name = g_strdup(name);
563
    opt->opts = opts;
564
    opt->desc = desc;
565
    opt->value.uint = val;
566
    opt->str = g_strdup_printf("%" PRId64, val);
567
    QTAILQ_INSERT_TAIL(&opts->head, opt, next);
568
    return true;
569
}
570

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

583
    QTAILQ_FOREACH(opt, &opts->head, next) {
584
        rc = func(opaque, opt->name, opt->str, errp);
585
        if (rc) {
586
            return rc;
587
        }
588
        assert(!errp || !*errp);
589
    }
590
    return 0;
591
}
592

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

597
    QTAILQ_FOREACH(opts, &list->head, next) {
598
        if (!opts->id && !id) {
599
            return opts;
600
        }
601
        if (opts->id && id && !strcmp(opts->id, id)) {
602
            return opts;
603
        }
604
    }
605
    return NULL;
606
}
607

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

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

646
void qemu_opts_reset(QemuOptsList *list)
647
{
648
    QemuOpts *opts, *next_opts;
649

650
    QTAILQ_FOREACH_SAFE(opts, &list->head, next, next_opts) {
651
        qemu_opts_del(opts);
652
    }
653
}
654

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

660
const char *qemu_opts_id(QemuOpts *opts)
661
{
662
    return opts->id;
663
}
664

665
/* The id string will be g_free()d by qemu_opts_del */
666
void qemu_opts_set_id(QemuOpts *opts, char *id)
667
{
668
    opts->id = id;
669
}
670

671
void qemu_opts_del(QemuOpts *opts)
672
{
673
    QemuOpt *opt;
674

675
    if (opts == NULL) {
676
        return;
677
    }
678

679
    for (;;) {
680
        opt = QTAILQ_FIRST(&opts->head);
681
        if (opt == NULL)
682
            break;
683
        qemu_opt_del(opt);
684
    }
685
    QTAILQ_REMOVE(&opts->list->head, opts, next);
686
    g_free(opts->id);
687
    g_free(opts);
688
}
689

690
/* print value, escaping any commas in value */
691
static void escaped_print(const char *value)
692
{
693
    const char *ptr;
694

695
    for (ptr = value; *ptr; ++ptr) {
696
        if (*ptr == ',') {
697
            putchar(',');
698
        }
699
        putchar(*ptr);
700
    }
701
}
702

703
void qemu_opts_print(QemuOpts *opts, const char *separator)
704
{
705
    QemuOpt *opt;
706
    QemuOptDesc *desc = opts->list->desc;
707
    const char *sep = "";
708

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

714
    if (desc[0].name == NULL) {
715
        QTAILQ_FOREACH(opt, &opts->head, next) {
716
            printf("%s%s=", sep, opt->name);
717
            escaped_print(opt->str);
718
            sep = separator;
719
        }
720
        return;
721
    }
722
    for (; desc && desc->name; desc++) {
723
        const char *value;
724
        opt = qemu_opt_find(opts, desc->name);
725

726
        value = opt ? opt->str : desc->def_value_str;
727
        if (!value) {
728
            continue;
729
        }
730
        if (desc->type == QEMU_OPT_STRING) {
731
            printf("%s%s=", sep, desc->name);
732
            escaped_print(value);
733
        } else if ((desc->type == QEMU_OPT_SIZE ||
734
                    desc->type == QEMU_OPT_NUMBER) && opt) {
735
            printf("%s%s=%" PRId64, sep, desc->name, opt->value.uint);
736
        } else {
737
            printf("%s%s=%s", sep, desc->name, value);
738
        }
739
        sep = separator;
740
    }
741
}
742

743
static const char *get_opt_name_value(const char *params,
744
                                      const char *firstname,
745
                                      bool warn_on_flag,
746
                                      bool *help_wanted,
747
                                      char **name, char **value)
748
{
749
    const char *p;
750
    const char *prefix = "";
751
    size_t len;
752
    bool is_help = false;
753

754
    len = strcspn(params, "=,");
755
    if (params[len] != '=') {
756
        /* found "foo,more" */
757
        if (firstname) {
758
            /* implicitly named first option */
759
            *name = g_strdup(firstname);
760
            p = get_opt_value(params, value);
761
        } else {
762
            /* option without value, must be a flag */
763
            p = get_opt_name(params, name, len);
764
            if (strncmp(*name, "no", 2) == 0) {
765
                memmove(*name, *name + 2, strlen(*name + 2) + 1);
766
                *value = g_strdup("off");
767
                prefix = "no";
768
            } else {
769
                *value = g_strdup("on");
770
                is_help = is_help_option(*name);
771
            }
772
            if (!is_help && warn_on_flag) {
773
                warn_report("short-form boolean option '%s%s' deprecated", prefix, *name);
774
                if (g_str_equal(*name, "delay")) {
775
                    error_printf("Please use nodelay=%s instead\n", prefix[0] ? "on" : "off");
776
                } else {
777
                    error_printf("Please use %s=%s instead\n", *name, *value);
778
                }
779
            }
780
        }
781
    } else {
782
        /* found "foo=bar,more" */
783
        p = get_opt_name(params, name, len);
784
        assert(*p == '=');
785
        p++;
786
        p = get_opt_value(p, value);
787
    }
788

789
    assert(!*p || *p == ',');
790
    if (help_wanted && is_help) {
791
        *help_wanted = true;
792
    }
793
    if (*p == ',') {
794
        p++;
795
    }
796
    return p;
797
}
798

799
static bool opts_do_parse(QemuOpts *opts, const char *params,
800
                          const char *firstname,
801
                          bool warn_on_flag, bool *help_wanted, Error **errp)
802
{
803
    char *option, *value;
804
    const char *p;
805
    QemuOpt *opt;
806

807
    for (p = params; *p;) {
808
        p = get_opt_name_value(p, firstname, warn_on_flag, help_wanted, &option, &value);
809
        if (help_wanted && *help_wanted) {
810
            g_free(option);
811
            g_free(value);
812
            return false;
813
        }
814
        firstname = NULL;
815

816
        if (!strcmp(option, "id")) {
817
            g_free(option);
818
            g_free(value);
819
            continue;
820
        }
821

822
        opt = opt_create(opts, option, value);
823
        g_free(option);
824
        if (!opt_validate(opt, errp)) {
825
            qemu_opt_del(opt);
826
            return false;
827
        }
828
    }
829

830
    return true;
831
}
832

833
static char *opts_parse_id(const char *params)
834
{
835
    const char *p;
836
    char *name, *value;
837

838
    for (p = params; *p;) {
839
        p = get_opt_name_value(p, NULL, false, NULL, &name, &value);
840
        if (!strcmp(name, "id")) {
841
            g_free(name);
842
            return value;
843
        }
844
        g_free(name);
845
        g_free(value);
846
    }
847

848
    return NULL;
849
}
850

851
bool has_help_option(const char *params)
852
{
853
    const char *p;
854
    char *name, *value;
855
    bool ret = false;
856

857
    for (p = params; *p;) {
858
        p = get_opt_name_value(p, NULL, false, &ret, &name, &value);
859
        g_free(name);
860
        g_free(value);
861
        if (ret) {
862
            return true;
863
        }
864
    }
865

866
    return false;
867
}
868

869
/**
870
 * Store options parsed from @params into @opts.
871
 * If @firstname is non-null, the first key=value in @params may omit
872
 * key=, and is treated as if key was @firstname.
873
 * On error, store an error object through @errp if non-null.
874
 */
875
bool qemu_opts_do_parse(QemuOpts *opts, const char *params,
876
                       const char *firstname, Error **errp)
877
{
878
    return opts_do_parse(opts, params, firstname, false, NULL, errp);
879
}
880

881
static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
882
                            bool permit_abbrev,
883
                            bool warn_on_flag, bool *help_wanted, Error **errp)
884
{
885
    const char *firstname;
886
    char *id = opts_parse_id(params);
887
    QemuOpts *opts;
888

889
    assert(!permit_abbrev || list->implied_opt_name);
890
    firstname = permit_abbrev ? list->implied_opt_name : NULL;
891

892
    opts = qemu_opts_create(list, id, !list->merge_lists, errp);
893
    g_free(id);
894
    if (opts == NULL) {
895
        return NULL;
896
    }
897

898
    if (!opts_do_parse(opts, params, firstname,
899
                       warn_on_flag, help_wanted, errp)) {
900
        qemu_opts_del(opts);
901
        return NULL;
902
    }
903

904
    return opts;
905
}
906

907
/**
908
 * Create a QemuOpts in @list and with options parsed from @params.
909
 * If @permit_abbrev, the first key=value in @params may omit key=,
910
 * and is treated as if key was @list->implied_opt_name.
911
 * On error, store an error object through @errp if non-null.
912
 * Return the new QemuOpts on success, null pointer on error.
913
 */
914
QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
915
                          bool permit_abbrev, Error **errp)
916
{
917
    return opts_parse(list, params, permit_abbrev, false, NULL, errp);
918
}
919

920
/**
921
 * Create a QemuOpts in @list and with options parsed from @params.
922
 * If @permit_abbrev, the first key=value in @params may omit key=,
923
 * and is treated as if key was @list->implied_opt_name.
924
 * Report errors with error_report_err().  This is inappropriate in
925
 * QMP context.  Do not use this function there!
926
 * Return the new QemuOpts on success, null pointer on error.
927
 */
928
QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
929
                                  bool permit_abbrev)
930
{
931
    Error *err = NULL;
932
    QemuOpts *opts;
933
    bool help_wanted = false;
934

935
    opts = opts_parse(list, params, permit_abbrev, true,
936
                      opts_accepts_any(list) ? NULL : &help_wanted,
937
                      &err);
938
    if (!opts) {
939
        assert(!!err + !!help_wanted == 1);
940
        if (help_wanted) {
941
            qemu_opts_print_help(list, true);
942
        } else {
943
            error_report_err(err);
944
        }
945
    }
946
    return opts;
947
}
948

949
static bool qemu_opts_from_qdict_entry(QemuOpts *opts,
950
                                       const QDictEntry *entry,
951
                                       Error **errp)
952
{
953
    const char *key = qdict_entry_key(entry);
954
    QObject *obj = qdict_entry_value(entry);
955
    char buf[32];
956
    g_autofree char *tmp = NULL;
957
    const char *value;
958

959
    if (!strcmp(key, "id")) {
960
        return true;
961
    }
962

963
    switch (qobject_type(obj)) {
964
    case QTYPE_QSTRING:
965
        value = qstring_get_str(qobject_to(QString, obj));
966
        break;
967
    case QTYPE_QNUM:
968
        tmp = qnum_to_string(qobject_to(QNum, obj));
969
        value = tmp;
970
        break;
971
    case QTYPE_QBOOL:
972
        pstrcpy(buf, sizeof(buf),
973
                qbool_get_bool(qobject_to(QBool, obj)) ? "on" : "off");
974
        value = buf;
975
        break;
976
    default:
977
        return true;
978
    }
979

980
    return qemu_opt_set(opts, key, value, errp);
981
}
982

983
/*
984
 * Create QemuOpts from a QDict.
985
 * Use value of key "id" as ID if it exists and is a QString.  Only
986
 * QStrings, QNums and QBools are copied.  Entries with other types
987
 * are silently ignored.
988
 */
989
QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
990
                               Error **errp)
991
{
992
    QemuOpts *opts;
993
    const QDictEntry *entry;
994

995
    opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1, errp);
996
    if (!opts) {
997
        return NULL;
998
    }
999

1000
    for (entry = qdict_first(qdict);
1001
         entry;
1002
         entry = qdict_next(qdict, entry)) {
1003
        if (!qemu_opts_from_qdict_entry(opts, entry, errp)) {
1004
            qemu_opts_del(opts);
1005
            return NULL;
1006
        }
1007
    }
1008

1009
    return opts;
1010
}
1011

1012
/*
1013
 * Adds all QDict entries to the QemuOpts that can be added and removes them
1014
 * from the QDict. When this function returns, the QDict contains only those
1015
 * entries that couldn't be added to the QemuOpts.
1016
 */
1017
bool qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp)
1018
{
1019
    const QDictEntry *entry, *next;
1020

1021
    entry = qdict_first(qdict);
1022

1023
    while (entry != NULL) {
1024
        next = qdict_next(qdict, entry);
1025

1026
        if (opts_accepts_any(opts->list) ||
1027
            find_desc_by_name(opts->list->desc, entry->key)) {
1028
            if (!qemu_opts_from_qdict_entry(opts, entry, errp)) {
1029
                return false;
1030
            }
1031
            qdict_del(qdict, entry->key);
1032
        }
1033

1034
        entry = next;
1035
    }
1036

1037
    return true;
1038
}
1039

1040
/*
1041
 * Convert from QemuOpts to QDict. The QDict values are of type QString.
1042
 *
1043
 * If @list is given, only add those options to the QDict that are contained in
1044
 * the list. If @del is true, any options added to the QDict are removed from
1045
 * the QemuOpts, otherwise they remain there.
1046
 *
1047
 * If two options in @opts have the same name, they are processed in order
1048
 * so that the last one wins (consistent with the reverse iteration in
1049
 * qemu_opt_find()), but all of them are deleted if @del is true.
1050
 *
1051
 * TODO We'll want to use types appropriate for opt->desc->type, but
1052
 * this is enough for now.
1053
 */
1054
QDict *qemu_opts_to_qdict_filtered(QemuOpts *opts, QDict *qdict,
1055
                                   QemuOptsList *list, bool del)
1056
{
1057
    QemuOpt *opt, *next;
1058

1059
    if (!qdict) {
1060
        qdict = qdict_new();
1061
    }
1062
    if (opts->id) {
1063
        qdict_put_str(qdict, "id", opts->id);
1064
    }
1065
    QTAILQ_FOREACH_SAFE(opt, &opts->head, next, next) {
1066
        if (list) {
1067
            QemuOptDesc *desc;
1068
            bool found = false;
1069
            for (desc = list->desc; desc->name; desc++) {
1070
                if (!strcmp(desc->name, opt->name)) {
1071
                    found = true;
1072
                    break;
1073
                }
1074
            }
1075
            if (!found) {
1076
                continue;
1077
            }
1078
        }
1079
        qdict_put_str(qdict, opt->name, opt->str);
1080
        if (del) {
1081
            qemu_opt_del(opt);
1082
        }
1083
    }
1084
    return qdict;
1085
}
1086

1087
/* Copy all options in a QemuOpts to the given QDict. See
1088
 * qemu_opts_to_qdict_filtered() for details. */
1089
QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
1090
{
1091
    return qemu_opts_to_qdict_filtered(opts, qdict, NULL, false);
1092
}
1093

1094
/* Validate parsed opts against descriptions where no
1095
 * descriptions were provided in the QemuOptsList.
1096
 */
1097
bool qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp)
1098
{
1099
    QemuOpt *opt;
1100

1101
    assert(opts_accepts_any(opts->list));
1102

1103
    QTAILQ_FOREACH(opt, &opts->head, next) {
1104
        opt->desc = find_desc_by_name(desc, opt->name);
1105
        if (!opt->desc) {
1106
            error_setg(errp, "Invalid parameter '%s'", opt->name);
1107
            return false;
1108
        }
1109

1110
        if (!qemu_opt_parse(opt, errp)) {
1111
            return false;
1112
        }
1113
    }
1114

1115
    return true;
1116
}
1117

1118
/**
1119
 * For each member of @list, call @func(@opaque, member, @errp).
1120
 * Call it with the current location temporarily set to the member's.
1121
 * @func() may store an Error through @errp, but must return non-zero then.
1122
 * When @func() returns non-zero, break the loop and return that value.
1123
 * Return zero when the loop completes.
1124
 */
1125
int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func,
1126
                      void *opaque, Error **errp)
1127
{
1128
    Location loc;
1129
    QemuOpts *opts, *next;
1130
    int rc = 0;
1131

1132
    loc_push_none(&loc);
1133
    QTAILQ_FOREACH_SAFE(opts, &list->head, next, next) {
1134
        loc_restore(&opts->loc);
1135
        rc = func(opaque, opts, errp);
1136
        if (rc) {
1137
            break;
1138
        }
1139
        assert(!errp || !*errp);
1140
    }
1141
    loc_pop(&loc);
1142
    return rc;
1143
}
1144

1145
static size_t count_opts_list(QemuOptsList *list)
1146
{
1147
    QemuOptDesc *desc = NULL;
1148
    size_t num_opts = 0;
1149

1150
    if (!list) {
1151
        return 0;
1152
    }
1153

1154
    desc = list->desc;
1155
    while (desc && desc->name) {
1156
        num_opts++;
1157
        desc++;
1158
    }
1159

1160
    return num_opts;
1161
}
1162

1163
void qemu_opts_free(QemuOptsList *list)
1164
{
1165
    g_free(list);
1166
}
1167

1168
/* Realloc dst option list and append options from an option list (list)
1169
 * to it. dst could be NULL or a malloced list.
1170
 * The lifetime of dst must be shorter than the input list because the
1171
 * QemuOptDesc->name, ->help, and ->def_value_str strings are shared.
1172
 */
1173
QemuOptsList *qemu_opts_append(QemuOptsList *dst,
1174
                               QemuOptsList *list)
1175
{
1176
    size_t num_opts, num_dst_opts;
1177
    QemuOptDesc *desc;
1178
    bool need_init = false;
1179
    bool need_head_update;
1180

1181
    if (!list) {
1182
        return dst;
1183
    }
1184

1185
    /* If dst is NULL, after realloc, some area of dst should be initialized
1186
     * before adding options to it.
1187
     */
1188
    if (!dst) {
1189
        need_init = true;
1190
        need_head_update = true;
1191
    } else {
1192
        /* Moreover, even if dst is not NULL, the realloc may move it to a
1193
         * different address in which case we may get a stale tail pointer
1194
         * in dst->head. */
1195
        need_head_update = QTAILQ_EMPTY(&dst->head);
1196
    }
1197

1198
    num_opts = count_opts_list(dst);
1199
    num_dst_opts = num_opts;
1200
    num_opts += count_opts_list(list);
1201
    dst = g_realloc(dst, sizeof(QemuOptsList) +
1202
                    (num_opts + 1) * sizeof(QemuOptDesc));
1203
    if (need_init) {
1204
        dst->name = NULL;
1205
        dst->implied_opt_name = NULL;
1206
        dst->merge_lists = false;
1207
    }
1208
    if (need_head_update) {
1209
        QTAILQ_INIT(&dst->head);
1210
    }
1211
    dst->desc[num_dst_opts].name = NULL;
1212

1213
    /* append list->desc to dst->desc */
1214
    if (list) {
1215
        desc = list->desc;
1216
        while (desc && desc->name) {
1217
            if (find_desc_by_name(dst->desc, desc->name) == NULL) {
1218
                dst->desc[num_dst_opts++] = *desc;
1219
                dst->desc[num_dst_opts].name = NULL;
1220
            }
1221
            desc++;
1222
        }
1223
    }
1224

1225
    return dst;
1226
}
1227

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.