target-i386: Use mulu2 and muls2
[qemu/pbrook.git] / qga / commands-posix.c
blob7a0202eb2a25487d03c81f4cb0e921195db2c81e
1 /*
2 * QEMU Guest Agent POSIX-specific command implementations
4 * Copyright IBM Corp. 2011
6 * Authors:
7 * Michael Roth <mdroth@linux.vnet.ibm.com>
8 * Michal Privoznik <mprivozn@redhat.com>
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.
14 #include <glib.h>
15 #include <sys/types.h>
16 #include <sys/ioctl.h>
17 #include <sys/wait.h>
18 #include "qga/guest-agent-core.h"
19 #include "qga-qmp-commands.h"
20 #include "qapi/qmp/qerror.h"
21 #include "qemu/queue.h"
22 #include "qemu/host-utils.h"
24 #ifndef CONFIG_HAS_ENVIRON
25 #ifdef __APPLE__
26 #include <crt_externs.h>
27 #define environ (*_NSGetEnviron())
28 #else
29 extern char **environ;
30 #endif
31 #endif
33 #if defined(__linux__)
34 #include <mntent.h>
35 #include <linux/fs.h>
36 #include <ifaddrs.h>
37 #include <arpa/inet.h>
38 #include <sys/socket.h>
39 #include <net/if.h>
41 #ifdef FIFREEZE
42 #define CONFIG_FSFREEZE
43 #endif
44 #ifdef FITRIM
45 #define CONFIG_FSTRIM
46 #endif
47 #endif
49 static void ga_wait_child(pid_t pid, int *status, Error **err)
51 pid_t rpid;
53 *status = 0;
55 do {
56 rpid = waitpid(pid, status, 0);
57 } while (rpid == -1 && errno == EINTR);
59 if (rpid == -1) {
60 error_setg_errno(err, errno, "failed to wait for child (pid: %d)", pid);
61 return;
64 g_assert(rpid == pid);
67 void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
69 const char *shutdown_flag;
70 Error *local_err = NULL;
71 pid_t pid;
72 int status;
74 slog("guest-shutdown called, mode: %s", mode);
75 if (!has_mode || strcmp(mode, "powerdown") == 0) {
76 shutdown_flag = "-P";
77 } else if (strcmp(mode, "halt") == 0) {
78 shutdown_flag = "-H";
79 } else if (strcmp(mode, "reboot") == 0) {
80 shutdown_flag = "-r";
81 } else {
82 error_setg(err,
83 "mode is invalid (valid values are: halt|powerdown|reboot");
84 return;
87 pid = fork();
88 if (pid == 0) {
89 /* child, start the shutdown */
90 setsid();
91 reopen_fd_to_null(0);
92 reopen_fd_to_null(1);
93 reopen_fd_to_null(2);
95 execle("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
96 "hypervisor initiated shutdown", (char*)NULL, environ);
97 _exit(EXIT_FAILURE);
98 } else if (pid < 0) {
99 error_setg_errno(err, errno, "failed to create child process");
100 return;
103 ga_wait_child(pid, &status, &local_err);
104 if (error_is_set(&local_err)) {
105 error_propagate(err, local_err);
106 return;
109 if (!WIFEXITED(status)) {
110 error_setg(err, "child process has terminated abnormally");
111 return;
114 if (WEXITSTATUS(status)) {
115 error_setg(err, "child process has failed to shutdown");
116 return;
119 /* succeded */
122 typedef struct GuestFileHandle {
123 uint64_t id;
124 FILE *fh;
125 QTAILQ_ENTRY(GuestFileHandle) next;
126 } GuestFileHandle;
128 static struct {
129 QTAILQ_HEAD(, GuestFileHandle) filehandles;
130 } guest_file_state;
132 static void guest_file_handle_add(FILE *fh)
134 GuestFileHandle *gfh;
136 gfh = g_malloc0(sizeof(GuestFileHandle));
137 gfh->id = fileno(fh);
138 gfh->fh = fh;
139 QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
142 static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err)
144 GuestFileHandle *gfh;
146 QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
148 if (gfh->id == id) {
149 return gfh;
153 error_setg(err, "handle '%" PRId64 "' has not been found", id);
154 return NULL;
157 int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
159 FILE *fh;
160 int fd;
161 int64_t ret = -1;
163 if (!has_mode) {
164 mode = "r";
166 slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
167 fh = fopen(path, mode);
168 if (!fh) {
169 error_setg_errno(err, errno, "failed to open file '%s' (mode: '%s')",
170 path, mode);
171 return -1;
174 /* set fd non-blocking to avoid common use cases (like reading from a
175 * named pipe) from hanging the agent
177 fd = fileno(fh);
178 ret = fcntl(fd, F_GETFL);
179 ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
180 if (ret == -1) {
181 error_setg_errno(err, errno, "failed to make file '%s' non-blocking",
182 path);
183 fclose(fh);
184 return -1;
187 guest_file_handle_add(fh);
188 slog("guest-file-open, handle: %d", fd);
189 return fd;
192 void qmp_guest_file_close(int64_t handle, Error **err)
194 GuestFileHandle *gfh = guest_file_handle_find(handle, err);
195 int ret;
197 slog("guest-file-close called, handle: %ld", handle);
198 if (!gfh) {
199 return;
202 ret = fclose(gfh->fh);
203 if (ret == EOF) {
204 error_setg_errno(err, errno, "failed to close handle");
205 return;
208 QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
209 g_free(gfh);
212 struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
213 int64_t count, Error **err)
215 GuestFileHandle *gfh = guest_file_handle_find(handle, err);
216 GuestFileRead *read_data = NULL;
217 guchar *buf;
218 FILE *fh;
219 size_t read_count;
221 if (!gfh) {
222 return NULL;
225 if (!has_count) {
226 count = QGA_READ_COUNT_DEFAULT;
227 } else if (count < 0) {
228 error_setg(err, "value '%" PRId64 "' is invalid for argument count",
229 count);
230 return NULL;
233 fh = gfh->fh;
234 buf = g_malloc0(count+1);
235 read_count = fread(buf, 1, count, fh);
236 if (ferror(fh)) {
237 error_setg_errno(err, errno, "failed to read file");
238 slog("guest-file-read failed, handle: %ld", handle);
239 } else {
240 buf[read_count] = 0;
241 read_data = g_malloc0(sizeof(GuestFileRead));
242 read_data->count = read_count;
243 read_data->eof = feof(fh);
244 if (read_count) {
245 read_data->buf_b64 = g_base64_encode(buf, read_count);
248 g_free(buf);
249 clearerr(fh);
251 return read_data;
254 GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
255 bool has_count, int64_t count, Error **err)
257 GuestFileWrite *write_data = NULL;
258 guchar *buf;
259 gsize buf_len;
260 int write_count;
261 GuestFileHandle *gfh = guest_file_handle_find(handle, err);
262 FILE *fh;
264 if (!gfh) {
265 return NULL;
268 fh = gfh->fh;
269 buf = g_base64_decode(buf_b64, &buf_len);
271 if (!has_count) {
272 count = buf_len;
273 } else if (count < 0 || count > buf_len) {
274 error_setg(err, "value '%" PRId64 "' is invalid for argument count",
275 count);
276 g_free(buf);
277 return NULL;
280 write_count = fwrite(buf, 1, count, fh);
281 if (ferror(fh)) {
282 error_setg_errno(err, errno, "failed to write to file");
283 slog("guest-file-write failed, handle: %ld", handle);
284 } else {
285 write_data = g_malloc0(sizeof(GuestFileWrite));
286 write_data->count = write_count;
287 write_data->eof = feof(fh);
289 g_free(buf);
290 clearerr(fh);
292 return write_data;
295 struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
296 int64_t whence, Error **err)
298 GuestFileHandle *gfh = guest_file_handle_find(handle, err);
299 GuestFileSeek *seek_data = NULL;
300 FILE *fh;
301 int ret;
303 if (!gfh) {
304 return NULL;
307 fh = gfh->fh;
308 ret = fseek(fh, offset, whence);
309 if (ret == -1) {
310 error_setg_errno(err, errno, "failed to seek file");
311 } else {
312 seek_data = g_malloc0(sizeof(GuestFileRead));
313 seek_data->position = ftell(fh);
314 seek_data->eof = feof(fh);
316 clearerr(fh);
318 return seek_data;
321 void qmp_guest_file_flush(int64_t handle, Error **err)
323 GuestFileHandle *gfh = guest_file_handle_find(handle, err);
324 FILE *fh;
325 int ret;
327 if (!gfh) {
328 return;
331 fh = gfh->fh;
332 ret = fflush(fh);
333 if (ret == EOF) {
334 error_setg_errno(err, errno, "failed to flush file");
338 static void guest_file_init(void)
340 QTAILQ_INIT(&guest_file_state.filehandles);
343 /* linux-specific implementations. avoid this if at all possible. */
344 #if defined(__linux__)
346 #if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
347 typedef struct FsMount {
348 char *dirname;
349 char *devtype;
350 QTAILQ_ENTRY(FsMount) next;
351 } FsMount;
353 typedef QTAILQ_HEAD(, FsMount) FsMountList;
355 static void free_fs_mount_list(FsMountList *mounts)
357 FsMount *mount, *temp;
359 if (!mounts) {
360 return;
363 QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) {
364 QTAILQ_REMOVE(mounts, mount, next);
365 g_free(mount->dirname);
366 g_free(mount->devtype);
367 g_free(mount);
372 * Walk the mount table and build a list of local file systems
374 static void build_fs_mount_list(FsMountList *mounts, Error **err)
376 struct mntent *ment;
377 FsMount *mount;
378 char const *mtab = "/proc/self/mounts";
379 FILE *fp;
381 fp = setmntent(mtab, "r");
382 if (!fp) {
383 error_setg(err, "failed to open mtab file: '%s'", mtab);
384 return;
387 while ((ment = getmntent(fp))) {
389 * An entry which device name doesn't start with a '/' is
390 * either a dummy file system or a network file system.
391 * Add special handling for smbfs and cifs as is done by
392 * coreutils as well.
394 if ((ment->mnt_fsname[0] != '/') ||
395 (strcmp(ment->mnt_type, "smbfs") == 0) ||
396 (strcmp(ment->mnt_type, "cifs") == 0)) {
397 continue;
400 mount = g_malloc0(sizeof(FsMount));
401 mount->dirname = g_strdup(ment->mnt_dir);
402 mount->devtype = g_strdup(ment->mnt_type);
404 QTAILQ_INSERT_TAIL(mounts, mount, next);
407 endmntent(fp);
409 #endif
411 #if defined(CONFIG_FSFREEZE)
413 typedef enum {
414 FSFREEZE_HOOK_THAW = 0,
415 FSFREEZE_HOOK_FREEZE,
416 } FsfreezeHookArg;
418 const char *fsfreeze_hook_arg_string[] = {
419 "thaw",
420 "freeze",
423 static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **err)
425 int status;
426 pid_t pid;
427 const char *hook;
428 const char *arg_str = fsfreeze_hook_arg_string[arg];
429 Error *local_err = NULL;
431 hook = ga_fsfreeze_hook(ga_state);
432 if (!hook) {
433 return;
435 if (access(hook, X_OK) != 0) {
436 error_setg_errno(err, errno, "can't access fsfreeze hook '%s'", hook);
437 return;
440 slog("executing fsfreeze hook with arg '%s'", arg_str);
441 pid = fork();
442 if (pid == 0) {
443 setsid();
444 reopen_fd_to_null(0);
445 reopen_fd_to_null(1);
446 reopen_fd_to_null(2);
448 execle(hook, hook, arg_str, NULL, environ);
449 _exit(EXIT_FAILURE);
450 } else if (pid < 0) {
451 error_setg_errno(err, errno, "failed to create child process");
452 return;
455 ga_wait_child(pid, &status, &local_err);
456 if (error_is_set(&local_err)) {
457 error_propagate(err, local_err);
458 return;
461 if (!WIFEXITED(status)) {
462 error_setg(err, "fsfreeze hook has terminated abnormally");
463 return;
466 status = WEXITSTATUS(status);
467 if (status) {
468 error_setg(err, "fsfreeze hook has failed with status %d", status);
469 return;
474 * Return status of freeze/thaw
476 GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
478 if (ga_is_frozen(ga_state)) {
479 return GUEST_FSFREEZE_STATUS_FROZEN;
482 return GUEST_FSFREEZE_STATUS_THAWED;
486 * Walk list of mounted file systems in the guest, and freeze the ones which
487 * are real local file systems.
489 int64_t qmp_guest_fsfreeze_freeze(Error **err)
491 int ret = 0, i = 0;
492 FsMountList mounts;
493 struct FsMount *mount;
494 Error *local_err = NULL;
495 int fd;
497 slog("guest-fsfreeze called");
499 execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err);
500 if (error_is_set(&local_err)) {
501 error_propagate(err, local_err);
502 return -1;
505 QTAILQ_INIT(&mounts);
506 build_fs_mount_list(&mounts, &local_err);
507 if (error_is_set(&local_err)) {
508 error_propagate(err, local_err);
509 return -1;
512 /* cannot risk guest agent blocking itself on a write in this state */
513 ga_set_frozen(ga_state);
515 QTAILQ_FOREACH(mount, &mounts, next) {
516 fd = qemu_open(mount->dirname, O_RDONLY);
517 if (fd == -1) {
518 error_setg_errno(err, errno, "failed to open %s", mount->dirname);
519 goto error;
522 /* we try to cull filesytems we know won't work in advance, but other
523 * filesytems may not implement fsfreeze for less obvious reasons.
524 * these will report EOPNOTSUPP. we simply ignore these when tallying
525 * the number of frozen filesystems.
527 * any other error means a failure to freeze a filesystem we
528 * expect to be freezable, so return an error in those cases
529 * and return system to thawed state.
531 ret = ioctl(fd, FIFREEZE);
532 if (ret == -1) {
533 if (errno != EOPNOTSUPP) {
534 error_setg_errno(err, errno, "failed to freeze %s",
535 mount->dirname);
536 close(fd);
537 goto error;
539 } else {
540 i++;
542 close(fd);
545 free_fs_mount_list(&mounts);
546 return i;
548 error:
549 free_fs_mount_list(&mounts);
550 qmp_guest_fsfreeze_thaw(NULL);
551 return 0;
555 * Walk list of frozen file systems in the guest, and thaw them.
557 int64_t qmp_guest_fsfreeze_thaw(Error **err)
559 int ret;
560 FsMountList mounts;
561 FsMount *mount;
562 int fd, i = 0, logged;
563 Error *local_err = NULL;
565 QTAILQ_INIT(&mounts);
566 build_fs_mount_list(&mounts, &local_err);
567 if (error_is_set(&local_err)) {
568 error_propagate(err, local_err);
569 return 0;
572 QTAILQ_FOREACH(mount, &mounts, next) {
573 logged = false;
574 fd = qemu_open(mount->dirname, O_RDONLY);
575 if (fd == -1) {
576 continue;
578 /* we have no way of knowing whether a filesystem was actually unfrozen
579 * as a result of a successful call to FITHAW, only that if an error
580 * was returned the filesystem was *not* unfrozen by that particular
581 * call.
583 * since multiple preceding FIFREEZEs require multiple calls to FITHAW
584 * to unfreeze, continuing issuing FITHAW until an error is returned,
585 * in which case either the filesystem is in an unfreezable state, or,
586 * more likely, it was thawed previously (and remains so afterward).
588 * also, since the most recent successful call is the one that did
589 * the actual unfreeze, we can use this to provide an accurate count
590 * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which
591 * may * be useful for determining whether a filesystem was unfrozen
592 * during the freeze/thaw phase by a process other than qemu-ga.
594 do {
595 ret = ioctl(fd, FITHAW);
596 if (ret == 0 && !logged) {
597 i++;
598 logged = true;
600 } while (ret == 0);
601 close(fd);
604 ga_unset_frozen(ga_state);
605 free_fs_mount_list(&mounts);
607 execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, err);
609 return i;
612 static void guest_fsfreeze_cleanup(void)
614 Error *err = NULL;
616 if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
617 qmp_guest_fsfreeze_thaw(&err);
618 if (err) {
619 slog("failed to clean up frozen filesystems: %s",
620 error_get_pretty(err));
621 error_free(err);
625 #endif /* CONFIG_FSFREEZE */
627 #if defined(CONFIG_FSTRIM)
629 * Walk list of mounted file systems in the guest, and trim them.
631 void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err)
633 int ret = 0;
634 FsMountList mounts;
635 struct FsMount *mount;
636 int fd;
637 Error *local_err = NULL;
638 struct fstrim_range r = {
639 .start = 0,
640 .len = -1,
641 .minlen = has_minimum ? minimum : 0,
644 slog("guest-fstrim called");
646 QTAILQ_INIT(&mounts);
647 build_fs_mount_list(&mounts, &local_err);
648 if (error_is_set(&local_err)) {
649 error_propagate(err, local_err);
650 return;
653 QTAILQ_FOREACH(mount, &mounts, next) {
654 fd = qemu_open(mount->dirname, O_RDONLY);
655 if (fd == -1) {
656 error_setg_errno(err, errno, "failed to open %s", mount->dirname);
657 goto error;
660 /* We try to cull filesytems we know won't work in advance, but other
661 * filesytems may not implement fstrim for less obvious reasons. These
662 * will report EOPNOTSUPP; we simply ignore these errors. Any other
663 * error means an unexpected error, so return it in those cases. In
664 * some other cases ENOTTY will be reported (e.g. CD-ROMs).
666 ret = ioctl(fd, FITRIM, &r);
667 if (ret == -1) {
668 if (errno != ENOTTY && errno != EOPNOTSUPP) {
669 error_setg_errno(err, errno, "failed to trim %s",
670 mount->dirname);
671 close(fd);
672 goto error;
675 close(fd);
678 error:
679 free_fs_mount_list(&mounts);
681 #endif /* CONFIG_FSTRIM */
684 #define LINUX_SYS_STATE_FILE "/sys/power/state"
685 #define SUSPEND_SUPPORTED 0
686 #define SUSPEND_NOT_SUPPORTED 1
688 static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
689 const char *sysfile_str, Error **err)
691 Error *local_err = NULL;
692 char *pmutils_path;
693 pid_t pid;
694 int status;
696 pmutils_path = g_find_program_in_path(pmutils_bin);
698 pid = fork();
699 if (!pid) {
700 char buf[32]; /* hopefully big enough */
701 ssize_t ret;
702 int fd;
704 setsid();
705 reopen_fd_to_null(0);
706 reopen_fd_to_null(1);
707 reopen_fd_to_null(2);
709 if (pmutils_path) {
710 execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
714 * If we get here either pm-utils is not installed or execle() has
715 * failed. Let's try the manual method if the caller wants it.
718 if (!sysfile_str) {
719 _exit(SUSPEND_NOT_SUPPORTED);
722 fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
723 if (fd < 0) {
724 _exit(SUSPEND_NOT_SUPPORTED);
727 ret = read(fd, buf, sizeof(buf)-1);
728 if (ret <= 0) {
729 _exit(SUSPEND_NOT_SUPPORTED);
731 buf[ret] = '\0';
733 if (strstr(buf, sysfile_str)) {
734 _exit(SUSPEND_SUPPORTED);
737 _exit(SUSPEND_NOT_SUPPORTED);
738 } else if (pid < 0) {
739 error_setg_errno(err, errno, "failed to create child process");
740 goto out;
743 ga_wait_child(pid, &status, &local_err);
744 if (error_is_set(&local_err)) {
745 error_propagate(err, local_err);
746 goto out;
749 if (!WIFEXITED(status)) {
750 error_setg(err, "child process has terminated abnormally");
751 goto out;
754 switch (WEXITSTATUS(status)) {
755 case SUSPEND_SUPPORTED:
756 goto out;
757 case SUSPEND_NOT_SUPPORTED:
758 error_setg(err,
759 "the requested suspend mode is not supported by the guest");
760 goto out;
761 default:
762 error_setg(err,
763 "the helper program '%s' returned an unexpected exit status"
764 " code (%d)", pmutils_path, WEXITSTATUS(status));
765 goto out;
768 out:
769 g_free(pmutils_path);
772 static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
773 Error **err)
775 Error *local_err = NULL;
776 char *pmutils_path;
777 pid_t pid;
778 int status;
780 pmutils_path = g_find_program_in_path(pmutils_bin);
782 pid = fork();
783 if (pid == 0) {
784 /* child */
785 int fd;
787 setsid();
788 reopen_fd_to_null(0);
789 reopen_fd_to_null(1);
790 reopen_fd_to_null(2);
792 if (pmutils_path) {
793 execle(pmutils_path, pmutils_bin, NULL, environ);
797 * If we get here either pm-utils is not installed or execle() has
798 * failed. Let's try the manual method if the caller wants it.
801 if (!sysfile_str) {
802 _exit(EXIT_FAILURE);
805 fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
806 if (fd < 0) {
807 _exit(EXIT_FAILURE);
810 if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
811 _exit(EXIT_FAILURE);
814 _exit(EXIT_SUCCESS);
815 } else if (pid < 0) {
816 error_setg_errno(err, errno, "failed to create child process");
817 goto out;
820 ga_wait_child(pid, &status, &local_err);
821 if (error_is_set(&local_err)) {
822 error_propagate(err, local_err);
823 goto out;
826 if (!WIFEXITED(status)) {
827 error_setg(err, "child process has terminated abnormally");
828 goto out;
831 if (WEXITSTATUS(status)) {
832 error_setg(err, "child process has failed to suspend");
833 goto out;
836 out:
837 g_free(pmutils_path);
840 void qmp_guest_suspend_disk(Error **err)
842 bios_supports_mode("pm-is-supported", "--hibernate", "disk", err);
843 if (error_is_set(err)) {
844 return;
847 guest_suspend("pm-hibernate", "disk", err);
850 void qmp_guest_suspend_ram(Error **err)
852 bios_supports_mode("pm-is-supported", "--suspend", "mem", err);
853 if (error_is_set(err)) {
854 return;
857 guest_suspend("pm-suspend", "mem", err);
860 void qmp_guest_suspend_hybrid(Error **err)
862 bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err);
863 if (error_is_set(err)) {
864 return;
867 guest_suspend("pm-suspend-hybrid", NULL, err);
870 static GuestNetworkInterfaceList *
871 guest_find_interface(GuestNetworkInterfaceList *head,
872 const char *name)
874 for (; head; head = head->next) {
875 if (strcmp(head->value->name, name) == 0) {
876 break;
880 return head;
884 * Build information about guest interfaces
886 GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
888 GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
889 struct ifaddrs *ifap, *ifa;
891 if (getifaddrs(&ifap) < 0) {
892 error_setg_errno(errp, errno, "getifaddrs failed");
893 goto error;
896 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
897 GuestNetworkInterfaceList *info;
898 GuestIpAddressList **address_list = NULL, *address_item = NULL;
899 char addr4[INET_ADDRSTRLEN];
900 char addr6[INET6_ADDRSTRLEN];
901 int sock;
902 struct ifreq ifr;
903 unsigned char *mac_addr;
904 void *p;
906 g_debug("Processing %s interface", ifa->ifa_name);
908 info = guest_find_interface(head, ifa->ifa_name);
910 if (!info) {
911 info = g_malloc0(sizeof(*info));
912 info->value = g_malloc0(sizeof(*info->value));
913 info->value->name = g_strdup(ifa->ifa_name);
915 if (!cur_item) {
916 head = cur_item = info;
917 } else {
918 cur_item->next = info;
919 cur_item = info;
923 if (!info->value->has_hardware_address &&
924 ifa->ifa_flags & SIOCGIFHWADDR) {
925 /* we haven't obtained HW address yet */
926 sock = socket(PF_INET, SOCK_STREAM, 0);
927 if (sock == -1) {
928 error_setg_errno(errp, errno, "failed to create socket");
929 goto error;
932 memset(&ifr, 0, sizeof(ifr));
933 pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->value->name);
934 if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
935 error_setg_errno(errp, errno,
936 "failed to get MAC address of %s",
937 ifa->ifa_name);
938 close(sock);
939 goto error;
942 close(sock);
943 mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
945 info->value->hardware_address =
946 g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x",
947 (int) mac_addr[0], (int) mac_addr[1],
948 (int) mac_addr[2], (int) mac_addr[3],
949 (int) mac_addr[4], (int) mac_addr[5]);
951 info->value->has_hardware_address = true;
954 if (ifa->ifa_addr &&
955 ifa->ifa_addr->sa_family == AF_INET) {
956 /* interface with IPv4 address */
957 p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
958 if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
959 error_setg_errno(errp, errno, "inet_ntop failed");
960 goto error;
963 address_item = g_malloc0(sizeof(*address_item));
964 address_item->value = g_malloc0(sizeof(*address_item->value));
965 address_item->value->ip_address = g_strdup(addr4);
966 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
968 if (ifa->ifa_netmask) {
969 /* Count the number of set bits in netmask.
970 * This is safe as '1' and '0' cannot be shuffled in netmask. */
971 p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
972 address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
974 } else if (ifa->ifa_addr &&
975 ifa->ifa_addr->sa_family == AF_INET6) {
976 /* interface with IPv6 address */
977 p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
978 if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
979 error_setg_errno(errp, errno, "inet_ntop failed");
980 goto error;
983 address_item = g_malloc0(sizeof(*address_item));
984 address_item->value = g_malloc0(sizeof(*address_item->value));
985 address_item->value->ip_address = g_strdup(addr6);
986 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
988 if (ifa->ifa_netmask) {
989 /* Count the number of set bits in netmask.
990 * This is safe as '1' and '0' cannot be shuffled in netmask. */
991 p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
992 address_item->value->prefix =
993 ctpop32(((uint32_t *) p)[0]) +
994 ctpop32(((uint32_t *) p)[1]) +
995 ctpop32(((uint32_t *) p)[2]) +
996 ctpop32(((uint32_t *) p)[3]);
1000 if (!address_item) {
1001 continue;
1004 address_list = &info->value->ip_addresses;
1006 while (*address_list && (*address_list)->next) {
1007 address_list = &(*address_list)->next;
1010 if (!*address_list) {
1011 *address_list = address_item;
1012 } else {
1013 (*address_list)->next = address_item;
1016 info->value->has_ip_addresses = true;
1021 freeifaddrs(ifap);
1022 return head;
1024 error:
1025 freeifaddrs(ifap);
1026 qapi_free_GuestNetworkInterfaceList(head);
1027 return NULL;
1030 #else /* defined(__linux__) */
1032 void qmp_guest_suspend_disk(Error **err)
1034 error_set(err, QERR_UNSUPPORTED);
1037 void qmp_guest_suspend_ram(Error **err)
1039 error_set(err, QERR_UNSUPPORTED);
1042 void qmp_guest_suspend_hybrid(Error **err)
1044 error_set(err, QERR_UNSUPPORTED);
1047 GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
1049 error_set(errp, QERR_UNSUPPORTED);
1050 return NULL;
1053 #endif
1055 #if !defined(CONFIG_FSFREEZE)
1057 GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
1059 error_set(err, QERR_UNSUPPORTED);
1061 return 0;
1064 int64_t qmp_guest_fsfreeze_freeze(Error **err)
1066 error_set(err, QERR_UNSUPPORTED);
1068 return 0;
1071 int64_t qmp_guest_fsfreeze_thaw(Error **err)
1073 error_set(err, QERR_UNSUPPORTED);
1075 return 0;
1077 #endif /* CONFIG_FSFREEZE */
1079 #if !defined(CONFIG_FSTRIM)
1080 void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err)
1082 error_set(err, QERR_UNSUPPORTED);
1084 #endif
1086 /* register init/cleanup routines for stateful command groups */
1087 void ga_command_state_init(GAState *s, GACommandState *cs)
1089 #if defined(CONFIG_FSFREEZE)
1090 ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
1091 #endif
1092 ga_command_state_add(cs, guest_file_init, NULL);