1 /*
2  * qemu_agent.c: interaction with QEMU guest agent
3  *
4  * Copyright (C) 2006-2014 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 <fcntl.h>
27 #include <sys/time.h>
28 #include <gio/gio.h>
29 
30 #include "qemu_agent.h"
31 #include "qemu_domain.h"
32 #include "viralloc.h"
33 #include "virlog.h"
34 #include "virerror.h"
35 #include "virjson.h"
36 #include "virfile.h"
37 #include "virprocess.h"
38 #include "virtime.h"
39 #include "virobject.h"
40 #include "virstring.h"
41 #include "virenum.h"
42 #include "virsocket.h"
43 #include "virutil.h"
44 
45 #define VIR_FROM_THIS VIR_FROM_QEMU
46 
47 VIR_LOG_INIT("qemu.qemu_agent");
48 
49 #define LINE_ENDING "\n"
50 
51 #define DEBUG_IO 0
52 #define DEBUG_RAW_IO 0
53 
54 /* We read from QEMU until seeing a \r\n pair to indicate a
55  * completed reply or event. To avoid memory denial-of-service
56  * though, we must have a size limit on amount of data we
57  * buffer. 10 MB is large enough that it ought to cope with
58  * normal QEMU replies, and small enough that we're not
59  * consuming unreasonable mem.
60  */
61 #define QEMU_AGENT_MAX_RESPONSE (10 * 1024 * 1024)
62 
63 typedef struct _qemuAgentMessage qemuAgentMessage;
64 struct _qemuAgentMessage {
65     char *txBuffer;
66     int txOffset;
67     int txLength;
68 
69     /* Used by the JSON agent to hold reply / error */
70     char *rxBuffer;
71     int rxLength;
72     void *rxObject;
73 
74     /* True if rxBuffer / rxObject are ready, or a
75      * fatal error occurred on the agent channel
76      */
77     bool finished;
78     /* true for sync command */
79     bool sync;
80     /* id of the issued sync command */
81     unsigned long long id;
82     bool first;
83 };
84 
85 
86 struct _qemuAgent {
87     virObjectLockable parent;
88 
89     virCond notify;
90 
91     int fd;
92 
93     GMainContext *context;
94     GSocket *socket;
95     GSource *watch;
96 
97     bool running;
98     bool singleSync;
99     bool inSync;
100 
101     virDomainObj *vm;
102 
103     qemuAgentCallbacks *cb;
104 
105     /* If there's a command being processed this will be
106      * non-NULL */
107     qemuAgentMessage *msg;
108 
109     /* Buffer incoming data ready for agent
110      * code to process & find message boundaries */
111     size_t bufferOffset;
112     size_t bufferLength;
113     char *buffer;
114 
115     /* If anything went wrong, this will be fed back
116      * the next agent msg */
117     virError lastError;
118 
119     /* Some guest agent commands don't return anything
120      * but fire up an event on qemu agent instead.
121      * Take that as indication of successful completion */
122     qemuAgentEvent await_event;
123     int timeout;
124 };
125 
126 static virClass *qemuAgentClass;
127 static void qemuAgentDispose(void *obj);
128 
qemuAgentOnceInit(void)129 static int qemuAgentOnceInit(void)
130 {
131     if (!VIR_CLASS_NEW(qemuAgent, virClassForObjectLockable()))
132         return -1;
133 
134     return 0;
135 }
136 
137 VIR_ONCE_GLOBAL_INIT(qemuAgent);
138 
139 
140 #if DEBUG_RAW_IO
141 static char *
qemuAgentEscapeNonPrintable(const char * text)142 qemuAgentEscapeNonPrintable(const char *text)
143 {
144     size_t i;
145     g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
146     for (i = 0; text[i] != '\0'; i++) {
147         if (text[i] == '\\')
148             virBufferAddLit(&buf, "\\\\");
149         else if (g_ascii_isprint(text[i]) || text[i] == '\n' ||
150                  (text[i] == '\r' && text[i+1] == '\n'))
151             virBufferAddChar(&buf, text[i]);
152         else
153             virBufferAsprintf(&buf, "\\x%02x", text[i]);
154     }
155     return virBufferContentAndReset(&buf);
156 }
157 #endif
158 
159 
qemuAgentDispose(void * obj)160 static void qemuAgentDispose(void *obj)
161 {
162     qemuAgent *agent = obj;
163 
164     VIR_DEBUG("agent=%p", agent);
165 
166     if (agent->vm)
167         virObjectUnref(agent->vm);
168     virCondDestroy(&agent->notify);
169     g_free(agent->buffer);
170     g_main_context_unref(agent->context);
171     virResetError(&agent->lastError);
172 }
173 
174 static int
qemuAgentOpenUnix(const char * socketpath)175 qemuAgentOpenUnix(const char *socketpath)
176 {
177     struct sockaddr_un addr;
178     int agentfd;
179 
180     if ((agentfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
181         virReportSystemError(errno,
182                              "%s", _("failed to create socket"));
183         return -1;
184     }
185 
186     if (virSetCloseExec(agentfd) < 0) {
187         virReportSystemError(errno, "%s",
188                              _("Unable to set agent "
189                                "close-on-exec flag"));
190         goto error;
191     }
192 
193     memset(&addr, 0, sizeof(addr));
194     addr.sun_family = AF_UNIX;
195     if (virStrcpyStatic(addr.sun_path, socketpath) < 0) {
196         virReportError(VIR_ERR_INTERNAL_ERROR,
197                        _("Socket path %s too big for destination"), socketpath);
198         goto error;
199     }
200 
201     if (connect(agentfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
202         virReportSystemError(errno, "%s",
203                              _("failed to connect to agent socket"));
204         goto error;
205     }
206 
207     return agentfd;
208 
209  error:
210     VIR_FORCE_CLOSE(agentfd);
211     return -1;
212 }
213 
214 
215 static int
qemuAgentIOProcessEvent(qemuAgent * agent,virJSONValue * obj)216 qemuAgentIOProcessEvent(qemuAgent *agent,
217                         virJSONValue *obj)
218 {
219     const char *type;
220     VIR_DEBUG("agent=%p obj=%p", agent, obj);
221 
222     type = virJSONValueObjectGetString(obj, "event");
223     if (!type) {
224         VIR_WARN("missing event type in message");
225         errno = EINVAL;
226         return -1;
227     }
228 
229     return 0;
230 }
231 
232 static int
qemuAgentIOProcessLine(qemuAgent * agent,const char * line,qemuAgentMessage * msg)233 qemuAgentIOProcessLine(qemuAgent *agent,
234                        const char *line,
235                        qemuAgentMessage *msg)
236 {
237     virJSONValue *obj = NULL;
238     int ret = -1;
239 
240     VIR_DEBUG("Line [%s]", line);
241 
242     if (!(obj = virJSONValueFromString(line))) {
243         /* receiving garbage on first sync is regular situation */
244         if (msg && msg->sync && msg->first) {
245             VIR_DEBUG("Received garbage on sync");
246             msg->finished = true;
247             return 0;
248         }
249 
250         goto cleanup;
251     }
252 
253     if (virJSONValueGetType(obj) != VIR_JSON_TYPE_OBJECT) {
254         virReportError(VIR_ERR_INTERNAL_ERROR,
255                        _("Parsed JSON reply '%s' isn't an object"), line);
256         goto cleanup;
257     }
258 
259     if (virJSONValueObjectHasKey(obj, "QMP") == 1) {
260         ret = 0;
261     } else if (virJSONValueObjectHasKey(obj, "event") == 1) {
262         ret = qemuAgentIOProcessEvent(agent, obj);
263     } else if (virJSONValueObjectHasKey(obj, "error") == 1 ||
264                virJSONValueObjectHasKey(obj, "return") == 1) {
265         if (msg) {
266             if (msg->sync) {
267                 unsigned long long id;
268 
269                 if (virJSONValueObjectGetNumberUlong(obj, "return", &id) < 0) {
270                     VIR_DEBUG("Ignoring delayed reply on sync");
271                     ret = 0;
272                     goto cleanup;
273                 }
274 
275                 VIR_DEBUG("Guest returned ID: %llu", id);
276 
277                 if (msg->id != id) {
278                     VIR_DEBUG("Guest agent returned ID: %llu instead of %llu",
279                               id, msg->id);
280                     ret = 0;
281                     goto cleanup;
282                 }
283             }
284             msg->rxObject = g_steal_pointer(&obj);
285             msg->finished = true;
286         } else {
287             /* we are out of sync */
288             VIR_DEBUG("Ignoring delayed reply");
289         }
290         ret = 0;
291     } else {
292         virReportError(VIR_ERR_INTERNAL_ERROR,
293                        _("Unknown JSON reply '%s'"), line);
294     }
295 
296  cleanup:
297     virJSONValueFree(obj);
298     return ret;
299 }
300 
qemuAgentIOProcessData(qemuAgent * agent,char * data,size_t len,qemuAgentMessage * msg)301 static int qemuAgentIOProcessData(qemuAgent *agent,
302                                   char *data,
303                                   size_t len,
304                                   qemuAgentMessage *msg)
305 {
306     int used = 0;
307     size_t i = 0;
308 #if DEBUG_IO
309 # if DEBUG_RAW_IO
310     g_autofree char *str1 = qemuAgentEscapeNonPrintable(data);
311     VIR_ERROR(_("[%s]"), str1);
312 # else
313     VIR_DEBUG("Data %zu bytes [%s]", len, data);
314 # endif
315 #endif
316 
317     while (used < len) {
318         char *nl = strstr(data + used, LINE_ENDING);
319 
320         if (nl) {
321             int got = nl - (data + used);
322             for (i = 0; i < strlen(LINE_ENDING); i++)
323                 data[used + got + i] = '\0';
324             if (qemuAgentIOProcessLine(agent, data + used, msg) < 0)
325                 return -1;
326             used += got + strlen(LINE_ENDING);
327         } else {
328             break;
329         }
330     }
331 
332     VIR_DEBUG("Total used %d bytes out of %zd available in buffer", used, len);
333     return used;
334 }
335 
336 /* This method processes data that has been received
337  * from the agent. Looking for async events and
338  * replies/errors.
339  */
340 static int
qemuAgentIOProcess(qemuAgent * agent)341 qemuAgentIOProcess(qemuAgent *agent)
342 {
343     int len;
344     qemuAgentMessage *msg = NULL;
345 
346     /* See if there's a message ready for reply; that is,
347      * one that has completed writing all its data.
348      */
349     if (agent->msg && agent->msg->txOffset == agent->msg->txLength)
350         msg = agent->msg;
351 
352 #if DEBUG_IO
353 # if DEBUG_RAW_IO
354     g_autofree char *str1 = qemuAgentEscapeNonPrintable(msg ? msg->txBuffer : "");
355     g_autofree char *str2 = qemuAgentEscapeNonPrintable(agent->buffer);
356     VIR_ERROR(_("Process %zu %p %p [[[%s]]][[[%s]]]"),
357               agent->bufferOffset, agent->msg, msg, str1, str2);
358 # else
359     VIR_DEBUG("Process %zu", agent->bufferOffset);
360 # endif
361 #endif
362 
363     len = qemuAgentIOProcessData(agent,
364                                  agent->buffer, agent->bufferOffset,
365                                  msg);
366 
367     if (len < 0)
368         return -1;
369 
370     if (len < agent->bufferOffset) {
371         memmove(agent->buffer, agent->buffer + len, agent->bufferOffset - len);
372         agent->bufferOffset -= len;
373     } else {
374         VIR_FREE(agent->buffer);
375         agent->bufferOffset = agent->bufferLength = 0;
376     }
377 #if DEBUG_IO
378     VIR_DEBUG("Process done %zu used %d", agent->bufferOffset, len);
379 #endif
380     if (msg && msg->finished)
381         virCondBroadcast(&agent->notify);
382     return len;
383 }
384 
385 
386 /*
387  * Called when the agent is able to write data
388  * Call this function while holding the agent lock.
389  */
390 static int
qemuAgentIOWrite(qemuAgent * agent)391 qemuAgentIOWrite(qemuAgent *agent)
392 {
393     int done;
394 
395     /* If no active message, or fully transmitted, then no-op */
396     if (!agent->msg || agent->msg->txOffset == agent->msg->txLength)
397         return 0;
398 
399     done = safewrite(agent->fd,
400                      agent->msg->txBuffer + agent->msg->txOffset,
401                      agent->msg->txLength - agent->msg->txOffset);
402 
403     if (done < 0) {
404         if (errno == EAGAIN)
405             return 0;
406 
407         virReportSystemError(errno, "%s",
408                              _("Unable to write to agent"));
409         return -1;
410     }
411     agent->msg->txOffset += done;
412     return done;
413 }
414 
415 /*
416  * Called when the agent has incoming data to read
417  * Call this function while holding the agent lock.
418  *
419  * Returns -1 on error, or number of bytes read
420  */
421 static int
qemuAgentIORead(qemuAgent * agent)422 qemuAgentIORead(qemuAgent *agent)
423 {
424     size_t avail = agent->bufferLength - agent->bufferOffset;
425     int ret = 0;
426 
427     if (avail < 1024) {
428         if (agent->bufferLength >= QEMU_AGENT_MAX_RESPONSE) {
429             virReportSystemError(ERANGE,
430                                  _("No complete agent response found in %d bytes"),
431                                  QEMU_AGENT_MAX_RESPONSE);
432             return -1;
433         }
434         VIR_REALLOC_N(agent->buffer, agent->bufferLength + 1024);
435         agent->bufferLength += 1024;
436         avail += 1024;
437     }
438 
439     /* Read as much as we can get into our buffer,
440        until we block on EAGAIN, or hit EOF */
441     while (avail > 1) {
442         int got;
443         got = read(agent->fd,
444                    agent->buffer + agent->bufferOffset,
445                    avail - 1);
446         if (got < 0) {
447             if (errno == EAGAIN)
448                 break;
449             virReportSystemError(errno, "%s",
450                                  _("Unable to read from agent"));
451             ret = -1;
452             break;
453         }
454         if (got == 0)
455             break;
456 
457         ret += got;
458         avail -= got;
459         agent->bufferOffset += got;
460         agent->buffer[agent->bufferOffset] = '\0';
461     }
462 
463 #if DEBUG_IO
464     VIR_DEBUG("Now read %zu bytes of data", agent->bufferOffset);
465 #endif
466 
467     return ret;
468 }
469 
470 
471 static gboolean
472 qemuAgentIO(GSocket *socket,
473             GIOCondition cond,
474             gpointer opaque);
475 
476 
477 static void
qemuAgentRegister(qemuAgent * agent)478 qemuAgentRegister(qemuAgent *agent)
479 {
480     GIOCondition cond = 0;
481 
482     if (agent->lastError.code == VIR_ERR_OK) {
483         cond |= G_IO_IN;
484 
485         if (agent->msg && agent->msg->txOffset < agent->msg->txLength)
486             cond |= G_IO_OUT;
487     }
488 
489     agent->watch = g_socket_create_source(agent->socket,
490                                         cond,
491                                         NULL);
492 
493     virObjectRef(agent);
494     g_source_set_callback(agent->watch,
495                           (GSourceFunc)qemuAgentIO,
496                           agent,
497                           (GDestroyNotify)virObjectUnref);
498 
499     g_source_attach(agent->watch,
500                     agent->context);
501 }
502 
503 
504 static void
qemuAgentUnregister(qemuAgent * agent)505 qemuAgentUnregister(qemuAgent *agent)
506 {
507     if (agent->watch) {
508         g_source_destroy(agent->watch);
509         vir_g_source_unref(agent->watch, agent->context);
510         agent->watch = NULL;
511     }
512 }
513 
514 
qemuAgentUpdateWatch(qemuAgent * agent)515 static void qemuAgentUpdateWatch(qemuAgent *agent)
516 {
517     qemuAgentUnregister(agent);
518     if (agent->socket)
519         qemuAgentRegister(agent);
520 }
521 
522 
523 static gboolean
qemuAgentIO(GSocket * socket G_GNUC_UNUSED,GIOCondition cond,gpointer opaque)524 qemuAgentIO(GSocket *socket G_GNUC_UNUSED,
525             GIOCondition cond,
526             gpointer opaque)
527 {
528     qemuAgent *agent = opaque;
529     bool error = false;
530     bool eof = false;
531 
532     virObjectRef(agent);
533     /* lock access to the agent and protect fd */
534     virObjectLock(agent);
535 #if DEBUG_IO
536     VIR_DEBUG("Agent %p I/O on watch %d socket %p cond %d", agent, agent->socket, cond);
537 #endif
538 
539     if (agent->fd == -1 || !agent->watch) {
540         virObjectUnlock(agent);
541         virObjectUnref(agent);
542         return G_SOURCE_REMOVE;
543     }
544 
545     if (agent->lastError.code != VIR_ERR_OK) {
546         if (cond & (G_IO_HUP | G_IO_ERR))
547             eof = true;
548         error = true;
549     } else {
550         if (cond & G_IO_OUT) {
551             if (qemuAgentIOWrite(agent) < 0)
552                 error = true;
553         }
554 
555         if (!error &&
556             cond & G_IO_IN) {
557             int got = qemuAgentIORead(agent);
558             if (got < 0) {
559                 error = true;
560             } else if (got == 0) {
561                 eof = true;
562             } else {
563                 /* Ignore hangup/error cond if we read some data, to
564                  * give time for that data to be consumed */
565                 cond = 0;
566 
567                 if (qemuAgentIOProcess(agent) < 0)
568                     error = true;
569             }
570         }
571 
572         if (!error &&
573             cond & G_IO_HUP) {
574             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
575                            _("End of file from agent socket"));
576             eof = true;
577         }
578 
579         if (!error && !eof &&
580             cond & G_IO_ERR) {
581             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
582                            _("Invalid file descriptor while waiting for agent"));
583             eof = true;
584         }
585     }
586 
587     if (error || eof) {
588         if (agent->lastError.code != VIR_ERR_OK) {
589             /* Already have an error, so clear any new error */
590             virResetLastError();
591         } else {
592             if (virGetLastErrorCode() == VIR_ERR_OK)
593                 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
594                                _("Error while processing agent IO"));
595             virCopyLastError(&agent->lastError);
596             virResetLastError();
597         }
598 
599         VIR_DEBUG("Error on agent %s", NULLSTR(agent->lastError.message));
600         /* If IO process resulted in an error & we have a message,
601          * then wakeup that waiter */
602         if (agent->msg && !agent->msg->finished) {
603             agent->msg->finished = true;
604             virCondSignal(&agent->notify);
605         }
606     }
607 
608     qemuAgentUpdateWatch(agent);
609 
610     /* We have to unlock to avoid deadlock against command thread,
611      * but is this safe ?  I think it is, because the callback
612      * will try to acquire the virDomainObj *mutex next */
613     if (eof) {
614         void (*eofNotify)(qemuAgent *, virDomainObj *)
615             = agent->cb->eofNotify;
616         virDomainObj *vm = agent->vm;
617 
618         /* Make sure anyone waiting wakes up now */
619         virCondSignal(&agent->notify);
620         virObjectUnlock(agent);
621         virObjectUnref(agent);
622         VIR_DEBUG("Triggering EOF callback");
623         (eofNotify)(agent, vm);
624     } else if (error) {
625         void (*errorNotify)(qemuAgent *, virDomainObj *)
626             = agent->cb->errorNotify;
627         virDomainObj *vm = agent->vm;
628 
629         /* Make sure anyone waiting wakes up now */
630         virCondSignal(&agent->notify);
631         virObjectUnlock(agent);
632         virObjectUnref(agent);
633         VIR_DEBUG("Triggering error callback");
634         (errorNotify)(agent, vm);
635     } else {
636         virObjectUnlock(agent);
637         virObjectUnref(agent);
638     }
639 
640     return G_SOURCE_REMOVE;
641 }
642 
643 
644 qemuAgent *
qemuAgentOpen(virDomainObj * vm,const virDomainChrSourceDef * config,GMainContext * context,qemuAgentCallbacks * cb,bool singleSync)645 qemuAgentOpen(virDomainObj *vm,
646               const virDomainChrSourceDef *config,
647               GMainContext *context,
648               qemuAgentCallbacks *cb,
649               bool singleSync)
650 {
651     qemuAgent *agent;
652     g_autoptr(GError) gerr = NULL;
653 
654     if (!cb || !cb->eofNotify) {
655         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
656                        _("EOF notify callback must be supplied"));
657         return NULL;
658     }
659 
660     if (qemuAgentInitialize() < 0)
661         return NULL;
662 
663     if (!(agent = virObjectLockableNew(qemuAgentClass)))
664         return NULL;
665 
666     agent->timeout = QEMU_DOMAIN_PRIVATE(vm)->agentTimeout;
667     agent->fd = -1;
668     if (virCondInit(&agent->notify) < 0) {
669         virReportSystemError(errno, "%s",
670                              _("cannot initialize agent condition"));
671         virObjectUnref(agent);
672         return NULL;
673     }
674     agent->vm = virObjectRef(vm);
675     agent->cb = cb;
676     agent->singleSync = singleSync;
677 
678     if (config->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
679         virReportError(VIR_ERR_INTERNAL_ERROR,
680                        _("unable to handle agent type: %s"),
681                        virDomainChrTypeToString(config->type));
682         goto cleanup;
683     }
684 
685     virObjectUnlock(vm);
686     agent->fd = qemuAgentOpenUnix(config->data.nix.path);
687     virObjectLock(vm);
688 
689     if (agent->fd == -1)
690         goto cleanup;
691 
692     agent->context = g_main_context_ref(context);
693 
694     agent->socket = g_socket_new_from_fd(agent->fd, &gerr);
695     if (!agent->socket) {
696         virReportError(VIR_ERR_INTERNAL_ERROR,
697                        _("Unable to create socket object: %s"),
698                        gerr->message);
699         goto cleanup;
700     }
701 
702     qemuAgentRegister(agent);
703 
704     agent->running = true;
705     VIR_DEBUG("New agent %p fd=%d", agent, agent->fd);
706 
707     return agent;
708 
709  cleanup:
710     qemuAgentClose(agent);
711     return NULL;
712 }
713 
714 
715 static void
qemuAgentNotifyCloseLocked(qemuAgent * agent)716 qemuAgentNotifyCloseLocked(qemuAgent *agent)
717 {
718     if (agent) {
719         agent->running = false;
720 
721         /* If there is somebody waiting for a message
722          * wake him up. No message will arrive anyway. */
723         if (agent->msg && !agent->msg->finished) {
724             agent->msg->finished = true;
725             virCondSignal(&agent->notify);
726         }
727     }
728 }
729 
730 
731 void
qemuAgentNotifyClose(qemuAgent * agent)732 qemuAgentNotifyClose(qemuAgent *agent)
733 {
734     if (!agent)
735         return;
736 
737     VIR_DEBUG("agent=%p", agent);
738 
739     virObjectLock(agent);
740     qemuAgentNotifyCloseLocked(agent);
741     virObjectUnlock(agent);
742 }
743 
744 
qemuAgentClose(qemuAgent * agent)745 void qemuAgentClose(qemuAgent *agent)
746 {
747     if (!agent)
748         return;
749 
750     VIR_DEBUG("agent=%p", agent);
751 
752     virObjectLock(agent);
753 
754     if (agent->socket) {
755         qemuAgentUnregister(agent);
756         g_object_unref(agent->socket);
757         agent->socket = NULL;
758         agent->fd = -1;
759     }
760 
761     qemuAgentNotifyCloseLocked(agent);
762     virObjectUnlock(agent);
763 
764     virObjectUnref(agent);
765 }
766 
767 #define QEMU_AGENT_WAIT_TIME 5
768 
769 /**
770  * qemuAgentSend:
771  * @agent: agent object
772  * @msg: Message
773  * @seconds: number of seconds to wait for the result, it can be either
774  *           -2, -1, 0 or positive.
775  *
776  * Send @msg to agent @agent. If @seconds is equal to
777  * VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK(-2), this function will block forever
778  * waiting for the result. The value of
779  * VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT(-1) means use default timeout value
780  * and VIR_DOMAIN_QEMU_AGENT_COMMAND_NOWAIT(0) makes this function return
781  * immediately without waiting. Any positive value means the number of seconds
782  * to wait for the result.
783  *
784  * Returns: 0 on success,
785  *          -2 on timeout,
786  *          -1 otherwise
787  */
qemuAgentSend(qemuAgent * agent,qemuAgentMessage * msg,int seconds)788 static int qemuAgentSend(qemuAgent *agent,
789                          qemuAgentMessage *msg,
790                          int seconds)
791 {
792     int ret = -1;
793     unsigned long long then = 0;
794 
795     /* Check whether qemu quit unexpectedly */
796     if (agent->lastError.code != VIR_ERR_OK) {
797         VIR_DEBUG("Attempt to send command while error is set %s",
798                   NULLSTR(agent->lastError.message));
799         virSetError(&agent->lastError);
800         return -1;
801     }
802 
803     if (seconds > VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) {
804         unsigned long long now;
805         if (virTimeMillisNow(&now) < 0)
806             return -1;
807         if (seconds == VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT)
808             seconds = QEMU_AGENT_WAIT_TIME;
809         then = now + seconds * 1000ull;
810     }
811 
812     agent->msg = msg;
813     qemuAgentUpdateWatch(agent);
814 
815     while (!agent->msg->finished) {
816         if ((then && virCondWaitUntil(&agent->notify, &agent->parent.lock, then) < 0) ||
817             (!then && virCondWait(&agent->notify, &agent->parent.lock) < 0)) {
818             if (errno == ETIMEDOUT) {
819                 virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
820                                _("Guest agent not available for now"));
821                 ret = -2;
822             } else {
823                 virReportSystemError(errno, "%s",
824                                      _("Unable to wait on agent socket "
825                                        "condition"));
826             }
827             agent->inSync = false;
828             goto cleanup;
829         }
830     }
831 
832     if (agent->lastError.code != VIR_ERR_OK) {
833         VIR_DEBUG("Send command resulted in error %s",
834                   NULLSTR(agent->lastError.message));
835         virSetError(&agent->lastError);
836         goto cleanup;
837     }
838 
839     ret = 0;
840 
841  cleanup:
842     agent->msg = NULL;
843     qemuAgentUpdateWatch(agent);
844 
845     return ret;
846 }
847 
848 
849 /**
850  * qemuAgentGuestSync:
851  * @agent: agent object
852  *
853  * Send guest-sync with unique ID
854  * and wait for reply. If we get one, check if
855  * received ID is equal to given.
856  *
857  * Returns: 0 on success,
858  *          -1 otherwise
859  */
860 static int
qemuAgentGuestSync(qemuAgent * agent)861 qemuAgentGuestSync(qemuAgent *agent)
862 {
863     int ret = -1;
864     int send_ret;
865     unsigned long long id;
866     qemuAgentMessage sync_msg;
867     int timeout = VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT;
868 
869     if (agent->singleSync && agent->inSync)
870         return 0;
871 
872     /* if user specified a custom agent timeout that is lower than the
873      * default timeout, use the shorter timeout instead */
874     if ((agent->timeout >= 0) && (agent->timeout < QEMU_AGENT_WAIT_TIME))
875         timeout = agent->timeout;
876 
877     memset(&sync_msg, 0, sizeof(sync_msg));
878     /* set only on first sync */
879     sync_msg.first = true;
880 
881  retry:
882     if (virTimeMillisNow(&id) < 0)
883         return -1;
884 
885     sync_msg.txBuffer = g_strdup_printf("{\"execute\":\"guest-sync\", "
886                                         "\"arguments\":{\"id\":%llu}}\n", id);
887 
888     sync_msg.txLength = strlen(sync_msg.txBuffer);
889     sync_msg.sync = true;
890     sync_msg.id = id;
891 
892     VIR_DEBUG("Sending guest-sync command with ID: %llu", id);
893 
894     send_ret = qemuAgentSend(agent, &sync_msg, timeout);
895 
896     VIR_DEBUG("qemuAgentSend returned: %d", send_ret);
897 
898     if (send_ret < 0)
899         goto cleanup;
900 
901     if (!sync_msg.rxObject) {
902         if (sync_msg.first) {
903             VIR_FREE(sync_msg.txBuffer);
904             memset(&sync_msg, 0, sizeof(sync_msg));
905             goto retry;
906         } else {
907             if (agent->running)
908                 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
909                                _("Missing agent reply object"));
910             else
911                 virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
912                                _("Guest agent disappeared while executing command"));
913             goto cleanup;
914         }
915     }
916 
917     if (agent->singleSync)
918         agent->inSync = true;
919 
920     ret = 0;
921 
922  cleanup:
923     virJSONValueFree(sync_msg.rxObject);
924     VIR_FREE(sync_msg.txBuffer);
925     return ret;
926 }
927 
928 static const char *
qemuAgentStringifyErrorClass(const char * klass)929 qemuAgentStringifyErrorClass(const char *klass)
930 {
931     if (STREQ_NULLABLE(klass, "BufferOverrun"))
932         return "Buffer overrun";
933     else if (STREQ_NULLABLE(klass, "CommandDisabled"))
934         return "The command has been disabled for this instance";
935     else if (STREQ_NULLABLE(klass, "CommandNotFound"))
936         return "The command has not been found";
937     else if (STREQ_NULLABLE(klass, "FdNotFound"))
938         return "File descriptor not found";
939     else if (STREQ_NULLABLE(klass, "InvalidParameter"))
940         return "Invalid parameter";
941     else if (STREQ_NULLABLE(klass, "InvalidParameterType"))
942         return "Invalid parameter type";
943     else if (STREQ_NULLABLE(klass, "InvalidParameterValue"))
944         return "Invalid parameter value";
945     else if (STREQ_NULLABLE(klass, "OpenFileFailed"))
946         return "Cannot open file";
947     else if (STREQ_NULLABLE(klass, "QgaCommandFailed"))
948         return "Guest agent command failed";
949     else if (STREQ_NULLABLE(klass, "QMPBadInputObjectMember"))
950         return "Bad QMP input object member";
951     else if (STREQ_NULLABLE(klass, "QMPExtraInputObjectMember"))
952         return "Unexpected extra object member";
953     else if (STREQ_NULLABLE(klass, "UndefinedError"))
954         return "An undefined error has occurred";
955     else if (STREQ_NULLABLE(klass, "Unsupported"))
956         return "this feature or command is not currently supported";
957     else if (klass)
958         return klass;
959     else
960         return "unknown QEMU command error";
961 }
962 
963 /* Ignoring OOM in this method, since we're already reporting
964  * a more important error
965  *
966  * XXX see qerror.h for different klasses & fill out useful params
967  */
968 static const char *
qemuAgentStringifyError(virJSONValue * error)969 qemuAgentStringifyError(virJSONValue *error)
970 {
971     const char *klass = virJSONValueObjectGetString(error, "class");
972     const char *detail = virJSONValueObjectGetString(error, "desc");
973 
974     /* The QMP 'desc' field is usually sufficient for our generic
975      * error reporting needs. However, if not present, translate
976      * the class into something readable.
977      */
978     if (!detail)
979         detail = qemuAgentStringifyErrorClass(klass);
980 
981     return detail;
982 }
983 
984 static const char *
qemuAgentCommandName(virJSONValue * cmd)985 qemuAgentCommandName(virJSONValue *cmd)
986 {
987     const char *name = virJSONValueObjectGetString(cmd, "execute");
988     if (name)
989         return name;
990     return "<unknown>";
991 }
992 
993 static int
qemuAgentCheckError(virJSONValue * cmd,virJSONValue * reply,bool report_unsupported)994 qemuAgentCheckError(virJSONValue *cmd,
995                     virJSONValue *reply,
996                     bool report_unsupported)
997 {
998     if (virJSONValueObjectHasKey(reply, "error")) {
999         virJSONValue *error = virJSONValueObjectGet(reply, "error");
1000         g_autofree char *cmdstr = virJSONValueToString(cmd, false);
1001         g_autofree char *replystr = virJSONValueToString(reply, false);
1002 
1003         /* Log the full JSON formatted command & error */
1004         VIR_DEBUG("unable to execute QEMU agent command %s: %s",
1005                   NULLSTR(cmdstr), NULLSTR(replystr));
1006 
1007         /* Only send the user the command name + friendly error */
1008         if (!error) {
1009             virReportError(VIR_ERR_INTERNAL_ERROR,
1010                            _("unable to execute QEMU agent command '%s'"),
1011                            qemuAgentCommandName(cmd));
1012             return -1;
1013         }
1014 
1015         if (!report_unsupported) {
1016             const char *klass = virJSONValueObjectGetString(error, "class");
1017 
1018             if (STREQ_NULLABLE(klass, "CommandNotFound") ||
1019                 STREQ_NULLABLE(klass, "CommandDisabled"))
1020                 return -2;
1021         }
1022 
1023         virReportError(VIR_ERR_INTERNAL_ERROR,
1024                        _("unable to execute QEMU agent command '%s': %s"),
1025                        qemuAgentCommandName(cmd),
1026                        qemuAgentStringifyError(error));
1027 
1028         return -1;
1029     }
1030     if (!virJSONValueObjectHasKey(reply, "return")) {
1031         g_autofree char *cmdstr = virJSONValueToString(cmd, false);
1032         g_autofree char *replystr = virJSONValueToString(reply, false);
1033 
1034         VIR_DEBUG("Neither 'return' nor 'error' is set in the JSON reply %s: %s",
1035                   NULLSTR(cmdstr), NULLSTR(replystr));
1036         virReportError(VIR_ERR_INTERNAL_ERROR,
1037                        _("unable to execute QEMU agent command '%s'"),
1038                        qemuAgentCommandName(cmd));
1039         return -1;
1040     }
1041     return 0;
1042 }
1043 
1044 static int
qemuAgentCommandFull(qemuAgent * agent,virJSONValue * cmd,virJSONValue ** reply,int seconds,bool report_unsupported)1045 qemuAgentCommandFull(qemuAgent *agent,
1046                      virJSONValue *cmd,
1047                      virJSONValue **reply,
1048                      int seconds,
1049                      bool report_unsupported)
1050 {
1051     int ret = -1;
1052     qemuAgentMessage msg;
1053     g_autofree char *cmdstr = NULL;
1054     int await_event = agent->await_event;
1055 
1056     *reply = NULL;
1057     memset(&msg, 0, sizeof(msg));
1058 
1059     if (!agent->running) {
1060         virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
1061                        _("Guest agent disappeared while executing command"));
1062         goto cleanup;
1063     }
1064 
1065     if (qemuAgentGuestSync(agent) < 0)
1066         goto cleanup;
1067 
1068     if (!(cmdstr = virJSONValueToString(cmd, false)))
1069         goto cleanup;
1070     msg.txBuffer = g_strdup_printf("%s" LINE_ENDING, cmdstr);
1071     msg.txLength = strlen(msg.txBuffer);
1072 
1073     VIR_DEBUG("Send command '%s' for write, seconds = %d", cmdstr, seconds);
1074 
1075     ret = qemuAgentSend(agent, &msg, seconds);
1076 
1077     VIR_DEBUG("Receive command reply ret=%d rxObject=%p",
1078               ret, msg.rxObject);
1079 
1080     if (ret < 0)
1081         goto cleanup;
1082 
1083     /* If we haven't obtained any reply but we wait for an
1084      * event, then don't report this as error */
1085     if (!msg.rxObject) {
1086         if (!await_event) {
1087             if (agent->running) {
1088                 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1089                                _("Missing agent reply object"));
1090             } else {
1091                 virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
1092                                _("Guest agent disappeared while executing command"));
1093             }
1094             ret = -1;
1095         }
1096         goto cleanup;
1097     }
1098 
1099     *reply = msg.rxObject;
1100     ret = qemuAgentCheckError(cmd, *reply, report_unsupported);
1101 
1102  cleanup:
1103     VIR_FREE(msg.txBuffer);
1104     agent->await_event = QEMU_AGENT_EVENT_NONE;
1105 
1106     return ret;
1107 }
1108 
1109 static int
qemuAgentCommand(qemuAgent * agent,virJSONValue * cmd,virJSONValue ** reply,int seconds)1110 qemuAgentCommand(qemuAgent *agent,
1111                  virJSONValue *cmd,
1112                  virJSONValue **reply,
1113                  int seconds)
1114 {
1115     return qemuAgentCommandFull(agent, cmd, reply, seconds, true);
1116 }
1117 
1118 static virJSONValue *G_GNUC_NULL_TERMINATED
qemuAgentMakeCommand(const char * cmdname,...)1119 qemuAgentMakeCommand(const char *cmdname,
1120                      ...)
1121 {
1122     g_autoptr(virJSONValue) obj = NULL;
1123     g_autoptr(virJSONValue) jargs = NULL;
1124     va_list args;
1125 
1126     va_start(args, cmdname);
1127 
1128     if (virJSONValueObjectAddVArgs(&jargs, args) < 0) {
1129         va_end(args);
1130         return NULL;
1131     }
1132 
1133     va_end(args);
1134 
1135     if (virJSONValueObjectAdd(&obj,
1136                               "s:execute", cmdname,
1137                               "A:arguments", &jargs,
1138                               NULL) < 0)
1139         return NULL;
1140 
1141     return g_steal_pointer(&obj);
1142 }
1143 
1144 static virJSONValue *
qemuAgentMakeStringsArray(const char ** strings,unsigned int len)1145 qemuAgentMakeStringsArray(const char **strings, unsigned int len)
1146 {
1147     size_t i;
1148     g_autoptr(virJSONValue) ret = virJSONValueNewArray();
1149 
1150     for (i = 0; i < len; i++) {
1151         g_autoptr(virJSONValue) str = virJSONValueNewString(strings[i]);
1152 
1153         if (virJSONValueArrayAppend(ret, &str) < 0)
1154             return NULL;
1155     }
1156 
1157     return g_steal_pointer(&ret);
1158 }
1159 
qemuAgentNotifyEvent(qemuAgent * agent,qemuAgentEvent event)1160 void qemuAgentNotifyEvent(qemuAgent *agent,
1161                           qemuAgentEvent event)
1162 {
1163     virObjectLock(agent);
1164 
1165     VIR_DEBUG("agent=%p event=%d await_event=%d", agent, event, agent->await_event);
1166     if (agent->await_event == event) {
1167         agent->await_event = QEMU_AGENT_EVENT_NONE;
1168         /* somebody waiting for this event, wake him up. */
1169         if (agent->msg && !agent->msg->finished) {
1170             agent->msg->finished = true;
1171             virCondSignal(&agent->notify);
1172         }
1173     }
1174 
1175     virObjectUnlock(agent);
1176 }
1177 
1178 VIR_ENUM_DECL(qemuAgentShutdownMode);
1179 
1180 VIR_ENUM_IMPL(qemuAgentShutdownMode,
1181               QEMU_AGENT_SHUTDOWN_LAST,
1182               "powerdown", "reboot", "halt",
1183 );
1184 
qemuAgentShutdown(qemuAgent * agent,qemuAgentShutdownMode mode)1185 int qemuAgentShutdown(qemuAgent *agent,
1186                       qemuAgentShutdownMode mode)
1187 {
1188     int ret = -1;
1189     virJSONValue *cmd;
1190     virJSONValue *reply = NULL;
1191 
1192     cmd = qemuAgentMakeCommand("guest-shutdown",
1193                                "s:mode", qemuAgentShutdownModeTypeToString(mode),
1194                                NULL);
1195     if (!cmd)
1196         return -1;
1197 
1198     if (mode == QEMU_AGENT_SHUTDOWN_REBOOT)
1199         agent->await_event = QEMU_AGENT_EVENT_RESET;
1200     else
1201         agent->await_event = QEMU_AGENT_EVENT_SHUTDOWN;
1202     ret = qemuAgentCommand(agent, cmd, &reply,
1203                            VIR_DOMAIN_QEMU_AGENT_COMMAND_SHUTDOWN);
1204 
1205     virJSONValueFree(cmd);
1206     virJSONValueFree(reply);
1207     return ret;
1208 }
1209 
1210 /*
1211  * qemuAgentFSFreeze:
1212  * @agent: agent object
1213  * @mountpoints: Array of mountpoint paths to be frozen, or NULL for all
1214  * @nmountpoints: Number of mountpoints to be frozen, or 0 for all
1215  *
1216  * Issue guest-fsfreeze-freeze command to guest agent,
1217  * which freezes file systems mounted on specified mountpoints
1218  * (or all file systems when @mountpoints is NULL), and returns
1219  * number of frozen file systems on success.
1220  *
1221  * Returns: number of file system frozen on success,
1222  *          -1 on error.
1223  */
qemuAgentFSFreeze(qemuAgent * agent,const char ** mountpoints,unsigned int nmountpoints)1224 int qemuAgentFSFreeze(qemuAgent *agent, const char **mountpoints,
1225                       unsigned int nmountpoints)
1226 {
1227     int ret = -1;
1228     virJSONValue *cmd;
1229     virJSONValue *arg = NULL;
1230     virJSONValue *reply = NULL;
1231 
1232     if (mountpoints && nmountpoints) {
1233         arg = qemuAgentMakeStringsArray(mountpoints, nmountpoints);
1234         if (!arg)
1235             return -1;
1236 
1237         cmd = qemuAgentMakeCommand("guest-fsfreeze-freeze-list",
1238                                    "a:mountpoints", &arg, NULL);
1239     } else {
1240         cmd = qemuAgentMakeCommand("guest-fsfreeze-freeze", NULL);
1241     }
1242 
1243     if (!cmd)
1244         goto cleanup;
1245 
1246     if (qemuAgentCommand(agent, cmd, &reply, agent->timeout) < 0)
1247         goto cleanup;
1248 
1249     if (virJSONValueObjectGetNumberInt(reply, "return", &ret) < 0) {
1250         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1251                        _("malformed return value"));
1252     }
1253 
1254  cleanup:
1255     virJSONValueFree(arg);
1256     virJSONValueFree(cmd);
1257     virJSONValueFree(reply);
1258     return ret;
1259 }
1260 
1261 /*
1262  * qemuAgentFSThaw:
1263  * @agent: agent object
1264  *
1265  * Issue guest-fsfreeze-thaw command to guest agent,
1266  * which unfreezes all mounted file systems and returns
1267  * number of thawed file systems on success.
1268  *
1269  * Returns: number of file system thawed on success,
1270  *          -1 on error.
1271  */
qemuAgentFSThaw(qemuAgent * agent)1272 int qemuAgentFSThaw(qemuAgent *agent)
1273 {
1274     int ret = -1;
1275     virJSONValue *cmd;
1276     virJSONValue *reply = NULL;
1277 
1278     cmd = qemuAgentMakeCommand("guest-fsfreeze-thaw", NULL);
1279 
1280     if (!cmd)
1281         return -1;
1282 
1283     if (qemuAgentCommand(agent, cmd, &reply, agent->timeout) < 0)
1284         goto cleanup;
1285 
1286     if (virJSONValueObjectGetNumberInt(reply, "return", &ret) < 0) {
1287         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1288                        _("malformed return value"));
1289     }
1290 
1291  cleanup:
1292     virJSONValueFree(cmd);
1293     virJSONValueFree(reply);
1294     return ret;
1295 }
1296 
1297 VIR_ENUM_DECL(qemuAgentSuspendMode);
1298 
1299 VIR_ENUM_IMPL(qemuAgentSuspendMode,
1300               VIR_NODE_SUSPEND_TARGET_LAST,
1301               "guest-suspend-ram",
1302               "guest-suspend-disk",
1303               "guest-suspend-hybrid",
1304 );
1305 
1306 int
qemuAgentSuspend(qemuAgent * agent,unsigned int target)1307 qemuAgentSuspend(qemuAgent *agent,
1308                  unsigned int target)
1309 {
1310     int ret = -1;
1311     virJSONValue *cmd;
1312     virJSONValue *reply = NULL;
1313 
1314     cmd = qemuAgentMakeCommand(qemuAgentSuspendModeTypeToString(target),
1315                                NULL);
1316     if (!cmd)
1317         return -1;
1318 
1319     agent->await_event = QEMU_AGENT_EVENT_SUSPEND;
1320     ret = qemuAgentCommand(agent, cmd, &reply, agent->timeout);
1321 
1322     virJSONValueFree(cmd);
1323     virJSONValueFree(reply);
1324     return ret;
1325 }
1326 
1327 int
qemuAgentArbitraryCommand(qemuAgent * agent,const char * cmd_str,char ** result,int timeout)1328 qemuAgentArbitraryCommand(qemuAgent *agent,
1329                           const char *cmd_str,
1330                           char **result,
1331                           int timeout)
1332 {
1333     int ret = -1;
1334     virJSONValue *cmd = NULL;
1335     virJSONValue *reply = NULL;
1336 
1337     *result = NULL;
1338     if (timeout < VIR_DOMAIN_QEMU_AGENT_COMMAND_MIN) {
1339         virReportError(VIR_ERR_INVALID_ARG,
1340                        _("guest agent timeout '%d' is "
1341                          "less than the minimum '%d'"),
1342                        timeout, VIR_DOMAIN_QEMU_AGENT_COMMAND_MIN);
1343         goto cleanup;
1344     }
1345 
1346     if (!(cmd = virJSONValueFromString(cmd_str)))
1347         goto cleanup;
1348 
1349     if ((ret = qemuAgentCommand(agent, cmd, &reply, timeout)) < 0)
1350         goto cleanup;
1351 
1352     if (!(*result = virJSONValueToString(reply, false)))
1353         ret = -1;
1354 
1355 
1356  cleanup:
1357     virJSONValueFree(cmd);
1358     virJSONValueFree(reply);
1359     return ret;
1360 }
1361 
1362 int
qemuAgentFSTrim(qemuAgent * agent,unsigned long long minimum)1363 qemuAgentFSTrim(qemuAgent *agent,
1364                 unsigned long long minimum)
1365 {
1366     int ret = -1;
1367     virJSONValue *cmd;
1368     virJSONValue *reply = NULL;
1369 
1370     cmd = qemuAgentMakeCommand("guest-fstrim",
1371                                "U:minimum", minimum,
1372                                NULL);
1373     if (!cmd)
1374         return ret;
1375 
1376     ret = qemuAgentCommand(agent, cmd, &reply, agent->timeout);
1377 
1378     virJSONValueFree(cmd);
1379     virJSONValueFree(reply);
1380     return ret;
1381 }
1382 
1383 int
qemuAgentGetVCPUs(qemuAgent * agent,qemuAgentCPUInfo ** info)1384 qemuAgentGetVCPUs(qemuAgent *agent,
1385                   qemuAgentCPUInfo **info)
1386 {
1387     int ret = -1;
1388     size_t i;
1389     virJSONValue *cmd;
1390     virJSONValue *reply = NULL;
1391     virJSONValue *data = NULL;
1392     size_t ndata;
1393 
1394     if (!(cmd = qemuAgentMakeCommand("guest-get-vcpus", NULL)))
1395         return -1;
1396 
1397     if (qemuAgentCommand(agent, cmd, &reply, agent->timeout) < 0)
1398         goto cleanup;
1399 
1400     if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
1401         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1402                        _("guest-get-vcpus reply was missing return data"));
1403         goto cleanup;
1404     }
1405 
1406     ndata = virJSONValueArraySize(data);
1407 
1408     *info = g_new0(qemuAgentCPUInfo, ndata);
1409 
1410     for (i = 0; i < ndata; i++) {
1411         virJSONValue *entry = virJSONValueArrayGet(data, i);
1412         qemuAgentCPUInfo *in = *info + i;
1413 
1414         if (!entry) {
1415             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1416                            _("array element missing in guest-get-vcpus return "
1417                              "value"));
1418             goto cleanup;
1419         }
1420 
1421         if (virJSONValueObjectGetNumberUint(entry, "logical-id", &in->id) < 0) {
1422             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1423                            _("'logical-id' missing in reply of guest-get-vcpus"));
1424             goto cleanup;
1425         }
1426 
1427         if (virJSONValueObjectGetBoolean(entry, "online", &in->online) < 0) {
1428             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1429                            _("'online' missing in reply of guest-get-vcpus"));
1430             goto cleanup;
1431         }
1432 
1433         if (virJSONValueObjectGetBoolean(entry, "can-offline",
1434                                          &in->offlinable) < 0) {
1435             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1436                            _("'can-offline' missing in reply of guest-get-vcpus"));
1437             goto cleanup;
1438         }
1439     }
1440 
1441     ret = ndata;
1442 
1443  cleanup:
1444     virJSONValueFree(cmd);
1445     virJSONValueFree(reply);
1446     return ret;
1447 }
1448 
1449 
1450 /* returns the value provided by the guest agent or -1 on internal error */
1451 static int
qemuAgentSetVCPUsCommand(qemuAgent * agent,qemuAgentCPUInfo * info,size_t ninfo,int * nmodified)1452 qemuAgentSetVCPUsCommand(qemuAgent *agent,
1453                          qemuAgentCPUInfo *info,
1454                          size_t ninfo,
1455                          int *nmodified)
1456 {
1457     g_autoptr(virJSONValue) cmd = NULL;
1458     g_autoptr(virJSONValue) reply = NULL;
1459     g_autoptr(virJSONValue) cpus = virJSONValueNewArray();
1460     size_t i;
1461     int ret;
1462 
1463     *nmodified = 0;
1464 
1465     for (i = 0; i < ninfo; i++) {
1466         qemuAgentCPUInfo *in = &info[i];
1467         g_autoptr(virJSONValue) cpu = virJSONValueNewObject();
1468 
1469         /* don't set state for cpus that were not touched */
1470         if (!in->modified)
1471             continue;
1472 
1473         (*nmodified)++;
1474 
1475         if (virJSONValueObjectAppendNumberInt(cpu, "logical-id", in->id) < 0)
1476             return -1;
1477 
1478         if (virJSONValueObjectAppendBoolean(cpu, "online", in->online) < 0)
1479             return -1;
1480 
1481         if (virJSONValueArrayAppend(cpus, &cpu) < 0)
1482             return -1;
1483     }
1484 
1485     if (*nmodified == 0)
1486         return 0;
1487 
1488     if (!(cmd = qemuAgentMakeCommand("guest-set-vcpus",
1489                                      "a:vcpus", &cpus,
1490                                      NULL)))
1491         return -1;
1492 
1493     if (qemuAgentCommand(agent, cmd, &reply, agent->timeout) < 0)
1494         return -1;
1495 
1496     /* All negative values are invalid. Return of 0 is bogus since we wouldn't
1497      * call the guest agent so that 0 cpus would be set successfully. Reporting
1498      * more successfully set vcpus that we've asked for is invalid. */
1499     if (virJSONValueObjectGetNumberInt(reply, "return", &ret) < 0 ||
1500         ret <= 0 || ret > *nmodified) {
1501         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1502                        _("guest agent returned malformed or invalid return value"));
1503         return -1;
1504     }
1505 
1506     return ret;
1507 }
1508 
1509 
1510 /**
1511  * Set the VCPU state using guest agent.
1512  *
1513  * Attempts to set the guest agent state for all cpus or until a proper error is
1514  * reported by the guest agent. This may require multiple calls.
1515  *
1516  * Returns -1 on error, 0 on success.
1517  */
1518 int
qemuAgentSetVCPUs(qemuAgent * agent,qemuAgentCPUInfo * info,size_t ninfo)1519 qemuAgentSetVCPUs(qemuAgent *agent,
1520                   qemuAgentCPUInfo *info,
1521                   size_t ninfo)
1522 {
1523     int rv;
1524     int nmodified;
1525     size_t i;
1526 
1527     do {
1528         if ((rv = qemuAgentSetVCPUsCommand(agent, info, ninfo, &nmodified)) < 0)
1529             return -1;
1530 
1531         /* all vcpus were set successfully */
1532         if (rv == nmodified)
1533             return 0;
1534 
1535         /* un-mark vcpus that were already set */
1536         for (i = 0; i < ninfo && rv > 0; i++) {
1537             if (!info[i].modified)
1538                 continue;
1539 
1540             info[i].modified = false;
1541             rv--;
1542         }
1543     } while (1);
1544 
1545     return 0;
1546 }
1547 
1548 
1549 /* modify the cpu info structure to set the correct amount of cpus */
1550 int
qemuAgentUpdateCPUInfo(unsigned int nvcpus,qemuAgentCPUInfo * cpuinfo,int ncpuinfo)1551 qemuAgentUpdateCPUInfo(unsigned int nvcpus,
1552                        qemuAgentCPUInfo *cpuinfo,
1553                        int ncpuinfo)
1554 {
1555     size_t i;
1556     int nonline = 0;
1557     int nofflinable = 0;
1558     ssize_t cpu0 = -1;
1559 
1560     /* count the active and offlinable cpus */
1561     for (i = 0; i < ncpuinfo; i++) {
1562         if (cpuinfo[i].id == 0)
1563             cpu0 = i;
1564 
1565         if (cpuinfo[i].online)
1566             nonline++;
1567 
1568         if (cpuinfo[i].offlinable && cpuinfo[i].online)
1569             nofflinable++;
1570 
1571         /* This shouldn't happen, but we can't trust the guest agent */
1572         if (!cpuinfo[i].online && !cpuinfo[i].offlinable) {
1573             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1574                            _("Invalid data provided by guest agent"));
1575             return -1;
1576         }
1577     }
1578 
1579     /* CPU0 was made offlinable in linux a while ago, but certain parts (suspend
1580      * to ram) of the kernel still don't cope well with that. Make sure that if
1581      * all remaining vCPUs are offlinable, vCPU0 will not be selected to be
1582      * offlined automatically */
1583     if (nofflinable == nonline && cpu0 >= 0 && cpuinfo[cpu0].online) {
1584         cpuinfo[cpu0].offlinable = false;
1585         nofflinable--;
1586     }
1587 
1588     /* the guest agent reported less cpus than requested */
1589     if (nvcpus > ncpuinfo) {
1590         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1591                        _("guest agent reports less cpu than requested"));
1592         return -1;
1593     }
1594 
1595     /* not enough offlinable CPUs to support the request */
1596     if (nvcpus < nonline - nofflinable) {
1597         virReportError(VIR_ERR_INVALID_ARG, "%s",
1598                        _("Cannot offline enough CPUs"));
1599         return -1;
1600     }
1601 
1602     for (i = 0; i < ncpuinfo; i++) {
1603         if (nvcpus < nonline) {
1604             /* unplug */
1605             if (cpuinfo[i].offlinable && cpuinfo[i].online) {
1606                 cpuinfo[i].online = false;
1607                 cpuinfo[i].modified = true;
1608                 nonline--;
1609             }
1610         } else if (nvcpus > nonline) {
1611             /* plug */
1612             if (!cpuinfo[i].online) {
1613                 cpuinfo[i].online = true;
1614                 cpuinfo[i].modified = true;
1615                 nonline++;
1616             }
1617         } else {
1618             /* done */
1619             break;
1620         }
1621     }
1622 
1623     return 0;
1624 }
1625 
1626 
1627 /**
1628  * qemuAgentGetHostname:
1629  *
1630  * Gets the guest hostname using the guest agent.
1631  *
1632  * Returns 0 on success and fills @hostname. On error -1 is returned with an
1633  * error reported and if '@report_unsupported' is false -2 is returned if the
1634  * guest agent does not support the command without reporting an error
1635  */
1636 int
qemuAgentGetHostname(qemuAgent * agent,char ** hostname,bool report_unsupported)1637 qemuAgentGetHostname(qemuAgent *agent,
1638                      char **hostname,
1639                      bool report_unsupported)
1640 {
1641     g_autoptr(virJSONValue) cmd = qemuAgentMakeCommand("guest-get-host-name", NULL);
1642     g_autoptr(virJSONValue) reply = NULL;
1643     virJSONValue *data = NULL;
1644     const char *result = NULL;
1645     int rc;
1646 
1647     if (!cmd)
1648         return -1;
1649 
1650     if ((rc = qemuAgentCommandFull(agent, cmd, &reply, agent->timeout,
1651                                    report_unsupported)) < 0)
1652         return rc;
1653 
1654     if (!(data = virJSONValueObjectGet(reply, "return"))) {
1655         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1656                        _("malformed return value"));
1657         return -1;
1658     }
1659 
1660     if (!(result = virJSONValueObjectGetString(data, "host-name"))) {
1661         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1662                        _("'host-name' missing in guest-get-host-name reply"));
1663         return -1;
1664     }
1665 
1666     *hostname = g_strdup(result);
1667 
1668     return 0;
1669 }
1670 
1671 
1672 int
qemuAgentGetTime(qemuAgent * agent,long long * seconds,unsigned int * nseconds)1673 qemuAgentGetTime(qemuAgent *agent,
1674                  long long *seconds,
1675                  unsigned int *nseconds)
1676 {
1677     int ret = -1;
1678     unsigned long long json_time;
1679     virJSONValue *cmd;
1680     virJSONValue *reply = NULL;
1681 
1682     cmd = qemuAgentMakeCommand("guest-get-time",
1683                                NULL);
1684     if (!cmd)
1685         return ret;
1686 
1687     if (qemuAgentCommand(agent, cmd, &reply, agent->timeout) < 0)
1688         goto cleanup;
1689 
1690     if (virJSONValueObjectGetNumberUlong(reply, "return", &json_time) < 0) {
1691         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1692                        _("malformed return value"));
1693         goto cleanup;
1694     }
1695 
1696     /* guest agent returns time in nanoseconds,
1697      * we need it in seconds here */
1698     *seconds = json_time / 1000000000LL;
1699     *nseconds = json_time % 1000000000LL;
1700     ret = 0;
1701 
1702  cleanup:
1703     virJSONValueFree(cmd);
1704     virJSONValueFree(reply);
1705     return ret;
1706 }
1707 
1708 
1709 /**
1710  * qemuAgentSetTime:
1711  * @setTime: time to set
1712  * @sync: let guest agent to read domain's RTC (@setTime is ignored)
1713  */
1714 int
qemuAgentSetTime(qemuAgent * agent,long long seconds,unsigned int nseconds,bool rtcSync)1715 qemuAgentSetTime(qemuAgent *agent,
1716                 long long seconds,
1717                 unsigned int nseconds,
1718                 bool rtcSync)
1719 {
1720     int ret = -1;
1721     virJSONValue *cmd;
1722     virJSONValue *reply = NULL;
1723 
1724     if (rtcSync) {
1725         cmd = qemuAgentMakeCommand("guest-set-time", NULL);
1726     } else {
1727         /* guest agent expect time with nanosecond granularity.
1728          * Impressing. */
1729         long long json_time;
1730 
1731         /* Check if we overflow. For some reason qemu doesn't handle unsigned
1732          * long long on the agent well as it silently truncates numbers to
1733          * signed long long. Therefore we must check overflow against LLONG_MAX
1734          * not ULLONG_MAX. */
1735         if (seconds > LLONG_MAX / 1000000000LL) {
1736             virReportError(VIR_ERR_INVALID_ARG,
1737                            _("Time '%lld' is too big for guest agent"),
1738                            seconds);
1739             return ret;
1740         }
1741 
1742         json_time = seconds * 1000000000LL;
1743         json_time += nseconds;
1744         cmd = qemuAgentMakeCommand("guest-set-time",
1745                                    "I:time", json_time,
1746                                    NULL);
1747     }
1748 
1749     if (!cmd)
1750         return ret;
1751 
1752     if (qemuAgentCommand(agent, cmd, &reply, agent->timeout) < 0)
1753         goto cleanup;
1754 
1755     ret = 0;
1756  cleanup:
1757     virJSONValueFree(cmd);
1758     virJSONValueFree(reply);
1759     return ret;
1760 }
1761 
1762 void
qemuAgentDiskAddressFree(qemuAgentDiskAddress * info)1763 qemuAgentDiskAddressFree(qemuAgentDiskAddress *info)
1764 {
1765     if (!info)
1766         return;
1767 
1768     g_free(info->serial);
1769     g_free(info->bus_type);
1770     g_free(info->devnode);
1771     g_free(info->ccw_addr);
1772     g_free(info);
1773 }
1774 
1775 
1776 void
qemuAgentDiskInfoFree(qemuAgentDiskInfo * info)1777 qemuAgentDiskInfoFree(qemuAgentDiskInfo *info)
1778 {
1779     if (!info)
1780         return;
1781 
1782     g_free(info->name);
1783     g_strfreev(info->dependencies);
1784     qemuAgentDiskAddressFree(info->address);
1785     g_free(info->alias);
1786     g_free(info);
1787 }
1788 
1789 
1790 void
qemuAgentFSInfoFree(qemuAgentFSInfo * info)1791 qemuAgentFSInfoFree(qemuAgentFSInfo *info)
1792 {
1793     size_t i;
1794 
1795     if (!info)
1796         return;
1797 
1798     g_free(info->mountpoint);
1799     g_free(info->name);
1800     g_free(info->fstype);
1801 
1802     for (i = 0; i < info->ndisks; i++)
1803         qemuAgentDiskAddressFree(info->disks[i]);
1804     g_free(info->disks);
1805 
1806     g_free(info);
1807 }
1808 
1809 
1810 static qemuAgentDiskAddress *
qemuAgentGetDiskAddress(virJSONValue * json)1811 qemuAgentGetDiskAddress(virJSONValue *json)
1812 {
1813     virJSONValue *pci;
1814     virJSONValue *ccw;
1815     g_autoptr(qemuAgentDiskAddress) addr = NULL;
1816 
1817     addr = g_new0(qemuAgentDiskAddress, 1);
1818     addr->bus_type = g_strdup(virJSONValueObjectGetString(json, "bus-type"));
1819     addr->serial = g_strdup(virJSONValueObjectGetString(json, "serial"));
1820     addr->devnode = g_strdup(virJSONValueObjectGetString(json, "dev"));
1821 
1822 #define GET_DISK_ADDR(jsonObject, var, name) \
1823     do { \
1824         if (virJSONValueObjectGetNumberUint(jsonObject, name, var) < 0) { \
1825             virReportError(VIR_ERR_INTERNAL_ERROR, \
1826                            _("'%s' missing"), name); \
1827             return NULL; \
1828         } \
1829     } while (0)
1830 
1831     GET_DISK_ADDR(json, &addr->bus, "bus");
1832     GET_DISK_ADDR(json, &addr->target, "target");
1833     GET_DISK_ADDR(json, &addr->unit, "unit");
1834 
1835     if (!(pci = virJSONValueObjectGet(json, "pci-controller"))) {
1836         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1837                        _("'pci-controller' missing"));
1838         return NULL;
1839     }
1840 
1841     GET_DISK_ADDR(pci, &addr->pci_controller.domain, "domain");
1842     GET_DISK_ADDR(pci, &addr->pci_controller.bus, "bus");
1843     GET_DISK_ADDR(pci, &addr->pci_controller.slot, "slot");
1844     GET_DISK_ADDR(pci, &addr->pci_controller.function, "function");
1845 
1846     if ((ccw = virJSONValueObjectGet(json, "ccw-address"))) {
1847         g_autofree virDomainDeviceCCWAddress *ccw_addr = NULL;
1848 
1849         ccw_addr = g_new0(virDomainDeviceCCWAddress, 1);
1850 
1851         GET_DISK_ADDR(ccw, &ccw_addr->cssid, "cssid");
1852         if (ccw_addr->cssid == 0)  /* Guest CSSID 0 is 0xfe on host */
1853             ccw_addr->cssid = 0xfe;
1854         GET_DISK_ADDR(ccw, &ccw_addr->ssid, "ssid");
1855         GET_DISK_ADDR(ccw, &ccw_addr->devno, "devno");
1856 
1857         addr->ccw_addr = g_steal_pointer(&ccw_addr);
1858     }
1859 #undef GET_DISK_ADDR
1860 
1861     return g_steal_pointer(&addr);
1862 }
1863 
1864 
1865 static int
qemuAgentGetFSInfoFillDisks(virJSONValue * jsondisks,qemuAgentFSInfo * fsinfo)1866 qemuAgentGetFSInfoFillDisks(virJSONValue *jsondisks,
1867                             qemuAgentFSInfo *fsinfo)
1868 {
1869     size_t ndisks;
1870     size_t i;
1871 
1872     if (!virJSONValueIsArray(jsondisks)) {
1873         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1874                        _("Malformed guest-get-fsinfo 'disk' data array"));
1875         return -1;
1876     }
1877 
1878     ndisks = virJSONValueArraySize(jsondisks);
1879 
1880     if (ndisks)
1881         fsinfo->disks = g_new0(qemuAgentDiskAddress *, ndisks);
1882     fsinfo->ndisks = ndisks;
1883 
1884     for (i = 0; i < fsinfo->ndisks; i++) {
1885         virJSONValue *jsondisk = virJSONValueArrayGet(jsondisks, i);
1886 
1887         if (!jsondisk) {
1888             virReportError(VIR_ERR_INTERNAL_ERROR,
1889                            _("array element '%zd' of '%zd' missing in "
1890                              "guest-get-fsinfo 'disk' data"),
1891                            i, fsinfo->ndisks);
1892             return -1;
1893         }
1894 
1895         if (!(fsinfo->disks[i] = qemuAgentGetDiskAddress(jsondisk)))
1896             return -1;
1897     }
1898 
1899     return 0;
1900 }
1901 
1902 /* Returns: number of entries in '@info' on success
1903  *          -2 when agent command is not supported by the agent and
1904  *             'report_unsupported' is false (libvirt error is not reported)
1905  *          -1 otherwise (libvirt error is reported)
1906  */
1907 int
qemuAgentGetFSInfo(qemuAgent * agent,qemuAgentFSInfo *** info,bool report_unsupported)1908 qemuAgentGetFSInfo(qemuAgent *agent,
1909                    qemuAgentFSInfo ***info,
1910                    bool report_unsupported)
1911 {
1912     size_t i;
1913     int ret = -1;
1914     g_autoptr(virJSONValue) cmd = NULL;
1915     g_autoptr(virJSONValue) reply = NULL;
1916     virJSONValue *data;
1917     size_t ndata = 0;
1918     qemuAgentFSInfo **info_ret = NULL;
1919     int rc;
1920 
1921     cmd = qemuAgentMakeCommand("guest-get-fsinfo", NULL);
1922     if (!cmd)
1923         return ret;
1924 
1925     if ((rc = qemuAgentCommandFull(agent, cmd, &reply, agent->timeout,
1926                                    report_unsupported)) < 0)
1927         return rc;
1928 
1929     if (!(data = virJSONValueObjectGet(reply, "return"))) {
1930         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1931                        _("guest-get-fsinfo reply was missing return data"));
1932         goto cleanup;
1933     }
1934 
1935     if (!virJSONValueIsArray(data)) {
1936         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1937                        _("Malformed guest-get-fsinfo data array"));
1938         goto cleanup;
1939     }
1940 
1941     ndata = virJSONValueArraySize(data);
1942     if (ndata == 0) {
1943         ret = 0;
1944         *info = NULL;
1945         goto cleanup;
1946     }
1947     info_ret = g_new0(qemuAgentFSInfo *, ndata);
1948 
1949     for (i = 0; i < ndata; i++) {
1950         /* Reverse the order to arrange in mount order */
1951         virJSONValue *entry = virJSONValueArrayGet(data, ndata - 1 - i);
1952         virJSONValue *disk;
1953         unsigned long long bytes_val;
1954         const char *result = NULL;
1955 
1956         if (!entry) {
1957             virReportError(VIR_ERR_INTERNAL_ERROR,
1958                            _("array element '%zd' of '%zd' missing in "
1959                              "guest-get-fsinfo return data"),
1960                            i, ndata);
1961             goto cleanup;
1962         }
1963 
1964         info_ret[i] = g_new0(qemuAgentFSInfo, 1);
1965 
1966         if (!(result = virJSONValueObjectGetString(entry, "mountpoint"))) {
1967             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1968                            _("'mountpoint' missing in reply of "
1969                              "guest-get-fsinfo"));
1970             goto cleanup;
1971         }
1972 
1973         info_ret[i]->mountpoint = g_strdup(result);
1974 
1975         if (!(result = virJSONValueObjectGetString(entry, "name"))) {
1976             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1977                            _("'name' missing in reply of guest-get-fsinfo"));
1978             goto cleanup;
1979         }
1980 
1981         info_ret[i]->name = g_strdup(result);
1982 
1983         if (!(result = virJSONValueObjectGetString(entry, "type"))) {
1984             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1985                            _("'type' missing in reply of guest-get-fsinfo"));
1986             goto cleanup;
1987         }
1988 
1989         info_ret[i]->fstype = g_strdup(result);
1990 
1991 
1992         /* 'used-bytes' and 'total-bytes' were added in qemu-ga 3.0 */
1993         if (virJSONValueObjectHasKey(entry, "used-bytes")) {
1994             if (virJSONValueObjectGetNumberUlong(entry, "used-bytes",
1995                                                  &bytes_val) < 0) {
1996                 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1997                                _("Error getting 'used-bytes' in reply of guest-get-fsinfo"));
1998                 goto cleanup;
1999             }
2000             info_ret[i]->used_bytes = bytes_val;
2001         } else {
2002             info_ret[i]->used_bytes = -1;
2003         }
2004 
2005         if (virJSONValueObjectHasKey(entry, "total-bytes")) {
2006             if (virJSONValueObjectGetNumberUlong(entry, "total-bytes",
2007                                                  &bytes_val) < 0) {
2008                 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2009                                _("Error getting 'total-bytes' in reply of guest-get-fsinfo"));
2010                 goto cleanup;
2011             }
2012             info_ret[i]->total_bytes = bytes_val;
2013         } else {
2014             info_ret[i]->total_bytes = -1;
2015         }
2016 
2017         if (!(disk = virJSONValueObjectGet(entry, "disk"))) {
2018             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2019                            _("'disk' missing in reply of guest-get-fsinfo"));
2020             goto cleanup;
2021         }
2022 
2023         if (qemuAgentGetFSInfoFillDisks(disk, info_ret[i]) < 0)
2024             goto cleanup;
2025     }
2026 
2027     *info = g_steal_pointer(&info_ret);
2028     ret = ndata;
2029 
2030  cleanup:
2031     if (info_ret) {
2032         for (i = 0; i < ndata; i++)
2033             qemuAgentFSInfoFree(info_ret[i]);
2034         g_free(info_ret);
2035     }
2036     return ret;
2037 }
2038 
2039 
2040 static int
qemuAgentGetInterfaceOneAddress(virDomainIPAddressPtr ip_addr,virJSONValue * ip_addr_obj,const char * name)2041 qemuAgentGetInterfaceOneAddress(virDomainIPAddressPtr ip_addr,
2042                                 virJSONValue *ip_addr_obj,
2043                                 const char *name)
2044 {
2045     const char *type, *addr;
2046 
2047     type = virJSONValueObjectGetString(ip_addr_obj, "ip-address-type");
2048     if (!type) {
2049         virReportError(VIR_ERR_INTERNAL_ERROR,
2050                        _("qemu agent didn't provide 'ip-address-type'"
2051                          " field for interface '%s'"), name);
2052         return -1;
2053     }
2054 
2055     if (STRNEQ(type, "ipv4") && STRNEQ(type, "ipv6")) {
2056         virReportError(VIR_ERR_INTERNAL_ERROR,
2057                        _("unknown ip address type '%s'"),
2058                        type);
2059         return -1;
2060     }
2061 
2062     addr = virJSONValueObjectGetString(ip_addr_obj, "ip-address");
2063     if (!addr) {
2064         virReportError(VIR_ERR_INTERNAL_ERROR,
2065                        _("qemu agent didn't provide 'ip-address'"
2066                          " field for interface '%s'"), name);
2067         return -1;
2068     }
2069 
2070     if (virJSONValueObjectGetNumberUint(ip_addr_obj, "prefix",
2071                                         &ip_addr->prefix) < 0) {
2072         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2073                        _("malformed 'prefix' field"));
2074         return -1;
2075     }
2076 
2077     if (STREQ(type, "ipv4"))
2078         ip_addr->type = VIR_IP_ADDR_TYPE_IPV4;
2079     else
2080         ip_addr->type = VIR_IP_ADDR_TYPE_IPV6;
2081 
2082     ip_addr->addr = g_strdup(addr);
2083     return 0;
2084 }
2085 
2086 
2087 /**
2088  * qemuAgentGetInterfaceAddresses:
2089  * @ifaces_ret: the array to put/update the interface in
2090  * @ifaces_count: the number of interfaces in that array
2091  * @ifaces_store: hash table into @ifaces_ret by interface name
2092  * @iface_obj: one item from the JSON array of interfaces
2093  *
2094  * This function processes @iface_obj (which represents
2095  * information about a single interface) and adds the information
2096  * into the ifaces_ret array.
2097  *
2098  * If we're processing an interface alias, the suffix is stripped
2099  * and information is appended to the entry found via the @ifaces_store
2100  * hash table.
2101  *
2102  * Otherwise, the next free position in @ifaces_ret is used,
2103  * its address added to @ifaces_store, and @ifaces_count incremented.
2104  */
2105 static int
qemuAgentGetInterfaceAddresses(virDomainInterfacePtr ** ifaces_ret,size_t * ifaces_count,GHashTable * ifaces_store,virJSONValue * iface_obj)2106 qemuAgentGetInterfaceAddresses(virDomainInterfacePtr **ifaces_ret,
2107                                size_t *ifaces_count,
2108                                GHashTable *ifaces_store,
2109                                virJSONValue *iface_obj)
2110 {
2111     virJSONValue *ip_addr_arr = NULL;
2112     const char *hwaddr, *name = NULL;
2113     virDomainInterfacePtr iface = NULL;
2114     g_autofree char *ifname = NULL;
2115     size_t addrs_count = 0;
2116     size_t j;
2117 
2118     /* interface name is required to be presented */
2119     name = virJSONValueObjectGetString(iface_obj, "name");
2120     if (!name) {
2121         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2122                        _("qemu agent didn't provide 'name' field"));
2123         return -1;
2124     }
2125 
2126     /* Handle interface alias (<ifname>:<alias>) */
2127     ifname = g_strdelimit(g_strdup(name), ":", '\0');
2128 
2129     iface = virHashLookup(ifaces_store, ifname);
2130 
2131     /* If the hash table doesn't contain this iface, add it */
2132     if (!iface) {
2133         VIR_EXPAND_N(*ifaces_ret, *ifaces_count, 1);
2134 
2135         iface = g_new0(virDomainInterface, 1);
2136         (*ifaces_ret)[*ifaces_count - 1] = iface;
2137 
2138         if (virHashAddEntry(ifaces_store, ifname, iface) < 0)
2139             return -1;
2140 
2141         iface->naddrs = 0;
2142         iface->name = g_strdup(ifname);
2143 
2144         hwaddr = virJSONValueObjectGetString(iface_obj, "hardware-address");
2145         iface->hwaddr = g_strdup(hwaddr);
2146     }
2147 
2148     /* as well as IP address which - moreover -
2149      * can be presented multiple times */
2150     ip_addr_arr = virJSONValueObjectGet(iface_obj, "ip-addresses");
2151     if (!ip_addr_arr)
2152         return 0;
2153 
2154     if (!virJSONValueIsArray(ip_addr_arr)) {
2155         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2156                        _("Malformed ip-addresses array"));
2157         return -1;
2158     }
2159 
2160     /* If current iface already exists, continue with the count */
2161     addrs_count = iface->naddrs;
2162 
2163     VIR_EXPAND_N(iface->addrs, addrs_count, virJSONValueArraySize(ip_addr_arr));
2164 
2165     for (j = 0; j < virJSONValueArraySize(ip_addr_arr); j++) {
2166         virJSONValue *ip_addr_obj = virJSONValueArrayGet(ip_addr_arr, j);
2167         virDomainIPAddressPtr ip_addr = iface->addrs + iface->naddrs;
2168         iface->naddrs++;
2169 
2170         if (qemuAgentGetInterfaceOneAddress(ip_addr, ip_addr_obj, name) < 0)
2171             return -1;
2172     }
2173 
2174     return 0;
2175 }
2176 
2177 
2178 static int
qemuAgentGetAllInterfaceAddresses(virDomainInterfacePtr ** ifaces_ret,virJSONValue * ret_array)2179 qemuAgentGetAllInterfaceAddresses(virDomainInterfacePtr **ifaces_ret,
2180                                   virJSONValue *ret_array)
2181 {
2182     g_autoptr(GHashTable) ifaces_store = NULL;
2183     size_t ifaces_count = 0;
2184     size_t i;
2185 
2186     *ifaces_ret = NULL;
2187     /* Hash table to handle the interface alias */
2188     ifaces_store = virHashNew(NULL);
2189 
2190     for (i = 0; i < virJSONValueArraySize(ret_array); i++) {
2191         virJSONValue *iface_obj = virJSONValueArrayGet(ret_array, i);
2192 
2193         if (qemuAgentGetInterfaceAddresses(ifaces_ret, &ifaces_count,
2194                                            ifaces_store, iface_obj) < 0)
2195             goto error;
2196     }
2197 
2198     return ifaces_count;
2199 
2200  error:
2201     if (*ifaces_ret) {
2202         for (i = 0; i < ifaces_count; i++)
2203             virDomainInterfaceFree((*ifaces_ret)[i]);
2204     }
2205     VIR_FREE(*ifaces_ret);
2206     return -1;
2207 }
2208 
2209 
2210 /*
2211  * qemuAgentGetInterfaces:
2212  * @agent: agent object
2213  * @ifaces: pointer to an array of pointers pointing to interface objects
2214  *
2215  * Issue guest-network-get-interfaces to guest agent, which returns a
2216  * list of interfaces of a running domain along with their IP and MAC
2217  * addresses.
2218  *
2219  * Returns: number of interfaces on success, -1 on error.
2220  */
2221 int
qemuAgentGetInterfaces(qemuAgent * agent,virDomainInterfacePtr ** ifaces,bool report_unsupported)2222 qemuAgentGetInterfaces(qemuAgent *agent,
2223                        virDomainInterfacePtr **ifaces,
2224                        bool report_unsupported)
2225 {
2226     g_autoptr(virJSONValue) cmd = NULL;
2227     g_autoptr(virJSONValue) reply = NULL;
2228     virJSONValue *ret_array = NULL;
2229     int rc;
2230 
2231     if (!(cmd = qemuAgentMakeCommand("guest-network-get-interfaces", NULL)))
2232         return -1;
2233 
2234     if ((rc = qemuAgentCommandFull(agent, cmd, &reply, agent->timeout,
2235                                    report_unsupported)) < 0)
2236         return rc;
2237 
2238     if (!(ret_array = virJSONValueObjectGetArray(reply, "return"))) {
2239         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2240                        _("qemu agent didn't return an array of interfaces"));
2241         return -1;
2242     }
2243 
2244     return qemuAgentGetAllInterfaceAddresses(ifaces, ret_array);
2245 }
2246 
2247 
2248 int
qemuAgentSetUserPassword(qemuAgent * agent,const char * user,const char * password,bool crypted)2249 qemuAgentSetUserPassword(qemuAgent *agent,
2250                          const char *user,
2251                          const char *password,
2252                          bool crypted)
2253 {
2254     g_autoptr(virJSONValue) cmd = NULL;
2255     g_autoptr(virJSONValue) reply = NULL;
2256     g_autofree char *password64 = NULL;
2257 
2258     password64 = g_base64_encode((unsigned char *)password,
2259                                  strlen(password));
2260 
2261     if (!(cmd = qemuAgentMakeCommand("guest-set-user-password",
2262                                      "b:crypted", crypted,
2263                                      "s:username", user,
2264                                      "s:password", password64,
2265                                      NULL)))
2266         return -1;
2267 
2268     if (qemuAgentCommand(agent, cmd, &reply, agent->timeout) < 0)
2269         return -1;
2270 
2271     return 0;
2272 }
2273 
2274 /* Returns: 0 on success
2275  *          -2 when agent command is not supported by the agent and
2276  *             'report_unsupported' is false (libvirt error is not reported)
2277  *          -1 otherwise (libvirt error is reported)
2278  */
2279 int
qemuAgentGetUsers(qemuAgent * agent,virTypedParameterPtr * params,int * nparams,int * maxparams,bool report_unsupported)2280 qemuAgentGetUsers(qemuAgent *agent,
2281                   virTypedParameterPtr *params,
2282                   int *nparams,
2283                   int *maxparams,
2284                   bool report_unsupported)
2285 {
2286     g_autoptr(virJSONValue) cmd = NULL;
2287     g_autoptr(virJSONValue) reply = NULL;
2288     virJSONValue *data = NULL;
2289     size_t ndata;
2290     size_t i;
2291     int rc;
2292 
2293     if (!(cmd = qemuAgentMakeCommand("guest-get-users", NULL)))
2294         return -1;
2295 
2296     if ((rc = qemuAgentCommandFull(agent, cmd, &reply, agent->timeout,
2297                                    report_unsupported)) < 0)
2298         return rc;
2299 
2300     if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
2301         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2302                        _("guest-get-users reply was missing return data"));
2303         return -1;
2304     }
2305 
2306     ndata = virJSONValueArraySize(data);
2307 
2308     if (virTypedParamsAddUInt(params, nparams, maxparams,
2309                               "user.count", ndata) < 0)
2310         return -1;
2311 
2312     for (i = 0; i < ndata; i++) {
2313         virJSONValue *entry = virJSONValueArrayGet(data, i);
2314         char param_name[VIR_TYPED_PARAM_FIELD_LENGTH];
2315         const char *strvalue;
2316         double logintime;
2317 
2318         if (!entry) {
2319             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2320                            _("array element missing in guest-get-users return "
2321                              "value"));
2322             return -1;
2323         }
2324 
2325         if (!(strvalue = virJSONValueObjectGetString(entry, "user"))) {
2326             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2327                            _("'user' missing in reply of guest-get-users"));
2328             return -1;
2329         }
2330 
2331         g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, "user.%zu.name", i);
2332         if (virTypedParamsAddString(params, nparams, maxparams,
2333                                     param_name, strvalue) < 0)
2334             return -1;
2335 
2336         /* 'domain' is only present for windows guests */
2337         if ((strvalue = virJSONValueObjectGetString(entry, "domain"))) {
2338             g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
2339                        "user.%zu.domain", i);
2340             if (virTypedParamsAddString(params, nparams, maxparams,
2341                                         param_name, strvalue) < 0)
2342                 return -1;
2343         }
2344 
2345         if (virJSONValueObjectGetNumberDouble(entry, "login-time", &logintime) < 0) {
2346             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2347                            _("'login-time' missing in reply of guest-get-users"));
2348             return -1;
2349         }
2350         g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
2351                    "user.%zu.login-time", i);
2352         if (virTypedParamsAddULLong(params, nparams, maxparams,
2353                                     param_name, logintime * 1000) < 0)
2354             return -1;
2355     }
2356 
2357     return 0;
2358 }
2359 
2360 /* Returns: 0 on success
2361  *          -2 when agent command is not supported by the agent and
2362  *             'report_unsupported' is false (libvirt error is not reported)
2363  *          -1 otherwise (libvirt error is reported)
2364  */
2365 int
qemuAgentGetOSInfo(qemuAgent * agent,virTypedParameterPtr * params,int * nparams,int * maxparams,bool report_unsupported)2366 qemuAgentGetOSInfo(qemuAgent *agent,
2367                    virTypedParameterPtr *params,
2368                    int *nparams,
2369                    int *maxparams,
2370                    bool report_unsupported)
2371 {
2372     g_autoptr(virJSONValue) cmd = NULL;
2373     g_autoptr(virJSONValue) reply = NULL;
2374     virJSONValue *data = NULL;
2375     int rc;
2376 
2377     if (!(cmd = qemuAgentMakeCommand("guest-get-osinfo", NULL)))
2378         return -1;
2379 
2380     if ((rc = qemuAgentCommandFull(agent, cmd, &reply, agent->timeout,
2381                                    report_unsupported)) < 0)
2382         return rc;
2383 
2384     if (!(data = virJSONValueObjectGetObject(reply, "return"))) {
2385         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2386                        _("guest-get-osinfo reply was missing return data"));
2387         return -1;
2388     }
2389 
2390 #define OSINFO_ADD_PARAM(agent_string_, param_string_) \
2391     do { \
2392         const char *result; \
2393         if ((result = virJSONValueObjectGetString(data, agent_string_))) { \
2394             if (virTypedParamsAddString(params, nparams, maxparams, \
2395                                         param_string_, result) < 0) { \
2396                 return -1; \
2397             } \
2398         } \
2399     } while (0)
2400     OSINFO_ADD_PARAM("id", "os.id");
2401     OSINFO_ADD_PARAM("name", "os.name");
2402     OSINFO_ADD_PARAM("pretty-name", "os.pretty-name");
2403     OSINFO_ADD_PARAM("version", "os.version");
2404     OSINFO_ADD_PARAM("version-id", "os.version-id");
2405     OSINFO_ADD_PARAM("machine", "os.machine");
2406     OSINFO_ADD_PARAM("variant", "os.variant");
2407     OSINFO_ADD_PARAM("variant-id", "os.variant-id");
2408     OSINFO_ADD_PARAM("kernel-release", "os.kernel-release");
2409     OSINFO_ADD_PARAM("kernel-version", "os.kernel-version");
2410 
2411     return 0;
2412 }
2413 
2414 /* Returns: 0 on success
2415  *          -2 when agent command is not supported by the agent and
2416  *             'report_unsupported' is false (libvirt error is not reported)
2417  *          -1 otherwise (libvirt error is reported)
2418  */
2419 int
qemuAgentGetTimezone(qemuAgent * agent,virTypedParameterPtr * params,int * nparams,int * maxparams,bool report_unsupported)2420 qemuAgentGetTimezone(qemuAgent *agent,
2421                      virTypedParameterPtr *params,
2422                      int *nparams,
2423                      int *maxparams,
2424                      bool report_unsupported)
2425 {
2426     g_autoptr(virJSONValue) cmd = NULL;
2427     g_autoptr(virJSONValue) reply = NULL;
2428     virJSONValue *data = NULL;
2429     const char *name;
2430     int offset;
2431     int rc;
2432 
2433     if (!(cmd = qemuAgentMakeCommand("guest-get-timezone", NULL)))
2434         return -1;
2435 
2436     if ((rc = qemuAgentCommandFull(agent, cmd, &reply, agent->timeout,
2437                                    report_unsupported)) < 0)
2438         return rc;
2439 
2440     if (!(data = virJSONValueObjectGetObject(reply, "return"))) {
2441         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2442                        _("guest-get-timezone reply was missing return data"));
2443         return -1;
2444     }
2445 
2446     if ((name = virJSONValueObjectGetString(data, "zone")) &&
2447         virTypedParamsAddString(params, nparams, maxparams,
2448                                 "timezone.name", name) < 0)
2449         return -1;
2450 
2451     if ((virJSONValueObjectGetNumberInt(data, "offset", &offset)) < 0) {
2452         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2453                        _("'offset' missing in reply of guest-get-timezone"));
2454         return -1;
2455     }
2456 
2457     if (virTypedParamsAddInt(params, nparams, maxparams,
2458                              "timezone.offset", offset) < 0)
2459         return -1;
2460 
2461     return 0;
2462 }
2463 
2464 /* qemuAgentSetResponseTimeout:
2465  * @agent: agent object
2466  * @timeout: number of seconds to wait for agent response
2467  *
2468  * The agent object must be locked prior to calling this function.
2469  */
2470 void
qemuAgentSetResponseTimeout(qemuAgent * agent,int timeout)2471 qemuAgentSetResponseTimeout(qemuAgent *agent,
2472                             int timeout)
2473 {
2474     agent->timeout = timeout;
2475 }
2476 
2477 /**
2478  * qemuAgentSSHGetAuthorizedKeys:
2479  * @agent: agent object
2480  * @user: user to get authorized keys for
2481  * @keys: Array of authorized keys
2482  *
2483  * Fetch the public keys from @user's $HOME/.ssh/authorized_keys.
2484  *
2485  * Returns: number of keys returned on success,
2486  *          -1 otherwise (error is reported)
2487  */
2488 int
qemuAgentSSHGetAuthorizedKeys(qemuAgent * agent,const char * user,char *** keys)2489 qemuAgentSSHGetAuthorizedKeys(qemuAgent *agent,
2490                               const char *user,
2491                               char ***keys)
2492 {
2493     g_autoptr(virJSONValue) cmd = NULL;
2494     g_autoptr(virJSONValue) reply = NULL;
2495     virJSONValue *data = NULL;
2496 
2497     if (!(cmd = qemuAgentMakeCommand("guest-ssh-get-authorized-keys",
2498                                      "s:username", user,
2499                                      NULL)))
2500         return -1;
2501 
2502     if (qemuAgentCommand(agent, cmd, &reply, agent->timeout) < 0)
2503         return -1;
2504 
2505     if (!(data = virJSONValueObjectGetObject(reply, "return"))) {
2506         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2507                        _("qemu agent didn't return an array of keys"));
2508         return -1;
2509     }
2510 
2511     if (!(*keys = virJSONValueObjectGetStringArray(data, "keys")))
2512         return -1;
2513 
2514     return g_strv_length(*keys);
2515 }
2516 
2517 
2518 /**
2519  * qemuAgentSSHAddAuthorizedKeys:
2520  * @agent: agent object
2521  * @user: user to add authorized keys for
2522  * @keys: Array of authorized keys
2523  * @nkeys: number of items in @keys array
2524  * @reset: whether to truncate authorized keys file before writing
2525  *
2526  * Append SSH @keys into the @user's authorized keys file. If
2527  * @reset is true then the file is truncated before write and
2528  * thus contains only newly added @keys.
2529  *
2530  * Returns: 0 on success,
2531  *          -1 otherwise (error is reported)
2532  */
2533 int
qemuAgentSSHAddAuthorizedKeys(qemuAgent * agent,const char * user,const char ** keys,size_t nkeys,bool reset)2534 qemuAgentSSHAddAuthorizedKeys(qemuAgent *agent,
2535                               const char *user,
2536                               const char **keys,
2537                               size_t nkeys,
2538                               bool reset)
2539 {
2540     g_autoptr(virJSONValue) cmd = NULL;
2541     g_autoptr(virJSONValue) reply = NULL;
2542     g_autoptr(virJSONValue) jkeys = NULL;
2543 
2544     jkeys = qemuAgentMakeStringsArray(keys, nkeys);
2545     if (jkeys == NULL)
2546         return -1;
2547 
2548     if (!(cmd = qemuAgentMakeCommand("guest-ssh-add-authorized-keys",
2549                                      "s:username", user,
2550                                      "a:keys", &jkeys,
2551                                      "b:reset", reset,
2552                                      NULL)))
2553         return -1;
2554 
2555     return qemuAgentCommand(agent, cmd, &reply, agent->timeout);
2556 }
2557 
2558 
2559 /**
2560  * qemuAgentSSHRemoveAuthorizedKeys:
2561  * @agent: agent object
2562  * @user: user to remove authorized keys for
2563  * @keys: Array of authorized keys
2564  * @nkeys: number of items in @keys array
2565  *
2566  * Remove SSH @keys from the @user's authorized keys file. It's
2567  * not considered an error when trying to remove a non-existent
2568  * key.
2569  *
2570  * Returns: 0 on success,
2571  *          -1 otherwise (error is reported)
2572  */
2573 int
qemuAgentSSHRemoveAuthorizedKeys(qemuAgent * agent,const char * user,const char ** keys,size_t nkeys)2574 qemuAgentSSHRemoveAuthorizedKeys(qemuAgent *agent,
2575                                  const char *user,
2576                                  const char **keys,
2577                                  size_t nkeys)
2578 {
2579     g_autoptr(virJSONValue) cmd = NULL;
2580     g_autoptr(virJSONValue) reply = NULL;
2581     g_autoptr(virJSONValue) jkeys = NULL;
2582 
2583     jkeys = qemuAgentMakeStringsArray(keys, nkeys);
2584     if (jkeys == NULL)
2585         return -1;
2586 
2587     if (!(cmd = qemuAgentMakeCommand("guest-ssh-remove-authorized-keys",
2588                                      "s:username", user,
2589                                      "a:keys", &jkeys,
2590                                      NULL)))
2591         return -1;
2592 
2593     return qemuAgentCommand(agent, cmd, &reply, agent->timeout);
2594 }
2595 
2596 
qemuAgentGetDisks(qemuAgent * agent,qemuAgentDiskInfo *** disks,bool report_unsupported)2597 int qemuAgentGetDisks(qemuAgent *agent,
2598                       qemuAgentDiskInfo ***disks,
2599                       bool report_unsupported)
2600 {
2601     g_autoptr(virJSONValue) cmd = NULL;
2602     g_autoptr(virJSONValue) reply = NULL;
2603     virJSONValue *data = NULL;
2604     size_t ndata;
2605     size_t i;
2606     int rc;
2607 
2608     if (!(cmd = qemuAgentMakeCommand("guest-get-disks", NULL)))
2609         return -1;
2610 
2611     if ((rc = qemuAgentCommandFull(agent, cmd, &reply, agent->timeout,
2612                                    report_unsupported)) < 0)
2613         return rc;
2614 
2615     if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
2616         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2617                        _("qemu agent didn't return an array of disks"));
2618         return -1;
2619     }
2620 
2621     ndata = virJSONValueArraySize(data);
2622 
2623     *disks = g_new0(qemuAgentDiskInfo *, ndata);
2624 
2625     for (i = 0; i < ndata; i++) {
2626         virJSONValue *addr;
2627         virJSONValue *entry = virJSONValueArrayGet(data, i);
2628         qemuAgentDiskInfo *disk;
2629 
2630         if (!entry) {
2631             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2632                            _("array element missing in guest-get-disks return "
2633                              "value"));
2634             goto error;
2635         }
2636 
2637         disk = g_new0(qemuAgentDiskInfo, 1);
2638         (*disks)[i] = disk;
2639 
2640         disk->name = g_strdup(virJSONValueObjectGetString(entry, "name"));
2641         if (!disk->name) {
2642             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2643                            _("'name' missing in reply of guest-get-disks"));
2644             goto error;
2645         }
2646 
2647         if (virJSONValueObjectGetBoolean(entry, "partition", &disk->partition) < 0) {
2648             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2649                            _("'partition' missing in reply of guest-get-disks"));
2650             goto error;
2651         }
2652 
2653         disk->dependencies = virJSONValueObjectGetStringArray(entry, "dependencies");
2654         disk->alias = g_strdup(virJSONValueObjectGetString(entry, "alias"));
2655         addr = virJSONValueObjectGetObject(entry, "address");
2656         if (addr) {
2657             disk->address = qemuAgentGetDiskAddress(addr);
2658             if (!disk->address)
2659                 goto error;
2660         }
2661     }
2662 
2663     return ndata;
2664 
2665  error:
2666     for (i = 0; i < ndata; i++) {
2667         qemuAgentDiskInfoFree((*disks)[i]);
2668     }
2669     g_free(*disks);
2670     return -1;
2671 }
2672