提交 df51a005 编写于 作者: P Peter Maydell

Merge remote-tracking branch 'remotes/elmarco/tags/option-pull-request' into staging

CLI help improvements

PULLv2:
 - fix uninitialized "seentype" variable in qom-test

# gpg: Signature made Fri 05 Oct 2018 13:28:21 BST
# gpg:                using RSA key DAE8E10975969CE5
# gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>"
# gpg:                 aka "Marc-André Lureau <marcandre.lureau@gmail.com>"
# Primary key fingerprint: 87A9 BD93 3F87 C606 D276  F62D DAE8 E109 7596 9CE5

* remotes/elmarco/tags/option-pull-request:
  vl: list user creatable properties when 'help' is argument
  hostmem: add some properties description
  vl: handle -object help
  tests/qom-proplist: check class properties iterator
  tests/qom-proplist: check properties are not listed multiple times
  tests/qom-proplist: check duplicate "bv" property registration failed
  qom/object: register 'type' property as class property
  qom/object: fix iterating properties over a class
  qemu-option: improve qemu_opts_print_help() output
  qemu-option: add help fallback to print the list of options
  cutils: add qemu_pstrcmp0()
  qdev-monitor: print help to stdout
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
...@@ -145,16 +145,25 @@ memfd_backend_class_init(ObjectClass *oc, void *data) ...@@ -145,16 +145,25 @@ memfd_backend_class_init(ObjectClass *oc, void *data)
memfd_backend_get_hugetlb, memfd_backend_get_hugetlb,
memfd_backend_set_hugetlb, memfd_backend_set_hugetlb,
&error_abort); &error_abort);
object_class_property_set_description(oc, "hugetlb",
"Use huge pages",
&error_abort);
object_class_property_add(oc, "hugetlbsize", "int", object_class_property_add(oc, "hugetlbsize", "int",
memfd_backend_get_hugetlbsize, memfd_backend_get_hugetlbsize,
memfd_backend_set_hugetlbsize, memfd_backend_set_hugetlbsize,
NULL, NULL, &error_abort); NULL, NULL, &error_abort);
object_class_property_set_description(oc, "hugetlbsize",
"Huge pages size (ex: 2M, 1G)",
&error_abort);
} }
if (qemu_memfd_check(MFD_ALLOW_SEALING)) { if (qemu_memfd_check(MFD_ALLOW_SEALING)) {
object_class_property_add_bool(oc, "seal", object_class_property_add_bool(oc, "seal",
memfd_backend_get_seal, memfd_backend_get_seal,
memfd_backend_set_seal, memfd_backend_set_seal,
&error_abort); &error_abort);
object_class_property_set_description(oc, "seal",
"Seal growing & shrinking",
&error_abort);
} }
} }
......
...@@ -397,27 +397,41 @@ host_memory_backend_class_init(ObjectClass *oc, void *data) ...@@ -397,27 +397,41 @@ host_memory_backend_class_init(ObjectClass *oc, void *data)
object_class_property_add_bool(oc, "merge", object_class_property_add_bool(oc, "merge",
host_memory_backend_get_merge, host_memory_backend_get_merge,
host_memory_backend_set_merge, &error_abort); host_memory_backend_set_merge, &error_abort);
object_class_property_set_description(oc, "merge",
"Mark memory as mergeable", &error_abort);
object_class_property_add_bool(oc, "dump", object_class_property_add_bool(oc, "dump",
host_memory_backend_get_dump, host_memory_backend_get_dump,
host_memory_backend_set_dump, &error_abort); host_memory_backend_set_dump, &error_abort);
object_class_property_set_description(oc, "dump",
"Set to 'off' to exclude from core dump", &error_abort);
object_class_property_add_bool(oc, "prealloc", object_class_property_add_bool(oc, "prealloc",
host_memory_backend_get_prealloc, host_memory_backend_get_prealloc,
host_memory_backend_set_prealloc, &error_abort); host_memory_backend_set_prealloc, &error_abort);
object_class_property_set_description(oc, "prealloc",
"Preallocate memory", &error_abort);
object_class_property_add(oc, "size", "int", object_class_property_add(oc, "size", "int",
host_memory_backend_get_size, host_memory_backend_get_size,
host_memory_backend_set_size, host_memory_backend_set_size,
NULL, NULL, &error_abort); NULL, NULL, &error_abort);
object_class_property_set_description(oc, "size",
"Size of the memory region (ex: 500M)", &error_abort);
object_class_property_add(oc, "host-nodes", "int", object_class_property_add(oc, "host-nodes", "int",
host_memory_backend_get_host_nodes, host_memory_backend_get_host_nodes,
host_memory_backend_set_host_nodes, host_memory_backend_set_host_nodes,
NULL, NULL, &error_abort); NULL, NULL, &error_abort);
object_class_property_set_description(oc, "host-nodes",
"Binds memory to the list of NUMA host nodes", &error_abort);
object_class_property_add_enum(oc, "policy", "HostMemPolicy", object_class_property_add_enum(oc, "policy", "HostMemPolicy",
&HostMemPolicy_lookup, &HostMemPolicy_lookup,
host_memory_backend_get_policy, host_memory_backend_get_policy,
host_memory_backend_set_policy, &error_abort); host_memory_backend_set_policy, &error_abort);
object_class_property_set_description(oc, "policy",
"Set the NUMA policy", &error_abort);
object_class_property_add_bool(oc, "share", object_class_property_add_bool(oc, "share",
host_memory_backend_get_share, host_memory_backend_set_share, host_memory_backend_get_share, host_memory_backend_set_share,
&error_abort); &error_abort);
object_class_property_set_description(oc, "share",
"Mark the memory as private to QEMU or shared", &error_abort);
} }
static const TypeInfo host_memory_backend_info = { static const TypeInfo host_memory_backend_info = {
......
...@@ -47,4 +47,7 @@ int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd); ...@@ -47,4 +47,7 @@ int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd);
void monitor_fdset_dup_fd_remove(int dup_fd); void monitor_fdset_dup_fd_remove(int dup_fd);
int monitor_fdset_dup_fd_find(int dup_fd); int monitor_fdset_dup_fd_find(int dup_fd);
void monitor_vfprintf(FILE *stream,
const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
#endif /* MONITOR_H */ #endif /* MONITOR_H */
...@@ -169,4 +169,16 @@ bool test_buffer_is_zero_next_accel(void); ...@@ -169,4 +169,16 @@ bool test_buffer_is_zero_next_accel(void);
int uleb128_encode_small(uint8_t *out, uint32_t n); int uleb128_encode_small(uint8_t *out, uint32_t n);
int uleb128_decode_small(const uint8_t *in, uint32_t *n); int uleb128_decode_small(const uint8_t *in, uint32_t *n);
/**
* qemu_pstrcmp0:
* @str1: a non-NULL pointer to a C string (*str1 can be NULL)
* @str2: a non-NULL pointer to a C string (*str2 can be NULL)
*
* Compares *str1 and *str2 with g_strcmp0().
*
* Returns: an integer less than, equal to, or greater than zero, if
* *str1 is <, == or > than *str2.
*/
int qemu_pstrcmp0(const char **str1, const char **str2);
#endif #endif
...@@ -4493,19 +4493,29 @@ static void monitor_readline_flush(void *opaque) ...@@ -4493,19 +4493,29 @@ static void monitor_readline_flush(void *opaque)
} }
/* /*
* Print to current monitor if we have one, else to stderr. * Print to current monitor if we have one, else to stream.
* TODO should return int, so callers can calculate width, but that * TODO should return int, so callers can calculate width, but that
* requires surgery to monitor_vprintf(). Left for another day. * requires surgery to monitor_vprintf(). Left for another day.
*/ */
void error_vprintf(const char *fmt, va_list ap) void monitor_vfprintf(FILE *stream, const char *fmt, va_list ap)
{ {
if (cur_mon && !monitor_cur_is_qmp()) { if (cur_mon && !monitor_cur_is_qmp()) {
monitor_vprintf(cur_mon, fmt, ap); monitor_vprintf(cur_mon, fmt, ap);
} else { } else {
vfprintf(stderr, fmt, ap); vfprintf(stream, fmt, ap);
} }
} }
/*
* Print to current monitor if we have one, else to stderr.
* TODO should return int, so callers can calculate width, but that
* requires surgery to monitor_vprintf(). Left for another day.
*/
void error_vprintf(const char *fmt, va_list ap)
{
monitor_vfprintf(stderr, fmt, ap);
}
void error_vprintf_unless_qmp(const char *fmt, va_list ap) void error_vprintf_unless_qmp(const char *fmt, va_list ap)
{ {
if (cur_mon && !monitor_cur_is_qmp()) { if (cur_mon && !monitor_cur_is_qmp()) {
......
...@@ -104,22 +104,31 @@ static bool qdev_class_has_alias(DeviceClass *dc) ...@@ -104,22 +104,31 @@ static bool qdev_class_has_alias(DeviceClass *dc)
return (qdev_class_get_alias(dc) != NULL); return (qdev_class_get_alias(dc) != NULL);
} }
static void out_printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
monitor_vfprintf(stdout, fmt, ap);
va_end(ap);
}
static void qdev_print_devinfo(DeviceClass *dc) static void qdev_print_devinfo(DeviceClass *dc)
{ {
error_printf("name \"%s\"", object_class_get_name(OBJECT_CLASS(dc))); out_printf("name \"%s\"", object_class_get_name(OBJECT_CLASS(dc)));
if (dc->bus_type) { if (dc->bus_type) {
error_printf(", bus %s", dc->bus_type); out_printf(", bus %s", dc->bus_type);
} }
if (qdev_class_has_alias(dc)) { if (qdev_class_has_alias(dc)) {
error_printf(", alias \"%s\"", qdev_class_get_alias(dc)); out_printf(", alias \"%s\"", qdev_class_get_alias(dc));
} }
if (dc->desc) { if (dc->desc) {
error_printf(", desc \"%s\"", dc->desc); out_printf(", desc \"%s\"", dc->desc);
} }
if (!dc->user_creatable) { if (!dc->user_creatable) {
error_printf(", no-user"); out_printf(", no-user");
} }
error_printf("\n"); out_printf("\n");
} }
static void qdev_print_devinfos(bool show_no_user) static void qdev_print_devinfos(bool show_no_user)
...@@ -155,8 +164,7 @@ static void qdev_print_devinfos(bool show_no_user) ...@@ -155,8 +164,7 @@ static void qdev_print_devinfos(bool show_no_user)
continue; continue;
} }
if (!cat_printed) { if (!cat_printed) {
error_printf("%s%s devices:\n", i ? "\n" : "", out_printf("%s%s devices:\n", i ? "\n" : "", cat_name[i]);
cat_name[i]);
cat_printed = true; cat_printed = true;
} }
qdev_print_devinfo(dc); qdev_print_devinfo(dc);
...@@ -278,13 +286,11 @@ int qdev_device_help(QemuOpts *opts) ...@@ -278,13 +286,11 @@ int qdev_device_help(QemuOpts *opts)
} }
for (prop = prop_list; prop; prop = prop->next) { for (prop = prop_list; prop; prop = prop->next) {
error_printf("%s.%s=%s", driver, out_printf("%s.%s=%s", driver, prop->value->name, prop->value->type);
prop->value->name,
prop->value->type);
if (prop->value->has_description) { if (prop->value->has_description) {
error_printf(" (%s)\n", prop->value->description); out_printf(" (%s)\n", prop->value->description);
} else { } else {
error_printf("\n"); out_printf("\n");
} }
} }
......
...@@ -1115,7 +1115,7 @@ void object_class_property_iter_init(ObjectPropertyIterator *iter, ...@@ -1115,7 +1115,7 @@ void object_class_property_iter_init(ObjectPropertyIterator *iter,
ObjectClass *klass) ObjectClass *klass)
{ {
g_hash_table_iter_init(&iter->iter, klass->properties); g_hash_table_iter_init(&iter->iter, klass->properties);
iter->nextclass = klass; iter->nextclass = object_class_get_parent(klass);
} }
ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name, ObjectProperty *object_class_property_find(ObjectClass *klass, const char *name,
...@@ -2430,9 +2430,10 @@ void object_class_property_set_description(ObjectClass *klass, ...@@ -2430,9 +2430,10 @@ void object_class_property_set_description(ObjectClass *klass,
op->description = g_strdup(description); op->description = g_strdup(description);
} }
static void object_instance_init(Object *obj) static void object_class_init(ObjectClass *klass, void *data)
{ {
object_property_add_str(obj, "type", qdev_get_type, NULL, NULL); object_class_property_add_str(klass, "type", qdev_get_type,
NULL, &error_abort);
} }
static void register_types(void) static void register_types(void)
...@@ -2446,7 +2447,7 @@ static void register_types(void) ...@@ -2446,7 +2447,7 @@ static void register_types(void)
static TypeInfo object_info = { static TypeInfo object_info = {
.name = TYPE_OBJECT, .name = TYPE_OBJECT,
.instance_size = sizeof(Object), .instance_size = sizeof(Object),
.instance_init = object_instance_init, .class_init = object_class_init,
.abstract = true, .abstract = true,
}; };
......
...@@ -141,14 +141,14 @@ Object *user_creatable_add_opts(QemuOpts *opts, Error **errp) ...@@ -141,14 +141,14 @@ Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
int user_creatable_add_opts_foreach(void *opaque, QemuOpts *opts, Error **errp) int user_creatable_add_opts_foreach(void *opaque, QemuOpts *opts, Error **errp)
{ {
bool (*type_predicate)(const char *) = opaque; bool (*type_opt_predicate)(const char *, QemuOpts *) = opaque;
Object *obj = NULL; Object *obj = NULL;
Error *err = NULL; Error *err = NULL;
const char *type; const char *type;
type = qemu_opt_get(opts, "qom-type"); type = qemu_opt_get(opts, "qom-type");
if (type && type_predicate && if (type && type_opt_predicate &&
!type_predicate(type)) { !type_opt_predicate(type, opts)) {
return 0; return 0;
} }
......
...@@ -125,10 +125,13 @@ static char *dummy_get_sv(Object *obj, ...@@ -125,10 +125,13 @@ static char *dummy_get_sv(Object *obj,
static void dummy_init(Object *obj) static void dummy_init(Object *obj)
{ {
Error *err = NULL;
object_property_add_bool(obj, "bv", object_property_add_bool(obj, "bv",
dummy_get_bv, dummy_get_bv,
dummy_set_bv, dummy_set_bv,
NULL); &err);
error_free_or_abort(&err);
} }
...@@ -517,32 +520,19 @@ static void test_dummy_getenum(void) ...@@ -517,32 +520,19 @@ static void test_dummy_getenum(void)
} }
static void test_dummy_iterator(void) static void test_dummy_prop_iterator(ObjectPropertyIterator *iter)
{ {
Object *parent = object_get_objects_root(); bool seenbv = false, seensv = false, seenav = false, seentype = false;
DummyObject *dobj = DUMMY_OBJECT(
object_new_with_props(TYPE_DUMMY,
parent,
"dummy0",
&error_abort,
"bv", "yes",
"sv", "Hiss hiss hiss",
"av", "platypus",
NULL));
ObjectProperty *prop; ObjectProperty *prop;
ObjectPropertyIterator iter;
bool seenbv = false, seensv = false, seenav = false, seentype;
object_property_iter_init(&iter, OBJECT(dobj)); while ((prop = object_property_iter_next(iter))) {
while ((prop = object_property_iter_next(&iter))) { if (!seenbv && g_str_equal(prop->name, "bv")) {
if (g_str_equal(prop->name, "bv")) {
seenbv = true; seenbv = true;
} else if (g_str_equal(prop->name, "sv")) { } else if (!seensv && g_str_equal(prop->name, "sv")) {
seensv = true; seensv = true;
} else if (g_str_equal(prop->name, "av")) { } else if (!seenav && g_str_equal(prop->name, "av")) {
seenav = true; seenav = true;
} else if (g_str_equal(prop->name, "type")) { } else if (!seentype && g_str_equal(prop->name, "type")) {
/* This prop comes from the base Object class */ /* This prop comes from the base Object class */
seentype = true; seentype = true;
} else { } else {
...@@ -554,10 +544,35 @@ static void test_dummy_iterator(void) ...@@ -554,10 +544,35 @@ static void test_dummy_iterator(void)
g_assert(seenav); g_assert(seenav);
g_assert(seensv); g_assert(seensv);
g_assert(seentype); g_assert(seentype);
}
static void test_dummy_iterator(void)
{
Object *parent = object_get_objects_root();
DummyObject *dobj = DUMMY_OBJECT(
object_new_with_props(TYPE_DUMMY,
parent,
"dummy0",
&error_abort,
"bv", "yes",
"sv", "Hiss hiss hiss",
"av", "platypus",
NULL));
ObjectPropertyIterator iter;
object_property_iter_init(&iter, OBJECT(dobj));
test_dummy_prop_iterator(&iter);
object_unparent(OBJECT(dobj)); object_unparent(OBJECT(dobj));
} }
static void test_dummy_class_iterator(void)
{
ObjectPropertyIterator iter;
ObjectClass *klass = object_class_by_name(TYPE_DUMMY);
object_class_property_iter_init(&iter, klass);
test_dummy_prop_iterator(&iter);
}
static void test_dummy_delchild(void) static void test_dummy_delchild(void)
{ {
...@@ -629,6 +644,7 @@ int main(int argc, char **argv) ...@@ -629,6 +644,7 @@ int main(int argc, char **argv)
g_test_add_func("/qom/proplist/badenum", test_dummy_badenum); g_test_add_func("/qom/proplist/badenum", test_dummy_badenum);
g_test_add_func("/qom/proplist/getenum", test_dummy_getenum); g_test_add_func("/qom/proplist/getenum", test_dummy_getenum);
g_test_add_func("/qom/proplist/iterator", test_dummy_iterator); g_test_add_func("/qom/proplist/iterator", test_dummy_iterator);
g_test_add_func("/qom/proplist/class_iterator", test_dummy_class_iterator);
g_test_add_func("/qom/proplist/delchild", test_dummy_delchild); g_test_add_func("/qom/proplist/delchild", test_dummy_delchild);
g_test_add_func("/qom/resolve/partial", test_qom_partial_path); g_test_add_func("/qom/resolve/partial", test_qom_partial_path);
......
...@@ -769,3 +769,8 @@ char *size_to_str(uint64_t val) ...@@ -769,3 +769,8 @@ char *size_to_str(uint64_t val)
return g_strdup_printf("%0.3g %sB", (double)val / div, suffixes[i]); return g_strdup_printf("%0.3g %sB", (double)val / div, suffixes[i]);
} }
int qemu_pstrcmp0(const char **str1, const char **str2)
{
return g_strcmp0(*str1, *str2);
}
...@@ -208,17 +208,51 @@ out: ...@@ -208,17 +208,51 @@ out:
return result; return result;
} }
static const char *opt_type_to_string(enum QemuOptType type)
{
switch (type) {
case QEMU_OPT_STRING:
return "str";
case QEMU_OPT_BOOL:
return "bool (on/off)";
case QEMU_OPT_NUMBER:
return "num";
case QEMU_OPT_SIZE:
return "size";
}
g_assert_not_reached();
}
void qemu_opts_print_help(QemuOptsList *list) void qemu_opts_print_help(QemuOptsList *list)
{ {
QemuOptDesc *desc; QemuOptDesc *desc;
int i;
GPtrArray *array = g_ptr_array_new();
assert(list); assert(list);
desc = list->desc; desc = list->desc;
while (desc && desc->name) { while (desc && desc->name) {
printf("%-16s %s\n", desc->name, GString *str = g_string_new(NULL);
desc->help ? desc->help : "No description available"); if (list->name) {
g_string_append_printf(str, "%s.", list->name);
}
g_string_append_printf(str, "%s=%s", desc->name,
opt_type_to_string(desc->type));
if (desc->help) {
g_string_append_printf(str, " - %s", desc->help);
}
g_ptr_array_add(array, g_string_free(str, false));
desc++; desc++;
} }
g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
for (i = 0; i < array->len; i++) {
printf("%s\n", (char *)array->pdata[i]);
}
g_ptr_array_set_free_func(array, g_free);
g_ptr_array_free(array, true);
} }
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
...@@ -486,7 +520,7 @@ int qemu_opt_unset(QemuOpts *opts, const char *name) ...@@ -486,7 +520,7 @@ int qemu_opt_unset(QemuOpts *opts, const char *name)
} }
static void opt_set(QemuOpts *opts, const char *name, char *value, static void opt_set(QemuOpts *opts, const char *name, char *value,
bool prepend, Error **errp) bool prepend, bool *invalidp, Error **errp)
{ {
QemuOpt *opt; QemuOpt *opt;
const QemuOptDesc *desc; const QemuOptDesc *desc;
...@@ -496,6 +530,9 @@ static void opt_set(QemuOpts *opts, const char *name, char *value, ...@@ -496,6 +530,9 @@ static void opt_set(QemuOpts *opts, const char *name, char *value,
if (!desc && !opts_accepts_any(opts)) { if (!desc && !opts_accepts_any(opts)) {
g_free(value); g_free(value);
error_setg(errp, QERR_INVALID_PARAMETER, name); error_setg(errp, QERR_INVALID_PARAMETER, name);
if (invalidp) {
*invalidp = true;
}
return; return;
} }
...@@ -519,7 +556,7 @@ static void opt_set(QemuOpts *opts, const char *name, char *value, ...@@ -519,7 +556,7 @@ static void opt_set(QemuOpts *opts, const char *name, char *value,
void qemu_opt_set(QemuOpts *opts, const char *name, const char *value, void qemu_opt_set(QemuOpts *opts, const char *name, const char *value,
Error **errp) Error **errp)
{ {
opt_set(opts, name, g_strdup(value), false, errp); opt_set(opts, name, g_strdup(value), false, NULL, errp);
} }
void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val, void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val,
...@@ -750,7 +787,8 @@ void qemu_opts_print(QemuOpts *opts, const char *separator) ...@@ -750,7 +787,8 @@ void qemu_opts_print(QemuOpts *opts, const char *separator)
} }
static void opts_do_parse(QemuOpts *opts, const char *params, static void opts_do_parse(QemuOpts *opts, const char *params,
const char *firstname, bool prepend, Error **errp) const char *firstname, bool prepend,
bool *invalidp, Error **errp)
{ {
char *option = NULL; char *option = NULL;
char *value = NULL; char *value = NULL;
...@@ -785,7 +823,7 @@ static void opts_do_parse(QemuOpts *opts, const char *params, ...@@ -785,7 +823,7 @@ static void opts_do_parse(QemuOpts *opts, const char *params,
} }
if (strcmp(option, "id") != 0) { if (strcmp(option, "id") != 0) {
/* store and parse */ /* store and parse */
opt_set(opts, option, value, prepend, &local_err); opt_set(opts, option, value, prepend, invalidp, &local_err);
value = NULL; value = NULL;
if (local_err) { if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
...@@ -814,11 +852,12 @@ static void opts_do_parse(QemuOpts *opts, const char *params, ...@@ -814,11 +852,12 @@ static void opts_do_parse(QemuOpts *opts, const char *params,
void qemu_opts_do_parse(QemuOpts *opts, const char *params, void qemu_opts_do_parse(QemuOpts *opts, const char *params,
const char *firstname, Error **errp) const char *firstname, Error **errp)
{ {
opts_do_parse(opts, params, firstname, false, errp); opts_do_parse(opts, params, firstname, false, NULL, errp);
} }
static QemuOpts *opts_parse(QemuOptsList *list, const char *params, static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
bool permit_abbrev, bool defaults, Error **errp) bool permit_abbrev, bool defaults,
bool *invalidp, Error **errp)
{ {
const char *firstname; const char *firstname;
char *id = NULL; char *id = NULL;
...@@ -850,7 +889,7 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, ...@@ -850,7 +889,7 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
return NULL; return NULL;
} }
opts_do_parse(opts, params, firstname, defaults, &local_err); opts_do_parse(opts, params, firstname, defaults, invalidp, &local_err);
if (local_err) { if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
qemu_opts_del(opts); qemu_opts_del(opts);
...@@ -870,7 +909,7 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, ...@@ -870,7 +909,7 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
bool permit_abbrev, Error **errp) bool permit_abbrev, Error **errp)
{ {
return opts_parse(list, params, permit_abbrev, false, errp); return opts_parse(list, params, permit_abbrev, false, NULL, errp);
} }
/** /**
...@@ -886,10 +925,16 @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params, ...@@ -886,10 +925,16 @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
{ {
Error *err = NULL; Error *err = NULL;
QemuOpts *opts; QemuOpts *opts;
bool invalidp = false;
opts = opts_parse(list, params, permit_abbrev, false, &err); opts = opts_parse(list, params, permit_abbrev, false, &invalidp, &err);
if (err) { if (err) {
error_report_err(err); if (invalidp && has_help_option(params)) {
qemu_opts_print_help(list);
error_free(err);
} else {
error_report_err(err);
}
} }
return opts; return opts;
} }
...@@ -899,7 +944,7 @@ void qemu_opts_set_defaults(QemuOptsList *list, const char *params, ...@@ -899,7 +944,7 @@ void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
{ {
QemuOpts *opts; QemuOpts *opts;
opts = opts_parse(list, params, permit_abbrev, true, NULL); opts = opts_parse(list, params, permit_abbrev, true, NULL, NULL);
assert(opts); assert(opts);
} }
......
...@@ -2696,8 +2696,55 @@ static int machine_set_property(void *opaque, ...@@ -2696,8 +2696,55 @@ static int machine_set_property(void *opaque,
* cannot be created here, as it depends on the chardev * cannot be created here, as it depends on the chardev
* already existing. * already existing.
*/ */
static bool object_create_initial(const char *type) static bool object_create_initial(const char *type, QemuOpts *opts)
{ {
ObjectClass *klass;
if (is_help_option(type)) {
GSList *l, *list;
printf("List of user creatable objects:\n");
list = object_class_get_list_sorted(TYPE_USER_CREATABLE, false);
for (l = list; l != NULL; l = l->next) {
ObjectClass *oc = OBJECT_CLASS(l->data);
printf("%s\n", object_class_get_name(oc));
}
g_slist_free(list);
exit(0);
}
klass = object_class_by_name(type);
if (klass && qemu_opt_has_help_opt(opts)) {
ObjectPropertyIterator iter;
ObjectProperty *prop;
GPtrArray *array = g_ptr_array_new();
int i;
object_class_property_iter_init(&iter, klass);
while ((prop = object_property_iter_next(&iter))) {
GString *str;
if (!prop->set) {
continue;
}
str = g_string_new(NULL);
g_string_append_printf(str, "%s.%s=%s", type,
prop->name, prop->type);
if (prop->description) {
g_string_append_printf(str, " - %s", prop->description);
}
g_ptr_array_add(array, g_string_free(str, false));
}
g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
for (i = 0; i < array->len; i++) {
printf("%s\n", (char *)array->pdata[i]);
}
g_ptr_array_set_free_func(array, g_free);
g_ptr_array_free(array, true);
exit(0);
}
if (g_str_equal(type, "rng-egd") || if (g_str_equal(type, "rng-egd") ||
g_str_has_prefix(type, "pr-manager-")) { g_str_has_prefix(type, "pr-manager-")) {
return false; return false;
...@@ -2744,9 +2791,9 @@ static bool object_create_initial(const char *type) ...@@ -2744,9 +2791,9 @@ static bool object_create_initial(const char *type)
* The remainder of object creation happens after the * The remainder of object creation happens after the
* creation of chardev, fsdev, net clients and device data types. * creation of chardev, fsdev, net clients and device data types.
*/ */
static bool object_create_delayed(const char *type) static bool object_create_delayed(const char *type, QemuOpts *opts)
{ {
return !object_create_initial(type); return !object_create_initial(type, opts);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册