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