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