qemu/qmp.c
<<
>>
Prefs
   1/*
   2 * QEMU Management Protocol
   3 *
   4 * Copyright IBM, Corp. 2011
   5 *
   6 * Authors:
   7 *  Anthony Liguori   <aliguori@us.ibm.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2.  See
  10 * the COPYING file in the top-level directory.
  11 *
  12 * Contributions after 2012-01-13 are licensed under the terms of the
  13 * GNU GPL, version 2 or (at your option) any later version.
  14 */
  15
  16#include "qemu-common.h"
  17#include "sysemu.h"
  18#include "qmp-commands.h"
  19#include "ui/qemu-spice.h"
  20#include "ui/vnc.h"
  21#include "kvm.h"
  22#include "arch_init.h"
  23#include "hw/qdev.h"
  24#include "blockdev.h"
  25#include "qemu/qom-qobject.h"
  26
  27NameInfo *qmp_query_name(Error **errp)
  28{
  29    NameInfo *info = g_malloc0(sizeof(*info));
  30
  31    if (qemu_name) {
  32        info->has_name = true;
  33        info->name = g_strdup(qemu_name);
  34    }
  35
  36    return info;
  37}
  38
  39VersionInfo *qmp_query_version(Error **err)
  40{
  41    VersionInfo *info = g_malloc0(sizeof(*info));
  42    const char *version = QEMU_VERSION;
  43    char *tmp;
  44
  45    info->qemu.major = strtol(version, &tmp, 10);
  46    tmp++;
  47    info->qemu.minor = strtol(tmp, &tmp, 10);
  48    tmp++;
  49    info->qemu.micro = strtol(tmp, &tmp, 10);
  50    info->package = g_strdup(QEMU_PKGVERSION);
  51
  52    return info;
  53}
  54
  55KvmInfo *qmp_query_kvm(Error **errp)
  56{
  57    KvmInfo *info = g_malloc0(sizeof(*info));
  58
  59    info->enabled = kvm_enabled();
  60    info->present = kvm_available();
  61
  62    return info;
  63}
  64
  65UuidInfo *qmp_query_uuid(Error **errp)
  66{
  67    UuidInfo *info = g_malloc0(sizeof(*info));
  68    char uuid[64];
  69
  70    snprintf(uuid, sizeof(uuid), UUID_FMT, qemu_uuid[0], qemu_uuid[1],
  71                   qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5],
  72                   qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9],
  73                   qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13],
  74                   qemu_uuid[14], qemu_uuid[15]);
  75
  76    info->UUID = g_strdup(uuid);
  77    return info;
  78}
  79
  80void qmp_quit(Error **err)
  81{
  82    no_shutdown = 0;
  83    qemu_system_shutdown_request();
  84}
  85
  86void qmp_stop(Error **errp)
  87{
  88    vm_stop(RUN_STATE_PAUSED);
  89}
  90
  91void qmp_system_reset(Error **errp)
  92{
  93    qemu_system_reset_request();
  94}
  95
  96void qmp_system_powerdown(Error **erp)
  97{
  98    qemu_system_powerdown_request();
  99}
 100
 101void qmp_cpu(int64_t index, Error **errp)
 102{
 103    /* Just do nothing */
 104}
 105
 106#ifndef CONFIG_VNC
 107/* If VNC support is enabled, the "true" query-vnc command is
 108   defined in the VNC subsystem */
 109VncInfo *qmp_query_vnc(Error **errp)
 110{
 111    error_set(errp, QERR_FEATURE_DISABLED, "vnc");
 112    return NULL;
 113};
 114#endif
 115
 116#ifndef CONFIG_SPICE
 117/* If SPICE support is enabled, the "true" query-spice command is
 118   defined in the SPICE subsystem. Also note that we use a small
 119   trick to maintain query-spice's original behavior, which is not
 120   to be available in the namespace if SPICE is not compiled in */
 121SpiceInfo *qmp_query_spice(Error **errp)
 122{
 123    error_set(errp, QERR_COMMAND_NOT_FOUND, "query-spice");
 124    return NULL;
 125};
 126#endif
 127
 128static void iostatus_bdrv_it(void *opaque, BlockDriverState *bs)
 129{
 130    bdrv_iostatus_reset(bs);
 131}
 132
 133static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs)
 134{
 135    Error **err = opaque;
 136
 137    if (!error_is_set(err) && bdrv_key_required(bs)) {
 138        error_set(err, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs),
 139                  bdrv_get_encrypted_filename(bs));
 140    }
 141}
 142
 143void qmp_cont(Error **errp)
 144{
 145    Error *local_err = NULL;
 146
 147    if (runstate_check(RUN_STATE_INMIGRATE)) {
 148        error_set(errp, QERR_MIGRATION_EXPECTED);
 149        return;
 150    } else if (runstate_check(RUN_STATE_INTERNAL_ERROR) ||
 151               runstate_check(RUN_STATE_SHUTDOWN)) {
 152        error_set(errp, QERR_RESET_REQUIRED);
 153        return;
 154    } else if (runstate_check(RUN_STATE_SUSPENDED)) {
 155        return;
 156    }
 157
 158    bdrv_iterate(iostatus_bdrv_it, NULL);
 159    bdrv_iterate(encrypted_bdrv_it, &local_err);
 160    if (local_err) {
 161        error_propagate(errp, local_err);
 162        return;
 163    }
 164
 165    vm_start();
 166}
 167
 168void qmp_system_wakeup(Error **errp)
 169{
 170    qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
 171}
 172
 173ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
 174{
 175    Object *obj;
 176    bool ambiguous = false;
 177    ObjectPropertyInfoList *props = NULL;
 178    ObjectProperty *prop;
 179
 180    obj = object_resolve_path(path, &ambiguous);
 181    if (obj == NULL) {
 182        error_set(errp, QERR_DEVICE_NOT_FOUND, path);
 183        return NULL;
 184    }
 185
 186    QTAILQ_FOREACH(prop, &obj->properties, node) {
 187        ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry));
 188
 189        entry->value = g_malloc0(sizeof(ObjectPropertyInfo));
 190        entry->next = props;
 191        props = entry;
 192
 193        entry->value->name = g_strdup(prop->name);
 194        entry->value->type = g_strdup(prop->type);
 195    }
 196
 197    return props;
 198}
 199
 200/* FIXME: teach qapi about how to pass through Visitors */
 201int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret)
 202{
 203    const char *path = qdict_get_str(qdict, "path");
 204    const char *property = qdict_get_str(qdict, "property");
 205    QObject *value = qdict_get(qdict, "value");
 206    Error *local_err = NULL;
 207    Object *obj;
 208
 209    obj = object_resolve_path(path, NULL);
 210    if (!obj) {
 211        error_set(&local_err, QERR_DEVICE_NOT_FOUND, path);
 212        goto out;
 213    }
 214
 215    object_property_set_qobject(obj, value, property, &local_err);
 216
 217out:
 218    if (local_err) {
 219        qerror_report_err(local_err);
 220        error_free(local_err);
 221        return -1;
 222    }
 223
 224    return 0;
 225}
 226
 227int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret)
 228{
 229    const char *path = qdict_get_str(qdict, "path");
 230    const char *property = qdict_get_str(qdict, "property");
 231    Error *local_err = NULL;
 232    Object *obj;
 233
 234    obj = object_resolve_path(path, NULL);
 235    if (!obj) {
 236        error_set(&local_err, QERR_DEVICE_NOT_FOUND, path);
 237        goto out;
 238    }
 239
 240    *ret = object_property_get_qobject(obj, property, &local_err);
 241
 242out:
 243    if (local_err) {
 244        qerror_report_err(local_err);
 245        error_free(local_err);
 246        return -1;
 247    }
 248
 249    return 0;
 250}
 251
 252void qmp_set_password(const char *protocol, const char *password,
 253                      bool has_connected, const char *connected, Error **errp)
 254{
 255    int disconnect_if_connected = 0;
 256    int fail_if_connected = 0;
 257    int rc;
 258
 259    if (has_connected) {
 260        if (strcmp(connected, "fail") == 0) {
 261            fail_if_connected = 1;
 262        } else if (strcmp(connected, "disconnect") == 0) {
 263            disconnect_if_connected = 1;
 264        } else if (strcmp(connected, "keep") == 0) {
 265            /* nothing */
 266        } else {
 267            error_set(errp, QERR_INVALID_PARAMETER, "connected");
 268            return;
 269        }
 270    }
 271
 272    if (strcmp(protocol, "spice") == 0) {
 273        if (!using_spice) {
 274            /* correct one? spice isn't a device ,,, */
 275            error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice");
 276            return;
 277        }
 278        rc = qemu_spice_set_passwd(password, fail_if_connected,
 279                                   disconnect_if_connected);
 280        if (rc != 0) {
 281            error_set(errp, QERR_SET_PASSWD_FAILED);
 282        }
 283        return;
 284    }
 285
 286    if (strcmp(protocol, "vnc") == 0) {
 287        if (fail_if_connected || disconnect_if_connected) {
 288            /* vnc supports "connected=keep" only */
 289            error_set(errp, QERR_INVALID_PARAMETER, "connected");
 290            return;
 291        }
 292        /* Note that setting an empty password will not disable login through
 293         * this interface. */
 294        rc = vnc_display_password(NULL, password);
 295        if (rc < 0) {
 296            error_set(errp, QERR_SET_PASSWD_FAILED);
 297        }
 298        return;
 299    }
 300
 301    error_set(errp, QERR_INVALID_PARAMETER, "protocol");
 302}
 303
 304void qmp_expire_password(const char *protocol, const char *whenstr,
 305                         Error **errp)
 306{
 307    time_t when;
 308    int rc;
 309
 310    if (strcmp(whenstr, "now") == 0) {
 311        when = 0;
 312    } else if (strcmp(whenstr, "never") == 0) {
 313        when = TIME_MAX;
 314    } else if (whenstr[0] == '+') {
 315        when = time(NULL) + strtoull(whenstr+1, NULL, 10);
 316    } else {
 317        when = strtoull(whenstr, NULL, 10);
 318    }
 319
 320    if (strcmp(protocol, "spice") == 0) {
 321        if (!using_spice) {
 322            /* correct one? spice isn't a device ,,, */
 323            error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice");
 324            return;
 325        }
 326        rc = qemu_spice_set_pw_expire(when);
 327        if (rc != 0) {
 328            error_set(errp, QERR_SET_PASSWD_FAILED);
 329        }
 330        return;
 331    }
 332
 333    if (strcmp(protocol, "vnc") == 0) {
 334        rc = vnc_display_pw_expire(NULL, when);
 335        if (rc != 0) {
 336            error_set(errp, QERR_SET_PASSWD_FAILED);
 337        }
 338        return;
 339    }
 340
 341    error_set(errp, QERR_INVALID_PARAMETER, "protocol");
 342}
 343
 344#ifdef CONFIG_VNC
 345void qmp_change_vnc_password(const char *password, Error **errp)
 346{
 347    if (vnc_display_password(NULL, password) < 0) {
 348        error_set(errp, QERR_SET_PASSWD_FAILED);
 349    }
 350}
 351
 352static void qmp_change_vnc_listen(const char *target, Error **err)
 353{
 354    if (vnc_display_open(NULL, target) < 0) {
 355        error_set(err, QERR_VNC_SERVER_FAILED, target);
 356    }
 357}
 358
 359static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
 360                           Error **errp)
 361{
 362    if (strcmp(target, "passwd") == 0 || strcmp(target, "password") == 0) {
 363        if (!has_arg) {
 364            error_set(errp, QERR_MISSING_PARAMETER, "password");
 365        } else {
 366            qmp_change_vnc_password(arg, errp);
 367        }
 368    } else {
 369        qmp_change_vnc_listen(target, errp);
 370    }
 371}
 372#else
 373void qmp_change_vnc_password(const char *password, Error **errp)
 374{
 375    error_set(errp, QERR_FEATURE_DISABLED, "vnc");
 376}
 377static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
 378                           Error **errp)
 379{
 380    error_set(errp, QERR_FEATURE_DISABLED, "vnc");
 381}
 382#endif /* !CONFIG_VNC */
 383
 384void qmp_change(const char *device, const char *target,
 385                bool has_arg, const char *arg, Error **err)
 386{
 387    if (strcmp(device, "vnc") == 0) {
 388        qmp_change_vnc(target, has_arg, arg, err);
 389    } else {
 390        qmp_change_blockdev(device, target, has_arg, arg, err);
 391    }
 392}
 393
 394static void qom_list_types_tramp(ObjectClass *klass, void *data)
 395{
 396    ObjectTypeInfoList *e, **pret = data;
 397    ObjectTypeInfo *info;
 398
 399    info = g_malloc0(sizeof(*info));
 400    info->name = g_strdup(object_class_get_name(klass));
 401
 402    e = g_malloc0(sizeof(*e));
 403    e->value = info;
 404    e->next = *pret;
 405    *pret = e;
 406}
 407
 408ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
 409                                       const char *implements,
 410                                       bool has_abstract,
 411                                       bool abstract,
 412                                       Error **errp)
 413{
 414    ObjectTypeInfoList *ret = NULL;
 415
 416    object_class_foreach(qom_list_types_tramp, implements, abstract, &ret);
 417
 418    return ret;
 419}
 420