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