qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

check-qom-proplist.c (18329B)


      1 /*
      2  * Copyright (C) 2015 Red Hat, Inc.
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Lesser General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2.1 of the License, or (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * Lesser General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Lesser General Public
     15  * License along with this library.  If not, see
     16  * <http://www.gnu.org/licenses/>.
     17  *
     18  * Author: Daniel P. Berrange <berrange@redhat.com>
     19  */
     20 
     21 #include "qemu/osdep.h"
     22 
     23 #include "qapi/error.h"
     24 #include "qapi/qobject-input-visitor.h"
     25 #include "qapi/qmp/qdict.h"
     26 #include "qapi/qmp/qobject.h"
     27 #include "qom/object.h"
     28 #include "qemu/module.h"
     29 #include "qemu/option.h"
     30 #include "qemu/keyval.h"
     31 #include "qemu/config-file.h"
     32 #include "qom/object_interfaces.h"
     33 
     34 
     35 #define TYPE_DUMMY "qemu-dummy"
     36 
     37 typedef struct DummyObject DummyObject;
     38 typedef struct DummyObjectClass DummyObjectClass;
     39 
     40 DECLARE_INSTANCE_CHECKER(DummyObject, DUMMY_OBJECT,
     41                          TYPE_DUMMY)
     42 
     43 typedef enum DummyAnimal DummyAnimal;
     44 
     45 enum DummyAnimal {
     46     DUMMY_FROG,
     47     DUMMY_ALLIGATOR,
     48     DUMMY_PLATYPUS,
     49 
     50     DUMMY_LAST,
     51 };
     52 
     53 const QEnumLookup dummy_animal_map = {
     54     .array = (const char *const[]) {
     55         [DUMMY_FROG] = "frog",
     56         [DUMMY_ALLIGATOR] = "alligator",
     57         [DUMMY_PLATYPUS] = "platypus",
     58     },
     59     .size = DUMMY_LAST
     60 };
     61 
     62 struct DummyObject {
     63     Object parent_obj;
     64 
     65     bool bv;
     66     DummyAnimal av;
     67     char *sv;
     68 };
     69 
     70 struct DummyObjectClass {
     71     ObjectClass parent_class;
     72 };
     73 
     74 
     75 static void dummy_set_bv(Object *obj,
     76                          bool value,
     77                          Error **errp)
     78 {
     79     DummyObject *dobj = DUMMY_OBJECT(obj);
     80 
     81     dobj->bv = value;
     82 }
     83 
     84 static bool dummy_get_bv(Object *obj,
     85                          Error **errp)
     86 {
     87     DummyObject *dobj = DUMMY_OBJECT(obj);
     88 
     89     return dobj->bv;
     90 }
     91 
     92 
     93 static void dummy_set_av(Object *obj,
     94                          int value,
     95                          Error **errp)
     96 {
     97     DummyObject *dobj = DUMMY_OBJECT(obj);
     98 
     99     dobj->av = value;
    100 }
    101 
    102 static int dummy_get_av(Object *obj,
    103                         Error **errp)
    104 {
    105     DummyObject *dobj = DUMMY_OBJECT(obj);
    106 
    107     return dobj->av;
    108 }
    109 
    110 
    111 static void dummy_set_sv(Object *obj,
    112                          const char *value,
    113                          Error **errp)
    114 {
    115     DummyObject *dobj = DUMMY_OBJECT(obj);
    116 
    117     g_free(dobj->sv);
    118     dobj->sv = g_strdup(value);
    119 }
    120 
    121 static char *dummy_get_sv(Object *obj,
    122                           Error **errp)
    123 {
    124     DummyObject *dobj = DUMMY_OBJECT(obj);
    125 
    126     return g_strdup(dobj->sv);
    127 }
    128 
    129 
    130 static void dummy_init(Object *obj)
    131 {
    132     object_property_add_bool(obj, "bv",
    133                              dummy_get_bv,
    134                              dummy_set_bv);
    135 }
    136 
    137 
    138 static void dummy_class_init(ObjectClass *cls, void *data)
    139 {
    140     object_class_property_add_str(cls, "sv",
    141                                   dummy_get_sv,
    142                                   dummy_set_sv);
    143     object_class_property_add_enum(cls, "av",
    144                                    "DummyAnimal",
    145                                    &dummy_animal_map,
    146                                    dummy_get_av,
    147                                    dummy_set_av);
    148 }
    149 
    150 
    151 static void dummy_finalize(Object *obj)
    152 {
    153     DummyObject *dobj = DUMMY_OBJECT(obj);
    154 
    155     g_free(dobj->sv);
    156 }
    157 
    158 
    159 static const TypeInfo dummy_info = {
    160     .name          = TYPE_DUMMY,
    161     .parent        = TYPE_OBJECT,
    162     .instance_size = sizeof(DummyObject),
    163     .instance_init = dummy_init,
    164     .instance_finalize = dummy_finalize,
    165     .class_size = sizeof(DummyObjectClass),
    166     .class_init = dummy_class_init,
    167     .interfaces = (InterfaceInfo[]) {
    168         { TYPE_USER_CREATABLE },
    169         { }
    170     }
    171 };
    172 
    173 
    174 /*
    175  * The following 3 object classes are used to
    176  * simulate the kind of relationships seen in
    177  * qdev, which result in complex object
    178  * property destruction ordering.
    179  *
    180  * DummyDev has a 'bus' child to a DummyBus
    181  * DummyBus has a 'backend' child to a DummyBackend
    182  * DummyDev has a 'backend' link to DummyBackend
    183  *
    184  * When DummyDev is finalized, it unparents the
    185  * DummyBackend, which unparents the DummyDev
    186  * which deletes the 'backend' link from DummyDev
    187  * to DummyBackend. This illustrates that the
    188  * object_property_del_all() method needs to
    189  * cope with the list of properties being changed
    190  * while it iterates over them.
    191  */
    192 typedef struct DummyDev DummyDev;
    193 typedef struct DummyDevClass DummyDevClass;
    194 typedef struct DummyBus DummyBus;
    195 typedef struct DummyBusClass DummyBusClass;
    196 typedef struct DummyBackend DummyBackend;
    197 typedef struct DummyBackendClass DummyBackendClass;
    198 
    199 #define TYPE_DUMMY_DEV "qemu-dummy-dev"
    200 #define TYPE_DUMMY_BUS "qemu-dummy-bus"
    201 #define TYPE_DUMMY_BACKEND "qemu-dummy-backend"
    202 
    203 DECLARE_INSTANCE_CHECKER(DummyDev, DUMMY_DEV,
    204                          TYPE_DUMMY_DEV)
    205 DECLARE_INSTANCE_CHECKER(DummyBus, DUMMY_BUS,
    206                          TYPE_DUMMY_BUS)
    207 DECLARE_INSTANCE_CHECKER(DummyBackend, DUMMY_BACKEND,
    208                          TYPE_DUMMY_BACKEND)
    209 
    210 struct DummyDev {
    211     Object parent_obj;
    212 
    213     DummyBus *bus;
    214 };
    215 
    216 struct DummyDevClass {
    217     ObjectClass parent_class;
    218 };
    219 
    220 struct DummyBus {
    221     Object parent_obj;
    222 
    223     DummyBackend *backend;
    224 };
    225 
    226 struct DummyBusClass {
    227     ObjectClass parent_class;
    228 };
    229 
    230 struct DummyBackend {
    231     Object parent_obj;
    232 };
    233 
    234 struct DummyBackendClass {
    235     ObjectClass parent_class;
    236 };
    237 
    238 
    239 static void dummy_dev_finalize(Object *obj)
    240 {
    241     DummyDev *dev = DUMMY_DEV(obj);
    242 
    243     object_unref(OBJECT(dev->bus));
    244 }
    245 
    246 static void dummy_dev_init(Object *obj)
    247 {
    248     DummyDev *dev = DUMMY_DEV(obj);
    249     DummyBus *bus = DUMMY_BUS(object_new(TYPE_DUMMY_BUS));
    250     DummyBackend *backend = DUMMY_BACKEND(object_new(TYPE_DUMMY_BACKEND));
    251 
    252     object_property_add_child(obj, "bus", OBJECT(bus));
    253     dev->bus = bus;
    254     object_property_add_child(OBJECT(bus), "backend", OBJECT(backend));
    255     bus->backend = backend;
    256 
    257     object_property_add_link(obj, "backend", TYPE_DUMMY_BACKEND,
    258                              (Object **)&bus->backend, NULL, 0);
    259 }
    260 
    261 static void dummy_dev_unparent(Object *obj)
    262 {
    263     DummyDev *dev = DUMMY_DEV(obj);
    264     object_unparent(OBJECT(dev->bus));
    265 }
    266 
    267 static void dummy_dev_class_init(ObjectClass *klass, void *opaque)
    268 {
    269     klass->unparent = dummy_dev_unparent;
    270 }
    271 
    272 
    273 static void dummy_bus_finalize(Object *obj)
    274 {
    275     DummyBus *bus = DUMMY_BUS(obj);
    276 
    277     object_unref(OBJECT(bus->backend));
    278 }
    279 
    280 static void dummy_bus_init(Object *obj)
    281 {
    282 }
    283 
    284 static void dummy_bus_unparent(Object *obj)
    285 {
    286     DummyBus *bus = DUMMY_BUS(obj);
    287     object_property_del(obj->parent, "backend");
    288     object_unparent(OBJECT(bus->backend));
    289 }
    290 
    291 static void dummy_bus_class_init(ObjectClass *klass, void *opaque)
    292 {
    293     klass->unparent = dummy_bus_unparent;
    294 }
    295 
    296 static void dummy_backend_init(Object *obj)
    297 {
    298 }
    299 
    300 
    301 static const TypeInfo dummy_dev_info = {
    302     .name          = TYPE_DUMMY_DEV,
    303     .parent        = TYPE_OBJECT,
    304     .instance_size = sizeof(DummyDev),
    305     .instance_init = dummy_dev_init,
    306     .instance_finalize = dummy_dev_finalize,
    307     .class_size = sizeof(DummyDevClass),
    308     .class_init = dummy_dev_class_init,
    309 };
    310 
    311 static const TypeInfo dummy_bus_info = {
    312     .name          = TYPE_DUMMY_BUS,
    313     .parent        = TYPE_OBJECT,
    314     .instance_size = sizeof(DummyBus),
    315     .instance_init = dummy_bus_init,
    316     .instance_finalize = dummy_bus_finalize,
    317     .class_size = sizeof(DummyBusClass),
    318     .class_init = dummy_bus_class_init,
    319 };
    320 
    321 static const TypeInfo dummy_backend_info = {
    322     .name          = TYPE_DUMMY_BACKEND,
    323     .parent        = TYPE_OBJECT,
    324     .instance_size = sizeof(DummyBackend),
    325     .instance_init = dummy_backend_init,
    326     .class_size = sizeof(DummyBackendClass),
    327 };
    328 
    329 static QemuOptsList qemu_object_opts = {
    330     .name = "object",
    331     .implied_opt_name = "qom-type",
    332     .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head),
    333     .desc = {
    334         { }
    335     },
    336 };
    337 
    338 
    339 static void test_dummy_createv(void)
    340 {
    341     Error *err = NULL;
    342     Object *parent = object_get_objects_root();
    343     DummyObject *dobj = DUMMY_OBJECT(
    344         object_new_with_props(TYPE_DUMMY,
    345                               parent,
    346                               "dummy0",
    347                               &err,
    348                               "bv", "yes",
    349                               "sv", "Hiss hiss hiss",
    350                               "av", "platypus",
    351                               NULL));
    352 
    353     g_assert(err == NULL);
    354     g_assert_cmpstr(dobj->sv, ==, "Hiss hiss hiss");
    355     g_assert(dobj->bv == true);
    356     g_assert(dobj->av == DUMMY_PLATYPUS);
    357 
    358     g_assert(object_resolve_path_component(parent, "dummy0")
    359              == OBJECT(dobj));
    360 
    361     object_unparent(OBJECT(dobj));
    362 }
    363 
    364 
    365 static Object *new_helper(Error **errp,
    366                           Object *parent,
    367                           ...)
    368 {
    369     va_list vargs;
    370     Object *obj;
    371 
    372     va_start(vargs, parent);
    373     obj = object_new_with_propv(TYPE_DUMMY,
    374                                 parent,
    375                                 "dummy0",
    376                                 errp,
    377                                 vargs);
    378     va_end(vargs);
    379     return obj;
    380 }
    381 
    382 static void test_dummy_createlist(void)
    383 {
    384     Error *err = NULL;
    385     Object *parent = object_get_objects_root();
    386     DummyObject *dobj = DUMMY_OBJECT(
    387         new_helper(&err,
    388                    parent,
    389                    "bv", "yes",
    390                    "sv", "Hiss hiss hiss",
    391                    "av", "platypus",
    392                    NULL));
    393 
    394     g_assert(err == NULL);
    395     g_assert_cmpstr(dobj->sv, ==, "Hiss hiss hiss");
    396     g_assert(dobj->bv == true);
    397     g_assert(dobj->av == DUMMY_PLATYPUS);
    398 
    399     g_assert(object_resolve_path_component(parent, "dummy0")
    400              == OBJECT(dobj));
    401 
    402     object_unparent(OBJECT(dobj));
    403 }
    404 
    405 static bool test_create_obj(QDict *qdict, Error **errp)
    406 {
    407     Visitor *v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
    408     Object *obj = user_creatable_add_type(TYPE_DUMMY, "dev0", qdict, v, errp);
    409 
    410     visit_free(v);
    411     object_unref(obj);
    412     return !!obj;
    413 }
    414 
    415 static void test_dummy_createcmdl(void)
    416 {
    417     QDict *qdict;
    418     DummyObject *dobj;
    419     Error *err = NULL;
    420     bool created, help;
    421     const char *params = "bv=yes,sv=Hiss hiss hiss,av=platypus";
    422 
    423     /* Needed for user_creatable_del.  */
    424     qemu_add_opts(&qemu_object_opts);
    425 
    426     qdict = keyval_parse(params, "qom-type", &help, &err);
    427     g_assert(err == NULL);
    428     g_assert(qdict);
    429     g_assert(!help);
    430 
    431     created = test_create_obj(qdict, &err);
    432     g_assert(created);
    433     g_assert(err == NULL);
    434     qobject_unref(qdict);
    435 
    436     dobj = DUMMY_OBJECT(object_resolve_path_component(object_get_objects_root(),
    437                                                       "dev0"));
    438     g_assert(dobj);
    439     g_assert_cmpstr(dobj->sv, ==, "Hiss hiss hiss");
    440     g_assert(dobj->bv == true);
    441     g_assert(dobj->av == DUMMY_PLATYPUS);
    442 
    443     qdict = keyval_parse(params, "qom-type", &help, &err);
    444     created = test_create_obj(qdict, &err);
    445     g_assert(!created);
    446     g_assert(err);
    447     g_assert(object_resolve_path_component(object_get_objects_root(), "dev0")
    448              == OBJECT(dobj));
    449     qobject_unref(qdict);
    450     error_free(err);
    451     err = NULL;
    452 
    453     qdict = keyval_parse(params, "qom-type", &help, &err);
    454     user_creatable_del("dev0", &error_abort);
    455     g_assert(object_resolve_path_component(object_get_objects_root(), "dev0")
    456              == NULL);
    457 
    458     created = test_create_obj(qdict, &err);
    459     g_assert(created);
    460     g_assert(err == NULL);
    461     qobject_unref(qdict);
    462 
    463     dobj = DUMMY_OBJECT(object_resolve_path_component(object_get_objects_root(),
    464                                                       "dev0"));
    465     g_assert(dobj);
    466     g_assert_cmpstr(dobj->sv, ==, "Hiss hiss hiss");
    467     g_assert(dobj->bv == true);
    468     g_assert(dobj->av == DUMMY_PLATYPUS);
    469     g_assert(object_resolve_path_component(object_get_objects_root(), "dev0")
    470              == OBJECT(dobj));
    471 
    472     object_unparent(OBJECT(dobj));
    473 }
    474 
    475 static void test_dummy_badenum(void)
    476 {
    477     Error *err = NULL;
    478     Object *parent = object_get_objects_root();
    479     Object *dobj =
    480         object_new_with_props(TYPE_DUMMY,
    481                               parent,
    482                               "dummy0",
    483                               &err,
    484                               "bv", "yes",
    485                               "sv", "Hiss hiss hiss",
    486                               "av", "yeti",
    487                               NULL);
    488 
    489     g_assert(dobj == NULL);
    490     g_assert(err != NULL);
    491     g_assert_cmpstr(error_get_pretty(err), ==,
    492                     "Parameter 'av' does not accept value 'yeti'");
    493 
    494     g_assert(object_resolve_path_component(parent, "dummy0")
    495              == NULL);
    496 
    497     error_free(err);
    498 }
    499 
    500 
    501 static void test_dummy_getenum(void)
    502 {
    503     Error *err = NULL;
    504     int val;
    505     Object *parent = object_get_objects_root();
    506     DummyObject *dobj = DUMMY_OBJECT(
    507         object_new_with_props(TYPE_DUMMY,
    508                          parent,
    509                          "dummy0",
    510                          &err,
    511                          "av", "platypus",
    512                          NULL));
    513 
    514     g_assert(err == NULL);
    515     g_assert(dobj->av == DUMMY_PLATYPUS);
    516 
    517     val = object_property_get_enum(OBJECT(dobj),
    518                                    "av",
    519                                    "DummyAnimal",
    520                                    &error_abort);
    521     g_assert(val == DUMMY_PLATYPUS);
    522 
    523     /* A bad enum type name */
    524     val = object_property_get_enum(OBJECT(dobj),
    525                                    "av",
    526                                    "BadAnimal",
    527                                    &err);
    528     g_assert(val == -1);
    529     error_free_or_abort(&err);
    530 
    531     /* A non-enum property name */
    532     val = object_property_get_enum(OBJECT(dobj),
    533                                    "iv",
    534                                    "DummyAnimal",
    535                                    &err);
    536     g_assert(val == -1);
    537     error_free_or_abort(&err);
    538 
    539     object_unparent(OBJECT(dobj));
    540 }
    541 
    542 
    543 static void test_dummy_prop_iterator(ObjectPropertyIterator *iter,
    544                                      const char *expected[], int n)
    545 {
    546     ObjectProperty *prop;
    547     int i;
    548 
    549     while ((prop = object_property_iter_next(iter))) {
    550         for (i = 0; i < n; i++) {
    551             if (!g_strcmp0(prop->name, expected[i])) {
    552                 break;
    553             }
    554         }
    555         g_assert(i < n);
    556         expected[i] = NULL;
    557     }
    558 
    559     for (i = 0; i < n; i++) {
    560         g_assert(!expected[i]);
    561     }
    562 }
    563 
    564 static void test_dummy_iterator(void)
    565 {
    566     const char *expected[] = {
    567         "type",                 /* inherited from TYPE_OBJECT */
    568         "sv", "av",             /* class properties */
    569         "bv"};                  /* instance property */
    570     Object *parent = object_get_objects_root();
    571     DummyObject *dobj = DUMMY_OBJECT(
    572         object_new_with_props(TYPE_DUMMY,
    573                               parent,
    574                               "dummy0",
    575                               &error_abort,
    576                               "bv", "yes",
    577                               "sv", "Hiss hiss hiss",
    578                               "av", "platypus",
    579                               NULL));
    580     ObjectPropertyIterator iter;
    581 
    582     object_property_iter_init(&iter, OBJECT(dobj));
    583     test_dummy_prop_iterator(&iter, expected, ARRAY_SIZE(expected));
    584     object_unparent(OBJECT(dobj));
    585 }
    586 
    587 static void test_dummy_class_iterator(void)
    588 {
    589     const char *expected[] = { "type", "av", "sv" };
    590     ObjectPropertyIterator iter;
    591     ObjectClass *klass = object_class_by_name(TYPE_DUMMY);
    592 
    593     object_class_property_iter_init(&iter, klass);
    594     test_dummy_prop_iterator(&iter, expected, ARRAY_SIZE(expected));
    595 }
    596 
    597 static void test_dummy_delchild(void)
    598 {
    599     Object *parent = object_get_objects_root();
    600     DummyDev *dev = DUMMY_DEV(
    601         object_new_with_props(TYPE_DUMMY_DEV,
    602                               parent,
    603                               "dev0",
    604                               &error_abort,
    605                               NULL));
    606 
    607     object_unparent(OBJECT(dev));
    608 }
    609 
    610 static void test_qom_partial_path(void)
    611 {
    612     Object *root  = object_get_objects_root();
    613     Object *cont1 = container_get(root, "/cont1");
    614     Object *obj1  = object_new(TYPE_DUMMY);
    615     Object *obj2a = object_new(TYPE_DUMMY);
    616     Object *obj2b = object_new(TYPE_DUMMY);
    617     bool ambiguous;
    618 
    619     /* Objects created:
    620      * /cont1
    621      * /cont1/obj1
    622      * /cont1/obj2 (obj2a)
    623      * /obj2 (obj2b)
    624      */
    625     object_property_add_child(cont1, "obj1", obj1);
    626     object_unref(obj1);
    627     object_property_add_child(cont1, "obj2", obj2a);
    628     object_unref(obj2a);
    629     object_property_add_child(root,  "obj2", obj2b);
    630     object_unref(obj2b);
    631 
    632     ambiguous = false;
    633     g_assert(!object_resolve_path_type("", TYPE_DUMMY, &ambiguous));
    634     g_assert(ambiguous);
    635     g_assert(!object_resolve_path_type("", TYPE_DUMMY, NULL));
    636 
    637     ambiguous = false;
    638     g_assert(!object_resolve_path("obj2", &ambiguous));
    639     g_assert(ambiguous);
    640     g_assert(!object_resolve_path("obj2", NULL));
    641 
    642     ambiguous = false;
    643     g_assert(object_resolve_path("obj1", &ambiguous) == obj1);
    644     g_assert(!ambiguous);
    645     g_assert(object_resolve_path("obj1", NULL) == obj1);
    646 
    647     object_unparent(obj2b);
    648     object_unparent(cont1);
    649 }
    650 
    651 int main(int argc, char **argv)
    652 {
    653     g_test_init(&argc, &argv, NULL);
    654 
    655     module_call_init(MODULE_INIT_QOM);
    656     type_register_static(&dummy_info);
    657     type_register_static(&dummy_dev_info);
    658     type_register_static(&dummy_bus_info);
    659     type_register_static(&dummy_backend_info);
    660 
    661     g_test_add_func("/qom/proplist/createlist", test_dummy_createlist);
    662     g_test_add_func("/qom/proplist/createv", test_dummy_createv);
    663     g_test_add_func("/qom/proplist/createcmdline", test_dummy_createcmdl);
    664     g_test_add_func("/qom/proplist/badenum", test_dummy_badenum);
    665     g_test_add_func("/qom/proplist/getenum", test_dummy_getenum);
    666     g_test_add_func("/qom/proplist/iterator", test_dummy_iterator);
    667     g_test_add_func("/qom/proplist/class_iterator", test_dummy_class_iterator);
    668     g_test_add_func("/qom/proplist/delchild", test_dummy_delchild);
    669     g_test_add_func("/qom/resolve/partial", test_qom_partial_path);
    670 
    671     return g_test_run();
    672 }