diff options
Diffstat (limited to 'qom/object.c')
-rw-r--r-- | qom/object.c | 131 |
1 files changed, 99 insertions, 32 deletions
diff --git a/qom/object.c b/qom/object.c index a2a1ffa1b3..f4de619b7b 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1023,10 +1023,23 @@ out: g_free(type); } +void object_property_allow_set_link(Object *obj, const char *name, + Object *val, Error **errp) +{ + /* Allow the link to be set, always */ +} + +typedef struct { + Object **child; + void (*check)(Object *, const char *, Object *, Error **); + ObjectPropertyLinkFlags flags; +} LinkProperty; + static void object_get_link_property(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { - Object **child = opaque; + LinkProperty *lprop = opaque; + Object **child = lprop->child; gchar *path; if (*child) { @@ -1039,65 +1052,119 @@ static void object_get_link_property(Object *obj, Visitor *v, void *opaque, } } -static void object_set_link_property(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) +/* + * object_resolve_link: + * + * Lookup an object and ensure its type matches the link property type. This + * is similar to object_resolve_path() except type verification against the + * link property is performed. + * + * Returns: The matched object or NULL on path lookup failures. + */ +static Object *object_resolve_link(Object *obj, const char *name, + const char *path, Error **errp) { - Object **child = opaque; - Object *old_target; - bool ambiguous = false; const char *type; - char *path; gchar *target_type; + bool ambiguous = false; + Object *target; + /* Go from link<FOO> to FOO. */ type = object_property_get_type(obj, name, NULL); + target_type = g_strndup(&type[5], strlen(type) - 6); + target = object_resolve_path_type(path, target_type, &ambiguous); + + if (ambiguous) { + error_set(errp, QERR_AMBIGUOUS_PATH, path); + } else if (!target) { + 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); + } + target = NULL; + } + g_free(target_type); - visit_type_str(v, &path, name, errp); - - old_target = *child; - *child = NULL; + return target; +} - if (strcmp(path, "") != 0) { - Object *target; +static void object_set_link_property(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + Error *local_err = NULL; + LinkProperty *prop = opaque; + Object **child = prop->child; + Object *old_target = *child; + Object *new_target = NULL; + char *path = NULL; - /* Go from link<FOO> to FOO. */ - target_type = g_strndup(&type[5], strlen(type) - 6); - target = object_resolve_path_type(path, target_type, &ambiguous); + visit_type_str(v, &path, name, &local_err); - if (ambiguous) { - error_set(errp, QERR_AMBIGUOUS_PATH, path); - } else if (target) { - object_ref(target); - *child = target; - } else { - 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); - } - } - g_free(target_type); + if (!local_err && strcmp(path, "") != 0) { + new_target = object_resolve_link(obj, name, path, &local_err); } g_free(path); + if (local_err) { + error_propagate(errp, local_err); + return; + } + prop->check(obj, name, new_target, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + if (new_target) { + object_ref(new_target); + } + *child = new_target; if (old_target != NULL) { object_unref(old_target); } } +static void object_release_link_property(Object *obj, const char *name, + void *opaque) +{ + LinkProperty *prop = opaque; + + if ((prop->flags & OBJ_PROP_LINK_UNREF_ON_RELEASE) && *prop->child) { + object_unref(*prop->child); + } + g_free(prop); +} + void object_property_add_link(Object *obj, const char *name, const char *type, Object **child, + void (*check)(Object *, const char *, + Object *, Error **), + ObjectPropertyLinkFlags flags, Error **errp) { + Error *local_err = NULL; + LinkProperty *prop = g_malloc(sizeof(*prop)); gchar *full_type; + prop->child = child; + prop->check = check; + prop->flags = flags; + full_type = g_strdup_printf("link<%s>", type); object_property_add(obj, name, full_type, object_get_link_property, - object_set_link_property, - NULL, child, errp); + check ? object_set_link_property : NULL, + object_release_link_property, + prop, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } g_free(full_type); } |