]> git.ipfire.org Git - thirdparty/libvirt.git/blob
53a7de8b77
[thirdparty/libvirt.git] /
1 /*
2 * qemu_monitor_json.c: interaction with QEMU monitor console
3 *
4 * Copyright (C) 2006-2016 Red Hat, Inc.
5 * Copyright (C) 2006 Daniel P. Berrange
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see
19 * <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <poll.h>
28 #include <unistd.h>
29 #include <sys/time.h>
30
31 #include "qemu_monitor_text.h"
32 #include "qemu_monitor_json.h"
33 #include "qemu_alias.h"
34 #include "qemu_parse_command.h"
35 #include "qemu_capabilities.h"
36 #include "viralloc.h"
37 #include "virlog.h"
38 #include "driver.h"
39 #include "datatypes.h"
40 #include "virerror.h"
41 #include "virjson.h"
42 #include "virprobe.h"
43 #include "virstring.h"
44 #include "cpu/cpu_x86.h"
45 #include "c-strcasestr.h"
46 #include "virenum.h"
47
48 #ifdef WITH_DTRACE_PROBES
49 # include "libvirt_qemu_probes.h"
50 #endif
51
52 #define VIR_FROM_THIS VIR_FROM_QEMU
53
54 VIR_LOG_INIT("qemu.qemu_monitor_json");
55
56 #define QOM_CPU_PATH "/machine/unattached/device[0]"
57
58 #define LINE_ENDING "\r\n"
59
60 static void qemuMonitorJSONHandleShutdown(qemuMonitorPtr mon, virJSONValuePtr data);
61 static void qemuMonitorJSONHandleReset(qemuMonitorPtr mon, virJSONValuePtr data);
62 static void qemuMonitorJSONHandlePowerdown(qemuMonitorPtr mon, virJSONValuePtr data);
63 static void qemuMonitorJSONHandleStop(qemuMonitorPtr mon, virJSONValuePtr data);
64 static void qemuMonitorJSONHandleResume(qemuMonitorPtr mon, virJSONValuePtr data);
65 static void qemuMonitorJSONHandleRTCChange(qemuMonitorPtr mon, virJSONValuePtr data);
66 static void qemuMonitorJSONHandleWatchdog(qemuMonitorPtr mon, virJSONValuePtr data);
67 static void qemuMonitorJSONHandleIOError(qemuMonitorPtr mon, virJSONValuePtr data);
68 static void qemuMonitorJSONHandleVNCConnect(qemuMonitorPtr mon, virJSONValuePtr data);
69 static void qemuMonitorJSONHandleVNCInitialize(qemuMonitorPtr mon, virJSONValuePtr data);
70 static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon, virJSONValuePtr data);
71 static void qemuMonitorJSONHandleSPICEConnect(qemuMonitorPtr mon, virJSONValuePtr data);
72 static void qemuMonitorJSONHandleSPICEInitialize(qemuMonitorPtr mon, virJSONValuePtr data);
73 static void qemuMonitorJSONHandleSPICEDisconnect(qemuMonitorPtr mon, virJSONValuePtr data);
74 static void qemuMonitorJSONHandleTrayChange(qemuMonitorPtr mon, virJSONValuePtr data);
75 static void qemuMonitorJSONHandlePMWakeup(qemuMonitorPtr mon, virJSONValuePtr data);
76 static void qemuMonitorJSONHandlePMSuspend(qemuMonitorPtr mon, virJSONValuePtr data);
77 static void qemuMonitorJSONHandleBlockJobCompleted(qemuMonitorPtr mon, virJSONValuePtr data);
78 static void qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon, virJSONValuePtr data);
79 static void qemuMonitorJSONHandleBlockJobReady(qemuMonitorPtr mon, virJSONValuePtr data);
80 static void qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon, virJSONValuePtr data);
81 static void qemuMonitorJSONHandlePMSuspendDisk(qemuMonitorPtr mon, virJSONValuePtr data);
82 static void qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon, virJSONValuePtr data);
83 static void qemuMonitorJSONHandleDeviceDeleted(qemuMonitorPtr mon, virJSONValuePtr data);
84 static void qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitorPtr mon, virJSONValuePtr data);
85 static void qemuMonitorJSONHandleSerialChange(qemuMonitorPtr mon, virJSONValuePtr data);
86 static void qemuMonitorJSONHandleSpiceMigrated(qemuMonitorPtr mon, virJSONValuePtr data);
87 static void qemuMonitorJSONHandleMigrationStatus(qemuMonitorPtr mon, virJSONValuePtr data);
88 static void qemuMonitorJSONHandleMigrationPass(qemuMonitorPtr mon, virJSONValuePtr data);
89 static void qemuMonitorJSONHandleAcpiOstInfo(qemuMonitorPtr mon, virJSONValuePtr data);
90 static void qemuMonitorJSONHandleBlockThreshold(qemuMonitorPtr mon, virJSONValuePtr data);
91 static void qemuMonitorJSONHandleDumpCompleted(qemuMonitorPtr mon, virJSONValuePtr data);
92 static void qemuMonitorJSONHandlePRManagerStatusChanged(qemuMonitorPtr mon, virJSONValuePtr data);
93 static void qemuMonitorJSONHandleRdmaGidStatusChanged(qemuMonitorPtr mon, virJSONValuePtr data);
94
95 typedef struct {
96 const char *type;
97 void (*handler)(qemuMonitorPtr mon, virJSONValuePtr data);
98 } qemuEventHandler;
99
100 static qemuEventHandler eventHandlers[] = {
101 { "ACPI_DEVICE_OST", qemuMonitorJSONHandleAcpiOstInfo, },
102 { "BALLOON_CHANGE", qemuMonitorJSONHandleBalloonChange, },
103 { "BLOCK_IO_ERROR", qemuMonitorJSONHandleIOError, },
104 { "BLOCK_JOB_CANCELLED", qemuMonitorJSONHandleBlockJobCanceled, },
105 { "BLOCK_JOB_COMPLETED", qemuMonitorJSONHandleBlockJobCompleted, },
106 { "BLOCK_JOB_READY", qemuMonitorJSONHandleBlockJobReady, },
107 { "BLOCK_WRITE_THRESHOLD", qemuMonitorJSONHandleBlockThreshold, },
108 { "DEVICE_DELETED", qemuMonitorJSONHandleDeviceDeleted, },
109 { "DEVICE_TRAY_MOVED", qemuMonitorJSONHandleTrayChange, },
110 { "DUMP_COMPLETED", qemuMonitorJSONHandleDumpCompleted, },
111 { "GUEST_PANICKED", qemuMonitorJSONHandleGuestPanic, },
112 { "MIGRATION", qemuMonitorJSONHandleMigrationStatus, },
113 { "MIGRATION_PASS", qemuMonitorJSONHandleMigrationPass, },
114 { "NIC_RX_FILTER_CHANGED", qemuMonitorJSONHandleNicRxFilterChanged, },
115 { "POWERDOWN", qemuMonitorJSONHandlePowerdown, },
116 { "PR_MANAGER_STATUS_CHANGED", qemuMonitorJSONHandlePRManagerStatusChanged, },
117 { "RDMA_GID_STATUS_CHANGED", qemuMonitorJSONHandleRdmaGidStatusChanged, },
118 { "RESET", qemuMonitorJSONHandleReset, },
119 { "RESUME", qemuMonitorJSONHandleResume, },
120 { "RTC_CHANGE", qemuMonitorJSONHandleRTCChange, },
121 { "SHUTDOWN", qemuMonitorJSONHandleShutdown, },
122 { "SPICE_CONNECTED", qemuMonitorJSONHandleSPICEConnect, },
123 { "SPICE_DISCONNECTED", qemuMonitorJSONHandleSPICEDisconnect, },
124 { "SPICE_INITIALIZED", qemuMonitorJSONHandleSPICEInitialize, },
125 { "SPICE_MIGRATE_COMPLETED", qemuMonitorJSONHandleSpiceMigrated, },
126 { "STOP", qemuMonitorJSONHandleStop, },
127 { "SUSPEND", qemuMonitorJSONHandlePMSuspend, },
128 { "SUSPEND_DISK", qemuMonitorJSONHandlePMSuspendDisk, },
129 { "VNC_CONNECTED", qemuMonitorJSONHandleVNCConnect, },
130 { "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },
131 { "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
132 { "VSERPORT_CHANGE", qemuMonitorJSONHandleSerialChange, },
133 { "WAKEUP", qemuMonitorJSONHandlePMWakeup, },
134 { "WATCHDOG", qemuMonitorJSONHandleWatchdog, },
135 /* We use bsearch, so keep this list sorted. */
136 };
137
138 static int
139 qemuMonitorEventCompare(const void *key, const void *elt)
140 {
141 const char *type = key;
142 const qemuEventHandler *handler = elt;
143 return strcmp(type, handler->type);
144 }
145
146 static int
147 qemuMonitorJSONIOProcessEvent(qemuMonitorPtr mon,
148 virJSONValuePtr obj)
149 {
150 const char *type;
151 qemuEventHandler *handler;
152 virJSONValuePtr data;
153 char *details = NULL;
154 virJSONValuePtr timestamp;
155 long long seconds = -1;
156 unsigned int micros = 0;
157
158 VIR_DEBUG("mon=%p obj=%p", mon, obj);
159
160 type = virJSONValueObjectGetString(obj, "event");
161 if (!type) {
162 VIR_WARN("missing event type in message");
163 errno = EINVAL;
164 return -1;
165 }
166
167 /* Not all events have data; and event reporting is best-effort only */
168 if ((data = virJSONValueObjectGet(obj, "data")))
169 details = virJSONValueToString(data, false);
170 if ((timestamp = virJSONValueObjectGet(obj, "timestamp"))) {
171 ignore_value(virJSONValueObjectGetNumberLong(timestamp, "seconds",
172 &seconds));
173 ignore_value(virJSONValueObjectGetNumberUint(timestamp, "microseconds",
174 &micros));
175 }
176 qemuMonitorEmitEvent(mon, type, seconds, micros, details);
177 VIR_FREE(details);
178
179 handler = bsearch(type, eventHandlers, ARRAY_CARDINALITY(eventHandlers),
180 sizeof(eventHandlers[0]), qemuMonitorEventCompare);
181 if (handler) {
182 VIR_DEBUG("handle %s handler=%p data=%p", type,
183 handler->handler, data);
184 (handler->handler)(mon, data);
185 }
186 return 0;
187 }
188
189 int
190 qemuMonitorJSONIOProcessLine(qemuMonitorPtr mon,
191 const char *line,
192 qemuMonitorMessagePtr msg)
193 {
194 virJSONValuePtr obj = NULL;
195 int ret = -1;
196
197 VIR_DEBUG("Line [%s]", line);
198
199 if (!(obj = virJSONValueFromString(line)))
200 goto cleanup;
201
202 if (virJSONValueGetType(obj) != VIR_JSON_TYPE_OBJECT) {
203 virReportError(VIR_ERR_INTERNAL_ERROR,
204 _("Parsed JSON reply '%s' isn't an object"), line);
205 goto cleanup;
206 }
207
208 if (virJSONValueObjectHasKey(obj, "QMP") == 1) {
209 ret = 0;
210 } else if (virJSONValueObjectHasKey(obj, "event") == 1) {
211 PROBE(QEMU_MONITOR_RECV_EVENT,
212 "mon=%p event=%s", mon, line);
213 ret = qemuMonitorJSONIOProcessEvent(mon, obj);
214 } else if (virJSONValueObjectHasKey(obj, "error") == 1 ||
215 virJSONValueObjectHasKey(obj, "return") == 1) {
216 PROBE(QEMU_MONITOR_RECV_REPLY,
217 "mon=%p reply=%s", mon, line);
218 if (msg) {
219 msg->rxObject = obj;
220 msg->finished = 1;
221 obj = NULL;
222 ret = 0;
223 } else {
224 virReportError(VIR_ERR_INTERNAL_ERROR,
225 _("Unexpected JSON reply '%s'"), line);
226 }
227 } else {
228 virReportError(VIR_ERR_INTERNAL_ERROR,
229 _("Unknown JSON reply '%s'"), line);
230 }
231
232 cleanup:
233 virJSONValueFree(obj);
234 return ret;
235 }
236
237 int qemuMonitorJSONIOProcess(qemuMonitorPtr mon,
238 const char *data,
239 size_t len,
240 qemuMonitorMessagePtr msg)
241 {
242 int used = 0;
243 /*VIR_DEBUG("Data %d bytes [%s]", len, data);*/
244
245 while (used < len) {
246 char *nl = strstr(data + used, LINE_ENDING);
247
248 if (nl) {
249 int got = nl - (data + used);
250 char *line;
251 if (VIR_STRNDUP(line, data + used, got) < 0)
252 return -1;
253 used += got + strlen(LINE_ENDING);
254 line[got] = '\0'; /* kill \n */
255 if (qemuMonitorJSONIOProcessLine(mon, line, msg) < 0) {
256 VIR_FREE(line);
257 return -1;
258 }
259
260 VIR_FREE(line);
261 } else {
262 break;
263 }
264 }
265
266 #if DEBUG_IO
267 VIR_DEBUG("Total used %d bytes out of %zd available in buffer", used, len);
268 #endif
269
270 return used;
271 }
272
273 static int
274 qemuMonitorJSONCommandWithFd(qemuMonitorPtr mon,
275 virJSONValuePtr cmd,
276 int scm_fd,
277 virJSONValuePtr *reply)
278 {
279 int ret = -1;
280 qemuMonitorMessage msg;
281 VIR_AUTOCLEAN(virBuffer) cmdbuf = VIR_BUFFER_INITIALIZER;
282 char *id = NULL;
283
284 *reply = NULL;
285
286 memset(&msg, 0, sizeof(msg));
287
288 if (virJSONValueObjectHasKey(cmd, "execute") == 1) {
289 if (!(id = qemuMonitorNextCommandID(mon)))
290 goto cleanup;
291 if (virJSONValueObjectAppendString(cmd, "id", id) < 0) {
292 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
293 _("Unable to append command 'id' string"));
294 goto cleanup;
295 }
296 }
297
298 if (virJSONValueToBuffer(cmd, &cmdbuf, false) < 0)
299 goto cleanup;
300 virBufferAddLit(&cmdbuf, "\r\n");
301
302 if (virBufferCheckError(&cmdbuf) < 0)
303 goto cleanup;
304
305 msg.txLength = virBufferUse(&cmdbuf);
306 msg.txBuffer = virBufferContentAndReset(&cmdbuf);
307 msg.txFD = scm_fd;
308
309 ret = qemuMonitorSend(mon, &msg);
310
311 if (ret == 0) {
312 if (!msg.rxObject) {
313 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
314 _("Missing monitor reply object"));
315 ret = -1;
316 } else {
317 *reply = msg.rxObject;
318 }
319 }
320
321 cleanup:
322 VIR_FREE(id);
323 VIR_FREE(msg.txBuffer);
324
325 return ret;
326 }
327
328
329 static int
330 qemuMonitorJSONCommand(qemuMonitorPtr mon,
331 virJSONValuePtr cmd,
332 virJSONValuePtr *reply)
333 {
334 return qemuMonitorJSONCommandWithFd(mon, cmd, -1, reply);
335 }
336
337 /* Ignoring OOM in this method, since we're already reporting
338 * a more important error
339 *
340 * XXX see qerror.h for different klasses & fill out useful params
341 */
342 static const char *
343 qemuMonitorJSONStringifyError(virJSONValuePtr error)
344 {
345 const char *klass = virJSONValueObjectGetString(error, "class");
346 const char *detail = NULL;
347
348 /* The QMP 'desc' field is usually sufficient for our generic
349 * error reporting needs.
350 */
351 if (klass)
352 detail = virJSONValueObjectGetString(error, "desc");
353
354
355 if (!detail)
356 detail = "unknown QEMU command error";
357
358 return detail;
359 }
360
361 static const char *
362 qemuMonitorJSONCommandName(virJSONValuePtr cmd)
363 {
364 const char *name = virJSONValueObjectGetString(cmd, "execute");
365 if (name)
366 return name;
367 else
368 return "<unknown>";
369 }
370
371 static int
372 qemuMonitorJSONCheckError(virJSONValuePtr cmd,
373 virJSONValuePtr reply)
374 {
375 if (virJSONValueObjectHasKey(reply, "error")) {
376 virJSONValuePtr error = virJSONValueObjectGet(reply, "error");
377 char *cmdstr = virJSONValueToString(cmd, false);
378 char *replystr = virJSONValueToString(reply, false);
379
380 /* Log the full JSON formatted command & error */
381 VIR_DEBUG("unable to execute QEMU command %s: %s",
382 NULLSTR(cmdstr), NULLSTR(replystr));
383
384 /* Only send the user the command name + friendly error */
385 if (!error)
386 virReportError(VIR_ERR_INTERNAL_ERROR,
387 _("unable to execute QEMU command '%s'"),
388 qemuMonitorJSONCommandName(cmd));
389 else
390 virReportError(VIR_ERR_INTERNAL_ERROR,
391 _("unable to execute QEMU command '%s': %s"),
392 qemuMonitorJSONCommandName(cmd),
393 qemuMonitorJSONStringifyError(error));
394
395 VIR_FREE(cmdstr);
396 VIR_FREE(replystr);
397 return -1;
398 } else if (!virJSONValueObjectHasKey(reply, "return")) {
399 char *cmdstr = virJSONValueToString(cmd, false);
400 char *replystr = virJSONValueToString(reply, false);
401
402 VIR_DEBUG("Neither 'return' nor 'error' is set in the JSON reply %s: %s",
403 NULLSTR(cmdstr), NULLSTR(replystr));
404 virReportError(VIR_ERR_INTERNAL_ERROR,
405 _("unable to execute QEMU command '%s'"),
406 qemuMonitorJSONCommandName(cmd));
407 VIR_FREE(cmdstr);
408 VIR_FREE(replystr);
409 return -1;
410 }
411 return 0;
412 }
413
414
415 static int
416 qemuMonitorJSONCheckReply(virJSONValuePtr cmd,
417 virJSONValuePtr reply,
418 virJSONType type)
419 {
420 virJSONValuePtr data;
421
422 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
423 return -1;
424
425 data = virJSONValueObjectGet(reply, "return");
426 if (virJSONValueGetType(data) != type) {
427 char *cmdstr = virJSONValueToString(cmd, false);
428 char *retstr = virJSONValueToString(data, false);
429
430 VIR_DEBUG("Unexpected return type %d (expecting %d) for command %s: %s",
431 virJSONValueGetType(data), type, cmdstr, retstr);
432 virReportError(VIR_ERR_INTERNAL_ERROR,
433 _("unexpected type returned by QEMU command '%s'"),
434 qemuMonitorJSONCommandName(cmd));
435
436 VIR_FREE(cmdstr);
437 VIR_FREE(retstr);
438 return -1;
439 }
440
441 return 0;
442 }
443
444
445 static bool
446 qemuMonitorJSONErrorIsClass(virJSONValuePtr error,
447 const char *klass)
448 {
449 return STREQ_NULLABLE(virJSONValueObjectGetString(error, "class"), klass);
450 }
451
452
453 static bool
454 qemuMonitorJSONHasError(virJSONValuePtr reply,
455 const char *klass)
456 {
457 virJSONValuePtr error;
458
459 if (!(error = virJSONValueObjectGet(reply, "error")))
460 return false;
461
462 return qemuMonitorJSONErrorIsClass(error, klass);
463 }
464
465
466 /**
467 * qemuMonitorJSONTransactionAdd:
468 * @actions: array of actions for the 'transaction' command
469 * @cmdname: command to add to @actions
470 * @...: arguments for @cmdname (see virJSONValueObjectAddVArgs for formatting)
471 *
472 * Add a new command with arguments to the existing ones. The resulting array
473 * is intended to be used as argument for the 'transaction' command.
474 *
475 * Returns 0 on success and -1 on error.
476 */
477 int
478 qemuMonitorJSONTransactionAdd(virJSONValuePtr actions,
479 const char *cmdname,
480 ...)
481 {
482 virJSONValuePtr entry = NULL;
483 virJSONValuePtr data = NULL;
484 va_list args;
485 int ret = -1;
486
487 va_start(args, cmdname);
488
489 if (virJSONValueObjectCreateVArgs(&data, args) < 0)
490 goto cleanup;
491
492 if (virJSONValueObjectCreate(&entry,
493 "s:type", cmdname,
494 "A:data", &data, NULL) < 0)
495 goto cleanup;
496
497 if (virJSONValueArrayAppend(actions, entry) < 0)
498 goto cleanup;
499
500 entry = NULL;
501 ret = 0;
502
503 cleanup:
504 virJSONValueFree(entry);
505 virJSONValueFree(data);
506 va_end(args);
507 return ret;
508 }
509
510
511 /**
512 * qemuMonitorJSONMakeCommandInternal:
513 * @cmdname: QMP command name
514 * @arguments: a JSON object containing command arguments or NULL
515 *
516 * Create a JSON object used on the QMP monitor to call a command.
517 *
518 * Note that @arguments is always consumed and should not be referenced after
519 * the call to this function.
520 */
521 static virJSONValuePtr
522 qemuMonitorJSONMakeCommandInternal(const char *cmdname,
523 virJSONValuePtr arguments)
524 {
525 virJSONValuePtr ret = NULL;
526
527 ignore_value(virJSONValueObjectCreate(&ret,
528 "s:execute", cmdname,
529 "A:arguments", &arguments, NULL));
530
531 virJSONValueFree(arguments);
532 return ret;
533 }
534
535
536 static virJSONValuePtr ATTRIBUTE_SENTINEL
537 qemuMonitorJSONMakeCommand(const char *cmdname,
538 ...)
539 {
540 virJSONValuePtr obj = NULL;
541 virJSONValuePtr jargs = NULL;
542 va_list args;
543
544 va_start(args, cmdname);
545
546 if (virJSONValueObjectCreateVArgs(&jargs, args) < 0)
547 goto cleanup;
548
549 obj = qemuMonitorJSONMakeCommandInternal(cmdname, jargs);
550
551 cleanup:
552 va_end(args);
553
554 return obj;
555 }
556
557
558 static virJSONValuePtr
559 qemuMonitorJSONKeywordStringToJSON(const char *str, const char *firstkeyword)
560 {
561 virJSONValuePtr ret = NULL;
562 char **keywords = NULL;
563 char **values = NULL;
564 int nkeywords = 0;
565 size_t i;
566
567 if (!(ret = virJSONValueNewObject()))
568 return NULL;
569
570 if (qemuParseKeywords(str, &keywords, &values, &nkeywords, 1) < 0)
571 goto error;
572
573 for (i = 0; i < nkeywords; i++) {
574 if (values[i] == NULL) {
575 if (i != 0) {
576 virReportError(VIR_ERR_INTERNAL_ERROR,
577 _("unexpected empty keyword in %s"), str);
578 goto error;
579 } else {
580 /* This 3rd arg isn't a typo - the way the parser works is
581 * that the value ended up in the keyword field */
582 if (virJSONValueObjectAppendString(ret, firstkeyword, keywords[i]) < 0)
583 goto error;
584 }
585 } else {
586 if (virJSONValueObjectAppendString(ret, keywords[i], values[i]) < 0)
587 goto error;
588 }
589 }
590
591 qemuParseKeywordsFree(nkeywords, keywords, values);
592 return ret;
593
594 error:
595 qemuParseKeywordsFree(nkeywords, keywords, values);
596 virJSONValueFree(ret);
597 return NULL;
598 }
599
600
601 static void qemuMonitorJSONHandleShutdown(qemuMonitorPtr mon, virJSONValuePtr data)
602 {
603 bool guest = false;
604 virTristateBool guest_initiated = VIR_TRISTATE_BOOL_ABSENT;
605
606 if (data && virJSONValueObjectGetBoolean(data, "guest", &guest) == 0)
607 guest_initiated = guest ? VIR_TRISTATE_BOOL_YES : VIR_TRISTATE_BOOL_NO;
608
609 qemuMonitorEmitShutdown(mon, guest_initiated);
610 }
611
612 static void qemuMonitorJSONHandleReset(qemuMonitorPtr mon, virJSONValuePtr data ATTRIBUTE_UNUSED)
613 {
614 qemuMonitorEmitReset(mon);
615 }
616
617 static void qemuMonitorJSONHandlePowerdown(qemuMonitorPtr mon, virJSONValuePtr data ATTRIBUTE_UNUSED)
618 {
619 qemuMonitorEmitPowerdown(mon);
620 }
621
622 static void qemuMonitorJSONHandleStop(qemuMonitorPtr mon, virJSONValuePtr data ATTRIBUTE_UNUSED)
623 {
624 qemuMonitorEmitStop(mon);
625 }
626
627 static void qemuMonitorJSONHandleResume(qemuMonitorPtr mon, virJSONValuePtr data ATTRIBUTE_UNUSED)
628 {
629 qemuMonitorEmitResume(mon);
630 }
631
632
633 static qemuMonitorEventPanicInfoPtr
634 qemuMonitorJSONGuestPanicExtractInfoHyperv(virJSONValuePtr data)
635 {
636 qemuMonitorEventPanicInfoPtr ret;
637
638 if (VIR_ALLOC(ret) < 0)
639 return NULL;
640
641 ret->type = QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_HYPERV;
642
643 if (virJSONValueObjectGetNumberUlong(data, "arg1", &ret->data.hyperv.arg1) < 0 ||
644 virJSONValueObjectGetNumberUlong(data, "arg2", &ret->data.hyperv.arg2) < 0 ||
645 virJSONValueObjectGetNumberUlong(data, "arg3", &ret->data.hyperv.arg3) < 0 ||
646 virJSONValueObjectGetNumberUlong(data, "arg4", &ret->data.hyperv.arg4) < 0 ||
647 virJSONValueObjectGetNumberUlong(data, "arg5", &ret->data.hyperv.arg5) < 0) {
648 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
649 _("malformed hyperv panic data"));
650 goto error;
651 }
652
653 return ret;
654
655 error:
656 qemuMonitorEventPanicInfoFree(ret);
657 return NULL;
658 }
659
660 static qemuMonitorEventPanicInfoPtr
661 qemuMonitorJSONGuestPanicExtractInfoS390(virJSONValuePtr data)
662 {
663 qemuMonitorEventPanicInfoPtr ret;
664 int core;
665 unsigned long long psw_mask, psw_addr;
666 const char *reason = NULL;
667
668 if (VIR_ALLOC(ret) < 0)
669 return NULL;
670
671 ret->type = QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_S390;
672
673 if (virJSONValueObjectGetNumberInt(data, "core", &core) < 0 ||
674 virJSONValueObjectGetNumberUlong(data, "psw-mask", &psw_mask) < 0 ||
675 virJSONValueObjectGetNumberUlong(data, "psw-addr", &psw_addr) < 0 ||
676 !(reason = virJSONValueObjectGetString(data, "reason"))) {
677 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("malformed s390 panic data"));
678 goto error;
679 }
680
681 ret->data.s390.core = core;
682 ret->data.s390.psw_mask = psw_mask;
683 ret->data.s390.psw_addr = psw_addr;
684
685 if (VIR_STRDUP(ret->data.s390.reason, reason) < 0)
686 goto error;
687
688 return ret;
689
690 error:
691 qemuMonitorEventPanicInfoFree(ret);
692 return NULL;
693 }
694
695 static qemuMonitorEventPanicInfoPtr
696 qemuMonitorJSONGuestPanicExtractInfo(virJSONValuePtr data)
697 {
698 const char *type = virJSONValueObjectGetString(data, "type");
699
700 if (STREQ_NULLABLE(type, "hyper-v"))
701 return qemuMonitorJSONGuestPanicExtractInfoHyperv(data);
702 else if (STREQ_NULLABLE(type, "s390"))
703 return qemuMonitorJSONGuestPanicExtractInfoS390(data);
704
705 virReportError(VIR_ERR_INTERNAL_ERROR,
706 _("unknown panic info type '%s'"), NULLSTR(type));
707 return NULL;
708 }
709
710
711 static void
712 qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon,
713 virJSONValuePtr data)
714 {
715 virJSONValuePtr infojson = virJSONValueObjectGetObject(data, "info");
716 qemuMonitorEventPanicInfoPtr info = NULL;
717
718 if (infojson)
719 info = qemuMonitorJSONGuestPanicExtractInfo(infojson);
720
721 qemuMonitorEmitGuestPanic(mon, info);
722 }
723
724
725 static void qemuMonitorJSONHandleRTCChange(qemuMonitorPtr mon, virJSONValuePtr data)
726 {
727 long long offset = 0;
728 if (virJSONValueObjectGetNumberLong(data, "offset", &offset) < 0) {
729 VIR_WARN("missing offset in RTC change event");
730 offset = 0;
731 }
732 qemuMonitorEmitRTCChange(mon, offset);
733 }
734
735 VIR_ENUM_DECL(qemuMonitorWatchdogAction);
736 VIR_ENUM_IMPL(qemuMonitorWatchdogAction,
737 VIR_DOMAIN_EVENT_WATCHDOG_LAST,
738 "none", "pause", "reset", "poweroff", "shutdown", "debug", "inject-nmi",
739 );
740
741 static void qemuMonitorJSONHandleWatchdog(qemuMonitorPtr mon, virJSONValuePtr data)
742 {
743 const char *action;
744 int actionID;
745 if (!(action = virJSONValueObjectGetString(data, "action")))
746 VIR_WARN("missing action in watchdog event");
747 if (action) {
748 if ((actionID = qemuMonitorWatchdogActionTypeFromString(action)) < 0) {
749 VIR_WARN("unknown action %s in watchdog event", action);
750 actionID = VIR_DOMAIN_EVENT_WATCHDOG_NONE;
751 }
752 } else {
753 actionID = VIR_DOMAIN_EVENT_WATCHDOG_NONE;
754 }
755 qemuMonitorEmitWatchdog(mon, actionID);
756 }
757
758 VIR_ENUM_DECL(qemuMonitorIOErrorAction);
759 VIR_ENUM_IMPL(qemuMonitorIOErrorAction,
760 VIR_DOMAIN_EVENT_IO_ERROR_LAST,
761 "ignore", "stop", "report",
762 );
763
764
765 static void
766 qemuMonitorJSONHandleIOError(qemuMonitorPtr mon, virJSONValuePtr data)
767 {
768 const char *device;
769 const char *nodename;
770 const char *action;
771 const char *reason = "";
772 bool nospc = false;
773 int actionID;
774
775 /* Throughout here we try our best to carry on upon errors,
776 since it's important to get as much info as possible out
777 to the application */
778
779 if ((action = virJSONValueObjectGetString(data, "action")) == NULL) {
780 VIR_WARN("Missing action in disk io error event");
781 action = "ignore";
782 }
783
784 if ((device = virJSONValueObjectGetString(data, "device")) == NULL)
785 VIR_WARN("missing device in disk io error event");
786
787 nodename = virJSONValueObjectGetString(data, "node-name");
788
789 if (virJSONValueObjectGetBoolean(data, "nospace", &nospc) == 0 && nospc)
790 reason = "enospc";
791
792 if ((actionID = qemuMonitorIOErrorActionTypeFromString(action)) < 0) {
793 VIR_WARN("unknown disk io error action '%s'", action);
794 actionID = VIR_DOMAIN_EVENT_IO_ERROR_NONE;
795 }
796
797 qemuMonitorEmitIOError(mon, device, nodename, actionID, reason);
798 }
799
800
801 VIR_ENUM_DECL(qemuMonitorGraphicsAddressFamily);
802 VIR_ENUM_IMPL(qemuMonitorGraphicsAddressFamily,
803 VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_LAST,
804 "ipv4", "ipv6", "unix",
805 );
806
807 static void
808 qemuMonitorJSONHandleGraphicsVNC(qemuMonitorPtr mon,
809 virJSONValuePtr data,
810 int phase)
811 {
812 const char *localNode, *localService, *localFamily;
813 const char *remoteNode, *remoteService, *remoteFamily;
814 const char *authScheme, *saslUsername, *x509dname;
815 int localFamilyID, remoteFamilyID;
816 virJSONValuePtr client;
817 virJSONValuePtr server;
818
819 if (!(client = virJSONValueObjectGetObject(data, "client"))) {
820 VIR_WARN("missing client info in VNC event");
821 return;
822 }
823 if (!(server = virJSONValueObjectGetObject(data, "server"))) {
824 VIR_WARN("missing server info in VNC event");
825 return;
826 }
827
828 if (!(authScheme = virJSONValueObjectGetString(server, "auth"))) {
829 /* not all events are required to contain auth scheme */
830 VIR_DEBUG("missing auth scheme in VNC event");
831 authScheme = "";
832 }
833
834 if (!(localFamily = virJSONValueObjectGetString(server, "family"))) {
835 VIR_WARN("missing local address family in VNC event");
836 return;
837 }
838 if (!(localNode = virJSONValueObjectGetString(server, "host"))) {
839 VIR_WARN("missing local hostname in VNC event");
840 return;
841 }
842 if (!(localService = virJSONValueObjectGetString(server, "service"))) {
843 VIR_WARN("missing local service in VNC event");
844 return;
845 }
846
847 if (!(remoteFamily = virJSONValueObjectGetString(client, "family"))) {
848 VIR_WARN("missing remote address family in VNC event");
849 return;
850 }
851 if (!(remoteNode = virJSONValueObjectGetString(client, "host"))) {
852 VIR_WARN("missing remote hostname in VNC event");
853 return;
854 }
855 if (!(remoteService = virJSONValueObjectGetString(client, "service"))) {
856 VIR_WARN("missing remote service in VNC event");
857 return;
858 }
859
860 saslUsername = virJSONValueObjectGetString(client, "sasl_username");
861 x509dname = virJSONValueObjectGetString(client, "x509_dname");
862
863 if ((localFamilyID = qemuMonitorGraphicsAddressFamilyTypeFromString(localFamily)) < 0) {
864 VIR_WARN("unknown address family '%s'", localFamily);
865 localFamilyID = VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4;
866 }
867 if ((remoteFamilyID = qemuMonitorGraphicsAddressFamilyTypeFromString(remoteFamily)) < 0) {
868 VIR_WARN("unknown address family '%s'", remoteFamily);
869 remoteFamilyID = VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4;
870 }
871
872 qemuMonitorEmitGraphics(mon, phase,
873 localFamilyID, localNode, localService,
874 remoteFamilyID, remoteNode, remoteService,
875 authScheme, x509dname, saslUsername);
876 }
877
878 static void qemuMonitorJSONHandleVNCConnect(qemuMonitorPtr mon, virJSONValuePtr data)
879 {
880 qemuMonitorJSONHandleGraphicsVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_CONNECT);
881 }
882
883
884 static void qemuMonitorJSONHandleVNCInitialize(qemuMonitorPtr mon, virJSONValuePtr data)
885 {
886 qemuMonitorJSONHandleGraphicsVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE);
887 }
888
889
890 static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon, virJSONValuePtr data)
891 {
892 qemuMonitorJSONHandleGraphicsVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT);
893 }
894
895
896 static void
897 qemuMonitorJSONHandleGraphicsSPICE(qemuMonitorPtr mon,
898 virJSONValuePtr data,
899 int phase)
900 {
901 const char *lhost, *lport, *lfamily;
902 const char *rhost, *rport, *rfamily;
903 const char *auth = "";
904 int lfamilyID, rfamilyID;
905 virJSONValuePtr client;
906 virJSONValuePtr server;
907
908 if (!(client = virJSONValueObjectGetObject(data, "client")) ||
909 !(server = virJSONValueObjectGetObject(data, "server"))) {
910 VIR_WARN("missing server or client info in SPICE event");
911 return;
912 }
913
914 if (phase == VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE &&
915 !(auth = virJSONValueObjectGetString(server, "auth"))) {
916 VIR_DEBUG("missing auth scheme in SPICE event");
917 auth = "";
918 }
919
920 if (!(lfamily = virJSONValueObjectGetString(server, "family"))) {
921 VIR_WARN("missing local address family in SPICE event");
922 return;
923 }
924 if (!(lhost = virJSONValueObjectGetString(server, "host"))) {
925 VIR_WARN("missing local hostname in SPICE event");
926 return;
927 }
928 if (!(lport = virJSONValueObjectGetString(server, "port"))) {
929 VIR_WARN("missing local port in SPICE event");
930 return;
931 }
932
933 if (!(rfamily = virJSONValueObjectGetString(client, "family"))) {
934 VIR_WARN("missing remote address family in SPICE event");
935 return;
936 }
937 if (!(rhost = virJSONValueObjectGetString(client, "host"))) {
938 VIR_WARN("missing remote hostname in SPICE event");
939 return;
940 }
941 if (!(rport = virJSONValueObjectGetString(client, "port"))) {
942 VIR_WARN("missing remote service in SPICE event");
943 return;
944 }
945
946 if ((lfamilyID = qemuMonitorGraphicsAddressFamilyTypeFromString(lfamily)) < 0) {
947 VIR_WARN("unknown address family '%s'", lfamily);
948 lfamilyID = VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4;
949 }
950 if ((rfamilyID = qemuMonitorGraphicsAddressFamilyTypeFromString(rfamily)) < 0) {
951 VIR_WARN("unknown address family '%s'", rfamily);
952 rfamilyID = VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4;
953 }
954
955 qemuMonitorEmitGraphics(mon, phase, lfamilyID, lhost, lport, rfamilyID,
956 rhost, rport, auth, NULL, NULL);
957 }
958
959
960 static void qemuMonitorJSONHandleSPICEConnect(qemuMonitorPtr mon, virJSONValuePtr data)
961 {
962 qemuMonitorJSONHandleGraphicsSPICE(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_CONNECT);
963 }
964
965
966 static void qemuMonitorJSONHandleSPICEInitialize(qemuMonitorPtr mon, virJSONValuePtr data)
967 {
968 qemuMonitorJSONHandleGraphicsSPICE(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE);
969 }
970
971
972 static void qemuMonitorJSONHandleSPICEDisconnect(qemuMonitorPtr mon, virJSONValuePtr data)
973 {
974 qemuMonitorJSONHandleGraphicsSPICE(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT);
975 }
976
977 static void
978 qemuMonitorJSONHandleBlockJobImpl(qemuMonitorPtr mon,
979 virJSONValuePtr data,
980 int event)
981 {
982 const char *device;
983 const char *type_str;
984 const char *error = NULL;
985 int type = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
986 unsigned long long offset, len;
987
988 if ((device = virJSONValueObjectGetString(data, "device")) == NULL) {
989 VIR_WARN("missing device in block job event");
990 goto out;
991 }
992
993 if (virJSONValueObjectGetNumberUlong(data, "offset", &offset) < 0) {
994 VIR_WARN("missing offset in block job event");
995 goto out;
996 }
997
998 if (virJSONValueObjectGetNumberUlong(data, "len", &len) < 0) {
999 VIR_WARN("missing len in block job event");
1000 goto out;
1001 }
1002
1003 if ((type_str = virJSONValueObjectGetString(data, "type")) == NULL) {
1004 VIR_WARN("missing type in block job event");
1005 goto out;
1006 }
1007
1008 if (STREQ(type_str, "stream"))
1009 type = VIR_DOMAIN_BLOCK_JOB_TYPE_PULL;
1010 else if (STREQ(type_str, "commit"))
1011 type = VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT;
1012 else if (STREQ(type_str, "mirror"))
1013 type = VIR_DOMAIN_BLOCK_JOB_TYPE_COPY;
1014
1015 switch ((virConnectDomainEventBlockJobStatus) event) {
1016 case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
1017 error = virJSONValueObjectGetString(data, "error");
1018 /* Make sure the whole device has been processed */
1019 if (offset != len || error)
1020 event = VIR_DOMAIN_BLOCK_JOB_FAILED;
1021 break;
1022 case VIR_DOMAIN_BLOCK_JOB_CANCELED:
1023 case VIR_DOMAIN_BLOCK_JOB_READY:
1024 break;
1025 case VIR_DOMAIN_BLOCK_JOB_FAILED:
1026 case VIR_DOMAIN_BLOCK_JOB_LAST:
1027 VIR_DEBUG("should not get here");
1028 break;
1029 }
1030
1031 out:
1032 qemuMonitorEmitBlockJob(mon, device, type, event, error);
1033 }
1034
1035 static void
1036 qemuMonitorJSONHandleTrayChange(qemuMonitorPtr mon,
1037 virJSONValuePtr data)
1038 {
1039 const char *devAlias = virJSONValueObjectGetString(data, "device");
1040 const char *devid = virJSONValueObjectGetString(data, "id");
1041 bool trayOpened;
1042 int reason;
1043
1044 /* drive alias is always reported but empty for -blockdev */
1045 if (*devAlias == '\0')
1046 devAlias = NULL;
1047
1048 if (!devAlias && !devid) {
1049 VIR_WARN("missing device in tray change event");
1050 return;
1051 }
1052
1053 if (virJSONValueObjectGetBoolean(data, "tray-open", &trayOpened) < 0) {
1054 VIR_WARN("missing tray-open in tray change event");
1055 return;
1056 }
1057
1058 if (trayOpened)
1059 reason = VIR_DOMAIN_EVENT_TRAY_CHANGE_OPEN;
1060 else
1061 reason = VIR_DOMAIN_EVENT_TRAY_CHANGE_CLOSE;
1062
1063 qemuMonitorEmitTrayChange(mon, devAlias, devid, reason);
1064 }
1065
1066 static void
1067 qemuMonitorJSONHandlePMWakeup(qemuMonitorPtr mon,
1068 virJSONValuePtr data ATTRIBUTE_UNUSED)
1069 {
1070 qemuMonitorEmitPMWakeup(mon);
1071 }
1072
1073 static void
1074 qemuMonitorJSONHandlePMSuspend(qemuMonitorPtr mon,
1075 virJSONValuePtr data ATTRIBUTE_UNUSED)
1076 {
1077 qemuMonitorEmitPMSuspend(mon);
1078 }
1079
1080 static void
1081 qemuMonitorJSONHandleBlockJobCompleted(qemuMonitorPtr mon,
1082 virJSONValuePtr data)
1083 {
1084 qemuMonitorJSONHandleBlockJobImpl(mon, data,
1085 VIR_DOMAIN_BLOCK_JOB_COMPLETED);
1086 }
1087
1088 static void
1089 qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon,
1090 virJSONValuePtr data)
1091 {
1092 qemuMonitorJSONHandleBlockJobImpl(mon, data,
1093 VIR_DOMAIN_BLOCK_JOB_CANCELED);
1094 }
1095
1096 static void
1097 qemuMonitorJSONHandleBlockJobReady(qemuMonitorPtr mon,
1098 virJSONValuePtr data)
1099 {
1100 qemuMonitorJSONHandleBlockJobImpl(mon, data,
1101 VIR_DOMAIN_BLOCK_JOB_READY);
1102 }
1103
1104 static void
1105 qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon,
1106 virJSONValuePtr data)
1107 {
1108 unsigned long long actual = 0;
1109 if (virJSONValueObjectGetNumberUlong(data, "actual", &actual) < 0) {
1110 VIR_WARN("missing actual in balloon change event");
1111 return;
1112 }
1113 actual = VIR_DIV_UP(actual, 1024);
1114 qemuMonitorEmitBalloonChange(mon, actual);
1115 }
1116
1117 static void
1118 qemuMonitorJSONHandlePMSuspendDisk(qemuMonitorPtr mon,
1119 virJSONValuePtr data ATTRIBUTE_UNUSED)
1120 {
1121 qemuMonitorEmitPMSuspendDisk(mon);
1122 }
1123
1124 static void
1125 qemuMonitorJSONHandleDeviceDeleted(qemuMonitorPtr mon, virJSONValuePtr data)
1126 {
1127 const char *device;
1128
1129 if (!(device = virJSONValueObjectGetString(data, "device"))) {
1130 VIR_DEBUG("missing device in device deleted event");
1131 return;
1132 }
1133
1134 qemuMonitorEmitDeviceDeleted(mon, device);
1135 }
1136
1137
1138 static void
1139 qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitorPtr mon, virJSONValuePtr data)
1140 {
1141 const char *name;
1142
1143 if (!(name = virJSONValueObjectGetString(data, "name"))) {
1144 VIR_WARN("missing device in NIC_RX_FILTER_CHANGED event");
1145 return;
1146 }
1147
1148 qemuMonitorEmitNicRxFilterChanged(mon, name);
1149 }
1150
1151
1152 static void
1153 qemuMonitorJSONHandleSerialChange(qemuMonitorPtr mon,
1154 virJSONValuePtr data)
1155 {
1156 const char *name;
1157 bool connected;
1158
1159 if (!(name = virJSONValueObjectGetString(data, "id"))) {
1160 VIR_WARN("missing device alias in VSERPORT_CHANGE event");
1161 return;
1162 }
1163
1164 if (virJSONValueObjectGetBoolean(data, "open", &connected) < 0) {
1165 VIR_WARN("missing port state for '%s' in VSERPORT_CHANGE event", name);
1166 return;
1167 }
1168
1169 qemuMonitorEmitSerialChange(mon, name, connected);
1170 }
1171
1172
1173 static void
1174 qemuMonitorJSONHandleSpiceMigrated(qemuMonitorPtr mon,
1175 virJSONValuePtr data ATTRIBUTE_UNUSED)
1176 {
1177 qemuMonitorEmitSpiceMigrated(mon);
1178 }
1179
1180
1181 static void
1182 qemuMonitorJSONHandleMigrationStatus(qemuMonitorPtr mon,
1183 virJSONValuePtr data)
1184 {
1185 const char *str;
1186 int status;
1187
1188 if (!(str = virJSONValueObjectGetString(data, "status"))) {
1189 VIR_WARN("missing status in migration event");
1190 return;
1191 }
1192
1193 if ((status = qemuMonitorMigrationStatusTypeFromString(str)) == -1) {
1194 VIR_WARN("unknown status '%s' in migration event", str);
1195 return;
1196 }
1197
1198 qemuMonitorEmitMigrationStatus(mon, status);
1199 }
1200
1201
1202 static void
1203 qemuMonitorJSONHandleMigrationPass(qemuMonitorPtr mon,
1204 virJSONValuePtr data)
1205 {
1206 int pass;
1207
1208 if (virJSONValueObjectGetNumberInt(data, "pass", &pass) < 0) {
1209 VIR_WARN("missing dirty-sync-count in migration-pass event");
1210 return;
1211 }
1212
1213 qemuMonitorEmitMigrationPass(mon, pass);
1214 }
1215
1216
1217 static void
1218 qemuMonitorJSONHandleAcpiOstInfo(qemuMonitorPtr mon, virJSONValuePtr data)
1219 {
1220 virJSONValuePtr info;
1221 const char *alias;
1222 const char *slotType;
1223 const char *slot;
1224 unsigned int source;
1225 unsigned int status;
1226
1227 if (!(info = virJSONValueObjectGetObject(data, "info")))
1228 goto error;
1229
1230 /* optional */
1231 alias = virJSONValueObjectGetString(info, "device");
1232
1233 if (!(slotType = virJSONValueObjectGetString(info, "slot-type")))
1234 goto error;
1235
1236 if (!(slot = virJSONValueObjectGetString(info, "slot")))
1237 goto error;
1238
1239 if (virJSONValueObjectGetNumberUint(info, "source", &source) < 0)
1240 goto error;
1241
1242 if (virJSONValueObjectGetNumberUint(info, "status", &status) < 0)
1243 goto error;
1244
1245 qemuMonitorEmitAcpiOstInfo(mon, alias, slotType, slot, source, status);
1246 return;
1247
1248 error:
1249 VIR_WARN("malformed ACPI_DEVICE_OST event");
1250 return;
1251 }
1252
1253
1254 static void
1255 qemuMonitorJSONHandleBlockThreshold(qemuMonitorPtr mon, virJSONValuePtr data)
1256 {
1257 const char *nodename;
1258 unsigned long long threshold;
1259 unsigned long long excess;
1260
1261 if (!(nodename = virJSONValueObjectGetString(data, "node-name")))
1262 goto error;
1263
1264 if (virJSONValueObjectGetNumberUlong(data, "write-threshold", &threshold) < 0)
1265 goto error;
1266
1267 if (virJSONValueObjectGetNumberUlong(data, "amount-exceeded", &excess) < 0)
1268 goto error;
1269
1270 qemuMonitorEmitBlockThreshold(mon, nodename, threshold, excess);
1271 return;
1272
1273 error:
1274 VIR_WARN("malformed 'BLOCK_WRITE_THRESHOLD' event");
1275 }
1276
1277
1278 static int
1279 qemuMonitorJSONExtractDumpStats(virJSONValuePtr result,
1280 qemuMonitorDumpStatsPtr ret)
1281 {
1282 const char *statusstr;
1283
1284 if (!(statusstr = virJSONValueObjectGetString(result, "status"))) {
1285 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1286 _("incomplete result, failed to get status"));
1287 return -1;
1288 }
1289
1290 ret->status = qemuMonitorDumpStatusTypeFromString(statusstr);
1291 if (ret->status < 0) {
1292 virReportError(VIR_ERR_INTERNAL_ERROR,
1293 _("incomplete result, unknown status string '%s'"),
1294 statusstr);
1295 return -1;
1296 }
1297
1298 if (virJSONValueObjectGetNumberUlong(result, "completed", &ret->completed) < 0) {
1299 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1300 _("incomplete result, failed to get completed"));
1301 return -1;
1302 }
1303
1304 if (virJSONValueObjectGetNumberUlong(result, "total", &ret->total) < 0) {
1305 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1306 _("incomplete result, failed to get total"));
1307 return -1;
1308 }
1309
1310 return 0;
1311 }
1312
1313
1314 static void
1315 qemuMonitorJSONHandleDumpCompleted(qemuMonitorPtr mon,
1316 virJSONValuePtr data)
1317 {
1318 virJSONValuePtr result;
1319 int status;
1320 qemuMonitorDumpStats stats = { 0 };
1321 const char *error = NULL;
1322
1323 if (!(result = virJSONValueObjectGetObject(data, "result"))) {
1324 VIR_WARN("missing result in dump completed event");
1325 return;
1326 }
1327
1328 status = qemuMonitorJSONExtractDumpStats(result, &stats);
1329
1330 error = virJSONValueObjectGetString(data, "error");
1331
1332 qemuMonitorEmitDumpCompleted(mon, status, &stats, error);
1333 }
1334
1335
1336 static void qemuMonitorJSONHandlePRManagerStatusChanged(qemuMonitorPtr mon,
1337 virJSONValuePtr data)
1338 {
1339 const char *name;
1340 bool connected;
1341
1342 if (!(name = virJSONValueObjectGetString(data, "id"))) {
1343 VIR_WARN("missing pr-manager alias in PR_MANAGER_STATUS_CHANGED event");
1344 return;
1345 }
1346
1347 if (virJSONValueObjectGetBoolean(data, "connected", &connected) < 0) {
1348 VIR_WARN("missing connected state for %s "
1349 "in PR_MANAGER_STATUS_CHANGED event", name);
1350 return;
1351 }
1352
1353 qemuMonitorEmitPRManagerStatusChanged(mon, name, connected);
1354 }
1355
1356
1357 static void qemuMonitorJSONHandleRdmaGidStatusChanged(qemuMonitorPtr mon,
1358 virJSONValuePtr data)
1359 {
1360 const char *netdev;
1361 bool gid_status;
1362 unsigned long long subnet_prefix, interface_id;
1363
1364 if (!(netdev = virJSONValueObjectGetString(data, "netdev"))) {
1365 VIR_WARN("missing netdev in GID_STATUS_CHANGED event");
1366 return;
1367 }
1368
1369 if (virJSONValueObjectGetBoolean(data, "gid-status", &gid_status)) {
1370 VIR_WARN("missing gid-status in GID_STATUS_CHANGED event");
1371 return;
1372 }
1373
1374 if (virJSONValueObjectGetNumberUlong(data, "subnet-prefix",
1375 &subnet_prefix)) {
1376 VIR_WARN("missing subnet-prefix in GID_STATUS_CHANGED event");
1377 return;
1378 }
1379
1380 if (virJSONValueObjectGetNumberUlong(data, "interface-id",
1381 &interface_id)) {
1382 VIR_WARN("missing interface-id in GID_STATUS_CHANGED event");
1383 return;
1384 }
1385
1386 qemuMonitorEmitRdmaGidStatusChanged(mon, netdev, gid_status, subnet_prefix,
1387 interface_id);
1388 }
1389
1390
1391 int
1392 qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
1393 const char *cmd_str,
1394 int scm_fd,
1395 char **reply_str)
1396 {
1397 virJSONValuePtr cmd = NULL;
1398 virJSONValuePtr reply = NULL;
1399 virJSONValuePtr obj;
1400 int ret = -1;
1401
1402 cmd = qemuMonitorJSONMakeCommand("human-monitor-command",
1403 "s:command-line", cmd_str,
1404 NULL);
1405
1406 if (!cmd || qemuMonitorJSONCommandWithFd(mon, cmd, scm_fd, &reply) < 0)
1407 goto cleanup;
1408
1409 if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
1410 virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
1411 _("Human monitor command is not available to run %s"),
1412 cmd_str);
1413 goto cleanup;
1414 }
1415
1416 if (qemuMonitorJSONCheckError(cmd, reply))
1417 goto cleanup;
1418
1419 obj = virJSONValueObjectGet(reply, "return");
1420
1421 if (reply_str) {
1422 const char *data;
1423
1424 data = virJSONValueGetString(obj);
1425 if (VIR_STRDUP(*reply_str, NULLSTR_EMPTY(data)) < 0)
1426 goto cleanup;
1427 }
1428
1429 ret = 0;
1430
1431 cleanup:
1432 virJSONValueFree(cmd);
1433 virJSONValueFree(reply);
1434 return ret;
1435 }
1436
1437
1438 int
1439 qemuMonitorJSONSetCapabilities(qemuMonitorPtr mon)
1440 {
1441 int ret = -1;
1442 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("qmp_capabilities", NULL);
1443 virJSONValuePtr reply = NULL;
1444 if (!cmd)
1445 return -1;
1446
1447 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
1448 goto cleanup;
1449
1450 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
1451 goto cleanup;
1452
1453 ret = 0;
1454 cleanup:
1455 virJSONValueFree(cmd);
1456 virJSONValueFree(reply);
1457 return ret;
1458 }
1459
1460
1461 int
1462 qemuMonitorJSONStartCPUs(qemuMonitorPtr mon)
1463 {
1464 int ret;
1465 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("cont", NULL);
1466 virJSONValuePtr reply = NULL;
1467 size_t i = 0;
1468 int timeout = 3;
1469 if (!cmd)
1470 return -1;
1471
1472 do {
1473 ret = qemuMonitorJSONCommand(mon, cmd, &reply);
1474
1475 if (ret != 0)
1476 break;
1477
1478 /* If no error, we're done */
1479 if ((ret = qemuMonitorJSONCheckError(cmd, reply)) == 0)
1480 break;
1481
1482 /* If error class is not MigrationExpected, we're done.
1483 * Otherwise try 'cont' cmd again */
1484 if (!qemuMonitorJSONHasError(reply, "MigrationExpected"))
1485 break;
1486
1487 virJSONValueFree(reply);
1488 reply = NULL;
1489 usleep(250000);
1490 } while (++i <= timeout);
1491
1492 virJSONValueFree(cmd);
1493 virJSONValueFree(reply);
1494 return ret;
1495 }
1496
1497
1498 int
1499 qemuMonitorJSONStopCPUs(qemuMonitorPtr mon)
1500 {
1501 int ret = -1;
1502 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("stop", NULL);
1503 virJSONValuePtr reply = NULL;
1504 if (!cmd)
1505 return -1;
1506
1507 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
1508 goto cleanup;
1509
1510 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
1511 goto cleanup;
1512
1513 ret = 0;
1514 cleanup:
1515 virJSONValueFree(cmd);
1516 virJSONValueFree(reply);
1517 return ret;
1518 }
1519
1520
1521 int
1522 qemuMonitorJSONGetStatus(qemuMonitorPtr mon,
1523 bool *running,
1524 virDomainPausedReason *reason)
1525 {
1526 int ret = -1;
1527 const char *status;
1528 virJSONValuePtr cmd;
1529 virJSONValuePtr reply = NULL;
1530 virJSONValuePtr data;
1531
1532 if (reason)
1533 *reason = VIR_DOMAIN_PAUSED_UNKNOWN;
1534
1535 if (!(cmd = qemuMonitorJSONMakeCommand("query-status", NULL)))
1536 return -1;
1537
1538 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
1539 goto cleanup;
1540
1541 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
1542 goto cleanup;
1543
1544 data = virJSONValueObjectGetObject(reply, "return");
1545
1546 if (virJSONValueObjectGetBoolean(data, "running", running) < 0) {
1547 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1548 _("query-status reply was missing running state"));
1549 goto cleanup;
1550 }
1551
1552 if ((status = virJSONValueObjectGetString(data, "status"))) {
1553 if (!*running && reason)
1554 *reason = qemuMonitorVMStatusToPausedReason(status);
1555 } else if (!*running) {
1556 VIR_DEBUG("query-status reply was missing status details");
1557 }
1558
1559 ret = 0;
1560
1561 cleanup:
1562 virJSONValueFree(cmd);
1563 virJSONValueFree(reply);
1564 return ret;
1565 }
1566
1567
1568 int qemuMonitorJSONSystemPowerdown(qemuMonitorPtr mon)
1569 {
1570 int ret = -1;
1571 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("system_powerdown", NULL);
1572 virJSONValuePtr reply = NULL;
1573 if (!cmd)
1574 return -1;
1575
1576 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
1577 goto cleanup;
1578
1579 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
1580 goto cleanup;
1581
1582 ret = 0;
1583 cleanup:
1584 virJSONValueFree(cmd);
1585 virJSONValueFree(reply);
1586 return ret;
1587 }
1588
1589 int qemuMonitorJSONSetLink(qemuMonitorPtr mon,
1590 const char *name,
1591 virDomainNetInterfaceLinkState state)
1592 {
1593 int ret = -1;
1594 virJSONValuePtr reply = NULL;
1595 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("set_link",
1596 "s:name", name,
1597 "b:up", state != VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN,
1598 NULL);
1599
1600 if (!cmd)
1601 return -1;
1602
1603 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
1604 goto cleanup;
1605
1606 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
1607 goto cleanup;
1608
1609 ret = 0;
1610 cleanup:
1611 virJSONValueFree(cmd);
1612 virJSONValueFree(reply);
1613 return ret;
1614 }
1615
1616 int qemuMonitorJSONSystemReset(qemuMonitorPtr mon)
1617 {
1618 int ret = -1;
1619 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("system_reset", NULL);
1620 virJSONValuePtr reply = NULL;
1621 if (!cmd)
1622 return -1;
1623
1624 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
1625 goto cleanup;
1626
1627 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
1628 goto cleanup;
1629
1630 ret = 0;
1631 cleanup:
1632 virJSONValueFree(cmd);
1633 virJSONValueFree(reply);
1634 return ret;
1635 }
1636
1637
1638 /**
1639 * qemuMonitorJSONExtractCPUS390Info:
1640 * @jsoncpu: pointer to a single JSON cpu entry
1641 * @cpu: pointer to a single cpu entry
1642 *
1643 * Derive the legacy cpu info 'halted' information
1644 * from the more accurate s390 cpu state. @cpu is
1645 * modified only on success.
1646 *
1647 * Note: the 'uninitialized' s390 cpu state can't be
1648 * mapped to halted yes/no.
1649 *
1650 * A s390 cpu entry could look like this
1651 * { "arch": "s390",
1652 * "cpu-index": 0,
1653 * "qom-path": "/machine/unattached/device[0]",
1654 * "thread_id": 3081,
1655 * "cpu-state": "operating" }
1656 *
1657 */
1658 static void
1659 qemuMonitorJSONExtractCPUS390Info(virJSONValuePtr jsoncpu,
1660 struct qemuMonitorQueryCpusEntry *cpu)
1661 {
1662 const char *cpu_state = virJSONValueObjectGetString(jsoncpu, "cpu-state");
1663
1664 if (STREQ_NULLABLE(cpu_state, "operating") ||
1665 STREQ_NULLABLE(cpu_state, "load"))
1666 cpu->halted = false;
1667 else if (STREQ_NULLABLE(cpu_state, "stopped") ||
1668 STREQ_NULLABLE(cpu_state, "check-stop"))
1669 cpu->halted = true;
1670 }
1671
1672
1673 /**
1674 * qemuMonitorJSONExtractCPUInfo:
1675 * @data: JSON response data
1676 * @entries: filled with detected cpu entries on success
1677 * @nentries: number of entries returned
1678 * @fast: true if this is a response from query-cpus-fast
1679 *
1680 * The JSON response @data will have the following format
1681 * in case @fast == false
1682 * [{ "arch": "x86",
1683 * "current": true,
1684 * "CPU": 0,
1685 * "qom_path": "/machine/unattached/device[0]",
1686 * "pc": -2130415978,
1687 * "halted": true,
1688 * "thread_id": 2631237,
1689 * ...},
1690 * {...}
1691 * ]
1692 * and for @fast == true
1693 * [{ "arch": "x86",
1694 * "cpu-index": 0,
1695 * "props": {
1696 * "core-id": 0,
1697 * "thread-id": 0,
1698 * "socket-id": 0
1699 * },
1700 * "qom-path": "/machine/unattached/device[0]",
1701 * "thread-id": 2631237,
1702 * ...},
1703 * {...}
1704 * ]
1705 * or for s390
1706 * [{ "arch": "s390",
1707 * "cpu-index": 0,
1708 * "props": {
1709 * "core-id": 0
1710 * },
1711 * "qom-path": "/machine/unattached/device[0]",
1712 * "thread-id": 1237,
1713 * "cpu-state": "operating",
1714 * ...},
1715 * {...}
1716 * ]
1717 *
1718 * Note that since QEMU 2.13.0 the "arch" output member of the
1719 * "query-cpus-fast" command is replaced by "target".
1720 */
1721 static int
1722 qemuMonitorJSONExtractCPUInfo(virJSONValuePtr data,
1723 struct qemuMonitorQueryCpusEntry **entries,
1724 size_t *nentries,
1725 bool fast)
1726 {
1727 const char *arch = NULL;
1728 struct qemuMonitorQueryCpusEntry *cpus = NULL;
1729 int ret = -1;
1730 size_t i;
1731 size_t ncpus;
1732
1733 if ((ncpus = virJSONValueArraySize(data)) == 0)
1734 return -2;
1735
1736 if (VIR_ALLOC_N(cpus, ncpus) < 0)
1737 goto cleanup;
1738
1739 for (i = 0; i < ncpus; i++) {
1740 virJSONValuePtr entry = virJSONValueArrayGet(data, i);
1741 int cpuid = -1;
1742 int thread = 0;
1743 bool halted = false;
1744 const char *qom_path;
1745 if (!entry) {
1746 ret = -2;
1747 goto cleanup;
1748 }
1749
1750 /* Some older qemu versions don't report the thread_id so treat this as
1751 * non-fatal, simply returning no data.
1752 * The return data of query-cpus-fast has different field names
1753 */
1754 if (fast) {
1755 if (!(arch = virJSONValueObjectGetString(entry, "target")))
1756 arch = virJSONValueObjectGetString(entry, "arch");
1757 ignore_value(virJSONValueObjectGetNumberInt(entry, "cpu-index", &cpuid));
1758 ignore_value(virJSONValueObjectGetNumberInt(entry, "thread-id", &thread));
1759 qom_path = virJSONValueObjectGetString(entry, "qom-path");
1760 } else {
1761 arch = virJSONValueObjectGetString(entry, "arch");
1762 ignore_value(virJSONValueObjectGetNumberInt(entry, "CPU", &cpuid));
1763 ignore_value(virJSONValueObjectGetNumberInt(entry, "thread_id", &thread));
1764 ignore_value(virJSONValueObjectGetBoolean(entry, "halted", &halted));
1765 qom_path = virJSONValueObjectGetString(entry, "qom_path");
1766 }
1767
1768 cpus[i].qemu_id = cpuid;
1769 cpus[i].tid = thread;
1770 cpus[i].halted = halted;
1771 if (VIR_STRDUP(cpus[i].qom_path, qom_path) < 0)
1772 goto cleanup;
1773
1774 /* process optional architecture-specific data */
1775 if (STREQ_NULLABLE(arch, "s390") || STREQ_NULLABLE(arch, "s390x"))
1776 qemuMonitorJSONExtractCPUS390Info(entry, cpus + i);
1777 }
1778
1779 VIR_STEAL_PTR(*entries, cpus);
1780 *nentries = ncpus;
1781 ret = 0;
1782
1783 cleanup:
1784 qemuMonitorQueryCpusFree(cpus, ncpus);
1785 return ret;
1786 }
1787
1788
1789 /**
1790 * qemuMonitorJSONQueryCPUs:
1791 *
1792 * @mon: monitor object
1793 * @entries: filled with detected entries on success
1794 * @nentries: number of entries returned
1795 * @force: force exit on error
1796 * @fast: use query-cpus-fast
1797 *
1798 * Queries qemu for cpu-related information. Failure to execute the command or
1799 * extract results does not produce an error as libvirt can continue without
1800 * this information, unless the caller has specified @force == true.
1801 *
1802 * Returns 0 on success, -1 on a fatal error (oom ...) and -2 if the
1803 * query failed gracefully.
1804 */
1805 int
1806 qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon,
1807 struct qemuMonitorQueryCpusEntry **entries,
1808 size_t *nentries,
1809 bool force,
1810 bool fast)
1811 {
1812 int ret = -1;
1813 virJSONValuePtr cmd;
1814 virJSONValuePtr reply = NULL;
1815 virJSONValuePtr data;
1816
1817 if (fast)
1818 cmd = qemuMonitorJSONMakeCommand("query-cpus-fast", NULL);
1819 else
1820 cmd = qemuMonitorJSONMakeCommand("query-cpus", NULL);
1821
1822 if (!cmd)
1823 return -1;
1824
1825 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
1826 goto cleanup;
1827
1828 if (force && qemuMonitorJSONCheckError(cmd, reply) < 0)
1829 goto cleanup;
1830
1831 if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
1832 ret = -2;
1833 goto cleanup;
1834 }
1835
1836 ret = qemuMonitorJSONExtractCPUInfo(data, entries, nentries, fast);
1837
1838 cleanup:
1839 virJSONValueFree(cmd);
1840 virJSONValueFree(reply);
1841 return ret;
1842 }
1843
1844
1845 int qemuMonitorJSONGetVirtType(qemuMonitorPtr mon,
1846 virDomainVirtType *virtType)
1847 {
1848 int ret = -1;
1849 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-kvm",
1850 NULL);
1851 virJSONValuePtr reply = NULL;
1852 virJSONValuePtr data;
1853 bool val = false;
1854
1855 *virtType = VIR_DOMAIN_VIRT_QEMU;
1856
1857 if (!cmd)
1858 return -1;
1859
1860 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
1861 goto cleanup;
1862
1863 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
1864 goto cleanup;
1865
1866 data = virJSONValueObjectGetObject(reply, "return");
1867
1868 if (virJSONValueObjectGetBoolean(data, "enabled", &val) < 0) {
1869 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1870 _("info kvm reply missing 'enabled' field"));
1871 goto cleanup;
1872 }
1873
1874 if (val)
1875 *virtType = VIR_DOMAIN_VIRT_KVM;
1876
1877 ret = 0;
1878 cleanup:
1879 virJSONValueFree(cmd);
1880 virJSONValueFree(reply);
1881 return ret;
1882 }
1883
1884
1885 /**
1886 * Loads correct video memory size values from QEMU and update the video
1887 * definition.
1888 *
1889 * Return 0 on success, -1 on failure and set proper error message.
1890 */
1891 int
1892 qemuMonitorJSONUpdateVideoMemorySize(qemuMonitorPtr mon,
1893 virDomainVideoDefPtr video,
1894 char *path)
1895 {
1896 qemuMonitorJSONObjectProperty prop = {
1897 QEMU_MONITOR_OBJECT_PROPERTY_ULONG,
1898 {0}
1899 };
1900
1901 switch (video->type) {
1902 case VIR_DOMAIN_VIDEO_TYPE_VGA:
1903 if (qemuMonitorJSONGetObjectProperty(mon, path, "vgamem_mb", &prop) < 0) {
1904 virReportError(VIR_ERR_INTERNAL_ERROR,
1905 _("QOM Object '%s' has no property 'vgamem_mb'"),
1906 path);
1907 return -1;
1908 }
1909 video->vram = prop.val.ul * 1024;
1910 break;
1911 case VIR_DOMAIN_VIDEO_TYPE_QXL:
1912 if (qemuMonitorJSONGetObjectProperty(mon, path, "vram_size", &prop) < 0) {
1913 virReportError(VIR_ERR_INTERNAL_ERROR,
1914 _("QOM Object '%s' has no property 'vram_size'"),
1915 path);
1916 return -1;
1917 }
1918 video->vram = prop.val.ul / 1024;
1919
1920 if (qemuMonitorJSONGetObjectProperty(mon, path, "ram_size", &prop) < 0) {
1921 virReportError(VIR_ERR_INTERNAL_ERROR,
1922 _("QOM Object '%s' has no property 'ram_size'"),
1923 path);
1924 return -1;
1925 }
1926 video->ram = prop.val.ul / 1024;
1927 if (qemuMonitorJSONGetObjectProperty(mon, path, "vgamem_mb", &prop) < 0) {
1928 virReportError(VIR_ERR_INTERNAL_ERROR,
1929 _("QOM Object '%s' has no property 'vgamem_mb'"),
1930 path);
1931 return -1;
1932 }
1933 video->vgamem = prop.val.ul * 1024;
1934 break;
1935 case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
1936 if (qemuMonitorJSONGetObjectProperty(mon, path, "vgamem_mb", &prop) < 0) {
1937 virReportError(VIR_ERR_INTERNAL_ERROR,
1938 _("QOM Object '%s' has no property 'vgamem_mb'"),
1939 path);
1940 return -1;
1941 }
1942 video->vram = prop.val.ul * 1024;
1943 break;
1944 case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
1945 case VIR_DOMAIN_VIDEO_TYPE_XEN:
1946 case VIR_DOMAIN_VIDEO_TYPE_VBOX:
1947 case VIR_DOMAIN_VIDEO_TYPE_LAST:
1948 break;
1949 }
1950
1951 return 0;
1952 }
1953
1954
1955 /**
1956 * Loads correct video vram64 size value from QEMU and update the video
1957 * definition.
1958 *
1959 * Return 0 on success, -1 on failure and set proper error message.
1960 */
1961 int
1962 qemuMonitorJSONUpdateVideoVram64Size(qemuMonitorPtr mon,
1963 virDomainVideoDefPtr video,
1964 char *path)
1965 {
1966 qemuMonitorJSONObjectProperty prop = {
1967 QEMU_MONITOR_OBJECT_PROPERTY_ULONG,
1968 {0}
1969 };
1970
1971 switch (video->type) {
1972 case VIR_DOMAIN_VIDEO_TYPE_QXL:
1973 if (video->vram64 != 0) {
1974 if (qemuMonitorJSONGetObjectProperty(mon, path,
1975 "vram64_size_mb", &prop) < 0) {
1976 virReportError(VIR_ERR_INTERNAL_ERROR,
1977 _("QOM Object '%s' has no property 'vram64_size_mb'"),
1978 path);
1979 return -1;
1980 }
1981 video->vram64 = prop.val.ul * 1024;
1982 }
1983 break;
1984 case VIR_DOMAIN_VIDEO_TYPE_VGA:
1985 case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
1986 case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
1987 case VIR_DOMAIN_VIDEO_TYPE_XEN:
1988 case VIR_DOMAIN_VIDEO_TYPE_VBOX:
1989 case VIR_DOMAIN_VIDEO_TYPE_LAST:
1990 break;
1991 }
1992
1993 return 0;
1994 }
1995
1996
1997 int
1998 qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon,
1999 unsigned long long *currmem)
2000 {
2001 int ret = -1;
2002 virJSONValuePtr data;
2003 unsigned long long mem;
2004 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-balloon",
2005 NULL);
2006 virJSONValuePtr reply = NULL;
2007
2008 *currmem = 0;
2009
2010 if (!cmd)
2011 return -1;
2012
2013 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
2014 goto cleanup;
2015
2016 /* See if balloon soft-failed */
2017 if (qemuMonitorJSONHasError(reply, "DeviceNotActive") ||
2018 qemuMonitorJSONHasError(reply, "KVMMissingCap")) {
2019 ret = 0;
2020 goto cleanup;
2021 }
2022
2023 /* See if any other fatal error occurred */
2024 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
2025 goto cleanup;
2026
2027 data = virJSONValueObjectGetObject(reply, "return");
2028
2029 if (virJSONValueObjectGetNumberUlong(data, "actual", &mem) < 0) {
2030 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2031 _("info balloon reply was missing balloon data"));
2032 goto cleanup;
2033 }
2034
2035 *currmem = (mem/1024);
2036 ret = 1;
2037 cleanup:
2038 virJSONValueFree(cmd);
2039 virJSONValueFree(reply);
2040 return ret;
2041 }
2042
2043
2044 /* Process the balloon driver statistics. The request and data returned
2045 * will be as follows (although the 'child[#]' entry will differ based on
2046 * where it's run).
2047 *
2048 * { "execute": "qom-get","arguments": \
2049 * { "path": "/machine/i440fx/pci.0/child[7]","property": "guest-stats"} }
2050 *
2051 * {"return": {"stats": \
2052 * {"stat-swap-out": 0,
2053 * "stat-free-memory": 686350336,
2054 * "stat-minor-faults": 697283,
2055 * "stat-major-faults": 951,
2056 * "stat-total-memory": 1019924480,
2057 * "stat-swap-in": 0},
2058 * "last-update": 1371221540}}
2059 *
2060 * A value in "stats" can be -1 indicating it's never been collected/stored.
2061 * The 'last-update' value could be used in the future in order to determine
2062 * rates and/or whether data has been collected since a previous cycle.
2063 * It's currently unused.
2064 */
2065 #define GET_BALLOON_STATS(OBJECT, FIELD, TAG, DIVISOR) \
2066 if (virJSONValueObjectHasKey(OBJECT, FIELD) && \
2067 (got < nr_stats)) { \
2068 if (virJSONValueObjectGetNumberUlong(OBJECT, FIELD, &mem) < 0) { \
2069 VIR_DEBUG("Failed to get '%s' value", FIELD); \
2070 } else { \
2071 /* Not being collected? No point in providing bad data */ \
2072 if (mem != -1UL) { \
2073 stats[got].tag = TAG; \
2074 stats[got].val = mem / DIVISOR; \
2075 got++; \
2076 } \
2077 } \
2078 }
2079
2080
2081 int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon,
2082 char *balloonpath,
2083 virDomainMemoryStatPtr stats,
2084 unsigned int nr_stats)
2085 {
2086 int ret = -1;
2087 virJSONValuePtr cmd = NULL;
2088 virJSONValuePtr reply = NULL;
2089 virJSONValuePtr data;
2090 virJSONValuePtr statsdata;
2091 unsigned long long mem;
2092 int got = 0;
2093
2094 ret = qemuMonitorJSONGetBalloonInfo(mon, &mem);
2095 if (ret == 1 && (got < nr_stats)) {
2096 stats[got].tag = VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON;
2097 stats[got].val = mem;
2098 got++;
2099 }
2100
2101 if (!balloonpath)
2102 goto cleanup;
2103
2104 if (!(cmd = qemuMonitorJSONMakeCommand("qom-get",
2105 "s:path", balloonpath,
2106 "s:property", "guest-stats",
2107 NULL)))
2108 goto cleanup;
2109
2110 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
2111 goto cleanup;
2112
2113 if ((data = virJSONValueObjectGetObject(reply, "error"))) {
2114 const char *klass = virJSONValueObjectGetString(data, "class");
2115 const char *desc = virJSONValueObjectGetString(data, "desc");
2116
2117 if (STREQ_NULLABLE(klass, "GenericError") &&
2118 STREQ_NULLABLE(desc, "guest hasn't updated any stats yet")) {
2119 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2120 _("the guest hasn't updated any stats yet"));
2121 goto cleanup;
2122 }
2123 }
2124
2125 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
2126 goto cleanup;
2127
2128 data = virJSONValueObjectGetObject(reply, "return");
2129
2130 if (!(statsdata = virJSONValueObjectGet(data, "stats"))) {
2131 VIR_DEBUG("data does not include 'stats'");
2132 goto cleanup;
2133 }
2134
2135 GET_BALLOON_STATS(statsdata, "stat-swap-in",
2136 VIR_DOMAIN_MEMORY_STAT_SWAP_IN, 1024);
2137 GET_BALLOON_STATS(statsdata, "stat-swap-out",
2138 VIR_DOMAIN_MEMORY_STAT_SWAP_OUT, 1024);
2139 GET_BALLOON_STATS(statsdata, "stat-major-faults",
2140 VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT, 1);
2141 GET_BALLOON_STATS(statsdata, "stat-minor-faults",
2142 VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT, 1);
2143 GET_BALLOON_STATS(statsdata, "stat-free-memory",
2144 VIR_DOMAIN_MEMORY_STAT_UNUSED, 1024);
2145 GET_BALLOON_STATS(statsdata, "stat-total-memory",
2146 VIR_DOMAIN_MEMORY_STAT_AVAILABLE, 1024);
2147 GET_BALLOON_STATS(statsdata, "stat-available-memory",
2148 VIR_DOMAIN_MEMORY_STAT_USABLE, 1024);
2149 GET_BALLOON_STATS(data, "last-update",
2150 VIR_DOMAIN_MEMORY_STAT_LAST_UPDATE, 1);
2151 GET_BALLOON_STATS(statsdata, "stat-disk-caches",
2152 VIR_DOMAIN_MEMORY_STAT_DISK_CACHES, 1024);
2153 GET_BALLOON_STATS(statsdata, "stat-htlb-pgalloc",
2154 VIR_DOMAIN_MEMORY_STAT_HUGETLB_PGALLOC, 1);
2155 GET_BALLOON_STATS(statsdata, "stat-htlb-pgfail",
2156 VIR_DOMAIN_MEMORY_STAT_HUGETLB_PGFAIL, 1);
2157
2158 ret = got;
2159 cleanup:
2160 virJSONValueFree(cmd);
2161 virJSONValueFree(reply);
2162 return ret;
2163 }
2164 #undef GET_BALLOON_STATS
2165
2166
2167 /*
2168 * Using the provided balloonpath, determine if we need to set the
2169 * collection interval property to enable statistics gathering.
2170 */
2171 int
2172 qemuMonitorJSONSetMemoryStatsPeriod(qemuMonitorPtr mon,
2173 char *balloonpath,
2174 int period)
2175 {
2176 qemuMonitorJSONObjectProperty prop;
2177
2178 /* Set to the value in memballoon (could enable or disable) */
2179 memset(&prop, 0, sizeof(qemuMonitorJSONObjectProperty));
2180 prop.type = QEMU_MONITOR_OBJECT_PROPERTY_INT;
2181 prop.val.iv = period;
2182 if (qemuMonitorJSONSetObjectProperty(mon, balloonpath,
2183 "guest-stats-polling-interval",
2184 &prop) < 0) {
2185 return -1;
2186 }
2187 return 0;
2188 }
2189
2190
2191 /* qemuMonitorJSONQueryBlock:
2192 * @mon: Monitor pointer
2193 *
2194 * This helper will attempt to make a "query-block" call and check for
2195 * errors before returning with the reply.
2196 *
2197 * Returns: NULL on error, reply on success
2198 */
2199 static virJSONValuePtr
2200 qemuMonitorJSONQueryBlock(qemuMonitorPtr mon)
2201 {
2202 virJSONValuePtr cmd;
2203 virJSONValuePtr reply = NULL;
2204 virJSONValuePtr devices = NULL;
2205
2206 if (!(cmd = qemuMonitorJSONMakeCommand("query-block", NULL)))
2207 return NULL;
2208
2209 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0 ||
2210 qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
2211 goto cleanup;
2212
2213 devices = virJSONValueObjectStealArray(reply, "return");
2214
2215 cleanup:
2216 virJSONValueFree(cmd);
2217 virJSONValueFree(reply);
2218 return devices;
2219 }
2220
2221
2222 static virJSONValuePtr
2223 qemuMonitorJSONGetBlockDev(virJSONValuePtr devices,
2224 size_t idx)
2225 {
2226 virJSONValuePtr dev = virJSONValueArrayGet(devices, idx);
2227
2228 if (!dev || virJSONValueGetType(dev) != VIR_JSON_TYPE_OBJECT) {
2229 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2230 _("query-block device entry was not in expected format"));
2231 return NULL;
2232 }
2233 return dev;
2234 }
2235
2236
2237 static const char *
2238 qemuMonitorJSONGetBlockDevDevice(virJSONValuePtr dev)
2239 {
2240 const char *thisdev;
2241
2242 if (!(thisdev = virJSONValueObjectGetString(dev, "device"))) {
2243 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2244 _("query-block device entry was not in expected format"));
2245 return NULL;
2246 }
2247
2248 return thisdev;
2249 }
2250
2251
2252 static int
2253 qemuMonitorJSONBlockInfoAdd(virHashTablePtr table,
2254 struct qemuDomainDiskInfo *info,
2255 const char *entryname)
2256 {
2257 struct qemuDomainDiskInfo *tmp = NULL;
2258 int ret = -1;
2259
2260 if (VIR_ALLOC(tmp) < 0)
2261 goto cleanup;
2262
2263 *tmp = *info;
2264 tmp->nodename = NULL;
2265
2266 if (info->nodename &&
2267 VIR_STRDUP(tmp->nodename, info->nodename) < 0)
2268 goto cleanup;
2269
2270 if (virHashAddEntry(table, entryname, tmp) < 0)
2271 goto cleanup;
2272
2273 tmp = NULL;
2274 ret = 0;
2275
2276 cleanup:
2277 if (tmp)
2278 VIR_FREE(tmp->nodename);
2279 VIR_FREE(tmp);
2280 return ret;
2281 }
2282
2283
2284 int qemuMonitorJSONGetBlockInfo(qemuMonitorPtr mon,
2285 virHashTablePtr table)
2286 {
2287 int ret = -1;
2288 size_t i;
2289
2290 virJSONValuePtr devices;
2291
2292 if (!(devices = qemuMonitorJSONQueryBlock(mon)))
2293 return -1;
2294
2295 for (i = 0; i < virJSONValueArraySize(devices); i++) {
2296 virJSONValuePtr dev;
2297 virJSONValuePtr image;
2298 struct qemuDomainDiskInfo info = { false };
2299 const char *thisdev;
2300 const char *status;
2301 const char *qdev;
2302
2303 if (!(dev = qemuMonitorJSONGetBlockDev(devices, i)))
2304 goto cleanup;
2305
2306 if (!(thisdev = qemuMonitorJSONGetBlockDevDevice(dev)))
2307 goto cleanup;
2308
2309 thisdev = qemuAliasDiskDriveSkipPrefix(thisdev);
2310 qdev = virJSONValueObjectGetString(dev, "qdev");
2311
2312 if (*thisdev == '\0')
2313 thisdev = NULL;
2314
2315 if (!qdev && !thisdev) {
2316 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2317 _("query-block device entry was not in expected format"));
2318 goto cleanup;
2319 }
2320
2321 if (virJSONValueObjectGetBoolean(dev, "removable", &info.removable) < 0) {
2322 virReportError(VIR_ERR_INTERNAL_ERROR,
2323 _("cannot read %s value"),
2324 "removable");
2325 goto cleanup;
2326 }
2327
2328 /* 'tray_open' is present only if the device has a tray */
2329 if (virJSONValueObjectGetBoolean(dev, "tray_open", &info.tray_open) == 0)
2330 info.tray = true;
2331
2332 /* presence of 'inserted' notifies that a medium is in the device */
2333 if ((image = virJSONValueObjectGetObject(dev, "inserted"))) {
2334 info.nodename = (char *) virJSONValueObjectGetString(image, "node-name");
2335 } else {
2336 info.empty = true;
2337 }
2338
2339 /* Missing io-status indicates no error */
2340 if ((status = virJSONValueObjectGetString(dev, "io-status"))) {
2341 info.io_status = qemuMonitorBlockIOStatusToError(status);
2342 if (info.io_status < 0)
2343 goto cleanup;
2344 }
2345
2346 if (thisdev &&
2347 qemuMonitorJSONBlockInfoAdd(table, &info, thisdev) < 0)
2348 goto cleanup;
2349
2350 if (qdev && STRNEQ_NULLABLE(thisdev, qdev) &&
2351 qemuMonitorJSONBlockInfoAdd(table, &info, qdev) < 0)
2352 goto cleanup;
2353 }
2354
2355 ret = 0;
2356 cleanup:
2357 virJSONValueFree(devices);
2358 return ret;
2359 }
2360
2361
2362 static qemuBlockStatsPtr
2363 qemuMonitorJSONBlockStatsCollectData(virJSONValuePtr dev,
2364 int *nstats)
2365 {
2366 qemuBlockStatsPtr bstats = NULL;
2367 qemuBlockStatsPtr ret = NULL;
2368 virJSONValuePtr parent;
2369 virJSONValuePtr parentstats;
2370 virJSONValuePtr stats;
2371
2372 if ((stats = virJSONValueObjectGetObject(dev, "stats")) == NULL) {
2373 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2374 _("blockstats stats entry was not "
2375 "in expected format"));
2376 goto cleanup;
2377 }
2378
2379 if (VIR_ALLOC(bstats) < 0)
2380 goto cleanup;
2381
2382 #define QEMU_MONITOR_BLOCK_STAT_GET(NAME, VAR, MANDATORY) \
2383 if (MANDATORY || virJSONValueObjectHasKey(stats, NAME)) { \
2384 (*nstats)++; \
2385 if (virJSONValueObjectGetNumberLong(stats, NAME, &VAR) < 0) { \
2386 virReportError(VIR_ERR_INTERNAL_ERROR, \
2387 _("cannot read %s statistic"), NAME); \
2388 goto cleanup; \
2389 } \
2390 }
2391 QEMU_MONITOR_BLOCK_STAT_GET("rd_bytes", bstats->rd_bytes, true);
2392 QEMU_MONITOR_BLOCK_STAT_GET("wr_bytes", bstats->wr_bytes, true);
2393 QEMU_MONITOR_BLOCK_STAT_GET("rd_operations", bstats->rd_req, true);
2394 QEMU_MONITOR_BLOCK_STAT_GET("wr_operations", bstats->wr_req, true);
2395 QEMU_MONITOR_BLOCK_STAT_GET("rd_total_time_ns", bstats->rd_total_times, false);
2396 QEMU_MONITOR_BLOCK_STAT_GET("wr_total_time_ns", bstats->wr_total_times, false);
2397 QEMU_MONITOR_BLOCK_STAT_GET("flush_operations", bstats->flush_req, false);
2398 QEMU_MONITOR_BLOCK_STAT_GET("flush_total_time_ns", bstats->flush_total_times, false);
2399 #undef QEMU_MONITOR_BLOCK_STAT_GET
2400
2401 if ((parent = virJSONValueObjectGetObject(dev, "parent")) &&
2402 (parentstats = virJSONValueObjectGetObject(parent, "stats"))) {
2403 if (virJSONValueObjectGetNumberUlong(parentstats, "wr_highest_offset",
2404 &bstats->wr_highest_offset) == 0)
2405 bstats->wr_highest_offset_valid = true;
2406 }
2407
2408 VIR_STEAL_PTR(ret, bstats);
2409
2410 cleanup:
2411 VIR_FREE(bstats);
2412 return ret;
2413 }
2414
2415
2416 static int
2417 qemuMonitorJSONAddOneBlockStatsInfo(qemuBlockStatsPtr bstats,
2418 const char *name,
2419 virHashTablePtr stats)
2420 {
2421 qemuBlockStatsPtr copy = NULL;
2422
2423 if (VIR_ALLOC(copy) < 0)
2424 return -1;
2425
2426 if (bstats)
2427 *copy = *bstats;
2428
2429 if (virHashAddEntry(stats, name, copy) < 0) {
2430 VIR_FREE(copy);
2431 return -1;
2432 }
2433
2434 return 0;
2435 }
2436
2437
2438 static int
2439 qemuMonitorJSONGetOneBlockStatsInfo(virJSONValuePtr dev,
2440 const char *dev_name,
2441 int depth,
2442 virHashTablePtr hash,
2443 bool backingChain)
2444 {
2445 qemuBlockStatsPtr bstats = NULL;
2446 int ret = -1;
2447 int nstats = 0;
2448 const char *qdevname = NULL;
2449 const char *nodename = NULL;
2450 char *devicename = NULL;
2451 virJSONValuePtr backing;
2452
2453 if (dev_name &&
2454 !(devicename = qemuDomainStorageAlias(dev_name, depth)))
2455 goto cleanup;
2456
2457 qdevname = virJSONValueObjectGetString(dev, "qdev");
2458 nodename = virJSONValueObjectGetString(dev, "node-name");
2459
2460 if (!devicename && !qdevname && !nodename) {
2461 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2462 _("blockstats device entry was not in expected format"));
2463 goto cleanup;
2464 }
2465
2466 if (!(bstats = qemuMonitorJSONBlockStatsCollectData(dev, &nstats)))
2467 goto cleanup;
2468
2469 if (devicename &&
2470 qemuMonitorJSONAddOneBlockStatsInfo(bstats, devicename, hash) < 0)
2471 goto cleanup;
2472
2473 if (qdevname && STRNEQ_NULLABLE(qdevname, devicename) &&
2474 qemuMonitorJSONAddOneBlockStatsInfo(bstats, qdevname, hash) < 0)
2475 goto cleanup;
2476
2477 if (nodename &&
2478 qemuMonitorJSONAddOneBlockStatsInfo(bstats, nodename, hash) < 0)
2479 goto cleanup;
2480
2481 if (backingChain &&
2482 (backing = virJSONValueObjectGetObject(dev, "backing")) &&
2483 qemuMonitorJSONGetOneBlockStatsInfo(backing, dev_name, depth + 1,
2484 hash, true) < 0)
2485 goto cleanup;
2486
2487 ret = nstats;
2488 cleanup:
2489 VIR_FREE(bstats);
2490 VIR_FREE(devicename);
2491 return ret;
2492 }
2493
2494
2495 virJSONValuePtr
2496 qemuMonitorJSONQueryBlockstats(qemuMonitorPtr mon)
2497 {
2498 virJSONValuePtr cmd;
2499 virJSONValuePtr reply = NULL;
2500 virJSONValuePtr ret = NULL;
2501
2502 if (!(cmd = qemuMonitorJSONMakeCommand("query-blockstats", NULL)))
2503 return NULL;
2504
2505 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
2506 goto cleanup;
2507
2508 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
2509 goto cleanup;
2510
2511 ret = virJSONValueObjectStealArray(reply, "return");
2512
2513 cleanup:
2514 virJSONValueFree(cmd);
2515 virJSONValueFree(reply);
2516 return ret;
2517 }
2518
2519
2520 int
2521 qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitorPtr mon,
2522 virHashTablePtr hash,
2523 bool backingChain)
2524 {
2525 int ret = -1;
2526 int nstats = 0;
2527 int rc;
2528 size_t i;
2529 virJSONValuePtr devices;
2530
2531 if (!(devices = qemuMonitorJSONQueryBlockstats(mon)))
2532 return -1;
2533
2534 for (i = 0; i < virJSONValueArraySize(devices); i++) {
2535 virJSONValuePtr dev = virJSONValueArrayGet(devices, i);
2536 const char *dev_name;
2537
2538 if (!dev || virJSONValueGetType(dev) != VIR_JSON_TYPE_OBJECT) {
2539 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2540 _("blockstats device entry was not "
2541 "in expected format"));
2542 goto cleanup;
2543 }
2544
2545 if (!(dev_name = virJSONValueObjectGetString(dev, "device"))) {
2546 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2547 _("blockstats device entry was not "
2548 "in expected format"));
2549 goto cleanup;
2550 }
2551
2552 if (*dev_name == '\0')
2553 dev_name = NULL;
2554
2555 rc = qemuMonitorJSONGetOneBlockStatsInfo(dev, dev_name, 0, hash,
2556 backingChain);
2557
2558 if (rc < 0)
2559 goto cleanup;
2560
2561 if (rc > nstats)
2562 nstats = rc;
2563 }
2564
2565 ret = nstats;
2566
2567 cleanup:
2568 virJSONValueFree(devices);
2569 return ret;
2570 }
2571
2572
2573 static int
2574 qemuMonitorJSONBlockStatsUpdateCapacityData(virJSONValuePtr image,
2575 const char *name,
2576 virHashTablePtr stats,
2577 qemuBlockStatsPtr *entry)
2578 {
2579 qemuBlockStatsPtr bstats;
2580
2581 if (!(bstats = virHashLookup(stats, name))) {
2582 if (VIR_ALLOC(bstats) < 0)
2583 return -1;
2584
2585 if (virHashAddEntry(stats, name, bstats) < 0) {
2586 VIR_FREE(bstats);
2587 return -1;
2588 }
2589 }
2590
2591 if (entry)
2592 *entry = bstats;
2593
2594 /* failures can be ignored after this point */
2595 if (virJSONValueObjectGetNumberUlong(image, "virtual-size",
2596 &bstats->capacity) < 0)
2597 return 0;
2598
2599 /* if actual-size is missing, image is not thin provisioned */
2600 if (virJSONValueObjectGetNumberUlong(image, "actual-size",
2601 &bstats->physical) < 0)
2602 bstats->physical = bstats->capacity;
2603
2604 return 0;
2605 }
2606
2607
2608 static int
2609 qemuMonitorJSONBlockStatsUpdateCapacityOne(virJSONValuePtr image,
2610 const char *dev_name,
2611 int depth,
2612 virHashTablePtr stats,
2613 bool backingChain)
2614 {
2615 int ret = -1;
2616 char *entry_name = qemuDomainStorageAlias(dev_name, depth);
2617 virJSONValuePtr backing;
2618
2619 if (qemuMonitorJSONBlockStatsUpdateCapacityData(image, entry_name,
2620 stats, NULL) < 0)
2621 goto cleanup;
2622
2623 if (backingChain &&
2624 (backing = virJSONValueObjectGetObject(image, "backing-image")) &&
2625 qemuMonitorJSONBlockStatsUpdateCapacityOne(backing,
2626 dev_name,
2627 depth + 1,
2628 stats,
2629 true) < 0)
2630 goto cleanup;
2631
2632 ret = 0;
2633 cleanup:
2634 VIR_FREE(entry_name);
2635 return ret;
2636 }
2637
2638
2639 int
2640 qemuMonitorJSONBlockStatsUpdateCapacity(qemuMonitorPtr mon,
2641 virHashTablePtr stats,
2642 bool backingChain)
2643 {
2644 int ret = -1;
2645 size_t i;
2646 virJSONValuePtr devices;
2647
2648 if (!(devices = qemuMonitorJSONQueryBlock(mon)))
2649 return -1;
2650
2651 for (i = 0; i < virJSONValueArraySize(devices); i++) {
2652 virJSONValuePtr dev;
2653 virJSONValuePtr inserted;
2654 virJSONValuePtr image;
2655 const char *dev_name;
2656
2657 if (!(dev = qemuMonitorJSONGetBlockDev(devices, i)))
2658 goto cleanup;
2659
2660 if (!(dev_name = qemuMonitorJSONGetBlockDevDevice(dev)))
2661 goto cleanup;
2662
2663 /* drive may be empty */
2664 if (!(inserted = virJSONValueObjectGetObject(dev, "inserted")) ||
2665 !(image = virJSONValueObjectGetObject(inserted, "image")))
2666 continue;
2667
2668 if (qemuMonitorJSONBlockStatsUpdateCapacityOne(image, dev_name, 0,
2669 stats,
2670 backingChain) < 0)
2671 goto cleanup;
2672 }
2673
2674 ret = 0;
2675
2676 cleanup:
2677 virJSONValueFree(devices);
2678 return ret;
2679 }
2680
2681
2682 static int
2683 qemuMonitorJSONBlockStatsUpdateCapacityBlockdevWorker(size_t pos ATTRIBUTE_UNUSED,
2684 virJSONValuePtr val,
2685 void *opaque)
2686 {
2687 virHashTablePtr stats = opaque;
2688 virJSONValuePtr image;
2689 const char *nodename;
2690 qemuBlockStatsPtr entry;
2691
2692 if (!(nodename = virJSONValueObjectGetString(val, "node-name")) ||
2693 !(image = virJSONValueObjectGetObject(val, "image"))) {
2694 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2695 _("query-named-block-nodes entry was not in expected format"));
2696 return -1;
2697 }
2698
2699 if (qemuMonitorJSONBlockStatsUpdateCapacityData(image, nodename, stats, &entry) < 0)
2700 return -1;
2701
2702 if (entry)
2703 ignore_value(virJSONValueObjectGetNumberUlong(val, "write_threshold",
2704 &entry->write_threshold));
2705
2706 return 1; /* we don't want to steal the value from the JSON array */
2707 }
2708
2709
2710 int
2711 qemuMonitorJSONBlockStatsUpdateCapacityBlockdev(qemuMonitorPtr mon,
2712 virHashTablePtr stats)
2713 {
2714 virJSONValuePtr nodes;
2715 int ret = -1;
2716
2717 if (!(nodes = qemuMonitorJSONQueryNamedBlockNodes(mon)))
2718 return -1;
2719
2720 if (virJSONValueArrayForeachSteal(nodes,
2721 qemuMonitorJSONBlockStatsUpdateCapacityBlockdevWorker,
2722 stats) < 0)
2723 goto cleanup;
2724
2725 ret = 0;
2726
2727 cleanup:
2728 virJSONValueFree(nodes);
2729 return ret;
2730 }
2731
2732
2733 int qemuMonitorJSONBlockResize(qemuMonitorPtr mon,
2734 const char *device,
2735 const char *nodename,
2736 unsigned long long size)
2737 {
2738 int ret = -1;
2739 virJSONValuePtr cmd;
2740 virJSONValuePtr reply = NULL;
2741
2742 cmd = qemuMonitorJSONMakeCommand("block_resize",
2743 "S:device", device,
2744 "S:node-name", nodename,
2745 "U:size", size,
2746 NULL);
2747 if (!cmd)
2748 return -1;
2749
2750 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
2751 goto cleanup;
2752
2753 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
2754 goto cleanup;
2755
2756 ret = 0;
2757 cleanup:
2758 virJSONValueFree(cmd);
2759 virJSONValueFree(reply);
2760 return ret;
2761 }
2762
2763
2764 int qemuMonitorJSONSetPassword(qemuMonitorPtr mon,
2765 const char *protocol,
2766 const char *password,
2767 const char *action_if_connected)
2768 {
2769 int ret = -1;
2770 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("set_password",
2771 "s:protocol", protocol,
2772 "s:password", password,
2773 "s:connected", action_if_connected,
2774 NULL);
2775 virJSONValuePtr reply = NULL;
2776 if (!cmd)
2777 return -1;
2778
2779 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
2780 goto cleanup;
2781
2782 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
2783 goto cleanup;
2784
2785 ret = 0;
2786 cleanup:
2787 virJSONValueFree(cmd);
2788 virJSONValueFree(reply);
2789 return ret;
2790 }
2791
2792 int qemuMonitorJSONExpirePassword(qemuMonitorPtr mon,
2793 const char *protocol,
2794 const char *expire_time)
2795 {
2796 int ret = -1;
2797 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("expire_password",
2798 "s:protocol", protocol,
2799 "s:time", expire_time,
2800 NULL);
2801 virJSONValuePtr reply = NULL;
2802 if (!cmd)
2803 return -1;
2804
2805 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
2806 goto cleanup;
2807
2808 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
2809 goto cleanup;
2810
2811 ret = 0;
2812 cleanup:
2813 virJSONValueFree(cmd);
2814 virJSONValueFree(reply);
2815 return ret;
2816 }
2817
2818
2819 int
2820 qemuMonitorJSONSetBalloon(qemuMonitorPtr mon,
2821 unsigned long long newmem)
2822 {
2823 int ret = -1;
2824 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("balloon",
2825 "U:value", newmem * 1024,
2826 NULL);
2827 virJSONValuePtr reply = NULL;
2828 if (!cmd)
2829 return -1;
2830
2831 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
2832 goto cleanup;
2833
2834 /* See if balloon soft-failed */
2835 if (qemuMonitorJSONHasError(reply, "DeviceNotActive") ||
2836 qemuMonitorJSONHasError(reply, "KVMMissingCap")) {
2837 ret = 0;
2838 goto cleanup;
2839 }
2840
2841 /* See if any other fatal error occurred */
2842 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
2843 goto cleanup;
2844
2845 /* Real success */
2846 ret = 1;
2847 cleanup:
2848 virJSONValueFree(cmd);
2849 virJSONValueFree(reply);
2850 return ret;
2851 }
2852
2853
2854 int qemuMonitorJSONSetCPU(qemuMonitorPtr mon,
2855 int cpu, bool online)
2856 {
2857 int ret = -1;
2858 virJSONValuePtr cmd = NULL;
2859 virJSONValuePtr reply = NULL;
2860
2861 if (online) {
2862 cmd = qemuMonitorJSONMakeCommand("cpu-add",
2863 "i:id", cpu,
2864 NULL);
2865 } else {
2866 /* offlining is not yet implemented in qmp */
2867 goto fallback;
2868 }
2869 if (!cmd)
2870 goto cleanup;
2871
2872 if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
2873 goto cleanup;
2874
2875 if (qemuMonitorJSONHasError(reply, "CommandNotFound"))
2876 goto fallback;
2877 else
2878 ret = qemuMonitorJSONCheckError(cmd, reply);
2879
2880 cleanup:
2881 virJSONValueFree(cmd);
2882 virJSONValueFree(reply);
2883 return ret;
2884
2885 fallback:
2886 VIR_DEBUG("no QMP support for cpu_set, trying HMP");
2887 ret = qemuMonitorTextSetCPU(mon, cpu, online);
2888 goto cleanup;
2889 }
2890
2891
2892 /**
2893 * Run QMP command to eject a media from ejectable device.
2894 *
2895 * Returns:
2896 * -1 on error
2897 * 0 on success
2898 */
2899 int qemuMonitorJSONEjectMedia(qemuMonitorPtr mon,
2900 const char *dev_name,
2901 bool force)
2902 {
2903 int ret = -1;
2904 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("eject",
2905 "s:device", dev_name,
2906 "b:force", force ? 1 : 0,
2907 NULL);
2908 virJSONValuePtr reply = NULL;
2909 if (!cmd)
2910 return -1;
2911
2912 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
2913 goto cleanup;
2914
2915 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
2916 goto cleanup;
2917
2918 ret = 0;
2919 cleanup:
2920 virJSONValueFree(cmd);
2921 virJSONValueFree(reply);
2922 return ret;
2923 }
2924
2925
2926 int qemuMonitorJSONChangeMedia(qemuMonitorPtr mon,
2927 const char *dev_name,
2928 const char *newmedia,
2929 const char *format)
2930 {
2931 int ret = -1;
2932 virJSONValuePtr cmd;
2933 virJSONValuePtr reply = NULL;
2934
2935 cmd = qemuMonitorJSONMakeCommand("change",
2936 "s:device", dev_name,
2937 "s:target", newmedia,
2938 "S:arg", format,
2939 NULL);
2940
2941 if (!cmd)
2942 return -1;
2943
2944 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
2945 goto cleanup;
2946
2947 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
2948 goto cleanup;
2949
2950 ret = 0;
2951 cleanup:
2952 virJSONValueFree(cmd);
2953 virJSONValueFree(reply);
2954 return ret;
2955 }
2956
2957
2958 static int qemuMonitorJSONSaveMemory(qemuMonitorPtr mon,
2959 const char *cmdtype,
2960 unsigned long long offset,
2961 size_t length,
2962 const char *path)
2963 {
2964 int ret = -1;
2965 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand(cmdtype,
2966 "U:val", offset,
2967 "u:size", length,
2968 "s:filename", path,
2969 NULL);
2970 virJSONValuePtr reply = NULL;
2971 if (!cmd)
2972 return -1;
2973
2974 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
2975 goto cleanup;
2976
2977 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
2978 goto cleanup;
2979
2980 ret = 0;
2981 cleanup:
2982 virJSONValueFree(cmd);
2983 virJSONValueFree(reply);
2984 return ret;
2985 }
2986
2987
2988 int qemuMonitorJSONSaveVirtualMemory(qemuMonitorPtr mon,
2989 unsigned long long offset,
2990 size_t length,
2991 const char *path)
2992 {
2993 return qemuMonitorJSONSaveMemory(mon, "memsave", offset, length, path);
2994 }
2995
2996 int qemuMonitorJSONSavePhysicalMemory(qemuMonitorPtr mon,
2997 unsigned long long offset,
2998 size_t length,
2999 const char *path)
3000 {
3001 return qemuMonitorJSONSaveMemory(mon, "pmemsave", offset, length, path);
3002 }
3003
3004
3005 int qemuMonitorJSONSetMigrationSpeed(qemuMonitorPtr mon,
3006 unsigned long bandwidth)
3007 {
3008 int ret = -1;
3009 virJSONValuePtr cmd;
3010 virJSONValuePtr reply = NULL;
3011 cmd = qemuMonitorJSONMakeCommand("migrate_set_speed",
3012 "U:value", bandwidth * 1024ULL * 1024ULL,
3013 NULL);
3014 if (!cmd)
3015 return -1;
3016
3017 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3018 goto cleanup;
3019
3020 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
3021 goto cleanup;
3022
3023 ret = 0;
3024 cleanup:
3025 virJSONValueFree(cmd);
3026 virJSONValueFree(reply);
3027 return ret;
3028 }
3029
3030
3031 int qemuMonitorJSONSetMigrationDowntime(qemuMonitorPtr mon,
3032 unsigned long long downtime)
3033 {
3034 int ret = -1;
3035 virJSONValuePtr cmd;
3036 virJSONValuePtr reply = NULL;
3037
3038 cmd = qemuMonitorJSONMakeCommand("migrate_set_downtime",
3039 "d:value", downtime / 1000.0,
3040 NULL);
3041 if (!cmd)
3042 return -1;
3043
3044 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3045 goto cleanup;
3046
3047 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
3048 goto cleanup;
3049
3050 ret = 0;
3051 cleanup:
3052 virJSONValueFree(cmd);
3053 virJSONValueFree(reply);
3054 return ret;
3055 }
3056
3057
3058 int
3059 qemuMonitorJSONGetMigrationCacheSize(qemuMonitorPtr mon,
3060 unsigned long long *cacheSize)
3061 {
3062 int ret = -1;
3063 virJSONValuePtr cmd;
3064 virJSONValuePtr reply = NULL;
3065
3066 *cacheSize = 0;
3067
3068 cmd = qemuMonitorJSONMakeCommand("query-migrate-cache-size", NULL);
3069 if (!cmd)
3070 return -1;
3071
3072 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3073 goto cleanup;
3074
3075 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_NUMBER) < 0)
3076 goto cleanup;
3077
3078 if (virJSONValueObjectGetNumberUlong(reply, "return", cacheSize) < 0) {
3079 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3080 _("invalid cache size in query-migrate-cache-size reply"));
3081 goto cleanup;
3082 }
3083
3084 ret = 0;
3085 cleanup:
3086 virJSONValueFree(cmd);
3087 virJSONValueFree(reply);
3088 return ret;
3089 }
3090
3091
3092 int
3093 qemuMonitorJSONSetMigrationCacheSize(qemuMonitorPtr mon,
3094 unsigned long long cacheSize)
3095 {
3096 int ret = -1;
3097 virJSONValuePtr cmd;
3098 virJSONValuePtr reply = NULL;
3099
3100 cmd = qemuMonitorJSONMakeCommand("migrate-set-cache-size",
3101 "U:value", cacheSize,
3102 NULL);
3103 if (!cmd)
3104 return -1;
3105
3106 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3107 goto cleanup;
3108
3109 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
3110 goto cleanup;
3111
3112 ret = 0;
3113 cleanup:
3114 virJSONValueFree(cmd);
3115 virJSONValueFree(reply);
3116 return ret;
3117 }
3118
3119
3120 int
3121 qemuMonitorJSONGetMigrationParams(qemuMonitorPtr mon,
3122 virJSONValuePtr *params)
3123 {
3124 int ret = -1;
3125 virJSONValuePtr cmd = NULL;
3126 virJSONValuePtr reply = NULL;
3127
3128 *params = NULL;
3129
3130 if (!(cmd = qemuMonitorJSONMakeCommand("query-migrate-parameters", NULL)))
3131 return -1;
3132
3133 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3134 goto cleanup;
3135
3136 if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
3137 ret = 0;
3138 goto cleanup;
3139 }
3140
3141 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
3142 goto cleanup;
3143
3144 *params = virJSONValueObjectStealObject(reply, "return");
3145 ret = 0;
3146
3147 cleanup:
3148 virJSONValueFree(cmd);
3149 virJSONValueFree(reply);
3150 return ret;
3151 }
3152
3153 int
3154 qemuMonitorJSONSetMigrationParams(qemuMonitorPtr mon,
3155 virJSONValuePtr params)
3156 {
3157 int ret = -1;
3158 virJSONValuePtr cmd = NULL;
3159 virJSONValuePtr reply = NULL;
3160
3161 if (!(cmd = virJSONValueNewObject()))
3162 goto cleanup;
3163
3164 if (virJSONValueObjectAppendString(cmd, "execute",
3165 "migrate-set-parameters") < 0)
3166 goto cleanup;
3167
3168 if (virJSONValueObjectAppend(cmd, "arguments", params) < 0)
3169 goto cleanup;
3170 params = NULL;
3171
3172 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3173 goto cleanup;
3174
3175 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
3176 goto cleanup;
3177
3178 ret = 0;
3179 cleanup:
3180 virJSONValueFree(cmd);
3181 virJSONValueFree(params);
3182 virJSONValueFree(reply);
3183 return ret;
3184 }
3185
3186
3187 static int
3188 qemuMonitorJSONGetMigrationStatsReply(virJSONValuePtr reply,
3189 qemuMonitorMigrationStatsPtr stats,
3190 char **error)
3191 {
3192 virJSONValuePtr ret;
3193 virJSONValuePtr ram;
3194 virJSONValuePtr disk;
3195 virJSONValuePtr comp;
3196 const char *statusstr;
3197 int rc;
3198 double mbps;
3199 const char *tmp;
3200
3201 ret = virJSONValueObjectGetObject(reply, "return");
3202
3203 if (!(statusstr = virJSONValueObjectGetString(ret, "status"))) {
3204 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3205 _("info migration reply was missing return status"));
3206 return -1;
3207 }
3208
3209 stats->status = qemuMonitorMigrationStatusTypeFromString(statusstr);
3210 if (stats->status < 0) {
3211 virReportError(VIR_ERR_INTERNAL_ERROR,
3212 _("unexpected migration status in %s"), statusstr);
3213 return -1;
3214 }
3215
3216 ignore_value(virJSONValueObjectGetNumberUlong(ret, "total-time",
3217 &stats->total_time));
3218 if (stats->status == QEMU_MONITOR_MIGRATION_STATUS_COMPLETED) {
3219 rc = virJSONValueObjectGetNumberUlong(ret, "downtime",
3220 &stats->downtime);
3221 } else {
3222 rc = virJSONValueObjectGetNumberUlong(ret, "expected-downtime",
3223 &stats->downtime);
3224 }
3225 if (rc == 0)
3226 stats->downtime_set = true;
3227
3228 if (virJSONValueObjectGetNumberUlong(ret, "setup-time",
3229 &stats->setup_time) == 0)
3230 stats->setup_time_set = true;
3231
3232 ignore_value(virJSONValueObjectGetNumberInt(ret, "cpu-throttle-percentage",
3233 &stats->cpu_throttle_percentage));
3234
3235 switch ((qemuMonitorMigrationStatus) stats->status) {
3236 case QEMU_MONITOR_MIGRATION_STATUS_INACTIVE:
3237 case QEMU_MONITOR_MIGRATION_STATUS_SETUP:
3238 case QEMU_MONITOR_MIGRATION_STATUS_CANCELLED:
3239 case QEMU_MONITOR_MIGRATION_STATUS_LAST:
3240 break;
3241
3242 case QEMU_MONITOR_MIGRATION_STATUS_ERROR:
3243 if (error) {
3244 tmp = virJSONValueObjectGetString(ret, "error-desc");
3245 if (tmp && VIR_STRDUP(*error, tmp) < 0)
3246 return -1;
3247 }
3248 break;
3249
3250 case QEMU_MONITOR_MIGRATION_STATUS_ACTIVE:
3251 case QEMU_MONITOR_MIGRATION_STATUS_POSTCOPY:
3252 case QEMU_MONITOR_MIGRATION_STATUS_COMPLETED:
3253 case QEMU_MONITOR_MIGRATION_STATUS_CANCELLING:
3254 case QEMU_MONITOR_MIGRATION_STATUS_PRE_SWITCHOVER:
3255 case QEMU_MONITOR_MIGRATION_STATUS_DEVICE:
3256 ram = virJSONValueObjectGetObject(ret, "ram");
3257 if (!ram) {
3258 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3259 _("migration was active, but no RAM info was set"));
3260 return -1;
3261 }
3262
3263 if (virJSONValueObjectGetNumberUlong(ram, "transferred",
3264 &stats->ram_transferred) < 0) {
3265 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3266 _("migration was active, but RAM 'transferred' "
3267 "data was missing"));
3268 return -1;
3269 }
3270 if (virJSONValueObjectGetNumberUlong(ram, "remaining",
3271 &stats->ram_remaining) < 0) {
3272 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3273 _("migration was active, but RAM 'remaining' "
3274 "data was missing"));
3275 return -1;
3276 }
3277 if (virJSONValueObjectGetNumberUlong(ram, "total",
3278 &stats->ram_total) < 0) {
3279 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3280 _("migration was active, but RAM 'total' "
3281 "data was missing"));
3282 return -1;
3283 }
3284
3285 if (virJSONValueObjectGetNumberDouble(ram, "mbps", &mbps) == 0 &&
3286 mbps > 0) {
3287 /* mpbs from QEMU reports Mbits/s (M as in 10^6 not Mi as 2^20) */
3288 stats->ram_bps = mbps * (1000 * 1000 / 8);
3289 }
3290
3291 if (virJSONValueObjectGetNumberUlong(ram, "duplicate",
3292 &stats->ram_duplicate) == 0)
3293 stats->ram_duplicate_set = true;
3294 ignore_value(virJSONValueObjectGetNumberUlong(ram, "normal",
3295 &stats->ram_normal));
3296 ignore_value(virJSONValueObjectGetNumberUlong(ram, "normal-bytes",
3297 &stats->ram_normal_bytes));
3298 ignore_value(virJSONValueObjectGetNumberUlong(ram, "dirty-pages-rate",
3299 &stats->ram_dirty_rate));
3300 ignore_value(virJSONValueObjectGetNumberUlong(ram, "page-size",
3301 &stats->ram_page_size));
3302 ignore_value(virJSONValueObjectGetNumberUlong(ram, "dirty-sync-count",
3303 &stats->ram_iteration));
3304 ignore_value(virJSONValueObjectGetNumberUlong(ram, "postcopy-requests",
3305 &stats->ram_postcopy_reqs));
3306
3307 disk = virJSONValueObjectGetObject(ret, "disk");
3308 if (disk) {
3309 rc = virJSONValueObjectGetNumberUlong(disk, "transferred",
3310 &stats->disk_transferred);
3311 if (rc < 0) {
3312 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3313 _("disk migration was active, but "
3314 "'transferred' data was missing"));
3315 return -1;
3316 }
3317
3318 rc = virJSONValueObjectGetNumberUlong(disk, "remaining",
3319 &stats->disk_remaining);
3320 if (rc < 0) {
3321 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3322 _("disk migration was active, but 'remaining' "
3323 "data was missing"));
3324 return -1;
3325 }
3326
3327 rc = virJSONValueObjectGetNumberUlong(disk, "total",
3328 &stats->disk_total);
3329 if (rc < 0) {
3330 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3331 _("disk migration was active, but 'total' "
3332 "data was missing"));
3333 return -1;
3334 }
3335
3336 if (virJSONValueObjectGetNumberDouble(disk, "mbps", &mbps) == 0 &&
3337 mbps > 0) {
3338 /* mpbs from QEMU reports Mbits/s (M as in 10^6 not Mi as 2^20) */
3339 stats->disk_bps = mbps * (1000 * 1000 / 8);
3340 }
3341 }
3342
3343 comp = virJSONValueObjectGetObject(ret, "xbzrle-cache");
3344 if (comp) {
3345 stats->xbzrle_set = true;
3346 rc = virJSONValueObjectGetNumberUlong(comp, "cache-size",
3347 &stats->xbzrle_cache_size);
3348 if (rc < 0) {
3349 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3350 _("XBZRLE is active, but 'cache-size' data "
3351 "was missing"));
3352 return -1;
3353 }
3354
3355 rc = virJSONValueObjectGetNumberUlong(comp, "bytes",
3356 &stats->xbzrle_bytes);
3357 if (rc < 0) {
3358 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3359 _("XBZRLE is active, but 'bytes' data "
3360 "was missing"));
3361 return -1;
3362 }
3363
3364 rc = virJSONValueObjectGetNumberUlong(comp, "pages",
3365 &stats->xbzrle_pages);
3366 if (rc < 0) {
3367 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3368 _("XBZRLE is active, but 'pages' data "
3369 "was missing"));
3370 return -1;
3371 }
3372
3373 rc = virJSONValueObjectGetNumberUlong(comp, "cache-miss",
3374 &stats->xbzrle_cache_miss);
3375 if (rc < 0) {
3376 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3377 _("XBZRLE is active, but 'cache-miss' data "
3378 "was missing"));
3379 return -1;
3380 }
3381
3382 rc = virJSONValueObjectGetNumberUlong(comp, "overflow",
3383 &stats->xbzrle_overflow);
3384 if (rc < 0) {
3385 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3386 _("XBZRLE is active, but 'overflow' data "
3387 "was missing"));
3388 return -1;
3389 }
3390 }
3391 break;
3392 }
3393
3394 return 0;
3395 }
3396
3397
3398 int qemuMonitorJSONGetMigrationStats(qemuMonitorPtr mon,
3399 qemuMonitorMigrationStatsPtr stats,
3400 char **error)
3401 {
3402 int ret = -1;
3403 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-migrate",
3404 NULL);
3405 virJSONValuePtr reply = NULL;
3406
3407 memset(stats, 0, sizeof(*stats));
3408
3409 if (!cmd)
3410 return -1;
3411
3412 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3413 goto cleanup;
3414
3415 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
3416 goto cleanup;
3417
3418 if (qemuMonitorJSONGetMigrationStatsReply(reply, stats, error) < 0)
3419 goto cleanup;
3420
3421 ret = 0;
3422 cleanup:
3423 if (ret < 0)
3424 memset(stats, 0, sizeof(*stats));
3425 virJSONValueFree(cmd);
3426 virJSONValueFree(reply);
3427 return ret;
3428 }
3429
3430
3431 int qemuMonitorJSONMigrate(qemuMonitorPtr mon,
3432 unsigned int flags,
3433 const char *uri)
3434 {
3435 int ret = -1;
3436 virJSONValuePtr cmd =
3437 qemuMonitorJSONMakeCommand("migrate",
3438 "b:detach", flags & QEMU_MONITOR_MIGRATE_BACKGROUND ? 1 : 0,
3439 "b:blk", flags & QEMU_MONITOR_MIGRATE_NON_SHARED_DISK ? 1 : 0,
3440 "b:inc", flags & QEMU_MONITOR_MIGRATE_NON_SHARED_INC ? 1 : 0,
3441 "s:uri", uri,
3442 NULL);
3443 virJSONValuePtr reply = NULL;
3444
3445 if (!cmd)
3446 return -1;
3447
3448 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3449 goto cleanup;
3450
3451 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
3452 goto cleanup;
3453
3454 ret = 0;
3455 cleanup:
3456 virJSONValueFree(cmd);
3457 virJSONValueFree(reply);
3458 return ret;
3459 }
3460
3461 int qemuMonitorJSONMigrateCancel(qemuMonitorPtr mon)
3462 {
3463 int ret = -1;
3464 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("migrate_cancel", NULL);
3465 virJSONValuePtr reply = NULL;
3466 if (!cmd)
3467 return -1;
3468
3469 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3470 goto cleanup;
3471
3472 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
3473 goto cleanup;
3474
3475 ret = 0;
3476 cleanup:
3477 virJSONValueFree(cmd);
3478 virJSONValueFree(reply);
3479 return ret;
3480 }
3481
3482
3483 /* qemuMonitorJSONQueryDump:
3484 * @mon: Monitor pointer
3485 * @stats: Monitor dump stats
3486 *
3487 * Attempt to make a "query-dump" call, check for errors, and get/return
3488 * the current from the reply
3489 *
3490 * Returns: 0 on success, -1 on failure
3491 */
3492 int
3493 qemuMonitorJSONQueryDump(qemuMonitorPtr mon,
3494 qemuMonitorDumpStatsPtr stats)
3495 {
3496 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-dump", NULL);
3497 virJSONValuePtr reply = NULL;
3498 virJSONValuePtr result = NULL;
3499 int ret = -1;
3500
3501 if (!cmd)
3502 return -1;
3503
3504 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3505 goto cleanup;
3506
3507 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
3508 goto cleanup;
3509
3510 result = virJSONValueObjectGetObject(reply, "return");
3511
3512 ret = qemuMonitorJSONExtractDumpStats(result, stats);
3513
3514 cleanup:
3515 virJSONValueFree(cmd);
3516 virJSONValueFree(reply);
3517 return ret;
3518 }
3519
3520
3521 int
3522 qemuMonitorJSONGetDumpGuestMemoryCapability(qemuMonitorPtr mon,
3523 const char *capability)
3524 {
3525 int ret = -1;
3526 virJSONValuePtr cmd;
3527 virJSONValuePtr reply = NULL;
3528 virJSONValuePtr caps;
3529 virJSONValuePtr formats;
3530 size_t i;
3531
3532 if (!(cmd = qemuMonitorJSONMakeCommand("query-dump-guest-memory-capability",
3533 NULL)))
3534 return -1;
3535
3536 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3537 goto cleanup;
3538
3539 if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
3540 ret = 0;
3541 goto cleanup;
3542 }
3543
3544 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
3545 goto cleanup;
3546
3547 caps = virJSONValueObjectGetObject(reply, "return");
3548
3549 if (!(formats = virJSONValueObjectGetArray(caps, "formats"))) {
3550 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3551 _("missing supported dump formats"));
3552 goto cleanup;
3553 }
3554
3555 for (i = 0; i < virJSONValueArraySize(formats); i++) {
3556 virJSONValuePtr dumpformat = virJSONValueArrayGet(formats, i);
3557
3558 if (!dumpformat || virJSONValueGetType(dumpformat) != VIR_JSON_TYPE_STRING) {
3559 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3560 _("missing entry in supported dump formats"));
3561 goto cleanup;
3562 }
3563
3564 if (STREQ(virJSONValueGetString(dumpformat), capability)) {
3565 ret = 1;
3566 goto cleanup;
3567 }
3568 }
3569
3570 ret = 0;
3571 cleanup:
3572 virJSONValueFree(cmd);
3573 virJSONValueFree(reply);
3574 return ret;
3575 }
3576
3577 int
3578 qemuMonitorJSONDump(qemuMonitorPtr mon,
3579 const char *protocol,
3580 const char *dumpformat,
3581 bool detach)
3582 {
3583 int ret = -1;
3584 virJSONValuePtr cmd = NULL;
3585 virJSONValuePtr reply = NULL;
3586
3587 cmd = qemuMonitorJSONMakeCommand("dump-guest-memory",
3588 "b:paging", false,
3589 "s:protocol", protocol,
3590 "S:format", dumpformat,
3591 "B:detach", detach,
3592 NULL);
3593 if (!cmd)
3594 return -1;
3595
3596 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3597 goto cleanup;
3598
3599 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
3600 goto cleanup;
3601
3602 ret = 0;
3603 cleanup:
3604 virJSONValueFree(cmd);
3605 virJSONValueFree(reply);
3606 return ret;
3607 }
3608
3609 int qemuMonitorJSONGraphicsRelocate(qemuMonitorPtr mon,
3610 int type,
3611 const char *hostname,
3612 int port,
3613 int tlsPort,
3614 const char *tlsSubject)
3615 {
3616 int ret = -1;
3617 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("client_migrate_info",
3618 "s:protocol",
3619 (type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE ? "spice" : "vnc"),
3620 "s:hostname", hostname,
3621 "i:port", port,
3622 "i:tls-port", tlsPort,
3623 "S:cert-subject", tlsSubject,
3624 NULL);
3625 virJSONValuePtr reply = NULL;
3626 if (!cmd)
3627 return -1;
3628
3629 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3630 goto cleanup;
3631
3632 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
3633 goto cleanup;
3634
3635 ret = 0;
3636 cleanup:
3637 virJSONValueFree(cmd);
3638 virJSONValueFree(reply);
3639 return ret;
3640 }
3641
3642
3643 int qemuMonitorJSONSendFileHandle(qemuMonitorPtr mon,
3644 const char *fdname,
3645 int fd)
3646 {
3647 int ret = -1;
3648 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("getfd",
3649 "s:fdname", fdname,
3650 NULL);
3651 virJSONValuePtr reply = NULL;
3652 if (!cmd)
3653 return -1;
3654
3655 if (qemuMonitorJSONCommandWithFd(mon, cmd, fd, &reply) < 0)
3656 goto cleanup;
3657
3658 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
3659 goto cleanup;
3660
3661 ret = 0;
3662 cleanup:
3663 virJSONValueFree(cmd);
3664 virJSONValueFree(reply);
3665 return ret;
3666 }
3667
3668
3669 int qemuMonitorJSONCloseFileHandle(qemuMonitorPtr mon,
3670 const char *fdname)
3671 {
3672 int ret = -1;
3673 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("closefd",
3674 "s:fdname", fdname,
3675 NULL);
3676 virJSONValuePtr reply = NULL;
3677 if (!cmd)
3678 return -1;
3679
3680 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3681 goto cleanup;
3682
3683 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
3684 goto cleanup;
3685
3686 ret = 0;
3687 cleanup:
3688 virJSONValueFree(cmd);
3689 virJSONValueFree(reply);
3690 return ret;
3691 }
3692
3693
3694 int
3695 qemuMonitorJSONAddFd(qemuMonitorPtr mon, int fdset, int fd, const char *name)
3696 {
3697 int ret;
3698 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("add-fd",
3699 "i:fdset-id", fdset,
3700 "S:opaque", name,
3701 NULL);
3702 virJSONValuePtr reply = NULL;
3703 if (!cmd)
3704 return -1;
3705
3706 ret = qemuMonitorJSONCommandWithFd(mon, cmd, fd, &reply);
3707
3708 if (ret == 0) {
3709 /* qemu 1.2 lacks the functionality we need; but we have to
3710 * probe to find that out. Don't log errors in that case. */
3711 if (STREQ_NULLABLE(name, "/dev/null") &&
3712 qemuMonitorJSONHasError(reply, "GenericError")) {
3713 ret = -2;
3714 goto cleanup;
3715 }
3716 ret = qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT);
3717 }
3718 if (ret == 0) {
3719 virJSONValuePtr data = virJSONValueObjectGetObject(reply, "return");
3720
3721 if (virJSONValueObjectGetNumberInt(data, "fd", &ret) < 0) {
3722 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3723 _("incomplete return information"));
3724 goto error;
3725 }
3726 }
3727
3728 cleanup:
3729 virJSONValueFree(cmd);
3730 virJSONValueFree(reply);
3731 return ret;
3732
3733 error:
3734 /* Best effort cleanup - kill the entire fdset (even if it has
3735 * earlier successful fd registrations), since we don't know which
3736 * fd qemu got, and don't want to leave the fd leaked in qemu. */
3737 qemuMonitorJSONRemoveFd(mon, fdset, -1);
3738 ret = -1;
3739 goto cleanup;
3740 }
3741
3742
3743 int
3744 qemuMonitorJSONRemoveFd(qemuMonitorPtr mon, int fdset, int fd)
3745 {
3746 int ret = -1;
3747 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("remove-fd",
3748 "i:fdset-id", fdset,
3749 fd < 0 ? NULL : "i:fd",
3750 fd, NULL);
3751 virJSONValuePtr reply = NULL;
3752 if (!cmd)
3753 return -1;
3754
3755 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3756 goto cleanup;
3757
3758 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
3759 goto cleanup;
3760
3761 ret = 0;
3762 cleanup:
3763 virJSONValueFree(cmd);
3764 virJSONValueFree(reply);
3765 return ret;
3766 }
3767
3768
3769 int qemuMonitorJSONAddNetdev(qemuMonitorPtr mon,
3770 const char *netdevstr)
3771 {
3772 int ret = -1;
3773 virJSONValuePtr cmd = NULL;
3774 virJSONValuePtr reply = NULL;
3775 virJSONValuePtr args = NULL;
3776
3777 cmd = qemuMonitorJSONMakeCommand("netdev_add", NULL);
3778 if (!cmd)
3779 return -1;
3780
3781 args = qemuMonitorJSONKeywordStringToJSON(netdevstr, "type");
3782 if (!args)
3783 goto cleanup;
3784
3785 if (virJSONValueObjectAppend(cmd, "arguments", args) < 0)
3786 goto cleanup;
3787 args = NULL; /* obj owns reference to args now */
3788
3789 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3790 goto cleanup;
3791
3792 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
3793 goto cleanup;
3794
3795 ret = 0;
3796 cleanup:
3797 virJSONValueFree(args);
3798 virJSONValueFree(cmd);
3799 virJSONValueFree(reply);
3800 return ret;
3801 }
3802
3803
3804 int qemuMonitorJSONRemoveNetdev(qemuMonitorPtr mon,
3805 const char *alias)
3806 {
3807 int ret = -1;
3808 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("netdev_del",
3809 "s:id", alias,
3810 NULL);
3811 virJSONValuePtr reply = NULL;
3812 if (!cmd)
3813 return -1;
3814
3815 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
3816 goto cleanup;
3817
3818 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
3819 goto cleanup;
3820
3821 ret = 0;
3822 cleanup:
3823 virJSONValueFree(cmd);
3824 virJSONValueFree(reply);
3825 return ret;
3826 }
3827
3828
3829 static int
3830 qemuMonitorJSONQueryRxFilterParse(virJSONValuePtr msg,
3831 virNetDevRxFilterPtr *filter)
3832 {
3833 int ret = -1;
3834 const char *tmp;
3835 virJSONValuePtr returnArray, entry, table, element;
3836 size_t nTable;
3837 size_t i;
3838 virNetDevRxFilterPtr fil = virNetDevRxFilterNew();
3839
3840 if (!fil)
3841 goto cleanup;
3842
3843 returnArray = virJSONValueObjectGetArray(msg, "return");
3844
3845 if (!(entry = virJSONValueArrayGet(returnArray, 0))) {
3846 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3847 _("query -rx-filter return data missing array element"));
3848 goto cleanup;
3849 }
3850
3851 if (!(tmp = virJSONValueObjectGetString(entry, "name"))) {
3852 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3853 _("Missing or invalid name "
3854 "in query-rx-filter response"));
3855 goto cleanup;
3856 }
3857 if (VIR_STRDUP(fil->name, tmp) < 0)
3858 goto cleanup;
3859 if ((!(tmp = virJSONValueObjectGetString(entry, "main-mac"))) ||
3860 virMacAddrParse(tmp, &fil->mac) < 0) {
3861 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3862 _("Missing or invalid 'main-mac' "
3863 "in query-rx-filter response"));
3864 goto cleanup;
3865 }
3866 if (virJSONValueObjectGetBoolean(entry, "promiscuous",
3867 &fil->promiscuous) < 0) {
3868 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3869 _("Missing or invalid 'promiscuous' "
3870 "in query-rx-filter response"));
3871 goto cleanup;
3872 }
3873 if (virJSONValueObjectGetBoolean(entry, "broadcast-allowed",
3874 &fil->broadcastAllowed) < 0) {
3875 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3876 _("Missing or invalid 'broadcast-allowed' "
3877 "in query-rx-filter response"));
3878 goto cleanup;
3879 }
3880
3881 if ((!(tmp = virJSONValueObjectGetString(entry, "unicast"))) ||
3882 ((fil->unicast.mode
3883 = virNetDevRxFilterModeTypeFromString(tmp)) < 0)) {
3884 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3885 _("Missing or invalid 'unicast' "
3886 "in query-rx-filter response"));
3887 goto cleanup;
3888 }
3889 if (virJSONValueObjectGetBoolean(entry, "unicast-overflow",
3890 &fil->unicast.overflow) < 0) {
3891 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3892 _("Missing or invalid 'unicast-overflow' "
3893 "in query-rx-filter response"));
3894 goto cleanup;
3895 }
3896 if ((!(table = virJSONValueObjectGet(entry, "unicast-table"))) ||
3897 (!virJSONValueIsArray(table))) {
3898 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3899 _("Missing or invalid 'unicast-table' array "
3900 "in query-rx-filter response"));
3901 goto cleanup;
3902 }
3903 nTable = virJSONValueArraySize(table);
3904 if (VIR_ALLOC_N(fil->unicast.table, nTable))
3905 goto cleanup;
3906 for (i = 0; i < nTable; i++) {
3907 if (!(element = virJSONValueArrayGet(table, i)) ||
3908 !(tmp = virJSONValueGetString(element))) {
3909 virReportError(VIR_ERR_INTERNAL_ERROR,
3910 _("Missing or invalid element %zu of 'unicast' "
3911 "list in query-rx-filter response"), i);
3912 goto cleanup;
3913 }
3914 if (virMacAddrParse(tmp, &fil->unicast.table[i]) < 0) {
3915 virReportError(VIR_ERR_INTERNAL_ERROR,
3916 _("invalid mac address '%s' in 'unicast-table' "
3917 "array in query-rx-filter response"), tmp);
3918 goto cleanup;
3919 }
3920 }
3921 fil->unicast.nTable = nTable;
3922
3923 if ((!(tmp = virJSONValueObjectGetString(entry, "multicast"))) ||
3924 ((fil->multicast.mode
3925 = virNetDevRxFilterModeTypeFromString(tmp)) < 0)) {
3926 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3927 _("Missing or invalid 'multicast' "
3928 "in query-rx-filter response"));
3929 goto cleanup;
3930 }
3931 if (virJSONValueObjectGetBoolean(entry, "multicast-overflow",
3932 &fil->multicast.overflow) < 0) {
3933 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3934 _("Missing or invalid 'multicast-overflow' "
3935 "in query-rx-filter response"));
3936 goto cleanup;
3937 }
3938 if ((!(table = virJSONValueObjectGet(entry, "multicast-table"))) ||
3939 (!virJSONValueIsArray(table))) {
3940 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3941 _("Missing or invalid 'multicast-table' array "
3942 "in query-rx-filter response"));
3943 goto cleanup;
3944 }
3945 nTable = virJSONValueArraySize(table);
3946 if (VIR_ALLOC_N(fil->multicast.table, nTable))
3947 goto cleanup;
3948 for (i = 0; i < nTable; i++) {
3949 if (!(element = virJSONValueArrayGet(table, i)) ||
3950 !(tmp = virJSONValueGetString(element))) {
3951 virReportError(VIR_ERR_INTERNAL_ERROR,
3952 _("Missing or invalid element %zu of 'multicast' "
3953 "list in query-rx-filter response"), i);
3954 goto cleanup;
3955 }
3956 if (virMacAddrParse(tmp, &fil->multicast.table[i]) < 0) {
3957 virReportError(VIR_ERR_INTERNAL_ERROR,
3958 _("invalid mac address '%s' in 'multicast-table' "
3959 "array in query-rx-filter response"), tmp);
3960 goto cleanup;
3961 }
3962 }
3963 fil->multicast.nTable = nTable;
3964
3965 if ((!(tmp = virJSONValueObjectGetString(entry, "vlan"))) ||
3966 ((fil->vlan.mode
3967 = virNetDevRxFilterModeTypeFromString(tmp)) < 0)) {
3968 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3969 _("Missing or invalid 'vlan' "
3970 "in query-rx-filter response"));
3971 goto cleanup;
3972 }
3973 if ((!(table = virJSONValueObjectGet(entry, "vlan-table"))) ||
3974 (!virJSONValueIsArray(table))) {
3975 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3976 _("Missing or invalid 'vlan-table' array "
3977 "in query-rx-filter response"));
3978 goto cleanup;
3979 }
3980 nTable = virJSONValueArraySize(table);
3981 if (VIR_ALLOC_N(fil->vlan.table, nTable))
3982 goto cleanup;
3983 for (i = 0; i < nTable; i++) {
3984 if (!(element = virJSONValueArrayGet(table, i)) ||
3985 virJSONValueGetNumberUint(element, &fil->vlan.table[i]) < 0) {
3986 virReportError(VIR_ERR_INTERNAL_ERROR,
3987 _("Missing or invalid element %zu of 'vlan-table' "
3988 "array in query-rx-filter response"), i);
3989 goto cleanup;
3990 }
3991 }
3992 fil->vlan.nTable = nTable;
3993
3994 ret = 0;
3995 cleanup:
3996 if (ret < 0) {
3997 virNetDevRxFilterFree(fil);
3998 fil = NULL;
3999 }
4000 *filter = fil;
4001 return ret;
4002 }
4003
4004
4005 int
4006 qemuMonitorJSONQueryRxFilter(qemuMonitorPtr mon, const char *alias,
4007 virNetDevRxFilterPtr *filter)
4008 {
4009 int ret = -1;
4010 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-rx-filter",
4011 "s:name", alias,
4012 NULL);
4013 virJSONValuePtr reply = NULL;
4014
4015 if (!cmd)
4016 goto cleanup;
4017
4018 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4019 goto cleanup;
4020
4021 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
4022 goto cleanup;
4023
4024 if (qemuMonitorJSONQueryRxFilterParse(reply, filter) < 0)
4025 goto cleanup;
4026
4027 ret = 0;
4028 cleanup:
4029 if (ret < 0) {
4030 virNetDevRxFilterFree(*filter);
4031 *filter = NULL;
4032 }
4033 virJSONValueFree(cmd);
4034 virJSONValueFree(reply);
4035 return ret;
4036 }
4037
4038
4039 /*
4040 * Example return data
4041 *
4042 * {"return": [
4043 * {"filename": "stdio", "label": "monitor"},
4044 * {"filename": "pty:/dev/pts/6", "label": "serial0", "frontend-open": true},
4045 * {"filename": "pty:/dev/pts/7", "label": "parallel0"}
4046 * ]}
4047 *
4048 */
4049 static int
4050 qemuMonitorJSONExtractChardevInfo(virJSONValuePtr reply,
4051 virHashTablePtr info)
4052 {
4053 virJSONValuePtr data;
4054 int ret = -1;
4055 size_t i;
4056 qemuMonitorChardevInfoPtr entry = NULL;
4057
4058 data = virJSONValueObjectGetArray(reply, "return");
4059
4060 for (i = 0; i < virJSONValueArraySize(data); i++) {
4061 virJSONValuePtr chardev = virJSONValueArrayGet(data, i);
4062 const char *type;
4063 const char *alias;
4064 bool connected;
4065
4066 if (!chardev) {
4067 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4068 _("character device information was missing array element"));
4069 goto cleanup;
4070 }
4071
4072 if (!(alias = virJSONValueObjectGetString(chardev, "label"))) {
4073 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4074 _("character device information was missing label"));
4075 goto cleanup;
4076 }
4077
4078 if (!(type = virJSONValueObjectGetString(chardev, "filename"))) {
4079 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4080 _("character device information was missing filename"));
4081 goto cleanup;
4082 }
4083
4084 if (VIR_ALLOC(entry) < 0)
4085 goto cleanup;
4086
4087 if (STRPREFIX(type, "pty:") &&
4088 VIR_STRDUP(entry->ptyPath, type + strlen("pty:")) < 0)
4089 goto cleanup;
4090
4091 if (virJSONValueObjectGetBoolean(chardev, "frontend-open", &connected) == 0) {
4092 if (connected)
4093 entry->state = VIR_DOMAIN_CHR_DEVICE_STATE_CONNECTED;
4094 else
4095 entry->state = VIR_DOMAIN_CHR_DEVICE_STATE_DISCONNECTED;
4096 }
4097
4098 if (virHashAddEntry(info, alias, entry) < 0) {
4099 virReportError(VIR_ERR_OPERATION_FAILED,
4100 _("failed to add chardev '%s' info"), alias);
4101 goto cleanup;
4102 }
4103
4104 entry = NULL;
4105 }
4106
4107 ret = 0;
4108
4109 cleanup:
4110 if (entry) {
4111 VIR_FREE(entry->ptyPath);
4112 VIR_FREE(entry);
4113 }
4114
4115 return ret;
4116 }
4117
4118
4119 int
4120 qemuMonitorJSONGetChardevInfo(qemuMonitorPtr mon,
4121 virHashTablePtr info)
4122
4123 {
4124 int ret = -1;
4125 virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-chardev",
4126 NULL);
4127 virJSONValuePtr reply = NULL;
4128
4129 if (!cmd)
4130 return -1;
4131
4132 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4133 goto cleanup;
4134
4135 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
4136 goto cleanup;
4137
4138 ret = qemuMonitorJSONExtractChardevInfo(reply, info);
4139 cleanup:
4140 virJSONValueFree(cmd);
4141 virJSONValueFree(reply);
4142 return ret;
4143 }
4144
4145
4146 int qemuMonitorJSONDelDevice(qemuMonitorPtr mon,
4147 const char *devalias)
4148 {
4149 int ret = -1;
4150 virJSONValuePtr cmd;
4151 virJSONValuePtr reply = NULL;
4152
4153 cmd = qemuMonitorJSONMakeCommand("device_del",
4154 "s:id", devalias,
4155 NULL);
4156 if (!cmd)
4157 return -1;
4158
4159 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4160 goto cleanup;
4161
4162 if (qemuMonitorJSONHasError(reply, "DeviceNotFound")) {
4163 ret = -2;
4164 goto cleanup;
4165 }
4166
4167 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
4168 goto cleanup;
4169
4170 ret = 0;
4171 cleanup:
4172 virJSONValueFree(cmd);
4173 virJSONValueFree(reply);
4174 return ret;
4175 }
4176
4177
4178 int
4179 qemuMonitorJSONAddDeviceArgs(qemuMonitorPtr mon,
4180 virJSONValuePtr args)
4181 {
4182 int ret = -1;
4183 virJSONValuePtr cmd = NULL;
4184 virJSONValuePtr reply = NULL;
4185
4186 if (!(cmd = qemuMonitorJSONMakeCommand("device_add", NULL)))
4187 goto cleanup;
4188
4189 if (virJSONValueObjectAppend(cmd, "arguments", args) < 0)
4190 goto cleanup;
4191 args = NULL; /* obj owns reference to args now */
4192
4193 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4194 goto cleanup;
4195
4196 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
4197 goto cleanup;
4198
4199 ret = 0;
4200 cleanup:
4201 virJSONValueFree(args);
4202 virJSONValueFree(cmd);
4203 virJSONValueFree(reply);
4204 return ret;
4205 }
4206
4207
4208 int
4209 qemuMonitorJSONAddDevice(qemuMonitorPtr mon,
4210 const char *devicestr)
4211 {
4212 virJSONValuePtr args;
4213
4214 if (!(args = qemuMonitorJSONKeywordStringToJSON(devicestr, "driver")))
4215 return -1;
4216
4217 return qemuMonitorJSONAddDeviceArgs(mon, args);
4218 }
4219
4220
4221 int
4222 qemuMonitorJSONAddObject(qemuMonitorPtr mon,
4223 virJSONValuePtr props)
4224 {
4225 int ret = -1;
4226 virJSONValuePtr cmd;
4227 virJSONValuePtr reply = NULL;
4228
4229 if (!(cmd = qemuMonitorJSONMakeCommandInternal("object-add", props)))
4230 goto cleanup;
4231
4232 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4233 goto cleanup;
4234
4235 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
4236 goto cleanup;
4237
4238 ret = 0;
4239 cleanup:
4240 virJSONValueFree(cmd);
4241 virJSONValueFree(reply);
4242 return ret;
4243 }
4244
4245
4246 int qemuMonitorJSONDelObject(qemuMonitorPtr mon,
4247 const char *objalias)
4248 {
4249 int ret = -1;
4250 virJSONValuePtr cmd;
4251 virJSONValuePtr reply = NULL;
4252
4253 cmd = qemuMonitorJSONMakeCommand("object-del",
4254 "s:id", objalias,
4255 NULL);
4256 if (!cmd)
4257 return -1;
4258
4259 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4260 goto cleanup;
4261
4262 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
4263 goto cleanup;
4264
4265 ret = 0;
4266 cleanup:
4267 virJSONValueFree(cmd);
4268 virJSONValueFree(reply);
4269 return ret;
4270 }
4271
4272
4273 /* speed is in bytes/sec */
4274 int
4275 qemuMonitorJSONDriveMirror(qemuMonitorPtr mon,
4276 const char *device, const char *file,
4277 const char *format, unsigned long long speed,
4278 unsigned int granularity,
4279 unsigned long long buf_size,
4280 bool shallow,
4281 bool reuse)
4282 {
4283 VIR_AUTOPTR(virJSONValue) cmd = NULL;
4284 VIR_AUTOPTR(virJSONValue) reply = NULL;
4285
4286 cmd = qemuMonitorJSONMakeCommand("drive-mirror",
4287 "s:device", device,
4288 "s:target", file,
4289 "Y:speed", speed,
4290 "z:granularity", granularity,
4291 "P:buf-size", buf_size,
4292 "s:sync", shallow ? "top" : "full",
4293 "s:mode", reuse ? "existing" : "absolute-paths",
4294 "S:format", format,
4295 NULL);
4296 if (!cmd)
4297 return -1;
4298
4299 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4300 return -1;
4301
4302 return qemuMonitorJSONCheckError(cmd, reply);
4303 }
4304
4305
4306 int
4307 qemuMonitorJSONBlockdevMirror(qemuMonitorPtr mon,
4308 const char *jobname,
4309 const char *device,
4310 const char *target,
4311 unsigned long long speed,
4312 unsigned int granularity,
4313 unsigned long long buf_size,
4314 bool shallow)
4315 {
4316 VIR_AUTOPTR(virJSONValue) cmd = NULL;
4317 VIR_AUTOPTR(virJSONValue) reply = NULL;
4318
4319 cmd = qemuMonitorJSONMakeCommand("blockdev-mirror",
4320 "S:job-id", jobname,
4321 "s:device", device,
4322 "s:target", target,
4323 "Y:speed", speed,
4324 "z:granularity", granularity,
4325 "P:buf-size", buf_size,
4326 "s:sync", shallow ? "top" : "full",
4327 NULL);
4328 if (!cmd)
4329 return -1;
4330
4331 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4332 return -1;
4333
4334 return qemuMonitorJSONCheckError(cmd, reply);
4335 }
4336
4337
4338 int
4339 qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr *actions)
4340 {
4341 int ret = -1;
4342 virJSONValuePtr cmd;
4343 virJSONValuePtr reply = NULL;
4344
4345 cmd = qemuMonitorJSONMakeCommand("transaction",
4346 "a:actions", actions,
4347 NULL);
4348 if (!cmd)
4349 goto cleanup;
4350
4351 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4352 goto cleanup;
4353
4354 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
4355 goto cleanup;
4356
4357 ret = 0;
4358 cleanup:
4359 virJSONValueFree(cmd);
4360 virJSONValueFree(reply);
4361 return ret;
4362 }
4363
4364 /* Probe if active commit is supported: pass in a bogus device and NULL top
4365 * and base. The probe return is true if active commit is detected or false
4366 * if not supported or on any error */
4367 bool
4368 qemuMonitorJSONSupportsActiveCommit(qemuMonitorPtr mon)
4369 {
4370 bool ret = false;
4371 virJSONValuePtr cmd;
4372 virJSONValuePtr reply = NULL;
4373
4374 if (!(cmd = qemuMonitorJSONMakeCommand("block-commit", "s:device",
4375 "bogus", NULL)))
4376 return false;
4377
4378 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4379 goto cleanup;
4380
4381 if (qemuMonitorJSONHasError(reply, "DeviceNotFound")) {
4382 VIR_DEBUG("block-commit supports active commit");
4383 ret = true;
4384 goto cleanup;
4385 }
4386
4387 /* This is a false negative for qemu 2.0; but probably not
4388 * worth the additional complexity to worry about it */
4389 VIR_DEBUG("block-commit requires 'top' parameter, "
4390 "assuming it lacks active commit");
4391 cleanup:
4392 virJSONValueFree(cmd);
4393 virJSONValueFree(reply);
4394 return ret;
4395 }
4396
4397
4398 /* speed is in bytes/sec. Returns 0 on success, -1 with error message
4399 * emitted on failure. */
4400 int
4401 qemuMonitorJSONBlockCommit(qemuMonitorPtr mon, const char *device,
4402 const char *top, const char *base,
4403 const char *backingName,
4404 unsigned long long speed)
4405 {
4406 int ret = -1;
4407 virJSONValuePtr cmd;
4408 virJSONValuePtr reply = NULL;
4409
4410 cmd = qemuMonitorJSONMakeCommand("block-commit",
4411 "s:device", device,
4412 "Y:speed", speed,
4413 "S:top", top,
4414 "S:base", base,
4415 "S:backing-file", backingName,
4416 NULL);
4417 if (!cmd)
4418 return -1;
4419
4420 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4421 goto cleanup;
4422
4423 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
4424 goto cleanup;
4425
4426 ret = 0;
4427 cleanup:
4428 virJSONValueFree(cmd);
4429 virJSONValueFree(reply);
4430 return ret;
4431 }
4432
4433
4434 static char *
4435 qemuMonitorJSONDiskNameLookupOne(virJSONValuePtr image,
4436 virStorageSourcePtr top,
4437 virStorageSourcePtr target)
4438 {
4439 virJSONValuePtr backing;
4440 char *ret;
4441
4442 /* The caller will report a generic message if we return NULL
4443 * without an error; but in some cases we can improve by reporting
4444 * a more specific message. */
4445 if (!top || !image)
4446 return NULL;
4447 if (top != target) {
4448 backing = virJSONValueObjectGetObject(image, "backing-image");
4449 return qemuMonitorJSONDiskNameLookupOne(backing, top->backingStore,
4450 target);
4451 }
4452 if (VIR_STRDUP(ret, virJSONValueObjectGetString(image, "filename")) < 0)
4453 return NULL;
4454 /* Sanity check - the name qemu gave us should resolve to the same
4455 file tracked by our target description. */
4456 if (virStorageSourceIsLocalStorage(target) &&
4457 STRNEQ(ret, target->path) &&
4458 !virFileLinkPointsTo(ret, target->path)) {
4459 virReportError(VIR_ERR_INTERNAL_ERROR,
4460 _("qemu block name '%s' doesn't match expected '%s'"),
4461 ret, target->path);
4462 VIR_FREE(ret);
4463 }
4464 return ret;
4465 }
4466
4467
4468 char *
4469 qemuMonitorJSONDiskNameLookup(qemuMonitorPtr mon,
4470 const char *device,
4471 virStorageSourcePtr top,
4472 virStorageSourcePtr target)
4473 {
4474 char *ret = NULL;
4475 virJSONValuePtr devices;
4476 size_t i;
4477
4478 if (!(devices = qemuMonitorJSONQueryBlock(mon)))
4479 return NULL;
4480
4481 for (i = 0; i < virJSONValueArraySize(devices); i++) {
4482 virJSONValuePtr dev;
4483 virJSONValuePtr inserted;
4484 virJSONValuePtr image;
4485 const char *thisdev;
4486
4487 if (!(dev = qemuMonitorJSONGetBlockDev(devices, i)))
4488 goto cleanup;
4489
4490 if (!(thisdev = qemuMonitorJSONGetBlockDevDevice(dev)))
4491 goto cleanup;
4492
4493 if (STREQ(thisdev, device)) {
4494 if ((inserted = virJSONValueObjectGetObject(dev, "inserted")) &&
4495 (image = virJSONValueObjectGetObject(inserted, "image"))) {
4496 ret = qemuMonitorJSONDiskNameLookupOne(image, top, target);
4497 }
4498 break;
4499 }
4500 }
4501 /* Guarantee an error when returning NULL, but don't override a
4502 * more specific error if one was already generated. */
4503 if (!ret && virGetLastErrorCode() == VIR_ERR_OK)
4504 virReportError(VIR_ERR_INTERNAL_ERROR,
4505 _("unable to find backing name for device %s"),
4506 device);
4507
4508 cleanup:
4509 virJSONValueFree(devices);
4510
4511 return ret;
4512 }
4513
4514
4515 int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon,
4516 const char *cmd_str,
4517 char **reply_str,
4518 bool hmp)
4519 {
4520 virJSONValuePtr cmd = NULL;
4521 virJSONValuePtr reply = NULL;
4522 int ret = -1;
4523
4524 if (hmp) {
4525 return qemuMonitorJSONHumanCommandWithFd(mon, cmd_str, -1, reply_str);
4526 } else {
4527 if (!(cmd = virJSONValueFromString(cmd_str)))
4528 goto cleanup;
4529
4530 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4531 goto cleanup;
4532
4533 if (!(*reply_str = virJSONValueToString(reply, false)))
4534 goto cleanup;
4535 }
4536
4537 ret = 0;
4538
4539 cleanup:
4540 virJSONValueFree(cmd);
4541 virJSONValueFree(reply);
4542 return ret;
4543 }
4544
4545 int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon)
4546 {
4547 int ret = -1;
4548 virJSONValuePtr cmd;
4549 virJSONValuePtr reply = NULL;
4550
4551 cmd = qemuMonitorJSONMakeCommand("inject-nmi", NULL);
4552 if (!cmd)
4553 return -1;
4554
4555 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4556 goto cleanup;
4557
4558 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
4559 goto cleanup;
4560
4561 ret = 0;
4562 cleanup:
4563 virJSONValueFree(cmd);
4564 virJSONValueFree(reply);
4565 return ret;
4566 }
4567
4568 int qemuMonitorJSONSendKey(qemuMonitorPtr mon,
4569 unsigned int holdtime,
4570 unsigned int *keycodes,
4571 unsigned int nkeycodes)
4572 {
4573 int ret = -1;
4574 virJSONValuePtr cmd = NULL;
4575 virJSONValuePtr reply = NULL;
4576 virJSONValuePtr keys = NULL;
4577 virJSONValuePtr key = NULL;
4578 size_t i;
4579
4580 /* create the key data array */
4581 if (!(keys = virJSONValueNewArray()))
4582 goto cleanup;
4583
4584 for (i = 0; i < nkeycodes; i++) {
4585 if (keycodes[i] > 0xffff) {
4586 virReportError(VIR_ERR_OPERATION_FAILED,
4587 _("keycode %zu is invalid: 0x%X"), i, keycodes[i]);
4588 goto cleanup;
4589 }
4590
4591 /* create single key object */
4592 if (!(key = virJSONValueNewObject()))
4593 goto cleanup;
4594
4595 /* Union KeyValue has two types, use the generic one */
4596 if (virJSONValueObjectAppendString(key, "type", "number") < 0)
4597 goto cleanup;
4598
4599 /* with the keycode */
4600 if (virJSONValueObjectAppendNumberInt(key, "data", keycodes[i]) < 0)
4601 goto cleanup;
4602
4603 if (virJSONValueArrayAppend(keys, key) < 0)
4604 goto cleanup;
4605
4606 key = NULL;
4607
4608 }
4609
4610 cmd = qemuMonitorJSONMakeCommand("send-key",
4611 "a:keys", &keys,
4612 "p:hold-time", holdtime,
4613 NULL);
4614 if (!cmd)
4615 goto cleanup;
4616
4617 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4618 goto cleanup;
4619
4620 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
4621 goto cleanup;
4622
4623 ret = 0;
4624 cleanup:
4625 virJSONValueFree(cmd);
4626 virJSONValueFree(reply);
4627 virJSONValueFree(keys);
4628 virJSONValueFree(key);
4629 return ret;
4630 }
4631
4632 int qemuMonitorJSONScreendump(qemuMonitorPtr mon,
4633 const char *device,
4634 unsigned int head,
4635 const char *file)
4636 {
4637 int ret = -1;
4638 virJSONValuePtr cmd, reply = NULL;
4639
4640 cmd = qemuMonitorJSONMakeCommand("screendump",
4641 "s:filename", file,
4642 "S:device", device,
4643 "p:head", head,
4644 NULL);
4645
4646 if (!cmd)
4647 return -1;
4648
4649 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4650 goto cleanup;
4651
4652 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
4653 goto cleanup;
4654
4655 ret = 0;
4656 cleanup:
4657 virJSONValueFree(cmd);
4658 virJSONValueFree(reply);
4659 return ret;
4660 }
4661
4662
4663 static int
4664 qemuMonitorJSONParseBlockJobInfo(virHashTablePtr blockJobs,
4665 virJSONValuePtr entry)
4666 {
4667 qemuMonitorBlockJobInfoPtr info = NULL;
4668 const char *device;
4669 const char *type;
4670 bool ready;
4671
4672 if (!(device = virJSONValueObjectGetString(entry, "device"))) {
4673 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4674 _("entry was missing 'device'"));
4675 return -1;
4676 }
4677 device = qemuAliasDiskDriveSkipPrefix(device);
4678
4679 if (VIR_ALLOC(info) < 0 ||
4680 virHashAddEntry(blockJobs, device, info) < 0) {
4681 VIR_FREE(info);
4682 return -1;
4683 }
4684
4685 /* assume we don't know the state */
4686 info->ready = -1;
4687
4688 if (!(type = virJSONValueObjectGetString(entry, "type"))) {
4689 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4690 _("entry was missing 'type'"));
4691 return -1;
4692 }
4693 if (STREQ(type, "stream"))
4694 info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_PULL;
4695 else if (STREQ(type, "commit"))
4696 info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT;
4697 else if (STREQ(type, "mirror"))
4698 info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_COPY;
4699 else
4700 info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
4701
4702 if (virJSONValueObjectGetNumberUlong(entry, "speed", &info->bandwidth) < 0) {
4703 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4704 _("entry was missing 'speed'"));
4705 return -1;
4706 }
4707
4708 if (virJSONValueObjectGetNumberUlong(entry, "offset", &info->cur) < 0) {
4709 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4710 _("entry was missing 'offset'"));
4711 return -1;
4712 }
4713
4714 if (virJSONValueObjectGetNumberUlong(entry, "len", &info->end) < 0) {
4715 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4716 _("entry was missing 'len'"));
4717 return -1;
4718 }
4719
4720 if (virJSONValueObjectGetBoolean(entry, "ready", &ready) == 0)
4721 info->ready = ready;
4722
4723 return 0;
4724 }
4725
4726 virHashTablePtr
4727 qemuMonitorJSONGetAllBlockJobInfo(qemuMonitorPtr mon)
4728 {
4729 virJSONValuePtr cmd = NULL;
4730 virJSONValuePtr reply = NULL;
4731 virJSONValuePtr data;
4732 size_t nr_results;
4733 size_t i;
4734 virHashTablePtr blockJobs = NULL;
4735
4736 cmd = qemuMonitorJSONMakeCommand("query-block-jobs", NULL);
4737 if (!cmd)
4738 return NULL;
4739 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4740 goto cleanup;
4741
4742 if ((data = virJSONValueObjectGetArray(reply, "return")) == NULL) {
4743 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4744 _("reply was missing return data"));
4745 goto cleanup;
4746 }
4747
4748 nr_results = virJSONValueArraySize(data);
4749 if (!(blockJobs = virHashCreate(nr_results, virHashValueFree)))
4750 goto cleanup;
4751
4752 for (i = 0; i < nr_results; i++) {
4753 virJSONValuePtr entry = virJSONValueArrayGet(data, i);
4754 if (!entry) {
4755 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4756 _("missing array element"));
4757 goto error;
4758 }
4759 if (qemuMonitorJSONParseBlockJobInfo(blockJobs, entry) < 0)
4760 goto error;
4761 }
4762
4763 cleanup:
4764 virJSONValueFree(cmd);
4765 virJSONValueFree(reply);
4766 return blockJobs;
4767
4768 error:
4769 virHashFree(blockJobs);
4770 blockJobs = NULL;
4771 goto cleanup;
4772 }
4773
4774
4775 static int
4776 qemuMonitorJSONBlockJobError(virJSONValuePtr cmd,
4777 virJSONValuePtr reply,
4778 const char *jobname)
4779 {
4780 virJSONValuePtr error;
4781
4782 if ((error = virJSONValueObjectGet(reply, "error")) &&
4783 (qemuMonitorJSONErrorIsClass(error, "DeviceNotActive"))) {
4784 virReportError(VIR_ERR_OPERATION_INVALID,
4785 _("No active block job '%s'"), jobname);
4786 return -1;
4787 }
4788
4789 return qemuMonitorJSONCheckError(cmd, reply);
4790 }
4791
4792
4793 /* speed is in bytes/sec */
4794 int
4795 qemuMonitorJSONBlockStream(qemuMonitorPtr mon,
4796 const char *device,
4797 const char *base,
4798 const char *backingName,
4799 unsigned long long speed)
4800 {
4801 int ret = -1;
4802 virJSONValuePtr cmd = NULL;
4803 virJSONValuePtr reply = NULL;
4804
4805 if (!(cmd = qemuMonitorJSONMakeCommand("block-stream",
4806 "s:device", device,
4807 "Y:speed", speed,
4808 "S:base", base,
4809 "S:backing-file", backingName,
4810 NULL)))
4811 return -1;
4812
4813 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4814 goto cleanup;
4815
4816 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
4817 goto cleanup;
4818
4819 ret = 0;
4820
4821 cleanup:
4822 virJSONValueFree(cmd);
4823 virJSONValueFree(reply);
4824 return ret;
4825 }
4826
4827
4828 int
4829 qemuMonitorJSONBlockJobCancel(qemuMonitorPtr mon,
4830 const char *jobname)
4831 {
4832 int ret = -1;
4833 virJSONValuePtr cmd = NULL;
4834 virJSONValuePtr reply = NULL;
4835
4836 if (!(cmd = qemuMonitorJSONMakeCommand("block-job-cancel",
4837 "s:device", jobname,
4838 NULL)))
4839 return -1;
4840
4841 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4842 goto cleanup;
4843
4844 if (qemuMonitorJSONBlockJobError(cmd, reply, jobname) < 0)
4845 goto cleanup;
4846
4847 ret = 0;
4848
4849 cleanup:
4850 virJSONValueFree(cmd);
4851 virJSONValueFree(reply);
4852 return ret;
4853 }
4854
4855
4856 int
4857 qemuMonitorJSONBlockJobSetSpeed(qemuMonitorPtr mon,
4858 const char *jobname,
4859 unsigned long long speed)
4860 {
4861 int ret = -1;
4862 virJSONValuePtr cmd;
4863 virJSONValuePtr reply = NULL;
4864
4865 if (!(cmd = qemuMonitorJSONMakeCommand("block-job-set-speed",
4866 "s:device", jobname,
4867 "J:speed", speed,
4868 NULL)))
4869 return -1;
4870
4871 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4872 goto cleanup;
4873
4874 if (qemuMonitorJSONBlockJobError(cmd, reply, jobname) < 0)
4875 goto cleanup;
4876
4877 ret = 0;
4878
4879 cleanup:
4880 virJSONValueFree(cmd);
4881 virJSONValueFree(reply);
4882 return ret;
4883 }
4884
4885
4886 int
4887 qemuMonitorJSONDrivePivot(qemuMonitorPtr mon,
4888 const char *jobname)
4889 {
4890 int ret = -1;
4891 virJSONValuePtr cmd;
4892 virJSONValuePtr reply = NULL;
4893
4894 cmd = qemuMonitorJSONMakeCommand("block-job-complete",
4895 "s:device", jobname,
4896 NULL);
4897 if (!cmd)
4898 return -1;
4899
4900 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4901 goto cleanup;
4902
4903 if (qemuMonitorJSONBlockJobError(cmd, reply, jobname) < 0)
4904 goto cleanup;
4905
4906 ret = 0;
4907 cleanup:
4908 virJSONValueFree(cmd);
4909 virJSONValueFree(reply);
4910 return ret;
4911 }
4912
4913
4914 int qemuMonitorJSONOpenGraphics(qemuMonitorPtr mon,
4915 const char *protocol,
4916 const char *fdname,
4917 bool skipauth)
4918 {
4919 int ret = -1;
4920 virJSONValuePtr cmd, reply = NULL;
4921
4922 cmd = qemuMonitorJSONMakeCommand("add_client",
4923 "s:protocol", protocol,
4924 "s:fdname", fdname,
4925 "b:skipauth", skipauth,
4926 NULL);
4927
4928 if (!cmd)
4929 return -1;
4930
4931 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
4932 goto cleanup;
4933
4934 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
4935 goto cleanup;
4936
4937 ret = 0;
4938 cleanup:
4939 virJSONValueFree(cmd);
4940 virJSONValueFree(reply);
4941 return ret;
4942 }
4943
4944
4945 #define GET_THROTTLE_STATS_OPTIONAL(FIELD, STORE) \
4946 if (virJSONValueObjectGetNumberUlong(inserted, \
4947 FIELD, \
4948 &reply->STORE) < 0) { \
4949 reply->STORE = 0; \
4950 }
4951 #define GET_THROTTLE_STATS(FIELD, STORE) \
4952 if (virJSONValueObjectGetNumberUlong(inserted, \
4953 FIELD, \
4954 &reply->STORE) < 0) { \
4955 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, \
4956 _("block_io_throttle field '%s' missing " \
4957 "in qemu's output"), \
4958 #STORE); \
4959 goto cleanup; \
4960 }
4961 static int
4962 qemuMonitorJSONBlockIoThrottleInfo(virJSONValuePtr io_throttle,
4963 const char *drivealias,
4964 const char *qdevid,
4965 virDomainBlockIoTuneInfoPtr reply)
4966 {
4967 int ret = -1;
4968 size_t i;
4969 bool found = false;
4970
4971 for (i = 0; i < virJSONValueArraySize(io_throttle); i++) {
4972 virJSONValuePtr temp_dev = virJSONValueArrayGet(io_throttle, i);
4973 virJSONValuePtr inserted;
4974 const char *current_drive;
4975 const char *current_qdev;
4976
4977 if (!temp_dev || virJSONValueGetType(temp_dev) != VIR_JSON_TYPE_OBJECT) {
4978 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4979 _("block_io_throttle device entry "
4980 "was not in expected format"));
4981 goto cleanup;
4982 }
4983
4984 current_qdev = virJSONValueObjectGetString(temp_dev, "qdev");
4985 current_drive = virJSONValueObjectGetString(temp_dev, "device");
4986
4987 if (!current_drive && !current_qdev) {
4988 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4989 _("block_io_throttle device entry "
4990 "was not in expected format"));
4991 goto cleanup;
4992 }
4993
4994 if ((drivealias && current_drive && STRNEQ(current_drive, drivealias)) ||
4995 (qdevid && current_qdev && STRNEQ(current_qdev, qdevid)))
4996 continue;
4997
4998 found = true;
4999 if (!(inserted = virJSONValueObjectGetObject(temp_dev, "inserted"))) {
5000 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5001 _("block_io_throttle inserted entry "
5002 "was not in expected format"));
5003 goto cleanup;
5004 }
5005 GET_THROTTLE_STATS("bps", total_bytes_sec);
5006 GET_THROTTLE_STATS("bps_rd", read_bytes_sec);
5007 GET_THROTTLE_STATS("bps_wr", write_bytes_sec);
5008 GET_THROTTLE_STATS("iops", total_iops_sec);
5009 GET_THROTTLE_STATS("iops_rd", read_iops_sec);
5010 GET_THROTTLE_STATS("iops_wr", write_iops_sec);
5011 GET_THROTTLE_STATS_OPTIONAL("bps_max", total_bytes_sec_max);
5012 GET_THROTTLE_STATS_OPTIONAL("bps_rd_max", read_bytes_sec_max);
5013 GET_THROTTLE_STATS_OPTIONAL("bps_wr_max", write_bytes_sec_max);
5014 GET_THROTTLE_STATS_OPTIONAL("iops_max", total_iops_sec_max);
5015 GET_THROTTLE_STATS_OPTIONAL("iops_rd_max", read_iops_sec_max);
5016 GET_THROTTLE_STATS_OPTIONAL("iops_wr_max", write_iops_sec_max);
5017 GET_THROTTLE_STATS_OPTIONAL("iops_size", size_iops_sec);
5018
5019 if (VIR_STRDUP(reply->group_name,
5020 virJSONValueObjectGetString(inserted, "group")) < 0)
5021 goto cleanup;
5022
5023 GET_THROTTLE_STATS_OPTIONAL("bps_max_length", total_bytes_sec_max_length);
5024 GET_THROTTLE_STATS_OPTIONAL("bps_rd_max_length", read_bytes_sec_max_length);
5025 GET_THROTTLE_STATS_OPTIONAL("bps_wr_max_length", write_bytes_sec_max_length);
5026 GET_THROTTLE_STATS_OPTIONAL("iops_max_length", total_iops_sec_max_length);
5027 GET_THROTTLE_STATS_OPTIONAL("iops_rd_max_length", read_iops_sec_max_length);
5028 GET_THROTTLE_STATS_OPTIONAL("iops_wr_max_length", write_iops_sec_max_length);
5029
5030 break;
5031 }
5032
5033 if (!found) {
5034 virReportError(VIR_ERR_INTERNAL_ERROR,
5035 _("cannot find throttling info for device '%s'"),
5036 drivealias ? drivealias : qdevid);
5037 goto cleanup;
5038 }
5039 ret = 0;
5040
5041 cleanup:
5042 return ret;
5043 }
5044 #undef GET_THROTTLE_STATS
5045 #undef GET_THROTTLE_STATS_OPTIONAL
5046
5047 int qemuMonitorJSONSetBlockIoThrottle(qemuMonitorPtr mon,
5048 const char *drivealias,
5049 const char *qomid,
5050 virDomainBlockIoTuneInfoPtr info,
5051 bool supportMaxOptions,
5052 bool supportGroupNameOption,
5053 bool supportMaxLengthOptions)
5054 {
5055 int ret = -1;
5056 virJSONValuePtr cmd = NULL;
5057 virJSONValuePtr result = NULL;
5058 virJSONValuePtr args = NULL;
5059 const char *errdev = drivealias;
5060
5061 if (!errdev)
5062 errdev = qomid;
5063
5064 if (!(cmd = qemuMonitorJSONMakeCommand("block_set_io_throttle", NULL)))
5065 return -1;
5066
5067 if (virJSONValueObjectCreate(&args,
5068 "S:device", drivealias,
5069 "S:id", qomid,
5070 "U:bps", info->total_bytes_sec,
5071 "U:bps_rd", info->read_bytes_sec,
5072 "U:bps_wr", info->write_bytes_sec,
5073 "U:iops", info->total_iops_sec,
5074 "U:iops_rd", info->read_iops_sec,
5075 "U:iops_wr", info->write_iops_sec,
5076 NULL) < 0)
5077 goto cleanup;
5078
5079 if (supportMaxOptions &&
5080 virJSONValueObjectAdd(args,
5081 "U:bps_max", info->total_bytes_sec_max,
5082 "U:bps_rd_max", info->read_bytes_sec_max,
5083 "U:bps_wr_max", info->write_bytes_sec_max,
5084 "U:iops_max", info->total_iops_sec_max,
5085 "U:iops_rd_max", info->read_iops_sec_max,
5086 "U:iops_wr_max", info->write_iops_sec_max,
5087 "U:iops_size", info->size_iops_sec,
5088 NULL) < 0)
5089 goto cleanup;
5090
5091 if (supportGroupNameOption &&
5092 virJSONValueObjectAdd(args,
5093 "S:group", info->group_name,
5094 NULL) < 0)
5095 goto cleanup;
5096
5097 if (supportMaxLengthOptions &&
5098 virJSONValueObjectAdd(args,
5099 "P:bps_max_length",
5100 info->total_bytes_sec_max_length,
5101 "P:bps_rd_max_length",
5102 info->read_bytes_sec_max_length,
5103 "P:bps_wr_max_length",
5104 info->write_bytes_sec_max_length,
5105 "P:iops_max_length",
5106 info->total_iops_sec_max_length,
5107 "P:iops_rd_max_length",
5108 info->read_iops_sec_max_length,
5109 "P:iops_wr_max_length",
5110 info->write_iops_sec_max_length,
5111 NULL) < 0)
5112 goto cleanup;
5113
5114 if (virJSONValueObjectAppend(cmd, "arguments", args) < 0)
5115 goto cleanup;
5116 args = NULL; /* obj owns reference to args now */
5117
5118 if (qemuMonitorJSONCommand(mon, cmd, &result) < 0)
5119 goto cleanup;
5120
5121 if (virJSONValueObjectHasKey(result, "error")) {
5122 if (qemuMonitorJSONHasError(result, "DeviceNotActive")) {
5123 virReportError(VIR_ERR_OPERATION_INVALID,
5124 _("No active operation on device: %s"), errdev);
5125 } else if (qemuMonitorJSONHasError(result, "NotSupported")) {
5126 virReportError(VIR_ERR_OPERATION_INVALID,
5127 _("Operation is not supported for device: %s"), errdev);
5128 } else {
5129 virJSONValuePtr error = virJSONValueObjectGet(result, "error");
5130 virReportError(VIR_ERR_INTERNAL_ERROR,
5131 _("unable to execute '%s', unexpected error: '%s'"),
5132 qemuMonitorJSONCommandName(cmd),
5133 qemuMonitorJSONStringifyError(error));
5134 }
5135 goto cleanup;
5136 }
5137
5138 ret = 0;
5139 cleanup:
5140 virJSONValueFree(cmd);
5141 virJSONValueFree(result);
5142 virJSONValueFree(args);
5143 return ret;
5144 }
5145
5146 int qemuMonitorJSONGetBlockIoThrottle(qemuMonitorPtr mon,
5147 const char *drivealias,
5148 const char *qdevid,
5149 virDomainBlockIoTuneInfoPtr reply)
5150 {
5151 int ret = -1;
5152 virJSONValuePtr devices = NULL;
5153
5154 if (!(devices = qemuMonitorJSONQueryBlock(mon)))
5155 return -1;
5156
5157 ret = qemuMonitorJSONBlockIoThrottleInfo(devices, drivealias, qdevid, reply);
5158 virJSONValueFree(devices);
5159 return ret;
5160 }
5161
5162 int qemuMonitorJSONSystemWakeup(qemuMonitorPtr mon)
5163 {
5164 int ret = -1;
5165 virJSONValuePtr cmd = NULL;
5166 virJSONValuePtr reply = NULL;
5167
5168 cmd = qemuMonitorJSONMakeCommand("system_wakeup", NULL);
5169 if (!cmd)
5170 return -1;
5171
5172 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
5173 goto cleanup;
5174
5175 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
5176 goto cleanup;
5177
5178 ret = 0;
5179 cleanup:
5180 virJSONValueFree(cmd);
5181 virJSONValueFree(reply);
5182 return ret;
5183 }
5184
5185 int qemuMonitorJSONGetVersion(qemuMonitorPtr mon,
5186 int *major,
5187 int *minor,
5188 int *micro,
5189 char **package)
5190 {
5191 int ret = -1;
5192 virJSONValuePtr cmd;
5193 virJSONValuePtr reply = NULL;
5194 virJSONValuePtr data;
5195 virJSONValuePtr qemu;
5196
5197 *major = *minor = *micro = 0;
5198 if (package)
5199 *package = NULL;
5200
5201 if (!(cmd = qemuMonitorJSONMakeCommand("query-version", NULL)))
5202 return -1;
5203
5204 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
5205 goto cleanup;
5206
5207 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
5208 goto cleanup;
5209
5210 data = virJSONValueObjectGetObject(reply, "return");
5211
5212 if (!(qemu = virJSONValueObjectGetObject(data, "qemu"))) {
5213 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5214 _("query-version reply was missing 'qemu' data"));
5215 goto cleanup;
5216 }
5217
5218 if (virJSONValueObjectGetNumberInt(qemu, "major", major) < 0) {
5219 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5220 _("query-version reply was missing 'major' version"));
5221 goto cleanup;
5222 }
5223 if (virJSONValueObjectGetNumberInt(qemu, "minor", minor) < 0) {
5224 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5225 _("query-version reply was missing 'minor' version"));
5226 goto cleanup;
5227 }
5228 if (virJSONValueObjectGetNumberInt(qemu, "micro", micro) < 0) {
5229 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5230 _("query-version reply was missing 'micro' version"));
5231 goto cleanup;
5232 }
5233
5234 if (package) {
5235 const char *tmp;
5236 if (!(tmp = virJSONValueObjectGetString(data, "package"))) {
5237 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5238 _("query-version reply was missing 'package' version"));
5239 goto cleanup;
5240 }
5241 if (VIR_STRDUP(*package, tmp) < 0)
5242 goto cleanup;
5243 }
5244
5245 ret = 0;
5246
5247 cleanup:
5248 virJSONValueFree(cmd);
5249 virJSONValueFree(reply);
5250 return ret;
5251 }
5252
5253
5254 int qemuMonitorJSONGetMachines(qemuMonitorPtr mon,
5255 qemuMonitorMachineInfoPtr **machines)
5256 {
5257 int ret = -1;
5258 virJSONValuePtr cmd;
5259 virJSONValuePtr reply = NULL;
5260 virJSONValuePtr data;
5261 qemuMonitorMachineInfoPtr *infolist = NULL;
5262 size_t n = 0;
5263 size_t i;
5264
5265 *machines = NULL;
5266
5267 if (!(cmd = qemuMonitorJSONMakeCommand("query-machines", NULL)))
5268 return -1;
5269
5270 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
5271 goto cleanup;
5272
5273 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
5274 goto cleanup;
5275
5276 data = virJSONValueObjectGetArray(reply, "return");
5277 n = virJSONValueArraySize(data);
5278
5279 /* null-terminated list */
5280 if (VIR_ALLOC_N(infolist, n + 1) < 0)
5281 goto cleanup;
5282
5283 for (i = 0; i < n; i++) {
5284 virJSONValuePtr child = virJSONValueArrayGet(data, i);
5285 const char *tmp;
5286 qemuMonitorMachineInfoPtr info;
5287
5288 if (VIR_ALLOC(info) < 0)
5289 goto cleanup;
5290
5291 infolist[i] = info;
5292
5293 if (!(tmp = virJSONValueObjectGetString(child, "name"))) {
5294 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5295 _("query-machines reply data was missing 'name'"));
5296 goto cleanup;
5297 }
5298
5299 if (VIR_STRDUP(info->name, tmp) < 0)
5300 goto cleanup;
5301
5302 if (virJSONValueObjectHasKey(child, "is-default") &&
5303 virJSONValueObjectGetBoolean(child, "is-default", &info->isDefault) < 0) {
5304 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5305 _("query-machines reply has malformed 'is-default' data"));
5306 goto cleanup;
5307 }
5308
5309 if (virJSONValueObjectHasKey(child, "alias")) {
5310 if (!(tmp = virJSONValueObjectGetString(child, "alias"))) {
5311 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5312 _("query-machines reply has malformed 'alias' data"));
5313 goto cleanup;
5314 }
5315 if (VIR_STRDUP(info->alias, tmp) < 0)
5316 goto cleanup;
5317 }
5318 if (virJSONValueObjectHasKey(child, "cpu-max") &&
5319 virJSONValueObjectGetNumberUint(child, "cpu-max", &info->maxCpus) < 0) {
5320 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5321 _("query-machines reply has malformed 'cpu-max' data"));
5322 goto cleanup;
5323 }
5324
5325 ignore_value(virJSONValueObjectGetBoolean(child, "hotpluggable-cpus",
5326 &info->hotplugCpus));
5327 }
5328
5329 ret = n;
5330 *machines = infolist;
5331 infolist = NULL;
5332
5333 cleanup:
5334 if (infolist) {
5335 for (i = 0; i < n; i++)
5336 qemuMonitorMachineInfoFree(infolist[i]);
5337 VIR_FREE(infolist);
5338 }
5339 virJSONValueFree(cmd);
5340 virJSONValueFree(reply);
5341 return ret;
5342 }
5343
5344
5345 int
5346 qemuMonitorJSONGetCPUDefinitions(qemuMonitorPtr mon,
5347 qemuMonitorCPUDefInfoPtr **cpus)
5348 {
5349 int ret = -1;
5350 virJSONValuePtr cmd;
5351 virJSONValuePtr reply = NULL;
5352 virJSONValuePtr data;
5353 qemuMonitorCPUDefInfoPtr *cpulist = NULL;
5354 size_t n = 0;
5355 size_t i;
5356
5357 *cpus = NULL;
5358
5359 if (!(cmd = qemuMonitorJSONMakeCommand("query-cpu-definitions", NULL)))
5360 return -1;
5361
5362 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
5363 goto cleanup;
5364
5365 /* Urgh, some QEMU architectures have the query-cpu-definitions
5366 * command, but return 'GenericError' with string "Not supported",
5367 * instead of simply omitting the command entirely :-(
5368 */
5369 if (qemuMonitorJSONHasError(reply, "GenericError")) {
5370 ret = 0;
5371 goto cleanup;
5372 }
5373
5374 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
5375 goto cleanup;
5376
5377 data = virJSONValueObjectGetArray(reply, "return");
5378 n = virJSONValueArraySize(data);
5379
5380 if (VIR_ALLOC_N(cpulist, n) < 0)
5381 goto cleanup;
5382
5383 for (i = 0; i < n; i++) {
5384 virJSONValuePtr child = virJSONValueArrayGet(data, i);
5385 const char *tmp;
5386 qemuMonitorCPUDefInfoPtr cpu;
5387
5388 if (VIR_ALLOC(cpu) < 0)
5389 goto cleanup;
5390
5391 cpulist[i] = cpu;
5392
5393 if (!(tmp = virJSONValueObjectGetString(child, "name"))) {
5394 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5395 _("query-cpu-definitions reply data was missing 'name'"));
5396 goto cleanup;
5397 }
5398
5399 if (VIR_STRDUP(cpu->name, tmp) < 0)
5400 goto cleanup;
5401
5402 if (virJSONValueObjectHasKey(child, "unavailable-features")) {
5403 virJSONValuePtr blockers;
5404 size_t j;
5405 size_t len;
5406
5407 blockers = virJSONValueObjectGetArray(child,
5408 "unavailable-features");
5409 if (!blockers) {
5410 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5411 _("unavailable-features in query-cpu-definitions "
5412 "reply data was not an array"));
5413 goto cleanup;
5414 }
5415
5416 len = virJSONValueArraySize(blockers);
5417
5418 if (len == 0) {
5419 cpu->usable = VIR_TRISTATE_BOOL_YES;
5420 continue;
5421 }
5422
5423 cpu->usable = VIR_TRISTATE_BOOL_NO;
5424 if (VIR_ALLOC_N(cpu->blockers, len + 1) < 0)
5425 goto cleanup;
5426
5427 for (j = 0; j < len; j++) {
5428 virJSONValuePtr blocker = virJSONValueArrayGet(blockers, j);
5429
5430 if (virJSONValueGetType(blocker) != VIR_JSON_TYPE_STRING) {
5431 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5432 _("unexpected value in unavailable-features "
5433 "array"));
5434 goto cleanup;
5435 }
5436
5437 if (VIR_STRDUP(cpu->blockers[j], virJSONValueGetString(blocker)) < 0)
5438 goto cleanup;
5439 }
5440 }
5441 }
5442
5443 ret = n;
5444 *cpus = cpulist;
5445 cpulist = NULL;
5446
5447 cleanup:
5448 if (cpulist) {
5449 for (i = 0; i < n; i++)
5450 qemuMonitorCPUDefInfoFree(cpulist[i]);
5451 VIR_FREE(cpulist);
5452 }
5453 virJSONValueFree(cmd);
5454 virJSONValueFree(reply);
5455 return ret;
5456 }
5457
5458
5459 VIR_ENUM_IMPL(qemuMonitorCPUProperty,
5460 QEMU_MONITOR_CPU_PROPERTY_LAST,
5461 "boolean", "string", "number",
5462 );
5463
5464 static int
5465 qemuMonitorJSONParseCPUModelProperty(const char *key,
5466 virJSONValue *value,
5467 void *opaque)
5468 {
5469 qemuMonitorCPUModelInfoPtr machine_model = opaque;
5470 qemuMonitorCPUPropertyPtr prop;
5471
5472 prop = machine_model->props + machine_model->nprops;
5473
5474 switch ((virJSONType)virJSONValueGetType(value)) {
5475 case VIR_JSON_TYPE_STRING:
5476 if (VIR_STRDUP(prop->value.string, virJSONValueGetString(value)) < 0)
5477 return -1;
5478 prop->type = QEMU_MONITOR_CPU_PROPERTY_STRING;
5479 break;
5480
5481 case VIR_JSON_TYPE_NUMBER:
5482 /* Ignore numbers which cannot be parsed as unsigned long long */
5483 if (virJSONValueGetNumberLong(value, &prop->value.number) < 0)
5484 return 0;
5485 prop->type = QEMU_MONITOR_CPU_PROPERTY_NUMBER;
5486 break;
5487
5488 case VIR_JSON_TYPE_BOOLEAN:
5489 virJSONValueGetBoolean(value, &prop->value.boolean);
5490 prop->type = QEMU_MONITOR_CPU_PROPERTY_BOOLEAN;
5491 break;
5492
5493 case VIR_JSON_TYPE_OBJECT:
5494 case VIR_JSON_TYPE_ARRAY:
5495 case VIR_JSON_TYPE_NULL:
5496 return 0;
5497 }
5498
5499 machine_model->nprops++;
5500 if (VIR_STRDUP(prop->name, key) < 0)
5501 return -1;
5502
5503 return 0;
5504 }
5505
5506 int
5507 qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon,
5508 qemuMonitorCPUModelExpansionType type,
5509 const char *model_name,
5510 bool migratable,
5511 qemuMonitorCPUModelInfoPtr *model_info)
5512 {
5513 int ret = -1;
5514 virJSONValuePtr model = NULL;
5515 virJSONValuePtr props = NULL;
5516 virJSONValuePtr cmd = NULL;
5517 virJSONValuePtr reply = NULL;
5518 virJSONValuePtr data;
5519 virJSONValuePtr cpu_model;
5520 virJSONValuePtr cpu_props;
5521 qemuMonitorCPUModelInfoPtr machine_model = NULL;
5522 char const *cpu_name;
5523 const char *typeStr = "";
5524
5525 *model_info = NULL;
5526
5527 if (!(model = virJSONValueNewObject()))
5528 goto cleanup;
5529
5530 if (virJSONValueObjectAppendString(model, "name", model_name) < 0)
5531 goto cleanup;
5532
5533 if (!migratable) {
5534 if (!(props = virJSONValueNewObject()) ||
5535 virJSONValueObjectAppendBoolean(props, "migratable", false) < 0 ||
5536 virJSONValueObjectAppend(model, "props", props) < 0)
5537 goto cleanup;
5538 props = NULL;
5539 }
5540
5541 retry:
5542 switch (type) {
5543 case QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC:
5544 case QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC_FULL:
5545 typeStr = "static";
5546 break;
5547
5548 case QEMU_MONITOR_CPU_MODEL_EXPANSION_FULL:
5549 typeStr = "full";
5550 break;
5551 }
5552
5553 if (!(cmd = qemuMonitorJSONMakeCommand("query-cpu-model-expansion",
5554 "s:type", typeStr,
5555 "a:model", &model,
5556 NULL)))
5557 goto cleanup;
5558
5559 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
5560 goto cleanup;
5561
5562 /* Even though query-cpu-model-expansion is advertised by query-commands it
5563 * may just return GenericError if it is not implemented for the requested
5564 * guest architecture or it is not supported in the host environment.
5565 */
5566 if (qemuMonitorJSONHasError(reply, "GenericError")) {
5567 ret = 0;
5568 goto cleanup;
5569 }
5570
5571 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
5572 goto cleanup;
5573
5574 data = virJSONValueObjectGetObject(reply, "return");
5575
5576 if (!(cpu_model = virJSONValueObjectGetObject(data, "model"))) {
5577 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5578 _("query-cpu-model-expansion reply data was missing 'model'"));
5579 goto cleanup;
5580 }
5581
5582 /* QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC_FULL requests "full" expansion
5583 * on the result of the initial "static" expansion.
5584 */
5585 if (type == QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC_FULL) {
5586 if (!(model = virJSONValueCopy(cpu_model)))
5587 goto cleanup;
5588
5589 virJSONValueFree(cmd);
5590 virJSONValueFree(reply);
5591 type = QEMU_MONITOR_CPU_MODEL_EXPANSION_FULL;
5592 goto retry;
5593 }
5594
5595 if (!(cpu_name = virJSONValueObjectGetString(cpu_model, "name"))) {
5596 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5597 _("query-cpu-model-expansion reply data was missing 'name'"));
5598 goto cleanup;
5599 }
5600
5601 if (!(cpu_props = virJSONValueObjectGetObject(cpu_model, "props"))) {
5602 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5603 _("query-cpu-model-expansion reply data was missing 'props'"));
5604 goto cleanup;
5605 }
5606
5607 if (VIR_ALLOC(machine_model) < 0)
5608 goto cleanup;
5609
5610 if (VIR_STRDUP(machine_model->name, cpu_name) < 0)
5611 goto cleanup;
5612
5613 if (VIR_ALLOC_N(machine_model->props, virJSONValueObjectKeysNumber(cpu_props)) < 0)
5614 goto cleanup;
5615
5616 if (virJSONValueObjectForeachKeyValue(cpu_props,
5617 qemuMonitorJSONParseCPUModelProperty,
5618 machine_model) < 0)
5619 goto cleanup;
5620
5621 ret = 0;
5622 *model_info = machine_model;
5623 machine_model = NULL;
5624
5625 cleanup:
5626 qemuMonitorCPUModelInfoFree(machine_model);
5627 virJSONValueFree(cmd);
5628 virJSONValueFree(reply);
5629 virJSONValueFree(model);
5630 virJSONValueFree(props);
5631 return ret;
5632 }
5633
5634
5635 int qemuMonitorJSONGetCommands(qemuMonitorPtr mon,
5636 char ***commands)
5637 {
5638 int ret = -1;
5639 virJSONValuePtr cmd;
5640 virJSONValuePtr reply = NULL;
5641 virJSONValuePtr data;
5642 char **commandlist = NULL;
5643 size_t n = 0;
5644 size_t i;
5645
5646 *commands = NULL;
5647
5648 if (!(cmd = qemuMonitorJSONMakeCommand("query-commands", NULL)))
5649 return -1;
5650
5651 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
5652 goto cleanup;
5653
5654 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
5655 goto cleanup;
5656
5657 data = virJSONValueObjectGetArray(reply, "return");
5658 n = virJSONValueArraySize(data);
5659
5660 /* null-terminated list */
5661 if (VIR_ALLOC_N(commandlist, n + 1) < 0)
5662 goto cleanup;
5663
5664 for (i = 0; i < n; i++) {
5665 virJSONValuePtr child = virJSONValueArrayGet(data, i);
5666 const char *tmp;
5667
5668 if (!(tmp = virJSONValueObjectGetString(child, "name"))) {
5669 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5670 _("query-commands reply data was missing 'name'"));
5671 goto cleanup;
5672 }
5673
5674 if (VIR_STRDUP(commandlist[i], tmp) < 0)
5675 goto cleanup;
5676 }
5677
5678 ret = n;
5679 *commands = commandlist;
5680 commandlist = NULL;
5681
5682
5683 cleanup:
5684 virStringListFree(commandlist);
5685 virJSONValueFree(cmd);
5686 virJSONValueFree(reply);
5687 return ret;
5688 }
5689
5690
5691 int qemuMonitorJSONGetEvents(qemuMonitorPtr mon,
5692 char ***events)
5693 {
5694 int ret = -1;
5695 virJSONValuePtr cmd;
5696 virJSONValuePtr reply = NULL;
5697 virJSONValuePtr data;
5698 char **eventlist = NULL;
5699 size_t n = 0;
5700 size_t i;
5701
5702 *events = NULL;
5703
5704 if (!(cmd = qemuMonitorJSONMakeCommand("query-events", NULL)))
5705 return -1;
5706
5707 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
5708 goto cleanup;
5709
5710 if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
5711 ret = 0;
5712 goto cleanup;
5713 }
5714
5715 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
5716 goto cleanup;
5717
5718 data = virJSONValueObjectGetArray(reply, "return");
5719 n = virJSONValueArraySize(data);
5720
5721 /* null-terminated list */
5722 if (VIR_ALLOC_N(eventlist, n + 1) < 0)
5723 goto cleanup;
5724
5725 for (i = 0; i < n; i++) {
5726 virJSONValuePtr child = virJSONValueArrayGet(data, i);
5727 const char *tmp;
5728
5729 if (!(tmp = virJSONValueObjectGetString(child, "name"))) {
5730 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5731 _("query-events reply data was missing 'name'"));
5732 goto cleanup;
5733 }
5734
5735 if (VIR_STRDUP(eventlist[i], tmp) < 0)
5736 goto cleanup;
5737 }
5738
5739 ret = n;
5740 *events = eventlist;
5741 eventlist = NULL;
5742
5743 cleanup:
5744 virStringListFree(eventlist);
5745 virJSONValueFree(cmd);
5746 virJSONValueFree(reply);
5747 return ret;
5748 }
5749
5750
5751 int
5752 qemuMonitorJSONGetCommandLineOptionParameters(qemuMonitorPtr mon,
5753 const char *option,
5754 char ***params,
5755 bool *found)
5756 {
5757 int ret = -1;
5758 virJSONValuePtr cmd = NULL;
5759 virJSONValuePtr reply = NULL;
5760 virJSONValuePtr data = NULL;
5761 virJSONValuePtr array = NULL;
5762 char **paramlist = NULL;
5763 size_t n = 0;
5764 size_t i;
5765
5766 *params = NULL;
5767 if (found)
5768 *found = false;
5769
5770 /* query-command-line-options has fixed output for a given qemu
5771 * binary; but since callers want to query parameters for one
5772 * option at a time, we cache the option list from qemu. */
5773 if (!(array = qemuMonitorGetOptions(mon))) {
5774 if (!(cmd = qemuMonitorJSONMakeCommand("query-command-line-options",
5775 NULL)))
5776 return -1;
5777
5778 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
5779 goto cleanup;
5780
5781 if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
5782 ret = 0;
5783 goto cleanup;
5784 }
5785
5786 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
5787 goto cleanup;
5788
5789 if (virJSONValueObjectRemoveKey(reply, "return", &array) <= 0) {
5790 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5791 _("query-command-line-options reply was missing "
5792 "return data"));
5793 goto cleanup;
5794 }
5795
5796 if (!virJSONValueIsArray(array)) {
5797 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5798 _("Malformed query-command-line-options array"));
5799 goto cleanup;
5800 }
5801
5802 qemuMonitorSetOptions(mon, array);
5803 }
5804
5805 for (i = 0; i < virJSONValueArraySize(array); i++) {
5806 virJSONValuePtr child = virJSONValueArrayGet(array, i);
5807 const char *tmp;
5808
5809 if (!(tmp = virJSONValueObjectGetString(child, "option"))) {
5810 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5811 _("query-command-line-options reply data was "
5812 "missing 'option'"));
5813 goto cleanup;
5814 }
5815 if (STREQ(tmp, option)) {
5816 data = virJSONValueObjectGet(child, "parameters");
5817 break;
5818 }
5819 }
5820
5821 if (!data) {
5822 /* Option not found; return 0 parameters rather than an error. */
5823 ret = 0;
5824 goto cleanup;
5825 }
5826
5827 if (found)
5828 *found = true;
5829
5830 if (!virJSONValueIsArray(data)) {
5831 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5832 _("Malformed query-command-line-options parameters array"));
5833 goto cleanup;
5834 }
5835 n = virJSONValueArraySize(data);
5836
5837 /* null-terminated list */
5838 if (VIR_ALLOC_N(paramlist, n + 1) < 0)
5839 goto cleanup;
5840
5841 for (i = 0; i < n; i++) {
5842 virJSONValuePtr child = virJSONValueArrayGet(data, i);
5843 const char *tmp;
5844
5845 if (!(tmp = virJSONValueObjectGetString(child, "name"))) {
5846 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5847 _("query-command-line-options parameter data was "
5848 "missing 'name'"));
5849 goto cleanup;
5850 }
5851
5852 if (VIR_STRDUP(paramlist[i], tmp) < 0)
5853 goto cleanup;
5854 }
5855
5856 ret = n;
5857 *params = paramlist;
5858 paramlist = NULL;
5859
5860 cleanup:
5861 /* If we failed before getting the JSON array of options, we (try)
5862 * to cache an empty array to speed up the next failure. */
5863 if (!qemuMonitorGetOptions(mon))
5864 qemuMonitorSetOptions(mon, virJSONValueNewArray());
5865
5866 virStringListFree(paramlist);
5867 virJSONValueFree(cmd);
5868 virJSONValueFree(reply);
5869 return ret;
5870 }
5871
5872
5873 int qemuMonitorJSONGetKVMState(qemuMonitorPtr mon,
5874 bool *enabled,
5875 bool *present)
5876 {
5877 int ret = -1;
5878 virJSONValuePtr cmd = NULL;
5879 virJSONValuePtr reply = NULL;
5880 virJSONValuePtr data = NULL;
5881
5882 /* Safe defaults */
5883 *enabled = *present = false;
5884
5885 if (!(cmd = qemuMonitorJSONMakeCommand("query-kvm", NULL)))
5886 return -1;
5887
5888 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
5889 goto cleanup;
5890
5891 if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
5892 ret = 0;
5893 goto cleanup;
5894 }
5895
5896 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
5897 goto cleanup;
5898
5899 data = virJSONValueObjectGetObject(reply, "return");
5900
5901 if (virJSONValueObjectGetBoolean(data, "enabled", enabled) < 0 ||
5902 virJSONValueObjectGetBoolean(data, "present", present) < 0) {
5903 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5904 _("query-kvm replied unexpected data"));
5905 goto cleanup;
5906 }
5907
5908 ret = 0;
5909
5910 cleanup:
5911 virJSONValueFree(cmd);
5912 virJSONValueFree(reply);
5913 return ret;
5914 }
5915
5916
5917 int qemuMonitorJSONGetObjectTypes(qemuMonitorPtr mon,
5918 char ***types)
5919 {
5920 int ret = -1;
5921 virJSONValuePtr cmd;
5922 virJSONValuePtr reply = NULL;
5923 virJSONValuePtr data;
5924 char **typelist = NULL;
5925 size_t n = 0;
5926 size_t i;
5927
5928 *types = NULL;
5929
5930 if (!(cmd = qemuMonitorJSONMakeCommand("qom-list-types", NULL)))
5931 return -1;
5932
5933 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
5934 goto cleanup;
5935
5936 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
5937 goto cleanup;
5938
5939 data = virJSONValueObjectGetArray(reply, "return");
5940 n = virJSONValueArraySize(data);
5941
5942 /* null-terminated list */
5943 if (VIR_ALLOC_N(typelist, n + 1) < 0)
5944 goto cleanup;
5945
5946 for (i = 0; i < n; i++) {
5947 virJSONValuePtr child = virJSONValueArrayGet(data, i);
5948 const char *tmp;
5949
5950 if (!(tmp = virJSONValueObjectGetString(child, "name"))) {
5951 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5952 _("qom-list-types reply data was missing 'name'"));
5953 goto cleanup;
5954 }
5955
5956 if (VIR_STRDUP(typelist[i], tmp) < 0)
5957 goto cleanup;
5958 }
5959
5960 ret = n;
5961 *types = typelist;
5962 typelist = NULL;
5963
5964 cleanup:
5965 virStringListFree(typelist);
5966 virJSONValueFree(cmd);
5967 virJSONValueFree(reply);
5968 return ret;
5969 }
5970
5971
5972 int qemuMonitorJSONGetObjectListPaths(qemuMonitorPtr mon,
5973 const char *path,
5974 qemuMonitorJSONListPathPtr **paths)
5975 {
5976 int ret = -1;
5977 virJSONValuePtr cmd;
5978 virJSONValuePtr reply = NULL;
5979 virJSONValuePtr data;
5980 qemuMonitorJSONListPathPtr *pathlist = NULL;
5981 size_t n = 0;
5982 size_t i;
5983
5984 *paths = NULL;
5985
5986 if (!(cmd = qemuMonitorJSONMakeCommand("qom-list",
5987 "s:path", path,
5988 NULL)))
5989 return -1;
5990
5991 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
5992 goto cleanup;
5993
5994 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
5995 goto cleanup;
5996
5997 data = virJSONValueObjectGetArray(reply, "return");
5998 n = virJSONValueArraySize(data);
5999
6000 /* null-terminated list */
6001 if (VIR_ALLOC_N(pathlist, n + 1) < 0)
6002 goto cleanup;
6003
6004 for (i = 0; i < n; i++) {
6005 virJSONValuePtr child = virJSONValueArrayGet(data, i);
6006 const char *tmp;
6007 qemuMonitorJSONListPathPtr info;
6008
6009 if (VIR_ALLOC(info) < 0)
6010 goto cleanup;
6011
6012 pathlist[i] = info;
6013
6014 if (!(tmp = virJSONValueObjectGetString(child, "name"))) {
6015 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6016 _("qom-list reply data was missing 'name'"));
6017 goto cleanup;
6018 }
6019
6020 if (VIR_STRDUP(info->name, tmp) < 0)
6021 goto cleanup;
6022
6023 if (virJSONValueObjectHasKey(child, "type")) {
6024 if (!(tmp = virJSONValueObjectGetString(child, "type"))) {
6025 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6026 _("qom-list reply has malformed 'type' data"));
6027 goto cleanup;
6028 }
6029 if (VIR_STRDUP(info->type, tmp) < 0)
6030 goto cleanup;
6031 }
6032 }
6033
6034 ret = n;
6035 *paths = pathlist;
6036 pathlist = NULL;
6037
6038 cleanup:
6039 if (pathlist) {
6040 for (i = 0; i < n; i++)
6041 qemuMonitorJSONListPathFree(pathlist[i]);
6042 VIR_FREE(pathlist);
6043 }
6044 virJSONValueFree(cmd);
6045 virJSONValueFree(reply);
6046 return ret;
6047 }
6048
6049 void qemuMonitorJSONListPathFree(qemuMonitorJSONListPathPtr paths)
6050 {
6051 if (!paths)
6052 return;
6053 VIR_FREE(paths->name);
6054 VIR_FREE(paths->type);
6055 VIR_FREE(paths);
6056 }
6057
6058
6059 int qemuMonitorJSONGetObjectProperty(qemuMonitorPtr mon,
6060 const char *path,
6061 const char *property,
6062 qemuMonitorJSONObjectPropertyPtr prop)
6063 {
6064 int ret = -1;
6065 virJSONValuePtr cmd;
6066 virJSONValuePtr reply = NULL;
6067 virJSONValuePtr data;
6068 const char *tmp;
6069
6070 if (!(cmd = qemuMonitorJSONMakeCommand("qom-get",
6071 "s:path", path,
6072 "s:property", property,
6073 NULL)))
6074 return -1;
6075
6076 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
6077 goto cleanup;
6078
6079 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
6080 goto cleanup;
6081
6082 data = virJSONValueObjectGet(reply, "return");
6083
6084 switch ((qemuMonitorJSONObjectPropertyType) prop->type) {
6085 /* Simple cases of boolean, int, long, uint, ulong, double, and string
6086 * will receive return value as part of {"return": xxx} statement
6087 */
6088 case QEMU_MONITOR_OBJECT_PROPERTY_BOOLEAN:
6089 ret = virJSONValueGetBoolean(data, &prop->val.b);
6090 break;
6091 case QEMU_MONITOR_OBJECT_PROPERTY_INT:
6092 ret = virJSONValueGetNumberInt(data, &prop->val.iv);
6093 break;
6094 case QEMU_MONITOR_OBJECT_PROPERTY_LONG:
6095 ret = virJSONValueGetNumberLong(data, &prop->val.l);
6096 break;
6097 case QEMU_MONITOR_OBJECT_PROPERTY_UINT:
6098 ret = virJSONValueGetNumberUint(data, &prop->val.ui);
6099 break;
6100 case QEMU_MONITOR_OBJECT_PROPERTY_ULONG:
6101 ret = virJSONValueGetNumberUlong(data, &prop->val.ul);
6102 break;
6103 case QEMU_MONITOR_OBJECT_PROPERTY_DOUBLE:
6104 ret = virJSONValueGetNumberDouble(data, &prop->val.d);
6105 break;
6106 case QEMU_MONITOR_OBJECT_PROPERTY_STRING:
6107 tmp = virJSONValueGetString(data);
6108 if (tmp && VIR_STRDUP(prop->val.str, tmp) < 0)
6109 goto cleanup;
6110 if (tmp)
6111 ret = 0;
6112 break;
6113 case QEMU_MONITOR_OBJECT_PROPERTY_LAST:
6114 virReportError(VIR_ERR_INTERNAL_ERROR,
6115 _("qom-get invalid object property type %d"),
6116 prop->type);
6117 goto cleanup;
6118 break;
6119 }
6120
6121 if (ret == -1) {
6122 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6123 _("qom-get reply was missing return data"));
6124 goto cleanup;
6125 }
6126
6127 ret = 0;
6128 cleanup:
6129 virJSONValueFree(cmd);
6130 virJSONValueFree(reply);
6131
6132 return ret;
6133 }
6134
6135
6136 #define MAKE_SET_CMD(STRING, VALUE) \
6137 cmd = qemuMonitorJSONMakeCommand("qom-set", \
6138 "s:path", path, \
6139 "s:property", property, \
6140 STRING, VALUE, \
6141 NULL)
6142 int qemuMonitorJSONSetObjectProperty(qemuMonitorPtr mon,
6143 const char *path,
6144 const char *property,
6145 qemuMonitorJSONObjectPropertyPtr prop)
6146 {
6147 int ret = -1;
6148 virJSONValuePtr cmd = NULL;
6149 virJSONValuePtr reply = NULL;
6150
6151 switch ((qemuMonitorJSONObjectPropertyType) prop->type) {
6152 /* Simple cases of boolean, int, long, uint, ulong, double, and string
6153 * will receive return value as part of {"return": xxx} statement
6154 */
6155 case QEMU_MONITOR_OBJECT_PROPERTY_BOOLEAN:
6156 MAKE_SET_CMD("b:value", prop->val.b);
6157 break;
6158 case QEMU_MONITOR_OBJECT_PROPERTY_INT:
6159 MAKE_SET_CMD("i:value", prop->val.iv);
6160 break;
6161 case QEMU_MONITOR_OBJECT_PROPERTY_LONG:
6162 MAKE_SET_CMD("I:value", prop->val.l);
6163 break;
6164 case QEMU_MONITOR_OBJECT_PROPERTY_UINT:
6165 MAKE_SET_CMD("u:value", prop->val.ui);
6166 break;
6167 case QEMU_MONITOR_OBJECT_PROPERTY_ULONG:
6168 MAKE_SET_CMD("U:value", prop->val.ul);
6169 break;
6170 case QEMU_MONITOR_OBJECT_PROPERTY_DOUBLE:
6171 MAKE_SET_CMD("d:value", prop->val.d);
6172 break;
6173 case QEMU_MONITOR_OBJECT_PROPERTY_STRING:
6174 MAKE_SET_CMD("s:value", prop->val.str);
6175 break;
6176 case QEMU_MONITOR_OBJECT_PROPERTY_LAST:
6177 virReportError(VIR_ERR_INTERNAL_ERROR,
6178 _("qom-set invalid object property type %d"),
6179 prop->type);
6180 goto cleanup;
6181
6182 }
6183 if (!cmd)
6184 return -1;
6185
6186 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
6187 goto cleanup;
6188
6189 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
6190 goto cleanup;
6191
6192 ret = 0;
6193 cleanup:
6194 virJSONValueFree(cmd);
6195 virJSONValueFree(reply);
6196
6197 return ret;
6198 }
6199 #undef MAKE_SET_CMD
6200
6201
6202 static int
6203 qemuMonitorJSONParsePropsList(virJSONValuePtr cmd,
6204 virJSONValuePtr reply,
6205 char ***props)
6206 {
6207 virJSONValuePtr data;
6208 char **proplist = NULL;
6209 size_t n = 0;
6210 size_t i;
6211 int ret = -1;
6212
6213 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
6214 goto cleanup;
6215
6216 data = virJSONValueObjectGetArray(reply, "return");
6217 n = virJSONValueArraySize(data);
6218
6219 /* null-terminated list */
6220 if (VIR_ALLOC_N(proplist, n + 1) < 0)
6221 goto cleanup;
6222
6223 for (i = 0; i < n; i++) {
6224 virJSONValuePtr child = virJSONValueArrayGet(data, i);
6225 const char *tmp;
6226
6227 if (!(tmp = virJSONValueObjectGetString(child, "name"))) {
6228 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6229 _("reply data was missing 'name'"));
6230 goto cleanup;
6231 }
6232
6233 if (VIR_STRDUP(proplist[i], tmp) < 0)
6234 goto cleanup;
6235 }
6236
6237 ret = n;
6238 *props = proplist;
6239 proplist = NULL;
6240
6241 cleanup:
6242 virStringListFree(proplist);
6243 return ret;
6244 }
6245
6246
6247 int qemuMonitorJSONGetDeviceProps(qemuMonitorPtr mon,
6248 const char *device,
6249 char ***props)
6250 {
6251 int ret = -1;
6252 virJSONValuePtr cmd;
6253 virJSONValuePtr reply = NULL;
6254
6255 *props = NULL;
6256
6257 if (!(cmd = qemuMonitorJSONMakeCommand("device-list-properties",
6258 "s:typename", device,
6259 NULL)))
6260 return -1;
6261
6262 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
6263 goto cleanup;
6264
6265 if (qemuMonitorJSONHasError(reply, "DeviceNotFound")) {
6266 ret = 0;
6267 goto cleanup;
6268 }
6269
6270 ret = qemuMonitorJSONParsePropsList(cmd, reply, props);
6271 cleanup:
6272 virJSONValueFree(reply);
6273 virJSONValueFree(cmd);
6274 return ret;
6275 }
6276
6277
6278 int
6279 qemuMonitorJSONGetObjectProps(qemuMonitorPtr mon,
6280 const char *object,
6281 char ***props)
6282 {
6283 int ret = -1;
6284 virJSONValuePtr cmd;
6285 virJSONValuePtr reply = NULL;
6286
6287 *props = NULL;
6288
6289 if (!(cmd = qemuMonitorJSONMakeCommand("qom-list-properties",
6290 "s:typename", object,
6291 NULL)))
6292 return -1;
6293
6294 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
6295 goto cleanup;
6296
6297 if (qemuMonitorJSONHasError(reply, "DeviceNotFound")) {
6298 ret = 0;
6299 goto cleanup;
6300 }
6301
6302 ret = qemuMonitorJSONParsePropsList(cmd, reply, props);
6303 cleanup:
6304 virJSONValueFree(reply);
6305 virJSONValueFree(cmd);
6306 return ret;
6307 }
6308
6309
6310 char *
6311 qemuMonitorJSONGetTargetArch(qemuMonitorPtr mon)
6312 {
6313 char *ret = NULL;
6314 const char *arch;
6315 virJSONValuePtr cmd;
6316 virJSONValuePtr reply = NULL;
6317 virJSONValuePtr data;
6318
6319 if (!(cmd = qemuMonitorJSONMakeCommand("query-target", NULL)))
6320 return NULL;
6321
6322 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
6323 goto cleanup;
6324
6325 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
6326 goto cleanup;
6327
6328 data = virJSONValueObjectGetObject(reply, "return");
6329
6330 if (!(arch = virJSONValueObjectGetString(data, "arch"))) {
6331 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6332 _("query-target reply was missing arch data"));
6333 goto cleanup;
6334 }
6335
6336 ignore_value(VIR_STRDUP(ret, arch));
6337
6338 cleanup:
6339 virJSONValueFree(cmd);
6340 virJSONValueFree(reply);
6341 return ret;
6342 }
6343
6344
6345 int
6346 qemuMonitorJSONGetMigrationCapabilities(qemuMonitorPtr mon,
6347 char ***capabilities)
6348 {
6349 int ret = -1;
6350 virJSONValuePtr cmd;
6351 virJSONValuePtr reply = NULL;
6352 virJSONValuePtr caps;
6353 char **list = NULL;
6354 size_t i;
6355 size_t n;
6356
6357 *capabilities = NULL;
6358
6359 if (!(cmd = qemuMonitorJSONMakeCommand("query-migrate-capabilities",
6360 NULL)))
6361 return -1;
6362
6363 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
6364 goto cleanup;
6365
6366 if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
6367 ret = 0;
6368 goto cleanup;
6369 }
6370
6371 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
6372 goto cleanup;
6373
6374 caps = virJSONValueObjectGetArray(reply, "return");
6375 n = virJSONValueArraySize(caps);
6376
6377 if (VIR_ALLOC_N(list, n + 1) < 0)
6378 goto cleanup;
6379
6380 for (i = 0; i < n; i++) {
6381 virJSONValuePtr cap = virJSONValueArrayGet(caps, i);
6382 const char *name;
6383
6384 if (!cap || virJSONValueGetType(cap) != VIR_JSON_TYPE_OBJECT) {
6385 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6386 _("missing entry in migration capabilities list"));
6387 goto cleanup;
6388 }
6389
6390 if (!(name = virJSONValueObjectGetString(cap, "capability"))) {
6391 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6392 _("missing migration capability name"));
6393 goto cleanup;
6394 }
6395
6396 if (VIR_STRDUP(list[i], name) < 1)
6397 goto cleanup;
6398 }
6399
6400 ret = n;
6401 *capabilities = list;
6402 list = NULL;
6403
6404 cleanup:
6405 virStringListFree(list);
6406 virJSONValueFree(cmd);
6407 virJSONValueFree(reply);
6408 return ret;
6409 }
6410
6411
6412 int
6413 qemuMonitorJSONSetMigrationCapabilities(qemuMonitorPtr mon,
6414 virJSONValuePtr caps)
6415 {
6416 int ret = -1;
6417 virJSONValuePtr cmd = NULL;
6418 virJSONValuePtr reply = NULL;
6419
6420 cmd = qemuMonitorJSONMakeCommand("migrate-set-capabilities",
6421 "a:capabilities", &caps,
6422 NULL);
6423 if (!cmd)
6424 goto cleanup;
6425
6426 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
6427 goto cleanup;
6428
6429 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
6430 goto cleanup;
6431
6432 ret = 0;
6433 cleanup:
6434 virJSONValueFree(caps);
6435 virJSONValueFree(cmd);
6436 virJSONValueFree(reply);
6437 return ret;
6438 }
6439
6440
6441 /**
6442 * qemuMonitorJSONGetGICCapabilities:
6443 * @mon: QEMU JSON monitor
6444 * @capabilities: where to store the GIC capabilities
6445 *
6446 * Use @mon to obtain information about the GIC capabilities for the
6447 * corresponding QEMU binary, and store them in @capabilities.
6448 *
6449 * If the QEMU binary has no GIC capabilities, or if GIC capabilities could
6450 * not be determined due to the lack of 'query-gic-capabilities' QMP command,
6451 * a NULL pointer will be returned instead of an empty array.
6452 *
6453 * Returns: the number of GIC capabilities obtained from the monitor,
6454 * <0 on failure
6455 */
6456 int
6457 qemuMonitorJSONGetGICCapabilities(qemuMonitorPtr mon,
6458 virGICCapability **capabilities)
6459 {
6460 int ret = -1;
6461 virJSONValuePtr cmd;
6462 virJSONValuePtr reply = NULL;
6463 virJSONValuePtr caps;
6464 virGICCapability *list = NULL;
6465 size_t i;
6466 size_t n;
6467
6468 *capabilities = NULL;
6469
6470 if (!(cmd = qemuMonitorJSONMakeCommand("query-gic-capabilities",
6471 NULL)))
6472 return -1;
6473
6474 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
6475 goto cleanup;
6476
6477 /* If the 'query-gic-capabilities' QMP command was not available
6478 * we simply successfully return zero capabilities.
6479 * This is the case for QEMU <2.6 and all non-ARM architectures */
6480 if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
6481 ret = 0;
6482 goto cleanup;
6483 }
6484
6485 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
6486 goto cleanup;
6487
6488 caps = virJSONValueObjectGetArray(reply, "return");
6489 n = virJSONValueArraySize(caps);
6490
6491 /* If the returned array was empty we have to return successfully */
6492 if (n == 0) {
6493 ret = 0;
6494 goto cleanup;
6495 }
6496
6497 if (VIR_ALLOC_N(list, n) < 0)
6498 goto cleanup;
6499
6500 for (i = 0; i < n; i++) {
6501 virJSONValuePtr cap = virJSONValueArrayGet(caps, i);
6502 int version;
6503 bool kernel;
6504 bool emulated;
6505
6506 if (!cap || virJSONValueGetType(cap) != VIR_JSON_TYPE_OBJECT) {
6507 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6508 _("missing entry in GIC capabilities list"));
6509 goto cleanup;
6510 }
6511
6512 if (virJSONValueObjectGetNumberInt(cap, "version", &version) < 0) {
6513 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6514 _("missing GIC version"));
6515 goto cleanup;
6516 }
6517
6518 if (virJSONValueObjectGetBoolean(cap, "kernel", &kernel) < 0) {
6519 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6520 _("missing in-kernel GIC information"));
6521 goto cleanup;
6522 }
6523
6524 if (virJSONValueObjectGetBoolean(cap, "emulated", &emulated) < 0) {
6525 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6526 _("missing emulated GIC information"));
6527 goto cleanup;
6528 }
6529
6530 list[i].version = version;
6531 if (kernel)
6532 list[i].implementation |= VIR_GIC_IMPLEMENTATION_KERNEL;
6533 if (emulated)
6534 list[i].implementation |= VIR_GIC_IMPLEMENTATION_EMULATED;
6535 }
6536
6537 ret = n;
6538 *capabilities = list;
6539 list = NULL;
6540
6541 cleanup:
6542 VIR_FREE(list);
6543 virJSONValueFree(cmd);
6544 virJSONValueFree(reply);
6545
6546 return ret;
6547 }
6548
6549
6550 /**
6551 * qemuMonitorJSONGetSEVCapabilities:
6552 * @mon: qemu monitor object
6553 * @capabilities: pointer to pointer to a SEV capability structure to be filled
6554 *
6555 * This function queries and fills in AMD's SEV platform-specific data.
6556 * Note that from QEMU's POV both -object sev-guest and query-sev-capabilities
6557 * can be present even if SEV is not available, which basically leaves us with
6558 * checking for JSON "GenericError" in order to differentiate between
6559 * compiled-in support and actual SEV support on the platform.
6560 *
6561 * Returns -1 on error, 0 if SEV is not supported, and 1 if SEV is supported on
6562 * the platform.
6563 */
6564 int
6565 qemuMonitorJSONGetSEVCapabilities(qemuMonitorPtr mon,
6566 virSEVCapability **capabilities)
6567 {
6568 int ret = -1;
6569 virJSONValuePtr cmd;
6570 virJSONValuePtr reply = NULL;
6571 virJSONValuePtr caps;
6572 const char *pdh = NULL;
6573 const char *cert_chain = NULL;
6574 unsigned int cbitpos;
6575 unsigned int reduced_phys_bits;
6576 VIR_AUTOPTR(virSEVCapability) capability = NULL;
6577
6578 *capabilities = NULL;
6579
6580 if (!(cmd = qemuMonitorJSONMakeCommand("query-sev-capabilities",
6581 NULL)))
6582 return -1;
6583
6584 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
6585 goto cleanup;
6586
6587 /* QEMU has only compiled-in support of SEV */
6588 if (qemuMonitorJSONHasError(reply, "GenericError")) {
6589 ret = 0;
6590 goto cleanup;
6591 }
6592
6593 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
6594 goto cleanup;
6595
6596 caps = virJSONValueObjectGetObject(reply, "return");
6597
6598 if (virJSONValueObjectGetNumberUint(caps, "cbitpos", &cbitpos) < 0) {
6599 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6600 _("query-sev-capabilities reply was missing"
6601 " 'cbitpos' field"));
6602 goto cleanup;
6603 }
6604
6605 if (virJSONValueObjectGetNumberUint(caps, "reduced-phys-bits",
6606 &reduced_phys_bits) < 0) {
6607 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6608 _("query-sev-capabilities reply was missing"
6609 " 'reduced-phys-bits' field"));
6610 goto cleanup;
6611 }
6612
6613 if (!(pdh = virJSONValueObjectGetString(caps, "pdh"))) {
6614 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6615 _("query-sev-capabilities reply was missing"
6616 " 'pdh' field"));
6617 goto cleanup;
6618 }
6619
6620 if (!(cert_chain = virJSONValueObjectGetString(caps, "cert-chain"))) {
6621 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6622 _("query-sev-capabilities reply was missing"
6623 " 'cert-chain' field"));
6624 goto cleanup;
6625 }
6626
6627 if (VIR_ALLOC(capability) < 0)
6628 goto cleanup;
6629
6630 if (VIR_STRDUP(capability->pdh, pdh) < 0)
6631 goto cleanup;
6632
6633 if (VIR_STRDUP(capability->cert_chain, cert_chain) < 0)
6634 goto cleanup;
6635
6636 capability->cbitpos = cbitpos;
6637 capability->reduced_phys_bits = reduced_phys_bits;
6638 VIR_STEAL_PTR(*capabilities, capability);
6639 ret = 1;
6640 cleanup:
6641 virJSONValueFree(cmd);
6642 virJSONValueFree(reply);
6643
6644 return ret;
6645 }
6646
6647 static virJSONValuePtr
6648 qemuMonitorJSONBuildInetSocketAddress(const char *host,
6649 const char *port)
6650 {
6651 virJSONValuePtr addr = NULL;
6652 virJSONValuePtr data = NULL;
6653
6654 if (virJSONValueObjectCreate(&data, "s:host", host,
6655 "s:port", port, NULL) < 0)
6656 return NULL;
6657
6658 if (virJSONValueObjectCreate(&addr, "s:type", "inet",
6659 "a:data", &data, NULL) < 0) {
6660 virJSONValueFree(data);
6661 return NULL;
6662 }
6663
6664 return addr;
6665 }
6666
6667 static virJSONValuePtr
6668 qemuMonitorJSONBuildUnixSocketAddress(const char *path)
6669 {
6670 virJSONValuePtr addr = NULL;
6671 virJSONValuePtr data = NULL;
6672
6673 if (virJSONValueObjectCreate(&data, "s:path", path, NULL) < 0)
6674 return NULL;
6675
6676 if (virJSONValueObjectCreate(&addr, "s:type", "unix",
6677 "a:data", &data, NULL) < 0) {
6678 virJSONValueFree(data);
6679 return NULL;
6680 }
6681
6682 return addr;
6683 }
6684
6685 int
6686 qemuMonitorJSONNBDServerStart(qemuMonitorPtr mon,
6687 const char *host,
6688 unsigned int port,
6689 const char *tls_alias)
6690 {
6691 int ret = -1;
6692 virJSONValuePtr cmd = NULL;
6693 virJSONValuePtr reply = NULL;
6694 virJSONValuePtr addr = NULL;
6695 char *port_str = NULL;
6696
6697 if (virAsprintf(&port_str, "%u", port) < 0)
6698 return ret;
6699
6700 if (!(addr = qemuMonitorJSONBuildInetSocketAddress(host, port_str)))
6701 goto cleanup;
6702
6703 if (!(cmd = qemuMonitorJSONMakeCommand("nbd-server-start",
6704 "a:addr", &addr,
6705 "S:tls-creds", tls_alias,
6706 NULL)))
6707 goto cleanup;
6708
6709 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
6710 goto cleanup;
6711
6712 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
6713 goto cleanup;
6714
6715 ret = 0;
6716
6717 cleanup:
6718 VIR_FREE(port_str);
6719 virJSONValueFree(reply);
6720 virJSONValueFree(cmd);
6721 virJSONValueFree(addr);
6722 return ret;
6723 }
6724
6725 int
6726 qemuMonitorJSONNBDServerAdd(qemuMonitorPtr mon,
6727 const char *deviceID,
6728 bool writable)
6729 {
6730 int ret = -1;
6731 virJSONValuePtr cmd;
6732 virJSONValuePtr reply = NULL;
6733
6734 if (!(cmd = qemuMonitorJSONMakeCommand("nbd-server-add",
6735 "s:device", deviceID,
6736 "b:writable", writable,
6737 NULL)))
6738 return ret;
6739
6740 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
6741 goto cleanup;
6742
6743 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
6744 goto cleanup;
6745
6746 ret = 0;
6747 cleanup:
6748 virJSONValueFree(cmd);
6749 virJSONValueFree(reply);
6750 return ret;
6751 }
6752
6753 int
6754 qemuMonitorJSONNBDServerStop(qemuMonitorPtr mon)
6755 {
6756 int ret = -1;
6757 virJSONValuePtr cmd;
6758 virJSONValuePtr reply = NULL;
6759
6760 if (!(cmd = qemuMonitorJSONMakeCommand("nbd-server-stop",
6761 NULL)))
6762 return ret;
6763
6764 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
6765 goto cleanup;
6766
6767 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
6768 goto cleanup;
6769
6770 ret = 0;
6771 cleanup:
6772 virJSONValueFree(cmd);
6773 virJSONValueFree(reply);
6774 return ret;
6775 }
6776
6777
6778 static int
6779 qemuMonitorJSONGetStringArray(qemuMonitorPtr mon, const char *qmpCmd,
6780 char ***array)
6781 {
6782 int ret = -1;
6783 virJSONValuePtr cmd;
6784 virJSONValuePtr reply = NULL;
6785 virJSONValuePtr data;
6786 char **list = NULL;
6787 size_t n = 0;
6788 size_t i;
6789
6790 *array = NULL;
6791
6792 if (!(cmd = qemuMonitorJSONMakeCommand(qmpCmd, NULL)))
6793 return -1;
6794
6795 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
6796 goto cleanup;
6797
6798 if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
6799 ret = 0;
6800 goto cleanup;
6801 }
6802
6803 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
6804 goto cleanup;
6805
6806 data = virJSONValueObjectGetArray(reply, "return");
6807 n = virJSONValueArraySize(data);
6808
6809 /* null-terminated list */
6810 if (VIR_ALLOC_N(list, n + 1) < 0)
6811 goto cleanup;
6812
6813 for (i = 0; i < n; i++) {
6814 virJSONValuePtr child = virJSONValueArrayGet(data, i);
6815 const char *tmp;
6816
6817 if (!(tmp = virJSONValueGetString(child))) {
6818 virReportError(VIR_ERR_INTERNAL_ERROR,
6819 _("%s array element does not contain data"),
6820 qmpCmd);
6821 goto cleanup;
6822 }
6823
6824 if (VIR_STRDUP(list[i], tmp) < 0)
6825 goto cleanup;
6826 }
6827
6828 ret = n;
6829 *array = list;
6830 list = NULL;
6831
6832 cleanup:
6833 virStringListFree(list);
6834 virJSONValueFree(cmd);
6835 virJSONValueFree(reply);
6836 return ret;
6837 }
6838
6839 int qemuMonitorJSONGetTPMModels(qemuMonitorPtr mon,
6840 char ***tpmmodels)
6841 {
6842 return qemuMonitorJSONGetStringArray(mon, "query-tpm-models", tpmmodels);
6843 }
6844
6845
6846 int qemuMonitorJSONGetTPMTypes(qemuMonitorPtr mon,
6847 char ***tpmtypes)
6848 {
6849 return qemuMonitorJSONGetStringArray(mon, "query-tpm-types", tpmtypes);
6850 }
6851
6852 static int
6853 qemuMonitorJSONBuildChrChardevReconnect(virJSONValuePtr object,
6854 const virDomainChrSourceReconnectDef *def)
6855 {
6856 if (def->enabled != VIR_TRISTATE_BOOL_YES)
6857 return 0;
6858
6859 return virJSONValueObjectAppendNumberUint(object, "reconnect", def->timeout);
6860 }
6861
6862 static virJSONValuePtr
6863 qemuMonitorJSONAttachCharDevCommand(const char *chrID,
6864 const virDomainChrSourceDef *chr)
6865 {
6866 virJSONValuePtr ret = NULL;
6867 virJSONValuePtr backend = NULL;
6868 virJSONValuePtr data = NULL;
6869 virJSONValuePtr addr = NULL;
6870 const char *backend_type = NULL;
6871 const char *host;
6872 const char *port;
6873 char *tlsalias = NULL;
6874 bool telnet;
6875
6876 if (!(backend = virJSONValueNewObject()) ||
6877 !(data = virJSONValueNewObject())) {
6878 goto cleanup;
6879 }
6880
6881 switch ((virDomainChrType)chr->type) {
6882 case VIR_DOMAIN_CHR_TYPE_NULL:
6883 case VIR_DOMAIN_CHR_TYPE_VC:
6884 backend_type = "null";
6885 break;
6886
6887 case VIR_DOMAIN_CHR_TYPE_PTY:
6888 backend_type = "pty";
6889 break;
6890
6891 case VIR_DOMAIN_CHR_TYPE_FILE:
6892 backend_type = "file";
6893 if (virJSONValueObjectAppendString(data, "out", chr->data.file.path) < 0)
6894 goto cleanup;
6895 break;
6896
6897 case VIR_DOMAIN_CHR_TYPE_DEV:
6898 backend_type = STRPREFIX(chrID, "parallel") ? "parallel" : "serial";
6899 if (virJSONValueObjectAppendString(data, "device",
6900 chr->data.file.path) < 0)
6901 goto cleanup;
6902 break;
6903
6904 case VIR_DOMAIN_CHR_TYPE_TCP:
6905 backend_type = "socket";
6906 addr = qemuMonitorJSONBuildInetSocketAddress(chr->data.tcp.host,
6907 chr->data.tcp.service);
6908 if (!addr ||
6909 virJSONValueObjectAppend(data, "addr", addr) < 0)
6910 goto cleanup;
6911 addr = NULL;
6912
6913 telnet = chr->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
6914
6915 if (chr->data.tcp.listen &&
6916 virJSONValueObjectAppendBoolean(data, "wait", false) < 0)
6917 goto cleanup;
6918
6919 if (virJSONValueObjectAppendBoolean(data, "telnet", telnet) < 0 ||
6920 virJSONValueObjectAppendBoolean(data, "server", chr->data.tcp.listen) < 0)
6921 goto cleanup;
6922 if (chr->data.tcp.tlscreds) {
6923 if (!(tlsalias = qemuAliasTLSObjFromSrcAlias(chrID)))
6924 goto cleanup;
6925
6926 if (virJSONValueObjectAppendString(data, "tls-creds", tlsalias) < 0)
6927 goto cleanup;
6928 }
6929
6930 if (qemuMonitorJSONBuildChrChardevReconnect(data, &chr->data.tcp.reconnect) < 0)
6931 goto cleanup;
6932 break;
6933
6934 case VIR_DOMAIN_CHR_TYPE_UDP:
6935 backend_type = "udp";
6936 host = chr->data.udp.connectHost;
6937 if (!host)
6938 host = "";
6939 addr = qemuMonitorJSONBuildInetSocketAddress(host,
6940 chr->data.udp.connectService);
6941 if (!addr ||
6942 virJSONValueObjectAppend(data, "remote", addr) < 0)
6943 goto cleanup;
6944
6945 host = chr->data.udp.bindHost;
6946 port = chr->data.udp.bindService;
6947 if (host || port) {
6948 if (!host)
6949 host = "";
6950 if (!port)
6951 port = "";
6952 addr = qemuMonitorJSONBuildInetSocketAddress(host, port);
6953 if (!addr ||
6954 virJSONValueObjectAppend(data, "local", addr) < 0)
6955 goto cleanup;
6956 }
6957 addr = NULL;
6958 break;
6959
6960 case VIR_DOMAIN_CHR_TYPE_UNIX:
6961 backend_type = "socket";
6962 addr = qemuMonitorJSONBuildUnixSocketAddress(chr->data.nix.path);
6963
6964 if (!addr ||
6965 virJSONValueObjectAppend(data, "addr", addr) < 0)
6966 goto cleanup;
6967 addr = NULL;
6968
6969 if (chr->data.nix.listen &&
6970 virJSONValueObjectAppendBoolean(data, "wait", false) < 0)
6971 goto cleanup;
6972
6973 if (virJSONValueObjectAppendBoolean(data, "server", chr->data.nix.listen) < 0)
6974 goto cleanup;
6975
6976 if (qemuMonitorJSONBuildChrChardevReconnect(data, &chr->data.nix.reconnect) < 0)
6977 goto cleanup;
6978 break;
6979
6980 case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
6981 backend_type = "spicevmc";
6982
6983 if (virJSONValueObjectAppendString(data, "type",
6984 virDomainChrSpicevmcTypeToString(chr->data.spicevmc)) < 0)
6985 goto cleanup;
6986 break;
6987
6988 case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
6989 case VIR_DOMAIN_CHR_TYPE_PIPE:
6990 case VIR_DOMAIN_CHR_TYPE_STDIO:
6991 case VIR_DOMAIN_CHR_TYPE_NMDM:
6992 case VIR_DOMAIN_CHR_TYPE_LAST:
6993 if (virDomainChrTypeToString(chr->type)) {
6994 virReportError(VIR_ERR_OPERATION_FAILED,
6995 _("Hotplug unsupported for char device type '%s'"),
6996 virDomainChrTypeToString(chr->type));
6997 } else {
6998 virReportError(VIR_ERR_OPERATION_FAILED,
6999 _("Hotplug unsupported for char device type '%d'"),
7000 chr->type);
7001 }
7002 goto cleanup;
7003 }
7004
7005 if (virJSONValueObjectAppendString(backend, "type", backend_type) < 0 ||
7006 virJSONValueObjectAppend(backend, "data", data) < 0)
7007 goto cleanup;
7008 data = NULL;
7009
7010 if (!(ret = qemuMonitorJSONMakeCommand("chardev-add",
7011 "s:id", chrID,
7012 "a:backend", &backend,
7013 NULL)))
7014 goto cleanup;
7015
7016 cleanup:
7017 VIR_FREE(tlsalias);
7018 virJSONValueFree(addr);
7019 virJSONValueFree(data);
7020 virJSONValueFree(backend);
7021 return ret;
7022 }
7023
7024
7025 int
7026 qemuMonitorJSONAttachCharDev(qemuMonitorPtr mon,
7027 const char *chrID,
7028 virDomainChrSourceDefPtr chr)
7029 {
7030 int ret = -1;
7031 virJSONValuePtr cmd;
7032 virJSONValuePtr reply = NULL;
7033
7034 if (!(cmd = qemuMonitorJSONAttachCharDevCommand(chrID, chr)))
7035 return ret;
7036
7037 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
7038 goto cleanup;
7039
7040 if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {
7041 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
7042 goto cleanup;
7043 } else {
7044 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
7045 goto cleanup;
7046 }
7047
7048 if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {
7049 virJSONValuePtr data = virJSONValueObjectGetObject(reply, "return");
7050 const char *path;
7051
7052 if (!(path = virJSONValueObjectGetString(data, "pty"))) {
7053 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7054 _("chardev-add reply was missing pty path"));
7055 goto cleanup;
7056 }
7057
7058 if (VIR_STRDUP(chr->data.file.path, path) < 0)
7059 goto cleanup;
7060 }
7061
7062 ret = 0;
7063
7064 cleanup:
7065 virJSONValueFree(cmd);
7066 virJSONValueFree(reply);
7067 return ret;
7068 }
7069
7070 int
7071 qemuMonitorJSONDetachCharDev(qemuMonitorPtr mon,
7072 const char *chrID)
7073 {
7074 int ret = -1;
7075 virJSONValuePtr cmd;
7076 virJSONValuePtr reply = NULL;
7077
7078 if (!(cmd = qemuMonitorJSONMakeCommand("chardev-remove",
7079 "s:id", chrID,
7080 NULL)))
7081 return ret;
7082
7083 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
7084 goto cleanup;
7085
7086 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
7087 goto cleanup;
7088
7089 ret = 0;
7090 cleanup:
7091 virJSONValueFree(cmd);
7092 virJSONValueFree(reply);
7093 return ret;
7094 }
7095
7096
7097 int
7098 qemuMonitorJSONGetDeviceAliases(qemuMonitorPtr mon,
7099 char ***aliases)
7100 {
7101 qemuMonitorJSONListPathPtr *paths = NULL;
7102 char **alias;
7103 int ret = -1;
7104 size_t i;
7105 int n;
7106
7107 *aliases = NULL;
7108
7109 n = qemuMonitorJSONGetObjectListPaths(mon, "/machine/peripheral", &paths);
7110 if (n < 0)
7111 return -1;
7112
7113 if (VIR_ALLOC_N(*aliases, n + 1) < 0)
7114 goto cleanup;
7115
7116 alias = *aliases;
7117 for (i = 0; i < n; i++) {
7118 if (STRPREFIX(paths[i]->type, "child<")) {
7119 *alias = paths[i]->name;
7120 paths[i]->name = NULL;
7121 alias++;
7122 }
7123 }
7124
7125 ret = 0;
7126
7127 cleanup:
7128 for (i = 0; i < n; i++)
7129 qemuMonitorJSONListPathFree(paths[i]);
7130 VIR_FREE(paths);
7131 return ret;
7132 }
7133
7134
7135 static int
7136 qemuMonitorJSONParseCPUx86FeatureWord(virJSONValuePtr data,
7137 virCPUx86CPUID *cpuid)
7138 {
7139 const char *reg;
7140 unsigned long long eax_in;
7141 unsigned long long ecx_in = 0;
7142 unsigned long long features;
7143
7144 memset(cpuid, 0, sizeof(*cpuid));
7145
7146 if (!(reg = virJSONValueObjectGetString(data, "cpuid-register"))) {
7147 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7148 _("missing cpuid-register in CPU data"));
7149 return -1;
7150 }
7151 if (virJSONValueObjectGetNumberUlong(data, "cpuid-input-eax", &eax_in) < 0) {
7152 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7153 _("missing or invalid cpuid-input-eax in CPU data"));
7154 return -1;
7155 }
7156 ignore_value(virJSONValueObjectGetNumberUlong(data, "cpuid-input-ecx",
7157 &ecx_in));
7158 if (virJSONValueObjectGetNumberUlong(data, "features", &features) < 0) {
7159 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7160 _("missing or invalid features in CPU data"));
7161 return -1;
7162 }
7163
7164 cpuid->eax_in = eax_in;
7165 cpuid->ecx_in = ecx_in;
7166 if (STREQ(reg, "EAX")) {
7167 cpuid->eax = features;
7168 } else if (STREQ(reg, "EBX")) {
7169 cpuid->ebx = features;
7170 } else if (STREQ(reg, "ECX")) {
7171 cpuid->ecx = features;
7172 } else if (STREQ(reg, "EDX")) {
7173 cpuid->edx = features;
7174 } else {
7175 virReportError(VIR_ERR_INTERNAL_ERROR,
7176 _("unknown CPU register '%s'"), reg);
7177 return -1;
7178 }
7179
7180 return 0;
7181 }
7182
7183
7184 static virCPUDataPtr
7185 qemuMonitorJSONParseCPUx86Features(virJSONValuePtr data)
7186 {
7187 virCPUDataPtr cpudata = NULL;
7188 virCPUx86DataItem item = { 0 };
7189 size_t i;
7190
7191 if (!(cpudata = virCPUDataNew(VIR_ARCH_X86_64)))
7192 goto error;
7193
7194 item.type = VIR_CPU_X86_DATA_CPUID;
7195 for (i = 0; i < virJSONValueArraySize(data); i++) {
7196 if (qemuMonitorJSONParseCPUx86FeatureWord(virJSONValueArrayGet(data, i),
7197 &item.data.cpuid) < 0 ||
7198 virCPUx86DataAdd(cpudata, &item) < 0)
7199 goto error;
7200 }
7201
7202 return cpudata;
7203
7204 error:
7205 virCPUDataFree(cpudata);
7206 return NULL;
7207 }
7208
7209
7210 int
7211 qemuMonitorJSONGetCPUx86Data(qemuMonitorPtr mon,
7212 const char *property,
7213 virCPUDataPtr *cpudata)
7214 {
7215 virJSONValuePtr cmd = NULL;
7216 virJSONValuePtr reply = NULL;
7217 virJSONValuePtr data;
7218 int ret = -1;
7219
7220 if (!(cmd = qemuMonitorJSONMakeCommand("qom-get",
7221 "s:path", QOM_CPU_PATH,
7222 "s:property", property,
7223 NULL)))
7224 goto cleanup;
7225
7226 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
7227 goto cleanup;
7228
7229 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
7230 goto cleanup;
7231
7232 data = virJSONValueObjectGetArray(reply, "return");
7233 if (!(*cpudata = qemuMonitorJSONParseCPUx86Features(data)))
7234 goto cleanup;
7235
7236 ret = 0;
7237
7238 cleanup:
7239 virJSONValueFree(cmd);
7240 virJSONValueFree(reply);
7241 return ret;
7242 }
7243
7244
7245 /*
7246 * Returns -1 on error, 0 if QEMU does not support reporting CPUID features
7247 * of a guest CPU, and 1 if the feature is supported.
7248 */
7249 static int
7250 qemuMonitorJSONCheckCPUx86(qemuMonitorPtr mon)
7251 {
7252 virJSONValuePtr cmd = NULL;
7253 virJSONValuePtr reply = NULL;
7254 virJSONValuePtr data;
7255 size_t i;
7256 size_t n;
7257 int ret = -1;
7258
7259 if (!(cmd = qemuMonitorJSONMakeCommand("qom-list",
7260 "s:path", QOM_CPU_PATH,
7261 NULL)))
7262 goto cleanup;
7263
7264 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
7265 goto cleanup;
7266
7267 if ((data = virJSONValueObjectGet(reply, "error"))) {
7268 const char *klass = virJSONValueObjectGetString(data, "class");
7269 if (STREQ_NULLABLE(klass, "DeviceNotFound") ||
7270 STREQ_NULLABLE(klass, "CommandNotFound")) {
7271 ret = 0;
7272 goto cleanup;
7273 }
7274 }
7275
7276 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
7277 goto cleanup;
7278
7279 data = virJSONValueObjectGetArray(reply, "return");
7280 n = virJSONValueArraySize(data);
7281
7282 for (i = 0; i < n; i++) {
7283 virJSONValuePtr element = virJSONValueArrayGet(data, i);
7284 if (STREQ_NULLABLE(virJSONValueObjectGetString(element, "name"),
7285 "feature-words"))
7286 break;
7287 }
7288
7289 if (i == n)
7290 ret = 0;
7291 else
7292 ret = 1;
7293
7294 cleanup:
7295 virJSONValueFree(cmd);
7296 virJSONValueFree(reply);
7297 return ret;
7298 }
7299
7300
7301 /**
7302 * qemuMonitorJSONGetGuestCPU:
7303 * @mon: Pointer to the monitor
7304 * @arch: arch of the guest
7305 * @data: returns the cpu data of the guest
7306 * @disabled: returns the CPU data for features which were disabled by QEMU
7307 *
7308 * Retrieve the definition of the guest CPU from a running qemu instance.
7309 *
7310 * Returns 0 on success, -2 if guest doesn't support this feature,
7311 * -1 on other errors.
7312 */
7313 int
7314 qemuMonitorJSONGetGuestCPU(qemuMonitorPtr mon,
7315 virArch arch,
7316 virCPUDataPtr *data,
7317 virCPUDataPtr *disabled)
7318 {
7319 virCPUDataPtr cpuEnabled = NULL;
7320 virCPUDataPtr cpuDisabled = NULL;
7321 int rc;
7322
7323 if (ARCH_IS_X86(arch)) {
7324 if ((rc = qemuMonitorJSONCheckCPUx86(mon)) < 0)
7325 return -1;
7326 else if (!rc)
7327 return -2;
7328
7329 if (qemuMonitorJSONGetCPUx86Data(mon, "feature-words",
7330 &cpuEnabled) < 0)
7331 goto error;
7332
7333 if (disabled &&
7334 qemuMonitorJSONGetCPUx86Data(mon, "filtered-features",
7335 &cpuDisabled) < 0)
7336 goto error;
7337
7338 *data = cpuEnabled;
7339 if (disabled)
7340 *disabled = cpuDisabled;
7341 return 0;
7342 }
7343
7344 virReportError(VIR_ERR_INTERNAL_ERROR,
7345 _("CPU definition retrieval isn't supported for '%s'"),
7346 virArchToString(arch));
7347 return -1;
7348
7349 error:
7350 virCPUDataFree(cpuEnabled);
7351 virCPUDataFree(cpuDisabled);
7352 return -1;
7353 }
7354
7355 int
7356 qemuMonitorJSONRTCResetReinjection(qemuMonitorPtr mon)
7357 {
7358 int ret = -1;
7359 virJSONValuePtr cmd;
7360 virJSONValuePtr reply = NULL;
7361
7362 if (!(cmd = qemuMonitorJSONMakeCommand("rtc-reset-reinjection",
7363 NULL)))
7364 return ret;
7365
7366 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
7367 goto cleanup;
7368
7369 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
7370 goto cleanup;
7371
7372 ret = 0;
7373 cleanup:
7374 virJSONValueFree(cmd);
7375 virJSONValueFree(reply);
7376 return ret;
7377 }
7378
7379 /**
7380 * Query and parse returned array of data such as:
7381 *
7382 * {u'return': [{u'id': u'iothread1', u'thread-id': 30992}, \
7383 * {u'id': u'iothread2', u'thread-id': 30993}]}
7384 */
7385 int
7386 qemuMonitorJSONGetIOThreads(qemuMonitorPtr mon,
7387 qemuMonitorIOThreadInfoPtr **iothreads)
7388 {
7389 int ret = -1;
7390 virJSONValuePtr cmd;
7391 virJSONValuePtr reply = NULL;
7392 virJSONValuePtr data;
7393 qemuMonitorIOThreadInfoPtr *infolist = NULL;
7394 size_t n = 0;
7395 size_t i;
7396
7397 *iothreads = NULL;
7398
7399 if (!(cmd = qemuMonitorJSONMakeCommand("query-iothreads", NULL)))
7400 return ret;
7401
7402 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
7403 goto cleanup;
7404
7405 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
7406 goto cleanup;
7407
7408 data = virJSONValueObjectGetArray(reply, "return");
7409 n = virJSONValueArraySize(data);
7410
7411 /* null-terminated list */
7412 if (VIR_ALLOC_N(infolist, n + 1) < 0)
7413 goto cleanup;
7414
7415 for (i = 0; i < n; i++) {
7416 virJSONValuePtr child = virJSONValueArrayGet(data, i);
7417 const char *tmp;
7418 qemuMonitorIOThreadInfoPtr info;
7419
7420 if (!(tmp = virJSONValueObjectGetString(child, "id"))) {
7421 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7422 _("query-iothreads reply data was missing 'id'"));
7423 goto cleanup;
7424 }
7425
7426 if (!STRPREFIX(tmp, "iothread"))
7427 continue;
7428
7429 if (VIR_ALLOC(info) < 0)
7430 goto cleanup;
7431
7432 infolist[i] = info;
7433
7434 if (virStrToLong_ui(tmp + strlen("iothread"),
7435 NULL, 10, &info->iothread_id) < 0) {
7436 virReportError(VIR_ERR_INTERNAL_ERROR,
7437 _("failed to find iothread id for '%s'"),
7438 tmp);
7439 goto cleanup;
7440 }
7441
7442 if (virJSONValueObjectGetNumberInt(child, "thread-id",
7443 &info->thread_id) < 0) {
7444 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7445 _("query-iothreads reply has malformed "
7446 "'thread-id' data"));
7447 goto cleanup;
7448 }
7449
7450 /* Fetch poll values (since QEMU 2.9 ) if available. QEMU
7451 * stores these values as int64_t's; however, the qapi type
7452 * is an int. The qapi/misc.json also mis-describes the grow
7453 * and shrink values as pure add/remove values. The source
7454 * util/aio-posix.c function aio_poll uses them as a factor
7455 * or divisor in it's calculation. We will fetch and store
7456 * them as defined in our structures. */
7457 if (virJSONValueObjectGetNumberUlong(child, "poll-max-ns",
7458 &info->poll_max_ns) == 0 &&
7459 virJSONValueObjectGetNumberUint(child, "poll-grow",
7460 &info->poll_grow) == 0 &&
7461 virJSONValueObjectGetNumberUint(child, "poll-shrink",
7462 &info->poll_shrink) == 0)
7463 info->poll_valid = true;
7464 }
7465
7466 ret = n;
7467 *iothreads = infolist;
7468 infolist = NULL;
7469
7470 cleanup:
7471 if (infolist) {
7472 for (i = 0; i < n; i++)
7473 VIR_FREE(infolist[i]);
7474 VIR_FREE(infolist);
7475 }
7476 virJSONValueFree(cmd);
7477 virJSONValueFree(reply);
7478 return ret;
7479 }
7480
7481
7482 int
7483 qemuMonitorJSONSetIOThread(qemuMonitorPtr mon,
7484 qemuMonitorIOThreadInfoPtr iothreadInfo)
7485 {
7486 int ret = -1;
7487 char *path = NULL;
7488 qemuMonitorJSONObjectProperty prop;
7489
7490 if (virAsprintf(&path, "/objects/iothread%u",
7491 iothreadInfo->iothread_id) < 0)
7492 goto cleanup;
7493
7494 #define VIR_IOTHREAD_SET_PROP(propName, propVal) \
7495 if (iothreadInfo->set_##propVal) { \
7496 memset(&prop, 0, sizeof(qemuMonitorJSONObjectProperty)); \
7497 prop.type = QEMU_MONITOR_OBJECT_PROPERTY_INT; \
7498 prop.val.iv = iothreadInfo->propVal; \
7499 if (qemuMonitorJSONSetObjectProperty(mon, path, propName, &prop) < 0) \
7500 goto cleanup; \
7501 }
7502
7503 VIR_IOTHREAD_SET_PROP("poll-max-ns", poll_max_ns);
7504 VIR_IOTHREAD_SET_PROP("poll-grow", poll_grow);
7505 VIR_IOTHREAD_SET_PROP("poll-shrink", poll_shrink);
7506
7507 #undef VIR_IOTHREAD_SET_PROP
7508
7509 ret = 0;
7510
7511 cleanup:
7512 VIR_FREE(path);
7513 return ret;
7514 }
7515
7516
7517 int
7518 qemuMonitorJSONGetMemoryDeviceInfo(qemuMonitorPtr mon,
7519 virHashTablePtr info)
7520 {
7521 int ret = -1;
7522 virJSONValuePtr cmd;
7523 virJSONValuePtr reply = NULL;
7524 virJSONValuePtr data = NULL;
7525 qemuMonitorMemoryDeviceInfoPtr meminfo = NULL;
7526 size_t i;
7527
7528 if (!(cmd = qemuMonitorJSONMakeCommand("query-memory-devices", NULL)))
7529 return -1;
7530
7531 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
7532 goto cleanup;
7533
7534 if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
7535 ret = -2;
7536 goto cleanup;
7537 }
7538
7539 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
7540 goto cleanup;
7541
7542 data = virJSONValueObjectGetArray(reply, "return");
7543
7544 for (i = 0; i < virJSONValueArraySize(data); i++) {
7545 virJSONValuePtr elem = virJSONValueArrayGet(data, i);
7546 const char *type;
7547
7548 if (!(type = virJSONValueObjectGetString(elem, "type"))) {
7549 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7550 _("query-memory-devices reply data doesn't contain "
7551 "enum type discriminator"));
7552 goto cleanup;
7553 }
7554
7555 /* dimm memory devices */
7556 if (STREQ(type, "dimm")) {
7557 virJSONValuePtr dimminfo;
7558 const char *devalias;
7559
7560 if (!(dimminfo = virJSONValueObjectGetObject(elem, "data"))) {
7561 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7562 _("query-memory-devices reply data doesn't "
7563 "contain enum data"));
7564 goto cleanup;
7565 }
7566
7567 if (!(devalias = virJSONValueObjectGetString(dimminfo, "id"))) {
7568 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7569 _("dimm memory info data is missing 'id'"));
7570 goto cleanup;
7571 }
7572
7573 if (VIR_ALLOC(meminfo) < 0)
7574 goto cleanup;
7575
7576 if (virJSONValueObjectGetNumberUlong(dimminfo, "addr",
7577 &meminfo->address) < 0) {
7578 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7579 _("malformed/missing addr in dimm memory info"));
7580 goto cleanup;
7581 }
7582
7583 if (virJSONValueObjectGetNumberUint(dimminfo, "slot",
7584 &meminfo->slot) < 0) {
7585 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7586 _("malformed/missing slot in dimm memory info"));
7587 goto cleanup;
7588 }
7589
7590 if (virJSONValueObjectGetBoolean(dimminfo, "hotplugged",
7591 &meminfo->hotplugged) < 0) {
7592 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7593 _("malformed/missing hotplugged in dimm memory info"));
7594 goto cleanup;
7595
7596 }
7597
7598 if (virJSONValueObjectGetBoolean(dimminfo, "hotpluggable",
7599 &meminfo->hotpluggable) < 0) {
7600 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7601 _("malformed/missing hotpluggable in dimm memory info"));
7602 goto cleanup;
7603
7604 }
7605
7606 if (virHashAddEntry(info, devalias, meminfo) < 0)
7607 goto cleanup;
7608
7609 meminfo = NULL;
7610 }
7611 }
7612
7613 ret = 0;
7614
7615 cleanup:
7616 VIR_FREE(meminfo);
7617 virJSONValueFree(cmd);
7618 virJSONValueFree(reply);
7619 return ret;
7620 }
7621
7622
7623 /**
7624 * Search for a QOM object link by alias and name.
7625 *
7626 * For @alias and @name, this function tries to find QOM object named @name
7627 * with id @alias in /machine/peripheral.
7628 *
7629 * Returns:
7630 * 0 - Found
7631 * -1 - Error - bail out
7632 * -2 - Not found
7633 */
7634 static int
7635 qemuMonitorJSONFindObjectPathByAlias(qemuMonitorPtr mon,
7636 const char *name,
7637 const char *alias,
7638 char **path)
7639 {
7640 qemuMonitorJSONListPathPtr *paths = NULL;
7641 char *child = NULL;
7642 int npaths;
7643 int ret = -1;
7644 size_t i;
7645
7646 npaths = qemuMonitorJSONGetObjectListPaths(mon, "/machine/peripheral", &paths);
7647 if (npaths < 0)
7648 return -1;
7649
7650 if (virAsprintf(&child, "child<%s>", name) < 0)
7651 goto cleanup;
7652
7653 for (i = 0; i < npaths; i++) {
7654 if (STREQ(paths[i]->name, alias) && STREQ(paths[i]->type, child)) {
7655 if (virAsprintf(path, "/machine/peripheral/%s", alias) < 0)
7656 goto cleanup;
7657
7658 ret = 0;
7659 goto cleanup;
7660 }
7661 }
7662
7663 ret = -2;
7664
7665 cleanup:
7666 for (i = 0; i < npaths; i++)
7667 qemuMonitorJSONListPathFree(paths[i]);
7668 VIR_FREE(paths);
7669 VIR_FREE(child);
7670 return ret;
7671 }
7672
7673
7674 /**
7675 * Recursively search for a QOM object link only by name.
7676 *
7677 * For @name, this function finds the first QOM object
7678 * named @name, recursively going through all the "child<>"
7679 * entries, starting from @curpath.
7680 *
7681 * Returns:
7682 * 0 - Found
7683 * -1 - Error - bail out
7684 * -2 - Not found
7685 */
7686 static int
7687 qemuMonitorJSONFindObjectPathByName(qemuMonitorPtr mon,
7688 const char *curpath,
7689 const char *name,
7690 char **path)
7691 {
7692 ssize_t i, npaths = 0;
7693 int ret = -2;
7694 char *nextpath = NULL;
7695 qemuMonitorJSONListPathPtr *paths = NULL;
7696
7697 VIR_DEBUG("Searching for '%s' Object Path starting at '%s'", name, curpath);
7698
7699 npaths = qemuMonitorJSONGetObjectListPaths(mon, curpath, &paths);
7700 if (npaths < 0)
7701 goto cleanup;
7702
7703 for (i = 0; i < npaths && ret == -2; i++) {
7704
7705 if (STREQ_NULLABLE(paths[i]->type, name)) {
7706 VIR_DEBUG("Path to '%s' is '%s/%s'", name, curpath, paths[i]->name);
7707 ret = 0;
7708 if (virAsprintf(path, "%s/%s", curpath, paths[i]->name) < 0) {
7709 *path = NULL;
7710 ret = -1;
7711 }
7712 goto cleanup;
7713 }
7714
7715 /* Type entries that begin with "child<" are a branch that can be
7716 * traversed looking for more entries
7717 */
7718 if (paths[i]->type && STRPREFIX(paths[i]->type, "child<")) {
7719 if (virAsprintf(&nextpath, "%s/%s", curpath, paths[i]->name) < 0) {
7720 ret = -1;
7721 goto cleanup;
7722 }
7723
7724 ret = qemuMonitorJSONFindObjectPathByName(mon, nextpath, name, path);
7725 VIR_FREE(nextpath);
7726 }
7727 }
7728
7729 cleanup:
7730 for (i = 0; i < npaths; i++)
7731 qemuMonitorJSONListPathFree(paths[i]);
7732 VIR_FREE(paths);
7733 VIR_FREE(nextpath);
7734 return ret;
7735 }
7736
7737
7738 /**
7739 * Recursively search for a QOM object link.
7740 *
7741 * For @name and @alias, this function finds the first QOM object.
7742 * The search is done at first by @alias and @name and if nothing was found
7743 * it continues recursively only with @name.
7744 *
7745 * Returns:
7746 * 0 - Found
7747 * -1 - Error
7748 * -2 - Not found
7749 */
7750 int
7751 qemuMonitorJSONFindLinkPath(qemuMonitorPtr mon,
7752 const char *name,
7753 const char *alias,
7754 char **path)
7755 {
7756 char *linkname = NULL;
7757 int ret = -1;
7758
7759 if (alias) {
7760 ret = qemuMonitorJSONFindObjectPathByAlias(mon, name, alias, path);
7761 if (ret == -1 || ret == 0)
7762 return ret;
7763 }
7764
7765 if (virAsprintf(&linkname, "link<%s>", name) < 0)
7766 return -1;
7767
7768 ret = qemuMonitorJSONFindObjectPathByName(mon, "/", linkname, path);
7769 VIR_FREE(linkname);
7770 return ret;
7771 }
7772
7773
7774 int
7775 qemuMonitorJSONMigrateIncoming(qemuMonitorPtr mon,
7776 const char *uri)
7777 {
7778 int ret = -1;
7779 virJSONValuePtr cmd;
7780 virJSONValuePtr reply = NULL;
7781
7782 if (!(cmd = qemuMonitorJSONMakeCommand("migrate-incoming",
7783 "s:uri", uri,
7784 NULL)))
7785 return -1;
7786
7787 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
7788 goto cleanup;
7789
7790 ret = qemuMonitorJSONCheckError(cmd, reply);
7791
7792 cleanup:
7793 virJSONValueFree(cmd);
7794 virJSONValueFree(reply);
7795 return ret;
7796 }
7797
7798
7799 int
7800 qemuMonitorJSONMigrateStartPostCopy(qemuMonitorPtr mon)
7801 {
7802 int ret = -1;
7803 virJSONValuePtr cmd;
7804 virJSONValuePtr reply = NULL;
7805
7806 if (!(cmd = qemuMonitorJSONMakeCommand("migrate-start-postcopy", NULL)))
7807 return -1;
7808
7809 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
7810 goto cleanup;
7811
7812 ret = qemuMonitorJSONCheckError(cmd, reply);
7813
7814 cleanup:
7815 virJSONValueFree(cmd);
7816 virJSONValueFree(reply);
7817 return ret;
7818 }
7819
7820
7821 int
7822 qemuMonitorJSONMigrateContinue(qemuMonitorPtr mon,
7823 qemuMonitorMigrationStatus status)
7824 {
7825 const char *statusStr = qemuMonitorMigrationStatusTypeToString(status);
7826 int ret = -1;
7827 virJSONValuePtr cmd;
7828 virJSONValuePtr reply = NULL;
7829
7830 if (!(cmd = qemuMonitorJSONMakeCommand("migrate-continue",
7831 "s:state", statusStr,
7832 NULL)))
7833 return -1;
7834
7835 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
7836 goto cleanup;
7837
7838 ret = qemuMonitorJSONCheckError(cmd, reply);
7839
7840 cleanup:
7841 virJSONValueFree(cmd);
7842 virJSONValueFree(reply);
7843 return ret;
7844 }
7845
7846
7847 int
7848 qemuMonitorJSONGetRTCTime(qemuMonitorPtr mon,
7849 struct tm *tm)
7850 {
7851 int ret = -1;
7852 virJSONValuePtr cmd;
7853 virJSONValuePtr reply = NULL;
7854 virJSONValuePtr data;
7855
7856 if (!(cmd = qemuMonitorJSONMakeCommand("qom-get",
7857 "s:path", "/machine",
7858 "s:property", "rtc-time",
7859 NULL)))
7860 return -1;
7861
7862 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
7863 goto cleanup;
7864
7865 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
7866 goto cleanup;
7867
7868 data = virJSONValueObjectGet(reply, "return");
7869
7870 if (virJSONValueObjectGetNumberInt(data, "tm_year", &tm->tm_year) < 0 ||
7871 virJSONValueObjectGetNumberInt(data, "tm_mon", &tm->tm_mon) < 0 ||
7872 virJSONValueObjectGetNumberInt(data, "tm_mday", &tm->tm_mday) < 0 ||
7873 virJSONValueObjectGetNumberInt(data, "tm_hour", &tm->tm_hour) < 0 ||
7874 virJSONValueObjectGetNumberInt(data, "tm_min", &tm->tm_min) < 0 ||
7875 virJSONValueObjectGetNumberInt(data, "tm_sec", &tm->tm_sec) < 0) {
7876 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7877 _("qemu returned malformed time"));
7878 goto cleanup;
7879 }
7880
7881 ret = 0;
7882 cleanup:
7883 virJSONValueFree(cmd);
7884 virJSONValueFree(reply);
7885 return ret;
7886 }
7887
7888
7889 void
7890 qemuMonitorQueryHotpluggableCpusFree(struct qemuMonitorQueryHotpluggableCpusEntry *entries,
7891 size_t nentries)
7892 {
7893 struct qemuMonitorQueryHotpluggableCpusEntry *entry;
7894 size_t i;
7895
7896 if (!entries)
7897 return;
7898
7899 for (i = 0; i < nentries; i++) {
7900 entry = entries + i;
7901
7902 VIR_FREE(entry->type);
7903 VIR_FREE(entry->qom_path);
7904 VIR_FREE(entry->alias);
7905 }
7906
7907 VIR_FREE(entries);
7908 }
7909
7910
7911 /**
7912 * [{
7913 * "props": {
7914 * "core-id": 0,
7915 * "thread-id": 0,
7916 * "socket-id": 0
7917 * },
7918 * "vcpus-count": 1,
7919 * "qom-path": "/machine/unattached/device[0]",
7920 * "type": "qemu64-x86_64-cpu"
7921 * },
7922 * {...}
7923 * ]
7924 */
7925 static int
7926 qemuMonitorJSONProcessHotpluggableCpusReply(virJSONValuePtr vcpu,
7927 struct qemuMonitorQueryHotpluggableCpusEntry *entry)
7928 {
7929 virJSONValuePtr props;
7930 const char *tmp;
7931
7932 if (!(tmp = virJSONValueObjectGetString(vcpu, "type"))) {
7933 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7934 _("query-hotpluggable-cpus didn't return device type"));
7935 return -1;
7936 }
7937
7938 if (VIR_STRDUP(entry->type, tmp) < 0)
7939 return -1;
7940
7941 if (virJSONValueObjectGetNumberUint(vcpu, "vcpus-count", &entry->vcpus) < 0) {
7942 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7943 _("query-hotpluggable-cpus didn't return vcpus-count"));
7944 return -1;
7945 }
7946
7947 if (!(props = virJSONValueObjectGetObject(vcpu, "props"))) {
7948 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7949 _("query-hotpluggable-cpus didn't return device props"));
7950 return -1;
7951 }
7952
7953 entry->node_id = -1;
7954 entry->socket_id = -1;
7955 entry->core_id = -1;
7956 entry->thread_id = -1;
7957
7958 ignore_value(virJSONValueObjectGetNumberInt(props, "node-id", &entry->node_id));
7959 ignore_value(virJSONValueObjectGetNumberInt(props, "socket-id", &entry->socket_id));
7960 ignore_value(virJSONValueObjectGetNumberInt(props, "core-id", &entry->core_id));
7961 ignore_value(virJSONValueObjectGetNumberInt(props, "thread-id", &entry->thread_id));
7962
7963 if (entry->node_id == -1 && entry->socket_id == -1 &&
7964 entry->core_id == -1 && entry->thread_id == -1) {
7965 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7966 _("query-hotpluggable-cpus entry doesn't report "
7967 "topology information"));
7968 return -1;
7969 }
7970
7971 /* qom path is not present unless the vCPU is online */
7972 if ((tmp = virJSONValueObjectGetString(vcpu, "qom-path"))) {
7973 if (VIR_STRDUP(entry->qom_path, tmp) < 0)
7974 return -1;
7975
7976 /* alias is the part after last slash having a "vcpu" prefix */
7977 if ((tmp = strrchr(tmp, '/')) && STRPREFIX(tmp + 1, "vcpu")) {
7978 if (VIR_STRDUP(entry->alias, tmp + 1) < 0)
7979 return -1;
7980 }
7981 }
7982
7983 return 0;
7984 }
7985
7986
7987 static int
7988 qemuMonitorQueryHotpluggableCpusEntrySort(const void *p1,
7989 const void *p2)
7990 {
7991 const struct qemuMonitorQueryHotpluggableCpusEntry *a = p1;
7992 const struct qemuMonitorQueryHotpluggableCpusEntry *b = p2;
7993
7994 if (a->socket_id != b->socket_id)
7995 return a->socket_id - b->socket_id;
7996
7997 if (a->core_id != b->core_id)
7998 return a->core_id - b->core_id;
7999
8000 return a->thread_id - b->thread_id;
8001 }
8002
8003
8004 int
8005 qemuMonitorJSONGetHotpluggableCPUs(qemuMonitorPtr mon,
8006 struct qemuMonitorQueryHotpluggableCpusEntry **entries,
8007 size_t *nentries)
8008 {
8009 struct qemuMonitorQueryHotpluggableCpusEntry *info = NULL;
8010 size_t ninfo = 0;
8011 int ret = -1;
8012 size_t i;
8013 virJSONValuePtr data;
8014 virJSONValuePtr cmd;
8015 virJSONValuePtr reply = NULL;
8016 virJSONValuePtr vcpu;
8017
8018 if (!(cmd = qemuMonitorJSONMakeCommand("query-hotpluggable-cpus", NULL)))
8019 return -1;
8020
8021 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
8022 goto cleanup;
8023
8024 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
8025 goto cleanup;
8026
8027 data = virJSONValueObjectGet(reply, "return");
8028 ninfo = virJSONValueArraySize(data);
8029
8030 if (VIR_ALLOC_N(info, ninfo) < 0)
8031 goto cleanup;
8032
8033 for (i = 0; i < ninfo; i++) {
8034 vcpu = virJSONValueArrayGet(data, i);
8035
8036 if (qemuMonitorJSONProcessHotpluggableCpusReply(vcpu, info + i) < 0)
8037 goto cleanup;
8038 }
8039
8040 qsort(info, ninfo, sizeof(*info), qemuMonitorQueryHotpluggableCpusEntrySort);
8041
8042 VIR_STEAL_PTR(*entries, info);
8043 *nentries = ninfo;
8044 ret = 0;
8045
8046 cleanup:
8047 qemuMonitorQueryHotpluggableCpusFree(info, ninfo);
8048 virJSONValueFree(cmd);
8049 virJSONValueFree(reply);
8050 return ret;
8051 }
8052
8053
8054 virJSONValuePtr
8055 qemuMonitorJSONQueryQMPSchema(qemuMonitorPtr mon)
8056 {
8057 virJSONValuePtr cmd;
8058 virJSONValuePtr reply = NULL;
8059 virJSONValuePtr ret = NULL;
8060
8061 if (!(cmd = qemuMonitorJSONMakeCommand("query-qmp-schema", NULL)))
8062 return NULL;
8063
8064 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
8065 goto cleanup;
8066
8067 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
8068 goto cleanup;
8069
8070 ret = virJSONValueObjectStealArray(reply, "return");
8071
8072 cleanup:
8073 virJSONValueFree(cmd);
8074 virJSONValueFree(reply);
8075
8076 return ret;
8077 }
8078
8079
8080 int
8081 qemuMonitorJSONSetBlockThreshold(qemuMonitorPtr mon,
8082 const char *nodename,
8083 unsigned long long threshold)
8084 {
8085 virJSONValuePtr cmd;
8086 virJSONValuePtr reply = NULL;
8087 int ret = -1;
8088
8089 if (!(cmd = qemuMonitorJSONMakeCommand("block-set-write-threshold",
8090 "s:node-name", nodename,
8091 "U:write-threshold", threshold,
8092 NULL)))
8093 return -1;
8094
8095 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
8096 goto cleanup;
8097
8098 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
8099 goto cleanup;
8100
8101 ret = 0;
8102
8103 cleanup:
8104 virJSONValueFree(cmd);
8105 virJSONValueFree(reply);
8106
8107 return ret;
8108 }
8109
8110
8111 virJSONValuePtr
8112 qemuMonitorJSONQueryNamedBlockNodes(qemuMonitorPtr mon)
8113 {
8114 virJSONValuePtr cmd;
8115 virJSONValuePtr reply = NULL;
8116 virJSONValuePtr ret = NULL;
8117
8118 if (!(cmd = qemuMonitorJSONMakeCommand("query-named-block-nodes", NULL)))
8119 return NULL;
8120
8121 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
8122 goto cleanup;
8123
8124 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
8125 goto cleanup;
8126
8127 ret = virJSONValueObjectStealArray(reply, "return");
8128
8129 cleanup:
8130 virJSONValueFree(cmd);
8131 virJSONValueFree(reply);
8132
8133 return ret;
8134 }
8135
8136
8137 int
8138 qemuMonitorJSONSetWatchdogAction(qemuMonitorPtr mon,
8139 const char *action)
8140 {
8141 virJSONValuePtr cmd;
8142 virJSONValuePtr reply = NULL;
8143 int ret = -1;
8144
8145 if (!(cmd = qemuMonitorJSONMakeCommand("watchdog-set-action",
8146 "s:action", action,
8147 NULL)))
8148 return -1;
8149
8150 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
8151 goto cleanup;
8152
8153 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
8154 goto cleanup;
8155
8156 ret = 0;
8157
8158 cleanup:
8159 virJSONValueFree(cmd);
8160 virJSONValueFree(reply);
8161 return ret;
8162 }
8163
8164
8165 int
8166 qemuMonitorJSONBlockdevAdd(qemuMonitorPtr mon,
8167 virJSONValuePtr props)
8168 {
8169 virJSONValuePtr cmd;
8170 virJSONValuePtr reply = NULL;
8171 int ret = -1;
8172
8173 if (!(cmd = qemuMonitorJSONMakeCommandInternal("blockdev-add", props)))
8174 return -1;
8175
8176 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
8177 goto cleanup;
8178
8179 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
8180 goto cleanup;
8181
8182 ret = 0;
8183
8184 cleanup:
8185 virJSONValueFree(cmd);
8186 virJSONValueFree(reply);
8187 return ret;
8188 }
8189
8190
8191 int
8192 qemuMonitorJSONBlockdevDel(qemuMonitorPtr mon,
8193 const char *nodename)
8194 {
8195 virJSONValuePtr cmd;
8196 virJSONValuePtr reply = NULL;
8197 int ret = -1;
8198
8199 if (!(cmd = qemuMonitorJSONMakeCommand("blockdev-del",
8200 "s:node-name", nodename,
8201 NULL)))
8202 return -1;
8203
8204 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
8205 goto cleanup;
8206
8207 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
8208 goto cleanup;
8209
8210 ret = 0;
8211
8212 cleanup:
8213 virJSONValueFree(cmd);
8214 virJSONValueFree(reply);
8215 return ret;
8216 }
8217
8218
8219 int
8220 qemuMonitorJSONBlockdevTrayOpen(qemuMonitorPtr mon,
8221 const char *id,
8222 bool force)
8223 {
8224 virJSONValuePtr cmd;
8225 virJSONValuePtr reply = NULL;
8226 int ret = -1;
8227
8228 if (!(cmd = qemuMonitorJSONMakeCommand("blockdev-open-tray",
8229 "s:id", id,
8230 "b:force", force, NULL)))
8231 return -1;
8232
8233 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
8234 goto cleanup;
8235
8236 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
8237 goto cleanup;
8238
8239 ret = 0;
8240
8241 cleanup:
8242 virJSONValueFree(cmd);
8243 virJSONValueFree(reply);
8244 return ret;
8245 }
8246
8247
8248 int
8249 qemuMonitorJSONBlockdevTrayClose(qemuMonitorPtr mon,
8250 const char *id)
8251 {
8252 virJSONValuePtr cmd;
8253 virJSONValuePtr reply = NULL;
8254 int ret = -1;
8255
8256 if (!(cmd = qemuMonitorJSONMakeCommand("blockdev-close-tray",
8257 "s:id", id, NULL)))
8258 return -1;
8259
8260 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
8261 goto cleanup;
8262
8263 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
8264 goto cleanup;
8265
8266 ret = 0;
8267
8268 cleanup:
8269 virJSONValueFree(cmd);
8270 virJSONValueFree(reply);
8271 return ret;
8272 }
8273
8274
8275 int
8276 qemuMonitorJSONBlockdevMediumRemove(qemuMonitorPtr mon,
8277 const char *id)
8278 {
8279 virJSONValuePtr cmd;
8280 virJSONValuePtr reply = NULL;
8281 int ret = -1;
8282
8283 if (!(cmd = qemuMonitorJSONMakeCommand("blockdev-remove-medium",
8284 "s:id", id, NULL)))
8285 return -1;
8286
8287 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
8288 goto cleanup;
8289
8290 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
8291 goto cleanup;
8292
8293 ret = 0;
8294
8295 cleanup:
8296 virJSONValueFree(cmd);
8297 virJSONValueFree(reply);
8298 return ret;
8299 }
8300
8301
8302 int
8303 qemuMonitorJSONBlockdevMediumInsert(qemuMonitorPtr mon,
8304 const char *id,
8305 const char *nodename)
8306 {
8307 virJSONValuePtr cmd;
8308 virJSONValuePtr reply = NULL;
8309 int ret = -1;
8310
8311 if (!(cmd = qemuMonitorJSONMakeCommand("blockdev-insert-medium",
8312 "s:id", id,
8313 "s:node-name", nodename,
8314 NULL)))
8315 return -1;
8316
8317 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
8318 goto cleanup;
8319
8320 if (qemuMonitorJSONCheckError(cmd, reply) < 0)
8321 goto cleanup;
8322
8323 ret = 0;
8324
8325 cleanup:
8326 virJSONValueFree(cmd);
8327 virJSONValueFree(reply);
8328 return ret;
8329 }
8330
8331
8332 /**
8333 * The function is used to retrieve the measurement of a SEV guest.
8334 * The measurement is signature of the memory contents that was encrypted
8335 * through the SEV launch flow.
8336 *
8337 * A example JSON output:
8338 *
8339 * { "execute" : "query-sev-launch-measure" }
8340 * { "return" : { "data" : "4l8LXeNlSPUDlXPJG5966/8%YZ" } }
8341 */
8342 char *
8343 qemuMonitorJSONGetSEVMeasurement(qemuMonitorPtr mon)
8344 {
8345 const char *tmp;
8346 char *measurement = NULL;
8347 virJSONValuePtr cmd;
8348 virJSONValuePtr reply = NULL;
8349 virJSONValuePtr data;
8350
8351 if (!(cmd = qemuMonitorJSONMakeCommand("query-sev-launch-measure", NULL)))
8352 return NULL;
8353
8354 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
8355 goto cleanup;
8356
8357 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
8358 goto cleanup;
8359
8360 data = virJSONValueObjectGetObject(reply, "return");
8361
8362 if (!(tmp = virJSONValueObjectGetString(data, "data")))
8363 goto cleanup;
8364
8365 if (VIR_STRDUP(measurement, tmp) < 0)
8366 goto cleanup;
8367
8368 cleanup:
8369 virJSONValueFree(cmd);
8370 virJSONValueFree(reply);
8371 return measurement;
8372 }
8373
8374
8375 /*
8376 * Example return data
8377 *
8378 * "return": [
8379 * { "connected": true, "id": "pr-helper0" }
8380 * ]
8381 */
8382 static int
8383 qemuMonitorJSONExtractPRManagerInfo(virJSONValuePtr reply,
8384 virHashTablePtr info)
8385 {
8386 qemuMonitorPRManagerInfoPtr entry = NULL;
8387 virJSONValuePtr data;
8388 int ret = -1;
8389 size_t i;
8390
8391 data = virJSONValueObjectGetArray(reply, "return");
8392
8393 for (i = 0; i < virJSONValueArraySize(data); i++) {
8394 virJSONValuePtr prManager = virJSONValueArrayGet(data, i);
8395 const char *alias;
8396
8397 if (!(alias = virJSONValueObjectGetString(prManager, "id")))
8398 goto malformed;
8399
8400 if (VIR_ALLOC(entry) < 0)
8401 goto cleanup;
8402
8403 if (virJSONValueObjectGetBoolean(prManager,
8404 "connected",
8405 &entry->connected) < 0) {
8406 goto malformed;
8407 }
8408
8409 if (virHashAddEntry(info, alias, entry) < 0)
8410 goto cleanup;
8411
8412 entry = NULL;
8413 }
8414
8415 ret = 0;
8416 cleanup:
8417 VIR_FREE(entry);
8418 return ret;
8419
8420 malformed:
8421 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
8422 _("malformed prManager reply"));
8423 goto cleanup;
8424 }
8425
8426
8427 int
8428 qemuMonitorJSONGetPRManagerInfo(qemuMonitorPtr mon,
8429 virHashTablePtr info)
8430 {
8431 int ret = -1;
8432 virJSONValuePtr cmd;
8433 virJSONValuePtr reply = NULL;
8434
8435 if (!(cmd = qemuMonitorJSONMakeCommand("query-pr-managers",
8436 NULL)))
8437 return -1;
8438
8439 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
8440 goto cleanup;
8441
8442 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
8443 goto cleanup;
8444
8445 ret = qemuMonitorJSONExtractPRManagerInfo(reply, info);
8446 cleanup:
8447 virJSONValueFree(cmd);
8448 virJSONValueFree(reply);
8449 return ret;
8450
8451 }
8452
8453
8454 static int
8455 qemuMonitorJSONExtractCurrentMachineInfo(virJSONValuePtr reply,
8456 qemuMonitorCurrentMachineInfoPtr info)
8457 {
8458 virJSONValuePtr data;
8459
8460 data = virJSONValueObjectGetObject(reply, "return");
8461 if (!data)
8462 goto malformed;
8463
8464 if (virJSONValueObjectGetBoolean(data, "wakeup-suspend-support",
8465 &info->wakeupSuspendSupport) < 0)
8466 goto malformed;
8467
8468 return 0;
8469
8470 malformed:
8471 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
8472 _("malformed qemu-current-machine reply"));
8473 return -1;
8474 }
8475
8476
8477 int
8478 qemuMonitorJSONGetCurrentMachineInfo(qemuMonitorPtr mon,
8479 qemuMonitorCurrentMachineInfoPtr info)
8480 {
8481 int ret = -1;
8482 virJSONValuePtr cmd;
8483 virJSONValuePtr reply = NULL;
8484
8485 if (!(cmd = qemuMonitorJSONMakeCommand("query-current-machine",
8486 NULL)))
8487 return -1;
8488
8489 if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
8490 goto cleanup;
8491
8492 if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
8493 goto cleanup;
8494
8495 ret = qemuMonitorJSONExtractCurrentMachineInfo(reply, info);
8496
8497 cleanup:
8498 virJSONValueFree(cmd);
8499 virJSONValueFree(reply);
8500 return ret;
8501 }