xref: /openbmc/qemu/util/qemu-option.c (revision 1e0a7549e1f93112a2c0c08d95eb16b604d32cca)
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   */
get_opt_name(const char * p,char ** option,size_t len)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   */
get_opt_value(const char * p,char ** value)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  
parse_option_number(const char * name,const char * value,uint64_t * ret,Error ** errp)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  
find_desc_by_name(const QemuOptDesc * desc,const char * name)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  
find_default_by_name(QemuOpts * opts,const char * name)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  
parse_option_size(const char * name,const char * value,uint64_t * ret,Error ** errp)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  
opt_type_to_string(enum QemuOptType type)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   */
qemu_opts_print_help(QemuOptsList * list,bool print_caption)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  
qemu_opt_find(QemuOpts * opts,const char * name)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  
qemu_opt_del(QemuOpt * opt)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   */
qemu_opt_del_all(QemuOpts * opts,const char * name)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  
qemu_opt_get(QemuOpts * opts,const char * name)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  
qemu_opt_iter_init(QemuOptsIter * iter,QemuOpts * opts,const char * name)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  
qemu_opt_iter_next(QemuOptsIter * iter)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   */
qemu_opt_get_del(QemuOpts * opts,const char * name)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  
qemu_opt_has_help_opt(QemuOpts * opts)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  
qemu_opt_get_bool_helper(QemuOpts * opts,const char * name,bool defval,bool del)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  
qemu_opt_get_bool(QemuOpts * opts,const char * name,bool defval)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  
qemu_opt_get_bool_del(QemuOpts * opts,const char * name,bool defval)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  
qemu_opt_get_number_helper(QemuOpts * opts,const char * name,uint64_t defval,bool del)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  
qemu_opt_get_number(QemuOpts * opts,const char * name,uint64_t defval)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  
qemu_opt_get_number_del(QemuOpts * opts,const char * name,uint64_t defval)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  
qemu_opt_get_size_helper(QemuOpts * opts,const char * name,uint64_t defval,bool del)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  
qemu_opt_get_size(QemuOpts * opts,const char * name,uint64_t defval)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  
qemu_opt_get_size_del(QemuOpts * opts,const char * name,uint64_t defval)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  
qemu_opt_parse(QemuOpt * opt,Error ** errp)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  
opts_accepts_any(const QemuOptsList * list)463  static bool opts_accepts_any(const QemuOptsList *list)
464  {
465      return list->desc[0].name == NULL;
466  }
467  
qemu_opt_unset(QemuOpts * opts,const char * name)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  
opt_create(QemuOpts * opts,const char * name,char * value)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  
opt_validate(QemuOpt * opt,Error ** errp)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  
qemu_opt_set(QemuOpts * opts,const char * name,const char * value,Error ** errp)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  
qemu_opt_set_bool(QemuOpts * opts,const char * name,bool val,Error ** errp)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  
qemu_opt_set_number(QemuOpts * opts,const char * name,int64_t val,Error ** errp)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   */
qemu_opt_foreach(QemuOpts * opts,qemu_opt_loopfunc func,void * opaque,Error ** errp)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  
qemu_opts_find(QemuOptsList * list,const char * id)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  
qemu_opts_create(QemuOptsList * list,const char * id,int fail_if_exists,Error ** errp)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  
qemu_opts_reset(QemuOptsList * list)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  
qemu_opts_loc_restore(QemuOpts * opts)655  void qemu_opts_loc_restore(QemuOpts *opts)
656  {
657      loc_restore(&opts->loc);
658  }
659  
qemu_opts_id(QemuOpts * opts)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 */
qemu_opts_set_id(QemuOpts * opts,char * id)666  void qemu_opts_set_id(QemuOpts *opts, char *id)
667  {
668      opts->id = id;
669  }
670  
qemu_opts_del(QemuOpts * opts)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 */
escaped_print(const char * 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  
qemu_opts_print(QemuOpts * opts,const char * separator)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  
get_opt_name_value(const char * params,const char * firstname,bool warn_on_flag,bool * help_wanted,char ** name,char ** value)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  
opts_do_parse(QemuOpts * opts,const char * params,const char * firstname,bool warn_on_flag,bool * help_wanted,Error ** errp)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  
opts_parse_id(const char * params)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  
has_help_option(const char * params)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   */
qemu_opts_do_parse(QemuOpts * opts,const char * params,const char * firstname,Error ** errp)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  
opts_parse(QemuOptsList * list,const char * params,bool permit_abbrev,bool warn_on_flag,bool * help_wanted,Error ** errp)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   */
qemu_opts_parse(QemuOptsList * list,const char * params,bool permit_abbrev,Error ** errp)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   */
qemu_opts_parse_noisily(QemuOptsList * list,const char * params,bool permit_abbrev)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  
qemu_opts_from_qdict_entry(QemuOpts * opts,const QDictEntry * entry,Error ** errp)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   */
qemu_opts_from_qdict(QemuOptsList * list,const QDict * qdict,Error ** errp)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   */
qemu_opts_absorb_qdict(QemuOpts * opts,QDict * qdict,Error ** errp)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   */
qemu_opts_to_qdict_filtered(QemuOpts * opts,QDict * qdict,QemuOptsList * list,bool del)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. */
qemu_opts_to_qdict(QemuOpts * opts,QDict * qdict)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   */
qemu_opts_validate(QemuOpts * opts,const QemuOptDesc * desc,Error ** errp)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   */
qemu_opts_foreach(QemuOptsList * list,qemu_opts_loopfunc func,void * opaque,Error ** errp)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  
count_opts_list(QemuOptsList * list)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  
qemu_opts_free(QemuOptsList * list)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   */
qemu_opts_append(QemuOptsList * dst,QemuOptsList * list)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