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