]> git.proxmox.com Git - mirror_qemu.git/blame - qga/commands-posix.c
Merge remote-tracking branch 'qmp/queue/qmp' into staging
[mirror_qemu.git] / qga / commands-posix.c
CommitLineData
e3d4d252 1/*
42074a9d 2 * QEMU Guest Agent POSIX-specific command implementations
e3d4d252
MR
3 *
4 * Copyright IBM Corp. 2011
5 *
6 * Authors:
7 * Michael Roth <mdroth@linux.vnet.ibm.com>
3424fc9f 8 * Michal Privoznik <mprivozn@redhat.com>
e3d4d252
MR
9 *
10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
11 * See the COPYING file in the top-level directory.
12 */
13
14#include <glib.h>
e72c3f2e
MR
15#include <sys/types.h>
16#include <sys/ioctl.h>
17#include "qga/guest-agent-core.h"
18#include "qga-qmp-commands.h"
19#include "qerror.h"
20#include "qemu-queue.h"
21#include "host-utils.h"
4eb36d40
AL
22
23#if defined(__linux__)
e3d4d252 24#include <mntent.h>
7006b9cf 25#include <linux/fs.h>
3424fc9f
MP
26#include <ifaddrs.h>
27#include <arpa/inet.h>
28#include <sys/socket.h>
29#include <net/if.h>
11d0f125 30#include <sys/wait.h>
e3d4d252 31
e72c3f2e
MR
32#if defined(__linux__) && defined(FIFREEZE)
33#define CONFIG_FSFREEZE
34#endif
35#endif
36
37#if defined(__linux__)
38/* TODO: use this in place of all post-fork() fclose(std*) callers */
11d0f125
LC
39static void reopen_fd_to_null(int fd)
40{
41 int nullfd;
42
43 nullfd = open("/dev/null", O_RDWR);
44 if (nullfd < 0) {
45 return;
46 }
47
48 dup2(nullfd, fd);
49
50 if (nullfd != fd) {
51 close(nullfd);
52 }
53}
e72c3f2e 54#endif /* defined(__linux__) */
11d0f125 55
e3d4d252
MR
56void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
57{
58 int ret;
59 const char *shutdown_flag;
60
61 slog("guest-shutdown called, mode: %s", mode);
62 if (!has_mode || strcmp(mode, "powerdown") == 0) {
63 shutdown_flag = "-P";
64 } else if (strcmp(mode, "halt") == 0) {
65 shutdown_flag = "-H";
66 } else if (strcmp(mode, "reboot") == 0) {
67 shutdown_flag = "-r";
68 } else {
69 error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode",
70 "halt|powerdown|reboot");
71 return;
72 }
73
74 ret = fork();
75 if (ret == 0) {
76 /* child, start the shutdown */
77 setsid();
78 fclose(stdin);
79 fclose(stdout);
80 fclose(stderr);
81
82 ret = execl("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
83 "hypervisor initiated shutdown", (char*)NULL);
84 if (ret) {
85 slog("guest-shutdown failed: %s", strerror(errno));
86 }
87 exit(!!ret);
88 } else if (ret < 0) {
89 error_set(err, QERR_UNDEFINED_ERROR);
90 }
91}
92
93typedef struct GuestFileHandle {
94 uint64_t id;
95 FILE *fh;
96 QTAILQ_ENTRY(GuestFileHandle) next;
97} GuestFileHandle;
98
99static struct {
100 QTAILQ_HEAD(, GuestFileHandle) filehandles;
101} guest_file_state;
102
103static void guest_file_handle_add(FILE *fh)
104{
105 GuestFileHandle *gfh;
106
7267c094 107 gfh = g_malloc0(sizeof(GuestFileHandle));
e3d4d252
MR
108 gfh->id = fileno(fh);
109 gfh->fh = fh;
110 QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
111}
112
113static GuestFileHandle *guest_file_handle_find(int64_t id)
114{
115 GuestFileHandle *gfh;
116
117 QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
118 {
119 if (gfh->id == id) {
120 return gfh;
121 }
122 }
123
124 return NULL;
125}
126
127int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
128{
129 FILE *fh;
130 int fd;
131 int64_t ret = -1;
132
133 if (!has_mode) {
134 mode = "r";
135 }
136 slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
137 fh = fopen(path, mode);
138 if (!fh) {
139 error_set(err, QERR_OPEN_FILE_FAILED, path);
140 return -1;
141 }
142
143 /* set fd non-blocking to avoid common use cases (like reading from a
144 * named pipe) from hanging the agent
145 */
146 fd = fileno(fh);
147 ret = fcntl(fd, F_GETFL);
148 ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
149 if (ret == -1) {
150 error_set(err, QERR_QGA_COMMAND_FAILED, "fcntl() failed");
151 fclose(fh);
152 return -1;
153 }
154
155 guest_file_handle_add(fh);
156 slog("guest-file-open, handle: %d", fd);
157 return fd;
158}
159
160void qmp_guest_file_close(int64_t handle, Error **err)
161{
162 GuestFileHandle *gfh = guest_file_handle_find(handle);
163 int ret;
164
165 slog("guest-file-close called, handle: %ld", handle);
166 if (!gfh) {
167 error_set(err, QERR_FD_NOT_FOUND, "handle");
168 return;
169 }
170
171 ret = fclose(gfh->fh);
172 if (ret == -1) {
173 error_set(err, QERR_QGA_COMMAND_FAILED, "fclose() failed");
174 return;
175 }
176
177 QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
7267c094 178 g_free(gfh);
e3d4d252
MR
179}
180
181struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
182 int64_t count, Error **err)
183{
184 GuestFileHandle *gfh = guest_file_handle_find(handle);
185 GuestFileRead *read_data = NULL;
186 guchar *buf;
187 FILE *fh;
188 size_t read_count;
189
190 if (!gfh) {
191 error_set(err, QERR_FD_NOT_FOUND, "handle");
192 return NULL;
193 }
194
195 if (!has_count) {
196 count = QGA_READ_COUNT_DEFAULT;
197 } else if (count < 0) {
198 error_set(err, QERR_INVALID_PARAMETER, "count");
199 return NULL;
200 }
201
202 fh = gfh->fh;
7267c094 203 buf = g_malloc0(count+1);
e3d4d252
MR
204 read_count = fread(buf, 1, count, fh);
205 if (ferror(fh)) {
206 slog("guest-file-read failed, handle: %ld", handle);
207 error_set(err, QERR_QGA_COMMAND_FAILED, "fread() failed");
208 } else {
209 buf[read_count] = 0;
7267c094 210 read_data = g_malloc0(sizeof(GuestFileRead));
e3d4d252
MR
211 read_data->count = read_count;
212 read_data->eof = feof(fh);
213 if (read_count) {
214 read_data->buf_b64 = g_base64_encode(buf, read_count);
215 }
216 }
7267c094 217 g_free(buf);
e3d4d252
MR
218 clearerr(fh);
219
220 return read_data;
221}
222
223GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
224 bool has_count, int64_t count, Error **err)
225{
226 GuestFileWrite *write_data = NULL;
227 guchar *buf;
228 gsize buf_len;
229 int write_count;
230 GuestFileHandle *gfh = guest_file_handle_find(handle);
231 FILE *fh;
232
233 if (!gfh) {
234 error_set(err, QERR_FD_NOT_FOUND, "handle");
235 return NULL;
236 }
237
238 fh = gfh->fh;
239 buf = g_base64_decode(buf_b64, &buf_len);
240
241 if (!has_count) {
242 count = buf_len;
243 } else if (count < 0 || count > buf_len) {
7267c094 244 g_free(buf);
e3d4d252
MR
245 error_set(err, QERR_INVALID_PARAMETER, "count");
246 return NULL;
247 }
248
249 write_count = fwrite(buf, 1, count, fh);
250 if (ferror(fh)) {
251 slog("guest-file-write failed, handle: %ld", handle);
252 error_set(err, QERR_QGA_COMMAND_FAILED, "fwrite() error");
253 } else {
7267c094 254 write_data = g_malloc0(sizeof(GuestFileWrite));
e3d4d252
MR
255 write_data->count = write_count;
256 write_data->eof = feof(fh);
257 }
7267c094 258 g_free(buf);
e3d4d252
MR
259 clearerr(fh);
260
261 return write_data;
262}
263
264struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
265 int64_t whence, Error **err)
266{
267 GuestFileHandle *gfh = guest_file_handle_find(handle);
268 GuestFileSeek *seek_data = NULL;
269 FILE *fh;
270 int ret;
271
272 if (!gfh) {
273 error_set(err, QERR_FD_NOT_FOUND, "handle");
274 return NULL;
275 }
276
277 fh = gfh->fh;
278 ret = fseek(fh, offset, whence);
279 if (ret == -1) {
280 error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
281 } else {
7267c094 282 seek_data = g_malloc0(sizeof(GuestFileRead));
e3d4d252
MR
283 seek_data->position = ftell(fh);
284 seek_data->eof = feof(fh);
285 }
286 clearerr(fh);
287
288 return seek_data;
289}
290
291void qmp_guest_file_flush(int64_t handle, Error **err)
292{
293 GuestFileHandle *gfh = guest_file_handle_find(handle);
294 FILE *fh;
295 int ret;
296
297 if (!gfh) {
298 error_set(err, QERR_FD_NOT_FOUND, "handle");
299 return;
300 }
301
302 fh = gfh->fh;
303 ret = fflush(fh);
304 if (ret == EOF) {
305 error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
306 }
307}
308
309static void guest_file_init(void)
310{
311 QTAILQ_INIT(&guest_file_state.filehandles);
312}
313
e72c3f2e
MR
314/* linux-specific implementations. avoid this if at all possible. */
315#if defined(__linux__)
316
7006b9cf 317#if defined(CONFIG_FSFREEZE)
e72c3f2e 318
7006b9cf
AL
319static void disable_logging(void)
320{
321 ga_disable_logging(ga_state);
322}
323
324static void enable_logging(void)
325{
326 ga_enable_logging(ga_state);
327}
328
e3d4d252
MR
329typedef struct GuestFsfreezeMount {
330 char *dirname;
331 char *devtype;
332 QTAILQ_ENTRY(GuestFsfreezeMount) next;
333} GuestFsfreezeMount;
334
335struct {
336 GuestFsfreezeStatus status;
337 QTAILQ_HEAD(, GuestFsfreezeMount) mount_list;
338} guest_fsfreeze_state;
339
340/*
341 * Walk the mount table and build a list of local file systems
342 */
343static int guest_fsfreeze_build_mount_list(void)
344{
345 struct mntent *ment;
346 GuestFsfreezeMount *mount, *temp;
347 char const *mtab = MOUNTED;
348 FILE *fp;
349
350 QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) {
351 QTAILQ_REMOVE(&guest_fsfreeze_state.mount_list, mount, next);
7267c094
AL
352 g_free(mount->dirname);
353 g_free(mount->devtype);
354 g_free(mount);
e3d4d252
MR
355 }
356
357 fp = setmntent(mtab, "r");
358 if (!fp) {
359 g_warning("fsfreeze: unable to read mtab");
360 return -1;
361 }
362
363 while ((ment = getmntent(fp))) {
364 /*
365 * An entry which device name doesn't start with a '/' is
366 * either a dummy file system or a network file system.
367 * Add special handling for smbfs and cifs as is done by
368 * coreutils as well.
369 */
370 if ((ment->mnt_fsname[0] != '/') ||
371 (strcmp(ment->mnt_type, "smbfs") == 0) ||
372 (strcmp(ment->mnt_type, "cifs") == 0)) {
373 continue;
374 }
375
7267c094
AL
376 mount = g_malloc0(sizeof(GuestFsfreezeMount));
377 mount->dirname = g_strdup(ment->mnt_dir);
378 mount->devtype = g_strdup(ment->mnt_type);
e3d4d252
MR
379
380 QTAILQ_INSERT_TAIL(&guest_fsfreeze_state.mount_list, mount, next);
381 }
382
383 endmntent(fp);
384
385 return 0;
386}
387
388/*
389 * Return status of freeze/thaw
390 */
391GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
392{
393 return guest_fsfreeze_state.status;
394}
395
396/*
397 * Walk list of mounted file systems in the guest, and freeze the ones which
398 * are real local file systems.
399 */
400int64_t qmp_guest_fsfreeze_freeze(Error **err)
401{
402 int ret = 0, i = 0;
403 struct GuestFsfreezeMount *mount, *temp;
404 int fd;
405 char err_msg[512];
406
407 slog("guest-fsfreeze called");
408
409 if (guest_fsfreeze_state.status == GUEST_FSFREEZE_STATUS_FROZEN) {
410 return 0;
411 }
412
413 ret = guest_fsfreeze_build_mount_list();
414 if (ret < 0) {
415 return ret;
416 }
417
418 /* cannot risk guest agent blocking itself on a write in this state */
419 disable_logging();
420
421 QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) {
422 fd = qemu_open(mount->dirname, O_RDONLY);
423 if (fd == -1) {
424 sprintf(err_msg, "failed to open %s, %s", mount->dirname, strerror(errno));
425 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
426 goto error;
427 }
428
429 /* we try to cull filesytems we know won't work in advance, but other
430 * filesytems may not implement fsfreeze for less obvious reasons.
431 * these will report EOPNOTSUPP, so we simply ignore them. when
432 * thawing, these filesystems will return an EINVAL instead, due to
433 * not being in a frozen state. Other filesystem-specific
434 * errors may result in EINVAL, however, so the user should check the
435 * number * of filesystems returned here against those returned by the
436 * thaw operation to determine whether everything completed
437 * successfully
438 */
439 ret = ioctl(fd, FIFREEZE);
440 if (ret < 0 && errno != EOPNOTSUPP) {
441 sprintf(err_msg, "failed to freeze %s, %s", mount->dirname, strerror(errno));
442 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
443 close(fd);
444 goto error;
445 }
446 close(fd);
447
448 i++;
449 }
450
451 guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_FROZEN;
452 return i;
453
454error:
455 if (i > 0) {
456 qmp_guest_fsfreeze_thaw(NULL);
457 }
458 return 0;
459}
460
461/*
462 * Walk list of frozen file systems in the guest, and thaw them.
463 */
464int64_t qmp_guest_fsfreeze_thaw(Error **err)
465{
466 int ret;
467 GuestFsfreezeMount *mount, *temp;
468 int fd, i = 0;
469 bool has_error = false;
470
471 QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) {
472 fd = qemu_open(mount->dirname, O_RDONLY);
473 if (fd == -1) {
474 has_error = true;
475 continue;
476 }
477 ret = ioctl(fd, FITHAW);
478 if (ret < 0 && errno != EOPNOTSUPP && errno != EINVAL) {
479 has_error = true;
480 close(fd);
481 continue;
482 }
483 close(fd);
484 i++;
485 }
486
487 if (has_error) {
488 guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_ERROR;
489 } else {
490 guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_THAWED;
491 }
492 enable_logging();
493 return i;
494}
495
496static void guest_fsfreeze_init(void)
497{
498 guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_THAWED;
499 QTAILQ_INIT(&guest_fsfreeze_state.mount_list);
500}
501
502static void guest_fsfreeze_cleanup(void)
503{
504 int64_t ret;
505 Error *err = NULL;
506
507 if (guest_fsfreeze_state.status == GUEST_FSFREEZE_STATUS_FROZEN) {
508 ret = qmp_guest_fsfreeze_thaw(&err);
509 if (ret < 0 || err) {
510 slog("failed to clean up frozen filesystems");
511 }
512 }
513}
e72c3f2e 514#endif /* CONFIG_FSFREEZE */
e3d4d252 515
11d0f125
LC
516#define LINUX_SYS_STATE_FILE "/sys/power/state"
517#define SUSPEND_SUPPORTED 0
518#define SUSPEND_NOT_SUPPORTED 1
519
520/**
521 * This function forks twice and the information about the mode support
522 * status is passed to the qemu-ga process via a pipe.
523 *
524 * This approach allows us to keep the way we reap terminated children
525 * in qemu-ga quite simple.
526 */
527static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
528 const char *sysfile_str, Error **err)
529{
530 pid_t pid;
531 ssize_t ret;
532 char *pmutils_path;
533 int status, pipefds[2];
534
535 if (pipe(pipefds) < 0) {
536 error_set(err, QERR_UNDEFINED_ERROR);
537 return;
538 }
539
540 pmutils_path = g_find_program_in_path(pmutils_bin);
541
542 pid = fork();
543 if (!pid) {
544 struct sigaction act;
545
546 memset(&act, 0, sizeof(act));
547 act.sa_handler = SIG_DFL;
548 sigaction(SIGCHLD, &act, NULL);
549
550 setsid();
551 close(pipefds[0]);
552 reopen_fd_to_null(0);
553 reopen_fd_to_null(1);
554 reopen_fd_to_null(2);
555
556 pid = fork();
557 if (!pid) {
558 int fd;
559 char buf[32]; /* hopefully big enough */
560
561 if (pmutils_path) {
562 execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
563 }
564
565 /*
566 * If we get here either pm-utils is not installed or execle() has
567 * failed. Let's try the manual method if the caller wants it.
568 */
569
570 if (!sysfile_str) {
571 _exit(SUSPEND_NOT_SUPPORTED);
572 }
573
574 fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
575 if (fd < 0) {
576 _exit(SUSPEND_NOT_SUPPORTED);
577 }
578
579 ret = read(fd, buf, sizeof(buf)-1);
580 if (ret <= 0) {
581 _exit(SUSPEND_NOT_SUPPORTED);
582 }
583 buf[ret] = '\0';
584
585 if (strstr(buf, sysfile_str)) {
586 _exit(SUSPEND_SUPPORTED);
587 }
588
589 _exit(SUSPEND_NOT_SUPPORTED);
590 }
591
592 if (pid > 0) {
593 wait(&status);
594 } else {
595 status = SUSPEND_NOT_SUPPORTED;
596 }
597
598 ret = write(pipefds[1], &status, sizeof(status));
599 if (ret != sizeof(status)) {
600 _exit(EXIT_FAILURE);
601 }
602
603 _exit(EXIT_SUCCESS);
604 }
605
606 close(pipefds[1]);
607 g_free(pmutils_path);
608
609 if (pid < 0) {
610 error_set(err, QERR_UNDEFINED_ERROR);
611 goto out;
612 }
613
614 ret = read(pipefds[0], &status, sizeof(status));
615 if (ret == sizeof(status) && WIFEXITED(status) &&
616 WEXITSTATUS(status) == SUSPEND_SUPPORTED) {
617 goto out;
618 }
619
620 error_set(err, QERR_UNSUPPORTED);
621
622out:
623 close(pipefds[0]);
624}
625
626static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
627 Error **err)
628{
629 pid_t pid;
630 char *pmutils_path;
631
632 pmutils_path = g_find_program_in_path(pmutils_bin);
633
634 pid = fork();
635 if (pid == 0) {
636 /* child */
637 int fd;
638
639 setsid();
640 reopen_fd_to_null(0);
641 reopen_fd_to_null(1);
642 reopen_fd_to_null(2);
643
644 if (pmutils_path) {
645 execle(pmutils_path, pmutils_bin, NULL, environ);
646 }
647
648 /*
649 * If we get here either pm-utils is not installed or execle() has
650 * failed. Let's try the manual method if the caller wants it.
651 */
652
653 if (!sysfile_str) {
654 _exit(EXIT_FAILURE);
655 }
656
657 fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
658 if (fd < 0) {
659 _exit(EXIT_FAILURE);
660 }
661
662 if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
663 _exit(EXIT_FAILURE);
664 }
665
666 _exit(EXIT_SUCCESS);
667 }
668
669 g_free(pmutils_path);
670
671 if (pid < 0) {
672 error_set(err, QERR_UNDEFINED_ERROR);
673 return;
674 }
675}
676
677void qmp_guest_suspend_disk(Error **err)
678{
679 bios_supports_mode("pm-is-supported", "--hibernate", "disk", err);
680 if (error_is_set(err)) {
681 return;
682 }
683
684 guest_suspend("pm-hibernate", "disk", err);
685}
686
fbf42210
LC
687void qmp_guest_suspend_ram(Error **err)
688{
689 bios_supports_mode("pm-is-supported", "--suspend", "mem", err);
690 if (error_is_set(err)) {
691 return;
692 }
693
694 guest_suspend("pm-suspend", "mem", err);
695}
696
95f4f404
LC
697void qmp_guest_suspend_hybrid(Error **err)
698{
699 bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err);
700 if (error_is_set(err)) {
701 return;
702 }
703
704 guest_suspend("pm-suspend-hybrid", NULL, err);
705}
706
3424fc9f
MP
707static GuestNetworkInterfaceList *
708guest_find_interface(GuestNetworkInterfaceList *head,
709 const char *name)
710{
711 for (; head; head = head->next) {
712 if (strcmp(head->value->name, name) == 0) {
713 break;
714 }
715 }
716
717 return head;
718}
719
720/*
721 * Build information about guest interfaces
722 */
723GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
724{
725 GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
726 struct ifaddrs *ifap, *ifa;
727 char err_msg[512];
728
729 if (getifaddrs(&ifap) < 0) {
730 snprintf(err_msg, sizeof(err_msg),
731 "getifaddrs failed: %s", strerror(errno));
732 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
733 goto error;
734 }
735
736 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
737 GuestNetworkInterfaceList *info;
738 GuestIpAddressList **address_list = NULL, *address_item = NULL;
739 char addr4[INET_ADDRSTRLEN];
740 char addr6[INET6_ADDRSTRLEN];
741 int sock;
742 struct ifreq ifr;
743 unsigned char *mac_addr;
744 void *p;
745
746 g_debug("Processing %s interface", ifa->ifa_name);
747
748 info = guest_find_interface(head, ifa->ifa_name);
749
750 if (!info) {
751 info = g_malloc0(sizeof(*info));
752 info->value = g_malloc0(sizeof(*info->value));
753 info->value->name = g_strdup(ifa->ifa_name);
754
755 if (!cur_item) {
756 head = cur_item = info;
757 } else {
758 cur_item->next = info;
759 cur_item = info;
760 }
761 }
762
763 if (!info->value->has_hardware_address &&
764 ifa->ifa_flags & SIOCGIFHWADDR) {
765 /* we haven't obtained HW address yet */
766 sock = socket(PF_INET, SOCK_STREAM, 0);
767 if (sock == -1) {
768 snprintf(err_msg, sizeof(err_msg),
769 "failed to create socket: %s", strerror(errno));
770 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
771 goto error;
772 }
773
774 memset(&ifr, 0, sizeof(ifr));
775 strncpy(ifr.ifr_name, info->value->name, IF_NAMESIZE);
776 if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
777 snprintf(err_msg, sizeof(err_msg),
778 "failed to get MAC addres of %s: %s",
779 ifa->ifa_name,
780 strerror(errno));
781 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
782 goto error;
783 }
784
785 mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
786
787 if (asprintf(&info->value->hardware_address,
788 "%02x:%02x:%02x:%02x:%02x:%02x",
789 (int) mac_addr[0], (int) mac_addr[1],
790 (int) mac_addr[2], (int) mac_addr[3],
791 (int) mac_addr[4], (int) mac_addr[5]) == -1) {
792 snprintf(err_msg, sizeof(err_msg),
793 "failed to format MAC: %s", strerror(errno));
794 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
795 goto error;
796 }
797
798 info->value->has_hardware_address = true;
799 close(sock);
800 }
801
802 if (ifa->ifa_addr &&
803 ifa->ifa_addr->sa_family == AF_INET) {
804 /* interface with IPv4 address */
805 address_item = g_malloc0(sizeof(*address_item));
806 address_item->value = g_malloc0(sizeof(*address_item->value));
807 p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
808 if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
809 snprintf(err_msg, sizeof(err_msg),
810 "inet_ntop failed : %s", strerror(errno));
811 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
812 goto error;
813 }
814
815 address_item->value->ip_address = g_strdup(addr4);
816 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
817
818 if (ifa->ifa_netmask) {
819 /* Count the number of set bits in netmask.
820 * This is safe as '1' and '0' cannot be shuffled in netmask. */
821 p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
822 address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
823 }
824 } else if (ifa->ifa_addr &&
825 ifa->ifa_addr->sa_family == AF_INET6) {
826 /* interface with IPv6 address */
827 address_item = g_malloc0(sizeof(*address_item));
828 address_item->value = g_malloc0(sizeof(*address_item->value));
829 p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
830 if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
831 snprintf(err_msg, sizeof(err_msg),
832 "inet_ntop failed : %s", strerror(errno));
833 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
834 goto error;
835 }
836
837 address_item->value->ip_address = g_strdup(addr6);
838 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
839
840 if (ifa->ifa_netmask) {
841 /* Count the number of set bits in netmask.
842 * This is safe as '1' and '0' cannot be shuffled in netmask. */
843 p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
844 address_item->value->prefix =
845 ctpop32(((uint32_t *) p)[0]) +
846 ctpop32(((uint32_t *) p)[1]) +
847 ctpop32(((uint32_t *) p)[2]) +
848 ctpop32(((uint32_t *) p)[3]);
849 }
850 }
851
852 if (!address_item) {
853 continue;
854 }
855
856 address_list = &info->value->ip_addresses;
857
858 while (*address_list && (*address_list)->next) {
859 address_list = &(*address_list)->next;
860 }
861
862 if (!*address_list) {
863 *address_list = address_item;
864 } else {
865 (*address_list)->next = address_item;
866 }
867
868 info->value->has_ip_addresses = true;
869
870
871 }
872
873 freeifaddrs(ifap);
874 return head;
875
876error:
877 freeifaddrs(ifap);
878 qapi_free_GuestNetworkInterfaceList(head);
879 return NULL;
880}
881
e72c3f2e
MR
882#else /* defined(__linux__) */
883
d35d4cb5 884void qmp_guest_suspend_disk(Error **err)
e72c3f2e
MR
885{
886 error_set(err, QERR_UNSUPPORTED);
e72c3f2e
MR
887}
888
d35d4cb5 889void qmp_guest_suspend_ram(Error **err)
e72c3f2e
MR
890{
891 error_set(err, QERR_UNSUPPORTED);
e72c3f2e
MR
892}
893
d35d4cb5 894void qmp_guest_suspend_hybrid(Error **err)
e72c3f2e
MR
895{
896 error_set(err, QERR_UNSUPPORTED);
e72c3f2e
MR
897}
898
d35d4cb5 899GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
e72c3f2e 900{
d35d4cb5
MR
901 error_set(errp, QERR_UNSUPPORTED);
902 return NULL;
e72c3f2e
MR
903}
904
d35d4cb5
MR
905#endif
906
907#if !defined(CONFIG_FSFREEZE)
908
909GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
e72c3f2e
MR
910{
911 error_set(err, QERR_UNSUPPORTED);
d35d4cb5
MR
912
913 return 0;
e72c3f2e
MR
914}
915
d35d4cb5 916int64_t qmp_guest_fsfreeze_freeze(Error **err)
e72c3f2e
MR
917{
918 error_set(err, QERR_UNSUPPORTED);
d35d4cb5
MR
919
920 return 0;
e72c3f2e
MR
921}
922
d35d4cb5 923int64_t qmp_guest_fsfreeze_thaw(Error **err)
e72c3f2e 924{
d35d4cb5
MR
925 error_set(err, QERR_UNSUPPORTED);
926
927 return 0;
e72c3f2e
MR
928}
929
930#endif
931
e3d4d252
MR
932/* register init/cleanup routines for stateful command groups */
933void ga_command_state_init(GAState *s, GACommandState *cs)
934{
7006b9cf 935#if defined(CONFIG_FSFREEZE)
e3d4d252 936 ga_command_state_add(cs, guest_fsfreeze_init, guest_fsfreeze_cleanup);
7006b9cf 937#endif
e3d4d252
MR
938 ga_command_state_add(cs, guest_file_init, NULL);
939}