|
|
1.1 root 1: /*
2: * QEMU Management Protocol
3: *
4: * Copyright IBM, Corp. 2011
5: *
6: * Authors:
7: * Anthony Liguori <[email protected]>
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: *
1.1.1.2 ! root 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.
1.1 root 14: */
15:
16: #include "qemu-common.h"
17: #include "sysemu.h"
18: #include "qmp-commands.h"
1.1.1.2 ! root 19: #include "ui/qemu-spice.h"
! 20: #include "ui/vnc.h"
1.1 root 21: #include "kvm.h"
22: #include "arch_init.h"
1.1.1.2 ! root 23: #include "hw/qdev.h"
! 24: #include "blockdev.h"
! 25: #include "qemu/qom-qobject.h"
1.1 root 26:
27: NameInfo *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:
39: VersionInfo *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:
55: KvmInfo *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:
65: UuidInfo *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:
80: void qmp_quit(Error **err)
81: {
82: no_shutdown = 0;
83: qemu_system_shutdown_request();
84: }
85:
86: void qmp_stop(Error **errp)
87: {
88: vm_stop(RUN_STATE_PAUSED);
89: }
90:
91: void qmp_system_reset(Error **errp)
92: {
93: qemu_system_reset_request();
94: }
95:
96: void qmp_system_powerdown(Error **erp)
97: {
98: qemu_system_powerdown_request();
99: }
100:
101: void 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 */
109: VncInfo *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 */
121: SpiceInfo *qmp_query_spice(Error **errp)
122: {
123: error_set(errp, QERR_COMMAND_NOT_FOUND, "query-spice");
124: return NULL;
125: };
126: #endif
1.1.1.2 ! root 127:
! 128: static void iostatus_bdrv_it(void *opaque, BlockDriverState *bs)
! 129: {
! 130: bdrv_iostatus_reset(bs);
! 131: }
! 132:
! 133: static 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:
! 143: void 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:
! 168: void qmp_system_wakeup(Error **errp)
! 169: {
! 170: qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
! 171: }
! 172:
! 173: ObjectPropertyInfoList *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 */
! 201: int 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:
! 217: out:
! 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:
! 227: int 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:
! 242: out:
! 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:
! 252: void 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:
! 304: void 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
! 345: void 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:
! 352: static 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:
! 359: static 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
! 373: void qmp_change_vnc_password(const char *password, Error **errp)
! 374: {
! 375: error_set(errp, QERR_FEATURE_DISABLED, "vnc");
! 376: }
! 377: static 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:
! 384: void 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:
! 394: static 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:
! 408: ObjectTypeInfoList *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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.