qom: use object_resolve_path_type for links

This allows to restrict partial matches to objects of the expected
type.  It will let people use bare names to reference drives
even though their name might be the same as a device's (e.g.
-drive id=hd0,if=none,... -device ...,drive=hd0,id=hd0).

As a useful byproduct, this fixes a problem with links of interface
type.  When a link property's type is an interface, the code expects
the implementation object (not the parent object) to be stored in the
variable.  The parent object does not contain the right vtable.

Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
master
Paolo Bonzini 2012-02-02 12:37:53 +01:00
parent 02fe2db631
commit 11e35bfdc7
3 changed files with 24 additions and 14 deletions

View File

@ -47,6 +47,10 @@ static const QErrorStringTable qerror_table[] = {
.error_fmt = QERR_ADD_CLIENT_FAILED,
.desc = "Could not add client",
},
{
.error_fmt = QERR_AMBIGUOUS_PATH,
.desc = "Path '%(path)' does not uniquely identify a %(object)"
},
{
.error_fmt = QERR_BAD_BUS_FOR_DEVICE,
.desc = "Device '%(device)' can't go on a %(bad_bus_type) bus",

View File

@ -54,6 +54,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_ADD_CLIENT_FAILED \
"{ 'class': 'AddClientFailed', 'data': {} }"
#define QERR_AMBIGUOUS_PATH \
"{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }"
#define QERR_BAD_BUS_FOR_DEVICE \
"{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"

View File

@ -840,6 +840,7 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
bool ambiguous = false;
const char *type;
char *path;
gchar *target_type;
type = object_property_get_type(obj, name, NULL);
@ -847,28 +848,30 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
if (*child) {
object_unref(*child);
*child = NULL;
}
if (strcmp(path, "") != 0) {
Object *target;
target = object_resolve_path(path, &ambiguous);
if (target) {
/* Go from link<FOO> to FOO. */
gchar *target_type = g_strndup(&type[5], strlen(type) - 6);
if (object_dynamic_cast(target, target_type)) {
object_ref(target);
*child = target;
} else {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
}
/* Go from link<FOO> to FOO. */
target_type = g_strndup(&type[5], strlen(type) - 6);
target = object_resolve_path_type(path, target_type, &ambiguous);
g_free(target_type);
if (ambiguous) {
error_set(errp, QERR_AMBIGUOUS_PATH, path);
} else if (target) {
object_ref(target);
*child = target;
} else {
error_set(errp, QERR_DEVICE_NOT_FOUND, path);
target = object_resolve_path(path, &ambiguous);
if (target || ambiguous) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type);
} else {
error_set(errp, QERR_DEVICE_NOT_FOUND, path);
}
}
} else {
*child = NULL;
g_free(target_type);
}
g_free(path);