xref: /qemu/qom/object_interfaces.c (revision fc7d2b45)
1 #include "qemu/osdep.h"
2 #include "qapi/error.h"
3 #include "qapi/qmp/qdict.h"
4 #include "qapi/qmp/qerror.h"
5 #include "qom/object_interfaces.h"
6 #include "qemu/module.h"
7 #include "qemu/option.h"
8 #include "qapi/opts-visitor.h"
9 #include "qemu/config-file.h"
10 
11 void user_creatable_complete(UserCreatable *uc, Error **errp)
12 {
13     UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
14 
15     if (ucc->complete) {
16         ucc->complete(uc, errp);
17     }
18 }
19 
20 bool user_creatable_can_be_deleted(UserCreatable *uc)
21 {
22 
23     UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
24 
25     if (ucc->can_be_deleted) {
26         return ucc->can_be_deleted(uc);
27     } else {
28         return true;
29     }
30 }
31 
32 Object *user_creatable_add_type(const char *type, const char *id,
33                                 const QDict *qdict,
34                                 Visitor *v, Error **errp)
35 {
36     Object *obj;
37     ObjectClass *klass;
38     const QDictEntry *e;
39     Error *local_err = NULL;
40 
41     klass = object_class_by_name(type);
42     if (!klass) {
43         error_setg(errp, "invalid object type: %s", type);
44         return NULL;
45     }
46 
47     if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) {
48         error_setg(errp, "object type '%s' isn't supported by object-add",
49                    type);
50         return NULL;
51     }
52 
53     if (object_class_is_abstract(klass)) {
54         error_setg(errp, "object type '%s' is abstract", type);
55         return NULL;
56     }
57 
58     assert(qdict);
59     obj = object_new(type);
60     visit_start_struct(v, NULL, NULL, 0, &local_err);
61     if (local_err) {
62         goto out;
63     }
64     for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
65         object_property_set(obj, v, e->key, &local_err);
66         if (local_err) {
67             break;
68         }
69     }
70     if (!local_err) {
71         visit_check_struct(v, &local_err);
72     }
73     visit_end_struct(v, NULL);
74     if (local_err) {
75         goto out;
76     }
77 
78     if (id != NULL) {
79         object_property_add_child(object_get_objects_root(),
80                                   id, obj, &local_err);
81         if (local_err) {
82             goto out;
83         }
84     }
85 
86     user_creatable_complete(USER_CREATABLE(obj), &local_err);
87     if (local_err) {
88         if (id != NULL) {
89             object_property_del(object_get_objects_root(),
90                                 id, &error_abort);
91         }
92         goto out;
93     }
94 out:
95     if (local_err) {
96         error_propagate(errp, local_err);
97         object_unref(obj);
98         return NULL;
99     }
100     return obj;
101 }
102 
103 
104 Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
105 {
106     Visitor *v;
107     QDict *pdict;
108     Object *obj;
109     const char *id = qemu_opts_id(opts);
110     char *type = qemu_opt_get_del(opts, "qom-type");
111 
112     if (!type) {
113         error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
114         return NULL;
115     }
116     if (!id) {
117         error_setg(errp, QERR_MISSING_PARAMETER, "id");
118         qemu_opt_set(opts, "qom-type", type, &error_abort);
119         g_free(type);
120         return NULL;
121     }
122 
123     qemu_opts_set_id(opts, NULL);
124     pdict = qemu_opts_to_qdict(opts, NULL);
125 
126     v = opts_visitor_new(opts);
127     obj = user_creatable_add_type(type, id, pdict, v, errp);
128     visit_free(v);
129 
130     qemu_opts_set_id(opts, (char *) id);
131     qemu_opt_set(opts, "qom-type", type, &error_abort);
132     g_free(type);
133     qobject_unref(pdict);
134     return obj;
135 }
136 
137 
138 int user_creatable_add_opts_foreach(void *opaque, QemuOpts *opts, Error **errp)
139 {
140     bool (*type_opt_predicate)(const char *, QemuOpts *) = opaque;
141     Object *obj = NULL;
142     const char *type;
143 
144     type = qemu_opt_get(opts, "qom-type");
145     if (type && type_opt_predicate &&
146         !type_opt_predicate(type, opts)) {
147         return 0;
148     }
149 
150     obj = user_creatable_add_opts(opts, errp);
151     if (!obj) {
152         return -1;
153     }
154     object_unref(obj);
155     return 0;
156 }
157 
158 
159 void user_creatable_del(const char *id, Error **errp)
160 {
161     Object *container;
162     Object *obj;
163 
164     container = object_get_objects_root();
165     obj = object_resolve_path_component(container, id);
166     if (!obj) {
167         error_setg(errp, "object '%s' not found", id);
168         return;
169     }
170 
171     if (!user_creatable_can_be_deleted(USER_CREATABLE(obj))) {
172         error_setg(errp, "object '%s' is in use, can not be deleted", id);
173         return;
174     }
175 
176     /*
177      * if object was defined on the command-line, remove its corresponding
178      * option group entry
179      */
180     qemu_opts_del(qemu_opts_find(qemu_find_opts_err("object", &error_abort),
181                                  id));
182 
183     object_unparent(obj);
184 }
185 
186 void user_creatable_cleanup(void)
187 {
188     object_unparent(object_get_objects_root());
189 }
190 
191 static void register_types(void)
192 {
193     static const TypeInfo uc_interface_info = {
194         .name          = TYPE_USER_CREATABLE,
195         .parent        = TYPE_INTERFACE,
196         .class_size = sizeof(UserCreatableClass),
197     };
198 
199     type_register_static(&uc_interface_info);
200 }
201 
202 type_init(register_types)
203