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