]> git.proxmox.com Git - qemu.git/blob - qga/commands-posix.c
qemu-ga: improve recovery options for fsfreeze
[qemu.git] / qga / commands-posix.c
1 /*
2 * QEMU Guest Agent POSIX-specific command implementations
3 *
4 * Copyright IBM Corp. 2011
5 *
6 * Authors:
7 * Michael Roth <mdroth@linux.vnet.ibm.com>
8 * Michal Privoznik <mprivozn@redhat.com>
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>
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"
22
23 #if defined(__linux__)
24 #include <mntent.h>
25 #include <linux/fs.h>
26 #include <ifaddrs.h>
27 #include <arpa/inet.h>
28 #include <sys/socket.h>
29 #include <net/if.h>
30 #include <sys/wait.h>
31
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 */
39 static 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 }
54 #endif /* defined(__linux__) */
55
56 void 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
93 typedef struct GuestFileHandle {
94 uint64_t id;
95 FILE *fh;
96 QTAILQ_ENTRY(GuestFileHandle) next;
97 } GuestFileHandle;
98
99 static struct {
100 QTAILQ_HEAD(, GuestFileHandle) filehandles;
101 } guest_file_state;
102
103 static void guest_file_handle_add(FILE *fh)
104 {
105 GuestFileHandle *gfh;
106
107 gfh = g_malloc0(sizeof(GuestFileHandle));
108 gfh->id = fileno(fh);
109 gfh->fh = fh;
110 QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
111 }
112
113 static 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
127 int64_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
160 void 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);
178 g_free(gfh);
179 }
180
181 struct 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;
203 buf = g_malloc0(count+1);
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;
210 read_data = g_malloc0(sizeof(GuestFileRead));
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 }
217 g_free(buf);
218 clearerr(fh);
219
220 return read_data;
221 }
222
223 GuestFileWrite *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) {
244 g_free(buf);
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 {
254 write_data = g_malloc0(sizeof(GuestFileWrite));
255 write_data->count = write_count;
256 write_data->eof = feof(fh);
257 }
258 g_free(buf);
259 clearerr(fh);
260
261 return write_data;
262 }
263
264 struct 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 {
282 seek_data = g_malloc0(sizeof(GuestFileRead));
283 seek_data->position = ftell(fh);
284 seek_data->eof = feof(fh);
285 }
286 clearerr(fh);
287
288 return seek_data;
289 }
290
291 void 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
309 static void guest_file_init(void)
310 {
311 QTAILQ_INIT(&guest_file_state.filehandles);
312 }
313
314 /* linux-specific implementations. avoid this if at all possible. */
315 #if defined(__linux__)
316
317 #if defined(CONFIG_FSFREEZE)
318
319 static void disable_logging(void)
320 {
321 ga_disable_logging(ga_state);
322 }
323
324 static void enable_logging(void)
325 {
326 ga_enable_logging(ga_state);
327 }
328
329 typedef struct GuestFsfreezeMount {
330 char *dirname;
331 char *devtype;
332 QTAILQ_ENTRY(GuestFsfreezeMount) next;
333 } GuestFsfreezeMount;
334
335 typedef QTAILQ_HEAD(, GuestFsfreezeMount) GuestFsfreezeMountList;
336
337 struct {
338 GuestFsfreezeStatus status;
339 } guest_fsfreeze_state;
340
341 static void guest_fsfreeze_free_mount_list(GuestFsfreezeMountList *mounts)
342 {
343 GuestFsfreezeMount *mount, *temp;
344
345 if (!mounts) {
346 return;
347 }
348
349 QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) {
350 QTAILQ_REMOVE(mounts, mount, next);
351 g_free(mount->dirname);
352 g_free(mount->devtype);
353 g_free(mount);
354 }
355 }
356
357 /*
358 * Walk the mount table and build a list of local file systems
359 */
360 static int guest_fsfreeze_build_mount_list(GuestFsfreezeMountList *mounts)
361 {
362 struct mntent *ment;
363 GuestFsfreezeMount *mount;
364 char const *mtab = MOUNTED;
365 FILE *fp;
366
367 fp = setmntent(mtab, "r");
368 if (!fp) {
369 g_warning("fsfreeze: unable to read mtab");
370 return -1;
371 }
372
373 while ((ment = getmntent(fp))) {
374 /*
375 * An entry which device name doesn't start with a '/' is
376 * either a dummy file system or a network file system.
377 * Add special handling for smbfs and cifs as is done by
378 * coreutils as well.
379 */
380 if ((ment->mnt_fsname[0] != '/') ||
381 (strcmp(ment->mnt_type, "smbfs") == 0) ||
382 (strcmp(ment->mnt_type, "cifs") == 0)) {
383 continue;
384 }
385
386 mount = g_malloc0(sizeof(GuestFsfreezeMount));
387 mount->dirname = g_strdup(ment->mnt_dir);
388 mount->devtype = g_strdup(ment->mnt_type);
389
390 QTAILQ_INSERT_TAIL(mounts, mount, next);
391 }
392
393 endmntent(fp);
394
395 return 0;
396 }
397
398 /*
399 * Return status of freeze/thaw
400 */
401 GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
402 {
403 return guest_fsfreeze_state.status;
404 }
405
406 /*
407 * Walk list of mounted file systems in the guest, and freeze the ones which
408 * are real local file systems.
409 */
410 int64_t qmp_guest_fsfreeze_freeze(Error **err)
411 {
412 int ret = 0, i = 0;
413 GuestFsfreezeMountList mounts;
414 struct GuestFsfreezeMount *mount;
415 int fd;
416 char err_msg[512];
417
418 slog("guest-fsfreeze called");
419
420 QTAILQ_INIT(&mounts);
421 ret = guest_fsfreeze_build_mount_list(&mounts);
422 if (ret < 0) {
423 return ret;
424 }
425
426 /* cannot risk guest agent blocking itself on a write in this state */
427 disable_logging();
428
429 QTAILQ_FOREACH(mount, &mounts, next) {
430 fd = qemu_open(mount->dirname, O_RDONLY);
431 if (fd == -1) {
432 sprintf(err_msg, "failed to open %s, %s", mount->dirname,
433 strerror(errno));
434 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
435 goto error;
436 }
437
438 /* we try to cull filesytems we know won't work in advance, but other
439 * filesytems may not implement fsfreeze for less obvious reasons.
440 * these will report EOPNOTSUPP. we simply ignore these when tallying
441 * the number of frozen filesystems.
442 *
443 * any other error means a failure to freeze a filesystem we
444 * expect to be freezable, so return an error in those cases
445 * and return system to thawed state.
446 */
447 ret = ioctl(fd, FIFREEZE);
448 if (ret == -1) {
449 if (errno != EOPNOTSUPP) {
450 sprintf(err_msg, "failed to freeze %s, %s",
451 mount->dirname, strerror(errno));
452 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
453 close(fd);
454 goto error;
455 }
456 } else {
457 i++;
458 }
459 close(fd);
460 }
461
462 guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_FROZEN;
463 guest_fsfreeze_free_mount_list(&mounts);
464 return i;
465
466 error:
467 guest_fsfreeze_free_mount_list(&mounts);
468 qmp_guest_fsfreeze_thaw(NULL);
469 return 0;
470 }
471
472 /*
473 * Walk list of frozen file systems in the guest, and thaw them.
474 */
475 int64_t qmp_guest_fsfreeze_thaw(Error **err)
476 {
477 int ret;
478 GuestFsfreezeMountList mounts;
479 GuestFsfreezeMount *mount;
480 int fd, i = 0, logged;
481
482 QTAILQ_INIT(&mounts);
483 ret = guest_fsfreeze_build_mount_list(&mounts);
484 if (ret) {
485 error_set(err, QERR_QGA_COMMAND_FAILED,
486 "failed to enumerate filesystems");
487 return 0;
488 }
489
490 QTAILQ_FOREACH(mount, &mounts, next) {
491 logged = false;
492 fd = qemu_open(mount->dirname, O_RDONLY);
493 if (fd == -1) {
494 continue;
495 }
496 /* we have no way of knowing whether a filesystem was actually unfrozen
497 * as a result of a successful call to FITHAW, only that if an error
498 * was returned the filesystem was *not* unfrozen by that particular
499 * call.
500 *
501 * since multiple preceeding FIFREEZEs require multiple calls to FITHAW
502 * to unfreeze, continuing issuing FITHAW until an error is returned,
503 * in which case either the filesystem is in an unfreezable state, or,
504 * more likely, it was thawed previously (and remains so afterward).
505 *
506 * also, since the most recent successful call is the one that did
507 * the actual unfreeze, we can use this to provide an accurate count
508 * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which
509 * may * be useful for determining whether a filesystem was unfrozen
510 * during the freeze/thaw phase by a process other than qemu-ga.
511 */
512 do {
513 ret = ioctl(fd, FITHAW);
514 if (ret == 0 && !logged) {
515 i++;
516 logged = true;
517 }
518 } while (ret == 0);
519 close(fd);
520 }
521
522 guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_THAWED;
523 enable_logging();
524 guest_fsfreeze_free_mount_list(&mounts);
525 return i;
526 }
527
528 static void guest_fsfreeze_init(void)
529 {
530 guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_THAWED;
531 }
532
533 static void guest_fsfreeze_cleanup(void)
534 {
535 int64_t ret;
536 Error *err = NULL;
537
538 if (guest_fsfreeze_state.status == GUEST_FSFREEZE_STATUS_FROZEN) {
539 ret = qmp_guest_fsfreeze_thaw(&err);
540 if (ret < 0 || err) {
541 slog("failed to clean up frozen filesystems");
542 }
543 }
544 }
545 #endif /* CONFIG_FSFREEZE */
546
547 #define LINUX_SYS_STATE_FILE "/sys/power/state"
548 #define SUSPEND_SUPPORTED 0
549 #define SUSPEND_NOT_SUPPORTED 1
550
551 /**
552 * This function forks twice and the information about the mode support
553 * status is passed to the qemu-ga process via a pipe.
554 *
555 * This approach allows us to keep the way we reap terminated children
556 * in qemu-ga quite simple.
557 */
558 static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
559 const char *sysfile_str, Error **err)
560 {
561 pid_t pid;
562 ssize_t ret;
563 char *pmutils_path;
564 int status, pipefds[2];
565
566 if (pipe(pipefds) < 0) {
567 error_set(err, QERR_UNDEFINED_ERROR);
568 return;
569 }
570
571 pmutils_path = g_find_program_in_path(pmutils_bin);
572
573 pid = fork();
574 if (!pid) {
575 struct sigaction act;
576
577 memset(&act, 0, sizeof(act));
578 act.sa_handler = SIG_DFL;
579 sigaction(SIGCHLD, &act, NULL);
580
581 setsid();
582 close(pipefds[0]);
583 reopen_fd_to_null(0);
584 reopen_fd_to_null(1);
585 reopen_fd_to_null(2);
586
587 pid = fork();
588 if (!pid) {
589 int fd;
590 char buf[32]; /* hopefully big enough */
591
592 if (pmutils_path) {
593 execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
594 }
595
596 /*
597 * If we get here either pm-utils is not installed or execle() has
598 * failed. Let's try the manual method if the caller wants it.
599 */
600
601 if (!sysfile_str) {
602 _exit(SUSPEND_NOT_SUPPORTED);
603 }
604
605 fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
606 if (fd < 0) {
607 _exit(SUSPEND_NOT_SUPPORTED);
608 }
609
610 ret = read(fd, buf, sizeof(buf)-1);
611 if (ret <= 0) {
612 _exit(SUSPEND_NOT_SUPPORTED);
613 }
614 buf[ret] = '\0';
615
616 if (strstr(buf, sysfile_str)) {
617 _exit(SUSPEND_SUPPORTED);
618 }
619
620 _exit(SUSPEND_NOT_SUPPORTED);
621 }
622
623 if (pid > 0) {
624 wait(&status);
625 } else {
626 status = SUSPEND_NOT_SUPPORTED;
627 }
628
629 ret = write(pipefds[1], &status, sizeof(status));
630 if (ret != sizeof(status)) {
631 _exit(EXIT_FAILURE);
632 }
633
634 _exit(EXIT_SUCCESS);
635 }
636
637 close(pipefds[1]);
638 g_free(pmutils_path);
639
640 if (pid < 0) {
641 error_set(err, QERR_UNDEFINED_ERROR);
642 goto out;
643 }
644
645 ret = read(pipefds[0], &status, sizeof(status));
646 if (ret == sizeof(status) && WIFEXITED(status) &&
647 WEXITSTATUS(status) == SUSPEND_SUPPORTED) {
648 goto out;
649 }
650
651 error_set(err, QERR_UNSUPPORTED);
652
653 out:
654 close(pipefds[0]);
655 }
656
657 static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
658 Error **err)
659 {
660 pid_t pid;
661 char *pmutils_path;
662
663 pmutils_path = g_find_program_in_path(pmutils_bin);
664
665 pid = fork();
666 if (pid == 0) {
667 /* child */
668 int fd;
669
670 setsid();
671 reopen_fd_to_null(0);
672 reopen_fd_to_null(1);
673 reopen_fd_to_null(2);
674
675 if (pmutils_path) {
676 execle(pmutils_path, pmutils_bin, NULL, environ);
677 }
678
679 /*
680 * If we get here either pm-utils is not installed or execle() has
681 * failed. Let's try the manual method if the caller wants it.
682 */
683
684 if (!sysfile_str) {
685 _exit(EXIT_FAILURE);
686 }
687
688 fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
689 if (fd < 0) {
690 _exit(EXIT_FAILURE);
691 }
692
693 if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
694 _exit(EXIT_FAILURE);
695 }
696
697 _exit(EXIT_SUCCESS);
698 }
699
700 g_free(pmutils_path);
701
702 if (pid < 0) {
703 error_set(err, QERR_UNDEFINED_ERROR);
704 return;
705 }
706 }
707
708 void qmp_guest_suspend_disk(Error **err)
709 {
710 bios_supports_mode("pm-is-supported", "--hibernate", "disk", err);
711 if (error_is_set(err)) {
712 return;
713 }
714
715 guest_suspend("pm-hibernate", "disk", err);
716 }
717
718 void qmp_guest_suspend_ram(Error **err)
719 {
720 bios_supports_mode("pm-is-supported", "--suspend", "mem", err);
721 if (error_is_set(err)) {
722 return;
723 }
724
725 guest_suspend("pm-suspend", "mem", err);
726 }
727
728 void qmp_guest_suspend_hybrid(Error **err)
729 {
730 bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err);
731 if (error_is_set(err)) {
732 return;
733 }
734
735 guest_suspend("pm-suspend-hybrid", NULL, err);
736 }
737
738 static GuestNetworkInterfaceList *
739 guest_find_interface(GuestNetworkInterfaceList *head,
740 const char *name)
741 {
742 for (; head; head = head->next) {
743 if (strcmp(head->value->name, name) == 0) {
744 break;
745 }
746 }
747
748 return head;
749 }
750
751 /*
752 * Build information about guest interfaces
753 */
754 GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
755 {
756 GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
757 struct ifaddrs *ifap, *ifa;
758 char err_msg[512];
759
760 if (getifaddrs(&ifap) < 0) {
761 snprintf(err_msg, sizeof(err_msg),
762 "getifaddrs failed: %s", strerror(errno));
763 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
764 goto error;
765 }
766
767 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
768 GuestNetworkInterfaceList *info;
769 GuestIpAddressList **address_list = NULL, *address_item = NULL;
770 char addr4[INET_ADDRSTRLEN];
771 char addr6[INET6_ADDRSTRLEN];
772 int sock;
773 struct ifreq ifr;
774 unsigned char *mac_addr;
775 void *p;
776
777 g_debug("Processing %s interface", ifa->ifa_name);
778
779 info = guest_find_interface(head, ifa->ifa_name);
780
781 if (!info) {
782 info = g_malloc0(sizeof(*info));
783 info->value = g_malloc0(sizeof(*info->value));
784 info->value->name = g_strdup(ifa->ifa_name);
785
786 if (!cur_item) {
787 head = cur_item = info;
788 } else {
789 cur_item->next = info;
790 cur_item = info;
791 }
792 }
793
794 if (!info->value->has_hardware_address &&
795 ifa->ifa_flags & SIOCGIFHWADDR) {
796 /* we haven't obtained HW address yet */
797 sock = socket(PF_INET, SOCK_STREAM, 0);
798 if (sock == -1) {
799 snprintf(err_msg, sizeof(err_msg),
800 "failed to create socket: %s", strerror(errno));
801 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
802 goto error;
803 }
804
805 memset(&ifr, 0, sizeof(ifr));
806 strncpy(ifr.ifr_name, info->value->name, IF_NAMESIZE);
807 if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
808 snprintf(err_msg, sizeof(err_msg),
809 "failed to get MAC addres of %s: %s",
810 ifa->ifa_name,
811 strerror(errno));
812 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
813 goto error;
814 }
815
816 mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
817
818 if (asprintf(&info->value->hardware_address,
819 "%02x:%02x:%02x:%02x:%02x:%02x",
820 (int) mac_addr[0], (int) mac_addr[1],
821 (int) mac_addr[2], (int) mac_addr[3],
822 (int) mac_addr[4], (int) mac_addr[5]) == -1) {
823 snprintf(err_msg, sizeof(err_msg),
824 "failed to format MAC: %s", strerror(errno));
825 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
826 goto error;
827 }
828
829 info->value->has_hardware_address = true;
830 close(sock);
831 }
832
833 if (ifa->ifa_addr &&
834 ifa->ifa_addr->sa_family == AF_INET) {
835 /* interface with IPv4 address */
836 address_item = g_malloc0(sizeof(*address_item));
837 address_item->value = g_malloc0(sizeof(*address_item->value));
838 p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
839 if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
840 snprintf(err_msg, sizeof(err_msg),
841 "inet_ntop failed : %s", strerror(errno));
842 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
843 goto error;
844 }
845
846 address_item->value->ip_address = g_strdup(addr4);
847 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
848
849 if (ifa->ifa_netmask) {
850 /* Count the number of set bits in netmask.
851 * This is safe as '1' and '0' cannot be shuffled in netmask. */
852 p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
853 address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
854 }
855 } else if (ifa->ifa_addr &&
856 ifa->ifa_addr->sa_family == AF_INET6) {
857 /* interface with IPv6 address */
858 address_item = g_malloc0(sizeof(*address_item));
859 address_item->value = g_malloc0(sizeof(*address_item->value));
860 p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
861 if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
862 snprintf(err_msg, sizeof(err_msg),
863 "inet_ntop failed : %s", strerror(errno));
864 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
865 goto error;
866 }
867
868 address_item->value->ip_address = g_strdup(addr6);
869 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
870
871 if (ifa->ifa_netmask) {
872 /* Count the number of set bits in netmask.
873 * This is safe as '1' and '0' cannot be shuffled in netmask. */
874 p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
875 address_item->value->prefix =
876 ctpop32(((uint32_t *) p)[0]) +
877 ctpop32(((uint32_t *) p)[1]) +
878 ctpop32(((uint32_t *) p)[2]) +
879 ctpop32(((uint32_t *) p)[3]);
880 }
881 }
882
883 if (!address_item) {
884 continue;
885 }
886
887 address_list = &info->value->ip_addresses;
888
889 while (*address_list && (*address_list)->next) {
890 address_list = &(*address_list)->next;
891 }
892
893 if (!*address_list) {
894 *address_list = address_item;
895 } else {
896 (*address_list)->next = address_item;
897 }
898
899 info->value->has_ip_addresses = true;
900
901
902 }
903
904 freeifaddrs(ifap);
905 return head;
906
907 error:
908 freeifaddrs(ifap);
909 qapi_free_GuestNetworkInterfaceList(head);
910 return NULL;
911 }
912
913 #else /* defined(__linux__) */
914
915 void qmp_guest_suspend_disk(Error **err)
916 {
917 error_set(err, QERR_UNSUPPORTED);
918 }
919
920 void qmp_guest_suspend_ram(Error **err)
921 {
922 error_set(err, QERR_UNSUPPORTED);
923 }
924
925 void qmp_guest_suspend_hybrid(Error **err)
926 {
927 error_set(err, QERR_UNSUPPORTED);
928 }
929
930 GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
931 {
932 error_set(errp, QERR_UNSUPPORTED);
933 return NULL;
934 }
935
936 #endif
937
938 #if !defined(CONFIG_FSFREEZE)
939
940 GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
941 {
942 error_set(err, QERR_UNSUPPORTED);
943
944 return 0;
945 }
946
947 int64_t qmp_guest_fsfreeze_freeze(Error **err)
948 {
949 error_set(err, QERR_UNSUPPORTED);
950
951 return 0;
952 }
953
954 int64_t qmp_guest_fsfreeze_thaw(Error **err)
955 {
956 error_set(err, QERR_UNSUPPORTED);
957
958 return 0;
959 }
960
961 #endif
962
963 /* register init/cleanup routines for stateful command groups */
964 void ga_command_state_init(GAState *s, GACommandState *cs)
965 {
966 #if defined(CONFIG_FSFREEZE)
967 ga_command_state_add(cs, guest_fsfreeze_init, guest_fsfreeze_cleanup);
968 #endif
969 ga_command_state_add(cs, guest_file_init, NULL);
970 }