qmp.c 19.1 KB
Newer Older
A
Anthony Liguori 已提交
1 2 3 4 5 6 7 8 9 10 11
/*
 * QEMU Management Protocol
 *
 * Copyright IBM, Corp. 2011
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *
 * This work is licensed under the terms of the GNU GPL, version 2.  See
 * the COPYING file in the top-level directory.
 *
12 13
 * Contributions after 2012-01-13 are licensed under the terms of the
 * GNU GPL, version 2 or (at your option) any later version.
A
Anthony Liguori 已提交
14 15 16
 */

#include "qemu-common.h"
17
#include "sysemu/sysemu.h"
A
Anthony Liguori 已提交
18
#include "qmp-commands.h"
19
#include "sysemu/char.h"
L
Luiz Capitulino 已提交
20 21
#include "ui/qemu-spice.h"
#include "ui/vnc.h"
22 23
#include "sysemu/kvm.h"
#include "sysemu/arch_init.h"
A
Anthony Liguori 已提交
24
#include "hw/qdev.h"
25
#include "sysemu/blockdev.h"
26
#include "qom/qom-qobject.h"
27
#include "qapi/qmp/qerror.h"
28 29
#include "qapi/qmp/qobject.h"
#include "qapi/qmp-input-visitor.h"
I
Igor Mammedov 已提交
30
#include "hw/boards.h"
31
#include "qom/object_interfaces.h"
32
#include "hw/mem/pc-dimm.h"
33
#include "hw/acpi/acpi_dev_interface.h"
A
Anthony Liguori 已提交
34 35 36 37 38 39 40 41 42 43 44 45

NameInfo *qmp_query_name(Error **errp)
{
    NameInfo *info = g_malloc0(sizeof(*info));

    if (qemu_name) {
        info->has_name = true;
        info->name = g_strdup(qemu_name);
    }

    return info;
}
L
Luiz Capitulino 已提交
46

47
VersionInfo *qmp_query_version(Error **errp)
L
Luiz Capitulino 已提交
48
{
49
    VersionInfo *info = g_new0(VersionInfo, 1);
L
Luiz Capitulino 已提交
50 51 52
    const char *version = QEMU_VERSION;
    char *tmp;

53 54
    info->qemu = g_new0(VersionTriple, 1);
    info->qemu->major = strtol(version, &tmp, 10);
L
Luiz Capitulino 已提交
55
    tmp++;
56
    info->qemu->minor = strtol(tmp, &tmp, 10);
L
Luiz Capitulino 已提交
57
    tmp++;
58
    info->qemu->micro = strtol(tmp, &tmp, 10);
L
Luiz Capitulino 已提交
59 60 61 62
    info->package = g_strdup(QEMU_PKGVERSION);

    return info;
}
L
Luiz Capitulino 已提交
63 64 65 66 67 68 69 70 71 72 73

KvmInfo *qmp_query_kvm(Error **errp)
{
    KvmInfo *info = g_malloc0(sizeof(*info));

    info->enabled = kvm_enabled();
    info->present = kvm_available();

    return info;
}

L
Luiz Capitulino 已提交
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
UuidInfo *qmp_query_uuid(Error **errp)
{
    UuidInfo *info = g_malloc0(sizeof(*info));
    char uuid[64];

    snprintf(uuid, sizeof(uuid), UUID_FMT, qemu_uuid[0], qemu_uuid[1],
                   qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5],
                   qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9],
                   qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13],
                   qemu_uuid[14], qemu_uuid[15]);

    info->UUID = g_strdup(uuid);
    return info;
}

89
void qmp_quit(Error **errp)
L
Luiz Capitulino 已提交
90 91 92 93 94
{
    no_shutdown = 0;
    qemu_system_shutdown_request();
}

L
Luiz Capitulino 已提交
95 96
void qmp_stop(Error **errp)
{
97 98 99 100 101
    if (runstate_check(RUN_STATE_INMIGRATE)) {
        autostart = 0;
    } else {
        vm_stop(RUN_STATE_PAUSED);
    }
L
Luiz Capitulino 已提交
102 103
}

L
Luiz Capitulino 已提交
104 105 106 107
void qmp_system_reset(Error **errp)
{
    qemu_system_reset_request();
}
L
Luiz Capitulino 已提交
108 109 110 111 112

void qmp_system_powerdown(Error **erp)
{
    qemu_system_powerdown_request();
}
L
Luiz Capitulino 已提交
113 114 115 116 117

void qmp_cpu(int64_t index, Error **errp)
{
    /* Just do nothing */
}
L
Luiz Capitulino 已提交
118

I
Igor Mammedov 已提交
119 120
void qmp_cpu_add(int64_t id, Error **errp)
{
121 122 123
    MachineClass *mc;

    mc = MACHINE_GET_CLASS(current_machine);
124 125
    if (mc->hot_add_cpu) {
        mc->hot_add_cpu(id, errp);
I
Igor Mammedov 已提交
126 127 128 129 130
    } else {
        error_setg(errp, "Not supported");
    }
}

L
Luiz Capitulino 已提交
131 132 133 134 135
#ifndef CONFIG_VNC
/* If VNC support is enabled, the "true" query-vnc command is
   defined in the VNC subsystem */
VncInfo *qmp_query_vnc(Error **errp)
{
136
    error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
L
Luiz Capitulino 已提交
137 138
    return NULL;
};
139 140 141

VncInfo2List *qmp_query_vnc_servers(Error **errp)
{
142
    error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
143 144
    return NULL;
};
L
Luiz Capitulino 已提交
145
#endif
L
Luiz Capitulino 已提交
146 147

#ifndef CONFIG_SPICE
148 149 150 151 152 153 154 155 156
/*
 * qmp-commands.hx ensures that QMP command query-spice exists only
 * #ifdef CONFIG_SPICE.  Necessary for an accurate query-commands
 * result.  However, the QAPI schema is blissfully unaware of that,
 * and the QAPI code generator happily generates a dead
 * qmp_marshal_input_query_spice() that calls qmp_query_spice().
 * Provide it one, or else linking fails.
 * FIXME Educate the QAPI schema on CONFIG_SPICE.
 */
L
Luiz Capitulino 已提交
157 158
SpiceInfo *qmp_query_spice(Error **errp)
{
159
    abort();
L
Luiz Capitulino 已提交
160 161
};
#endif
L
Luiz Capitulino 已提交
162 163 164

void qmp_cont(Error **errp)
{
165
    Error *local_err = NULL;
166
    BlockDriverState *bs;
L
Luiz Capitulino 已提交
167

168
    if (runstate_needs_reset()) {
169
        error_setg(errp, "Resetting the Virtual Machine is required");
L
Luiz Capitulino 已提交
170
        return;
171 172
    } else if (runstate_check(RUN_STATE_SUSPENDED)) {
        return;
L
Luiz Capitulino 已提交
173 174
    }

175 176 177 178
    for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) {
        bdrv_iostatus_reset(bs);
    }
    for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) {
179 180 181
        bdrv_add_key(bs, NULL, &local_err);
        if (local_err) {
            error_propagate(errp, local_err);
182 183
            return;
        }
L
Luiz Capitulino 已提交
184 185
    }

186 187 188 189 190
    if (runstate_check(RUN_STATE_INMIGRATE)) {
        autostart = 1;
    } else {
        vm_start();
    }
L
Luiz Capitulino 已提交
191
}
A
Anthony Liguori 已提交
192

193 194 195 196 197
void qmp_system_wakeup(Error **errp)
{
    qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
}

198
ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
A
Anthony Liguori 已提交
199
{
200
    Object *obj;
A
Anthony Liguori 已提交
201
    bool ambiguous = false;
202 203
    ObjectPropertyInfoList *props = NULL;
    ObjectProperty *prop;
A
Anthony Liguori 已提交
204

205 206
    obj = object_resolve_path(path, &ambiguous);
    if (obj == NULL) {
207 208 209
        if (ambiguous) {
            error_setg(errp, "Path '%s' is ambiguous", path);
        } else {
210 211
            error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
                      "Device '%s' not found", path);
212
        }
A
Anthony Liguori 已提交
213 214 215
        return NULL;
    }

216 217
    QTAILQ_FOREACH(prop, &obj->properties, node) {
        ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry));
A
Anthony Liguori 已提交
218

219
        entry->value = g_malloc0(sizeof(ObjectPropertyInfo));
A
Anthony Liguori 已提交
220 221 222 223 224 225 226 227 228
        entry->next = props;
        props = entry;

        entry->value->name = g_strdup(prop->name);
        entry->value->type = g_strdup(prop->type);
    }

    return props;
}
229 230

/* FIXME: teach qapi about how to pass through Visitors */
231
void qmp_qom_set(QDict *qdict, QObject **ret, Error **errp)
232 233 234 235
{
    const char *path = qdict_get_str(qdict, "path");
    const char *property = qdict_get_str(qdict, "property");
    QObject *value = qdict_get(qdict, "value");
236
    Object *obj;
237

238 239
    obj = object_resolve_path(path, NULL);
    if (!obj) {
240
        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
241
                  "Device '%s' not found", path);
242
        return;
243 244
    }

245
    object_property_set_qobject(obj, value, property, errp);
246 247
}

248
void qmp_qom_get(QDict *qdict, QObject **ret, Error **errp)
249 250 251
{
    const char *path = qdict_get_str(qdict, "path");
    const char *property = qdict_get_str(qdict, "property");
252
    Object *obj;
253

254 255
    obj = object_resolve_path(path, NULL);
    if (!obj) {
256
        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
257
                  "Device '%s' not found", path);
258
        return;
259 260
    }

261
    *ret = object_property_get_qobject(obj, property, errp);
262
}
L
Luiz Capitulino 已提交
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278

void qmp_set_password(const char *protocol, const char *password,
                      bool has_connected, const char *connected, Error **errp)
{
    int disconnect_if_connected = 0;
    int fail_if_connected = 0;
    int rc;

    if (has_connected) {
        if (strcmp(connected, "fail") == 0) {
            fail_if_connected = 1;
        } else if (strcmp(connected, "disconnect") == 0) {
            disconnect_if_connected = 1;
        } else if (strcmp(connected, "keep") == 0) {
            /* nothing */
        } else {
279
            error_setg(errp, QERR_INVALID_PARAMETER, "connected");
L
Luiz Capitulino 已提交
280 281 282 283 284
            return;
        }
    }

    if (strcmp(protocol, "spice") == 0) {
285
        if (!qemu_using_spice(errp)) {
L
Luiz Capitulino 已提交
286 287 288 289 290
            return;
        }
        rc = qemu_spice_set_passwd(password, fail_if_connected,
                                   disconnect_if_connected);
        if (rc != 0) {
291
            error_setg(errp, QERR_SET_PASSWD_FAILED);
L
Luiz Capitulino 已提交
292 293 294 295 296 297 298
        }
        return;
    }

    if (strcmp(protocol, "vnc") == 0) {
        if (fail_if_connected || disconnect_if_connected) {
            /* vnc supports "connected=keep" only */
299
            error_setg(errp, QERR_INVALID_PARAMETER, "connected");
L
Luiz Capitulino 已提交
300 301 302 303 304 305
            return;
        }
        /* Note that setting an empty password will not disable login through
         * this interface. */
        rc = vnc_display_password(NULL, password);
        if (rc < 0) {
306
            error_setg(errp, QERR_SET_PASSWD_FAILED);
L
Luiz Capitulino 已提交
307 308 309 310
        }
        return;
    }

311
    error_setg(errp, QERR_INVALID_PARAMETER, "protocol");
L
Luiz Capitulino 已提交
312
}
L
Luiz Capitulino 已提交
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330

void qmp_expire_password(const char *protocol, const char *whenstr,
                         Error **errp)
{
    time_t when;
    int rc;

    if (strcmp(whenstr, "now") == 0) {
        when = 0;
    } else if (strcmp(whenstr, "never") == 0) {
        when = TIME_MAX;
    } else if (whenstr[0] == '+') {
        when = time(NULL) + strtoull(whenstr+1, NULL, 10);
    } else {
        when = strtoull(whenstr, NULL, 10);
    }

    if (strcmp(protocol, "spice") == 0) {
331
        if (!qemu_using_spice(errp)) {
L
Luiz Capitulino 已提交
332 333 334 335
            return;
        }
        rc = qemu_spice_set_pw_expire(when);
        if (rc != 0) {
336
            error_setg(errp, QERR_SET_PASSWD_FAILED);
L
Luiz Capitulino 已提交
337 338 339 340 341 342 343
        }
        return;
    }

    if (strcmp(protocol, "vnc") == 0) {
        rc = vnc_display_pw_expire(NULL, when);
        if (rc != 0) {
344
            error_setg(errp, QERR_SET_PASSWD_FAILED);
L
Luiz Capitulino 已提交
345 346 347 348
        }
        return;
    }

349
    error_setg(errp, QERR_INVALID_PARAMETER, "protocol");
L
Luiz Capitulino 已提交
350
}
351

L
Luiz Capitulino 已提交
352
#ifdef CONFIG_VNC
353 354 355
void qmp_change_vnc_password(const char *password, Error **errp)
{
    if (vnc_display_password(NULL, password) < 0) {
356
        error_setg(errp, QERR_SET_PASSWD_FAILED);
357 358
    }
}
L
Luiz Capitulino 已提交
359

360
static void qmp_change_vnc_listen(const char *target, Error **errp)
L
Luiz Capitulino 已提交
361
{
362 363 364 365 366 367 368 369 370 371 372 373
    QemuOptsList *olist = qemu_find_opts("vnc");
    QemuOpts *opts;

    if (strstr(target, "id=")) {
        error_setg(errp, "id not supported");
        return;
    }

    opts = qemu_opts_find(olist, "default");
    if (opts) {
        qemu_opts_del(opts);
    }
374
    opts = vnc_parse(target, errp);
375 376 377 378
    if (!opts) {
        return;
    }

379
    vnc_display_open("default", errp);
L
Luiz Capitulino 已提交
380 381 382 383 384 385 386
}

static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
                           Error **errp)
{
    if (strcmp(target, "passwd") == 0 || strcmp(target, "password") == 0) {
        if (!has_arg) {
387
            error_setg(errp, QERR_MISSING_PARAMETER, "password");
L
Luiz Capitulino 已提交
388 389 390 391 392 393 394 395 396 397
        } else {
            qmp_change_vnc_password(arg, errp);
        }
    } else {
        qmp_change_vnc_listen(target, errp);
    }
}
#else
void qmp_change_vnc_password(const char *password, Error **errp)
{
398
    error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
L
Luiz Capitulino 已提交
399 400 401 402
}
static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
                           Error **errp)
{
403
    error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
L
Luiz Capitulino 已提交
404 405 406 407
}
#endif /* !CONFIG_VNC */

void qmp_change(const char *device, const char *target,
408
                bool has_arg, const char *arg, Error **errp)
L
Luiz Capitulino 已提交
409 410
{
    if (strcmp(device, "vnc") == 0) {
411
        qmp_change_vnc(target, has_arg, arg, errp);
L
Luiz Capitulino 已提交
412
    } else {
413
        qmp_change_blockdev(device, target, arg, errp);
L
Luiz Capitulino 已提交
414 415
    }
}
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442

static void qom_list_types_tramp(ObjectClass *klass, void *data)
{
    ObjectTypeInfoList *e, **pret = data;
    ObjectTypeInfo *info;

    info = g_malloc0(sizeof(*info));
    info->name = g_strdup(object_class_get_name(klass));

    e = g_malloc0(sizeof(*e));
    e->value = info;
    e->next = *pret;
    *pret = e;
}

ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
                                       const char *implements,
                                       bool has_abstract,
                                       bool abstract,
                                       Error **errp)
{
    ObjectTypeInfoList *ret = NULL;

    object_class_foreach(qom_list_types_tramp, implements, abstract, &ret);

    return ret;
}
443

444 445 446 447 448 449 450 451 452
/* Return a DevicePropertyInfo for a qdev property.
 *
 * If a qdev property with the given name does not exist, use the given default
 * type.  If the qdev property info should not be shown, return NULL.
 *
 * The caller must free the return value.
 */
static DevicePropertyInfo *make_device_property_info(ObjectClass *klass,
                                                     const char *name,
453 454
                                                     const char *default_type,
                                                     const char *description)
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
{
    DevicePropertyInfo *info;
    Property *prop;

    do {
        for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) {
            if (strcmp(name, prop->name) != 0) {
                continue;
            }

            /*
             * TODO Properties without a parser are just for dirty hacks.
             * qdev_prop_ptr is the only such PropertyInfo.  It's marked
             * for removal.  This conditional should be removed along with
             * it.
             */
            if (!prop->info->set) {
                return NULL;           /* no way to set it, don't show */
            }

            info = g_malloc0(sizeof(*info));
            info->name = g_strdup(prop->name);
477 478 479
            info->type = g_strdup(prop->info->name);
            info->has_description = !!prop->info->description;
            info->description = g_strdup(prop->info->description);
480 481 482 483 484 485 486 487 488
            return info;
        }
        klass = object_class_get_parent(klass);
    } while (klass != object_class_by_name(TYPE_DEVICE));

    /* Not a qdev property, use the default type */
    info = g_malloc0(sizeof(*info));
    info->name = g_strdup(name);
    info->type = g_strdup(default_type);
489 490 491
    info->has_description = !!description;
    info->description = g_strdup(description);

492 493 494
    return info;
}

495 496 497 498
DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
                                                   Error **errp)
{
    ObjectClass *klass;
499 500
    Object *obj;
    ObjectProperty *prop;
501 502 503 504
    DevicePropertyInfoList *prop_list = NULL;

    klass = object_class_by_name(typename);
    if (klass == NULL) {
505 506
        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
                  "Device '%s' not found", typename);
507 508 509 510 511
        return NULL;
    }

    klass = object_class_dynamic_cast(klass, TYPE_DEVICE);
    if (klass == NULL) {
512
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "name", TYPE_DEVICE);
513 514 515
        return NULL;
    }

516
    obj = object_new(typename);
517

518 519 520 521 522 523 524 525
    QTAILQ_FOREACH(prop, &obj->properties, node) {
        DevicePropertyInfo *info;
        DevicePropertyInfoList *entry;

        /* Skip Object and DeviceState properties */
        if (strcmp(prop->name, "type") == 0 ||
            strcmp(prop->name, "realized") == 0 ||
            strcmp(prop->name, "hotpluggable") == 0 ||
526
            strcmp(prop->name, "hotplugged") == 0 ||
527 528 529
            strcmp(prop->name, "parent_bus") == 0) {
            continue;
        }
530

531 532 533 534 535 536
        /* Skip legacy properties since they are just string versions of
         * properties that we already list.
         */
        if (strstart(prop->name, "legacy-", NULL)) {
            continue;
        }
537

538 539
        info = make_device_property_info(klass, prop->name, prop->type,
                                         prop->description);
540 541
        if (!info) {
            continue;
542
        }
543 544 545 546 547 548 549 550

        entry = g_malloc0(sizeof(*entry));
        entry->value = info;
        entry->next = prop_list;
        prop_list = entry;
    }

    object_unref(obj);
551 552 553

    return prop_list;
}
554

555 556 557 558 559
CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
{
    return arch_query_cpu_definitions(errp);
}

L
Luiz Capitulino 已提交
560 561 562 563 564 565 566 567 568 569 570 571 572
void qmp_add_client(const char *protocol, const char *fdname,
                    bool has_skipauth, bool skipauth, bool has_tls, bool tls,
                    Error **errp)
{
    CharDriverState *s;
    int fd;

    fd = monitor_get_fd(cur_mon, fdname, errp);
    if (fd < 0) {
        return;
    }

    if (strcmp(protocol, "spice") == 0) {
573
        if (!qemu_using_spice(errp)) {
L
Luiz Capitulino 已提交
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
            close(fd);
            return;
        }
        skipauth = has_skipauth ? skipauth : false;
        tls = has_tls ? tls : false;
        if (qemu_spice_display_add_client(fd, skipauth, tls) < 0) {
            error_setg(errp, "spice failed to add client");
            close(fd);
        }
        return;
#ifdef CONFIG_VNC
    } else if (strcmp(protocol, "vnc") == 0) {
        skipauth = has_skipauth ? skipauth : false;
        vnc_display_add_client(NULL, fd, skipauth);
        return;
#endif
    } else if ((s = qemu_chr_find(protocol)) != NULL) {
        if (qemu_chr_add_client(s, fd) < 0) {
            error_setg(errp, "failed to add client");
            close(fd);
            return;
        }
        return;
    }

    error_setg(errp, "protocol '%s' is invalid", protocol);
    close(fd);
}
602

603 604 605 606
void object_add(const char *type, const char *id, const QDict *qdict,
                Visitor *v, Error **errp)
{
    Object *obj;
607
    ObjectClass *klass;
608 609 610
    const QDictEntry *e;
    Error *local_err = NULL;

611 612
    klass = object_class_by_name(type);
    if (!klass) {
613
        error_setg(errp, "invalid object type: %s", type);
614 615 616
        return;
    }

617 618 619 620 621 622 623 624 625 626 627
    if (!object_class_dynamic_cast(klass, TYPE_USER_CREATABLE)) {
        error_setg(errp, "object type '%s' isn't supported by object-add",
                   type);
        return;
    }

    if (object_class_is_abstract(klass)) {
        error_setg(errp, "object type '%s' is abstract", type);
        return;
    }

628 629 630 631 632
    obj = object_new(type);
    if (qdict) {
        for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
            object_property_set(obj, v, e->key, &local_err);
            if (local_err) {
633
                goto out;
634 635 636 637
            }
        }
    }

638
    object_property_add_child(object_get_objects_root(),
639
                              id, obj, &local_err);
640 641 642 643
    if (local_err) {
        goto out;
    }

644 645
    user_creatable_complete(obj, &local_err);
    if (local_err) {
646
        object_property_del(object_get_objects_root(),
647 648 649
                            id, &error_abort);
        goto out;
    }
650 651 652 653
out:
    if (local_err) {
        error_propagate(errp, local_err);
    }
654 655 656
    object_unref(obj);
}

657
void qmp_object_add(QDict *qdict, QObject **ret, Error **errp)
658 659 660 661 662 663 664 665 666 667
{
    const char *type = qdict_get_str(qdict, "qom-type");
    const char *id = qdict_get_str(qdict, "id");
    QObject *props = qdict_get(qdict, "props");
    const QDict *pdict = NULL;
    QmpInputVisitor *qiv;

    if (props) {
        pdict = qobject_to_qdict(props);
        if (!pdict) {
668 669
            error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
            return;
670 671 672 673
        }
    }

    qiv = qmp_input_visitor_new(props);
674
    object_add(type, id, pdict, qmp_input_get_visitor(qiv), errp);
675 676 677
    qmp_input_visitor_cleanup(qiv);
}

678 679 680 681 682
void qmp_object_del(const char *id, Error **errp)
{
    Object *container;
    Object *obj;

683
    container = object_get_objects_root();
684 685 686 687 688
    obj = object_resolve_path_component(container, id);
    if (!obj) {
        error_setg(errp, "object id not found");
        return;
    }
689 690 691 692 693

    if (!user_creatable_can_be_deleted(USER_CREATABLE(obj), errp)) {
        error_setg(errp, "%s is in use, can not be deleted", id);
        return;
    }
694 695
    object_unparent(obj);
}
696 697 698 699 700 701 702 703 704 705

MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp)
{
    MemoryDeviceInfoList *head = NULL;
    MemoryDeviceInfoList **prev = &head;

    qmp_pc_dimm_device_list(qdev_get_machine(), &prev);

    return head;
}
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724

ACPIOSTInfoList *qmp_query_acpi_ospm_status(Error **errp)
{
    bool ambig;
    ACPIOSTInfoList *head = NULL;
    ACPIOSTInfoList **prev = &head;
    Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, &ambig);

    if (obj) {
        AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
        AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj);

        adevc->ospm_status(adev, &prev);
    } else {
        error_setg(errp, "command is not supported, missing ACPI device");
    }

    return head;
}