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