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