qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

qemu-config.c (15169B)


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