xref: /openbmc/qemu/util/qemu-config.c (revision 13b1e9667737132440f4d500c31cb69320c6b15a)
1  #include "qemu/osdep.h"
2  #include "block/qdict.h" /* for qdict_extract_subqdict() */
3  #include "qapi/error.h"
4  #include "qapi/qmp/qdict.h"
5  #include "qapi/qmp/qlist.h"
6  #include "qemu/error-report.h"
7  #include "qemu/option.h"
8  #include "qemu/config-file.h"
9  
10  QemuOptsList *vm_config_groups[48];
11  QemuOptsList *drive_config_groups[5];
12  
find_list(QemuOptsList ** lists,const char * group,Error ** errp)13  static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
14                                 Error **errp)
15  {
16      int i;
17  
18      qemu_load_module_for_opts(group);
19      for (i = 0; lists[i] != NULL; i++) {
20          if (strcmp(lists[i]->name, group) == 0)
21              break;
22      }
23      if (lists[i] == NULL) {
24          error_setg(errp, "There is no option group '%s'", group);
25      }
26      return lists[i];
27  }
28  
qemu_find_opts(const char * group)29  QemuOptsList *qemu_find_opts(const char *group)
30  {
31      QemuOptsList *ret;
32      Error *local_err = NULL;
33  
34      ret = find_list(vm_config_groups, group, &local_err);
35      if (local_err) {
36          error_report_err(local_err);
37      }
38  
39      return ret;
40  }
41  
qemu_find_opts_singleton(const char * group)42  QemuOpts *qemu_find_opts_singleton(const char *group)
43  {
44      QemuOptsList *list;
45      QemuOpts *opts;
46  
47      list = qemu_find_opts(group);
48      assert(list);
49      opts = qemu_opts_find(list, NULL);
50      if (!opts) {
51          opts = qemu_opts_create(list, NULL, 0, &error_abort);
52      }
53      return opts;
54  }
55  
qemu_find_opts_err(const char * group,Error ** errp)56  QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
57  {
58      return find_list(vm_config_groups, group, errp);
59  }
60  
qemu_add_drive_opts(QemuOptsList * list)61  void qemu_add_drive_opts(QemuOptsList *list)
62  {
63      int entries, i;
64  
65      entries = ARRAY_SIZE(drive_config_groups);
66      entries--; /* keep list NULL terminated */
67      for (i = 0; i < entries; i++) {
68          if (drive_config_groups[i] == NULL) {
69              drive_config_groups[i] = list;
70              return;
71          }
72      }
73      fprintf(stderr, "ran out of space in drive_config_groups");
74      abort();
75  }
76  
qemu_add_opts(QemuOptsList * list)77  void qemu_add_opts(QemuOptsList *list)
78  {
79      int entries, i;
80  
81      entries = ARRAY_SIZE(vm_config_groups);
82      entries--; /* keep list NULL terminated */
83      for (i = 0; i < entries; i++) {
84          if (vm_config_groups[i] == NULL) {
85              vm_config_groups[i] = list;
86              return;
87          }
88      }
89      fprintf(stderr, "ran out of space in vm_config_groups");
90      abort();
91  }
92  
93  /* Returns number of config groups on success, -errno on error */
qemu_config_foreach(FILE * fp,QEMUConfigCB * cb,void * opaque,const char * fname,Error ** errp)94  static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque,
95                                 const char *fname, Error **errp)
96  {
97      ERRP_GUARD();
98      char line[1024], prev_group[64], group[64], arg[64], value[1024];
99      Location loc;
100      QDict *qdict = NULL;
101      int res = -EINVAL, lno = 0;
102      int count = 0;
103  
104      loc_push_none(&loc);
105      while (fgets(line, sizeof(line), fp) != NULL) {
106          ++lno;
107          if (line[0] == '\n') {
108              /* skip empty lines */
109              continue;
110          }
111          if (line[0] == '#') {
112              /* comment */
113              continue;
114          }
115          if (line[0] == '[') {
116              QDict *prev = qdict;
117              if (sscanf(line, "[%63s \"%63[^\"]\"]", group, value) == 2) {
118                  qdict = qdict_new();
119                  qdict_put_str(qdict, "id", value);
120                  count++;
121              } else if (sscanf(line, "[%63[^]]]", group) == 1) {
122                  qdict = qdict_new();
123                  count++;
124              }
125              if (qdict != prev) {
126                  if (prev) {
127                      cb(prev_group, prev, opaque, errp);
128                      qobject_unref(prev);
129                      if (*errp) {
130                          goto out;
131                      }
132                  }
133                  strcpy(prev_group, group);
134                  continue;
135              }
136          }
137          loc_set_file(fname, lno);
138          value[0] = '\0';
139          if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2 ||
140              sscanf(line, " %63s = \"\"", arg) == 1) {
141              /* arg = value */
142              if (qdict == NULL) {
143                  error_setg(errp, "no group defined");
144                  goto out;
145              }
146              qdict_put_str(qdict, arg, value);
147              continue;
148          }
149          error_setg(errp, "parse error");
150          goto out;
151      }
152      if (ferror(fp)) {
153          loc_pop(&loc);
154          error_setg_errno(errp, errno, "Cannot read config file");
155          goto out_no_loc;
156      }
157      res = count;
158      if (qdict) {
159          cb(group, qdict, opaque, errp);
160      }
161  out:
162      loc_pop(&loc);
163  out_no_loc:
164      qobject_unref(qdict);
165      return res;
166  }
167  
qemu_config_do_parse(const char * group,QDict * qdict,void * opaque,Error ** errp)168  void qemu_config_do_parse(const char *group, QDict *qdict, void *opaque, Error **errp)
169  {
170      QemuOptsList **lists = opaque;
171      QemuOptsList *list;
172  
173      list = find_list(lists, group, errp);
174      if (!list) {
175          return;
176      }
177  
178      qemu_opts_from_qdict(list, qdict, errp);
179  }
180  
qemu_config_parse(FILE * fp,QemuOptsList ** lists,const char * fname,Error ** errp)181  int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp)
182  {
183      return qemu_config_foreach(fp, qemu_config_do_parse, lists, fname, errp);
184  }
185  
qemu_read_config_file(const char * filename,QEMUConfigCB * cb,Error ** errp)186  int qemu_read_config_file(const char *filename, QEMUConfigCB *cb, Error **errp)
187  {
188      FILE *f = fopen(filename, "r");
189      int ret;
190  
191      if (f == NULL) {
192          error_setg_file_open(errp, errno, filename);
193          return -errno;
194      }
195  
196      ret = qemu_config_foreach(f, cb, vm_config_groups, filename, errp);
197      fclose(f);
198      return ret;
199  }
200  
config_parse_qdict_section(QDict * options,QemuOptsList * opts,Error ** errp)201  static bool config_parse_qdict_section(QDict *options, QemuOptsList *opts,
202                                         Error **errp)
203  {
204      QemuOpts *subopts;
205      g_autoptr(QDict) subqdict = NULL;
206      g_autoptr(QList) list = NULL;
207      size_t orig_size, enum_size;
208      char *prefix;
209  
210      prefix = g_strdup_printf("%s.", opts->name);
211      qdict_extract_subqdict(options, &subqdict, prefix);
212      g_free(prefix);
213      orig_size = qdict_size(subqdict);
214      if (!orig_size) {
215          return true;
216      }
217  
218      subopts = qemu_opts_create(opts, NULL, 0, errp);
219      if (!subopts) {
220          return false;
221      }
222  
223      if (!qemu_opts_absorb_qdict(subopts, subqdict, errp)) {
224          return false;
225      }
226  
227      enum_size = qdict_size(subqdict);
228      if (enum_size < orig_size && enum_size) {
229          error_setg(errp, "Unknown option '%s' for [%s]",
230                     qdict_first(subqdict)->key, opts->name);
231          return false;
232      }
233  
234      if (enum_size) {
235          /* Multiple, enumerated sections */
236          QListEntry *list_entry;
237          unsigned i = 0;
238  
239          /* Not required anymore */
240          qemu_opts_del(subopts);
241  
242          qdict_array_split(subqdict, &list);
243          if (qdict_size(subqdict)) {
244              error_setg(errp, "Unused option '%s' for [%s]",
245                         qdict_first(subqdict)->key, opts->name);
246              return false;
247          }
248  
249          QLIST_FOREACH_ENTRY(list, list_entry) {
250              QDict *section = qobject_to(QDict, qlist_entry_obj(list_entry));
251              char *opt_name;
252  
253              if (!section) {
254                  error_setg(errp, "[%s] section (index %u) does not consist of "
255                             "keys", opts->name, i);
256                  return false;
257              }
258  
259              opt_name = g_strdup_printf("%s.%u", opts->name, i++);
260              subopts = qemu_opts_create(opts, opt_name, 1, errp);
261              g_free(opt_name);
262              if (!subopts) {
263                  return false;
264              }
265  
266              if (!qemu_opts_absorb_qdict(subopts, section, errp)) {
267                  qemu_opts_del(subopts);
268                  return false;
269              }
270  
271              if (qdict_size(section)) {
272                  error_setg(errp, "[%s] section doesn't support the option '%s'",
273                             opts->name, qdict_first(section)->key);
274                  qemu_opts_del(subopts);
275                  return false;
276              }
277          }
278      }
279  
280      return true;
281  }
282  
qemu_config_parse_qdict(QDict * options,QemuOptsList ** lists,Error ** errp)283  bool qemu_config_parse_qdict(QDict *options, QemuOptsList **lists,
284                               Error **errp)
285  {
286      int i;
287  
288      for (i = 0; lists[i]; i++) {
289          if (!config_parse_qdict_section(options, lists[i], errp)) {
290              return false;
291          }
292      }
293  
294      return true;
295  }
296