qemu/util/qemu-config.c
<<
>>
Prefs
   1#include "qemu/osdep.h"
   2#include "block/qdict.h" /* for qdict_extract_subqdict() */
   3#include "qapi/error.h"
   4#include "qobject/qdict.h"
   5#include "qobject/qlist.h"
   6#include "qemu/error-report.h"
   7#include "qemu/option.h"
   8#include "qemu/config-file.h"
   9
  10QemuOptsList *vm_config_groups[48];
  11QemuOptsList *drive_config_groups[5];
  12
  13static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
  14                               Error **errp)
  15{
  16    int i;
  17
  18    qemu_load_module_for_opts(group);
  19    for (i = 0; lists[i] != NULL; i++) {
  20        if (strcmp(lists[i]->name, group) == 0)
  21            break;
  22    }
  23    if (lists[i] == NULL) {
  24        error_setg(errp, "There is no option group '%s'", group);
  25    }
  26    return lists[i];
  27}
  28
  29QemuOptsList *qemu_find_opts(const char *group)
  30{
  31    QemuOptsList *ret;
  32    Error *local_err = NULL;
  33
  34    ret = find_list(vm_config_groups, group, &local_err);
  35    if (local_err) {
  36        error_report_err(local_err);
  37    }
  38
  39    return ret;
  40}
  41
  42QemuOpts *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
  56QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
  57{
  58    return find_list(vm_config_groups, group, errp);
  59}
  60
  61void qemu_add_drive_opts(QemuOptsList *list)
  62{
  63    int entries, i;
  64
  65    entries = ARRAY_SIZE(drive_config_groups);
  66    entries--; /* keep list NULL terminated */
  67    for (i = 0; i < entries; i++) {
  68        if (drive_config_groups[i] == NULL) {
  69            drive_config_groups[i] = list;
  70            return;
  71        }
  72    }
  73    fprintf(stderr, "ran out of space in drive_config_groups");
  74    abort();
  75}
  76
  77void qemu_add_opts(QemuOptsList *list)
  78{
  79    int entries, i;
  80
  81    entries = ARRAY_SIZE(vm_config_groups);
  82    entries--; /* keep list NULL terminated */
  83    for (i = 0; i < entries; i++) {
  84        if (vm_config_groups[i] == NULL) {
  85            vm_config_groups[i] = list;
  86            return;
  87        }
  88    }
  89    fprintf(stderr, "ran out of space in vm_config_groups");
  90    abort();
  91}
  92
  93/* Returns number of config groups on success, -errno on error */
  94static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque,
  95                               const char *fname, Error **errp)
  96{
  97    ERRP_GUARD();
  98    char line[1024], prev_group[64], group[64], arg[64], value[1024];
  99    Location loc;
 100    QDict *qdict = NULL;
 101    int res = -EINVAL, lno = 0;
 102    int count = 0;
 103
 104    loc_push_none(&loc);
 105    while (fgets(line, sizeof(line), fp) != NULL) {
 106        ++lno;
 107        if (line[0] == '\n') {
 108            /* skip empty lines */
 109            continue;
 110        }
 111        if (line[0] == '#') {
 112            /* comment */
 113            continue;
 114        }
 115        if (line[0] == '[') {
 116            QDict *prev = qdict;
 117            if (sscanf(line, "[%63s \"%63[^\"]\"]", group, value) == 2) {
 118                qdict = qdict_new();
 119                qdict_put_str(qdict, "id", value);
 120                count++;
 121            } else if (sscanf(line, "[%63[^]]]", group) == 1) {
 122                qdict = qdict_new();
 123                count++;
 124            }
 125            if (qdict != prev) {
 126                if (prev) {
 127                    cb(prev_group, prev, opaque, errp);
 128                    qobject_unref(prev);
 129                    if (*errp) {
 130                        goto out;
 131                    }
 132                }
 133                strcpy(prev_group, group);
 134                continue;
 135            }
 136        }
 137        loc_set_file(fname, lno);
 138        value[0] = '\0';
 139        if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2 ||
 140            sscanf(line, " %63s = \"\"", arg) == 1) {
 141            /* arg = value */
 142            if (qdict == NULL) {
 143                error_setg(errp, "no group defined");
 144                goto out;
 145            }
 146            qdict_put_str(qdict, arg, value);
 147            continue;
 148        }
 149        error_setg(errp, "parse error");
 150        goto out;
 151    }
 152    if (ferror(fp)) {
 153        loc_pop(&loc);
 154        error_setg_errno(errp, errno, "Cannot read config file");
 155        goto out_no_loc;
 156    }
 157    res = count;
 158    if (qdict) {
 159        cb(group, qdict, opaque, errp);
 160    }
 161out:
 162    loc_pop(&loc);
 163out_no_loc:
 164    qobject_unref(qdict);
 165    return res;
 166}
 167
 168void qemu_config_do_parse(const char *group, QDict *qdict, void *opaque, Error **errp)
 169{
 170    QemuOptsList **lists = opaque;
 171    QemuOptsList *list;
 172
 173    list = find_list(lists, group, errp);
 174    if (!list) {
 175        return;
 176    }
 177
 178    qemu_opts_from_qdict(list, qdict, errp);
 179}
 180
 181int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp)
 182{
 183    return qemu_config_foreach(fp, qemu_config_do_parse, lists, fname, errp);
 184}
 185
 186int qemu_read_config_file(const char *filename, QEMUConfigCB *cb, Error **errp)
 187{
 188    FILE *f = fopen(filename, "r");
 189    int ret;
 190
 191    if (f == NULL) {
 192        error_setg_file_open(errp, errno, filename);
 193        return -errno;
 194    }
 195
 196    ret = qemu_config_foreach(f, cb, vm_config_groups, filename, errp);
 197    fclose(f);
 198    return ret;
 199}
 200
 201static bool config_parse_qdict_section(QDict *options, QemuOptsList *opts,
 202                                       Error **errp)
 203{
 204    QemuOpts *subopts;
 205    g_autoptr(QDict) subqdict = NULL;
 206    g_autoptr(QList) list = NULL;
 207    size_t orig_size, enum_size;
 208    char *prefix;
 209
 210    prefix = g_strdup_printf("%s.", opts->name);
 211    qdict_extract_subqdict(options, &subqdict, prefix);
 212    g_free(prefix);
 213    orig_size = qdict_size(subqdict);
 214    if (!orig_size) {
 215        return true;
 216    }
 217
 218    subopts = qemu_opts_create(opts, NULL, 0, errp);
 219    if (!subopts) {
 220        return false;
 221    }
 222
 223    if (!qemu_opts_absorb_qdict(subopts, subqdict, errp)) {
 224        return false;
 225    }
 226
 227    enum_size = qdict_size(subqdict);
 228    if (enum_size < orig_size && enum_size) {
 229        error_setg(errp, "Unknown option '%s' for [%s]",
 230                   qdict_first(subqdict)->key, opts->name);
 231        return false;
 232    }
 233
 234    if (enum_size) {
 235        /* Multiple, enumerated sections */
 236        QListEntry *list_entry;
 237        unsigned i = 0;
 238
 239        /* Not required anymore */
 240        qemu_opts_del(subopts);
 241
 242        qdict_array_split(subqdict, &list);
 243        if (qdict_size(subqdict)) {
 244            error_setg(errp, "Unused option '%s' for [%s]",
 245                       qdict_first(subqdict)->key, opts->name);
 246            return false;
 247        }
 248
 249        QLIST_FOREACH_ENTRY(list, list_entry) {
 250            QDict *section = qobject_to(QDict, qlist_entry_obj(list_entry));
 251            char *opt_name;
 252
 253            if (!section) {
 254                error_setg(errp, "[%s] section (index %u) does not consist of "
 255                           "keys", opts->name, i);
 256                return false;
 257            }
 258
 259            opt_name = g_strdup_printf("%s.%u", opts->name, i++);
 260            subopts = qemu_opts_create(opts, opt_name, 1, errp);
 261            g_free(opt_name);
 262            if (!subopts) {
 263                return false;
 264            }
 265
 266            if (!qemu_opts_absorb_qdict(subopts, section, errp)) {
 267                qemu_opts_del(subopts);
 268                return false;
 269            }
 270
 271            if (qdict_size(section)) {
 272                error_setg(errp, "[%s] section doesn't support the option '%s'",
 273                           opts->name, qdict_first(section)->key);
 274                qemu_opts_del(subopts);
 275                return false;
 276            }
 277        }
 278    }
 279
 280    return true;
 281}
 282
 283bool qemu_config_parse_qdict(QDict *options, QemuOptsList **lists,
 284                             Error **errp)
 285{
 286    int i;
 287
 288    for (i = 0; lists[i]; i++) {
 289        if (!config_parse_qdict_section(options, lists[i], errp)) {
 290            return false;
 291        }
 292    }
 293
 294    return true;
 295}
 296