1 #include "qemu/osdep.h" 2 #include "qapi/error.h" 3 #include "qapi/qmp/qdict.h" 4 #include "qom/object_interfaces.h" 5 #include "qemu/module.h" 6 #include "qemu/option.h" 7 #include "qapi-visit.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 if (object_property_find(obj, "id", NULL)) { 69 object_property_set_str(obj, id, "id", &local_err); 70 if (local_err) { 71 goto out; 72 } 73 } 74 visit_start_struct(v, NULL, NULL, 0, &local_err); 75 if (local_err) { 76 goto out; 77 } 78 for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) { 79 object_property_set(obj, v, e->key, &local_err); 80 if (local_err) { 81 break; 82 } 83 } 84 if (!local_err) { 85 visit_check_struct(v, &local_err); 86 } 87 visit_end_struct(v, NULL); 88 if (local_err) { 89 goto out; 90 } 91 92 object_property_add_child(object_get_objects_root(), 93 id, obj, &local_err); 94 if (local_err) { 95 goto out; 96 } 97 98 user_creatable_complete(obj, &local_err); 99 if (local_err) { 100 object_property_del(object_get_objects_root(), 101 id, &error_abort); 102 goto out; 103 } 104 out: 105 if (local_err) { 106 error_propagate(errp, local_err); 107 object_unref(obj); 108 return NULL; 109 } 110 return obj; 111 } 112 113 114 Object *user_creatable_add_opts(QemuOpts *opts, Error **errp) 115 { 116 Visitor *v; 117 QDict *pdict; 118 Object *obj; 119 const char *id = qemu_opts_id(opts); 120 char *type = qemu_opt_get_del(opts, "qom-type"); 121 122 if (!type) { 123 error_setg(errp, QERR_MISSING_PARAMETER, "qom-type"); 124 return NULL; 125 } 126 if (!id) { 127 error_setg(errp, QERR_MISSING_PARAMETER, "id"); 128 qemu_opt_set(opts, "qom-type", type, &error_abort); 129 g_free(type); 130 return NULL; 131 } 132 133 qemu_opts_set_id(opts, NULL); 134 pdict = qemu_opts_to_qdict(opts, NULL); 135 136 v = opts_visitor_new(opts); 137 obj = user_creatable_add_type(type, id, pdict, v, errp); 138 visit_free(v); 139 140 qemu_opts_set_id(opts, (char *) id); 141 qemu_opt_set(opts, "qom-type", type, &error_abort); 142 g_free(type); 143 QDECREF(pdict); 144 return obj; 145 } 146 147 148 int user_creatable_add_opts_foreach(void *opaque, QemuOpts *opts, Error **errp) 149 { 150 bool (*type_predicate)(const char *) = opaque; 151 Object *obj = NULL; 152 Error *err = NULL; 153 const char *type; 154 155 type = qemu_opt_get(opts, "qom-type"); 156 if (type && type_predicate && 157 !type_predicate(type)) { 158 return 0; 159 } 160 161 obj = user_creatable_add_opts(opts, &err); 162 if (!obj) { 163 error_report_err(err); 164 return -1; 165 } 166 object_unref(obj); 167 return 0; 168 } 169 170 171 void user_creatable_del(const char *id, Error **errp) 172 { 173 Object *container; 174 Object *obj; 175 176 container = object_get_objects_root(); 177 obj = object_resolve_path_component(container, id); 178 if (!obj) { 179 error_setg(errp, "object '%s' not found", id); 180 return; 181 } 182 183 if (!user_creatable_can_be_deleted(USER_CREATABLE(obj))) { 184 error_setg(errp, "object '%s' is in use, can not be deleted", id); 185 return; 186 } 187 188 /* 189 * if object was defined on the command-line, remove its corresponding 190 * option group entry 191 */ 192 qemu_opts_del(qemu_opts_find(qemu_find_opts_err("object", &error_abort), 193 id)); 194 195 object_unparent(obj); 196 } 197 198 void user_creatable_cleanup(void) 199 { 200 object_unparent(object_get_objects_root()); 201 } 202 203 static void register_types(void) 204 { 205 static const TypeInfo uc_interface_info = { 206 .name = TYPE_USER_CREATABLE, 207 .parent = TYPE_INTERFACE, 208 .class_size = sizeof(UserCreatableClass), 209 }; 210 211 type_register_static(&uc_interface_info); 212 } 213 214 type_init(register_types) 215