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