]> Git Repo - 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      <[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 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 }
This page took 0.074907 seconds and 4 git commands to generate.