File:  [Qemu by Fabrice Bellard] / qemu / qemu-config.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:33:41 2018 UTC (3 years, 3 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu0125, qemu0124, qemu0123, qemu0122, qemu0121, qemu0120, HEAD
qemu 0.12.0

    1: #include "qemu-common.h"
    2: #include "qemu-option.h"
    3: #include "qemu-config.h"
    4: #include "sysemu.h"
    5: #include "hw/qdev.h"
    6: 
    7: 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)",
   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 if list */ }
   83:     },
   84: };
   85: 
   86: QemuOptsList qemu_chardev_opts = {
   87:     .name = "chardev",
   88:     .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head),
   89:     .desc = {
   90:         {
   91:             .name = "backend",
   92:             .type = QEMU_OPT_STRING,
   93:         },{
   94:             .name = "path",
   95:             .type = QEMU_OPT_STRING,
   96:         },{
   97:             .name = "host",
   98:             .type = QEMU_OPT_STRING,
   99:         },{
  100:             .name = "port",
  101:             .type = QEMU_OPT_STRING,
  102:         },{
  103:             .name = "localaddr",
  104:             .type = QEMU_OPT_STRING,
  105:         },{
  106:             .name = "localport",
  107:             .type = QEMU_OPT_STRING,
  108:         },{
  109:             .name = "to",
  110:             .type = QEMU_OPT_NUMBER,
  111:         },{
  112:             .name = "ipv4",
  113:             .type = QEMU_OPT_BOOL,
  114:         },{
  115:             .name = "ipv6",
  116:             .type = QEMU_OPT_BOOL,
  117:         },{
  118:             .name = "wait",
  119:             .type = QEMU_OPT_BOOL,
  120:         },{
  121:             .name = "server",
  122:             .type = QEMU_OPT_BOOL,
  123:         },{
  124:             .name = "delay",
  125:             .type = QEMU_OPT_BOOL,
  126:         },{
  127:             .name = "telnet",
  128:             .type = QEMU_OPT_BOOL,
  129:         },{
  130:             .name = "width",
  131:             .type = QEMU_OPT_NUMBER,
  132:         },{
  133:             .name = "height",
  134:             .type = QEMU_OPT_NUMBER,
  135:         },{
  136:             .name = "cols",
  137:             .type = QEMU_OPT_NUMBER,
  138:         },{
  139:             .name = "rows",
  140:             .type = QEMU_OPT_NUMBER,
  141:         },{
  142:             .name = "mux",
  143:             .type = QEMU_OPT_BOOL,
  144:         },{
  145:             .name = "signal",
  146:             .type = QEMU_OPT_BOOL,
  147:         },
  148:         { /* end if list */ }
  149:     },
  150: };
  151: 
  152: QemuOptsList qemu_device_opts = {
  153:     .name = "device",
  154:     .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
  155:     .desc = {
  156:         /*
  157:          * no elements => accept any
  158:          * sanity checking will happen later
  159:          * when setting device properties
  160:          */
  161:         { /* end if list */ }
  162:     },
  163: };
  164: 
  165: QemuOptsList qemu_netdev_opts = {
  166:     .name = "netdev",
  167:     .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
  168:     .desc = {
  169:         /*
  170:          * no elements => accept any params
  171:          * validation will happen later
  172:          */
  173:         { /* end of list */ }
  174:     },
  175: };
  176: 
  177: QemuOptsList qemu_net_opts = {
  178:     .name = "net",
  179:     .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
  180:     .desc = {
  181:         /*
  182:          * no elements => accept any params
  183:          * validation will happen later
  184:          */
  185:         { /* end of list */ }
  186:     },
  187: };
  188: 
  189: QemuOptsList qemu_rtc_opts = {
  190:     .name = "rtc",
  191:     .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head),
  192:     .desc = {
  193:         {
  194:             .name = "base",
  195:             .type = QEMU_OPT_STRING,
  196:         },{
  197:             .name = "clock",
  198:             .type = QEMU_OPT_STRING,
  199: #ifdef TARGET_I386
  200:         },{
  201:             .name = "driftfix",
  202:             .type = QEMU_OPT_STRING,
  203: #endif
  204:         },
  205:         { /* end if list */ }
  206:     },
  207: };
  208: 
  209: QemuOptsList qemu_global_opts = {
  210:     .name = "global",
  211:     .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
  212:     .desc = {
  213:         {
  214:             .name = "driver",
  215:             .type = QEMU_OPT_STRING,
  216:         },{
  217:             .name = "property",
  218:             .type = QEMU_OPT_STRING,
  219:         },{
  220:             .name = "value",
  221:             .type = QEMU_OPT_STRING,
  222:         },
  223:         { /* end if list */ }
  224:     },
  225: };
  226: 
  227: QemuOptsList qemu_mon_opts = {
  228:     .name = "mon",
  229:     .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
  230:     .desc = {
  231:         {
  232:             .name = "mode",
  233:             .type = QEMU_OPT_STRING,
  234:         },{
  235:             .name = "chardev",
  236:             .type = QEMU_OPT_STRING,
  237:         },{
  238:             .name = "default",
  239:             .type = QEMU_OPT_BOOL,
  240:         },
  241:         { /* end if list */ }
  242:     },
  243: };
  244: 
  245: static QemuOptsList *lists[] = {
  246:     &qemu_drive_opts,
  247:     &qemu_chardev_opts,
  248:     &qemu_device_opts,
  249:     &qemu_netdev_opts,
  250:     &qemu_net_opts,
  251:     &qemu_rtc_opts,
  252:     &qemu_global_opts,
  253:     &qemu_mon_opts,
  254:     NULL,
  255: };
  256: 
  257: static QemuOptsList *find_list(const char *group)
  258: {
  259:     int i;
  260: 
  261:     for (i = 0; lists[i] != NULL; i++) {
  262:         if (strcmp(lists[i]->name, group) == 0)
  263:             break;
  264:     }
  265:     if (lists[i] == NULL) {
  266:         qemu_error("there is no option group \"%s\"\n", group);
  267:     }
  268:     return lists[i];
  269: }
  270: 
  271: int qemu_set_option(const char *str)
  272: {
  273:     char group[64], id[64], arg[64];
  274:     QemuOptsList *list;
  275:     QemuOpts *opts;
  276:     int rc, offset;
  277: 
  278:     rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
  279:     if (rc < 3 || str[offset] != '=') {
  280:         qemu_error("can't parse: \"%s\"\n", str);
  281:         return -1;
  282:     }
  283: 
  284:     list = find_list(group);
  285:     if (list == NULL) {
  286:         return -1;
  287:     }
  288: 
  289:     opts = qemu_opts_find(list, id);
  290:     if (!opts) {
  291:         qemu_error("there is no %s \"%s\" defined\n",
  292:                    list->name, id);
  293:         return -1;
  294:     }
  295: 
  296:     if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
  297:         return -1;
  298:     }
  299:     return 0;
  300: }
  301: 
  302: int qemu_global_option(const char *str)
  303: {
  304:     char driver[64], property[64];
  305:     QemuOpts *opts;
  306:     int rc, offset;
  307: 
  308:     rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
  309:     if (rc < 2 || str[offset] != '=') {
  310:         qemu_error("can't parse: \"%s\"\n", str);
  311:         return -1;
  312:     }
  313: 
  314:     opts = qemu_opts_create(&qemu_global_opts, NULL, 0);
  315:     qemu_opt_set(opts, "driver", driver);
  316:     qemu_opt_set(opts, "property", property);
  317:     qemu_opt_set(opts, "value", str+offset+1);
  318:     return 0;
  319: }
  320: 
  321: static int qemu_add_one_global(QemuOpts *opts, void *opaque)
  322: {
  323:     GlobalProperty *g;
  324: 
  325:     g = qemu_mallocz(sizeof(*g));
  326:     g->driver   = qemu_opt_get(opts, "driver");
  327:     g->property = qemu_opt_get(opts, "property");
  328:     g->value    = qemu_opt_get(opts, "value");
  329:     qdev_prop_register_global(g);
  330:     return 0;
  331: }
  332: 
  333: void qemu_add_globals(void)
  334: {
  335:     qemu_opts_foreach(&qemu_global_opts, qemu_add_one_global, NULL, 0);
  336: }
  337: 
  338: struct ConfigWriteData {
  339:     QemuOptsList *list;
  340:     FILE *fp;
  341: };
  342: 
  343: static int config_write_opt(const char *name, const char *value, void *opaque)
  344: {
  345:     struct ConfigWriteData *data = opaque;
  346: 
  347:     fprintf(data->fp, "  %s = \"%s\"\n", name, value);
  348:     return 0;
  349: }
  350: 
  351: static int config_write_opts(QemuOpts *opts, void *opaque)
  352: {
  353:     struct ConfigWriteData *data = opaque;
  354:     const char *id = qemu_opts_id(opts);
  355: 
  356:     if (id) {
  357:         fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
  358:     } else {
  359:         fprintf(data->fp, "[%s]\n", data->list->name);
  360:     }
  361:     qemu_opt_foreach(opts, config_write_opt, data, 0);
  362:     fprintf(data->fp, "\n");
  363:     return 0;
  364: }
  365: 
  366: void qemu_config_write(FILE *fp)
  367: {
  368:     struct ConfigWriteData data = { .fp = fp };
  369:     int i;
  370: 
  371:     fprintf(fp, "# qemu config file\n\n");
  372:     for (i = 0; lists[i] != NULL; i++) {
  373:         data.list = lists[i];
  374:         qemu_opts_foreach(data.list, config_write_opts, &data, 0);
  375:     }
  376: }
  377: 
  378: int qemu_config_parse(FILE *fp)
  379: {
  380:     char line[1024], group[64], id[64], arg[64], value[1024];
  381:     QemuOptsList *list = NULL;
  382:     QemuOpts *opts = NULL;
  383: 
  384:     while (fgets(line, sizeof(line), fp) != NULL) {
  385:         if (line[0] == '\n') {
  386:             /* skip empty lines */
  387:             continue;
  388:         }
  389:         if (line[0] == '#') {
  390:             /* comment */
  391:             continue;
  392:         }
  393:         if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
  394:             /* group with id */
  395:             list = find_list(group);
  396:             if (list == NULL)
  397:                 return -1;
  398:             opts = qemu_opts_create(list, id, 1);
  399:             continue;
  400:         }
  401:         if (sscanf(line, "[%63[^]]]", group) == 1) {
  402:             /* group without id */
  403:             list = find_list(group);
  404:             if (list == NULL)
  405:                 return -1;
  406:             opts = qemu_opts_create(list, NULL, 0);
  407:             continue;
  408:         }
  409:         if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
  410:             /* arg = value */
  411:             if (opts == NULL) {
  412:                 fprintf(stderr, "no group defined\n");
  413:                 return -1;
  414:             }
  415:             if (qemu_opt_set(opts, arg, value) != 0) {
  416:                 fprintf(stderr, "failed to set \"%s\" for %s\n",
  417:                         arg, group);
  418:                 return -1;
  419:             }
  420:             continue;
  421:         }
  422:         fprintf(stderr, "parse error: %s\n", line);
  423:         return -1;
  424:     }
  425:     return 0;
  426: }

unix.superglobalmegacorp.com