qemu/qom/object_interfaces.c
<<
>>
Prefs
   1#include "qemu/osdep.h"
   2
   3#include "qemu/cutils.h"
   4#include "qapi/error.h"
   5#include "qapi/qapi-visit-qom.h"
   6#include "qapi/qmp/qobject.h"
   7#include "qapi/qmp/qdict.h"
   8#include "qapi/qmp/qerror.h"
   9#include "qapi/qmp/qjson.h"
  10#include "qapi/qobject-input-visitor.h"
  11#include "qapi/qobject-output-visitor.h"
  12#include "qom/object_interfaces.h"
  13#include "qemu/help_option.h"
  14#include "qemu/id.h"
  15#include "qemu/module.h"
  16#include "qemu/option.h"
  17#include "qemu/qemu-print.h"
  18#include "qapi/opts-visitor.h"
  19#include "qemu/config-file.h"
  20#include "qemu/keyval.h"
  21
  22bool user_creatable_complete(UserCreatable *uc, Error **errp)
  23{
  24    UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
  25    Error *err = NULL;
  26
  27    if (ucc->complete) {
  28        ucc->complete(uc, &err);
  29        error_propagate(errp, err);
  30    }
  31    return !err;
  32}
  33
  34bool user_creatable_can_be_deleted(UserCreatable *uc)
  35{
  36
  37    UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
  38
  39    if (ucc->can_be_deleted) {
  40        return ucc->can_be_deleted(uc);
  41    } else {
  42        return true;
  43    }
  44}
  45
  46static void object_set_properties_from_qdict(Object *obj, const QDict *qdict,
  47                                             Visitor *v, Error **errp)
  48{
  49    const QDictEntry *e;
  50
  51    if (!visit_start_struct(v, NULL, NULL, 0, errp)) {
  52        return;
  53    }
  54    for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
  55        if (!object_property_set(obj, e->key, v, errp)) {
  56            goto out;
  57        }
  58    }
  59    visit_check_struct(v, errp);
  60out:
  61    visit_end_struct(v, NULL);
  62}
  63
  64void object_set_properties_from_keyval(Object *obj, const QDict *qdict,
  65                                       bool from_json, Error **errp)
  66{
  67    Visitor *v;
  68    if (from_json) {
  69        v = qobject_input_visitor_new(QOBJECT(qdict));
  70    } else {
  71        v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
  72    }
  73    object_set_properties_from_qdict(obj, qdict, v, errp);
  74    visit_free(v);
  75}
  76
  77Object *user_creatable_add_type(const char *type, const char *id,
  78                                const QDict *qdict,
  79                                Visitor *v, Error **errp)
  80{
  81    ERRP_GUARD();
  82    Object *obj;
  83    ObjectClass *klass;
  84    Error *local_err = NULL;
  85
  86    if (id != NULL && !id_wellformed(id)) {
  87        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "id", "an identifier");
  88        error_append_hint(errp, "Identifiers consist of letters, digits, "
  89                          "'-', '.', '_', starting with a letter.\n");
  90        return NULL;
  91    }
  92
  93    klass = object_class_by_name(type);
  94    if (!klass) {
  95        error_setg(errp, "invalid object type: %s", type);
  96        return NULL;
  97    }
  98
  99    if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) {
 100        error_setg(errp, "object type '%s' isn't supported by object-add",
 101                   type);
 102        return NULL;
 103    }
 104
 105    if (object_class_is_abstract(klass)) {
 106        error_setg(errp, "object type '%s' is abstract", type);
 107        return NULL;
 108    }
 109
 110    assert(qdict);
 111    obj = object_new(type);
 112    object_set_properties_from_qdict(obj, qdict, v, &local_err);
 113    if (local_err) {
 114        goto out;
 115    }
 116
 117    if (id != NULL) {
 118        object_property_try_add_child(object_get_objects_root(),
 119                                      id, obj, &local_err);
 120        if (local_err) {
 121            goto out;
 122        }
 123    }
 124
 125    if (!user_creatable_complete(USER_CREATABLE(obj), &local_err)) {
 126        if (id != NULL) {
 127            object_property_del(object_get_objects_root(), id);
 128        }
 129        goto out;
 130    }
 131out:
 132    if (local_err) {
 133        error_propagate(errp, local_err);
 134        object_unref(obj);
 135        return NULL;
 136    }
 137    return obj;
 138}
 139
 140void user_creatable_add_qapi(ObjectOptions *options, Error **errp)
 141{
 142    Visitor *v;
 143    QObject *qobj;
 144    QDict *props;
 145    Object *obj;
 146
 147    v = qobject_output_visitor_new(&qobj);
 148    visit_type_ObjectOptions(v, NULL, &options, &error_abort);
 149    visit_complete(v, &qobj);
 150    visit_free(v);
 151
 152    props = qobject_to(QDict, qobj);
 153    qdict_del(props, "qom-type");
 154    qdict_del(props, "id");
 155
 156    v = qobject_input_visitor_new(QOBJECT(props));
 157    obj = user_creatable_add_type(ObjectType_str(options->qom_type),
 158                                  options->id, props, v, errp);
 159    object_unref(obj);
 160    qobject_unref(qobj);
 161    visit_free(v);
 162}
 163
 164char *object_property_help(const char *name, const char *type,
 165                           QObject *defval, const char *description)
 166{
 167    GString *str = g_string_new(NULL);
 168
 169    g_string_append_printf(str, "  %s=<%s>", name, type);
 170    if (description || defval) {
 171        if (str->len < 24) {
 172            g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
 173        }
 174        g_string_append(str, " - ");
 175    }
 176    if (description) {
 177        g_string_append(str, description);
 178    }
 179    if (defval) {
 180        g_autofree char *def_json = g_string_free(qobject_to_json(defval),
 181                                                  false);
 182        g_string_append_printf(str, " (default: %s)", def_json);
 183    }
 184
 185    return g_string_free(str, false);
 186}
 187
 188static void user_creatable_print_types(void)
 189{
 190    GSList *l, *list;
 191
 192    qemu_printf("List of user creatable objects:\n");
 193    list = object_class_get_list_sorted(TYPE_USER_CREATABLE, false);
 194    for (l = list; l != NULL; l = l->next) {
 195        ObjectClass *oc = OBJECT_CLASS(l->data);
 196        qemu_printf("  %s\n", object_class_get_name(oc));
 197    }
 198    g_slist_free(list);
 199}
 200
 201bool type_print_class_properties(const char *type)
 202{
 203    ObjectClass *klass;
 204    ObjectPropertyIterator iter;
 205    ObjectProperty *prop;
 206    GPtrArray *array;
 207    int i;
 208
 209    klass = object_class_by_name(type);
 210    if (!klass) {
 211        return false;
 212    }
 213
 214    array = g_ptr_array_new();
 215    object_class_property_iter_init(&iter, klass);
 216    while ((prop = object_property_iter_next(&iter))) {
 217        if (!prop->set) {
 218            continue;
 219        }
 220
 221        g_ptr_array_add(array,
 222                        object_property_help(prop->name, prop->type,
 223                                             prop->defval, prop->description));
 224    }
 225    g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
 226    if (array->len > 0) {
 227        qemu_printf("%s options:\n", type);
 228    } else {
 229        qemu_printf("There are no options for %s.\n", type);
 230    }
 231    for (i = 0; i < array->len; i++) {
 232        qemu_printf("%s\n", (char *)array->pdata[i]);
 233    }
 234    g_ptr_array_set_free_func(array, g_free);
 235    g_ptr_array_free(array, true);
 236    return true;
 237}
 238
 239bool user_creatable_print_help(const char *type, QemuOpts *opts)
 240{
 241    if (is_help_option(type)) {
 242        user_creatable_print_types();
 243        return true;
 244    }
 245
 246    if (qemu_opt_has_help_opt(opts)) {
 247        return type_print_class_properties(type);
 248    }
 249
 250    return false;
 251}
 252
 253static void user_creatable_print_help_from_qdict(QDict *args)
 254{
 255    const char *type = qdict_get_try_str(args, "qom-type");
 256
 257    if (!type || !type_print_class_properties(type)) {
 258        user_creatable_print_types();
 259    }
 260}
 261
 262ObjectOptions *user_creatable_parse_str(const char *optarg, Error **errp)
 263{
 264    ERRP_GUARD();
 265    QObject *obj;
 266    bool help;
 267    Visitor *v;
 268    ObjectOptions *options;
 269
 270    if (optarg[0] == '{') {
 271        obj = qobject_from_json(optarg, errp);
 272        if (!obj) {
 273            return NULL;
 274        }
 275        v = qobject_input_visitor_new(obj);
 276    } else {
 277        QDict *args = keyval_parse(optarg, "qom-type", &help, errp);
 278        if (*errp) {
 279            return NULL;
 280        }
 281        if (help) {
 282            user_creatable_print_help_from_qdict(args);
 283            qobject_unref(args);
 284            return NULL;
 285        }
 286
 287        obj = QOBJECT(args);
 288        v = qobject_input_visitor_new_keyval(obj);
 289    }
 290
 291    visit_type_ObjectOptions(v, NULL, &options, errp);
 292    visit_free(v);
 293    qobject_unref(obj);
 294
 295    return options;
 296}
 297
 298bool user_creatable_add_from_str(const char *optarg, Error **errp)
 299{
 300    ERRP_GUARD();
 301    ObjectOptions *options;
 302
 303    options = user_creatable_parse_str(optarg, errp);
 304    if (!options) {
 305        return false;
 306    }
 307
 308    user_creatable_add_qapi(options, errp);
 309    qapi_free_ObjectOptions(options);
 310    return !*errp;
 311}
 312
 313void user_creatable_process_cmdline(const char *optarg)
 314{
 315    if (!user_creatable_add_from_str(optarg, &error_fatal)) {
 316        /* Help was printed */
 317        exit(EXIT_SUCCESS);
 318    }
 319}
 320
 321bool user_creatable_del(const char *id, Error **errp)
 322{
 323    QemuOptsList *opts_list;
 324    Object *container;
 325    Object *obj;
 326
 327    container = object_get_objects_root();
 328    obj = object_resolve_path_component(container, id);
 329    if (!obj) {
 330        error_setg(errp, "object '%s' not found", id);
 331        return false;
 332    }
 333
 334    if (!user_creatable_can_be_deleted(USER_CREATABLE(obj))) {
 335        error_setg(errp, "object '%s' is in use, can not be deleted", id);
 336        return false;
 337    }
 338
 339    /*
 340     * if object was defined on the command-line, remove its corresponding
 341     * option group entry
 342     */
 343    opts_list = qemu_find_opts_err("object", NULL);
 344    if (opts_list) {
 345        qemu_opts_del(qemu_opts_find(opts_list, id));
 346    }
 347
 348    object_unparent(obj);
 349    return true;
 350}
 351
 352void user_creatable_cleanup(void)
 353{
 354    object_unparent(object_get_objects_root());
 355}
 356
 357static void register_types(void)
 358{
 359    static const TypeInfo uc_interface_info = {
 360        .name          = TYPE_USER_CREATABLE,
 361        .parent        = TYPE_INTERFACE,
 362        .class_size = sizeof(UserCreatableClass),
 363    };
 364
 365    type_register_static(&uc_interface_info);
 366}
 367
 368type_init(register_types)
 369