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