]> Git Repo - qemu.git/blobdiff - qom/object.c
block: vmdk - make ret variable usage clear
[qemu.git] / qom / object.c
index 62e7e415d9bc87913a813fc18004753bfd7fd029..1812c73327b4e89be91e7cbff9ba23cce4c9d7d1 100644 (file)
@@ -13,6 +13,7 @@
 #include "qom/object.h"
 #include "qemu-common.h"
 #include "qapi/visitor.h"
+#include "qapi-visit.h"
 #include "qapi/string-input-visitor.h"
 #include "qapi/string-output-visitor.h"
 #include "qapi/qmp/qerror.h"
@@ -355,11 +356,6 @@ static inline bool object_property_is_child(ObjectProperty *prop)
     return strstart(prop->type, "child<", NULL);
 }
 
-static inline bool object_property_is_link(ObjectProperty *prop)
-{
-    return strstart(prop->type, "link<", NULL);
-}
-
 static void object_property_del_all(Object *obj)
 {
     while (!QTAILQ_EMPTY(&obj->properties)) {
@@ -373,6 +369,7 @@ static void object_property_del_all(Object *obj)
 
         g_free(prop->name);
         g_free(prop->type);
+        g_free(prop->description);
         g_free(prop);
     }
 }
@@ -391,18 +388,9 @@ static void object_property_del_child(Object *obj, Object *child, Error **errp)
 
 void object_unparent(Object *obj)
 {
-    if (!obj->parent) {
-        return;
-    }
-
-    object_ref(obj);
-    if (obj->class->unparent) {
-        (obj->class->unparent)(obj);
-    }
     if (obj->parent) {
         object_property_del_child(obj->parent, obj, NULL);
     }
-    object_unref(obj);
 }
 
 static void object_deinit(Object *obj, TypeImpl *type)
@@ -421,8 +409,8 @@ static void object_finalize(void *data)
     Object *obj = data;
     TypeImpl *ti = obj->class->type;
 
-    object_deinit(obj, ti);
     object_property_del_all(obj);
+    object_deinit(obj, ti);
 
     g_assert(obj->ref == 0);
     if (obj->free) {
@@ -681,10 +669,10 @@ void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
 int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque),
                          void *opaque)
 {
-    ObjectProperty *prop;
+    ObjectProperty *prop, *next;
     int ret = 0;
 
-    QTAILQ_FOREACH(prop, &obj->properties, node) {
+    QTAILQ_FOREACH_SAFE(prop, &obj->properties, node, next) {
         if (object_property_is_child(prop)) {
             ret = fn(prop->opaque, opaque);
             if (ret != 0) {
@@ -714,11 +702,17 @@ GSList *object_class_get_list(const char *implements_type,
 
 void object_ref(Object *obj)
 {
+    if (!obj) {
+        return;
+    }
      atomic_inc(&obj->ref);
 }
 
 void object_unref(Object *obj)
 {
+    if (!obj) {
+        return;
+    }
     g_assert(obj->ref > 0);
 
     /* parent always holds a reference to its children */
@@ -727,20 +721,42 @@ void object_unref(Object *obj)
     }
 }
 
-void object_property_add(Object *obj, const char *name, const char *type,
-                         ObjectPropertyAccessor *get,
-                         ObjectPropertyAccessor *set,
-                         ObjectPropertyRelease *release,
-                         void *opaque, Error **errp)
+ObjectProperty *
+object_property_add(Object *obj, const char *name, const char *type,
+                    ObjectPropertyAccessor *get,
+                    ObjectPropertyAccessor *set,
+                    ObjectPropertyRelease *release,
+                    void *opaque, Error **errp)
 {
     ObjectProperty *prop;
+    size_t name_len = strlen(name);
+
+    if (name_len >= 3 && !memcmp(name + name_len - 3, "[*]", 4)) {
+        int i;
+        ObjectProperty *ret;
+        char *name_no_array = g_strdup(name);
+
+        name_no_array[name_len - 3] = '\0';
+        for (i = 0; ; ++i) {
+            char *full_name = g_strdup_printf("%s[%d]", name_no_array, i);
+
+            ret = object_property_add(obj, full_name, type, get, set,
+                                      release, opaque, NULL);
+            g_free(full_name);
+            if (ret) {
+                break;
+            }
+        }
+        g_free(name_no_array);
+        return ret;
+    }
 
     QTAILQ_FOREACH(prop, &obj->properties, node) {
         if (strcmp(prop->name, name) == 0) {
             error_setg(errp, "attempt to add duplicate property '%s'"
                        " to object (type '%s')", name,
                        object_get_typename(obj));
-            return;
+            return NULL;
         }
     }
 
@@ -755,6 +771,7 @@ void object_property_add(Object *obj, const char *name, const char *type,
     prop->opaque = opaque;
 
     QTAILQ_INSERT_TAIL(&obj->properties, prop, node);
+    return prop;
 }
 
 ObjectProperty *object_property_find(Object *obj, const char *name,
@@ -768,7 +785,7 @@ ObjectProperty *object_property_find(Object *obj, const char *name,
         }
     }
 
-    error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
+    error_setg(errp, "Property '.%s' not found", name);
     return NULL;
 }
 
@@ -787,6 +804,7 @@ void object_property_del(Object *obj, const char *name, Error **errp)
 
     g_free(prop->name);
     g_free(prop->type);
+    g_free(prop->description);
     g_free(prop);
 }
 
@@ -854,9 +872,13 @@ char *object_property_get_str(Object *obj, const char *name,
 void object_property_set_link(Object *obj, Object *value,
                               const char *name, Error **errp)
 {
-    gchar *path = object_get_canonical_path(value);
-    object_property_set_str(obj, path, name, errp);
-    g_free(path);
+    if (value) {
+        gchar *path = object_get_canonical_path(value);
+        object_property_set_str(obj, path, name, errp);
+        g_free(path);
+    } else {
+        object_property_set_str(obj, "", name, errp);
+    }
 }
 
 Object *object_property_get_link(Object *obj, const char *name,
@@ -938,6 +960,48 @@ int64_t object_property_get_int(Object *obj, const char *name,
     return retval;
 }
 
+int object_property_get_enum(Object *obj, const char *name,
+                             const char *strings[], Error **errp)
+{
+    StringOutputVisitor *sov;
+    StringInputVisitor *siv;
+    char *str;
+    int ret;
+
+    sov = string_output_visitor_new(false);
+    object_property_get(obj, string_output_get_visitor(sov), name, errp);
+    str = string_output_get_string(sov);
+    siv = string_input_visitor_new(str);
+    string_output_visitor_cleanup(sov);
+    visit_type_enum(string_input_get_visitor(siv),
+                    &ret, strings, NULL, name, errp);
+
+    g_free(str);
+    string_input_visitor_cleanup(siv);
+
+    return ret;
+}
+
+void object_property_get_uint16List(Object *obj, const char *name,
+                                    uint16List **list, Error **errp)
+{
+    StringOutputVisitor *ov;
+    StringInputVisitor *iv;
+    char *str;
+
+    ov = string_output_visitor_new(false);
+    object_property_get(obj, string_output_get_visitor(ov),
+                        name, errp);
+    str = string_output_get_string(ov);
+    iv = string_input_visitor_new(str);
+    visit_type_uint16List(string_input_get_visitor(iv),
+                          list, NULL, errp);
+
+    g_free(str);
+    string_output_visitor_cleanup(ov);
+    string_input_visitor_cleanup(iv);
+}
+
 void object_property_parse(Object *obj, const char *string,
                            const char *name, Error **errp)
 {
@@ -948,15 +1012,23 @@ void object_property_parse(Object *obj, const char *string,
     string_input_visitor_cleanup(mi);
 }
 
-char *object_property_print(Object *obj, const char *name,
+char *object_property_print(Object *obj, const char *name, bool human,
                             Error **errp)
 {
     StringOutputVisitor *mo;
-    char *string;
+    char *string = NULL;
+    Error *local_err = NULL;
+
+    mo = string_output_visitor_new(human);
+    object_property_get(obj, string_output_get_visitor(mo), name, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        goto out;
+    }
 
-    mo = string_output_visitor_new();
-    object_property_get(obj, string_output_get_visitor(mo), name, errp);
     string = string_output_get_string(mo);
+
+out:
     string_output_visitor_cleanup(mo);
     return string;
 }
@@ -993,11 +1065,20 @@ static void object_get_child_property(Object *obj, Visitor *v, void *opaque,
     g_free(path);
 }
 
+static Object *object_resolve_child_property(Object *parent, void *opaque, const gchar *part)
+{
+    return opaque;
+}
+
 static void object_finalize_child_property(Object *obj, const char *name,
                                            void *opaque)
 {
     Object *child = opaque;
 
+    if (child->class->unparent) {
+        (child->class->unparent)(child);
+    }
+    child->parent = NULL;
     object_unref(child);
 }
 
@@ -1006,27 +1087,47 @@ void object_property_add_child(Object *obj, const char *name,
 {
     Error *local_err = NULL;
     gchar *type;
+    ObjectProperty *op;
+
+    if (child->parent != NULL) {
+        error_setg(errp, "child object is already parented");
+        return;
+    }
 
     type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
 
-    object_property_add(obj, name, type, object_get_child_property, NULL,
-                        object_finalize_child_property, child, &local_err);
+    op = object_property_add(obj, name, type, object_get_child_property, NULL,
+                             object_finalize_child_property, child, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         goto out;
     }
+
+    op->resolve = object_resolve_child_property;
     object_ref(child);
-    g_assert(child->parent == NULL);
     child->parent = obj;
 
 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,102 +1140,175 @@ 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, ERROR_CLASS_GENERIC_ERROR,
+                  "Path '%s' does not uniquely identify an object", 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;
+    }
 
-    if (old_target != NULL) {
-        object_unref(old_target);
+    prop->check(obj, name, new_target, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
     }
+
+    object_ref(new_target);
+    *child = new_target;
+    object_unref(old_target);
+}
+
+static Object *object_resolve_link_property(Object *parent, void *opaque, const gchar *part)
+{
+    LinkProperty *lprop = opaque;
+
+    return *lprop->child;
+}
+
+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;
+    ObjectProperty *op;
+
+    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);
+    op = object_property_add(obj, name, full_type,
+                             object_get_link_property,
+                             check ? object_set_link_property : NULL,
+                             object_release_link_property,
+                             prop,
+                             &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        g_free(prop);
+        goto out;
+    }
+
+    op->resolve = object_resolve_link_property;
 
+out:
     g_free(full_type);
 }
 
+gchar *object_get_canonical_path_component(Object *obj)
+{
+    ObjectProperty *prop = NULL;
+
+    g_assert(obj);
+    g_assert(obj->parent != NULL);
+
+    QTAILQ_FOREACH(prop, &obj->parent->properties, node) {
+        if (!object_property_is_child(prop)) {
+            continue;
+        }
+
+        if (prop->opaque == obj) {
+            return g_strdup(prop->name);
+        }
+    }
+
+    /* obj had a parent but was not a child, should never happen */
+    g_assert_not_reached();
+    return NULL;
+}
+
 gchar *object_get_canonical_path(Object *obj)
 {
     Object *root = object_get_root();
-    char *newpath = NULL, *path = NULL;
+    char *newpath, *path = NULL;
 
     while (obj != root) {
-        ObjectProperty *prop = NULL;
-
-        g_assert(obj->parent != NULL);
-
-        QTAILQ_FOREACH(prop, &obj->parent->properties, node) {
-            if (!object_property_is_child(prop)) {
-                continue;
-            }
+        char *component = object_get_canonical_path_component(obj);
 
-            if (prop->opaque == obj) {
-                if (path) {
-                    newpath = g_strdup_printf("%s/%s", prop->name, path);
-                    g_free(path);
-                    path = newpath;
-                } else {
-                    path = g_strdup(prop->name);
-                }
-                break;
-            }
+        if (path) {
+            newpath = g_strdup_printf("%s/%s", component, path);
+            g_free(component);
+            g_free(path);
+            path = newpath;
+        } else {
+            path = component;
         }
 
-        g_assert(prop != NULL);
-
         obj = obj->parent;
     }
 
-    newpath = g_strdup_printf("/%s", path);
+    newpath = g_strdup_printf("/%s", path ? path : "");
     g_free(path);
 
     return newpath;
@@ -1147,10 +1321,8 @@ Object *object_resolve_path_component(Object *parent, const gchar *part)
         return NULL;
     }
 
-    if (object_property_is_link(prop)) {
-        return *(Object **)prop->opaque;
-    } else if (object_property_is_child(prop)) {
-        return prop->opaque;
+    if (prop->resolve) {
+        return prop->resolve(parent, prop->opaque, part);
     } else {
         return NULL;
     }
@@ -1293,6 +1465,7 @@ void object_property_add_str(Object *obj, const char *name,
                            void (*set)(Object *, const char *, Error **),
                            Error **errp)
 {
+    Error *local_err = NULL;
     StringProperty *prop = g_malloc0(sizeof(*prop));
 
     prop->get = get;
@@ -1302,7 +1475,11 @@ void object_property_add_str(Object *obj, const char *name,
                         get ? property_get_str : NULL,
                         set ? property_set_str : NULL,
                         property_release_str,
-                        prop, errp);
+                        prop, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        g_free(prop);
+    }
 }
 
 typedef struct BoolProperty
@@ -1349,6 +1526,7 @@ void object_property_add_bool(Object *obj, const char *name,
                               void (*set)(Object *, bool, Error **),
                               Error **errp)
 {
+    Error *local_err = NULL;
     BoolProperty *prop = g_malloc0(sizeof(*prop));
 
     prop->get = get;
@@ -1358,7 +1536,11 @@ void object_property_add_bool(Object *obj, const char *name,
                         get ? property_get_bool : NULL,
                         set ? property_set_bool : NULL,
                         property_release_bool,
-                        prop, errp);
+                        prop, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        g_free(prop);
+    }
 }
 
 static char *qdev_get_type(Object *obj, Error **errp)
@@ -1426,6 +1608,102 @@ void object_property_add_uint64_ptr(Object *obj, const char *name,
                         NULL, NULL, (void *)v, errp);
 }
 
+typedef struct {
+    Object *target_obj;
+    const char *target_name;
+} AliasProperty;
+
+static void property_get_alias(Object *obj, struct Visitor *v, void *opaque,
+                               const char *name, Error **errp)
+{
+    AliasProperty *prop = opaque;
+
+    object_property_get(prop->target_obj, v, prop->target_name, errp);
+}
+
+static void property_set_alias(Object *obj, struct Visitor *v, void *opaque,
+                               const char *name, Error **errp)
+{
+    AliasProperty *prop = opaque;
+
+    object_property_set(prop->target_obj, v, prop->target_name, errp);
+}
+
+static Object *property_resolve_alias(Object *obj, void *opaque,
+                                      const gchar *part)
+{
+    AliasProperty *prop = opaque;
+
+    return object_resolve_path_component(prop->target_obj, prop->target_name);
+}
+
+static void property_release_alias(Object *obj, const char *name, void *opaque)
+{
+    AliasProperty *prop = opaque;
+
+    g_free(prop);
+}
+
+void object_property_add_alias(Object *obj, const char *name,
+                               Object *target_obj, const char *target_name,
+                               Error **errp)
+{
+    AliasProperty *prop;
+    ObjectProperty *op;
+    ObjectProperty *target_prop;
+    gchar *prop_type;
+    Error *local_err = NULL;
+
+    target_prop = object_property_find(target_obj, target_name, errp);
+    if (!target_prop) {
+        return;
+    }
+
+    if (object_property_is_child(target_prop)) {
+        prop_type = g_strdup_printf("link%s",
+                                    target_prop->type + strlen("child"));
+    } else {
+        prop_type = g_strdup(target_prop->type);
+    }
+
+    prop = g_malloc(sizeof(*prop));
+    prop->target_obj = target_obj;
+    prop->target_name = target_name;
+
+    op = object_property_add(obj, name, prop_type,
+                             property_get_alias,
+                             property_set_alias,
+                             property_release_alias,
+                             prop, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        g_free(prop);
+        goto out;
+    }
+    op->resolve = property_resolve_alias;
+
+    object_property_set_description(obj, name,
+                                    target_prop->description,
+                                    &error_abort);
+
+out:
+    g_free(prop_type);
+}
+
+void object_property_set_description(Object *obj, const char *name,
+                                     const char *description, Error **errp)
+{
+    ObjectProperty *op;
+
+    op = object_property_find(obj, name, errp);
+    if (!op) {
+        return;
+    }
+
+    g_free(op->description);
+    op->description = g_strdup(description);
+}
+
 static void object_instance_init(Object *obj)
 {
     object_property_add_str(obj, "type", qdev_get_type, NULL, NULL);
This page took 0.041661 seconds and 4 git commands to generate.