xref: /openbmc/qemu/util/qemu-option.c (revision 30648dd5)
1baacf047SPaolo Bonzini /*
2baacf047SPaolo Bonzini  * Commandline option parsing functions
3baacf047SPaolo Bonzini  *
4baacf047SPaolo Bonzini  * Copyright (c) 2003-2008 Fabrice Bellard
5baacf047SPaolo Bonzini  * Copyright (c) 2009 Kevin Wolf <kwolf@redhat.com>
6baacf047SPaolo Bonzini  *
7baacf047SPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
8baacf047SPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
9baacf047SPaolo Bonzini  * in the Software without restriction, including without limitation the rights
10baacf047SPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11baacf047SPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
12baacf047SPaolo Bonzini  * furnished to do so, subject to the following conditions:
13baacf047SPaolo Bonzini  *
14baacf047SPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
15baacf047SPaolo Bonzini  * all copies or substantial portions of the Software.
16baacf047SPaolo Bonzini  *
17baacf047SPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18baacf047SPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19baacf047SPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20baacf047SPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21baacf047SPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22baacf047SPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23baacf047SPaolo Bonzini  * THE SOFTWARE.
24baacf047SPaolo Bonzini  */
25baacf047SPaolo Bonzini 
26aafd7584SPeter Maydell #include "qemu/osdep.h"
27baacf047SPaolo Bonzini 
28da34e65cSMarkus Armbruster #include "qapi/error.h"
29baacf047SPaolo Bonzini #include "qemu/error-report.h"
306b673957SMarkus Armbruster #include "qapi/qmp/qbool.h"
316b673957SMarkus Armbruster #include "qapi/qmp/qdict.h"
3215280c36SMarkus Armbruster #include "qapi/qmp/qnum.h"
336b673957SMarkus Armbruster #include "qapi/qmp/qstring.h"
34baacf047SPaolo Bonzini #include "qapi/qmp/qerror.h"
35baacf047SPaolo Bonzini #include "qemu/option_int.h"
36f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
37f348b6d1SVeronia Bahaa #include "qemu/id.h"
38f348b6d1SVeronia Bahaa #include "qemu/help_option.h"
39baacf047SPaolo Bonzini 
40baacf047SPaolo Bonzini /*
41924e9b0dSPaolo Bonzini  * Extracts the name of an option from the parameter string (@p points at the
42baacf047SPaolo Bonzini  * first byte of the option name)
43baacf047SPaolo Bonzini  *
44924e9b0dSPaolo Bonzini  * The option name is @len characters long and is copied into @option. The
45924e9b0dSPaolo Bonzini  * caller is responsible for free'ing @option when no longer required.
46baacf047SPaolo Bonzini  *
47baacf047SPaolo Bonzini  * The return value is the position of the delimiter/zero byte after the option
48924e9b0dSPaolo Bonzini  * name in @p.
49baacf047SPaolo Bonzini  */
get_opt_name(const char * p,char ** option,size_t len)50924e9b0dSPaolo Bonzini static const char *get_opt_name(const char *p, char **option, size_t len)
51baacf047SPaolo Bonzini {
52924e9b0dSPaolo Bonzini     *option = g_strndup(p, len);
53924e9b0dSPaolo Bonzini     return p + len;
54baacf047SPaolo Bonzini }
55baacf047SPaolo Bonzini 
56baacf047SPaolo Bonzini /*
57baacf047SPaolo Bonzini  * Extracts the value of an option from the parameter string p (p points at the
58baacf047SPaolo Bonzini  * first byte of the option value)
59baacf047SPaolo Bonzini  *
60baacf047SPaolo Bonzini  * This function is comparable to get_opt_name with the difference that the
61baacf047SPaolo Bonzini  * delimiter is fixed to be comma which starts a new option. To specify an
62baacf047SPaolo Bonzini  * option value that contains commas, double each comma.
63baacf047SPaolo Bonzini  */
get_opt_value(const char * p,char ** value)64950c4e6cSDaniel P. Berrangé const char *get_opt_value(const char *p, char **value)
65baacf047SPaolo Bonzini {
66950c4e6cSDaniel P. Berrangé     size_t capacity = 0, length;
67950c4e6cSDaniel P. Berrangé     const char *offset;
68baacf047SPaolo Bonzini 
69950c4e6cSDaniel P. Berrangé     *value = NULL;
70950c4e6cSDaniel P. Berrangé     while (1) {
715c99fa37SKeno Fischer         offset = qemu_strchrnul(p, ',');
72950c4e6cSDaniel P. Berrangé         length = offset - p;
73950c4e6cSDaniel P. Berrangé         if (*offset != '\0' && *(offset + 1) == ',') {
74950c4e6cSDaniel P. Berrangé             length++;
75950c4e6cSDaniel P. Berrangé         }
76950c4e6cSDaniel P. Berrangé         *value = g_renew(char, *value, capacity + length + 1);
77950c4e6cSDaniel P. Berrangé         strncpy(*value + capacity, p, length);
78950c4e6cSDaniel P. Berrangé         (*value)[capacity + length] = '\0';
79950c4e6cSDaniel P. Berrangé         capacity += length;
80950c4e6cSDaniel P. Berrangé         if (*offset == '\0' ||
81950c4e6cSDaniel P. Berrangé             *(offset + 1) != ',') {
82baacf047SPaolo Bonzini             break;
83baacf047SPaolo Bonzini         }
84baacf047SPaolo Bonzini 
85950c4e6cSDaniel P. Berrangé         p += (offset - p) + 2;
86950c4e6cSDaniel P. Berrangé     }
87950c4e6cSDaniel P. Berrangé 
88950c4e6cSDaniel P. Berrangé     return offset;
89baacf047SPaolo Bonzini }
90baacf047SPaolo Bonzini 
parse_option_number(const char * name,const char * value,uint64_t * ret,Error ** errp)91c75d7f71SMarkus Armbruster static bool parse_option_number(const char *name, const char *value,
92baacf047SPaolo Bonzini                                 uint64_t *ret, Error **errp)
93baacf047SPaolo Bonzini {
94baacf047SPaolo Bonzini     uint64_t number;
953403e5ebSMarkus Armbruster     int err;
96baacf047SPaolo Bonzini 
973403e5ebSMarkus Armbruster     err = qemu_strtou64(value, NULL, 0, &number);
983403e5ebSMarkus Armbruster     if (err == -ERANGE) {
993403e5ebSMarkus Armbruster         error_setg(errp, "Value '%s' is too large for parameter '%s'",
1003403e5ebSMarkus Armbruster                    value, name);
101c75d7f71SMarkus Armbruster         return false;
1023403e5ebSMarkus Armbruster     }
1033403e5ebSMarkus Armbruster     if (err) {
104c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number");
105c75d7f71SMarkus Armbruster         return false;
106baacf047SPaolo Bonzini     }
107baacf047SPaolo Bonzini     *ret = number;
108c75d7f71SMarkus Armbruster     return true;
109baacf047SPaolo Bonzini }
110baacf047SPaolo Bonzini 
find_desc_by_name(const QemuOptDesc * desc,const char * name)1115e89db76SChunyan Liu static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc,
1125e89db76SChunyan Liu                                             const char *name)
1135e89db76SChunyan Liu {
1145e89db76SChunyan Liu     int i;
1155e89db76SChunyan Liu 
1165e89db76SChunyan Liu     for (i = 0; desc[i].name != NULL; i++) {
1175e89db76SChunyan Liu         if (strcmp(desc[i].name, name) == 0) {
1185e89db76SChunyan Liu             return &desc[i];
1195e89db76SChunyan Liu         }
1205e89db76SChunyan Liu     }
1215e89db76SChunyan Liu 
1225e89db76SChunyan Liu     return NULL;
1235e89db76SChunyan Liu }
1245e89db76SChunyan Liu 
find_default_by_name(QemuOpts * opts,const char * name)125f23db652SMarkus Armbruster static const char *find_default_by_name(QemuOpts *opts, const char *name)
126f23db652SMarkus Armbruster {
127f23db652SMarkus Armbruster     const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name);
128f23db652SMarkus Armbruster 
129f23db652SMarkus Armbruster     return desc ? desc->def_value_str : NULL;
130f23db652SMarkus Armbruster }
131f23db652SMarkus Armbruster 
parse_option_size(const char * name,const char * value,uint64_t * ret,Error ** errp)132c75d7f71SMarkus Armbruster bool parse_option_size(const char *name, const char *value,
133baacf047SPaolo Bonzini                        uint64_t *ret, Error **errp)
134baacf047SPaolo Bonzini {
13575cdcd15SMarkus Armbruster     uint64_t size;
13675cdcd15SMarkus Armbruster     int err;
137baacf047SPaolo Bonzini 
13875cdcd15SMarkus Armbruster     err = qemu_strtosz(value, NULL, &size);
13975cdcd15SMarkus Armbruster     if (err == -ERANGE) {
1409e19ad4eSMarkus Armbruster         error_setg(errp, "Value '%s' is out of range for parameter '%s'",
14175cdcd15SMarkus Armbruster                    value, name);
142c75d7f71SMarkus Armbruster         return false;
14375cdcd15SMarkus Armbruster     }
14475cdcd15SMarkus Armbruster     if (err) {
14521278992SBo Tu         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name,
14621278992SBo Tu                    "a non-negative number below 2^64");
14775cdcd15SMarkus Armbruster         error_append_hint(errp, "Optional suffix k, M, G, T, P or E means"
14875cdcd15SMarkus Armbruster                           " kilo-, mega-, giga-, tera-, peta-\n"
14975cdcd15SMarkus Armbruster                           "and exabytes, respectively.\n");
150c75d7f71SMarkus Armbruster         return false;
15121278992SBo Tu     }
15275cdcd15SMarkus Armbruster     *ret = size;
153c75d7f71SMarkus Armbruster     return true;
154baacf047SPaolo Bonzini }
155baacf047SPaolo Bonzini 
opt_type_to_string(enum QemuOptType type)1569cbef9d6SMarc-André Lureau static const char *opt_type_to_string(enum QemuOptType type)
1579cbef9d6SMarc-André Lureau {
1589cbef9d6SMarc-André Lureau     switch (type) {
1599cbef9d6SMarc-André Lureau     case QEMU_OPT_STRING:
1609cbef9d6SMarc-André Lureau         return "str";
1619cbef9d6SMarc-André Lureau     case QEMU_OPT_BOOL:
1629cbef9d6SMarc-André Lureau         return "bool (on/off)";
1639cbef9d6SMarc-André Lureau     case QEMU_OPT_NUMBER:
1649cbef9d6SMarc-André Lureau         return "num";
1659cbef9d6SMarc-André Lureau     case QEMU_OPT_SIZE:
1669cbef9d6SMarc-André Lureau         return "size";
1679cbef9d6SMarc-André Lureau     }
1689cbef9d6SMarc-André Lureau 
1699cbef9d6SMarc-André Lureau     g_assert_not_reached();
1709cbef9d6SMarc-André Lureau }
1719cbef9d6SMarc-André Lureau 
17263898712SMax Reitz /**
17363898712SMax Reitz  * Print the list of options available in the given list.  If
17463898712SMax Reitz  * @print_caption is true, a caption (including the list name, if it
17563898712SMax Reitz  * exists) is printed.  The options itself will be indented, so
17663898712SMax Reitz  * @print_caption should only be set to false if the caller prints its
17763898712SMax Reitz  * own custom caption (so that the indentation makes sense).
17863898712SMax Reitz  */
qemu_opts_print_help(QemuOptsList * list,bool print_caption)17963898712SMax Reitz void qemu_opts_print_help(QemuOptsList *list, bool print_caption)
180504189a9SChunyan Liu {
181504189a9SChunyan Liu     QemuOptDesc *desc;
1829cbef9d6SMarc-André Lureau     int i;
1839cbef9d6SMarc-André Lureau     GPtrArray *array = g_ptr_array_new();
184504189a9SChunyan Liu 
185504189a9SChunyan Liu     assert(list);
186504189a9SChunyan Liu     desc = list->desc;
187504189a9SChunyan Liu     while (desc && desc->name) {
1889cbef9d6SMarc-André Lureau         GString *str = g_string_new(NULL);
18963898712SMax Reitz         g_string_append_printf(str, "  %s=<%s>", desc->name,
1909cbef9d6SMarc-André Lureau                                opt_type_to_string(desc->type));
1919cbef9d6SMarc-André Lureau         if (desc->help) {
19263898712SMax Reitz             if (str->len < 24) {
19363898712SMax Reitz                 g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
19463898712SMax Reitz             }
1959cbef9d6SMarc-André Lureau             g_string_append_printf(str, " - %s", desc->help);
1969cbef9d6SMarc-André Lureau         }
1979cbef9d6SMarc-André Lureau         g_ptr_array_add(array, g_string_free(str, false));
198504189a9SChunyan Liu         desc++;
199504189a9SChunyan Liu     }
2009cbef9d6SMarc-André Lureau 
2019cbef9d6SMarc-André Lureau     g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
20263898712SMax Reitz     if (print_caption && array->len > 0) {
20363898712SMax Reitz         if (list->name) {
20463898712SMax Reitz             printf("%s options:\n", list->name);
20563898712SMax Reitz         } else {
20663898712SMax Reitz             printf("Options:\n");
20763898712SMax Reitz         }
20863898712SMax Reitz     } else if (array->len == 0) {
20963898712SMax Reitz         if (list->name) {
21063898712SMax Reitz             printf("There are no options for %s.\n", list->name);
21163898712SMax Reitz         } else {
21263898712SMax Reitz             printf("No options available.\n");
21363898712SMax Reitz         }
21463898712SMax Reitz     }
2159cbef9d6SMarc-André Lureau     for (i = 0; i < array->len; i++) {
2169cbef9d6SMarc-André Lureau         printf("%s\n", (char *)array->pdata[i]);
2179cbef9d6SMarc-André Lureau     }
2189cbef9d6SMarc-André Lureau     g_ptr_array_set_free_func(array, g_free);
2199cbef9d6SMarc-André Lureau     g_ptr_array_free(array, true);
2209cbef9d6SMarc-André Lureau 
221504189a9SChunyan Liu }
222baacf047SPaolo Bonzini /* ------------------------------------------------------------------ */
223baacf047SPaolo Bonzini 
qemu_opt_find(QemuOpts * opts,const char * name)22474c3c197SChunyan Liu QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name)
225baacf047SPaolo Bonzini {
226baacf047SPaolo Bonzini     QemuOpt *opt;
227baacf047SPaolo Bonzini 
228eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE(opt, &opts->head, next) {
229baacf047SPaolo Bonzini         if (strcmp(opt->name, name) != 0)
230baacf047SPaolo Bonzini             continue;
231baacf047SPaolo Bonzini         return opt;
232baacf047SPaolo Bonzini     }
233baacf047SPaolo Bonzini     return NULL;
234baacf047SPaolo Bonzini }
235baacf047SPaolo Bonzini 
qemu_opt_del(QemuOpt * opt)236fc345512SChunyan Liu static void qemu_opt_del(QemuOpt *opt)
237fc345512SChunyan Liu {
238fc345512SChunyan Liu     QTAILQ_REMOVE(&opt->opts->head, opt, next);
239fc345512SChunyan Liu     g_free(opt->name);
240fc345512SChunyan Liu     g_free(opt->str);
241fc345512SChunyan Liu     g_free(opt);
242fc345512SChunyan Liu }
243fc345512SChunyan Liu 
244782730b0SChunyan Liu /* qemu_opt_set allows many settings for the same option.
245782730b0SChunyan Liu  * This function deletes all settings for an option.
246782730b0SChunyan Liu  */
qemu_opt_del_all(QemuOpts * opts,const char * name)247782730b0SChunyan Liu static void qemu_opt_del_all(QemuOpts *opts, const char *name)
248782730b0SChunyan Liu {
249782730b0SChunyan Liu     QemuOpt *opt, *next_opt;
250782730b0SChunyan Liu 
251782730b0SChunyan Liu     QTAILQ_FOREACH_SAFE(opt, &opts->head, next, next_opt) {
252782730b0SChunyan Liu         if (!strcmp(opt->name, name)) {
253782730b0SChunyan Liu             qemu_opt_del(opt);
254782730b0SChunyan Liu         }
255782730b0SChunyan Liu     }
256782730b0SChunyan Liu }
257782730b0SChunyan Liu 
qemu_opt_get(QemuOpts * opts,const char * name)258baacf047SPaolo Bonzini const char *qemu_opt_get(QemuOpts *opts, const char *name)
259baacf047SPaolo Bonzini {
260435db4cfSChunyan Liu     QemuOpt *opt;
26109722032SChunyan Liu 
262435db4cfSChunyan Liu     if (opts == NULL) {
263435db4cfSChunyan Liu         return NULL;
264435db4cfSChunyan Liu     }
265435db4cfSChunyan Liu 
266435db4cfSChunyan Liu     opt = qemu_opt_find(opts, name);
26709722032SChunyan Liu     if (!opt) {
26844b0b7d1SMarkus Armbruster         return find_default_by_name(opts, name);
26909722032SChunyan Liu     }
27044b0b7d1SMarkus Armbruster 
27144b0b7d1SMarkus Armbruster     return opt->str;
272baacf047SPaolo Bonzini }
273baacf047SPaolo Bonzini 
qemu_opt_iter_init(QemuOptsIter * iter,QemuOpts * opts,const char * name)274e998e209SDaniel P. Berrange void qemu_opt_iter_init(QemuOptsIter *iter, QemuOpts *opts, const char *name)
275e998e209SDaniel P. Berrange {
276e998e209SDaniel P. Berrange     iter->opts = opts;
277e998e209SDaniel P. Berrange     iter->opt = QTAILQ_FIRST(&opts->head);
278e998e209SDaniel P. Berrange     iter->name = name;
279e998e209SDaniel P. Berrange }
280e998e209SDaniel P. Berrange 
qemu_opt_iter_next(QemuOptsIter * iter)281e998e209SDaniel P. Berrange const char *qemu_opt_iter_next(QemuOptsIter *iter)
282e998e209SDaniel P. Berrange {
283e998e209SDaniel P. Berrange     QemuOpt *ret = iter->opt;
284e998e209SDaniel P. Berrange     if (iter->name) {
285e998e209SDaniel P. Berrange         while (ret && !g_str_equal(iter->name, ret->name)) {
286e998e209SDaniel P. Berrange             ret = QTAILQ_NEXT(ret, next);
287e998e209SDaniel P. Berrange         }
288e998e209SDaniel P. Berrange     }
289e998e209SDaniel P. Berrange     iter->opt = ret ? QTAILQ_NEXT(ret, next) : NULL;
290e998e209SDaniel P. Berrange     return ret ? ret->str : NULL;
291e998e209SDaniel P. Berrange }
292e998e209SDaniel P. Berrange 
293782730b0SChunyan Liu /* Get a known option (or its default) and remove it from the list
294782730b0SChunyan Liu  * all in one action. Return a malloced string of the option value.
295782730b0SChunyan Liu  * Result must be freed by caller with g_free().
296782730b0SChunyan Liu  */
qemu_opt_get_del(QemuOpts * opts,const char * name)297782730b0SChunyan Liu char *qemu_opt_get_del(QemuOpts *opts, const char *name)
298782730b0SChunyan Liu {
299782730b0SChunyan Liu     QemuOpt *opt;
30044b0b7d1SMarkus Armbruster     char *str;
301782730b0SChunyan Liu 
302782730b0SChunyan Liu     if (opts == NULL) {
303782730b0SChunyan Liu         return NULL;
304782730b0SChunyan Liu     }
305782730b0SChunyan Liu 
306782730b0SChunyan Liu     opt = qemu_opt_find(opts, name);
307782730b0SChunyan Liu     if (!opt) {
30844b0b7d1SMarkus Armbruster         return g_strdup(find_default_by_name(opts, name));
309782730b0SChunyan Liu     }
310782730b0SChunyan Liu     str = opt->str;
311782730b0SChunyan Liu     opt->str = NULL;
312782730b0SChunyan Liu     qemu_opt_del_all(opts, name);
313782730b0SChunyan Liu     return str;
314782730b0SChunyan Liu }
315782730b0SChunyan Liu 
qemu_opt_has_help_opt(QemuOpts * opts)316baacf047SPaolo Bonzini bool qemu_opt_has_help_opt(QemuOpts *opts)
317baacf047SPaolo Bonzini {
318baacf047SPaolo Bonzini     QemuOpt *opt;
319baacf047SPaolo Bonzini 
320eae3eb3eSPaolo Bonzini     QTAILQ_FOREACH_REVERSE(opt, &opts->head, next) {
321baacf047SPaolo Bonzini         if (is_help_option(opt->name)) {
322baacf047SPaolo Bonzini             return true;
323baacf047SPaolo Bonzini         }
324baacf047SPaolo Bonzini     }
325baacf047SPaolo Bonzini     return false;
326baacf047SPaolo Bonzini }
327baacf047SPaolo Bonzini 
qemu_opt_get_bool_helper(QemuOpts * opts,const char * name,bool defval,bool del)328782730b0SChunyan Liu static bool qemu_opt_get_bool_helper(QemuOpts *opts, const char *name,
329782730b0SChunyan Liu                                      bool defval, bool del)
330baacf047SPaolo Bonzini {
331435db4cfSChunyan Liu     QemuOpt *opt;
332f23db652SMarkus Armbruster     const char *def_val;
333782730b0SChunyan Liu     bool ret = defval;
334baacf047SPaolo Bonzini 
335435db4cfSChunyan Liu     if (opts == NULL) {
336435db4cfSChunyan Liu         return ret;
337435db4cfSChunyan Liu     }
338435db4cfSChunyan Liu 
339435db4cfSChunyan Liu     opt = qemu_opt_find(opts, name);
34009722032SChunyan Liu     if (opt == NULL) {
341f23db652SMarkus Armbruster         def_val = find_default_by_name(opts, name);
342f23db652SMarkus Armbruster         if (def_val) {
343372bcb25SPaolo Bonzini             qapi_bool_parse(name, def_val, &ret, &error_abort);
34409722032SChunyan Liu         }
345782730b0SChunyan Liu         return ret;
34609722032SChunyan Liu     }
347baacf047SPaolo Bonzini     assert(opt->desc && opt->desc->type == QEMU_OPT_BOOL);
348782730b0SChunyan Liu     ret = opt->value.boolean;
349782730b0SChunyan Liu     if (del) {
350782730b0SChunyan Liu         qemu_opt_del_all(opts, name);
351782730b0SChunyan Liu     }
352782730b0SChunyan Liu     return ret;
353782730b0SChunyan Liu }
354782730b0SChunyan Liu 
qemu_opt_get_bool(QemuOpts * opts,const char * name,bool defval)355782730b0SChunyan Liu bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval)
356782730b0SChunyan Liu {
357782730b0SChunyan Liu     return qemu_opt_get_bool_helper(opts, name, defval, false);
358782730b0SChunyan Liu }
359782730b0SChunyan Liu 
qemu_opt_get_bool_del(QemuOpts * opts,const char * name,bool defval)360782730b0SChunyan Liu bool qemu_opt_get_bool_del(QemuOpts *opts, const char *name, bool defval)
361782730b0SChunyan Liu {
362782730b0SChunyan Liu     return qemu_opt_get_bool_helper(opts, name, defval, true);
363782730b0SChunyan Liu }
364782730b0SChunyan Liu 
qemu_opt_get_number_helper(QemuOpts * opts,const char * name,uint64_t defval,bool del)365782730b0SChunyan Liu static uint64_t qemu_opt_get_number_helper(QemuOpts *opts, const char *name,
366782730b0SChunyan Liu                                            uint64_t defval, bool del)
367782730b0SChunyan Liu {
368435db4cfSChunyan Liu     QemuOpt *opt;
369f23db652SMarkus Armbruster     const char *def_val;
370782730b0SChunyan Liu     uint64_t ret = defval;
371782730b0SChunyan Liu 
372435db4cfSChunyan Liu     if (opts == NULL) {
373435db4cfSChunyan Liu         return ret;
374435db4cfSChunyan Liu     }
375435db4cfSChunyan Liu 
376435db4cfSChunyan Liu     opt = qemu_opt_find(opts, name);
377782730b0SChunyan Liu     if (opt == NULL) {
378f23db652SMarkus Armbruster         def_val = find_default_by_name(opts, name);
379f23db652SMarkus Armbruster         if (def_val) {
380f23db652SMarkus Armbruster             parse_option_number(name, def_val, &ret, &error_abort);
381782730b0SChunyan Liu         }
382782730b0SChunyan Liu         return ret;
383782730b0SChunyan Liu     }
384782730b0SChunyan Liu     assert(opt->desc && opt->desc->type == QEMU_OPT_NUMBER);
385782730b0SChunyan Liu     ret = opt->value.uint;
386782730b0SChunyan Liu     if (del) {
387782730b0SChunyan Liu         qemu_opt_del_all(opts, name);
388782730b0SChunyan Liu     }
389782730b0SChunyan Liu     return ret;
390baacf047SPaolo Bonzini }
391baacf047SPaolo Bonzini 
qemu_opt_get_number(QemuOpts * opts,const char * name,uint64_t defval)392baacf047SPaolo Bonzini uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval)
393baacf047SPaolo Bonzini {
394782730b0SChunyan Liu     return qemu_opt_get_number_helper(opts, name, defval, false);
395782730b0SChunyan Liu }
396782730b0SChunyan Liu 
qemu_opt_get_number_del(QemuOpts * opts,const char * name,uint64_t defval)397782730b0SChunyan Liu uint64_t qemu_opt_get_number_del(QemuOpts *opts, const char *name,
398782730b0SChunyan Liu                                  uint64_t defval)
399782730b0SChunyan Liu {
400782730b0SChunyan Liu     return qemu_opt_get_number_helper(opts, name, defval, true);
401782730b0SChunyan Liu }
402782730b0SChunyan Liu 
qemu_opt_get_size_helper(QemuOpts * opts,const char * name,uint64_t defval,bool del)403782730b0SChunyan Liu static uint64_t qemu_opt_get_size_helper(QemuOpts *opts, const char *name,
404782730b0SChunyan Liu                                          uint64_t defval, bool del)
405782730b0SChunyan Liu {
406435db4cfSChunyan Liu     QemuOpt *opt;
407f23db652SMarkus Armbruster     const char *def_val;
408782730b0SChunyan Liu     uint64_t ret = defval;
409baacf047SPaolo Bonzini 
410435db4cfSChunyan Liu     if (opts == NULL) {
411435db4cfSChunyan Liu         return ret;
412435db4cfSChunyan Liu     }
413435db4cfSChunyan Liu 
414435db4cfSChunyan Liu     opt = qemu_opt_find(opts, name);
41509722032SChunyan Liu     if (opt == NULL) {
416f23db652SMarkus Armbruster         def_val = find_default_by_name(opts, name);
417f23db652SMarkus Armbruster         if (def_val) {
418f23db652SMarkus Armbruster             parse_option_size(name, def_val, &ret, &error_abort);
41909722032SChunyan Liu         }
420782730b0SChunyan Liu         return ret;
42109722032SChunyan Liu     }
422782730b0SChunyan Liu     assert(opt->desc && opt->desc->type == QEMU_OPT_SIZE);
423782730b0SChunyan Liu     ret = opt->value.uint;
424782730b0SChunyan Liu     if (del) {
425782730b0SChunyan Liu         qemu_opt_del_all(opts, name);
426782730b0SChunyan Liu     }
427782730b0SChunyan Liu     return ret;
428baacf047SPaolo Bonzini }
429baacf047SPaolo Bonzini 
qemu_opt_get_size(QemuOpts * opts,const char * name,uint64_t defval)430baacf047SPaolo Bonzini uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval)
431baacf047SPaolo Bonzini {
432782730b0SChunyan Liu     return qemu_opt_get_size_helper(opts, name, defval, false);
433782730b0SChunyan Liu }
434baacf047SPaolo Bonzini 
qemu_opt_get_size_del(QemuOpts * opts,const char * name,uint64_t defval)435782730b0SChunyan Liu uint64_t qemu_opt_get_size_del(QemuOpts *opts, const char *name,
436782730b0SChunyan Liu                                uint64_t defval)
437782730b0SChunyan Liu {
438782730b0SChunyan Liu     return qemu_opt_get_size_helper(opts, name, defval, true);
439baacf047SPaolo Bonzini }
440baacf047SPaolo Bonzini 
qemu_opt_parse(QemuOpt * opt,Error ** errp)441c75d7f71SMarkus Armbruster static bool qemu_opt_parse(QemuOpt *opt, Error **errp)
442baacf047SPaolo Bonzini {
443baacf047SPaolo Bonzini     if (opt->desc == NULL)
444c75d7f71SMarkus Armbruster         return true;
445baacf047SPaolo Bonzini 
446baacf047SPaolo Bonzini     switch (opt->desc->type) {
447baacf047SPaolo Bonzini     case QEMU_OPT_STRING:
448baacf047SPaolo Bonzini         /* nothing */
449c75d7f71SMarkus Armbruster         return true;
450baacf047SPaolo Bonzini     case QEMU_OPT_BOOL:
451372bcb25SPaolo Bonzini         return qapi_bool_parse(opt->name, opt->str, &opt->value.boolean, errp);
452baacf047SPaolo Bonzini     case QEMU_OPT_NUMBER:
453c75d7f71SMarkus Armbruster         return parse_option_number(opt->name, opt->str, &opt->value.uint,
454c75d7f71SMarkus Armbruster                                    errp);
455baacf047SPaolo Bonzini     case QEMU_OPT_SIZE:
456c75d7f71SMarkus Armbruster         return parse_option_size(opt->name, opt->str, &opt->value.uint,
457c75d7f71SMarkus Armbruster                                  errp);
458baacf047SPaolo Bonzini     default:
459baacf047SPaolo Bonzini         abort();
460baacf047SPaolo Bonzini     }
461baacf047SPaolo Bonzini }
462baacf047SPaolo Bonzini 
opts_accepts_any(const QemuOptsList * list)46345c53fe6SPaolo Bonzini static bool opts_accepts_any(const QemuOptsList *list)
464baacf047SPaolo Bonzini {
46545c53fe6SPaolo Bonzini     return list->desc[0].name == NULL;
466baacf047SPaolo Bonzini }
467baacf047SPaolo Bonzini 
qemu_opt_unset(QemuOpts * opts,const char * name)4680dd6c526SKevin Wolf int qemu_opt_unset(QemuOpts *opts, const char *name)
4690dd6c526SKevin Wolf {
4700dd6c526SKevin Wolf     QemuOpt *opt = qemu_opt_find(opts, name);
4710dd6c526SKevin Wolf 
47245c53fe6SPaolo Bonzini     assert(opts_accepts_any(opts->list));
4730dd6c526SKevin Wolf 
4740dd6c526SKevin Wolf     if (opt == NULL) {
4750dd6c526SKevin Wolf         return -1;
4760dd6c526SKevin Wolf     } else {
4770dd6c526SKevin Wolf         qemu_opt_del(opt);
4780dd6c526SKevin Wolf         return 0;
4790dd6c526SKevin Wolf     }
4800dd6c526SKevin Wolf }
4810dd6c526SKevin Wolf 
opt_create(QemuOpts * opts,const char * name,char * value)482904806c6SPaolo Bonzini static QemuOpt *opt_create(QemuOpts *opts, const char *name, char *value)
48381a8a072SMarkus Armbruster {
48481a8a072SMarkus Armbruster     QemuOpt *opt = g_malloc0(sizeof(*opt));
48581a8a072SMarkus Armbruster 
48681a8a072SMarkus Armbruster     opt->name = g_strdup(name);
48781a8a072SMarkus Armbruster     opt->str = value;
48881a8a072SMarkus Armbruster     opt->opts = opts;
48981a8a072SMarkus Armbruster     QTAILQ_INSERT_TAIL(&opts->head, opt, next);
49081a8a072SMarkus Armbruster 
49181a8a072SMarkus Armbruster     return opt;
49281a8a072SMarkus Armbruster }
49381a8a072SMarkus Armbruster 
opt_validate(QemuOpt * opt,Error ** errp)494afd73625SPaolo Bonzini static bool opt_validate(QemuOpt *opt, Error **errp)
495baacf047SPaolo Bonzini {
496baacf047SPaolo Bonzini     const QemuOptDesc *desc;
49745c53fe6SPaolo Bonzini     const QemuOptsList *list = opt->opts->list;
498baacf047SPaolo Bonzini 
49945c53fe6SPaolo Bonzini     desc = find_desc_by_name(list->desc, opt->name);
50045c53fe6SPaolo Bonzini     if (!desc && !opts_accepts_any(list)) {
50164af7a8bSMarkus Armbruster         error_setg(errp, QERR_INVALID_PARAMETER, opt->name);
50264af7a8bSMarkus Armbruster         return false;
503baacf047SPaolo Bonzini     }
504baacf047SPaolo Bonzini 
505baacf047SPaolo Bonzini     opt->desc = desc;
506668f62ecSMarkus Armbruster     if (!qemu_opt_parse(opt, errp)) {
50764af7a8bSMarkus Armbruster         return false;
508baacf047SPaolo Bonzini     }
50964af7a8bSMarkus Armbruster 
51064af7a8bSMarkus Armbruster     return true;
511baacf047SPaolo Bonzini }
512baacf047SPaolo Bonzini 
qemu_opt_set(QemuOpts * opts,const char * name,const char * value,Error ** errp)513c75d7f71SMarkus Armbruster bool qemu_opt_set(QemuOpts *opts, const char *name, const char *value,
514baacf047SPaolo Bonzini                   Error **errp)
515baacf047SPaolo Bonzini {
516904806c6SPaolo Bonzini     QemuOpt *opt = opt_create(opts, name, g_strdup(value));
51764af7a8bSMarkus Armbruster 
518afd73625SPaolo Bonzini     if (!opt_validate(opt, errp)) {
51964af7a8bSMarkus Armbruster         qemu_opt_del(opt);
520c75d7f71SMarkus Armbruster         return false;
52164af7a8bSMarkus Armbruster     }
522c75d7f71SMarkus Armbruster     return true;
523baacf047SPaolo Bonzini }
524baacf047SPaolo Bonzini 
qemu_opt_set_bool(QemuOpts * opts,const char * name,bool val,Error ** errp)525c75d7f71SMarkus Armbruster bool qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val,
526cccb7967SMarkus Armbruster                        Error **errp)
527baacf047SPaolo Bonzini {
528baacf047SPaolo Bonzini     QemuOpt *opt;
5299da7197aSMarkus Armbruster     const QemuOptDesc *desc;
53045c53fe6SPaolo Bonzini     const QemuOptsList *list = opts->list;
531baacf047SPaolo Bonzini 
53245c53fe6SPaolo Bonzini     desc = find_desc_by_name(list->desc, name);
53345c53fe6SPaolo Bonzini     if (!desc && !opts_accepts_any(list)) {
534c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_INVALID_PARAMETER, name);
535c75d7f71SMarkus Armbruster         return false;
536baacf047SPaolo Bonzini     }
537baacf047SPaolo Bonzini 
5389da7197aSMarkus Armbruster     opt = g_malloc0(sizeof(*opt));
539baacf047SPaolo Bonzini     opt->name = g_strdup(name);
540baacf047SPaolo Bonzini     opt->opts = opts;
5419da7197aSMarkus Armbruster     opt->desc = desc;
542baacf047SPaolo Bonzini     opt->value.boolean = !!val;
543baacf047SPaolo Bonzini     opt->str = g_strdup(val ? "on" : "off");
544baacf047SPaolo Bonzini     QTAILQ_INSERT_TAIL(&opts->head, opt, next);
545c75d7f71SMarkus Armbruster     return true;
546baacf047SPaolo Bonzini }
547baacf047SPaolo Bonzini 
qemu_opt_set_number(QemuOpts * opts,const char * name,int64_t val,Error ** errp)548c75d7f71SMarkus Armbruster bool qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val,
54939101f25SMarkus Armbruster                          Error **errp)
550baacf047SPaolo Bonzini {
551baacf047SPaolo Bonzini     QemuOpt *opt;
5529da7197aSMarkus Armbruster     const QemuOptDesc *desc;
55345c53fe6SPaolo Bonzini     const QemuOptsList *list = opts->list;
554baacf047SPaolo Bonzini 
55545c53fe6SPaolo Bonzini     desc = find_desc_by_name(list->desc, name);
55645c53fe6SPaolo Bonzini     if (!desc && !opts_accepts_any(list)) {
557c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_INVALID_PARAMETER, name);
558c75d7f71SMarkus Armbruster         return false;
559baacf047SPaolo Bonzini     }
560baacf047SPaolo Bonzini 
5619da7197aSMarkus Armbruster     opt = g_malloc0(sizeof(*opt));
562baacf047SPaolo Bonzini     opt->name = g_strdup(name);
563baacf047SPaolo Bonzini     opt->opts = opts;
5649da7197aSMarkus Armbruster     opt->desc = desc;
565baacf047SPaolo Bonzini     opt->value.uint = val;
566baacf047SPaolo Bonzini     opt->str = g_strdup_printf("%" PRId64, val);
567baacf047SPaolo Bonzini     QTAILQ_INSERT_TAIL(&opts->head, opt, next);
568c75d7f71SMarkus Armbruster     return true;
569baacf047SPaolo Bonzini }
570baacf047SPaolo Bonzini 
5711640b200SMarkus Armbruster /**
57271df1d83SMarkus Armbruster  * For each member of @opts, call @func(@opaque, name, value, @errp).
57371df1d83SMarkus Armbruster  * @func() may store an Error through @errp, but must return non-zero then.
5741640b200SMarkus Armbruster  * When @func() returns non-zero, break the loop and return that value.
5751640b200SMarkus Armbruster  * Return zero when the loop completes.
5761640b200SMarkus Armbruster  */
qemu_opt_foreach(QemuOpts * opts,qemu_opt_loopfunc func,void * opaque,Error ** errp)57771df1d83SMarkus Armbruster int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
57871df1d83SMarkus Armbruster                      Error **errp)
579baacf047SPaolo Bonzini {
580baacf047SPaolo Bonzini     QemuOpt *opt;
5811640b200SMarkus Armbruster     int rc;
582baacf047SPaolo Bonzini 
583baacf047SPaolo Bonzini     QTAILQ_FOREACH(opt, &opts->head, next) {
58471df1d83SMarkus Armbruster         rc = func(opaque, opt->name, opt->str, errp);
5851640b200SMarkus Armbruster         if (rc) {
586baacf047SPaolo Bonzini             return rc;
587baacf047SPaolo Bonzini         }
58871df1d83SMarkus Armbruster         assert(!errp || !*errp);
5891640b200SMarkus Armbruster     }
5901640b200SMarkus Armbruster     return 0;
5911640b200SMarkus Armbruster }
592baacf047SPaolo Bonzini 
qemu_opts_find(QemuOptsList * list,const char * id)593baacf047SPaolo Bonzini QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id)
594baacf047SPaolo Bonzini {
595baacf047SPaolo Bonzini     QemuOpts *opts;
596baacf047SPaolo Bonzini 
597baacf047SPaolo Bonzini     QTAILQ_FOREACH(opts, &list->head, next) {
59896bc97ebSMarkus Armbruster         if (!opts->id && !id) {
599baacf047SPaolo Bonzini             return opts;
600baacf047SPaolo Bonzini         }
60196bc97ebSMarkus Armbruster         if (opts->id && id && !strcmp(opts->id, id)) {
602baacf047SPaolo Bonzini             return opts;
603baacf047SPaolo Bonzini         }
60496bc97ebSMarkus Armbruster     }
605baacf047SPaolo Bonzini     return NULL;
606baacf047SPaolo Bonzini }
607baacf047SPaolo Bonzini 
qemu_opts_create(QemuOptsList * list,const char * id,int fail_if_exists,Error ** errp)608baacf047SPaolo Bonzini QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id,
609baacf047SPaolo Bonzini                            int fail_if_exists, Error **errp)
610baacf047SPaolo Bonzini {
611baacf047SPaolo Bonzini     QemuOpts *opts = NULL;
612baacf047SPaolo Bonzini 
61363758d10SPaolo Bonzini     if (list->merge_lists) {
614baacf047SPaolo Bonzini         if (id) {
61563758d10SPaolo Bonzini             error_setg(errp, QERR_INVALID_PARAMETER, "id");
61663758d10SPaolo Bonzini             return NULL;
61763758d10SPaolo Bonzini         }
61863758d10SPaolo Bonzini         opts = qemu_opts_find(list, NULL);
61963758d10SPaolo Bonzini         if (opts) {
62063758d10SPaolo Bonzini             return opts;
62163758d10SPaolo Bonzini         }
62263758d10SPaolo Bonzini     } else if (id) {
62363758d10SPaolo Bonzini         assert(fail_if_exists);
624f5bebbbbSMarkus Armbruster         if (!id_wellformed(id)) {
625c6bd8c70SMarkus Armbruster             error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "id",
626c6bd8c70SMarkus Armbruster                        "an identifier");
62750b7b000SEric Blake             error_append_hint(errp, "Identifiers consist of letters, digits, "
628543202c0SMarkus Armbruster                               "'-', '.', '_', starting with a letter.\n");
629baacf047SPaolo Bonzini             return NULL;
630baacf047SPaolo Bonzini         }
631baacf047SPaolo Bonzini         opts = qemu_opts_find(list, id);
632baacf047SPaolo Bonzini         if (opts != NULL) {
633f231b88dSCole Robinson             error_setg(errp, "Duplicate ID '%s' for %s", id, list->name);
634baacf047SPaolo Bonzini             return NULL;
635baacf047SPaolo Bonzini         }
636baacf047SPaolo Bonzini     }
637baacf047SPaolo Bonzini     opts = g_malloc0(sizeof(*opts));
638baacf047SPaolo Bonzini     opts->id = g_strdup(id);
639baacf047SPaolo Bonzini     opts->list = list;
640baacf047SPaolo Bonzini     loc_save(&opts->loc);
641baacf047SPaolo Bonzini     QTAILQ_INIT(&opts->head);
642baacf047SPaolo Bonzini     QTAILQ_INSERT_TAIL(&list->head, opts, next);
643baacf047SPaolo Bonzini     return opts;
644baacf047SPaolo Bonzini }
645baacf047SPaolo Bonzini 
qemu_opts_reset(QemuOptsList * list)646baacf047SPaolo Bonzini void qemu_opts_reset(QemuOptsList *list)
647baacf047SPaolo Bonzini {
648baacf047SPaolo Bonzini     QemuOpts *opts, *next_opts;
649baacf047SPaolo Bonzini 
650baacf047SPaolo Bonzini     QTAILQ_FOREACH_SAFE(opts, &list->head, next, next_opts) {
651baacf047SPaolo Bonzini         qemu_opts_del(opts);
652baacf047SPaolo Bonzini     }
653baacf047SPaolo Bonzini }
654baacf047SPaolo Bonzini 
qemu_opts_loc_restore(QemuOpts * opts)655baacf047SPaolo Bonzini void qemu_opts_loc_restore(QemuOpts *opts)
656baacf047SPaolo Bonzini {
657baacf047SPaolo Bonzini     loc_restore(&opts->loc);
658baacf047SPaolo Bonzini }
659baacf047SPaolo Bonzini 
qemu_opts_id(QemuOpts * opts)660baacf047SPaolo Bonzini const char *qemu_opts_id(QemuOpts *opts)
661baacf047SPaolo Bonzini {
662baacf047SPaolo Bonzini     return opts->id;
663baacf047SPaolo Bonzini }
664baacf047SPaolo Bonzini 
665326642bcSKevin Wolf /* The id string will be g_free()d by qemu_opts_del */
qemu_opts_set_id(QemuOpts * opts,char * id)666326642bcSKevin Wolf void qemu_opts_set_id(QemuOpts *opts, char *id)
667326642bcSKevin Wolf {
668326642bcSKevin Wolf     opts->id = id;
669326642bcSKevin Wolf }
670326642bcSKevin Wolf 
qemu_opts_del(QemuOpts * opts)671baacf047SPaolo Bonzini void qemu_opts_del(QemuOpts *opts)
672baacf047SPaolo Bonzini {
673baacf047SPaolo Bonzini     QemuOpt *opt;
674baacf047SPaolo Bonzini 
6754782183dSChunyan Liu     if (opts == NULL) {
6764782183dSChunyan Liu         return;
6774782183dSChunyan Liu     }
6784782183dSChunyan Liu 
679baacf047SPaolo Bonzini     for (;;) {
680baacf047SPaolo Bonzini         opt = QTAILQ_FIRST(&opts->head);
681baacf047SPaolo Bonzini         if (opt == NULL)
682baacf047SPaolo Bonzini             break;
683baacf047SPaolo Bonzini         qemu_opt_del(opt);
684baacf047SPaolo Bonzini     }
685baacf047SPaolo Bonzini     QTAILQ_REMOVE(&opts->list->head, opts, next);
686baacf047SPaolo Bonzini     g_free(opts->id);
687baacf047SPaolo Bonzini     g_free(opts);
688baacf047SPaolo Bonzini }
689baacf047SPaolo Bonzini 
690fe646693SKővágó, Zoltán /* print value, escaping any commas in value */
escaped_print(const char * value)691fe646693SKővágó, Zoltán static void escaped_print(const char *value)
692fe646693SKővágó, Zoltán {
693fe646693SKővágó, Zoltán     const char *ptr;
694fe646693SKővágó, Zoltán 
695fe646693SKővágó, Zoltán     for (ptr = value; *ptr; ++ptr) {
696fe646693SKővágó, Zoltán         if (*ptr == ',') {
697fe646693SKővágó, Zoltán             putchar(',');
698fe646693SKővágó, Zoltán         }
699fe646693SKővágó, Zoltán         putchar(*ptr);
700fe646693SKővágó, Zoltán     }
701fe646693SKővágó, Zoltán }
702fe646693SKővágó, Zoltán 
qemu_opts_print(QemuOpts * opts,const char * separator)703fe646693SKővágó, Zoltán void qemu_opts_print(QemuOpts *opts, const char *separator)
704baacf047SPaolo Bonzini {
705baacf047SPaolo Bonzini     QemuOpt *opt;
70609722032SChunyan Liu     QemuOptDesc *desc = opts->list->desc;
707fe646693SKővágó, Zoltán     const char *sep = "";
708fe646693SKővágó, Zoltán 
709fe646693SKővágó, Zoltán     if (opts->id) {
710fe646693SKővágó, Zoltán         printf("id=%s", opts->id); /* passed id_wellformed -> no commas */
711fe646693SKővágó, Zoltán         sep = separator;
712fe646693SKővágó, Zoltán     }
713baacf047SPaolo Bonzini 
71409722032SChunyan Liu     if (desc[0].name == NULL) {
715baacf047SPaolo Bonzini         QTAILQ_FOREACH(opt, &opts->head, next) {
716fe646693SKővágó, Zoltán             printf("%s%s=", sep, opt->name);
717fe646693SKővágó, Zoltán             escaped_print(opt->str);
718fe646693SKővágó, Zoltán             sep = separator;
719baacf047SPaolo Bonzini         }
72009722032SChunyan Liu         return;
72109722032SChunyan Liu     }
72209722032SChunyan Liu     for (; desc && desc->name; desc++) {
72309722032SChunyan Liu         const char *value;
724da78e382SDr. David Alan Gilbert         opt = qemu_opt_find(opts, desc->name);
72509722032SChunyan Liu 
72609722032SChunyan Liu         value = opt ? opt->str : desc->def_value_str;
72709722032SChunyan Liu         if (!value) {
72809722032SChunyan Liu             continue;
72909722032SChunyan Liu         }
73009722032SChunyan Liu         if (desc->type == QEMU_OPT_STRING) {
731fe646693SKővágó, Zoltán             printf("%s%s=", sep, desc->name);
732fe646693SKővágó, Zoltán             escaped_print(value);
73309722032SChunyan Liu         } else if ((desc->type == QEMU_OPT_SIZE ||
73409722032SChunyan Liu                     desc->type == QEMU_OPT_NUMBER) && opt) {
73543c5d8f8SFam Zheng             printf("%s%s=%" PRId64, sep, desc->name, opt->value.uint);
73609722032SChunyan Liu         } else {
73743c5d8f8SFam Zheng             printf("%s%s=%s", sep, desc->name, value);
73809722032SChunyan Liu         }
739fe646693SKővágó, Zoltán         sep = separator;
74009722032SChunyan Liu     }
741baacf047SPaolo Bonzini }
742baacf047SPaolo Bonzini 
get_opt_name_value(const char * params,const char * firstname,bool warn_on_flag,bool * help_wanted,char ** name,char ** value)7436129803bSMarkus Armbruster static const char *get_opt_name_value(const char *params,
7446129803bSMarkus Armbruster                                       const char *firstname,
745ccd3b3b8SPaolo Bonzini                                       bool warn_on_flag,
746afd73625SPaolo Bonzini                                       bool *help_wanted,
7476129803bSMarkus Armbruster                                       char **name, char **value)
748baacf047SPaolo Bonzini {
749924e9b0dSPaolo Bonzini     const char *p;
750ccd3b3b8SPaolo Bonzini     const char *prefix = "";
751924e9b0dSPaolo Bonzini     size_t len;
752afd73625SPaolo Bonzini     bool is_help = false;
753baacf047SPaolo Bonzini 
754924e9b0dSPaolo Bonzini     len = strcspn(params, "=,");
755924e9b0dSPaolo Bonzini     if (params[len] != '=') {
756baacf047SPaolo Bonzini         /* found "foo,more" */
7576129803bSMarkus Armbruster         if (firstname) {
758baacf047SPaolo Bonzini             /* implicitly named first option */
7596129803bSMarkus Armbruster             *name = g_strdup(firstname);
7606129803bSMarkus Armbruster             p = get_opt_value(params, value);
761baacf047SPaolo Bonzini         } else {
7626129803bSMarkus Armbruster             /* option without value, must be a flag */
763924e9b0dSPaolo Bonzini             p = get_opt_name(params, name, len);
7646129803bSMarkus Armbruster             if (strncmp(*name, "no", 2) == 0) {
7656129803bSMarkus Armbruster                 memmove(*name, *name + 2, strlen(*name + 2) + 1);
7666129803bSMarkus Armbruster                 *value = g_strdup("off");
767ccd3b3b8SPaolo Bonzini                 prefix = "no";
768baacf047SPaolo Bonzini             } else {
7696129803bSMarkus Armbruster                 *value = g_strdup("on");
770afd73625SPaolo Bonzini                 is_help = is_help_option(*name);
771baacf047SPaolo Bonzini             }
772ccd3b3b8SPaolo Bonzini             if (!is_help && warn_on_flag) {
773ccd3b3b8SPaolo Bonzini                 warn_report("short-form boolean option '%s%s' deprecated", prefix, *name);
774fe636424SPaolo Bonzini                 if (g_str_equal(*name, "delay")) {
775fe636424SPaolo Bonzini                     error_printf("Please use nodelay=%s instead\n", prefix[0] ? "on" : "off");
776fe636424SPaolo Bonzini                 } else {
777ccd3b3b8SPaolo Bonzini                     error_printf("Please use %s=%s instead\n", *name, *value);
778ccd3b3b8SPaolo Bonzini                 }
779baacf047SPaolo Bonzini             }
780fe636424SPaolo Bonzini         }
781baacf047SPaolo Bonzini     } else {
782baacf047SPaolo Bonzini         /* found "foo=bar,more" */
783924e9b0dSPaolo Bonzini         p = get_opt_name(params, name, len);
784e652714fSDaniel P. Berrangé         assert(*p == '=');
785baacf047SPaolo Bonzini         p++;
7866129803bSMarkus Armbruster         p = get_opt_value(p, value);
787baacf047SPaolo Bonzini     }
788e652714fSDaniel P. Berrangé 
7896129803bSMarkus Armbruster     assert(!*p || *p == ',');
790afd73625SPaolo Bonzini     if (help_wanted && is_help) {
791afd73625SPaolo Bonzini         *help_wanted = true;
792afd73625SPaolo Bonzini     }
7936129803bSMarkus Armbruster     if (*p == ',') {
7946129803bSMarkus Armbruster         p++;
7956129803bSMarkus Armbruster     }
7966129803bSMarkus Armbruster     return p;
7976129803bSMarkus Armbruster }
7986129803bSMarkus Armbruster 
opts_do_parse(QemuOpts * opts,const char * params,const char * firstname,bool warn_on_flag,bool * help_wanted,Error ** errp)799c75d7f71SMarkus Armbruster static bool opts_do_parse(QemuOpts *opts, const char *params,
800904806c6SPaolo Bonzini                           const char *firstname,
801ccd3b3b8SPaolo Bonzini                           bool warn_on_flag, bool *help_wanted, Error **errp)
8026129803bSMarkus Armbruster {
8036129803bSMarkus Armbruster     char *option, *value;
8046129803bSMarkus Armbruster     const char *p;
80564af7a8bSMarkus Armbruster     QemuOpt *opt;
8066129803bSMarkus Armbruster 
8076129803bSMarkus Armbruster     for (p = params; *p;) {
808ccd3b3b8SPaolo Bonzini         p = get_opt_name_value(p, firstname, warn_on_flag, help_wanted, &option, &value);
809afd73625SPaolo Bonzini         if (help_wanted && *help_wanted) {
810afd73625SPaolo Bonzini             g_free(option);
811afd73625SPaolo Bonzini             g_free(value);
812afd73625SPaolo Bonzini             return false;
813afd73625SPaolo Bonzini         }
8146129803bSMarkus Armbruster         firstname = NULL;
8156129803bSMarkus Armbruster 
8166129803bSMarkus Armbruster         if (!strcmp(option, "id")) {
817e652714fSDaniel P. Berrangé             g_free(option);
818950c4e6cSDaniel P. Berrangé             g_free(value);
8196129803bSMarkus Armbruster             continue;
8206129803bSMarkus Armbruster         }
8216129803bSMarkus Armbruster 
822904806c6SPaolo Bonzini         opt = opt_create(opts, option, value);
8236129803bSMarkus Armbruster         g_free(option);
824afd73625SPaolo Bonzini         if (!opt_validate(opt, errp)) {
82564af7a8bSMarkus Armbruster             qemu_opt_del(opt);
826c75d7f71SMarkus Armbruster             return false;
8276129803bSMarkus Armbruster         }
8286129803bSMarkus Armbruster     }
829c75d7f71SMarkus Armbruster 
830c75d7f71SMarkus Armbruster     return true;
831baacf047SPaolo Bonzini }
832baacf047SPaolo Bonzini 
opts_parse_id(const char * params)833933d1527SMarkus Armbruster static char *opts_parse_id(const char *params)
834933d1527SMarkus Armbruster {
835933d1527SMarkus Armbruster     const char *p;
836933d1527SMarkus Armbruster     char *name, *value;
837933d1527SMarkus Armbruster 
838933d1527SMarkus Armbruster     for (p = params; *p;) {
839ccd3b3b8SPaolo Bonzini         p = get_opt_name_value(p, NULL, false, NULL, &name, &value);
840933d1527SMarkus Armbruster         if (!strcmp(name, "id")) {
841933d1527SMarkus Armbruster             g_free(name);
842933d1527SMarkus Armbruster             return value;
843933d1527SMarkus Armbruster         }
844933d1527SMarkus Armbruster         g_free(name);
845933d1527SMarkus Armbruster         g_free(value);
846933d1527SMarkus Armbruster     }
847933d1527SMarkus Armbruster 
848933d1527SMarkus Armbruster     return NULL;
849933d1527SMarkus Armbruster }
850933d1527SMarkus Armbruster 
has_help_option(const char * params)85180a94855SMarkus Armbruster bool has_help_option(const char *params)
85280a94855SMarkus Armbruster {
85380a94855SMarkus Armbruster     const char *p;
85480a94855SMarkus Armbruster     char *name, *value;
855afd73625SPaolo Bonzini     bool ret = false;
85680a94855SMarkus Armbruster 
85780a94855SMarkus Armbruster     for (p = params; *p;) {
858ccd3b3b8SPaolo Bonzini         p = get_opt_name_value(p, NULL, false, &ret, &name, &value);
85980a94855SMarkus Armbruster         g_free(name);
86080a94855SMarkus Armbruster         g_free(value);
86180a94855SMarkus Armbruster         if (ret) {
86280a94855SMarkus Armbruster             return true;
86380a94855SMarkus Armbruster         }
86480a94855SMarkus Armbruster     }
86580a94855SMarkus Armbruster 
86680a94855SMarkus Armbruster     return false;
86780a94855SMarkus Armbruster }
86880a94855SMarkus Armbruster 
869dc523cd3SMarkus Armbruster /**
870dc523cd3SMarkus Armbruster  * Store options parsed from @params into @opts.
871dc523cd3SMarkus Armbruster  * If @firstname is non-null, the first key=value in @params may omit
872dc523cd3SMarkus Armbruster  * key=, and is treated as if key was @firstname.
873dc523cd3SMarkus Armbruster  * On error, store an error object through @errp if non-null.
874dc523cd3SMarkus Armbruster  */
qemu_opts_do_parse(QemuOpts * opts,const char * params,const char * firstname,Error ** errp)875c75d7f71SMarkus Armbruster bool qemu_opts_do_parse(QemuOpts *opts, const char *params,
876dc523cd3SMarkus Armbruster                        const char *firstname, Error **errp)
877baacf047SPaolo Bonzini {
878904806c6SPaolo Bonzini     return opts_do_parse(opts, params, firstname, false, NULL, errp);
879baacf047SPaolo Bonzini }
880baacf047SPaolo Bonzini 
opts_parse(QemuOptsList * list,const char * params,bool permit_abbrev,bool warn_on_flag,bool * help_wanted,Error ** errp)881baacf047SPaolo Bonzini static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
882904806c6SPaolo Bonzini                             bool permit_abbrev,
883ccd3b3b8SPaolo Bonzini                             bool warn_on_flag, bool *help_wanted, Error **errp)
884baacf047SPaolo Bonzini {
885baacf047SPaolo Bonzini     const char *firstname;
886933d1527SMarkus Armbruster     char *id = opts_parse_id(params);
887baacf047SPaolo Bonzini     QemuOpts *opts;
888baacf047SPaolo Bonzini 
889baacf047SPaolo Bonzini     assert(!permit_abbrev || list->implied_opt_name);
890baacf047SPaolo Bonzini     firstname = permit_abbrev ? list->implied_opt_name : NULL;
891baacf047SPaolo Bonzini 
89263758d10SPaolo Bonzini     opts = qemu_opts_create(list, id, !list->merge_lists, errp);
893950c4e6cSDaniel P. Berrangé     g_free(id);
894baacf047SPaolo Bonzini     if (opts == NULL) {
895baacf047SPaolo Bonzini         return NULL;
896baacf047SPaolo Bonzini     }
897baacf047SPaolo Bonzini 
898904806c6SPaolo Bonzini     if (!opts_do_parse(opts, params, firstname,
899ccd3b3b8SPaolo Bonzini                        warn_on_flag, help_wanted, errp)) {
900baacf047SPaolo Bonzini         qemu_opts_del(opts);
901baacf047SPaolo Bonzini         return NULL;
902baacf047SPaolo Bonzini     }
903baacf047SPaolo Bonzini 
904baacf047SPaolo Bonzini     return opts;
905baacf047SPaolo Bonzini }
906baacf047SPaolo Bonzini 
9074f81273dSMarkus Armbruster /**
9084f81273dSMarkus Armbruster  * Create a QemuOpts in @list and with options parsed from @params.
9094f81273dSMarkus Armbruster  * If @permit_abbrev, the first key=value in @params may omit key=,
9104f81273dSMarkus Armbruster  * and is treated as if key was @list->implied_opt_name.
91170b94331SMarkus Armbruster  * On error, store an error object through @errp if non-null.
9124f81273dSMarkus Armbruster  * Return the new QemuOpts on success, null pointer on error.
9134f81273dSMarkus Armbruster  */
qemu_opts_parse(QemuOptsList * list,const char * params,bool permit_abbrev,Error ** errp)914baacf047SPaolo Bonzini QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
91570b94331SMarkus Armbruster                           bool permit_abbrev, Error **errp)
91670b94331SMarkus Armbruster {
917904806c6SPaolo Bonzini     return opts_parse(list, params, permit_abbrev, false, NULL, errp);
91870b94331SMarkus Armbruster }
91970b94331SMarkus Armbruster 
92070b94331SMarkus Armbruster /**
92170b94331SMarkus Armbruster  * Create a QemuOpts in @list and with options parsed from @params.
92270b94331SMarkus Armbruster  * If @permit_abbrev, the first key=value in @params may omit key=,
92370b94331SMarkus Armbruster  * and is treated as if key was @list->implied_opt_name.
92470b94331SMarkus Armbruster  * Report errors with error_report_err().  This is inappropriate in
92570b94331SMarkus Armbruster  * QMP context.  Do not use this function there!
92670b94331SMarkus Armbruster  * Return the new QemuOpts on success, null pointer on error.
92770b94331SMarkus Armbruster  */
qemu_opts_parse_noisily(QemuOptsList * list,const char * params,bool permit_abbrev)92870b94331SMarkus Armbruster QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
92970b94331SMarkus Armbruster                                   bool permit_abbrev)
930baacf047SPaolo Bonzini {
9314f81273dSMarkus Armbruster     Error *err = NULL;
9324f81273dSMarkus Armbruster     QemuOpts *opts;
93356a9efa1SMarkus Armbruster     bool help_wanted = false;
9344f81273dSMarkus Armbruster 
935904806c6SPaolo Bonzini     opts = opts_parse(list, params, permit_abbrev, true,
936afd73625SPaolo Bonzini                       opts_accepts_any(list) ? NULL : &help_wanted,
937afd73625SPaolo Bonzini                       &err);
938afd73625SPaolo Bonzini     if (!opts) {
939afd73625SPaolo Bonzini         assert(!!err + !!help_wanted == 1);
94056a9efa1SMarkus Armbruster         if (help_wanted) {
94163898712SMax Reitz             qemu_opts_print_help(list, true);
942e05979d0SMarc-André Lureau         } else {
94370b94331SMarkus Armbruster             error_report_err(err);
9444f81273dSMarkus Armbruster         }
945e05979d0SMarc-André Lureau     }
9464f81273dSMarkus Armbruster     return opts;
947baacf047SPaolo Bonzini }
948baacf047SPaolo Bonzini 
qemu_opts_from_qdict_entry(QemuOpts * opts,const QDictEntry * entry,Error ** errp)949c75d7f71SMarkus Armbruster static bool qemu_opts_from_qdict_entry(QemuOpts *opts,
9502500f6f3SMarkus Armbruster                                        const QDictEntry *entry,
9512500f6f3SMarkus Armbruster                                        Error **errp)
952baacf047SPaolo Bonzini {
9532500f6f3SMarkus Armbruster     const char *key = qdict_entry_key(entry);
9542500f6f3SMarkus Armbruster     QObject *obj = qdict_entry_value(entry);
955c75d7f71SMarkus Armbruster     char buf[32];
956c75d7f71SMarkus Armbruster     g_autofree char *tmp = NULL;
957baacf047SPaolo Bonzini     const char *value;
958baacf047SPaolo Bonzini 
9592500f6f3SMarkus Armbruster     if (!strcmp(key, "id")) {
960c75d7f71SMarkus Armbruster         return true;
961baacf047SPaolo Bonzini     }
962baacf047SPaolo Bonzini 
963baacf047SPaolo Bonzini     switch (qobject_type(obj)) {
964baacf047SPaolo Bonzini     case QTYPE_QSTRING:
9657dc847ebSMax Reitz         value = qstring_get_str(qobject_to(QString, obj));
966baacf047SPaolo Bonzini         break;
96701b2ffceSMarc-André Lureau     case QTYPE_QNUM:
9687dc847ebSMax Reitz         tmp = qnum_to_string(qobject_to(QNum, obj));
96901b2ffceSMarc-André Lureau         value = tmp;
970baacf047SPaolo Bonzini         break;
971baacf047SPaolo Bonzini     case QTYPE_QBOOL:
972baacf047SPaolo Bonzini         pstrcpy(buf, sizeof(buf),
9737dc847ebSMax Reitz                 qbool_get_bool(qobject_to(QBool, obj)) ? "on" : "off");
974baacf047SPaolo Bonzini         value = buf;
975baacf047SPaolo Bonzini         break;
976baacf047SPaolo Bonzini     default:
977c75d7f71SMarkus Armbruster         return true;
978baacf047SPaolo Bonzini     }
979baacf047SPaolo Bonzini 
980c75d7f71SMarkus Armbruster     return qemu_opt_set(opts, key, value, errp);
981baacf047SPaolo Bonzini }
982baacf047SPaolo Bonzini 
983baacf047SPaolo Bonzini /*
984baacf047SPaolo Bonzini  * Create QemuOpts from a QDict.
98501b2ffceSMarc-André Lureau  * Use value of key "id" as ID if it exists and is a QString.  Only
98601b2ffceSMarc-André Lureau  * QStrings, QNums and QBools are copied.  Entries with other types
98701b2ffceSMarc-André Lureau  * are silently ignored.
988baacf047SPaolo Bonzini  */
qemu_opts_from_qdict(QemuOptsList * list,const QDict * qdict,Error ** errp)989baacf047SPaolo Bonzini QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
990baacf047SPaolo Bonzini                                Error **errp)
991baacf047SPaolo Bonzini {
992baacf047SPaolo Bonzini     QemuOpts *opts;
9937b1cd1c6SMarkus Armbruster     const QDictEntry *entry;
994baacf047SPaolo Bonzini 
995c6ecec43SMarkus Armbruster     opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1, errp);
996c6ecec43SMarkus Armbruster     if (!opts) {
997baacf047SPaolo Bonzini         return NULL;
998baacf047SPaolo Bonzini     }
999baacf047SPaolo Bonzini 
10007b1cd1c6SMarkus Armbruster     for (entry = qdict_first(qdict);
10017b1cd1c6SMarkus Armbruster          entry;
10027b1cd1c6SMarkus Armbruster          entry = qdict_next(qdict, entry)) {
1003668f62ecSMarkus Armbruster         if (!qemu_opts_from_qdict_entry(opts, entry, errp)) {
1004baacf047SPaolo Bonzini             qemu_opts_del(opts);
1005baacf047SPaolo Bonzini             return NULL;
1006baacf047SPaolo Bonzini         }
10072500f6f3SMarkus Armbruster     }
1008baacf047SPaolo Bonzini 
1009baacf047SPaolo Bonzini     return opts;
1010baacf047SPaolo Bonzini }
1011baacf047SPaolo Bonzini 
1012baacf047SPaolo Bonzini /*
1013376609ccSKevin Wolf  * Adds all QDict entries to the QemuOpts that can be added and removes them
1014376609ccSKevin Wolf  * from the QDict. When this function returns, the QDict contains only those
1015376609ccSKevin Wolf  * entries that couldn't be added to the QemuOpts.
1016376609ccSKevin Wolf  */
qemu_opts_absorb_qdict(QemuOpts * opts,QDict * qdict,Error ** errp)1017c75d7f71SMarkus Armbruster bool qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp)
1018376609ccSKevin Wolf {
1019376609ccSKevin Wolf     const QDictEntry *entry, *next;
1020376609ccSKevin Wolf 
1021376609ccSKevin Wolf     entry = qdict_first(qdict);
1022376609ccSKevin Wolf 
1023376609ccSKevin Wolf     while (entry != NULL) {
1024376609ccSKevin Wolf         next = qdict_next(qdict, entry);
1025376609ccSKevin Wolf 
1026941a4736SPaolo Bonzini         if (opts_accepts_any(opts->list) ||
1027941a4736SPaolo Bonzini             find_desc_by_name(opts->list->desc, entry->key)) {
1028668f62ecSMarkus Armbruster             if (!qemu_opts_from_qdict_entry(opts, entry, errp)) {
1029c75d7f71SMarkus Armbruster                 return false;
1030376609ccSKevin Wolf             }
10312500f6f3SMarkus Armbruster             qdict_del(qdict, entry->key);
1032376609ccSKevin Wolf         }
1033376609ccSKevin Wolf 
1034376609ccSKevin Wolf         entry = next;
1035376609ccSKevin Wolf     }
1036c75d7f71SMarkus Armbruster 
1037c75d7f71SMarkus Armbruster     return true;
1038376609ccSKevin Wolf }
1039376609ccSKevin Wolf 
1040376609ccSKevin Wolf /*
104172215395SKevin Wolf  * Convert from QemuOpts to QDict. The QDict values are of type QString.
104272215395SKevin Wolf  *
104372215395SKevin Wolf  * If @list is given, only add those options to the QDict that are contained in
104472215395SKevin Wolf  * the list. If @del is true, any options added to the QDict are removed from
104572215395SKevin Wolf  * the QemuOpts, otherwise they remain there.
104672215395SKevin Wolf  *
104772215395SKevin Wolf  * If two options in @opts have the same name, they are processed in order
104872215395SKevin Wolf  * so that the last one wins (consistent with the reverse iteration in
104972215395SKevin Wolf  * qemu_opt_find()), but all of them are deleted if @del is true.
105072215395SKevin Wolf  *
1051baacf047SPaolo Bonzini  * TODO We'll want to use types appropriate for opt->desc->type, but
1052baacf047SPaolo Bonzini  * this is enough for now.
1053baacf047SPaolo Bonzini  */
qemu_opts_to_qdict_filtered(QemuOpts * opts,QDict * qdict,QemuOptsList * list,bool del)105472215395SKevin Wolf QDict *qemu_opts_to_qdict_filtered(QemuOpts *opts, QDict *qdict,
105572215395SKevin Wolf                                    QemuOptsList *list, bool del)
1056baacf047SPaolo Bonzini {
105772215395SKevin Wolf     QemuOpt *opt, *next;
1058baacf047SPaolo Bonzini 
1059baacf047SPaolo Bonzini     if (!qdict) {
1060baacf047SPaolo Bonzini         qdict = qdict_new();
1061baacf047SPaolo Bonzini     }
1062baacf047SPaolo Bonzini     if (opts->id) {
106346f5ac20SEric Blake         qdict_put_str(qdict, "id", opts->id);
1064baacf047SPaolo Bonzini     }
106572215395SKevin Wolf     QTAILQ_FOREACH_SAFE(opt, &opts->head, next, next) {
106672215395SKevin Wolf         if (list) {
106772215395SKevin Wolf             QemuOptDesc *desc;
106872215395SKevin Wolf             bool found = false;
106972215395SKevin Wolf             for (desc = list->desc; desc->name; desc++) {
107072215395SKevin Wolf                 if (!strcmp(desc->name, opt->name)) {
107172215395SKevin Wolf                     found = true;
107272215395SKevin Wolf                     break;
107372215395SKevin Wolf                 }
107472215395SKevin Wolf             }
107572215395SKevin Wolf             if (!found) {
107672215395SKevin Wolf                 continue;
107772215395SKevin Wolf             }
107872215395SKevin Wolf         }
107928934e0cSEric Blake         qdict_put_str(qdict, opt->name, opt->str);
108072215395SKevin Wolf         if (del) {
108172215395SKevin Wolf             qemu_opt_del(opt);
108272215395SKevin Wolf         }
1083baacf047SPaolo Bonzini     }
1084baacf047SPaolo Bonzini     return qdict;
1085baacf047SPaolo Bonzini }
1086baacf047SPaolo Bonzini 
108772215395SKevin Wolf /* Copy all options in a QemuOpts to the given QDict. See
108872215395SKevin Wolf  * qemu_opts_to_qdict_filtered() for details. */
qemu_opts_to_qdict(QemuOpts * opts,QDict * qdict)108972215395SKevin Wolf QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
109072215395SKevin Wolf {
109172215395SKevin Wolf     return qemu_opts_to_qdict_filtered(opts, qdict, NULL, false);
109272215395SKevin Wolf }
109372215395SKevin Wolf 
1094baacf047SPaolo Bonzini /* Validate parsed opts against descriptions where no
1095baacf047SPaolo Bonzini  * descriptions were provided in the QemuOptsList.
1096baacf047SPaolo Bonzini  */
qemu_opts_validate(QemuOpts * opts,const QemuOptDesc * desc,Error ** errp)1097c75d7f71SMarkus Armbruster bool qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp)
1098baacf047SPaolo Bonzini {
1099baacf047SPaolo Bonzini     QemuOpt *opt;
1100baacf047SPaolo Bonzini 
110145c53fe6SPaolo Bonzini     assert(opts_accepts_any(opts->list));
1102baacf047SPaolo Bonzini 
1103baacf047SPaolo Bonzini     QTAILQ_FOREACH(opt, &opts->head, next) {
1104baacf047SPaolo Bonzini         opt->desc = find_desc_by_name(desc, opt->name);
1105baacf047SPaolo Bonzini         if (!opt->desc) {
1106c6bd8c70SMarkus Armbruster             error_setg(errp, QERR_INVALID_PARAMETER, opt->name);
1107c75d7f71SMarkus Armbruster             return false;
1108baacf047SPaolo Bonzini         }
1109baacf047SPaolo Bonzini 
1110668f62ecSMarkus Armbruster         if (!qemu_opt_parse(opt, errp)) {
1111c75d7f71SMarkus Armbruster             return false;
1112baacf047SPaolo Bonzini         }
1113baacf047SPaolo Bonzini     }
1114c75d7f71SMarkus Armbruster 
1115c75d7f71SMarkus Armbruster     return true;
1116baacf047SPaolo Bonzini }
1117baacf047SPaolo Bonzini 
1118a4c7367fSMarkus Armbruster /**
111928d0de7aSMarkus Armbruster  * For each member of @list, call @func(@opaque, member, @errp).
1120a4c7367fSMarkus Armbruster  * Call it with the current location temporarily set to the member's.
112128d0de7aSMarkus Armbruster  * @func() may store an Error through @errp, but must return non-zero then.
1122a4c7367fSMarkus Armbruster  * When @func() returns non-zero, break the loop and return that value.
1123a4c7367fSMarkus Armbruster  * Return zero when the loop completes.
1124a4c7367fSMarkus Armbruster  */
qemu_opts_foreach(QemuOptsList * list,qemu_opts_loopfunc func,void * opaque,Error ** errp)1125a4c7367fSMarkus Armbruster int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func,
112628d0de7aSMarkus Armbruster                       void *opaque, Error **errp)
1127baacf047SPaolo Bonzini {
1128baacf047SPaolo Bonzini     Location loc;
1129*30648dd5SKevin Wolf     QemuOpts *opts, *next;
113037f32349SMarkus Armbruster     int rc = 0;
1131baacf047SPaolo Bonzini 
1132baacf047SPaolo Bonzini     loc_push_none(&loc);
1133*30648dd5SKevin Wolf     QTAILQ_FOREACH_SAFE(opts, &list->head, next, next) {
1134baacf047SPaolo Bonzini         loc_restore(&opts->loc);
113528d0de7aSMarkus Armbruster         rc = func(opaque, opts, errp);
1136a4c7367fSMarkus Armbruster         if (rc) {
113737f32349SMarkus Armbruster             break;
1138a4c7367fSMarkus Armbruster         }
113928d0de7aSMarkus Armbruster         assert(!errp || !*errp);
1140baacf047SPaolo Bonzini     }
1141baacf047SPaolo Bonzini     loc_pop(&loc);
114237f32349SMarkus Armbruster     return rc;
1143baacf047SPaolo Bonzini }
11448559e45eSChunyan Liu 
count_opts_list(QemuOptsList * list)11458559e45eSChunyan Liu static size_t count_opts_list(QemuOptsList *list)
11468559e45eSChunyan Liu {
11478559e45eSChunyan Liu     QemuOptDesc *desc = NULL;
11488559e45eSChunyan Liu     size_t num_opts = 0;
11498559e45eSChunyan Liu 
11508559e45eSChunyan Liu     if (!list) {
11518559e45eSChunyan Liu         return 0;
11528559e45eSChunyan Liu     }
11538559e45eSChunyan Liu 
11548559e45eSChunyan Liu     desc = list->desc;
11558559e45eSChunyan Liu     while (desc && desc->name) {
11568559e45eSChunyan Liu         num_opts++;
11578559e45eSChunyan Liu         desc++;
11588559e45eSChunyan Liu     }
11598559e45eSChunyan Liu 
11608559e45eSChunyan Liu     return num_opts;
11618559e45eSChunyan Liu }
11628559e45eSChunyan Liu 
qemu_opts_free(QemuOptsList * list)11638559e45eSChunyan Liu void qemu_opts_free(QemuOptsList *list)
11648559e45eSChunyan Liu {
11658559e45eSChunyan Liu     g_free(list);
11668559e45eSChunyan Liu }
1167a1097a26SChunyan Liu 
1168c282e1fdSChunyan Liu /* Realloc dst option list and append options from an option list (list)
1169c282e1fdSChunyan Liu  * to it. dst could be NULL or a malloced list.
117098d896d9SChunyan Liu  * The lifetime of dst must be shorter than the input list because the
117198d896d9SChunyan Liu  * QemuOptDesc->name, ->help, and ->def_value_str strings are shared.
1172a1097a26SChunyan Liu  */
qemu_opts_append(QemuOptsList * dst,QemuOptsList * list)1173a1097a26SChunyan Liu QemuOptsList *qemu_opts_append(QemuOptsList *dst,
1174c282e1fdSChunyan Liu                                QemuOptsList *list)
1175a1097a26SChunyan Liu {
1176a1097a26SChunyan Liu     size_t num_opts, num_dst_opts;
1177a1097a26SChunyan Liu     QemuOptDesc *desc;
1178a1097a26SChunyan Liu     bool need_init = false;
1179a7607150SMichal Privoznik     bool need_head_update;
1180a1097a26SChunyan Liu 
1181c282e1fdSChunyan Liu     if (!list) {
1182a1097a26SChunyan Liu         return dst;
1183a1097a26SChunyan Liu     }
1184a1097a26SChunyan Liu 
1185a1097a26SChunyan Liu     /* If dst is NULL, after realloc, some area of dst should be initialized
1186a1097a26SChunyan Liu      * before adding options to it.
1187a1097a26SChunyan Liu      */
1188a1097a26SChunyan Liu     if (!dst) {
1189a1097a26SChunyan Liu         need_init = true;
1190a7607150SMichal Privoznik         need_head_update = true;
1191a7607150SMichal Privoznik     } else {
1192a7607150SMichal Privoznik         /* Moreover, even if dst is not NULL, the realloc may move it to a
1193a7607150SMichal Privoznik          * different address in which case we may get a stale tail pointer
1194a7607150SMichal Privoznik          * in dst->head. */
1195a7607150SMichal Privoznik         need_head_update = QTAILQ_EMPTY(&dst->head);
1196a1097a26SChunyan Liu     }
1197a1097a26SChunyan Liu 
1198a1097a26SChunyan Liu     num_opts = count_opts_list(dst);
1199a1097a26SChunyan Liu     num_dst_opts = num_opts;
1200a1097a26SChunyan Liu     num_opts += count_opts_list(list);
1201a1097a26SChunyan Liu     dst = g_realloc(dst, sizeof(QemuOptsList) +
1202a1097a26SChunyan Liu                     (num_opts + 1) * sizeof(QemuOptDesc));
1203a1097a26SChunyan Liu     if (need_init) {
1204a1097a26SChunyan Liu         dst->name = NULL;
1205a1097a26SChunyan Liu         dst->implied_opt_name = NULL;
1206a1097a26SChunyan Liu         dst->merge_lists = false;
1207a1097a26SChunyan Liu     }
1208a7607150SMichal Privoznik     if (need_head_update) {
1209a7607150SMichal Privoznik         QTAILQ_INIT(&dst->head);
1210a7607150SMichal Privoznik     }
1211a1097a26SChunyan Liu     dst->desc[num_dst_opts].name = NULL;
1212a1097a26SChunyan Liu 
1213a1097a26SChunyan Liu     /* append list->desc to dst->desc */
1214a1097a26SChunyan Liu     if (list) {
1215a1097a26SChunyan Liu         desc = list->desc;
1216a1097a26SChunyan Liu         while (desc && desc->name) {
1217a1097a26SChunyan Liu             if (find_desc_by_name(dst->desc, desc->name) == NULL) {
121898d896d9SChunyan Liu                 dst->desc[num_dst_opts++] = *desc;
1219a1097a26SChunyan Liu                 dst->desc[num_dst_opts].name = NULL;
1220a1097a26SChunyan Liu             }
1221a1097a26SChunyan Liu             desc++;
1222a1097a26SChunyan Liu         }
1223a1097a26SChunyan Liu     }
1224a1097a26SChunyan Liu 
1225a1097a26SChunyan Liu     return dst;
1226a1097a26SChunyan Liu }
1227