Home | History | Annotate | Download | only in util
      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 
      7 static QemuOptsList qemu_drive_opts = {
      8     .name = "drive",
      9     .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
     10     .desc = {
     11         {
     12             .name = "bus",
     13             .type = QEMU_OPT_NUMBER,
     14             .help = "bus number",
     15         },{
     16             .name = "unit",
     17             .type = QEMU_OPT_NUMBER,
     18             .help = "unit number (i.e. lun for scsi)",
     19         },{
     20             .name = "if",
     21             .type = QEMU_OPT_STRING,
     22             .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
     23         },{
     24             .name = "index",
     25             .type = QEMU_OPT_NUMBER,
     26         },{
     27             .name = "cyls",
     28             .type = QEMU_OPT_NUMBER,
     29             .help = "number of cylinders (ide disk geometry)",
     30         },{
     31             .name = "heads",
     32             .type = QEMU_OPT_NUMBER,
     33             .help = "number of heads (ide disk geometry)",
     34         },{
     35             .name = "secs",
     36             .type = QEMU_OPT_NUMBER,
     37             .help = "number of sectors (ide disk geometry)",
     38         },{
     39             .name = "trans",
     40             .type = QEMU_OPT_STRING,
     41             .help = "chs translation (auto, lba. none)",
     42         },{
     43             .name = "media",
     44             .type = QEMU_OPT_STRING,
     45             .help = "media type (disk, cdrom)",
     46         },{
     47             .name = "snapshot",
     48             .type = QEMU_OPT_BOOL,
     49         },{
     50             .name = "file",
     51             .type = QEMU_OPT_STRING,
     52             .help = "disk image",
     53         },{
     54             .name = "cache",
     55             .type = QEMU_OPT_STRING,
     56             .help = "host cache usage (none, writeback, writethrough, unsafe)",
     57         },{
     58             .name = "aio",
     59             .type = QEMU_OPT_STRING,
     60             .help = "host AIO implementation (threads, native)",
     61         },{
     62             .name = "format",
     63             .type = QEMU_OPT_STRING,
     64             .help = "disk format (raw, qcow2, ...)",
     65         },{
     66             .name = "serial",
     67             .type = QEMU_OPT_STRING,
     68         },{
     69             .name = "rerror",
     70             .type = QEMU_OPT_STRING,
     71         },{
     72             .name = "werror",
     73             .type = QEMU_OPT_STRING,
     74         },{
     75             .name = "addr",
     76             .type = QEMU_OPT_STRING,
     77             .help = "pci address (virtio only)",
     78         },{
     79             .name = "readonly",
     80             .type = QEMU_OPT_BOOL,
     81         },
     82         { /* end of list */ }
     83     },
     84 };
     85 
     86 static QemuOptsList qemu_chardev_opts = {
     87     .name = "chardev",
     88     .implied_opt_name = "backend",
     89     .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head),
     90     .desc = {
     91         {
     92             .name = "backend",
     93             .type = QEMU_OPT_STRING,
     94         },{
     95             .name = "path",
     96             .type = QEMU_OPT_STRING,
     97         },{
     98             .name = "host",
     99             .type = QEMU_OPT_STRING,
    100         },{
    101             .name = "port",
    102             .type = QEMU_OPT_STRING,
    103         },{
    104             .name = "localaddr",
    105             .type = QEMU_OPT_STRING,
    106         },{
    107             .name = "localport",
    108             .type = QEMU_OPT_STRING,
    109         },{
    110             .name = "to",
    111             .type = QEMU_OPT_NUMBER,
    112         },{
    113             .name = "ipv4",
    114             .type = QEMU_OPT_BOOL,
    115         },{
    116             .name = "ipv6",
    117             .type = QEMU_OPT_BOOL,
    118         },{
    119             .name = "wait",
    120             .type = QEMU_OPT_BOOL,
    121         },{
    122             .name = "server",
    123             .type = QEMU_OPT_BOOL,
    124         },{
    125             .name = "delay",
    126             .type = QEMU_OPT_BOOL,
    127         },{
    128             .name = "telnet",
    129             .type = QEMU_OPT_BOOL,
    130         },{
    131             .name = "width",
    132             .type = QEMU_OPT_NUMBER,
    133         },{
    134             .name = "height",
    135             .type = QEMU_OPT_NUMBER,
    136         },{
    137             .name = "cols",
    138             .type = QEMU_OPT_NUMBER,
    139         },{
    140             .name = "rows",
    141             .type = QEMU_OPT_NUMBER,
    142         },{
    143             .name = "mux",
    144             .type = QEMU_OPT_BOOL,
    145         },{
    146             .name = "signal",
    147             .type = QEMU_OPT_BOOL,
    148         },{
    149             .name = "name",
    150             .type = QEMU_OPT_STRING,
    151         },{
    152             .name = "debug",
    153             .type = QEMU_OPT_NUMBER,
    154         },
    155         { /* end of list */ }
    156     },
    157 };
    158 
    159 QemuOptsList qemu_fsdev_opts = {
    160     .name = "fsdev",
    161     .implied_opt_name = "fstype",
    162     .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head),
    163     .desc = {
    164         {
    165             .name = "fstype",
    166             .type = QEMU_OPT_STRING,
    167         }, {
    168             .name = "path",
    169             .type = QEMU_OPT_STRING,
    170         }, {
    171             .name = "security_model",
    172             .type = QEMU_OPT_STRING,
    173         },
    174         { /*End of list */ }
    175     },
    176 };
    177 
    178 QemuOptsList qemu_virtfs_opts = {
    179     .name = "virtfs",
    180     .implied_opt_name = "fstype",
    181     .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head),
    182     .desc = {
    183         {
    184             .name = "fstype",
    185             .type = QEMU_OPT_STRING,
    186         }, {
    187             .name = "path",
    188             .type = QEMU_OPT_STRING,
    189         }, {
    190             .name = "mount_tag",
    191             .type = QEMU_OPT_STRING,
    192         }, {
    193             .name = "security_model",
    194             .type = QEMU_OPT_STRING,
    195         },
    196 
    197         { /*End of list */ }
    198     },
    199 };
    200 
    201 static QemuOptsList qemu_device_opts = {
    202     .name = "device",
    203     .implied_opt_name = "driver",
    204     .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
    205     .desc = {
    206         /*
    207          * no elements => accept any
    208          * sanity checking will happen later
    209          * when setting device properties
    210          */
    211         { /* end of list */ }
    212     },
    213 };
    214 
    215 static QemuOptsList qemu_netdev_opts = {
    216     .name = "netdev",
    217     .implied_opt_name = "type",
    218     .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
    219     .desc = {
    220         /*
    221          * no elements => accept any params
    222          * validation will happen later
    223          */
    224         { /* end of list */ }
    225     },
    226 };
    227 
    228 static QemuOptsList qemu_net_opts = {
    229     .name = "net",
    230     .implied_opt_name = "type",
    231     .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
    232     .desc = {
    233         /*
    234          * no elements => accept any params
    235          * validation will happen later
    236          */
    237         { /* end of list */ }
    238     },
    239 };
    240 
    241 static QemuOptsList qemu_rtc_opts = {
    242     .name = "rtc",
    243     .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head),
    244     .desc = {
    245         {
    246             .name = "base",
    247             .type = QEMU_OPT_STRING,
    248         },{
    249             .name = "clock",
    250             .type = QEMU_OPT_STRING,
    251         },{
    252             .name = "driftfix",
    253             .type = QEMU_OPT_STRING,
    254         },
    255         { /* end of list */ }
    256     },
    257 };
    258 
    259 static QemuOptsList qemu_global_opts = {
    260     .name = "global",
    261     .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
    262     .desc = {
    263         {
    264             .name = "driver",
    265             .type = QEMU_OPT_STRING,
    266         },{
    267             .name = "property",
    268             .type = QEMU_OPT_STRING,
    269         },{
    270             .name = "value",
    271             .type = QEMU_OPT_STRING,
    272         },
    273         { /* end of list */ }
    274     },
    275 };
    276 
    277 static QemuOptsList qemu_mon_opts = {
    278     .name = "mon",
    279     .implied_opt_name = "chardev",
    280     .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
    281     .desc = {
    282         {
    283             .name = "mode",
    284             .type = QEMU_OPT_STRING,
    285         },{
    286             .name = "chardev",
    287             .type = QEMU_OPT_STRING,
    288         },{
    289             .name = "default",
    290             .type = QEMU_OPT_BOOL,
    291         },{
    292             .name = "pretty",
    293             .type = QEMU_OPT_BOOL,
    294         },
    295         { /* end of list */ }
    296     },
    297 };
    298 
    299 #ifdef CONFIG_SIMPLE_TRACE
    300 static QemuOptsList qemu_trace_opts = {
    301     .name = "trace",
    302     .implied_opt_name = "trace",
    303     .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
    304     .desc = {
    305         {
    306             .name = "file",
    307             .type = QEMU_OPT_STRING,
    308         },
    309         { /* end if list */ }
    310     },
    311 };
    312 #endif
    313 
    314 static QemuOptsList qemu_cpudef_opts = {
    315     .name = "cpudef",
    316     .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head),
    317     .desc = {
    318         {
    319             .name = "name",
    320             .type = QEMU_OPT_STRING,
    321         },{
    322             .name = "level",
    323             .type = QEMU_OPT_NUMBER,
    324         },{
    325             .name = "vendor",
    326             .type = QEMU_OPT_STRING,
    327         },{
    328             .name = "family",
    329             .type = QEMU_OPT_NUMBER,
    330         },{
    331             .name = "model",
    332             .type = QEMU_OPT_NUMBER,
    333         },{
    334             .name = "stepping",
    335             .type = QEMU_OPT_NUMBER,
    336         },{
    337             .name = "feature_edx",      /* cpuid 0000_0001.edx */
    338             .type = QEMU_OPT_STRING,
    339         },{
    340             .name = "feature_ecx",      /* cpuid 0000_0001.ecx */
    341             .type = QEMU_OPT_STRING,
    342         },{
    343             .name = "extfeature_edx",   /* cpuid 8000_0001.edx */
    344             .type = QEMU_OPT_STRING,
    345         },{
    346             .name = "extfeature_ecx",   /* cpuid 8000_0001.ecx */
    347             .type = QEMU_OPT_STRING,
    348         },{
    349             .name = "xlevel",
    350             .type = QEMU_OPT_NUMBER,
    351         },{
    352             .name = "model_id",
    353             .type = QEMU_OPT_STRING,
    354         },{
    355             .name = "vendor_override",
    356             .type = QEMU_OPT_NUMBER,
    357         },
    358         { /* end of list */ }
    359     },
    360 };
    361 
    362 QemuOptsList qemu_spice_opts = {
    363     .name = "spice",
    364     .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head),
    365     .desc = {
    366         {
    367             .name = "port",
    368             .type = QEMU_OPT_NUMBER,
    369         },{
    370             .name = "tls-port",
    371             .type = QEMU_OPT_NUMBER,
    372         },{
    373             .name = "addr",
    374             .type = QEMU_OPT_STRING,
    375         },{
    376             .name = "ipv4",
    377             .type = QEMU_OPT_BOOL,
    378         },{
    379             .name = "ipv6",
    380             .type = QEMU_OPT_BOOL,
    381         },{
    382             .name = "password",
    383             .type = QEMU_OPT_STRING,
    384         },{
    385             .name = "disable-ticketing",
    386             .type = QEMU_OPT_BOOL,
    387         },{
    388             .name = "x509-dir",
    389             .type = QEMU_OPT_STRING,
    390         },{
    391             .name = "x509-key-file",
    392             .type = QEMU_OPT_STRING,
    393         },{
    394             .name = "x509-key-password",
    395             .type = QEMU_OPT_STRING,
    396         },{
    397             .name = "x509-cert-file",
    398             .type = QEMU_OPT_STRING,
    399         },{
    400             .name = "x509-cacert-file",
    401             .type = QEMU_OPT_STRING,
    402         },{
    403             .name = "x509-dh-key-file",
    404             .type = QEMU_OPT_STRING,
    405         },{
    406             .name = "tls-ciphers",
    407             .type = QEMU_OPT_STRING,
    408         },{
    409             .name = "tls-channel",
    410             .type = QEMU_OPT_STRING,
    411         },{
    412             .name = "plaintext-channel",
    413             .type = QEMU_OPT_STRING,
    414         },{
    415             .name = "image-compression",
    416             .type = QEMU_OPT_STRING,
    417         },{
    418             .name = "jpeg-wan-compression",
    419             .type = QEMU_OPT_STRING,
    420         },{
    421             .name = "zlib-glz-wan-compression",
    422             .type = QEMU_OPT_STRING,
    423         },{
    424             .name = "streaming-video",
    425             .type = QEMU_OPT_STRING,
    426         },{
    427             .name = "agent-mouse",
    428             .type = QEMU_OPT_BOOL,
    429         },{
    430             .name = "playback-compression",
    431             .type = QEMU_OPT_BOOL,
    432         },
    433         { /* end if list */ }
    434     },
    435 };
    436 
    437 QemuOptsList qemu_option_rom_opts = {
    438     .name = "option-rom",
    439     .implied_opt_name = "romfile",
    440     .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head),
    441     .desc = {
    442         {
    443             .name = "bootindex",
    444             .type = QEMU_OPT_NUMBER,
    445         }, {
    446             .name = "romfile",
    447             .type = QEMU_OPT_STRING,
    448         },
    449         { /* end if list */ }
    450     },
    451 };
    452 
    453 static QemuOptsList *vm_config_groups[32] = {
    454     &qemu_drive_opts,
    455     &qemu_chardev_opts,
    456     &qemu_device_opts,
    457     &qemu_netdev_opts,
    458     &qemu_net_opts,
    459     &qemu_rtc_opts,
    460     &qemu_global_opts,
    461     &qemu_mon_opts,
    462     &qemu_cpudef_opts,
    463 #ifdef CONFIG_SIMPLE_TRACE
    464     &qemu_trace_opts,
    465 #endif
    466     &qemu_option_rom_opts,
    467     NULL,
    468 };
    469 
    470 static QemuOptsList *find_list(QemuOptsList **lists, const char *group)
    471 {
    472     int i;
    473 
    474     for (i = 0; lists[i] != NULL; i++) {
    475         if (strcmp(lists[i]->name, group) == 0)
    476             break;
    477     }
    478     if (lists[i] == NULL) {
    479         error_report("there is no option group \"%s\"", group);
    480     }
    481     return lists[i];
    482 }
    483 
    484 QemuOptsList *qemu_find_opts(const char *group)
    485 {
    486     return find_list(vm_config_groups, group);
    487 }
    488 
    489 void qemu_add_opts(QemuOptsList *list)
    490 {
    491     int entries, i;
    492 
    493     entries = ARRAY_SIZE(vm_config_groups);
    494     entries--; /* keep list NULL terminated */
    495     for (i = 0; i < entries; i++) {
    496         if (vm_config_groups[i] == NULL) {
    497             vm_config_groups[i] = list;
    498             return;
    499         }
    500     }
    501     fprintf(stderr, "ran out of space in vm_config_groups");
    502     abort();
    503 }
    504 
    505 int qemu_set_option(const char *str)
    506 {
    507     char group[64], id[64], arg[64];
    508     QemuOptsList *list;
    509     QemuOpts *opts;
    510     int rc, offset;
    511 
    512     rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
    513     if (rc < 3 || str[offset] != '=') {
    514         error_report("can't parse: \"%s\"", str);
    515         return -1;
    516     }
    517 
    518     list = qemu_find_opts(group);
    519     if (list == NULL) {
    520         return -1;
    521     }
    522 
    523     opts = qemu_opts_find(list, id);
    524     if (!opts) {
    525         error_report("there is no %s \"%s\" defined",
    526                      list->name, id);
    527         return -1;
    528     }
    529 
    530     if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
    531         return -1;
    532     }
    533     return 0;
    534 }
    535 
    536 int qemu_global_option(const char *str)
    537 {
    538     char driver[64], property[64];
    539     QemuOpts *opts;
    540     int rc, offset;
    541 
    542     rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
    543     if (rc < 2 || str[offset] != '=') {
    544         error_report("can't parse: \"%s\"", str);
    545         return -1;
    546     }
    547 
    548     opts = qemu_opts_create(&qemu_global_opts, NULL, 0);
    549     qemu_opt_set(opts, "driver", driver);
    550     qemu_opt_set(opts, "property", property);
    551     qemu_opt_set(opts, "value", str+offset+1);
    552     return 0;
    553 }
    554 
    555 struct ConfigWriteData {
    556     QemuOptsList *list;
    557     FILE *fp;
    558 };
    559 
    560 static int config_write_opt(const char *name, const char *value, void *opaque)
    561 {
    562     struct ConfigWriteData *data = opaque;
    563 
    564     fprintf(data->fp, "  %s = \"%s\"\n", name, value);
    565     return 0;
    566 }
    567 
    568 static int config_write_opts(QemuOpts *opts, void *opaque)
    569 {
    570     struct ConfigWriteData *data = opaque;
    571     const char *id = qemu_opts_id(opts);
    572 
    573     if (id) {
    574         fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
    575     } else {
    576         fprintf(data->fp, "[%s]\n", data->list->name);
    577     }
    578     qemu_opt_foreach(opts, config_write_opt, data, 0);
    579     fprintf(data->fp, "\n");
    580     return 0;
    581 }
    582 
    583 void qemu_config_write(FILE *fp)
    584 {
    585     struct ConfigWriteData data = { .fp = fp };
    586     QemuOptsList **lists = vm_config_groups;
    587     int i;
    588 
    589     fprintf(fp, "# qemu config file\n\n");
    590     for (i = 0; lists[i] != NULL; i++) {
    591         data.list = lists[i];
    592         qemu_opts_foreach(data.list, config_write_opts, &data, 0);
    593     }
    594 }
    595 
    596 int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
    597 {
    598     char line[1024], group[64], id[64], arg[64], value[1024];
    599     Location loc;
    600     QemuOptsList *list = NULL;
    601     QemuOpts *opts = NULL;
    602     int res = -1, lno = 0;
    603 
    604     loc_push_none(&loc);
    605     while (fgets(line, sizeof(line), fp) != NULL) {
    606         loc_set_file(fname, ++lno);
    607         if (line[0] == '\n') {
    608             /* skip empty lines */
    609             continue;
    610         }
    611         if (line[0] == '#') {
    612             /* comment */
    613             continue;
    614         }
    615         if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
    616             /* group with id */
    617             list = find_list(lists, group);
    618             if (list == NULL)
    619                 goto out;
    620             opts = qemu_opts_create(list, id, 1);
    621             continue;
    622         }
    623         if (sscanf(line, "[%63[^]]]", group) == 1) {
    624             /* group without id */
    625             list = find_list(lists, group);
    626             if (list == NULL)
    627                 goto out;
    628             opts = qemu_opts_create(list, NULL, 0);
    629             continue;
    630         }
    631         if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
    632             /* arg = value */
    633             if (opts == NULL) {
    634                 error_report("no group defined");
    635                 goto out;
    636             }
    637             if (qemu_opt_set(opts, arg, value) != 0) {
    638                 goto out;
    639             }
    640             continue;
    641         }
    642         error_report("parse error");
    643         goto out;
    644     }
    645     if (ferror(fp)) {
    646         error_report("error reading file");
    647         goto out;
    648     }
    649     res = 0;
    650 out:
    651     loc_pop(&loc);
    652     return res;
    653 }
    654 
    655 int qemu_read_config_file(const char *filename)
    656 {
    657     FILE *f = fopen(filename, "r");
    658     int ret;
    659 
    660     if (f == NULL) {
    661         return -errno;
    662     }
    663 
    664     ret = qemu_config_parse(f, vm_config_groups, filename);
    665     fclose(f);
    666 
    667     if (ret == 0) {
    668         return 0;
    669     } else {
    670         return -EINVAL;
    671     }
    672 }
    673