]> Git Repo - qemu.git/blob - qga/commands-posix.c
Merge remote-tracking branch 'spice/spice.v55' into staging
[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      <[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 "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 typedef struct GuestFsfreezeMount {
320     char *dirname;
321     char *devtype;
322     QTAILQ_ENTRY(GuestFsfreezeMount) next;
323 } GuestFsfreezeMount;
324
325 typedef QTAILQ_HEAD(, GuestFsfreezeMount) GuestFsfreezeMountList;
326
327 static void guest_fsfreeze_free_mount_list(GuestFsfreezeMountList *mounts)
328 {
329      GuestFsfreezeMount *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 guest_fsfreeze_build_mount_list(GuestFsfreezeMountList *mounts)
347 {
348     struct mntent *ment;
349     GuestFsfreezeMount *mount;
350     char const *mtab = MOUNTED;
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(GuestFsfreezeMount));
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
384 /*
385  * Return status of freeze/thaw
386  */
387 GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
388 {
389     if (ga_is_frozen(ga_state)) {
390         return GUEST_FSFREEZE_STATUS_FROZEN;
391     }
392
393     return GUEST_FSFREEZE_STATUS_THAWED;
394 }
395
396 /*
397  * Walk list of mounted file systems in the guest, and freeze the ones which
398  * are real local file systems.
399  */
400 int64_t qmp_guest_fsfreeze_freeze(Error **err)
401 {
402     int ret = 0, i = 0;
403     GuestFsfreezeMountList mounts;
404     struct GuestFsfreezeMount *mount;
405     int fd;
406     char err_msg[512];
407
408     slog("guest-fsfreeze called");
409
410     QTAILQ_INIT(&mounts);
411     ret = guest_fsfreeze_build_mount_list(&mounts);
412     if (ret < 0) {
413         return ret;
414     }
415
416     /* cannot risk guest agent blocking itself on a write in this state */
417     ga_set_frozen(ga_state);
418
419     QTAILQ_FOREACH(mount, &mounts, next) {
420         fd = qemu_open(mount->dirname, O_RDONLY);
421         if (fd == -1) {
422             sprintf(err_msg, "failed to open %s, %s", mount->dirname,
423                     strerror(errno));
424             error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
425             goto error;
426         }
427
428         /* we try to cull filesytems we know won't work in advance, but other
429          * filesytems may not implement fsfreeze for less obvious reasons.
430          * these will report EOPNOTSUPP. we simply ignore these when tallying
431          * the number of frozen filesystems.
432          *
433          * any other error means a failure to freeze a filesystem we
434          * expect to be freezable, so return an error in those cases
435          * and return system to thawed state.
436          */
437         ret = ioctl(fd, FIFREEZE);
438         if (ret == -1) {
439             if (errno != EOPNOTSUPP) {
440                 sprintf(err_msg, "failed to freeze %s, %s",
441                         mount->dirname, strerror(errno));
442                 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
443                 close(fd);
444                 goto error;
445             }
446         } else {
447             i++;
448         }
449         close(fd);
450     }
451
452     guest_fsfreeze_free_mount_list(&mounts);
453     return i;
454
455 error:
456     guest_fsfreeze_free_mount_list(&mounts);
457     qmp_guest_fsfreeze_thaw(NULL);
458     return 0;
459 }
460
461 /*
462  * Walk list of frozen file systems in the guest, and thaw them.
463  */
464 int64_t qmp_guest_fsfreeze_thaw(Error **err)
465 {
466     int ret;
467     GuestFsfreezeMountList mounts;
468     GuestFsfreezeMount *mount;
469     int fd, i = 0, logged;
470
471     QTAILQ_INIT(&mounts);
472     ret = guest_fsfreeze_build_mount_list(&mounts);
473     if (ret) {
474         error_set(err, QERR_QGA_COMMAND_FAILED,
475                   "failed to enumerate filesystems");
476         return 0;
477     }
478
479     QTAILQ_FOREACH(mount, &mounts, next) {
480         logged = false;
481         fd = qemu_open(mount->dirname, O_RDONLY);
482         if (fd == -1) {
483             continue;
484         }
485         /* we have no way of knowing whether a filesystem was actually unfrozen
486          * as a result of a successful call to FITHAW, only that if an error
487          * was returned the filesystem was *not* unfrozen by that particular
488          * call.
489          *
490          * since multiple preceding FIFREEZEs require multiple calls to FITHAW
491          * to unfreeze, continuing issuing FITHAW until an error is returned,
492          * in which case either the filesystem is in an unfreezable state, or,
493          * more likely, it was thawed previously (and remains so afterward).
494          *
495          * also, since the most recent successful call is the one that did
496          * the actual unfreeze, we can use this to provide an accurate count
497          * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which
498          * may * be useful for determining whether a filesystem was unfrozen
499          * during the freeze/thaw phase by a process other than qemu-ga.
500          */
501         do {
502             ret = ioctl(fd, FITHAW);
503             if (ret == 0 && !logged) {
504                 i++;
505                 logged = true;
506             }
507         } while (ret == 0);
508         close(fd);
509     }
510
511     ga_unset_frozen(ga_state);
512     guest_fsfreeze_free_mount_list(&mounts);
513     return i;
514 }
515
516 static void guest_fsfreeze_cleanup(void)
517 {
518     int64_t ret;
519     Error *err = NULL;
520
521     if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
522         ret = qmp_guest_fsfreeze_thaw(&err);
523         if (ret < 0 || err) {
524             slog("failed to clean up frozen filesystems");
525         }
526     }
527 }
528 #endif /* CONFIG_FSFREEZE */
529
530 #define LINUX_SYS_STATE_FILE "/sys/power/state"
531 #define SUSPEND_SUPPORTED 0
532 #define SUSPEND_NOT_SUPPORTED 1
533
534 /**
535  * This function forks twice and the information about the mode support
536  * status is passed to the qemu-ga process via a pipe.
537  *
538  * This approach allows us to keep the way we reap terminated children
539  * in qemu-ga quite simple.
540  */
541 static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
542                                const char *sysfile_str, Error **err)
543 {
544     pid_t pid;
545     ssize_t ret;
546     char *pmutils_path;
547     int status, pipefds[2];
548
549     if (pipe(pipefds) < 0) {
550         error_set(err, QERR_UNDEFINED_ERROR);
551         return;
552     }
553
554     pmutils_path = g_find_program_in_path(pmutils_bin);
555
556     pid = fork();
557     if (!pid) {
558         struct sigaction act;
559
560         memset(&act, 0, sizeof(act));
561         act.sa_handler = SIG_DFL;
562         sigaction(SIGCHLD, &act, NULL);
563
564         setsid();
565         close(pipefds[0]);
566         reopen_fd_to_null(0);
567         reopen_fd_to_null(1);
568         reopen_fd_to_null(2);
569
570         pid = fork();
571         if (!pid) {
572             int fd;
573             char buf[32]; /* hopefully big enough */
574
575             if (pmutils_path) {
576                 execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
577             }
578
579             /*
580              * If we get here either pm-utils is not installed or execle() has
581              * failed. Let's try the manual method if the caller wants it.
582              */
583
584             if (!sysfile_str) {
585                 _exit(SUSPEND_NOT_SUPPORTED);
586             }
587
588             fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
589             if (fd < 0) {
590                 _exit(SUSPEND_NOT_SUPPORTED);
591             }
592
593             ret = read(fd, buf, sizeof(buf)-1);
594             if (ret <= 0) {
595                 _exit(SUSPEND_NOT_SUPPORTED);
596             }
597             buf[ret] = '\0';
598
599             if (strstr(buf, sysfile_str)) {
600                 _exit(SUSPEND_SUPPORTED);
601             }
602
603             _exit(SUSPEND_NOT_SUPPORTED);
604         }
605
606         if (pid > 0) {
607             wait(&status);
608         } else {
609             status = SUSPEND_NOT_SUPPORTED;
610         }
611
612         ret = write(pipefds[1], &status, sizeof(status));
613         if (ret != sizeof(status)) {
614             _exit(EXIT_FAILURE);
615         }
616
617         _exit(EXIT_SUCCESS);
618     }
619
620     close(pipefds[1]);
621     g_free(pmutils_path);
622
623     if (pid < 0) {
624         error_set(err, QERR_UNDEFINED_ERROR);
625         goto out;
626     }
627
628     ret = read(pipefds[0], &status, sizeof(status));
629     if (ret == sizeof(status) && WIFEXITED(status) &&
630         WEXITSTATUS(status) == SUSPEND_SUPPORTED) {
631             goto out;
632     }
633
634     error_set(err, QERR_UNSUPPORTED);
635
636 out:
637     close(pipefds[0]);
638 }
639
640 static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
641                           Error **err)
642 {
643     pid_t pid;
644     char *pmutils_path;
645
646     pmutils_path = g_find_program_in_path(pmutils_bin);
647
648     pid = fork();
649     if (pid == 0) {
650         /* child */
651         int fd;
652
653         setsid();
654         reopen_fd_to_null(0);
655         reopen_fd_to_null(1);
656         reopen_fd_to_null(2);
657
658         if (pmutils_path) {
659             execle(pmutils_path, pmutils_bin, NULL, environ);
660         }
661
662         /*
663          * If we get here either pm-utils is not installed or execle() has
664          * failed. Let's try the manual method if the caller wants it.
665          */
666
667         if (!sysfile_str) {
668             _exit(EXIT_FAILURE);
669         }
670
671         fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
672         if (fd < 0) {
673             _exit(EXIT_FAILURE);
674         }
675
676         if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
677             _exit(EXIT_FAILURE);
678         }
679
680         _exit(EXIT_SUCCESS);
681     }
682
683     g_free(pmutils_path);
684
685     if (pid < 0) {
686         error_set(err, QERR_UNDEFINED_ERROR);
687         return;
688     }
689 }
690
691 void qmp_guest_suspend_disk(Error **err)
692 {
693     bios_supports_mode("pm-is-supported", "--hibernate", "disk", err);
694     if (error_is_set(err)) {
695         return;
696     }
697
698     guest_suspend("pm-hibernate", "disk", err);
699 }
700
701 void qmp_guest_suspend_ram(Error **err)
702 {
703     bios_supports_mode("pm-is-supported", "--suspend", "mem", err);
704     if (error_is_set(err)) {
705         return;
706     }
707
708     guest_suspend("pm-suspend", "mem", err);
709 }
710
711 void qmp_guest_suspend_hybrid(Error **err)
712 {
713     bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err);
714     if (error_is_set(err)) {
715         return;
716     }
717
718     guest_suspend("pm-suspend-hybrid", NULL, err);
719 }
720
721 static GuestNetworkInterfaceList *
722 guest_find_interface(GuestNetworkInterfaceList *head,
723                      const char *name)
724 {
725     for (; head; head = head->next) {
726         if (strcmp(head->value->name, name) == 0) {
727             break;
728         }
729     }
730
731     return head;
732 }
733
734 /*
735  * Build information about guest interfaces
736  */
737 GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
738 {
739     GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
740     struct ifaddrs *ifap, *ifa;
741     char err_msg[512];
742
743     if (getifaddrs(&ifap) < 0) {
744         snprintf(err_msg, sizeof(err_msg),
745                  "getifaddrs failed: %s", strerror(errno));
746         error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
747         goto error;
748     }
749
750     for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
751         GuestNetworkInterfaceList *info;
752         GuestIpAddressList **address_list = NULL, *address_item = NULL;
753         char addr4[INET_ADDRSTRLEN];
754         char addr6[INET6_ADDRSTRLEN];
755         int sock;
756         struct ifreq ifr;
757         unsigned char *mac_addr;
758         void *p;
759
760         g_debug("Processing %s interface", ifa->ifa_name);
761
762         info = guest_find_interface(head, ifa->ifa_name);
763
764         if (!info) {
765             info = g_malloc0(sizeof(*info));
766             info->value = g_malloc0(sizeof(*info->value));
767             info->value->name = g_strdup(ifa->ifa_name);
768
769             if (!cur_item) {
770                 head = cur_item = info;
771             } else {
772                 cur_item->next = info;
773                 cur_item = info;
774             }
775         }
776
777         if (!info->value->has_hardware_address &&
778             ifa->ifa_flags & SIOCGIFHWADDR) {
779             /* we haven't obtained HW address yet */
780             sock = socket(PF_INET, SOCK_STREAM, 0);
781             if (sock == -1) {
782                 snprintf(err_msg, sizeof(err_msg),
783                          "failed to create socket: %s", strerror(errno));
784                 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
785                 goto error;
786             }
787
788             memset(&ifr, 0, sizeof(ifr));
789             strncpy(ifr.ifr_name,  info->value->name, IF_NAMESIZE);
790             if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
791                 snprintf(err_msg, sizeof(err_msg),
792                          "failed to get MAC address of %s: %s",
793                          ifa->ifa_name,
794                          strerror(errno));
795                 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
796                 goto error;
797             }
798
799             mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
800
801             if (asprintf(&info->value->hardware_address,
802                          "%02x:%02x:%02x:%02x:%02x:%02x",
803                          (int) mac_addr[0], (int) mac_addr[1],
804                          (int) mac_addr[2], (int) mac_addr[3],
805                          (int) mac_addr[4], (int) mac_addr[5]) == -1) {
806                 snprintf(err_msg, sizeof(err_msg),
807                          "failed to format MAC: %s", strerror(errno));
808                 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
809                 goto error;
810             }
811
812             info->value->has_hardware_address = true;
813             close(sock);
814         }
815
816         if (ifa->ifa_addr &&
817             ifa->ifa_addr->sa_family == AF_INET) {
818             /* interface with IPv4 address */
819             address_item = g_malloc0(sizeof(*address_item));
820             address_item->value = g_malloc0(sizeof(*address_item->value));
821             p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
822             if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
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(addr4);
830             address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
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_in *)ifa->ifa_netmask)->sin_addr;
836                 address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
837             }
838         } else if (ifa->ifa_addr &&
839                    ifa->ifa_addr->sa_family == AF_INET6) {
840             /* interface with IPv6 address */
841             address_item = g_malloc0(sizeof(*address_item));
842             address_item->value = g_malloc0(sizeof(*address_item->value));
843             p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
844             if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
845                 snprintf(err_msg, sizeof(err_msg),
846                          "inet_ntop failed : %s", strerror(errno));
847                 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
848                 goto error;
849             }
850
851             address_item->value->ip_address = g_strdup(addr6);
852             address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
853
854             if (ifa->ifa_netmask) {
855                 /* Count the number of set bits in netmask.
856                  * This is safe as '1' and '0' cannot be shuffled in netmask. */
857                 p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
858                 address_item->value->prefix =
859                     ctpop32(((uint32_t *) p)[0]) +
860                     ctpop32(((uint32_t *) p)[1]) +
861                     ctpop32(((uint32_t *) p)[2]) +
862                     ctpop32(((uint32_t *) p)[3]);
863             }
864         }
865
866         if (!address_item) {
867             continue;
868         }
869
870         address_list = &info->value->ip_addresses;
871
872         while (*address_list && (*address_list)->next) {
873             address_list = &(*address_list)->next;
874         }
875
876         if (!*address_list) {
877             *address_list = address_item;
878         } else {
879             (*address_list)->next = address_item;
880         }
881
882         info->value->has_ip_addresses = true;
883
884
885     }
886
887     freeifaddrs(ifap);
888     return head;
889
890 error:
891     freeifaddrs(ifap);
892     qapi_free_GuestNetworkInterfaceList(head);
893     return NULL;
894 }
895
896 #else /* defined(__linux__) */
897
898 void qmp_guest_suspend_disk(Error **err)
899 {
900     error_set(err, QERR_UNSUPPORTED);
901 }
902
903 void qmp_guest_suspend_ram(Error **err)
904 {
905     error_set(err, QERR_UNSUPPORTED);
906 }
907
908 void qmp_guest_suspend_hybrid(Error **err)
909 {
910     error_set(err, QERR_UNSUPPORTED);
911 }
912
913 GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
914 {
915     error_set(errp, QERR_UNSUPPORTED);
916     return NULL;
917 }
918
919 #endif
920
921 #if !defined(CONFIG_FSFREEZE)
922
923 GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
924 {
925     error_set(err, QERR_UNSUPPORTED);
926
927     return 0;
928 }
929
930 int64_t qmp_guest_fsfreeze_freeze(Error **err)
931 {
932     error_set(err, QERR_UNSUPPORTED);
933
934     return 0;
935 }
936
937 int64_t qmp_guest_fsfreeze_thaw(Error **err)
938 {
939     error_set(err, QERR_UNSUPPORTED);
940
941     return 0;
942 }
943
944 #endif
945
946 /* register init/cleanup routines for stateful command groups */
947 void ga_command_state_init(GAState *s, GACommandState *cs)
948 {
949 #if defined(CONFIG_FSFREEZE)
950     ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
951 #endif
952     ga_command_state_add(cs, guest_file_init, NULL);
953 }
This page took 0.077398 seconds and 4 git commands to generate.