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