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

unix.superglobalmegacorp.com