xref: /openbmc/qemu/qom/object_interfaces.c (revision 073d9f2c)
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     object_property_add_child(object_get_objects_root(),
79                               id, obj, &local_err);
80     if (local_err) {
81         goto out;
82     }
83 
84     user_creatable_complete(USER_CREATABLE(obj), &local_err);
85     if (local_err) {
86         object_property_del(object_get_objects_root(),
87                             id, &error_abort);
88         goto out;
89     }
90 out:
91     if (local_err) {
92         error_propagate(errp, local_err);
93         object_unref(obj);
94         return NULL;
95     }
96     return obj;
97 }
98 
99 
100 Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
101 {
102     Visitor *v;
103     QDict *pdict;
104     Object *obj;
105     const char *id = qemu_opts_id(opts);
106     char *type = qemu_opt_get_del(opts, "qom-type");
107 
108     if (!type) {
109         error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
110         return NULL;
111     }
112     if (!id) {
113         error_setg(errp, QERR_MISSING_PARAMETER, "id");
114         qemu_opt_set(opts, "qom-type", type, &error_abort);
115         g_free(type);
116         return NULL;
117     }
118 
119     qemu_opts_set_id(opts, NULL);
120     pdict = qemu_opts_to_qdict(opts, NULL);
121 
122     v = opts_visitor_new(opts);
123     obj = user_creatable_add_type(type, id, pdict, v, errp);
124     visit_free(v);
125 
126     qemu_opts_set_id(opts, (char *) id);
127     qemu_opt_set(opts, "qom-type", type, &error_abort);
128     g_free(type);
129     qobject_unref(pdict);
130     return obj;
131 }
132 
133 
134 int user_creatable_add_opts_foreach(void *opaque, QemuOpts *opts, Error **errp)
135 {
136     bool (*type_opt_predicate)(const char *, QemuOpts *) = opaque;
137     Object *obj = NULL;
138     const char *type;
139 
140     type = qemu_opt_get(opts, "qom-type");
141     if (type && type_opt_predicate &&
142         !type_opt_predicate(type, opts)) {
143         return 0;
144     }
145 
146     obj = user_creatable_add_opts(opts, errp);
147     if (!obj) {
148         return -1;
149     }
150     object_unref(obj);
151     return 0;
152 }
153 
154 
155 void user_creatable_del(const char *id, Error **errp)
156 {
157     Object *container;
158     Object *obj;
159 
160     container = object_get_objects_root();
161     obj = object_resolve_path_component(container, id);
162     if (!obj) {
163         error_setg(errp, "object '%s' not found", id);
164         return;
165     }
166 
167     if (!user_creatable_can_be_deleted(USER_CREATABLE(obj))) {
168         error_setg(errp, "object '%s' is in use, can not be deleted", id);
169         return;
170     }
171 
172     /*
173      * if object was defined on the command-line, remove its corresponding
174      * option group entry
175      */
176     qemu_opts_del(qemu_opts_find(qemu_find_opts_err("object", &error_abort),
177                                  id));
178 
179     object_unparent(obj);
180 }
181 
182 void user_creatable_cleanup(void)
183 {
184     object_unparent(object_get_objects_root());
185 }
186 
187 static void register_types(void)
188 {
189     static const TypeInfo uc_interface_info = {
190         .name          = TYPE_USER_CREATABLE,
191         .parent        = TYPE_INTERFACE,
192         .class_size = sizeof(UserCreatableClass),
193     };
194 
195     type_register_static(&uc_interface_info);
196 }
197 
198 type_init(register_types)
199