Update <qemu/option.h>
Change-Id: Ic05c9302b47e52aa342595db74d34adf877bffb6
diff --git a/Makefile.target b/Makefile.target
index b4fb714..5a29a48 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -303,6 +303,7 @@
disas.c \
dma-helpers.c \
gdbstub.c \
+ qdev-monitor-android.c \
qemu-timer.c \
log-rotate-android.c \
vl-android.c \
@@ -321,6 +322,7 @@
util/bitmap.c \
util/bitops.c \
ui/keymaps.c \
+ util/qemu-config.c \
util/qemu-timer-common.c \
util/iov.c \
diff --git a/blockdev.c b/blockdev.c
index 5a024c9..73110e1 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -451,7 +451,7 @@
break;
case IF_VIRTIO:
/* add virtio block device */
- opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
+ opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0, NULL);
qemu_opt_set(opts, "driver", "virtio-blk-pci");
qemu_opt_set(opts, "drive", dinfo->id);
if (devaddr)
@@ -600,3 +600,15 @@
return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
}
#endif
+
+QemuOptsList qemu_drive_opts = {
+ .name = "drive",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
+ .desc = {
+ /*
+ * no elements => accept any params
+ * validation will happen later
+ */
+ { /* end of list */ }
+ },
+};
diff --git a/include/qemu/option.h b/include/qemu/option.h
index 6a70604..e5641f8 100644
--- a/include/qemu/option.h
+++ b/include/qemu/option.h
@@ -28,6 +28,7 @@
#include <stdint.h>
#include "qemu/queue.h"
+#include "qapi/error.h"
#include "qapi/qmp/qdict.h"
enum QEMUOptionParType {
@@ -45,6 +46,7 @@
char* s;
} value;
const char *help;
+ bool assigned;
} QEMUOptionParameter;
@@ -74,9 +76,13 @@
QEMUOptionParameter *list);
QEMUOptionParameter *parse_option_parameters(const char *param,
QEMUOptionParameter *list, QEMUOptionParameter *dest);
+void parse_option_size(const char *name, const char *value,
+ uint64_t *ret, Error **errp);
void free_option_parameters(QEMUOptionParameter *list);
void print_option_parameters(QEMUOptionParameter *list);
void print_option_help(QEMUOptionParameter *list);
+bool has_help_option(const char *param);
+bool is_valid_option_list(const char *param);
/* ------------------------------------------------------------------ */
@@ -100,32 +106,56 @@
struct QemuOptsList {
const char *name;
const char *implied_opt_name;
+ bool merge_lists; /* Merge multiple uses of option into a single list? */
QTAILQ_HEAD(, QemuOpts) head;
QemuOptDesc desc[];
};
const char *qemu_opt_get(QemuOpts *opts, const char *name);
-int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval);
+/**
+ * qemu_opt_has_help_opt:
+ * @opts: options to search for a help request
+ *
+ * Check whether the options specified by @opts include one of the
+ * standard strings which indicate that the user is asking for a
+ * list of the valid values for a command line option (as defined
+ * by is_help_option()).
+ *
+ * Returns: true if @opts includes 'help' or equivalent.
+ */
+bool qemu_opt_has_help_opt(QemuOpts *opts);
+bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval);
uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval);
uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval);
+int qemu_opt_unset(QemuOpts *opts, const char *name);
int qemu_opt_set(QemuOpts *opts, const char *name, const char *value);
+void qemu_opt_set_err(QemuOpts *opts, const char *name, const char *value,
+ Error **errp);
+int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val);
+int qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val);
typedef int (*qemu_opt_loopfunc)(const char *name, const char *value, void *opaque);
int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
int abort_on_failure);
QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id);
-QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists);
+QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id,
+ int fail_if_exists, Error **errp);
void qemu_opts_reset(QemuOptsList *list);
void qemu_opts_loc_restore(QemuOpts *opts);
int qemu_opts_set(QemuOptsList *list, const char *id,
const char *name, const char *value);
const char *qemu_opts_id(QemuOpts *opts);
+void qemu_opts_set_id(QemuOpts *opts, char *id);
void qemu_opts_del(QemuOpts *opts);
-int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc);
+void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp);
int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname);
QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, int permit_abbrev);
-QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict);
+void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
+ int permit_abbrev);
+QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
+ Error **errp);
QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict);
+void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp);
typedef int (*qemu_opts_loopfunc)(QemuOpts *opts, void *opaque);
int qemu_opts_print(QemuOpts *opts, void *dummy);
diff --git a/include/qemu/option_int.h b/include/qemu/option_int.h
new file mode 100644
index 0000000..8212fa4
--- /dev/null
+++ b/include/qemu/option_int.h
@@ -0,0 +1,54 @@
+/*
+ * Commandline option parsing functions
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2009 Kevin Wolf <kwolf@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_OPTIONS_INTERNAL_H
+#define QEMU_OPTIONS_INTERNAL_H
+
+#include "qemu/option.h"
+#include "qemu/error-report.h"
+
+struct QemuOpt {
+ const char *name;
+ const char *str;
+
+ const QemuOptDesc *desc;
+ union {
+ bool boolean;
+ uint64_t uint;
+ } value;
+
+ QemuOpts *opts;
+ QTAILQ_ENTRY(QemuOpt) next;
+};
+
+struct QemuOpts {
+ char *id;
+ QemuOptsList *list;
+ Location loc;
+ QTAILQ_HEAD(QemuOptHead, QemuOpt) head;
+ QTAILQ_ENTRY(QemuOpts) next;
+};
+
+#endif
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 34134e4..360a5f2 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -260,4 +260,14 @@
void register_devices(void);
+extern QemuOptsList qemu_legacy_drive_opts;
+extern QemuOptsList qemu_common_drive_opts;
+extern QemuOptsList qemu_drive_opts;
+extern QemuOptsList qemu_chardev_opts;
+extern QemuOptsList qemu_device_opts;
+extern QemuOptsList qemu_netdev_opts;
+extern QemuOptsList qemu_net_opts;
+extern QemuOptsList qemu_global_opts;
+extern QemuOptsList qemu_mon_opts;
+
#endif
diff --git a/qdev-monitor-android.c b/qdev-monitor-android.c
new file mode 100644
index 0000000..1b39077
--- /dev/null
+++ b/qdev-monitor-android.c
@@ -0,0 +1,52 @@
+/*
+ * Dynamic device configuration and creation.
+ *
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysemu/sysemu.h"
+
+QemuOptsList qemu_device_opts = {
+ .name = "device",
+ .implied_opt_name = "driver",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
+ .desc = {
+ /*
+ * no elements => accept any
+ * sanity checking will happen later
+ * when setting device properties
+ */
+ { /* end of list */ }
+ },
+};
+
+QemuOptsList qemu_global_opts = {
+ .name = "global",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
+ .desc = {
+ {
+ .name = "driver",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "property",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "value",
+ .type = QEMU_OPT_STRING,
+ },
+ { /* end of list */ }
+ },
+};
diff --git a/qemu-char.c b/qemu-char.c
index 70b0183..63d2efe 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2398,7 +2398,7 @@
const char *p;
QemuOpts *opts;
- opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1);
+ opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1, NULL);
if (NULL == opts)
return NULL;
@@ -2741,3 +2741,82 @@
}
return NULL;
}
+
+QemuOptsList qemu_chardev_opts = {
+ .name = "chardev",
+ .implied_opt_name = "backend",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head),
+ .desc = {
+ {
+ .name = "backend",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "path",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "host",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "port",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "localaddr",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "localport",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "to",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "ipv4",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "ipv6",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "wait",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "server",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "delay",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "telnet",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "width",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "height",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "cols",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "rows",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "mux",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "signal",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "name",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "debug",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "size",
+ .type = QEMU_OPT_SIZE,
+ },{
+ .name = "chardev",
+ .type = QEMU_OPT_STRING,
+ },
+ { /* end of list */ }
+ },
+};
diff --git a/ui/console.c b/ui/console.c
index e0ca59b..437030b 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1602,7 +1602,7 @@
int width, height;
char temp[32];
- opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1);
+ opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1, NULL);
if (NULL == opts)
return NULL;
diff --git a/util/qemu-config.c b/util/qemu-config.c
index 0813ce1..f4e4f38 100644
--- a/util/qemu-config.c
+++ b/util/qemu-config.c
@@ -2,472 +2,16 @@
#include "qemu/error-report.h"
#include "qemu/option.h"
#include "qemu/config-file.h"
+#include "qapi/qmp/qerror.h"
#include "hw/qdev.h"
+#include "qapi/error.h"
+#include "qmp-commands.h"
-static QemuOptsList qemu_drive_opts = {
- .name = "drive",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
- .desc = {
- {
- .name = "bus",
- .type = QEMU_OPT_NUMBER,
- .help = "bus number",
- },{
- .name = "unit",
- .type = QEMU_OPT_NUMBER,
- .help = "unit number (i.e. lun for scsi)",
- },{
- .name = "if",
- .type = QEMU_OPT_STRING,
- .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
- },{
- .name = "index",
- .type = QEMU_OPT_NUMBER,
- },{
- .name = "cyls",
- .type = QEMU_OPT_NUMBER,
- .help = "number of cylinders (ide disk geometry)",
- },{
- .name = "heads",
- .type = QEMU_OPT_NUMBER,
- .help = "number of heads (ide disk geometry)",
- },{
- .name = "secs",
- .type = QEMU_OPT_NUMBER,
- .help = "number of sectors (ide disk geometry)",
- },{
- .name = "trans",
- .type = QEMU_OPT_STRING,
- .help = "chs translation (auto, lba. none)",
- },{
- .name = "media",
- .type = QEMU_OPT_STRING,
- .help = "media type (disk, cdrom)",
- },{
- .name = "snapshot",
- .type = QEMU_OPT_BOOL,
- },{
- .name = "file",
- .type = QEMU_OPT_STRING,
- .help = "disk image",
- },{
- .name = "cache",
- .type = QEMU_OPT_STRING,
- .help = "host cache usage (none, writeback, writethrough, unsafe)",
- },{
- .name = "aio",
- .type = QEMU_OPT_STRING,
- .help = "host AIO implementation (threads, native)",
- },{
- .name = "format",
- .type = QEMU_OPT_STRING,
- .help = "disk format (raw, qcow2, ...)",
- },{
- .name = "serial",
- .type = QEMU_OPT_STRING,
- },{
- .name = "rerror",
- .type = QEMU_OPT_STRING,
- },{
- .name = "werror",
- .type = QEMU_OPT_STRING,
- },{
- .name = "addr",
- .type = QEMU_OPT_STRING,
- .help = "pci address (virtio only)",
- },{
- .name = "readonly",
- .type = QEMU_OPT_BOOL,
- },
- { /* end of list */ }
- },
-};
+static QemuOptsList *vm_config_groups[32];
+static QemuOptsList *drive_config_groups[4];
-static QemuOptsList qemu_chardev_opts = {
- .name = "chardev",
- .implied_opt_name = "backend",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head),
- .desc = {
- {
- .name = "backend",
- .type = QEMU_OPT_STRING,
- },{
- .name = "path",
- .type = QEMU_OPT_STRING,
- },{
- .name = "host",
- .type = QEMU_OPT_STRING,
- },{
- .name = "port",
- .type = QEMU_OPT_STRING,
- },{
- .name = "localaddr",
- .type = QEMU_OPT_STRING,
- },{
- .name = "localport",
- .type = QEMU_OPT_STRING,
- },{
- .name = "to",
- .type = QEMU_OPT_NUMBER,
- },{
- .name = "ipv4",
- .type = QEMU_OPT_BOOL,
- },{
- .name = "ipv6",
- .type = QEMU_OPT_BOOL,
- },{
- .name = "wait",
- .type = QEMU_OPT_BOOL,
- },{
- .name = "server",
- .type = QEMU_OPT_BOOL,
- },{
- .name = "delay",
- .type = QEMU_OPT_BOOL,
- },{
- .name = "telnet",
- .type = QEMU_OPT_BOOL,
- },{
- .name = "width",
- .type = QEMU_OPT_NUMBER,
- },{
- .name = "height",
- .type = QEMU_OPT_NUMBER,
- },{
- .name = "cols",
- .type = QEMU_OPT_NUMBER,
- },{
- .name = "rows",
- .type = QEMU_OPT_NUMBER,
- },{
- .name = "mux",
- .type = QEMU_OPT_BOOL,
- },{
- .name = "signal",
- .type = QEMU_OPT_BOOL,
- },{
- .name = "name",
- .type = QEMU_OPT_STRING,
- },{
- .name = "debug",
- .type = QEMU_OPT_NUMBER,
- },
- { /* end of list */ }
- },
-};
-
-QemuOptsList qemu_fsdev_opts = {
- .name = "fsdev",
- .implied_opt_name = "fstype",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head),
- .desc = {
- {
- .name = "fstype",
- .type = QEMU_OPT_STRING,
- }, {
- .name = "path",
- .type = QEMU_OPT_STRING,
- }, {
- .name = "security_model",
- .type = QEMU_OPT_STRING,
- },
- { /*End of list */ }
- },
-};
-
-QemuOptsList qemu_virtfs_opts = {
- .name = "virtfs",
- .implied_opt_name = "fstype",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head),
- .desc = {
- {
- .name = "fstype",
- .type = QEMU_OPT_STRING,
- }, {
- .name = "path",
- .type = QEMU_OPT_STRING,
- }, {
- .name = "mount_tag",
- .type = QEMU_OPT_STRING,
- }, {
- .name = "security_model",
- .type = QEMU_OPT_STRING,
- },
-
- { /*End of list */ }
- },
-};
-
-static QemuOptsList qemu_device_opts = {
- .name = "device",
- .implied_opt_name = "driver",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
- .desc = {
- /*
- * no elements => accept any
- * sanity checking will happen later
- * when setting device properties
- */
- { /* end of list */ }
- },
-};
-
-static QemuOptsList qemu_netdev_opts = {
- .name = "netdev",
- .implied_opt_name = "type",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
- .desc = {
- /*
- * no elements => accept any params
- * validation will happen later
- */
- { /* end of list */ }
- },
-};
-
-static QemuOptsList qemu_net_opts = {
- .name = "net",
- .implied_opt_name = "type",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
- .desc = {
- /*
- * no elements => accept any params
- * validation will happen later
- */
- { /* end of list */ }
- },
-};
-
-static QemuOptsList qemu_rtc_opts = {
- .name = "rtc",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head),
- .desc = {
- {
- .name = "base",
- .type = QEMU_OPT_STRING,
- },{
- .name = "clock",
- .type = QEMU_OPT_STRING,
- },{
- .name = "driftfix",
- .type = QEMU_OPT_STRING,
- },
- { /* end of list */ }
- },
-};
-
-static QemuOptsList qemu_global_opts = {
- .name = "global",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
- .desc = {
- {
- .name = "driver",
- .type = QEMU_OPT_STRING,
- },{
- .name = "property",
- .type = QEMU_OPT_STRING,
- },{
- .name = "value",
- .type = QEMU_OPT_STRING,
- },
- { /* end of list */ }
- },
-};
-
-static QemuOptsList qemu_mon_opts = {
- .name = "mon",
- .implied_opt_name = "chardev",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
- .desc = {
- {
- .name = "mode",
- .type = QEMU_OPT_STRING,
- },{
- .name = "chardev",
- .type = QEMU_OPT_STRING,
- },{
- .name = "default",
- .type = QEMU_OPT_BOOL,
- },{
- .name = "pretty",
- .type = QEMU_OPT_BOOL,
- },
- { /* end of list */ }
- },
-};
-
-#ifdef CONFIG_SIMPLE_TRACE
-static QemuOptsList qemu_trace_opts = {
- .name = "trace",
- .implied_opt_name = "trace",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
- .desc = {
- {
- .name = "file",
- .type = QEMU_OPT_STRING,
- },
- { /* end if list */ }
- },
-};
-#endif
-
-static QemuOptsList qemu_cpudef_opts = {
- .name = "cpudef",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head),
- .desc = {
- {
- .name = "name",
- .type = QEMU_OPT_STRING,
- },{
- .name = "level",
- .type = QEMU_OPT_NUMBER,
- },{
- .name = "vendor",
- .type = QEMU_OPT_STRING,
- },{
- .name = "family",
- .type = QEMU_OPT_NUMBER,
- },{
- .name = "model",
- .type = QEMU_OPT_NUMBER,
- },{
- .name = "stepping",
- .type = QEMU_OPT_NUMBER,
- },{
- .name = "feature_edx", /* cpuid 0000_0001.edx */
- .type = QEMU_OPT_STRING,
- },{
- .name = "feature_ecx", /* cpuid 0000_0001.ecx */
- .type = QEMU_OPT_STRING,
- },{
- .name = "extfeature_edx", /* cpuid 8000_0001.edx */
- .type = QEMU_OPT_STRING,
- },{
- .name = "extfeature_ecx", /* cpuid 8000_0001.ecx */
- .type = QEMU_OPT_STRING,
- },{
- .name = "xlevel",
- .type = QEMU_OPT_NUMBER,
- },{
- .name = "model_id",
- .type = QEMU_OPT_STRING,
- },{
- .name = "vendor_override",
- .type = QEMU_OPT_NUMBER,
- },
- { /* end of list */ }
- },
-};
-
-QemuOptsList qemu_spice_opts = {
- .name = "spice",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head),
- .desc = {
- {
- .name = "port",
- .type = QEMU_OPT_NUMBER,
- },{
- .name = "tls-port",
- .type = QEMU_OPT_NUMBER,
- },{
- .name = "addr",
- .type = QEMU_OPT_STRING,
- },{
- .name = "ipv4",
- .type = QEMU_OPT_BOOL,
- },{
- .name = "ipv6",
- .type = QEMU_OPT_BOOL,
- },{
- .name = "password",
- .type = QEMU_OPT_STRING,
- },{
- .name = "disable-ticketing",
- .type = QEMU_OPT_BOOL,
- },{
- .name = "x509-dir",
- .type = QEMU_OPT_STRING,
- },{
- .name = "x509-key-file",
- .type = QEMU_OPT_STRING,
- },{
- .name = "x509-key-password",
- .type = QEMU_OPT_STRING,
- },{
- .name = "x509-cert-file",
- .type = QEMU_OPT_STRING,
- },{
- .name = "x509-cacert-file",
- .type = QEMU_OPT_STRING,
- },{
- .name = "x509-dh-key-file",
- .type = QEMU_OPT_STRING,
- },{
- .name = "tls-ciphers",
- .type = QEMU_OPT_STRING,
- },{
- .name = "tls-channel",
- .type = QEMU_OPT_STRING,
- },{
- .name = "plaintext-channel",
- .type = QEMU_OPT_STRING,
- },{
- .name = "image-compression",
- .type = QEMU_OPT_STRING,
- },{
- .name = "jpeg-wan-compression",
- .type = QEMU_OPT_STRING,
- },{
- .name = "zlib-glz-wan-compression",
- .type = QEMU_OPT_STRING,
- },{
- .name = "streaming-video",
- .type = QEMU_OPT_STRING,
- },{
- .name = "agent-mouse",
- .type = QEMU_OPT_BOOL,
- },{
- .name = "playback-compression",
- .type = QEMU_OPT_BOOL,
- },
- { /* end if list */ }
- },
-};
-
-QemuOptsList qemu_option_rom_opts = {
- .name = "option-rom",
- .implied_opt_name = "romfile",
- .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head),
- .desc = {
- {
- .name = "bootindex",
- .type = QEMU_OPT_NUMBER,
- }, {
- .name = "romfile",
- .type = QEMU_OPT_STRING,
- },
- { /* end if list */ }
- },
-};
-
-static QemuOptsList *vm_config_groups[32] = {
- &qemu_drive_opts,
- &qemu_chardev_opts,
- &qemu_device_opts,
- &qemu_netdev_opts,
- &qemu_net_opts,
- &qemu_rtc_opts,
- &qemu_global_opts,
- &qemu_mon_opts,
- &qemu_cpudef_opts,
-#ifdef CONFIG_SIMPLE_TRACE
- &qemu_trace_opts,
-#endif
- &qemu_option_rom_opts,
- NULL,
-};
-
-static QemuOptsList *find_list(QemuOptsList **lists, const char *group)
+static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
+ Error **errp)
{
int i;
@@ -476,14 +20,182 @@
break;
}
if (lists[i] == NULL) {
- error_report("there is no option group \"%s\"", group);
+ error_setg(errp, "There is no option group '%s'", group);
}
return lists[i];
}
QemuOptsList *qemu_find_opts(const char *group)
{
- return find_list(vm_config_groups, group);
+ QemuOptsList *ret;
+ Error *local_err = NULL;
+
+ ret = find_list(vm_config_groups, group, &local_err);
+ if (local_err) {
+ error_report("%s", error_get_pretty(local_err));
+ error_free(local_err);
+ }
+
+ return ret;
+}
+
+QemuOpts *qemu_find_opts_singleton(const char *group)
+{
+ QemuOptsList *list;
+ QemuOpts *opts;
+
+ list = qemu_find_opts(group);
+ assert(list);
+ opts = qemu_opts_find(list, NULL);
+ if (!opts) {
+ opts = qemu_opts_create(list, NULL, 0, &error_abort);
+ }
+ return opts;
+}
+
+static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
+{
+ CommandLineParameterInfoList *param_list = NULL, *entry;
+ CommandLineParameterInfo *info;
+ int i;
+
+ for (i = 0; desc[i].name != NULL; i++) {
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strdup(desc[i].name);
+
+ switch (desc[i].type) {
+ case QEMU_OPT_STRING:
+ info->type = COMMAND_LINE_PARAMETER_TYPE_STRING;
+ break;
+ case QEMU_OPT_BOOL:
+ info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN;
+ break;
+ case QEMU_OPT_NUMBER:
+ info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER;
+ break;
+ case QEMU_OPT_SIZE:
+ info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE;
+ break;
+ }
+
+ if (desc[i].help) {
+ info->has_help = true;
+ info->help = g_strdup(desc[i].help);
+ }
+
+ entry = g_malloc0(sizeof(*entry));
+ entry->value = info;
+ entry->next = param_list;
+ param_list = entry;
+ }
+
+ return param_list;
+}
+
+/* remove repeated entry from the info list */
+static void cleanup_infolist(CommandLineParameterInfoList *head)
+{
+ CommandLineParameterInfoList *pre_entry, *cur, *del_entry;
+
+ cur = head;
+ while (cur->next) {
+ pre_entry = head;
+ while (pre_entry != cur->next) {
+ if (!strcmp(pre_entry->value->name, cur->next->value->name)) {
+ del_entry = cur->next;
+ cur->next = cur->next->next;
+ g_free(del_entry);
+ break;
+ }
+ pre_entry = pre_entry->next;
+ }
+ cur = cur->next;
+ }
+}
+
+/* merge the description items of two parameter infolists */
+static void connect_infolist(CommandLineParameterInfoList *head,
+ CommandLineParameterInfoList *new)
+{
+ CommandLineParameterInfoList *cur;
+
+ cur = head;
+ while (cur->next) {
+ cur = cur->next;
+ }
+ cur->next = new;
+}
+
+/* access all the local QemuOptsLists for drive option */
+static CommandLineParameterInfoList *get_drive_infolist(void)
+{
+ CommandLineParameterInfoList *head = NULL, *cur;
+ int i;
+
+ for (i = 0; drive_config_groups[i] != NULL; i++) {
+ if (!head) {
+ head = query_option_descs(drive_config_groups[i]->desc);
+ } else {
+ cur = query_option_descs(drive_config_groups[i]->desc);
+ connect_infolist(head, cur);
+ }
+ }
+ cleanup_infolist(head);
+
+ return head;
+}
+
+CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
+ const char *option,
+ Error **errp)
+{
+ CommandLineOptionInfoList *conf_list = NULL, *entry;
+ CommandLineOptionInfo *info;
+ int i;
+
+ for (i = 0; vm_config_groups[i] != NULL; i++) {
+ if (!has_option || !strcmp(option, vm_config_groups[i]->name)) {
+ info = g_malloc0(sizeof(*info));
+ info->option = g_strdup(vm_config_groups[i]->name);
+ if (!strcmp("drive", vm_config_groups[i]->name)) {
+ info->parameters = get_drive_infolist();
+ } else {
+ info->parameters =
+ query_option_descs(vm_config_groups[i]->desc);
+ }
+ entry = g_malloc0(sizeof(*entry));
+ entry->value = info;
+ entry->next = conf_list;
+ conf_list = entry;
+ }
+ }
+
+ if (conf_list == NULL) {
+ error_setg(errp, "invalid option name: %s", option);
+ }
+
+ return conf_list;
+}
+
+QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
+{
+ return find_list(vm_config_groups, group, errp);
+}
+
+void qemu_add_drive_opts(QemuOptsList *list)
+{
+ int entries, i;
+
+ entries = ARRAY_SIZE(drive_config_groups);
+ entries--; /* keep list NULL terminated */
+ for (i = 0; i < entries; i++) {
+ if (drive_config_groups[i] == NULL) {
+ drive_config_groups[i] = list;
+ return;
+ }
+ }
+ fprintf(stderr, "ran out of space in drive_config_groups");
+ abort();
}
void qemu_add_opts(QemuOptsList *list)
@@ -533,25 +245,6 @@
return 0;
}
-int qemu_global_option(const char *str)
-{
- char driver[64], property[64];
- QemuOpts *opts;
- int rc, offset;
-
- rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
- if (rc < 2 || str[offset] != '=') {
- error_report("can't parse: \"%s\"", str);
- return -1;
- }
-
- opts = qemu_opts_create(&qemu_global_opts, NULL, 0);
- qemu_opt_set(opts, "driver", driver);
- qemu_opt_set(opts, "property", property);
- qemu_opt_set(opts, "value", str+offset+1);
- return 0;
-}
-
struct ConfigWriteData {
QemuOptsList *list;
FILE *fp;
@@ -598,6 +291,7 @@
char line[1024], group[64], id[64], arg[64], value[1024];
Location loc;
QemuOptsList *list = NULL;
+ Error *local_err = NULL;
QemuOpts *opts = NULL;
int res = -1, lno = 0;
@@ -614,18 +308,24 @@
}
if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
/* group with id */
- list = find_list(lists, group);
- if (list == NULL)
+ list = find_list(lists, group, &local_err);
+ if (local_err) {
+ error_report("%s", error_get_pretty(local_err));
+ error_free(local_err);
goto out;
- opts = qemu_opts_create(list, id, 1);
+ }
+ opts = qemu_opts_create(list, id, 1, NULL);
continue;
}
if (sscanf(line, "[%63[^]]]", group) == 1) {
/* group without id */
- list = find_list(lists, group);
- if (list == NULL)
+ list = find_list(lists, group, &local_err);
+ if (local_err) {
+ error_report("%s", error_get_pretty(local_err));
+ error_free(local_err);
goto out;
- opts = qemu_opts_create(list, NULL, 0);
+ }
+ opts = qemu_opts_create(list, NULL, 0, &error_abort);
continue;
}
if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
@@ -670,3 +370,109 @@
return -EINVAL;
}
}
+
+static void config_parse_qdict_section(QDict *options, QemuOptsList *opts,
+ Error **errp)
+{
+ QemuOpts *subopts;
+ QDict *subqdict;
+ QList *list = NULL;
+ Error *local_err = NULL;
+ size_t orig_size, enum_size;
+ char *prefix;
+
+ prefix = g_strdup_printf("%s.", opts->name);
+ qdict_extract_subqdict(options, &subqdict, prefix);
+ g_free(prefix);
+ orig_size = qdict_size(subqdict);
+ if (!orig_size) {
+ goto out;
+ }
+
+ subopts = qemu_opts_create(opts, NULL, 0, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto out;
+ }
+
+ qemu_opts_absorb_qdict(subopts, subqdict, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto out;
+ }
+
+ enum_size = qdict_size(subqdict);
+ if (enum_size < orig_size && enum_size) {
+ error_setg(errp, "Unknown option '%s' for [%s]",
+ qdict_first(subqdict)->key, opts->name);
+ goto out;
+ }
+
+ if (enum_size) {
+ /* Multiple, enumerated sections */
+ QListEntry *list_entry;
+ unsigned i = 0;
+
+ /* Not required anymore */
+ qemu_opts_del(subopts);
+
+ qdict_array_split(subqdict, &list);
+ if (qdict_size(subqdict)) {
+ error_setg(errp, "Unused option '%s' for [%s]",
+ qdict_first(subqdict)->key, opts->name);
+ goto out;
+ }
+
+ QLIST_FOREACH_ENTRY(list, list_entry) {
+ QDict *section = qobject_to_qdict(qlist_entry_obj(list_entry));
+ char *opt_name;
+
+ if (!section) {
+ error_setg(errp, "[%s] section (index %u) does not consist of "
+ "keys", opts->name, i);
+ goto out;
+ }
+
+ opt_name = g_strdup_printf("%s.%u", opts->name, i++);
+ subopts = qemu_opts_create(opts, opt_name, 1, &local_err);
+ g_free(opt_name);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto out;
+ }
+
+ qemu_opts_absorb_qdict(subopts, section, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ qemu_opts_del(subopts);
+ goto out;
+ }
+
+ if (qdict_size(section)) {
+ error_setg(errp, "[%s] section doesn't support the option '%s'",
+ opts->name, qdict_first(section)->key);
+ qemu_opts_del(subopts);
+ goto out;
+ }
+ }
+ }
+
+out:
+ QDECREF(subqdict);
+ QDECREF(list);
+}
+
+void qemu_config_parse_qdict(QDict *options, QemuOptsList **lists,
+ Error **errp)
+{
+ int i;
+ Error *local_err = NULL;
+
+ for (i = 0; lists[i]; i++) {
+ config_parse_qdict_section(options, lists[i], &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
+}
diff --git a/util/qemu-option.c b/util/qemu-option.c
index 0bfea2d..e1db004 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -29,8 +29,9 @@
#include "qemu-common.h"
#include "qemu/error-report.h"
#include "qapi/qmp/types.h"
-#include "qemu/option.h"
+#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
+#include "qemu/option_int.h"
/*
* Extracts the name of an option from the parameter string (p points at the
@@ -151,7 +152,6 @@
}
return 0;
}
-
/*
* Searches an option list for an option with the given name
*/
@@ -168,7 +168,8 @@
return NULL;
}
-static int parse_option_bool(const char *name, const char *value, int *ret)
+static void parse_option_bool(const char *name, const char *value, bool *ret,
+ Error **errp)
{
if (value != NULL) {
if (!strcmp(value, "on")) {
@@ -176,16 +177,15 @@
} else if (!strcmp(value, "off")) {
*ret = 0;
} else {
- qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "'on' or 'off'");
- return -1;
+ error_set(errp,QERR_INVALID_PARAMETER_VALUE, name, "'on' or 'off'");
}
} else {
*ret = 1;
}
- return 0;
}
-static int parse_option_number(const char *name, const char *value, uint64_t *ret)
+static void parse_option_number(const char *name, const char *value,
+ uint64_t *ret, Error **errp)
{
char *postfix;
uint64_t number;
@@ -193,18 +193,17 @@
if (value != NULL) {
number = strtoull(value, &postfix, 0);
if (*postfix != '\0') {
- qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "a number");
- return -1;
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number");
+ return;
}
*ret = number;
} else {
- qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "a number");
- return -1;
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number");
}
- return 0;
}
-static int parse_option_size(const char *name, const char *value, uint64_t *ret)
+void parse_option_size(const char *name, const char *value,
+ uint64_t *ret, Error **errp)
{
char *postfix;
double sizef;
@@ -214,28 +213,32 @@
switch (*postfix) {
case 'T':
sizef *= 1024;
+ /* fall through */
case 'G':
sizef *= 1024;
+ /* fall through */
case 'M':
sizef *= 1024;
+ /* fall through */
case 'K':
case 'k':
sizef *= 1024;
+ /* fall through */
case 'b':
case '\0':
*ret = (uint64_t) sizef;
break;
default:
- qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "a size");
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, name, "a size");
+#if 0 /* conversion from qerror_report() to error_set() broke this: */
error_printf_unless_qmp("You may use k, M, G or T suffixes for "
"kilobytes, megabytes, gigabytes and terabytes.\n");
- return -1;
+#endif
+ return;
}
} else {
- qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "a size");
- return -1;
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, name, "a size");
}
- return 0;
}
/*
@@ -258,7 +261,8 @@
int set_option_parameter(QEMUOptionParameter *list, const char *name,
const char *value)
{
- int flag;
+ bool flag;
+ Error *local_err = NULL;
// Find a matching parameter
list = get_option_parameter(list, name);
@@ -270,9 +274,10 @@
// Process parameter
switch (list->type) {
case OPT_FLAG:
- if (parse_option_bool(name, value, &flag) == -1)
- return -1;
- list->value.n = flag;
+ parse_option_bool(name, value, &flag, &local_err);
+ if (!local_err) {
+ list->value.n = flag;
+ }
break;
case OPT_STRING:
@@ -285,8 +290,7 @@
break;
case OPT_SIZE:
- if (parse_option_size(name, value, &list->value.n) == -1)
- return -1;
+ parse_option_size(name, value, &list->value.n, &local_err);
break;
default:
@@ -294,6 +298,14 @@
return -1;
}
+ if (local_err) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ return -1;
+ }
+
+ list->assigned = true;
+
return 0;
}
@@ -325,6 +337,8 @@
return -1;
}
+ list->assigned = true;
+
return 0;
}
@@ -416,6 +430,7 @@
char value[256];
char *param_delim, *value_delim;
char next_delim;
+ int i;
if (list == NULL) {
return NULL;
@@ -425,6 +440,10 @@
dest = allocated = append_option_parameters(NULL, list);
}
+ for (i = 0; dest[i].name; i++) {
+ dest[i].assigned = false;
+ }
+
while (*param) {
// Find parameter name and value in the string
@@ -460,6 +479,55 @@
return NULL;
}
+bool has_help_option(const char *param)
+{
+ size_t buflen = strlen(param) + 1;
+ char *buf = g_malloc0(buflen);
+ const char *p = param;
+ bool result = false;
+
+ while (*p) {
+ p = get_opt_value(buf, buflen, p);
+ if (*p) {
+ p++;
+ }
+
+ if (is_help_option(buf)) {
+ result = true;
+ goto out;
+ }
+ }
+
+out:
+ free(buf);
+ return result;
+}
+
+bool is_valid_option_list(const char *param)
+{
+ size_t buflen = strlen(param) + 1;
+ char *buf = g_malloc0(buflen);
+ const char *p = param;
+ bool result = true;
+
+ while (*p) {
+ p = get_opt_value(buf, buflen, p);
+ if (*p && !*++p) {
+ result = false;
+ goto out;
+ }
+
+ if (!*buf || *buf == ',') {
+ result = false;
+ goto out;
+ }
+ }
+
+out:
+ free(buf);
+ return result;
+}
+
/*
* Prints all options of a list that have a value to stdout
*/
@@ -480,7 +548,7 @@
printf("%s=%" PRId64 " ", list->name, list->value.n);
break;
default:
- printf("%s=(unkown type) ", list->name);
+ printf("%s=(unknown type) ", list->name);
break;
}
list++;
@@ -502,28 +570,6 @@
/* ------------------------------------------------------------------ */
-struct QemuOpt {
- const char *name;
- const char *str;
-
- const QemuOptDesc *desc;
- union {
- int boolean;
- uint64_t uint;
- } value;
-
- QemuOpts *opts;
- QTAILQ_ENTRY(QemuOpt) next;
-};
-
-struct QemuOpts {
- char *id;
- QemuOptsList *list;
- Location loc;
- QTAILQ_HEAD(QemuOptHead, QemuOpt) head;
- QTAILQ_ENTRY(QemuOpts) next;
-};
-
static QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name)
{
QemuOpt *opt;
@@ -542,7 +588,19 @@
return opt ? opt->str : NULL;
}
-int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval)
+bool qemu_opt_has_help_opt(QemuOpts *opts)
+{
+ QemuOpt *opt;
+
+ QTAILQ_FOREACH_REVERSE(opt, &opts->head, QemuOptHead, next) {
+ if (is_help_option(opt->name)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval)
{
QemuOpt *opt = qemu_opt_find(opts, name);
@@ -572,20 +630,24 @@
return opt->value.uint;
}
-static int qemu_opt_parse(QemuOpt *opt)
+static void qemu_opt_parse(QemuOpt *opt, Error **errp)
{
if (opt->desc == NULL)
- return 0;
+ return;
+
switch (opt->desc->type) {
case QEMU_OPT_STRING:
/* nothing */
- return 0;
+ return;
case QEMU_OPT_BOOL:
- return parse_option_bool(opt->name, opt->str, &opt->value.boolean);
+ parse_option_bool(opt->name, opt->str, &opt->value.boolean, errp);
+ break;
case QEMU_OPT_NUMBER:
- return parse_option_number(opt->name, opt->str, &opt->value.uint);
+ parse_option_number(opt->name, opt->str, &opt->value.uint, errp);
+ break;
case QEMU_OPT_SIZE:
- return parse_option_size(opt->name, opt->str, &opt->value.uint);
+ parse_option_size(opt->name, opt->str, &opt->value.uint, errp);
+ break;
default:
abort();
}
@@ -599,40 +661,130 @@
g_free(opt);
}
-int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
+static bool opts_accepts_any(const QemuOpts *opts)
{
- QemuOpt *opt;
- const QemuOptDesc *desc = opts->list->desc;
+ return opts->list->desc[0].name == NULL;
+}
+
+static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc,
+ const char *name)
+{
int i;
for (i = 0; desc[i].name != NULL; i++) {
if (strcmp(desc[i].name, name) == 0) {
- break;
+ return &desc[i];
}
}
- if (desc[i].name == NULL) {
- if (i == 0) {
- /* empty list -> allow any */;
- } else {
- qerror_report(QERR_INVALID_PARAMETER, name);
- return -1;
- }
+
+ return NULL;
+}
+
+int qemu_opt_unset(QemuOpts *opts, const char *name)
+{
+ QemuOpt *opt = qemu_opt_find(opts, name);
+
+ assert(opts_accepts_any(opts));
+
+ if (opt == NULL) {
+ return -1;
+ } else {
+ qemu_opt_del(opt);
+ return 0;
+ }
+}
+
+static void opt_set(QemuOpts *opts, const char *name, const char *value,
+ bool prepend, Error **errp)
+{
+ QemuOpt *opt;
+ const QemuOptDesc *desc;
+ Error *local_err = NULL;
+
+ desc = find_desc_by_name(opts->list->desc, name);
+ if (!desc && !opts_accepts_any(opts)) {
+ error_set(errp, QERR_INVALID_PARAMETER, name);
+ return;
}
opt = g_malloc0(sizeof(*opt));
opt->name = g_strdup(name);
opt->opts = opts;
- QTAILQ_INSERT_TAIL(&opts->head, opt, next);
- if (desc[i].name != NULL) {
- opt->desc = desc+i;
+ if (prepend) {
+ QTAILQ_INSERT_HEAD(&opts->head, opt, next);
+ } else {
+ QTAILQ_INSERT_TAIL(&opts->head, opt, next);
}
- if (value) {
- opt->str = g_strdup(value);
- }
- if (qemu_opt_parse(opt) < 0) {
+ opt->desc = desc;
+ opt->str = g_strdup(value);
+ qemu_opt_parse(opt, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
qemu_opt_del(opt);
+ }
+}
+
+int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
+{
+ Error *local_err = NULL;
+
+ opt_set(opts, name, value, false, &local_err);
+ if (local_err) {
+ qerror_report_err(local_err);
+ error_free(local_err);
return -1;
}
+
+ return 0;
+}
+
+void qemu_opt_set_err(QemuOpts *opts, const char *name, const char *value,
+ Error **errp)
+{
+ opt_set(opts, name, value, false, errp);
+}
+
+int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val)
+{
+ QemuOpt *opt;
+ const QemuOptDesc *desc = opts->list->desc;
+
+ opt = g_malloc0(sizeof(*opt));
+ opt->desc = find_desc_by_name(desc, name);
+ if (!opt->desc && !opts_accepts_any(opts)) {
+ qerror_report(QERR_INVALID_PARAMETER, name);
+ g_free(opt);
+ return -1;
+ }
+
+ opt->name = g_strdup(name);
+ opt->opts = opts;
+ opt->value.boolean = !!val;
+ opt->str = g_strdup(val ? "on" : "off");
+ QTAILQ_INSERT_TAIL(&opts->head, opt, next);
+
+ return 0;
+}
+
+int qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val)
+{
+ QemuOpt *opt;
+ const QemuOptDesc *desc = opts->list->desc;
+
+ opt = g_malloc0(sizeof(*opt));
+ opt->desc = find_desc_by_name(desc, name);
+ if (!opt->desc && !opts_accepts_any(opts)) {
+ qerror_report(QERR_INVALID_PARAMETER, name);
+ g_free(opt);
+ return -1;
+ }
+
+ opt->name = g_strdup(name);
+ opt->opts = opts;
+ opt->value.uint = val;
+ opt->str = g_strdup_printf("%" PRId64, val);
+ QTAILQ_INSERT_TAIL(&opts->head, opt, next);
+
return 0;
}
@@ -655,13 +807,12 @@
QemuOpts *opts;
QTAILQ_FOREACH(opts, &list->head, next) {
- if (!opts->id) {
- continue;
+ if (!opts->id && !id) {
+ return opts;
}
- if (strcmp(opts->id, id) != 0) {
- continue;
+ if (opts->id && id && !strcmp(opts->id, id)) {
+ return opts;
}
- return opts;
}
return NULL;
}
@@ -681,30 +832,36 @@
return 1;
}
-QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists)
+QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id,
+ int fail_if_exists, Error **errp)
{
QemuOpts *opts = NULL;
if (id) {
if (!id_wellformed(id)) {
- qerror_report(QERR_INVALID_PARAMETER_VALUE, "id", "an identifier");
+ error_set(errp,QERR_INVALID_PARAMETER_VALUE, "id", "an identifier");
+#if 0 /* conversion from qerror_report() to error_set() broke this: */
error_printf_unless_qmp("Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.\n");
+#endif
return NULL;
}
opts = qemu_opts_find(list, id);
if (opts != NULL) {
- if (fail_if_exists) {
- qerror_report(QERR_DUPLICATE_ID, id, list->name);
+ if (fail_if_exists && !list->merge_lists) {
+ error_set(errp, QERR_DUPLICATE_ID, id, list->name);
return NULL;
} else {
return opts;
}
}
+ } else if (list->merge_lists) {
+ opts = qemu_opts_find(list, NULL);
+ if (opts) {
+ return opts;
+ }
}
opts = g_malloc0(sizeof(*opts));
- if (id) {
- opts->id = g_strdup(id);
- }
+ opts->id = g_strdup(id);
opts->list = list;
loc_save(&opts->loc);
QTAILQ_INIT(&opts->head);
@@ -730,9 +887,12 @@
const char *name, const char *value)
{
QemuOpts *opts;
+ Error *local_err = NULL;
- opts = qemu_opts_create(list, id, 1);
- if (opts == NULL) {
+ opts = qemu_opts_create(list, id, 1, &local_err);
+ if (local_err) {
+ qerror_report_err(local_err);
+ error_free(local_err);
return -1;
}
return qemu_opt_set(opts, name, value);
@@ -743,6 +903,12 @@
return opts->id;
}
+/* The id string will be g_free()d by qemu_opts_del */
+void qemu_opts_set_id(QemuOpts *opts, char *id)
+{
+ opts->id = id;
+}
+
void qemu_opts_del(QemuOpts *opts)
{
QemuOpt *opt;
@@ -771,10 +937,12 @@
return 0;
}
-int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname)
+static int opts_do_parse(QemuOpts *opts, const char *params,
+ const char *firstname, bool prepend)
{
char option[128], value[1024];
const char *p,*pe,*pc;
+ Error *local_err = NULL;
for (p = params; *p != '\0'; p++) {
pe = strchr(p, '=');
@@ -806,7 +974,10 @@
}
if (strcmp(option, "id") != 0) {
/* store and parse */
- if (qemu_opt_set(opts, option, value) == -1) {
+ opt_set(opts, option, value, prepend, &local_err);
+ if (local_err) {
+ qerror_report_err(local_err);
+ error_free(local_err);
return -1;
}
}
@@ -817,13 +988,19 @@
return 0;
}
-QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
- int permit_abbrev)
+int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname)
+{
+ return opts_do_parse(opts, params, firstname, false);
+}
+
+static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
+ int permit_abbrev, bool defaults)
{
const char *firstname;
char value[1024], *id = NULL;
const char *p;
QemuOpts *opts;
+ Error *local_err = NULL;
assert(!permit_abbrev || list->implied_opt_name);
firstname = permit_abbrev ? list->implied_opt_name : NULL;
@@ -835,11 +1012,25 @@
get_opt_value(value, sizeof(value), p+4);
id = value;
}
- opts = qemu_opts_create(list, id, 1);
- if (opts == NULL)
- return NULL;
- if (qemu_opts_do_parse(opts, params, firstname) != 0) {
+ /*
+ * This code doesn't work for defaults && !list->merge_lists: when
+ * params has no id=, and list has an element with !opts->id, it
+ * appends a new element instead of returning the existing opts.
+ * However, we got no use for this case. Guard against possible
+ * (if unlikely) future misuse:
+ */
+ assert(!defaults || list->merge_lists);
+ opts = qemu_opts_create(list, id, !defaults, &local_err);
+ if (opts == NULL) {
+ if (local_err) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ }
+ return NULL;
+ }
+
+ if (opts_do_parse(opts, params, firstname, defaults) != 0) {
qemu_opts_del(opts);
return NULL;
}
@@ -847,13 +1038,34 @@
return opts;
}
+QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
+ int permit_abbrev)
+{
+ return opts_parse(list, params, permit_abbrev, false);
+}
+
+void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
+ int permit_abbrev)
+{
+ QemuOpts *opts;
+
+ opts = opts_parse(list, params, permit_abbrev, true);
+ assert(opts);
+}
+
+typedef struct OptsFromQDictState {
+ QemuOpts *opts;
+ Error **errp;
+} OptsFromQDictState;
+
static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque)
{
+ OptsFromQDictState *state = opaque;
char buf[32];
const char *value;
int n;
- if (!strcmp(key, "id")) {
+ if (!strcmp(key, "id") || error_is_set(state->errp)) {
return;
}
@@ -881,7 +1093,8 @@
default:
return;
}
- qemu_opt_set(opaque, key, value);
+
+ qemu_opt_set_err(state->opts, key, value, state->errp);
}
/*
@@ -890,19 +1103,69 @@
* Only QStrings, QInts, QFloats and QBools are copied. Entries with
* other types are silently ignored.
*/
-QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict)
+QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
+ Error **errp)
{
+ OptsFromQDictState state;
+ Error *local_err = NULL;
QemuOpts *opts;
- opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1);
- if (opts == NULL)
+ opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1,
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return NULL;
+ }
- qdict_iter(qdict, qemu_opts_from_qdict_1, opts);
+ assert(opts != NULL);
+
+ state.errp = &local_err;
+ state.opts = opts;
+ qdict_iter(qdict, qemu_opts_from_qdict_1, &state);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ qemu_opts_del(opts);
+ return NULL;
+ }
+
return opts;
}
/*
+ * Adds all QDict entries to the QemuOpts that can be added and removes them
+ * from the QDict. When this function returns, the QDict contains only those
+ * entries that couldn't be added to the QemuOpts.
+ */
+void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp)
+{
+ const QDictEntry *entry, *next;
+
+ entry = qdict_first(qdict);
+
+ while (entry != NULL) {
+ Error *local_err = NULL;
+ OptsFromQDictState state = {
+ .errp = &local_err,
+ .opts = opts,
+ };
+
+ next = qdict_next(qdict, entry);
+
+ if (find_desc_by_name(opts->list->desc, entry->key)) {
+ qemu_opts_from_qdict_1(entry->key, entry->value, &state);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ } else {
+ qdict_del(qdict, entry->key);
+ }
+ }
+
+ entry = next;
+ }
+}
+
+/*
* Convert from QemuOpts to QDict.
* The QDict values are of type QString.
* TODO We'll want to use types appropriate for opt->desc->type, but
@@ -929,33 +1192,26 @@
/* Validate parsed opts against descriptions where no
* descriptions were provided in the QemuOptsList.
*/
-int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc)
+void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp)
{
QemuOpt *opt;
+ Error *local_err = NULL;
- assert(opts->list->desc[0].name == NULL);
+ assert(opts_accepts_any(opts));
QTAILQ_FOREACH(opt, &opts->head, next) {
- int i;
-
- for (i = 0; desc[i].name != NULL; i++) {
- if (strcmp(desc[i].name, opt->name) == 0) {
- break;
- }
- }
- if (desc[i].name == NULL) {
- qerror_report(QERR_INVALID_PARAMETER, opt->name);
- return -1;
+ opt->desc = find_desc_by_name(desc, opt->name);
+ if (!opt->desc) {
+ error_set(errp, QERR_INVALID_PARAMETER, opt->name);
+ return;
}
- opt->desc = &desc[i];
-
- if (qemu_opt_parse(opt) < 0) {
- return -1;
+ qemu_opt_parse(opt, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
}
}
-
- return 0;
}
int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque,
diff --git a/util/qemu-sockets-android.c b/util/qemu-sockets-android.c
index aa06256..371a7e4 100644
--- a/util/qemu-sockets-android.c
+++ b/util/qemu-sockets-android.c
@@ -447,7 +447,7 @@
char *optstr;
int sock = -1;
- opts = qemu_opts_create(&dummy_opts, NULL, 0);
+ opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL);
if (inet_parse(opts, str) == 0) {
sock = inet_listen_opts(opts, port_offset);
if (sock != -1 && ostr) {
@@ -474,7 +474,7 @@
QemuOpts *opts;
int sock = -1;
- opts = qemu_opts_create(&dummy_opts, NULL, 0);
+ opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL);
if (inet_parse(opts, str) == 0)
sock = inet_connect_opts(opts);
qemu_opts_del(opts);
@@ -558,7 +558,7 @@
char *path, *optstr;
int sock, len;
- opts = qemu_opts_create(&dummy_opts, NULL, 0);
+ opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL);
optstr = strchr(str, ',');
if (optstr) {
@@ -586,7 +586,7 @@
QemuOpts *opts;
int sock;
- opts = qemu_opts_create(&dummy_opts, NULL, 0);
+ opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL);
qemu_opt_set(opts, "path", path);
sock = unix_connect_opts(opts);
qemu_opts_del(opts);
diff --git a/vl-android.c b/vl-android.c
index 8c8738a..decfdbb 100644
--- a/vl-android.c
+++ b/vl-android.c
@@ -2128,6 +2128,34 @@
os_setup_early_signal_handling();
module_call_init(MODULE_INIT_MACHINE);
+
+ module_call_init(MODULE_INIT_QOM);
+
+ qemu_add_opts(&qemu_drive_opts);
+ //qemu_add_drive_opts(&qemu_legacy_drive_opts);
+ //qemu_add_drive_opts(&qemu_common_drive_opts);
+ qemu_add_drive_opts(&qemu_drive_opts);
+ qemu_add_opts(&qemu_chardev_opts);
+ qemu_add_opts(&qemu_device_opts);
+ //qemu_add_opts(&qemu_netdev_opts);
+ //qemu_add_opts(&qemu_net_opts);
+ //qemu_add_opts(&qemu_rtc_opts);
+ //qemu_add_opts(&qemu_global_opts);
+ //qemu_add_opts(&qemu_mon_opts);
+ //qemu_add_opts(&qemu_trace_opts);
+ //qemu_add_opts(&qemu_option_rom_opts);
+ //qemu_add_opts(&qemu_machine_opts);
+ //qemu_add_opts(&qemu_mem_opts);
+ //qemu_add_opts(&qemu_smp_opts);
+ //qemu_add_opts(&qemu_boot_opts);
+ //qemu_add_opts(&qemu_sandbox_opts);
+ //qemu_add_opts(&qemu_add_fd_opts);
+ //qemu_add_opts(&qemu_object_opts);
+ //qemu_add_opts(&qemu_tpmdev_opts);
+ //qemu_add_opts(&qemu_realtime_opts);
+ //qemu_add_opts(&qemu_msg_opts);
+ //qemu_add_opts(&qemu_name_opts);
+
machine = find_default_machine();
cpu_model = NULL;
initrd_filename = NULL;