1 #include "qemu/osdep.h" 2 #include "block/qdict.h" /* for qdict_extract_subqdict() */ 3 #include "qapi/error.h" 4 #include "qapi/qapi-commands-misc.h" 5 #include "qapi/qmp/qdict.h" 6 #include "qapi/qmp/qlist.h" 7 #include "qemu/error-report.h" 8 #include "qemu/option.h" 9 #include "qemu/config-file.h" 10 #include "hw/boards.h" 11 12 static QemuOptsList *vm_config_groups[48]; 13 static QemuOptsList *drive_config_groups[5]; 14 15 static QemuOptsList *find_list(QemuOptsList **lists, const char *group, 16 Error **errp) 17 { 18 int i; 19 20 qemu_load_module_for_opts(group); 21 for (i = 0; lists[i] != NULL; i++) { 22 if (strcmp(lists[i]->name, group) == 0) 23 break; 24 } 25 if (lists[i] == NULL) { 26 error_setg(errp, "There is no option group '%s'", group); 27 } 28 return lists[i]; 29 } 30 31 QemuOptsList *qemu_find_opts(const char *group) 32 { 33 QemuOptsList *ret; 34 Error *local_err = NULL; 35 36 ret = find_list(vm_config_groups, group, &local_err); 37 if (local_err) { 38 error_report_err(local_err); 39 } 40 41 return ret; 42 } 43 44 QemuOpts *qemu_find_opts_singleton(const char *group) 45 { 46 QemuOptsList *list; 47 QemuOpts *opts; 48 49 list = qemu_find_opts(group); 50 assert(list); 51 opts = qemu_opts_find(list, NULL); 52 if (!opts) { 53 opts = qemu_opts_create(list, NULL, 0, &error_abort); 54 } 55 return opts; 56 } 57 58 static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc) 59 { 60 CommandLineParameterInfoList *param_list = NULL; 61 CommandLineParameterInfo *info; 62 int i; 63 64 for (i = 0; desc[i].name != NULL; i++) { 65 info = g_malloc0(sizeof(*info)); 66 info->name = g_strdup(desc[i].name); 67 68 switch (desc[i].type) { 69 case QEMU_OPT_STRING: 70 info->type = COMMAND_LINE_PARAMETER_TYPE_STRING; 71 break; 72 case QEMU_OPT_BOOL: 73 info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN; 74 break; 75 case QEMU_OPT_NUMBER: 76 info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER; 77 break; 78 case QEMU_OPT_SIZE: 79 info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE; 80 break; 81 } 82 83 info->help = g_strdup(desc[i].help); 84 info->q_default = g_strdup(desc[i].def_value_str); 85 86 QAPI_LIST_PREPEND(param_list, info); 87 } 88 89 return param_list; 90 } 91 92 /* remove repeated entry from the info list */ 93 static void cleanup_infolist(CommandLineParameterInfoList *head) 94 { 95 CommandLineParameterInfoList *pre_entry, *cur, *del_entry; 96 97 cur = head; 98 while (cur->next) { 99 pre_entry = head; 100 while (pre_entry != cur->next) { 101 if (!strcmp(pre_entry->value->name, cur->next->value->name)) { 102 del_entry = cur->next; 103 cur->next = cur->next->next; 104 del_entry->next = NULL; 105 qapi_free_CommandLineParameterInfoList(del_entry); 106 break; 107 } 108 pre_entry = pre_entry->next; 109 } 110 cur = cur->next; 111 } 112 } 113 114 /* merge the description items of two parameter infolists */ 115 static void connect_infolist(CommandLineParameterInfoList *head, 116 CommandLineParameterInfoList *new) 117 { 118 CommandLineParameterInfoList *cur; 119 120 cur = head; 121 while (cur->next) { 122 cur = cur->next; 123 } 124 cur->next = new; 125 } 126 127 /* access all the local QemuOptsLists for drive option */ 128 static CommandLineParameterInfoList *get_drive_infolist(void) 129 { 130 CommandLineParameterInfoList *head = NULL, *cur; 131 int i; 132 133 for (i = 0; drive_config_groups[i] != NULL; i++) { 134 if (!head) { 135 head = query_option_descs(drive_config_groups[i]->desc); 136 } else { 137 cur = query_option_descs(drive_config_groups[i]->desc); 138 connect_infolist(head, cur); 139 } 140 } 141 cleanup_infolist(head); 142 143 return head; 144 } 145 146 static CommandLineParameterInfo *objprop_to_cmdline_prop(ObjectProperty *prop) 147 { 148 CommandLineParameterInfo *info; 149 150 info = g_malloc0(sizeof(*info)); 151 info->name = g_strdup(prop->name); 152 153 if (g_str_equal(prop->type, "bool") || g_str_equal(prop->type, "OnOffAuto")) { 154 info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN; 155 } else if (g_str_equal(prop->type, "int")) { 156 info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER; 157 } else if (g_str_equal(prop->type, "size")) { 158 info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE; 159 } else { 160 info->type = COMMAND_LINE_PARAMETER_TYPE_STRING; 161 } 162 163 if (prop->description) { 164 info->help = g_strdup(prop->description); 165 } 166 167 return info; 168 } 169 170 static CommandLineParameterInfoList *query_all_machine_properties(void) 171 { 172 CommandLineParameterInfoList *params = NULL, *clpiter; 173 CommandLineParameterInfo *info; 174 GSList *machines, *curr_mach; 175 ObjectPropertyIterator op_iter; 176 ObjectProperty *prop; 177 bool is_new; 178 179 machines = object_class_get_list(TYPE_MACHINE, false); 180 assert(machines); 181 182 /* Loop over all machine classes */ 183 for (curr_mach = machines; curr_mach; curr_mach = curr_mach->next) { 184 object_class_property_iter_init(&op_iter, curr_mach->data); 185 /* ... and over the properties of each machine: */ 186 while ((prop = object_property_iter_next(&op_iter))) { 187 if (!prop->set) { 188 continue; 189 } 190 /* 191 * Check whether the property has already been put into the list 192 * (via another machine class) 193 */ 194 is_new = true; 195 for (clpiter = params; clpiter != NULL; clpiter = clpiter->next) { 196 if (g_str_equal(clpiter->value->name, prop->name)) { 197 is_new = false; 198 break; 199 } 200 } 201 /* If it hasn't been added before, add it now to the list */ 202 if (is_new) { 203 info = objprop_to_cmdline_prop(prop); 204 QAPI_LIST_PREPEND(params, info); 205 } 206 } 207 } 208 209 g_slist_free(machines); 210 211 /* Add entry for the "type" parameter */ 212 info = g_malloc0(sizeof(*info)); 213 info->name = g_strdup("type"); 214 info->type = COMMAND_LINE_PARAMETER_TYPE_STRING; 215 info->help = g_strdup("machine type"); 216 QAPI_LIST_PREPEND(params, info); 217 218 return params; 219 } 220 221 CommandLineOptionInfoList *qmp_query_command_line_options(const char *option, 222 Error **errp) 223 { 224 CommandLineOptionInfoList *conf_list = NULL; 225 CommandLineOptionInfo *info; 226 int i; 227 228 for (i = 0; vm_config_groups[i] != NULL; i++) { 229 if (!option || !strcmp(option, vm_config_groups[i]->name)) { 230 info = g_malloc0(sizeof(*info)); 231 info->option = g_strdup(vm_config_groups[i]->name); 232 if (!strcmp("drive", vm_config_groups[i]->name)) { 233 info->parameters = get_drive_infolist(); 234 } else { 235 info->parameters = 236 query_option_descs(vm_config_groups[i]->desc); 237 } 238 QAPI_LIST_PREPEND(conf_list, info); 239 } 240 } 241 242 if (!option || !strcmp(option, "machine")) { 243 info = g_malloc0(sizeof(*info)); 244 info->option = g_strdup("machine"); 245 info->parameters = query_all_machine_properties(); 246 QAPI_LIST_PREPEND(conf_list, info); 247 } 248 249 if (conf_list == NULL) { 250 error_setg(errp, "invalid option name: %s", option); 251 } 252 253 return conf_list; 254 } 255 256 QemuOptsList *qemu_find_opts_err(const char *group, Error **errp) 257 { 258 return find_list(vm_config_groups, group, errp); 259 } 260 261 void qemu_add_drive_opts(QemuOptsList *list) 262 { 263 int entries, i; 264 265 entries = ARRAY_SIZE(drive_config_groups); 266 entries--; /* keep list NULL terminated */ 267 for (i = 0; i < entries; i++) { 268 if (drive_config_groups[i] == NULL) { 269 drive_config_groups[i] = list; 270 return; 271 } 272 } 273 fprintf(stderr, "ran out of space in drive_config_groups"); 274 abort(); 275 } 276 277 void qemu_add_opts(QemuOptsList *list) 278 { 279 int entries, i; 280 281 entries = ARRAY_SIZE(vm_config_groups); 282 entries--; /* keep list NULL terminated */ 283 for (i = 0; i < entries; i++) { 284 if (vm_config_groups[i] == NULL) { 285 vm_config_groups[i] = list; 286 return; 287 } 288 } 289 fprintf(stderr, "ran out of space in vm_config_groups"); 290 abort(); 291 } 292 293 /* Returns number of config groups on success, -errno on error */ 294 static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque, 295 const char *fname, Error **errp) 296 { 297 ERRP_GUARD(); 298 char line[1024], prev_group[64], group[64], arg[64], value[1024]; 299 Location loc; 300 QDict *qdict = NULL; 301 int res = -EINVAL, lno = 0; 302 int count = 0; 303 304 loc_push_none(&loc); 305 while (fgets(line, sizeof(line), fp) != NULL) { 306 ++lno; 307 if (line[0] == '\n') { 308 /* skip empty lines */ 309 continue; 310 } 311 if (line[0] == '#') { 312 /* comment */ 313 continue; 314 } 315 if (line[0] == '[') { 316 QDict *prev = qdict; 317 if (sscanf(line, "[%63s \"%63[^\"]\"]", group, value) == 2) { 318 qdict = qdict_new(); 319 qdict_put_str(qdict, "id", value); 320 count++; 321 } else if (sscanf(line, "[%63[^]]]", group) == 1) { 322 qdict = qdict_new(); 323 count++; 324 } 325 if (qdict != prev) { 326 if (prev) { 327 cb(prev_group, prev, opaque, errp); 328 qobject_unref(prev); 329 if (*errp) { 330 goto out; 331 } 332 } 333 strcpy(prev_group, group); 334 continue; 335 } 336 } 337 loc_set_file(fname, lno); 338 value[0] = '\0'; 339 if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2 || 340 sscanf(line, " %63s = \"\"", arg) == 1) { 341 /* arg = value */ 342 if (qdict == NULL) { 343 error_setg(errp, "no group defined"); 344 goto out; 345 } 346 qdict_put_str(qdict, arg, value); 347 continue; 348 } 349 error_setg(errp, "parse error"); 350 goto out; 351 } 352 if (ferror(fp)) { 353 loc_pop(&loc); 354 error_setg_errno(errp, errno, "Cannot read config file"); 355 goto out_no_loc; 356 } 357 res = count; 358 if (qdict) { 359 cb(group, qdict, opaque, errp); 360 } 361 out: 362 loc_pop(&loc); 363 out_no_loc: 364 qobject_unref(qdict); 365 return res; 366 } 367 368 void qemu_config_do_parse(const char *group, QDict *qdict, void *opaque, Error **errp) 369 { 370 QemuOptsList **lists = opaque; 371 QemuOptsList *list; 372 373 list = find_list(lists, group, errp); 374 if (!list) { 375 return; 376 } 377 378 qemu_opts_from_qdict(list, qdict, errp); 379 } 380 381 int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp) 382 { 383 return qemu_config_foreach(fp, qemu_config_do_parse, lists, fname, errp); 384 } 385 386 int qemu_read_config_file(const char *filename, QEMUConfigCB *cb, Error **errp) 387 { 388 FILE *f = fopen(filename, "r"); 389 int ret; 390 391 if (f == NULL) { 392 error_setg_file_open(errp, errno, filename); 393 return -errno; 394 } 395 396 ret = qemu_config_foreach(f, cb, vm_config_groups, filename, errp); 397 fclose(f); 398 return ret; 399 } 400 401 static bool config_parse_qdict_section(QDict *options, QemuOptsList *opts, 402 Error **errp) 403 { 404 QemuOpts *subopts; 405 g_autoptr(QDict) subqdict = NULL; 406 g_autoptr(QList) list = NULL; 407 size_t orig_size, enum_size; 408 char *prefix; 409 410 prefix = g_strdup_printf("%s.", opts->name); 411 qdict_extract_subqdict(options, &subqdict, prefix); 412 g_free(prefix); 413 orig_size = qdict_size(subqdict); 414 if (!orig_size) { 415 return true; 416 } 417 418 subopts = qemu_opts_create(opts, NULL, 0, errp); 419 if (!subopts) { 420 return false; 421 } 422 423 if (!qemu_opts_absorb_qdict(subopts, subqdict, errp)) { 424 return false; 425 } 426 427 enum_size = qdict_size(subqdict); 428 if (enum_size < orig_size && enum_size) { 429 error_setg(errp, "Unknown option '%s' for [%s]", 430 qdict_first(subqdict)->key, opts->name); 431 return false; 432 } 433 434 if (enum_size) { 435 /* Multiple, enumerated sections */ 436 QListEntry *list_entry; 437 unsigned i = 0; 438 439 /* Not required anymore */ 440 qemu_opts_del(subopts); 441 442 qdict_array_split(subqdict, &list); 443 if (qdict_size(subqdict)) { 444 error_setg(errp, "Unused option '%s' for [%s]", 445 qdict_first(subqdict)->key, opts->name); 446 return false; 447 } 448 449 QLIST_FOREACH_ENTRY(list, list_entry) { 450 QDict *section = qobject_to(QDict, qlist_entry_obj(list_entry)); 451 char *opt_name; 452 453 if (!section) { 454 error_setg(errp, "[%s] section (index %u) does not consist of " 455 "keys", opts->name, i); 456 return false; 457 } 458 459 opt_name = g_strdup_printf("%s.%u", opts->name, i++); 460 subopts = qemu_opts_create(opts, opt_name, 1, errp); 461 g_free(opt_name); 462 if (!subopts) { 463 return false; 464 } 465 466 if (!qemu_opts_absorb_qdict(subopts, section, errp)) { 467 qemu_opts_del(subopts); 468 return false; 469 } 470 471 if (qdict_size(section)) { 472 error_setg(errp, "[%s] section doesn't support the option '%s'", 473 opts->name, qdict_first(section)->key); 474 qemu_opts_del(subopts); 475 return false; 476 } 477 } 478 } 479 480 return true; 481 } 482 483 bool qemu_config_parse_qdict(QDict *options, QemuOptsList **lists, 484 Error **errp) 485 { 486 int i; 487 488 for (i = 0; lists[i]; i++) { 489 if (!config_parse_qdict_section(options, lists[i], errp)) { 490 return false; 491 } 492 } 493 494 return true; 495 } 496