File:  [Qemu by Fabrice Bellard] / qemu / qemu-config.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:55:31 2018 UTC (3 years, 1 month ago) by root
Branches: qemu, MAIN
CVS tags: qemu1000, qemu0151, HEAD
qemu 0.15.1

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

unix.superglobalmegacorp.com