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 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 /* restore machine options that are now machine's properties */ 147 static QemuOptsList machine_opts = { 148 .merge_lists = true, 149 .head = QTAILQ_HEAD_INITIALIZER(machine_opts.head), 150 .desc = { 151 { 152 .name = "type", 153 .type = QEMU_OPT_STRING, 154 .help = "emulated machine" 155 },{ 156 .name = "accel", 157 .type = QEMU_OPT_STRING, 158 .help = "accelerator list", 159 },{ 160 .name = "kernel_irqchip", 161 .type = QEMU_OPT_BOOL, 162 .help = "use KVM in-kernel irqchip", 163 },{ 164 .name = "kvm_shadow_mem", 165 .type = QEMU_OPT_SIZE, 166 .help = "KVM shadow MMU size", 167 },{ 168 .name = "kernel", 169 .type = QEMU_OPT_STRING, 170 .help = "Linux kernel image file", 171 },{ 172 .name = "initrd", 173 .type = QEMU_OPT_STRING, 174 .help = "Linux initial ramdisk file", 175 },{ 176 .name = "append", 177 .type = QEMU_OPT_STRING, 178 .help = "Linux kernel command line", 179 },{ 180 .name = "dtb", 181 .type = QEMU_OPT_STRING, 182 .help = "Linux kernel device tree file", 183 },{ 184 .name = "dumpdtb", 185 .type = QEMU_OPT_STRING, 186 .help = "Dump current dtb to a file and quit", 187 },{ 188 .name = "phandle_start", 189 .type = QEMU_OPT_NUMBER, 190 .help = "The first phandle ID we may generate dynamically", 191 },{ 192 .name = "dt_compatible", 193 .type = QEMU_OPT_STRING, 194 .help = "Overrides the \"compatible\" property of the dt root node", 195 },{ 196 .name = "dump-guest-core", 197 .type = QEMU_OPT_BOOL, 198 .help = "Include guest memory in a core dump", 199 },{ 200 .name = "mem-merge", 201 .type = QEMU_OPT_BOOL, 202 .help = "enable/disable memory merge support", 203 },{ 204 .name = "usb", 205 .type = QEMU_OPT_BOOL, 206 .help = "Set on/off to enable/disable usb", 207 },{ 208 .name = "firmware", 209 .type = QEMU_OPT_STRING, 210 .help = "firmware image", 211 },{ 212 .name = "iommu", 213 .type = QEMU_OPT_BOOL, 214 .help = "Set on/off to enable/disable Intel IOMMU (VT-d)", 215 },{ 216 .name = "suppress-vmdesc", 217 .type = QEMU_OPT_BOOL, 218 .help = "Set on to disable self-describing migration", 219 },{ 220 .name = "aes-key-wrap", 221 .type = QEMU_OPT_BOOL, 222 .help = "enable/disable AES key wrapping using the CPACF wrapping key", 223 },{ 224 .name = "dea-key-wrap", 225 .type = QEMU_OPT_BOOL, 226 .help = "enable/disable DEA key wrapping using the CPACF wrapping key", 227 },{ 228 .name = "loadparm", 229 .type = QEMU_OPT_STRING, 230 .help = "Up to 8 chars in set of [A-Za-z0-9. ](lower case chars" 231 " converted to upper case) to pass to machine" 232 " loader, boot manager, and guest kernel", 233 }, 234 { /* End of list */ } 235 } 236 }; 237 238 CommandLineOptionInfoList *qmp_query_command_line_options(const char *option, 239 Error **errp) 240 { 241 CommandLineOptionInfoList *conf_list = NULL; 242 CommandLineOptionInfo *info; 243 int i; 244 245 for (i = 0; vm_config_groups[i] != NULL; i++) { 246 if (!option || !strcmp(option, vm_config_groups[i]->name)) { 247 info = g_malloc0(sizeof(*info)); 248 info->option = g_strdup(vm_config_groups[i]->name); 249 if (!strcmp("drive", vm_config_groups[i]->name)) { 250 info->parameters = get_drive_infolist(); 251 } else { 252 info->parameters = 253 query_option_descs(vm_config_groups[i]->desc); 254 } 255 QAPI_LIST_PREPEND(conf_list, info); 256 } 257 } 258 259 if (!option || !strcmp(option, "machine")) { 260 info = g_malloc0(sizeof(*info)); 261 info->option = g_strdup("machine"); 262 info->parameters = query_option_descs(machine_opts.desc); 263 QAPI_LIST_PREPEND(conf_list, info); 264 } 265 266 if (conf_list == NULL) { 267 error_setg(errp, "invalid option name: %s", option); 268 } 269 270 return conf_list; 271 } 272 273 QemuOptsList *qemu_find_opts_err(const char *group, Error **errp) 274 { 275 return find_list(vm_config_groups, group, errp); 276 } 277 278 void qemu_add_drive_opts(QemuOptsList *list) 279 { 280 int entries, i; 281 282 entries = ARRAY_SIZE(drive_config_groups); 283 entries--; /* keep list NULL terminated */ 284 for (i = 0; i < entries; i++) { 285 if (drive_config_groups[i] == NULL) { 286 drive_config_groups[i] = list; 287 return; 288 } 289 } 290 fprintf(stderr, "ran out of space in drive_config_groups"); 291 abort(); 292 } 293 294 void qemu_add_opts(QemuOptsList *list) 295 { 296 int entries, i; 297 298 entries = ARRAY_SIZE(vm_config_groups); 299 entries--; /* keep list NULL terminated */ 300 for (i = 0; i < entries; i++) { 301 if (vm_config_groups[i] == NULL) { 302 vm_config_groups[i] = list; 303 return; 304 } 305 } 306 fprintf(stderr, "ran out of space in vm_config_groups"); 307 abort(); 308 } 309 310 /* Returns number of config groups on success, -errno on error */ 311 static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque, 312 const char *fname, Error **errp) 313 { 314 char line[1024], prev_group[64], group[64], arg[64], value[1024]; 315 Location loc; 316 Error *local_err = NULL; 317 QDict *qdict = NULL; 318 int res = -EINVAL, lno = 0; 319 int count = 0; 320 321 loc_push_none(&loc); 322 while (fgets(line, sizeof(line), fp) != NULL) { 323 ++lno; 324 if (line[0] == '\n') { 325 /* skip empty lines */ 326 continue; 327 } 328 if (line[0] == '#') { 329 /* comment */ 330 continue; 331 } 332 if (line[0] == '[') { 333 QDict *prev = qdict; 334 if (sscanf(line, "[%63s \"%63[^\"]\"]", group, value) == 2) { 335 qdict = qdict_new(); 336 qdict_put_str(qdict, "id", value); 337 count++; 338 } else if (sscanf(line, "[%63[^]]]", group) == 1) { 339 qdict = qdict_new(); 340 count++; 341 } 342 if (qdict != prev) { 343 if (prev) { 344 cb(prev_group, prev, opaque, &local_err); 345 qobject_unref(prev); 346 if (local_err) { 347 error_propagate(errp, local_err); 348 goto out; 349 } 350 } 351 strcpy(prev_group, group); 352 continue; 353 } 354 } 355 loc_set_file(fname, lno); 356 value[0] = '\0'; 357 if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2 || 358 sscanf(line, " %63s = \"\"", arg) == 1) { 359 /* arg = value */ 360 if (qdict == NULL) { 361 error_setg(errp, "no group defined"); 362 goto out; 363 } 364 qdict_put_str(qdict, arg, value); 365 continue; 366 } 367 error_setg(errp, "parse error"); 368 goto out; 369 } 370 if (ferror(fp)) { 371 loc_pop(&loc); 372 error_setg_errno(errp, errno, "Cannot read config file"); 373 goto out_no_loc; 374 } 375 res = count; 376 if (qdict) { 377 cb(group, qdict, opaque, errp); 378 } 379 out: 380 loc_pop(&loc); 381 out_no_loc: 382 qobject_unref(qdict); 383 return res; 384 } 385 386 void qemu_config_do_parse(const char *group, QDict *qdict, void *opaque, Error **errp) 387 { 388 QemuOptsList **lists = opaque; 389 QemuOptsList *list; 390 391 list = find_list(lists, group, errp); 392 if (!list) { 393 return; 394 } 395 396 qemu_opts_from_qdict(list, qdict, errp); 397 } 398 399 int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp) 400 { 401 return qemu_config_foreach(fp, qemu_config_do_parse, lists, fname, errp); 402 } 403 404 int qemu_read_config_file(const char *filename, QEMUConfigCB *cb, Error **errp) 405 { 406 FILE *f = fopen(filename, "r"); 407 int ret; 408 409 if (f == NULL) { 410 error_setg_file_open(errp, errno, filename); 411 return -errno; 412 } 413 414 ret = qemu_config_foreach(f, cb, vm_config_groups, filename, errp); 415 fclose(f); 416 return ret; 417 } 418 419 static void config_parse_qdict_section(QDict *options, QemuOptsList *opts, 420 Error **errp) 421 { 422 QemuOpts *subopts; 423 QDict *subqdict; 424 QList *list = NULL; 425 size_t orig_size, enum_size; 426 char *prefix; 427 428 prefix = g_strdup_printf("%s.", opts->name); 429 qdict_extract_subqdict(options, &subqdict, prefix); 430 g_free(prefix); 431 orig_size = qdict_size(subqdict); 432 if (!orig_size) { 433 goto out; 434 } 435 436 subopts = qemu_opts_create(opts, NULL, 0, errp); 437 if (!subopts) { 438 goto out; 439 } 440 441 if (!qemu_opts_absorb_qdict(subopts, subqdict, errp)) { 442 goto out; 443 } 444 445 enum_size = qdict_size(subqdict); 446 if (enum_size < orig_size && enum_size) { 447 error_setg(errp, "Unknown option '%s' for [%s]", 448 qdict_first(subqdict)->key, opts->name); 449 goto out; 450 } 451 452 if (enum_size) { 453 /* Multiple, enumerated sections */ 454 QListEntry *list_entry; 455 unsigned i = 0; 456 457 /* Not required anymore */ 458 qemu_opts_del(subopts); 459 460 qdict_array_split(subqdict, &list); 461 if (qdict_size(subqdict)) { 462 error_setg(errp, "Unused option '%s' for [%s]", 463 qdict_first(subqdict)->key, opts->name); 464 goto out; 465 } 466 467 QLIST_FOREACH_ENTRY(list, list_entry) { 468 QDict *section = qobject_to(QDict, qlist_entry_obj(list_entry)); 469 char *opt_name; 470 471 if (!section) { 472 error_setg(errp, "[%s] section (index %u) does not consist of " 473 "keys", opts->name, i); 474 goto out; 475 } 476 477 opt_name = g_strdup_printf("%s.%u", opts->name, i++); 478 subopts = qemu_opts_create(opts, opt_name, 1, errp); 479 g_free(opt_name); 480 if (!subopts) { 481 goto out; 482 } 483 484 if (!qemu_opts_absorb_qdict(subopts, section, errp)) { 485 qemu_opts_del(subopts); 486 goto out; 487 } 488 489 if (qdict_size(section)) { 490 error_setg(errp, "[%s] section doesn't support the option '%s'", 491 opts->name, qdict_first(section)->key); 492 qemu_opts_del(subopts); 493 goto out; 494 } 495 } 496 } 497 498 out: 499 qobject_unref(subqdict); 500 qobject_unref(list); 501 } 502 503 void qemu_config_parse_qdict(QDict *options, QemuOptsList **lists, 504 Error **errp) 505 { 506 int i; 507 Error *local_err = NULL; 508 509 for (i = 0; lists[i]; i++) { 510 config_parse_qdict_section(options, lists[i], &local_err); 511 if (local_err) { 512 error_propagate(errp, local_err); 513 return; 514 } 515 } 516 } 517