#include "qemu/cutils.h"
#include "qapi/error.h"
+#include "qapi/qapi-commands-qom.h"
+#include "qapi/qapi-visit-qom.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h"
#include "qapi/qmp/qjson.h"
-#include "qapi/qmp/qstring.h"
#include "qapi/qobject-input-visitor.h"
+#include "qapi/qobject-output-visitor.h"
#include "qom/object_interfaces.h"
#include "qemu/help_option.h"
+#include "qemu/id.h"
#include "qemu/module.h"
#include "qemu/option.h"
+#include "qemu/qemu-print.h"
#include "qapi/opts-visitor.h"
#include "qemu/config-file.h"
+#include "qemu/keyval.h"
-void user_creatable_complete(UserCreatable *uc, Error **errp)
+bool user_creatable_complete(UserCreatable *uc, Error **errp)
{
UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
+ Error *err = NULL;
if (ucc->complete) {
- ucc->complete(uc, errp);
+ ucc->complete(uc, &err);
+ error_propagate(errp, err);
}
+ return !err;
}
bool user_creatable_can_be_deleted(UserCreatable *uc)
}
}
+static void object_set_properties_from_qdict(Object *obj, const QDict *qdict,
+ Visitor *v, Error **errp)
+{
+ const QDictEntry *e;
+
+ if (!visit_start_struct(v, NULL, NULL, 0, errp)) {
+ return;
+ }
+ for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
+ if (!object_property_set(obj, e->key, v, errp)) {
+ goto out;
+ }
+ }
+ visit_check_struct(v, errp);
+out:
+ visit_end_struct(v, NULL);
+}
+
+void object_set_properties_from_keyval(Object *obj, const QDict *qdict,
+ bool from_json, Error **errp)
+{
+ Visitor *v;
+ if (from_json) {
+ v = qobject_input_visitor_new(QOBJECT(qdict));
+ } else {
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
+ }
+ object_set_properties_from_qdict(obj, qdict, v, errp);
+ visit_free(v);
+}
+
Object *user_creatable_add_type(const char *type, const char *id,
const QDict *qdict,
Visitor *v, Error **errp)
{
+ ERRP_GUARD();
Object *obj;
ObjectClass *klass;
- const QDictEntry *e;
Error *local_err = NULL;
+ if (id != NULL && !id_wellformed(id)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "id", "an identifier");
+ error_append_hint(errp, "Identifiers consist of letters, digits, "
+ "'-', '.', '_', starting with a letter.\n");
+ return NULL;
+ }
+
klass = object_class_by_name(type);
if (!klass) {
error_setg(errp, "invalid object type: %s", type);
assert(qdict);
obj = object_new(type);
- visit_start_struct(v, NULL, NULL, 0, &local_err);
- if (local_err) {
- goto out;
- }
- for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
- object_property_set(obj, v, e->key, &local_err);
- if (local_err) {
- break;
- }
- }
- if (!local_err) {
- visit_check_struct(v, &local_err);
- }
- visit_end_struct(v, NULL);
+ object_set_properties_from_qdict(obj, qdict, v, &local_err);
if (local_err) {
goto out;
}
if (id != NULL) {
- object_property_add_child(object_get_objects_root(),
- id, obj);
+ object_property_try_add_child(object_get_objects_root(),
+ id, obj, &local_err);
+ if (local_err) {
+ goto out;
+ }
}
- user_creatable_complete(USER_CREATABLE(obj), &local_err);
- if (local_err) {
+ if (!user_creatable_complete(USER_CREATABLE(obj), &local_err)) {
if (id != NULL) {
object_property_del(object_get_objects_root(), id);
}
return obj;
}
-void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp)
+void user_creatable_add_qapi(ObjectOptions *options, Error **errp)
{
Visitor *v;
+ QObject *qobj;
+ QDict *props;
Object *obj;
- g_autofree char *type = NULL;
- g_autofree char *id = NULL;
-
- type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
- if (!type) {
- error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
- return;
- }
- qdict_del(qdict, "qom-type");
-
- id = g_strdup(qdict_get_try_str(qdict, "id"));
- if (!id) {
- error_setg(errp, QERR_MISSING_PARAMETER, "id");
- return;
- }
- qdict_del(qdict, "id");
- if (keyval) {
- v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
- } else {
- v = qobject_input_visitor_new(QOBJECT(qdict));
- }
- obj = user_creatable_add_type(type, id, qdict, v, errp);
+ v = qobject_output_visitor_new(&qobj);
+ visit_type_ObjectOptions(v, NULL, &options, &error_abort);
+ visit_complete(v, &qobj);
visit_free(v);
- object_unref(obj);
-}
-Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
-{
- Visitor *v;
- QDict *pdict;
- Object *obj;
- const char *id = qemu_opts_id(opts);
- char *type = qemu_opt_get_del(opts, "qom-type");
+ props = qobject_to(QDict, qobj);
+ qdict_del(props, "qom-type");
+ qdict_del(props, "id");
- if (!type) {
- error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
- return NULL;
- }
- if (!id) {
- error_setg(errp, QERR_MISSING_PARAMETER, "id");
- qemu_opt_set(opts, "qom-type", type, &error_abort);
- g_free(type);
- return NULL;
- }
-
- qemu_opts_set_id(opts, NULL);
- pdict = qemu_opts_to_qdict(opts, NULL);
-
- v = opts_visitor_new(opts);
- obj = user_creatable_add_type(type, id, pdict, v, errp);
- visit_free(v);
-
- qemu_opts_set_id(opts, (char *) id);
- qemu_opt_set(opts, "qom-type", type, &error_abort);
- g_free(type);
- qobject_unref(pdict);
- return obj;
-}
-
-
-int user_creatable_add_opts_foreach(void *opaque, QemuOpts *opts, Error **errp)
-{
- bool (*type_opt_predicate)(const char *, QemuOpts *) = opaque;
- Object *obj = NULL;
- const char *type;
-
- type = qemu_opt_get(opts, "qom-type");
- if (type && type_opt_predicate &&
- !type_opt_predicate(type, opts)) {
- return 0;
- }
-
- obj = user_creatable_add_opts(opts, errp);
- if (!obj) {
- return -1;
- }
+ v = qobject_input_visitor_new(QOBJECT(props));
+ obj = user_creatable_add_type(ObjectType_str(options->qom_type),
+ options->id, props, v, errp);
object_unref(obj);
- return 0;
+ qobject_unref(qobj);
+ visit_free(v);
}
char *object_property_help(const char *name, const char *type,
g_string_append(str, description);
}
if (defval) {
- g_autofree char *def_json = qstring_free(qobject_to_json(defval), TRUE);
+ g_autofree char *def_json = g_string_free(qobject_to_json(defval),
+ false);
g_string_append_printf(str, " (default: %s)", def_json);
}
return g_string_free(str, false);
}
-bool user_creatable_print_help(const char *type, QemuOpts *opts)
+static void user_creatable_print_types(void)
+{
+ GSList *l, *list;
+
+ qemu_printf("List of user creatable objects:\n");
+ list = object_class_get_list_sorted(TYPE_USER_CREATABLE, false);
+ for (l = list; l != NULL; l = l->next) {
+ ObjectClass *oc = OBJECT_CLASS(l->data);
+ qemu_printf(" %s\n", object_class_get_name(oc));
+ }
+ g_slist_free(list);
+}
+
+bool type_print_class_properties(const char *type)
{
ObjectClass *klass;
+ ObjectPropertyIterator iter;
+ ObjectProperty *prop;
+ GPtrArray *array;
+ int i;
- if (is_help_option(type)) {
- GSList *l, *list;
+ klass = object_class_by_name(type);
+ if (!klass) {
+ return false;
+ }
- printf("List of user creatable objects:\n");
- list = object_class_get_list_sorted(TYPE_USER_CREATABLE, false);
- for (l = list; l != NULL; l = l->next) {
- ObjectClass *oc = OBJECT_CLASS(l->data);
- printf(" %s\n", object_class_get_name(oc));
+ array = g_ptr_array_new();
+ object_class_property_iter_init(&iter, klass);
+ while ((prop = object_property_iter_next(&iter))) {
+ if (!prop->set) {
+ continue;
}
- g_slist_free(list);
+
+ g_ptr_array_add(array,
+ object_property_help(prop->name, prop->type,
+ prop->defval, prop->description));
+ }
+ g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
+ if (array->len > 0) {
+ qemu_printf("%s options:\n", type);
+ } else {
+ qemu_printf("There are no options for %s.\n", type);
+ }
+ for (i = 0; i < array->len; i++) {
+ qemu_printf("%s\n", (char *)array->pdata[i]);
+ }
+ g_ptr_array_set_free_func(array, g_free);
+ g_ptr_array_free(array, true);
+ return true;
+}
+
+bool user_creatable_print_help(const char *type, QemuOpts *opts)
+{
+ if (is_help_option(type)) {
+ user_creatable_print_types();
return true;
}
- klass = object_class_by_name(type);
- if (klass && qemu_opt_has_help_opt(opts)) {
- ObjectPropertyIterator iter;
- ObjectProperty *prop;
- GPtrArray *array = g_ptr_array_new();
- int i;
-
- object_class_property_iter_init(&iter, klass);
- while ((prop = object_property_iter_next(&iter))) {
- if (!prop->set) {
- continue;
- }
-
- g_ptr_array_add(array,
- object_property_help(prop->name, prop->type,
- prop->defval, prop->description));
+ if (qemu_opt_has_help_opt(opts)) {
+ return type_print_class_properties(type);
+ }
+
+ return false;
+}
+
+static void user_creatable_print_help_from_qdict(QDict *args)
+{
+ const char *type = qdict_get_try_str(args, "qom-type");
+
+ if (!type || !type_print_class_properties(type)) {
+ user_creatable_print_types();
+ }
+}
+
+ObjectOptions *user_creatable_parse_str(const char *optarg, Error **errp)
+{
+ ERRP_GUARD();
+ QObject *obj;
+ bool help;
+ Visitor *v;
+ ObjectOptions *options;
+
+ if (optarg[0] == '{') {
+ obj = qobject_from_json(optarg, errp);
+ if (!obj) {
+ return NULL;
}
- g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
- if (array->len > 0) {
- printf("%s options:\n", type);
- } else {
- printf("There are no options for %s.\n", type);
+ v = qobject_input_visitor_new(obj);
+ } else {
+ QDict *args = keyval_parse(optarg, "qom-type", &help, errp);
+ if (*errp) {
+ return NULL;
}
- for (i = 0; i < array->len; i++) {
- printf("%s\n", (char *)array->pdata[i]);
+ if (help) {
+ user_creatable_print_help_from_qdict(args);
+ qobject_unref(args);
+ return NULL;
}
- g_ptr_array_set_free_func(array, g_free);
- g_ptr_array_free(array, true);
- return true;
+
+ obj = QOBJECT(args);
+ v = qobject_input_visitor_new_keyval(obj);
}
- return false;
+ visit_type_ObjectOptions(v, NULL, &options, errp);
+ visit_free(v);
+ qobject_unref(obj);
+
+ return options;
+}
+
+bool user_creatable_add_from_str(const char *optarg, Error **errp)
+{
+ ERRP_GUARD();
+ ObjectOptions *options;
+
+ options = user_creatable_parse_str(optarg, errp);
+ if (!options) {
+ return false;
+ }
+
+ user_creatable_add_qapi(options, errp);
+ qapi_free_ObjectOptions(options);
+ return !*errp;
}
-void user_creatable_del(const char *id, Error **errp)
+void user_creatable_process_cmdline(const char *optarg)
{
+ if (!user_creatable_add_from_str(optarg, &error_fatal)) {
+ /* Help was printed */
+ exit(EXIT_SUCCESS);
+ }
+}
+
+bool user_creatable_del(const char *id, Error **errp)
+{
+ QemuOptsList *opts_list;
Object *container;
Object *obj;
obj = object_resolve_path_component(container, id);
if (!obj) {
error_setg(errp, "object '%s' not found", id);
- return;
+ return false;
}
if (!user_creatable_can_be_deleted(USER_CREATABLE(obj))) {
error_setg(errp, "object '%s' is in use, can not be deleted", id);
- return;
+ return false;
}
/*
* if object was defined on the command-line, remove its corresponding
* option group entry
*/
- qemu_opts_del(qemu_opts_find(qemu_find_opts_err("object", &error_abort),
- id));
+ opts_list = qemu_find_opts_err("object", NULL);
+ if (opts_list) {
+ qemu_opts_del(qemu_opts_find(opts_list, id));
+ }
object_unparent(obj);
+ return true;
}
void user_creatable_cleanup(void)