Statistics
| Branch: | Revision:

root / qmp.c @ 5eeee3fa

History | View | Annotate | Download (10.8 kB)

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 "qapi/qmp-input-visitor.h"
25
#include "qapi/qmp-output-visitor.h"
26
#include "blockdev.h"
27

    
28
NameInfo *qmp_query_name(Error **errp)
29
{
30
    NameInfo *info = g_malloc0(sizeof(*info));
31

    
32
    if (qemu_name) {
33
        info->has_name = true;
34
        info->name = g_strdup(qemu_name);
35
    }
36

    
37
    return info;
38
}
39

    
40
VersionInfo *qmp_query_version(Error **err)
41
{
42
    VersionInfo *info = g_malloc0(sizeof(*info));
43
    const char *version = QEMU_VERSION;
44
    char *tmp;
45

    
46
    info->qemu.major = strtol(version, &tmp, 10);
47
    tmp++;
48
    info->qemu.minor = strtol(tmp, &tmp, 10);
49
    tmp++;
50
    info->qemu.micro = strtol(tmp, &tmp, 10);
51
    info->package = g_strdup(QEMU_PKGVERSION);
52

    
53
    return info;
54
}
55

    
56
KvmInfo *qmp_query_kvm(Error **errp)
57
{
58
    KvmInfo *info = g_malloc0(sizeof(*info));
59

    
60
    info->enabled = kvm_enabled();
61
    info->present = kvm_available();
62

    
63
    return info;
64
}
65

    
66
UuidInfo *qmp_query_uuid(Error **errp)
67
{
68
    UuidInfo *info = g_malloc0(sizeof(*info));
69
    char uuid[64];
70

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

    
77
    info->UUID = g_strdup(uuid);
78
    return info;
79
}
80

    
81
void qmp_quit(Error **err)
82
{
83
    no_shutdown = 0;
84
    qemu_system_shutdown_request();
85
}
86

    
87
void qmp_stop(Error **errp)
88
{
89
    vm_stop(RUN_STATE_PAUSED);
90
}
91

    
92
void qmp_system_reset(Error **errp)
93
{
94
    qemu_system_reset_request();
95
}
96

    
97
void qmp_system_powerdown(Error **erp)
98
{
99
    qemu_system_powerdown_request();
100
}
101

    
102
void qmp_cpu(int64_t index, Error **errp)
103
{
104
    /* Just do nothing */
105
}
106

    
107
#ifndef CONFIG_VNC
108
/* If VNC support is enabled, the "true" query-vnc command is
109
   defined in the VNC subsystem */
110
VncInfo *qmp_query_vnc(Error **errp)
111
{
112
    error_set(errp, QERR_FEATURE_DISABLED, "vnc");
113
    return NULL;
114
};
115
#endif
116

    
117
#ifndef CONFIG_SPICE
118
/* If SPICE support is enabled, the "true" query-spice command is
119
   defined in the SPICE subsystem. Also note that we use a small
120
   trick to maintain query-spice's original behavior, which is not
121
   to be available in the namespace if SPICE is not compiled in */
122
SpiceInfo *qmp_query_spice(Error **errp)
123
{
124
    error_set(errp, QERR_COMMAND_NOT_FOUND, "query-spice");
125
    return NULL;
126
};
127
#endif
128

    
129
static void iostatus_bdrv_it(void *opaque, BlockDriverState *bs)
130
{
131
    bdrv_iostatus_reset(bs);
132
}
133

    
134
static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs)
135
{
136
    Error **err = opaque;
137

    
138
    if (!error_is_set(err) && bdrv_key_required(bs)) {
139
        error_set(err, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs),
140
                  bdrv_get_encrypted_filename(bs));
141
    }
142
}
143

    
144
void qmp_cont(Error **errp)
145
{
146
    Error *local_err = NULL;
147

    
148
    if (runstate_check(RUN_STATE_INMIGRATE)) {
149
        error_set(errp, QERR_MIGRATION_EXPECTED);
150
        return;
151
    } else if (runstate_check(RUN_STATE_INTERNAL_ERROR) ||
152
               runstate_check(RUN_STATE_SHUTDOWN)) {
153
        error_set(errp, QERR_RESET_REQUIRED);
154
        return;
155
    }
156

    
157
    bdrv_iterate(iostatus_bdrv_it, NULL);
158
    bdrv_iterate(encrypted_bdrv_it, &local_err);
159
    if (local_err) {
160
        error_propagate(errp, local_err);
161
        return;
162
    }
163

    
164
    vm_start();
165
}
166

    
167
DevicePropertyInfoList *qmp_qom_list(const char *path, Error **errp)
168
{
169
    DeviceState *dev;
170
    bool ambiguous = false;
171
    DevicePropertyInfoList *props = NULL;
172
    DeviceProperty *prop;
173

    
174
    dev = qdev_resolve_path(path, &ambiguous);
175
    if (dev == NULL) {
176
        error_set(errp, QERR_DEVICE_NOT_FOUND, path);
177
        return NULL;
178
    }
179

    
180
    QTAILQ_FOREACH(prop, &dev->properties, node) {
181
        DevicePropertyInfoList *entry = g_malloc0(sizeof(*entry));
182

    
183
        entry->value = g_malloc0(sizeof(DevicePropertyInfo));
184
        entry->next = props;
185
        props = entry;
186

    
187
        entry->value->name = g_strdup(prop->name);
188
        entry->value->type = g_strdup(prop->type);
189
    }
190

    
191
    return props;
192
}
193

    
194
/* FIXME: teach qapi about how to pass through Visitors */
195
int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret)
196
{
197
    const char *path = qdict_get_str(qdict, "path");
198
    const char *property = qdict_get_str(qdict, "property");
199
    QObject *value = qdict_get(qdict, "value");
200
    Error *local_err = NULL;
201
    QmpInputVisitor *mi;
202
    DeviceState *dev;
203

    
204
    dev = qdev_resolve_path(path, NULL);
205
    if (!dev) {
206
        error_set(&local_err, QERR_DEVICE_NOT_FOUND, path);
207
        goto out;
208
    }
209

    
210
    mi = qmp_input_visitor_new(value);
211
    qdev_property_set(dev, qmp_input_get_visitor(mi), property, &local_err);
212

    
213
    qmp_input_visitor_cleanup(mi);
214

    
215
out:
216
    if (local_err) {
217
        qerror_report_err(local_err);
218
        error_free(local_err);
219
        return -1;
220
    }
221

    
222
    return 0;
223
}
224

    
225
int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret)
226
{
227
    const char *path = qdict_get_str(qdict, "path");
228
    const char *property = qdict_get_str(qdict, "property");
229
    Error *local_err = NULL;
230
    QmpOutputVisitor *mo;
231
    DeviceState *dev;
232

    
233
    dev = qdev_resolve_path(path, NULL);
234
    if (!dev) {
235
        error_set(&local_err, QERR_DEVICE_NOT_FOUND, path);
236
        goto out;
237
    }
238

    
239
    mo = qmp_output_visitor_new();
240
    qdev_property_get(dev, qmp_output_get_visitor(mo), property, &local_err);
241
    if (!local_err) {
242
        *ret = qmp_output_get_qobject(mo);
243
    }
244

    
245
    qmp_output_visitor_cleanup(mo);
246

    
247
out:
248
    if (local_err) {
249
        qerror_report_err(local_err);
250
        error_free(local_err);
251
        return -1;
252
    }
253

    
254
    return 0;
255
}
256

    
257
void qmp_set_password(const char *protocol, const char *password,
258
                      bool has_connected, const char *connected, Error **errp)
259
{
260
    int disconnect_if_connected = 0;
261
    int fail_if_connected = 0;
262
    int rc;
263

    
264
    if (has_connected) {
265
        if (strcmp(connected, "fail") == 0) {
266
            fail_if_connected = 1;
267
        } else if (strcmp(connected, "disconnect") == 0) {
268
            disconnect_if_connected = 1;
269
        } else if (strcmp(connected, "keep") == 0) {
270
            /* nothing */
271
        } else {
272
            error_set(errp, QERR_INVALID_PARAMETER, "connected");
273
            return;
274
        }
275
    }
276

    
277
    if (strcmp(protocol, "spice") == 0) {
278
        if (!using_spice) {
279
            /* correct one? spice isn't a device ,,, */
280
            error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice");
281
            return;
282
        }
283
        rc = qemu_spice_set_passwd(password, fail_if_connected,
284
                                   disconnect_if_connected);
285
        if (rc != 0) {
286
            error_set(errp, QERR_SET_PASSWD_FAILED);
287
        }
288
        return;
289
    }
290

    
291
    if (strcmp(protocol, "vnc") == 0) {
292
        if (fail_if_connected || disconnect_if_connected) {
293
            /* vnc supports "connected=keep" only */
294
            error_set(errp, QERR_INVALID_PARAMETER, "connected");
295
            return;
296
        }
297
        /* Note that setting an empty password will not disable login through
298
         * this interface. */
299
        rc = vnc_display_password(NULL, password);
300
        if (rc < 0) {
301
            error_set(errp, QERR_SET_PASSWD_FAILED);
302
        }
303
        return;
304
    }
305

    
306
    error_set(errp, QERR_INVALID_PARAMETER, "protocol");
307
}
308

    
309
void qmp_expire_password(const char *protocol, const char *whenstr,
310
                         Error **errp)
311
{
312
    time_t when;
313
    int rc;
314

    
315
    if (strcmp(whenstr, "now") == 0) {
316
        when = 0;
317
    } else if (strcmp(whenstr, "never") == 0) {
318
        when = TIME_MAX;
319
    } else if (whenstr[0] == '+') {
320
        when = time(NULL) + strtoull(whenstr+1, NULL, 10);
321
    } else {
322
        when = strtoull(whenstr, NULL, 10);
323
    }
324

    
325
    if (strcmp(protocol, "spice") == 0) {
326
        if (!using_spice) {
327
            /* correct one? spice isn't a device ,,, */
328
            error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice");
329
            return;
330
        }
331
        rc = qemu_spice_set_pw_expire(when);
332
        if (rc != 0) {
333
            error_set(errp, QERR_SET_PASSWD_FAILED);
334
        }
335
        return;
336
    }
337

    
338
    if (strcmp(protocol, "vnc") == 0) {
339
        rc = vnc_display_pw_expire(NULL, when);
340
        if (rc != 0) {
341
            error_set(errp, QERR_SET_PASSWD_FAILED);
342
        }
343
        return;
344
    }
345

    
346
    error_set(errp, QERR_INVALID_PARAMETER, "protocol");
347
}
348

    
349
#ifdef CONFIG_VNC
350
void qmp_change_vnc_password(const char *password, Error **errp)
351
{
352
    if (vnc_display_password(NULL, password) < 0) {
353
        error_set(errp, QERR_SET_PASSWD_FAILED);
354
    }
355
}
356

    
357
static void qmp_change_vnc_listen(const char *target, Error **err)
358
{
359
    if (vnc_display_open(NULL, target) < 0) {
360
        error_set(err, QERR_VNC_SERVER_FAILED, target);
361
    }
362
}
363

    
364
static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
365
                           Error **errp)
366
{
367
    if (strcmp(target, "passwd") == 0 || strcmp(target, "password") == 0) {
368
        if (!has_arg) {
369
            error_set(errp, QERR_MISSING_PARAMETER, "password");
370
        } else {
371
            qmp_change_vnc_password(arg, errp);
372
        }
373
    } else {
374
        qmp_change_vnc_listen(target, errp);
375
    }
376
}
377
#else
378
void qmp_change_vnc_password(const char *password, Error **errp)
379
{
380
    error_set(errp, QERR_FEATURE_DISABLED, "vnc");
381
}
382
static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
383
                           Error **errp)
384
{
385
    error_set(errp, QERR_FEATURE_DISABLED, "vnc");
386
}
387
#endif /* !CONFIG_VNC */
388

    
389
void qmp_change(const char *device, const char *target,
390
                bool has_arg, const char *arg, Error **err)
391
{
392
    if (strcmp(device, "vnc") == 0) {
393
        qmp_change_vnc(target, has_arg, arg, err);
394
    } else {
395
        qmp_change_blockdev(device, target, has_arg, arg, err);
396
    }
397
}
398

    
399
static void qom_list_types_tramp(ObjectClass *klass, void *data)
400
{
401
    ObjectTypeInfoList *e, **pret = data;
402
    ObjectTypeInfo *info;
403

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

    
407
    e = g_malloc0(sizeof(*e));
408
    e->value = info;
409
    e->next = *pret;
410
    *pret = e;
411
}
412

    
413
ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
414
                                       const char *implements,
415
                                       bool has_abstract,
416
                                       bool abstract,
417
                                       Error **errp)
418
{
419
    ObjectTypeInfoList *ret = NULL;
420

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

    
423
    return ret;
424
}