File:  [Qemu by Fabrice Bellard] / qemu / qmp.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:35:04 2018 UTC (3 years, 5 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu1101, HEAD
qemu 1.1.1

    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: 
   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
  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: }

unix.superglobalmegacorp.com