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