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                                                      &micros));
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", &parameters) <= 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