qemu/util/qemu-config.c
<<
>>
Prefs
   1#include "qemu-common.h"
   2#include "qemu/error-report.h"
   3#include "qemu/option.h"
   4#include "qemu/config-file.h"
   5#include "hw/qdev.h"
   6#include "qapi/error.h"
   7
   8static QemuOptsList *vm_config_groups[32];
   9
  10static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
  11                               Error **errp)
  12{
  13    int i;
  14
  15    for (i = 0; lists[i] != NULL; i++) {
  16        if (strcmp(lists[i]->name, group) == 0)
  17            break;
  18    }
  19    if (lists[i] == NULL) {
  20        error_set(errp, QERR_INVALID_OPTION_GROUP, group);
  21    }
  22    return lists[i];
  23}
  24
  25QemuOptsList *qemu_find_opts(const char *group)
  26{
  27    QemuOptsList *ret;
  28    Error *local_err = NULL;
  29
  30    ret = find_list(vm_config_groups, group, &local_err);
  31    if (error_is_set(&local_err)) {
  32        error_report("%s", error_get_pretty(local_err));
  33        error_free(local_err);
  34    }
  35
  36    return ret;
  37}
  38
  39QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
  40{
  41    return find_list(vm_config_groups, group, errp);
  42}
  43
  44void qemu_add_opts(QemuOptsList *list)
  45{
  46    int entries, i;
  47
  48    entries = ARRAY_SIZE(vm_config_groups);
  49    entries--; /* keep list NULL terminated */
  50    for (i = 0; i < entries; i++) {
  51        if (vm_config_groups[i] == NULL) {
  52            vm_config_groups[i] = list;
  53            return;
  54        }
  55    }
  56    fprintf(stderr, "ran out of space in vm_config_groups");
  57    abort();
  58}
  59
  60int qemu_set_option(const char *str)
  61{
  62    char group[64], id[64], arg[64];
  63    QemuOptsList *list;
  64    QemuOpts *opts;
  65    int rc, offset;
  66
  67    rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
  68    if (rc < 3 || str[offset] != '=') {
  69        error_report("can't parse: \"%s\"", str);
  70        return -1;
  71    }
  72
  73    list = qemu_find_opts(group);
  74    if (list == NULL) {
  75        return -1;
  76    }
  77
  78    opts = qemu_opts_find(list, id);
  79    if (!opts) {
  80        error_report("there is no %s \"%s\" defined",
  81                     list->name, id);
  82        return -1;
  83    }
  84
  85    if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
  86        return -1;
  87    }
  88    return 0;
  89}
  90
  91struct ConfigWriteData {
  92    QemuOptsList *list;
  93    FILE *fp;
  94};
  95
  96static int config_write_opt(const char *name, const char *value, void *opaque)
  97{
  98    struct ConfigWriteData *data = opaque;
  99
 100    fprintf(data->fp, "  %s = \"%s\"\n", name, value);
 101    return 0;
 102}
 103
 104static int config_write_opts(QemuOpts *opts, void *opaque)
 105{
 106    struct ConfigWriteData *data = opaque;
 107    const char *id = qemu_opts_id(opts);
 108
 109    if (id) {
 110        fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
 111    } else {
 112        fprintf(data->fp, "[%s]\n", data->list->name);
 113    }
 114    qemu_opt_foreach(opts, config_write_opt, data, 0);
 115    fprintf(data->fp, "\n");
 116    return 0;
 117}
 118
 119void qemu_config_write(FILE *fp)
 120{
 121    struct ConfigWriteData data = { .fp = fp };
 122    QemuOptsList **lists = vm_config_groups;
 123    int i;
 124
 125    fprintf(fp, "# qemu config file\n\n");
 126    for (i = 0; lists[i] != NULL; i++) {
 127        data.list = lists[i];
 128        qemu_opts_foreach(data.list, config_write_opts, &data, 0);
 129    }
 130}
 131
 132int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
 133{
 134    char line[1024], group[64], id[64], arg[64], value[1024];
 135    Location loc;
 136    QemuOptsList *list = NULL;
 137    Error *local_err = NULL;
 138    QemuOpts *opts = NULL;
 139    int res = -1, lno = 0;
 140
 141    loc_push_none(&loc);
 142    while (fgets(line, sizeof(line), fp) != NULL) {
 143        loc_set_file(fname, ++lno);
 144        if (line[0] == '\n') {
 145            /* skip empty lines */
 146            continue;
 147        }
 148        if (line[0] == '#') {
 149            /* comment */
 150            continue;
 151        }
 152        if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
 153            /* group with id */
 154            list = find_list(lists, group, &local_err);
 155            if (error_is_set(&local_err)) {
 156                error_report("%s", error_get_pretty(local_err));
 157                error_free(local_err);
 158                goto out;
 159            }
 160            opts = qemu_opts_create(list, id, 1, NULL);
 161            continue;
 162        }
 163        if (sscanf(line, "[%63[^]]]", group) == 1) {
 164            /* group without id */
 165            list = find_list(lists, group, &local_err);
 166            if (error_is_set(&local_err)) {
 167                error_report("%s", error_get_pretty(local_err));
 168                error_free(local_err);
 169                goto out;
 170            }
 171            opts = qemu_opts_create_nofail(list);
 172            continue;
 173        }
 174        if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
 175            /* arg = value */
 176            if (opts == NULL) {
 177                error_report("no group defined");
 178                goto out;
 179            }
 180            if (qemu_opt_set(opts, arg, value) != 0) {
 181                goto out;
 182            }
 183            continue;
 184        }
 185        error_report("parse error");
 186        goto out;
 187    }
 188    if (ferror(fp)) {
 189        error_report("error reading file");
 190        goto out;
 191    }
 192    res = 0;
 193out:
 194    loc_pop(&loc);
 195    return res;
 196}
 197
 198int qemu_read_config_file(const char *filename)
 199{
 200    FILE *f = fopen(filename, "r");
 201    int ret;
 202
 203    if (f == NULL) {
 204        return -errno;
 205    }
 206
 207    ret = qemu_config_parse(f, vm_config_groups, filename);
 208    fclose(f);
 209
 210    if (ret == 0) {
 211        return 0;
 212    } else {
 213        return -EINVAL;
 214    }
 215}
 216