2016-01-29 18:50:02 +01:00
|
|
|
#include "qemu/osdep.h"
|
2019-10-11 19:20:12 +02:00
|
|
|
|
|
|
|
#include "qemu/cutils.h"
|
include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef. Since then, we've moved to include qemu/osdep.h
everywhere. Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h. That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h. Include qapi/error.h in .c files that need it and don't
get it now. Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly. Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h. Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third. Unfortunately, the number depending on
qapi-types.h shrinks only a little. More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-03-14 09:01:28 +01:00
|
|
|
#include "qapi/error.h"
|
2018-02-01 12:18:39 +01:00
|
|
|
#include "qapi/qmp/qdict.h"
|
2018-02-11 10:35:39 +01:00
|
|
|
#include "qapi/qmp/qerror.h"
|
2020-01-10 16:30:37 +01:00
|
|
|
#include "qapi/qmp/qjson.h"
|
|
|
|
#include "qapi/qmp/qstring.h"
|
2020-04-16 17:04:20 +02:00
|
|
|
#include "qapi/qobject-input-visitor.h"
|
2014-01-16 17:34:38 +01:00
|
|
|
#include "qom/object_interfaces.h"
|
2019-10-11 19:20:12 +02:00
|
|
|
#include "qemu/help_option.h"
|
2014-01-16 17:34:38 +01:00
|
|
|
#include "qemu/module.h"
|
2018-02-01 12:18:46 +01:00
|
|
|
#include "qemu/option.h"
|
2016-02-10 19:40:59 +01:00
|
|
|
#include "qapi/opts-visitor.h"
|
monitor: fix object_del for command-line-created objects
Currently objects specified on the command-line are only partially
cleaned up when 'object_del' is issued in either HMP or QMP: the
object itself is fully finalized, but the QemuOpts are not removed.
This results in the following behavior:
x86_64-softmmu/qemu-system-x86_64 -monitor stdio \
-object memory-backend-ram,id=ram1,size=256M
QEMU 2.7.91 monitor - type 'help' for more information
(qemu) object_del ram1
(qemu) object_del ram1
object 'ram1' not found
(qemu) object_add memory-backend-ram,id=ram1,size=256M
Duplicate ID 'ram1' for object
Try "help object_add" for more information
which can be an issue for use-cases like memory hotplug.
This happens on the HMP side because hmp_object_add() attempts to
create a temporary QemuOpts entry with ID 'ram1', which ends up
conflicting with the command-line-created entry, since it was never
cleaned up during the previous hmp_object_del() call.
We address this by adding a check in user_creatable_del(), which
is called by both qmp_object_del() and hmp_object_del() to handle
the actual object cleanup, to determine whether an option group entry
matching the object's ID is present and removing it if it is.
Note that qmp_object_add() never attempts to create a temporary
QemuOpts entry, so it does not encounter the duplicate ID error,
which is why this isn't generally visible in libvirt.
Cc: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Eric Blake <eblake@redhat.com>
Cc: Daniel Berrange <berrange@redhat.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1496531612-22166-3-git-send-email-mdroth@linux.vnet.ibm.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2017-06-04 01:13:32 +02:00
|
|
|
#include "qemu/config-file.h"
|
2014-01-16 17:34:38 +01:00
|
|
|
|
2018-12-04 15:20:07 +01:00
|
|
|
void user_creatable_complete(UserCreatable *uc, Error **errp)
|
2014-01-16 17:34:38 +01:00
|
|
|
{
|
2018-12-04 15:20:07 +01:00
|
|
|
UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
|
2014-01-16 17:34:38 +01:00
|
|
|
|
|
|
|
if (ucc->complete) {
|
|
|
|
ucc->complete(uc, errp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-30 00:03:37 +02:00
|
|
|
bool user_creatable_can_be_deleted(UserCreatable *uc)
|
2015-03-30 10:36:28 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
|
|
|
|
|
|
|
|
if (ucc->can_be_deleted) {
|
2017-08-30 00:03:37 +02:00
|
|
|
return ucc->can_be_deleted(uc);
|
2015-03-30 10:36:28 +02:00
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-10 19:40:59 +01:00
|
|
|
Object *user_creatable_add_type(const char *type, const char *id,
|
|
|
|
const QDict *qdict,
|
|
|
|
Visitor *v, Error **errp)
|
|
|
|
{
|
|
|
|
Object *obj;
|
|
|
|
ObjectClass *klass;
|
|
|
|
const QDictEntry *e;
|
|
|
|
Error *local_err = NULL;
|
|
|
|
|
|
|
|
klass = object_class_by_name(type);
|
|
|
|
if (!klass) {
|
|
|
|
error_setg(errp, "invalid object type: %s", type);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) {
|
|
|
|
error_setg(errp, "object type '%s' isn't supported by object-add",
|
|
|
|
type);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (object_class_is_abstract(klass)) {
|
|
|
|
error_setg(errp, "object type '%s' is abstract", type);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
qom: Wrap prop visit in visit_start_struct
The qmp-input visitor was allowing callers to play rather fast
and loose: when visiting a QDict, you could grab members of the
root dictionary without first pushing into the dict; the final
such culprit was the QOM code for converting to and from object
properties. But we are about to tighten the input visitor, at
which point user_creatable_add_type() as called with a QMP input
visitor via qmp_object_add() MUST follow the same paradigms as
everyone else, of pushing into the struct before grabbing its
keys.
The use of 'err ? NULL : &err' is temporary; a later patch will
clean that up when it splits visit_end_struct().
Furthermore, note that both callers always pass qdict, so we can
convert the conditional into an assert and reduce indentation.
The change has no impact to the testsuite now, but is required to
avoid a failure in tests/test-netfilter once qmp-input is made
stricter to detect inconsistent 'name' arguments on the root visit.
Since user_creatable_add_type() is also called with OptsVisitor
through user_creatable_add_opts(), we must also check that there
is no negative impact there; both pre- and post-patch, we see:
$ ./x86_64-softmmu/qemu-system-x86_64 -nographic -nodefaults -qmp stdio -object secret,id=sec0,data=letmein,format=raw,foo=bar
qemu-system-x86_64: -object secret,id=sec0,data=letmein,format=raw,foo=bar: Property '.foo' not found
That is, the only new checking that the new visit_end_struct() can
perform is for excess input, but we already catch excess input
earlier in object_property_set().
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1461879932-9020-10-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-04-28 23:45:17 +02:00
|
|
|
assert(qdict);
|
2016-02-10 19:40:59 +01:00
|
|
|
obj = object_new(type);
|
qom: Wrap prop visit in visit_start_struct
The qmp-input visitor was allowing callers to play rather fast
and loose: when visiting a QDict, you could grab members of the
root dictionary without first pushing into the dict; the final
such culprit was the QOM code for converting to and from object
properties. But we are about to tighten the input visitor, at
which point user_creatable_add_type() as called with a QMP input
visitor via qmp_object_add() MUST follow the same paradigms as
everyone else, of pushing into the struct before grabbing its
keys.
The use of 'err ? NULL : &err' is temporary; a later patch will
clean that up when it splits visit_end_struct().
Furthermore, note that both callers always pass qdict, so we can
convert the conditional into an assert and reduce indentation.
The change has no impact to the testsuite now, but is required to
avoid a failure in tests/test-netfilter once qmp-input is made
stricter to detect inconsistent 'name' arguments on the root visit.
Since user_creatable_add_type() is also called with OptsVisitor
through user_creatable_add_opts(), we must also check that there
is no negative impact there; both pre- and post-patch, we see:
$ ./x86_64-softmmu/qemu-system-x86_64 -nographic -nodefaults -qmp stdio -object secret,id=sec0,data=letmein,format=raw,foo=bar
qemu-system-x86_64: -object secret,id=sec0,data=letmein,format=raw,foo=bar: Property '.foo' not found
That is, the only new checking that the new visit_end_struct() can
perform is for excess input, but we already catch excess input
earlier in object_property_set().
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1461879932-9020-10-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-04-28 23:45:17 +02:00
|
|
|
visit_start_struct(v, NULL, NULL, 0, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
|
|
|
|
object_property_set(obj, v, e->key, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
break;
|
2016-02-10 19:40:59 +01:00
|
|
|
}
|
|
|
|
}
|
qapi: Split visit_end_struct() into pieces
As mentioned in previous patches, we want to call visit_end_struct()
functions unconditionally, so that visitors can release resources
tied up since the matching visit_start_struct() without also having
to worry about error priority if more than one error occurs.
Even though error_propagate() can be safely used to ignore a second
error during cleanup caused by a first error, it is simpler if the
cleanup cannot set an error. So, split out the error checking
portion (basically, input visitors checking for unvisited keys) into
a new function visit_check_struct(), which can be safely skipped if
any earlier errors are encountered, and leave the cleanup portion
(which never fails, but must be called unconditionally if
visit_start_struct() succeeded) in visit_end_struct().
Generated code in qapi-visit.c has diffs resembling:
|@@ -59,10 +59,12 @@ void visit_type_ACPIOSTInfo(Visitor *v,
| goto out_obj;
| }
| visit_type_ACPIOSTInfo_members(v, obj, &err);
|- error_propagate(errp, err);
|- err = NULL;
|+ if (err) {
|+ goto out_obj;
|+ }
|+ visit_check_struct(v, &err);
| out_obj:
|- visit_end_struct(v, &err);
|+ visit_end_struct(v);
| out:
and in qapi-event.c:
@@ -47,7 +47,10 @@ void qapi_event_send_acpi_device_ost(ACP
| goto out;
| }
| visit_type_q_obj_ACPI_DEVICE_OST_arg_members(v, ¶m, &err);
|- visit_end_struct(v, err ? NULL : &err);
|+ if (!err) {
|+ visit_check_struct(v, &err);
|+ }
|+ visit_end_struct(v);
| if (err) {
| goto out;
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1461879932-9020-20-git-send-email-eblake@redhat.com>
[Conflict with a doc fixup resolved]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-04-28 23:45:27 +02:00
|
|
|
if (!local_err) {
|
|
|
|
visit_check_struct(v, &local_err);
|
|
|
|
}
|
qapi: Add parameter to visit_end_*
Rather than making the dealloc visitor track of stack of pointers
remembered during visit_start_* in order to free them during
visit_end_*, it's a lot easier to just make all callers pass the
same pointer to visit_end_*. The generated code has access to the
same pointer, while all other users are doing virtual walks and
can pass NULL. The dealloc visitor is then greatly simplified.
All three visit_end_*() functions intentionally take a void**,
even though the visit_start_*() functions differ between void**,
GenericList**, and GenericAlternate**. This is done for several
reasons: when doing a virtual walk, passing NULL doesn't care
what the type is, but when doing a generated walk, we already
have to cast the caller's specific FOO* to call visit_start,
while using void** lets us use visit_end without a cast. Also,
an upcoming patch will add a clone visitor that wants to use
the same implementation for all three visit_end callbacks,
which is made easier if all three share the same signature.
For visitors with already track per-object state (the QMP visitors
via a stack, and the string visitors which do not allow nesting),
add an assertion that the caller is indeed passing the same
pointer to paired calls.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-4-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 18:48:34 +02:00
|
|
|
visit_end_struct(v, NULL);
|
qom: Wrap prop visit in visit_start_struct
The qmp-input visitor was allowing callers to play rather fast
and loose: when visiting a QDict, you could grab members of the
root dictionary without first pushing into the dict; the final
such culprit was the QOM code for converting to and from object
properties. But we are about to tighten the input visitor, at
which point user_creatable_add_type() as called with a QMP input
visitor via qmp_object_add() MUST follow the same paradigms as
everyone else, of pushing into the struct before grabbing its
keys.
The use of 'err ? NULL : &err' is temporary; a later patch will
clean that up when it splits visit_end_struct().
Furthermore, note that both callers always pass qdict, so we can
convert the conditional into an assert and reduce indentation.
The change has no impact to the testsuite now, but is required to
avoid a failure in tests/test-netfilter once qmp-input is made
stricter to detect inconsistent 'name' arguments on the root visit.
Since user_creatable_add_type() is also called with OptsVisitor
through user_creatable_add_opts(), we must also check that there
is no negative impact there; both pre- and post-patch, we see:
$ ./x86_64-softmmu/qemu-system-x86_64 -nographic -nodefaults -qmp stdio -object secret,id=sec0,data=letmein,format=raw,foo=bar
qemu-system-x86_64: -object secret,id=sec0,data=letmein,format=raw,foo=bar: Property '.foo' not found
That is, the only new checking that the new visit_end_struct() can
perform is for excess input, but we already catch excess input
earlier in object_property_set().
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1461879932-9020-10-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-04-28 23:45:17 +02:00
|
|
|
if (local_err) {
|
|
|
|
goto out;
|
|
|
|
}
|
2016-02-10 19:40:59 +01:00
|
|
|
|
2018-06-15 17:39:35 +02:00
|
|
|
if (id != NULL) {
|
|
|
|
object_property_add_child(object_get_objects_root(),
|
|
|
|
id, obj, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
goto out;
|
|
|
|
}
|
2016-02-10 19:40:59 +01:00
|
|
|
}
|
|
|
|
|
2018-12-04 15:20:07 +01:00
|
|
|
user_creatable_complete(USER_CREATABLE(obj), &local_err);
|
2016-02-10 19:40:59 +01:00
|
|
|
if (local_err) {
|
2018-06-15 17:39:35 +02:00
|
|
|
if (id != NULL) {
|
|
|
|
object_property_del(object_get_objects_root(),
|
|
|
|
id, &error_abort);
|
|
|
|
}
|
2016-02-10 19:40:59 +01:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
object_unref(obj);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2020-04-16 17:26:06 +02:00
|
|
|
void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp)
|
2020-04-16 17:04:20 +02:00
|
|
|
{
|
|
|
|
Visitor *v;
|
|
|
|
Object *obj;
|
|
|
|
g_autofree char *type = NULL;
|
|
|
|
g_autofree char *id = NULL;
|
|
|
|
|
|
|
|
type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
|
|
|
|
if (!type) {
|
|
|
|
error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
qdict_del(qdict, "qom-type");
|
|
|
|
|
|
|
|
id = g_strdup(qdict_get_try_str(qdict, "id"));
|
|
|
|
if (!id) {
|
|
|
|
error_setg(errp, QERR_MISSING_PARAMETER, "id");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
qdict_del(qdict, "id");
|
|
|
|
|
2020-04-16 17:26:06 +02:00
|
|
|
if (keyval) {
|
|
|
|
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
|
|
|
|
} else {
|
|
|
|
v = qobject_input_visitor_new(QOBJECT(qdict));
|
|
|
|
}
|
2020-04-16 17:04:20 +02:00
|
|
|
obj = user_creatable_add_type(type, id, qdict, v, errp);
|
|
|
|
visit_free(v);
|
|
|
|
object_unref(obj);
|
|
|
|
}
|
2016-02-10 19:40:59 +01:00
|
|
|
|
|
|
|
Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
|
|
|
|
{
|
2016-06-09 18:48:36 +02:00
|
|
|
Visitor *v;
|
2016-02-10 19:40:59 +01:00
|
|
|
QDict *pdict;
|
2017-01-10 13:53:14 +01:00
|
|
|
Object *obj;
|
|
|
|
const char *id = qemu_opts_id(opts);
|
qom: Avoid unvisited 'id'/'qom-type' in user_creatable_add_opts
A regression in commit 15c2f669e caused us to silently ignore
excess input to the QemuOpts visitor. Later, commit ea4641
accidentally abused that situation, by removing "qom-type" and
"id" from the corresponding QDict but leaving them defined in
the QemuOpts, when using the pair of containers to create a
user-defined object. Note that since we are already traversing
two separate items (a QDict and a QemuOpts), we are already
able to flag bogus arguments, as in:
$ ./x86_64-softmmu/qemu-system-x86_64 -nodefaults -nographic -qmp stdio -object memory-backend-ram,id=mem1,size=4k,bogus=huh
qemu-system-x86_64: -object memory-backend-ram,id=mem1,size=4k,bogus=huh: Property '.bogus' not found
So the only real concern is that when we re-enable strict checking
in the QemuOpts visitor, we do not want to start flagging the two
leftover keys as unvisited. Rearrange the code to clean out the
QemuOpts listing in advance, rather than removing items from the
QDict. Since "qom-type" is usually an automatic implicit default,
we don't have to restore it (this does mean that once instantiated,
QemuOpts is not necessarily an accurate representation of the
original command line - but this is not the first place to do that);
however "id" has to be put back (requiring us to cast away a const).
[As a side note, hmp_object_add() turns a QDict into a QemuOpts,
then calls user_creatable_add_opts() which converts QemuOpts into
a new QDict. There are probably a lot of wasteful conversions like
this, but cleaning them up is a much bigger task than the immediate
regression fix.]
CC: qemu-stable@nongnu.org
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20170322144525.18964-3-eblake@redhat.com>
Tested-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2017-03-22 15:45:24 +01:00
|
|
|
char *type = qemu_opt_get_del(opts, "qom-type");
|
2017-01-10 13:53:14 +01:00
|
|
|
|
|
|
|
if (!type) {
|
|
|
|
error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (!id) {
|
|
|
|
error_setg(errp, QERR_MISSING_PARAMETER, "id");
|
2017-03-23 17:03:15 +01:00
|
|
|
qemu_opt_set(opts, "qom-type", type, &error_abort);
|
qom: Avoid unvisited 'id'/'qom-type' in user_creatable_add_opts
A regression in commit 15c2f669e caused us to silently ignore
excess input to the QemuOpts visitor. Later, commit ea4641
accidentally abused that situation, by removing "qom-type" and
"id" from the corresponding QDict but leaving them defined in
the QemuOpts, when using the pair of containers to create a
user-defined object. Note that since we are already traversing
two separate items (a QDict and a QemuOpts), we are already
able to flag bogus arguments, as in:
$ ./x86_64-softmmu/qemu-system-x86_64 -nodefaults -nographic -qmp stdio -object memory-backend-ram,id=mem1,size=4k,bogus=huh
qemu-system-x86_64: -object memory-backend-ram,id=mem1,size=4k,bogus=huh: Property '.bogus' not found
So the only real concern is that when we re-enable strict checking
in the QemuOpts visitor, we do not want to start flagging the two
leftover keys as unvisited. Rearrange the code to clean out the
QemuOpts listing in advance, rather than removing items from the
QDict. Since "qom-type" is usually an automatic implicit default,
we don't have to restore it (this does mean that once instantiated,
QemuOpts is not necessarily an accurate representation of the
original command line - but this is not the first place to do that);
however "id" has to be put back (requiring us to cast away a const).
[As a side note, hmp_object_add() turns a QDict into a QemuOpts,
then calls user_creatable_add_opts() which converts QemuOpts into
a new QDict. There are probably a lot of wasteful conversions like
this, but cleaning them up is a much bigger task than the immediate
regression fix.]
CC: qemu-stable@nongnu.org
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20170322144525.18964-3-eblake@redhat.com>
Tested-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2017-03-22 15:45:24 +01:00
|
|
|
g_free(type);
|
2017-01-10 13:53:14 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
2016-02-10 19:40:59 +01:00
|
|
|
|
qom: Avoid unvisited 'id'/'qom-type' in user_creatable_add_opts
A regression in commit 15c2f669e caused us to silently ignore
excess input to the QemuOpts visitor. Later, commit ea4641
accidentally abused that situation, by removing "qom-type" and
"id" from the corresponding QDict but leaving them defined in
the QemuOpts, when using the pair of containers to create a
user-defined object. Note that since we are already traversing
two separate items (a QDict and a QemuOpts), we are already
able to flag bogus arguments, as in:
$ ./x86_64-softmmu/qemu-system-x86_64 -nodefaults -nographic -qmp stdio -object memory-backend-ram,id=mem1,size=4k,bogus=huh
qemu-system-x86_64: -object memory-backend-ram,id=mem1,size=4k,bogus=huh: Property '.bogus' not found
So the only real concern is that when we re-enable strict checking
in the QemuOpts visitor, we do not want to start flagging the two
leftover keys as unvisited. Rearrange the code to clean out the
QemuOpts listing in advance, rather than removing items from the
QDict. Since "qom-type" is usually an automatic implicit default,
we don't have to restore it (this does mean that once instantiated,
QemuOpts is not necessarily an accurate representation of the
original command line - but this is not the first place to do that);
however "id" has to be put back (requiring us to cast away a const).
[As a side note, hmp_object_add() turns a QDict into a QemuOpts,
then calls user_creatable_add_opts() which converts QemuOpts into
a new QDict. There are probably a lot of wasteful conversions like
this, but cleaning them up is a much bigger task than the immediate
regression fix.]
CC: qemu-stable@nongnu.org
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20170322144525.18964-3-eblake@redhat.com>
Tested-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2017-03-22 15:45:24 +01:00
|
|
|
qemu_opts_set_id(opts, NULL);
|
2016-02-10 19:40:59 +01:00
|
|
|
pdict = qemu_opts_to_qdict(opts, NULL);
|
|
|
|
|
2017-01-10 13:53:14 +01:00
|
|
|
v = opts_visitor_new(opts);
|
|
|
|
obj = user_creatable_add_type(type, id, pdict, v, errp);
|
2016-06-09 18:48:36 +02:00
|
|
|
visit_free(v);
|
2017-01-10 13:53:14 +01:00
|
|
|
|
qom: Avoid unvisited 'id'/'qom-type' in user_creatable_add_opts
A regression in commit 15c2f669e caused us to silently ignore
excess input to the QemuOpts visitor. Later, commit ea4641
accidentally abused that situation, by removing "qom-type" and
"id" from the corresponding QDict but leaving them defined in
the QemuOpts, when using the pair of containers to create a
user-defined object. Note that since we are already traversing
two separate items (a QDict and a QemuOpts), we are already
able to flag bogus arguments, as in:
$ ./x86_64-softmmu/qemu-system-x86_64 -nodefaults -nographic -qmp stdio -object memory-backend-ram,id=mem1,size=4k,bogus=huh
qemu-system-x86_64: -object memory-backend-ram,id=mem1,size=4k,bogus=huh: Property '.bogus' not found
So the only real concern is that when we re-enable strict checking
in the QemuOpts visitor, we do not want to start flagging the two
leftover keys as unvisited. Rearrange the code to clean out the
QemuOpts listing in advance, rather than removing items from the
QDict. Since "qom-type" is usually an automatic implicit default,
we don't have to restore it (this does mean that once instantiated,
QemuOpts is not necessarily an accurate representation of the
original command line - but this is not the first place to do that);
however "id" has to be put back (requiring us to cast away a const).
[As a side note, hmp_object_add() turns a QDict into a QemuOpts,
then calls user_creatable_add_opts() which converts QemuOpts into
a new QDict. There are probably a lot of wasteful conversions like
this, but cleaning them up is a much bigger task than the immediate
regression fix.]
CC: qemu-stable@nongnu.org
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20170322144525.18964-3-eblake@redhat.com>
Tested-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2017-03-22 15:45:24 +01:00
|
|
|
qemu_opts_set_id(opts, (char *) id);
|
2017-03-23 17:03:15 +01:00
|
|
|
qemu_opt_set(opts, "qom-type", type, &error_abort);
|
qom: Avoid unvisited 'id'/'qom-type' in user_creatable_add_opts
A regression in commit 15c2f669e caused us to silently ignore
excess input to the QemuOpts visitor. Later, commit ea4641
accidentally abused that situation, by removing "qom-type" and
"id" from the corresponding QDict but leaving them defined in
the QemuOpts, when using the pair of containers to create a
user-defined object. Note that since we are already traversing
two separate items (a QDict and a QemuOpts), we are already
able to flag bogus arguments, as in:
$ ./x86_64-softmmu/qemu-system-x86_64 -nodefaults -nographic -qmp stdio -object memory-backend-ram,id=mem1,size=4k,bogus=huh
qemu-system-x86_64: -object memory-backend-ram,id=mem1,size=4k,bogus=huh: Property '.bogus' not found
So the only real concern is that when we re-enable strict checking
in the QemuOpts visitor, we do not want to start flagging the two
leftover keys as unvisited. Rearrange the code to clean out the
QemuOpts listing in advance, rather than removing items from the
QDict. Since "qom-type" is usually an automatic implicit default,
we don't have to restore it (this does mean that once instantiated,
QemuOpts is not necessarily an accurate representation of the
original command line - but this is not the first place to do that);
however "id" has to be put back (requiring us to cast away a const).
[As a side note, hmp_object_add() turns a QDict into a QemuOpts,
then calls user_creatable_add_opts() which converts QemuOpts into
a new QDict. There are probably a lot of wasteful conversions like
this, but cleaning them up is a much bigger task than the immediate
regression fix.]
CC: qemu-stable@nongnu.org
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20170322144525.18964-3-eblake@redhat.com>
Tested-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2017-03-22 15:45:24 +01:00
|
|
|
g_free(type);
|
2018-04-19 17:01:43 +02:00
|
|
|
qobject_unref(pdict);
|
2016-02-10 19:40:59 +01:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int user_creatable_add_opts_foreach(void *opaque, QemuOpts *opts, Error **errp)
|
|
|
|
{
|
2018-09-06 15:05:34 +02:00
|
|
|
bool (*type_opt_predicate)(const char *, QemuOpts *) = opaque;
|
2016-02-10 19:40:59 +01:00
|
|
|
Object *obj = NULL;
|
|
|
|
const char *type;
|
|
|
|
|
|
|
|
type = qemu_opt_get(opts, "qom-type");
|
2018-09-06 15:05:34 +02:00
|
|
|
if (type && type_opt_predicate &&
|
|
|
|
!type_opt_predicate(type, opts)) {
|
2016-02-10 19:40:59 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-17 10:26:43 +02:00
|
|
|
obj = user_creatable_add_opts(opts, errp);
|
2016-02-10 19:40:59 +01:00
|
|
|
if (!obj) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
object_unref(obj);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-10 16:30:37 +01:00
|
|
|
char *object_property_help(const char *name, const char *type,
|
|
|
|
QObject *defval, const char *description)
|
|
|
|
{
|
|
|
|
GString *str = g_string_new(NULL);
|
|
|
|
|
|
|
|
g_string_append_printf(str, " %s=<%s>", name, type);
|
|
|
|
if (description || defval) {
|
|
|
|
if (str->len < 24) {
|
|
|
|
g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
|
|
|
|
}
|
|
|
|
g_string_append(str, " - ");
|
|
|
|
}
|
|
|
|
if (description) {
|
|
|
|
g_string_append(str, description);
|
|
|
|
}
|
|
|
|
if (defval) {
|
|
|
|
g_autofree char *def_json = qstring_free(qobject_to_json(defval), TRUE);
|
|
|
|
g_string_append_printf(str, " (default: %s)", def_json);
|
|
|
|
}
|
|
|
|
|
|
|
|
return g_string_free(str, false);
|
|
|
|
}
|
|
|
|
|
2019-10-11 19:20:12 +02:00
|
|
|
bool user_creatable_print_help(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);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
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))) {
|
|
|
|
if (!prop->set) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-01-10 16:30:37 +01:00
|
|
|
g_ptr_array_add(array,
|
|
|
|
object_property_help(prop->name, prop->type,
|
|
|
|
prop->defval, prop->description));
|
2019-10-11 19:20:12 +02:00
|
|
|
}
|
|
|
|
g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
|
|
|
|
if (array->len > 0) {
|
|
|
|
printf("%s options:\n", type);
|
|
|
|
} else {
|
|
|
|
printf("There are no options for %s.\n", type);
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2016-02-10 19:40:59 +01:00
|
|
|
|
|
|
|
void user_creatable_del(const char *id, Error **errp)
|
|
|
|
{
|
|
|
|
Object *container;
|
|
|
|
Object *obj;
|
|
|
|
|
|
|
|
container = object_get_objects_root();
|
|
|
|
obj = object_resolve_path_component(container, id);
|
|
|
|
if (!obj) {
|
|
|
|
error_setg(errp, "object '%s' not found", id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-08-30 00:03:37 +02:00
|
|
|
if (!user_creatable_can_be_deleted(USER_CREATABLE(obj))) {
|
2016-02-10 19:40:59 +01:00
|
|
|
error_setg(errp, "object '%s' is in use, can not be deleted", id);
|
|
|
|
return;
|
|
|
|
}
|
monitor: fix object_del for command-line-created objects
Currently objects specified on the command-line are only partially
cleaned up when 'object_del' is issued in either HMP or QMP: the
object itself is fully finalized, but the QemuOpts are not removed.
This results in the following behavior:
x86_64-softmmu/qemu-system-x86_64 -monitor stdio \
-object memory-backend-ram,id=ram1,size=256M
QEMU 2.7.91 monitor - type 'help' for more information
(qemu) object_del ram1
(qemu) object_del ram1
object 'ram1' not found
(qemu) object_add memory-backend-ram,id=ram1,size=256M
Duplicate ID 'ram1' for object
Try "help object_add" for more information
which can be an issue for use-cases like memory hotplug.
This happens on the HMP side because hmp_object_add() attempts to
create a temporary QemuOpts entry with ID 'ram1', which ends up
conflicting with the command-line-created entry, since it was never
cleaned up during the previous hmp_object_del() call.
We address this by adding a check in user_creatable_del(), which
is called by both qmp_object_del() and hmp_object_del() to handle
the actual object cleanup, to determine whether an option group entry
matching the object's ID is present and removing it if it is.
Note that qmp_object_add() never attempts to create a temporary
QemuOpts entry, so it does not encounter the duplicate ID error,
which is why this isn't generally visible in libvirt.
Cc: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Eric Blake <eblake@redhat.com>
Cc: Daniel Berrange <berrange@redhat.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1496531612-22166-3-git-send-email-mdroth@linux.vnet.ibm.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2017-06-04 01:13:32 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* if object was defined on the command-line, remove its corresponding
|
|
|
|
* option group entry
|
|
|
|
*/
|
|
|
|
qemu_opts_del(qemu_opts_find(qemu_find_opts_err("object", &error_abort),
|
|
|
|
id));
|
|
|
|
|
2016-02-10 19:40:59 +01:00
|
|
|
object_unparent(obj);
|
|
|
|
}
|
|
|
|
|
2017-08-24 21:23:13 +02:00
|
|
|
void user_creatable_cleanup(void)
|
|
|
|
{
|
|
|
|
object_unparent(object_get_objects_root());
|
|
|
|
}
|
|
|
|
|
2014-01-16 17:34:38 +01:00
|
|
|
static void register_types(void)
|
|
|
|
{
|
|
|
|
static const TypeInfo uc_interface_info = {
|
|
|
|
.name = TYPE_USER_CREATABLE,
|
|
|
|
.parent = TYPE_INTERFACE,
|
|
|
|
.class_size = sizeof(UserCreatableClass),
|
|
|
|
};
|
|
|
|
|
|
|
|
type_register_static(&uc_interface_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
type_init(register_types)
|