xref: /openbmc/qemu/qga/commands-posix.c (revision 35d08458)
1 /*
2  * QEMU Guest Agent POSIX-specific command implementations
3  *
4  * Copyright IBM Corp. 2011
5  *
6  * Authors:
7  *  Michael Roth      <mdroth@linux.vnet.ibm.com>
8  *  Michal Privoznik  <mprivozn@redhat.com>
9  *
10  * This work is licensed under the terms of the GNU GPL, version 2 or later.
11  * See the COPYING file in the top-level directory.
12  */
13 
14 #include <glib.h>
15 #include <sys/types.h>
16 #include <sys/ioctl.h>
17 #include <sys/wait.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <sys/stat.h>
24 #include <inttypes.h>
25 #include "qga/guest-agent-core.h"
26 #include "qga-qmp-commands.h"
27 #include "qapi/qmp/qerror.h"
28 #include "qemu/queue.h"
29 #include "qemu/host-utils.h"
30 
31 #ifndef CONFIG_HAS_ENVIRON
32 #ifdef __APPLE__
33 #include <crt_externs.h>
34 #define environ (*_NSGetEnviron())
35 #else
36 extern char **environ;
37 #endif
38 #endif
39 
40 #if defined(__linux__)
41 #include <mntent.h>
42 #include <linux/fs.h>
43 #include <ifaddrs.h>
44 #include <arpa/inet.h>
45 #include <sys/socket.h>
46 #include <net/if.h>
47 
48 #ifdef FIFREEZE
49 #define CONFIG_FSFREEZE
50 #endif
51 #ifdef FITRIM
52 #define CONFIG_FSTRIM
53 #endif
54 #endif
55 
56 static void ga_wait_child(pid_t pid, int *status, Error **errp)
57 {
58     pid_t rpid;
59 
60     *status = 0;
61 
62     do {
63         rpid = waitpid(pid, status, 0);
64     } while (rpid == -1 && errno == EINTR);
65 
66     if (rpid == -1) {
67         error_setg_errno(errp, errno, "failed to wait for child (pid: %d)",
68                          pid);
69         return;
70     }
71 
72     g_assert(rpid == pid);
73 }
74 
75 void qmp_guest_shutdown(bool has_mode, const char *mode, Error **errp)
76 {
77     const char *shutdown_flag;
78     Error *local_err = NULL;
79     pid_t pid;
80     int status;
81 
82     slog("guest-shutdown called, mode: %s", mode);
83     if (!has_mode || strcmp(mode, "powerdown") == 0) {
84         shutdown_flag = "-P";
85     } else if (strcmp(mode, "halt") == 0) {
86         shutdown_flag = "-H";
87     } else if (strcmp(mode, "reboot") == 0) {
88         shutdown_flag = "-r";
89     } else {
90         error_setg(errp,
91                    "mode is invalid (valid values are: halt|powerdown|reboot");
92         return;
93     }
94 
95     pid = fork();
96     if (pid == 0) {
97         /* child, start the shutdown */
98         setsid();
99         reopen_fd_to_null(0);
100         reopen_fd_to_null(1);
101         reopen_fd_to_null(2);
102 
103         execle("/sbin/shutdown", "shutdown", "-h", shutdown_flag, "+0",
104                "hypervisor initiated shutdown", (char*)NULL, environ);
105         _exit(EXIT_FAILURE);
106     } else if (pid < 0) {
107         error_setg_errno(errp, errno, "failed to create child process");
108         return;
109     }
110 
111     ga_wait_child(pid, &status, &local_err);
112     if (local_err) {
113         error_propagate(errp, local_err);
114         return;
115     }
116 
117     if (!WIFEXITED(status)) {
118         error_setg(errp, "child process has terminated abnormally");
119         return;
120     }
121 
122     if (WEXITSTATUS(status)) {
123         error_setg(errp, "child process has failed to shutdown");
124         return;
125     }
126 
127     /* succeeded */
128 }
129 
130 int64_t qmp_guest_get_time(Error **errp)
131 {
132    int ret;
133    qemu_timeval tq;
134    int64_t time_ns;
135 
136    ret = qemu_gettimeofday(&tq);
137    if (ret < 0) {
138        error_setg_errno(errp, errno, "Failed to get time");
139        return -1;
140    }
141 
142    time_ns = tq.tv_sec * 1000000000LL + tq.tv_usec * 1000;
143    return time_ns;
144 }
145 
146 void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
147 {
148     int ret;
149     int status;
150     pid_t pid;
151     Error *local_err = NULL;
152     struct timeval tv;
153 
154     /* If user has passed a time, validate and set it. */
155     if (has_time) {
156         /* year-2038 will overflow in case time_t is 32bit */
157         if (time_ns / 1000000000 != (time_t)(time_ns / 1000000000)) {
158             error_setg(errp, "Time %" PRId64 " is too large", time_ns);
159             return;
160         }
161 
162         tv.tv_sec = time_ns / 1000000000;
163         tv.tv_usec = (time_ns % 1000000000) / 1000;
164 
165         ret = settimeofday(&tv, NULL);
166         if (ret < 0) {
167             error_setg_errno(errp, errno, "Failed to set time to guest");
168             return;
169         }
170     }
171 
172     /* Now, if user has passed a time to set and the system time is set, we
173      * just need to synchronize the hardware clock. However, if no time was
174      * passed, user is requesting the opposite: set the system time from the
175      * hardware clock (RTC). */
176     pid = fork();
177     if (pid == 0) {
178         setsid();
179         reopen_fd_to_null(0);
180         reopen_fd_to_null(1);
181         reopen_fd_to_null(2);
182 
183         /* Use '/sbin/hwclock -w' to set RTC from the system time,
184          * or '/sbin/hwclock -s' to set the system time from RTC. */
185         execle("/sbin/hwclock", "hwclock", has_time ? "-w" : "-s",
186                NULL, environ);
187         _exit(EXIT_FAILURE);
188     } else if (pid < 0) {
189         error_setg_errno(errp, errno, "failed to create child process");
190         return;
191     }
192 
193     ga_wait_child(pid, &status, &local_err);
194     if (local_err) {
195         error_propagate(errp, local_err);
196         return;
197     }
198 
199     if (!WIFEXITED(status)) {
200         error_setg(errp, "child process has terminated abnormally");
201         return;
202     }
203 
204     if (WEXITSTATUS(status)) {
205         error_setg(errp, "hwclock failed to set hardware clock to system time");
206         return;
207     }
208 }
209 
210 typedef struct GuestFileHandle {
211     uint64_t id;
212     FILE *fh;
213     QTAILQ_ENTRY(GuestFileHandle) next;
214 } GuestFileHandle;
215 
216 static struct {
217     QTAILQ_HEAD(, GuestFileHandle) filehandles;
218 } guest_file_state;
219 
220 static int64_t guest_file_handle_add(FILE *fh, Error **errp)
221 {
222     GuestFileHandle *gfh;
223     int64_t handle;
224 
225     handle = ga_get_fd_handle(ga_state, errp);
226     if (handle < 0) {
227         return -1;
228     }
229 
230     gfh = g_malloc0(sizeof(GuestFileHandle));
231     gfh->id = handle;
232     gfh->fh = fh;
233     QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
234 
235     return handle;
236 }
237 
238 static GuestFileHandle *guest_file_handle_find(int64_t id, Error **errp)
239 {
240     GuestFileHandle *gfh;
241 
242     QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
243     {
244         if (gfh->id == id) {
245             return gfh;
246         }
247     }
248 
249     error_setg(errp, "handle '%" PRId64 "' has not been found", id);
250     return NULL;
251 }
252 
253 typedef const char * const ccpc;
254 
255 #ifndef O_BINARY
256 #define O_BINARY 0
257 #endif
258 
259 /* http://pubs.opengroup.org/onlinepubs/9699919799/functions/fopen.html */
260 static const struct {
261     ccpc *forms;
262     int oflag_base;
263 } guest_file_open_modes[] = {
264     { (ccpc[]){ "r",          NULL }, O_RDONLY                                 },
265     { (ccpc[]){ "rb",         NULL }, O_RDONLY                      | O_BINARY },
266     { (ccpc[]){ "w",          NULL }, O_WRONLY | O_CREAT | O_TRUNC             },
267     { (ccpc[]){ "wb",         NULL }, O_WRONLY | O_CREAT | O_TRUNC  | O_BINARY },
268     { (ccpc[]){ "a",          NULL }, O_WRONLY | O_CREAT | O_APPEND            },
269     { (ccpc[]){ "ab",         NULL }, O_WRONLY | O_CREAT | O_APPEND | O_BINARY },
270     { (ccpc[]){ "r+",         NULL }, O_RDWR                                   },
271     { (ccpc[]){ "rb+", "r+b", NULL }, O_RDWR                        | O_BINARY },
272     { (ccpc[]){ "w+",         NULL }, O_RDWR   | O_CREAT | O_TRUNC             },
273     { (ccpc[]){ "wb+", "w+b", NULL }, O_RDWR   | O_CREAT | O_TRUNC  | O_BINARY },
274     { (ccpc[]){ "a+",         NULL }, O_RDWR   | O_CREAT | O_APPEND            },
275     { (ccpc[]){ "ab+", "a+b", NULL }, O_RDWR   | O_CREAT | O_APPEND | O_BINARY }
276 };
277 
278 static int
279 find_open_flag(const char *mode_str, Error **errp)
280 {
281     unsigned mode;
282 
283     for (mode = 0; mode < ARRAY_SIZE(guest_file_open_modes); ++mode) {
284         ccpc *form;
285 
286         form = guest_file_open_modes[mode].forms;
287         while (*form != NULL && strcmp(*form, mode_str) != 0) {
288             ++form;
289         }
290         if (*form != NULL) {
291             break;
292         }
293     }
294 
295     if (mode == ARRAY_SIZE(guest_file_open_modes)) {
296         error_setg(errp, "invalid file open mode '%s'", mode_str);
297         return -1;
298     }
299     return guest_file_open_modes[mode].oflag_base | O_NOCTTY | O_NONBLOCK;
300 }
301 
302 #define DEFAULT_NEW_FILE_MODE (S_IRUSR | S_IWUSR | \
303                                S_IRGRP | S_IWGRP | \
304                                S_IROTH | S_IWOTH)
305 
306 static FILE *
307 safe_open_or_create(const char *path, const char *mode, Error **errp)
308 {
309     Error *local_err = NULL;
310     int oflag;
311 
312     oflag = find_open_flag(mode, &local_err);
313     if (local_err == NULL) {
314         int fd;
315 
316         /* If the caller wants / allows creation of a new file, we implement it
317          * with a two step process: open() + (open() / fchmod()).
318          *
319          * First we insist on creating the file exclusively as a new file. If
320          * that succeeds, we're free to set any file-mode bits on it. (The
321          * motivation is that we want to set those file-mode bits independently
322          * of the current umask.)
323          *
324          * If the exclusive creation fails because the file already exists
325          * (EEXIST is not possible for any other reason), we just attempt to
326          * open the file, but in this case we won't be allowed to change the
327          * file-mode bits on the preexistent file.
328          *
329          * The pathname should never disappear between the two open()s in
330          * practice. If it happens, then someone very likely tried to race us.
331          * In this case just go ahead and report the ENOENT from the second
332          * open() to the caller.
333          *
334          * If the caller wants to open a preexistent file, then the first
335          * open() is decisive and its third argument is ignored, and the second
336          * open() and the fchmod() are never called.
337          */
338         fd = open(path, oflag | ((oflag & O_CREAT) ? O_EXCL : 0), 0);
339         if (fd == -1 && errno == EEXIST) {
340             oflag &= ~(unsigned)O_CREAT;
341             fd = open(path, oflag);
342         }
343 
344         if (fd == -1) {
345             error_setg_errno(&local_err, errno, "failed to open file '%s' "
346                              "(mode: '%s')", path, mode);
347         } else {
348             qemu_set_cloexec(fd);
349 
350             if ((oflag & O_CREAT) && fchmod(fd, DEFAULT_NEW_FILE_MODE) == -1) {
351                 error_setg_errno(&local_err, errno, "failed to set permission "
352                                  "0%03o on new file '%s' (mode: '%s')",
353                                  (unsigned)DEFAULT_NEW_FILE_MODE, path, mode);
354             } else {
355                 FILE *f;
356 
357                 f = fdopen(fd, mode);
358                 if (f == NULL) {
359                     error_setg_errno(&local_err, errno, "failed to associate "
360                                      "stdio stream with file descriptor %d, "
361                                      "file '%s' (mode: '%s')", fd, path, mode);
362                 } else {
363                     return f;
364                 }
365             }
366 
367             close(fd);
368             if (oflag & O_CREAT) {
369                 unlink(path);
370             }
371         }
372     }
373 
374     error_propagate(errp, local_err);
375     return NULL;
376 }
377 
378 int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode,
379                             Error **errp)
380 {
381     FILE *fh;
382     Error *local_err = NULL;
383     int fd;
384     int64_t ret = -1, handle;
385 
386     if (!has_mode) {
387         mode = "r";
388     }
389     slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
390     fh = safe_open_or_create(path, mode, &local_err);
391     if (local_err != NULL) {
392         error_propagate(errp, local_err);
393         return -1;
394     }
395 
396     /* set fd non-blocking to avoid common use cases (like reading from a
397      * named pipe) from hanging the agent
398      */
399     fd = fileno(fh);
400     ret = fcntl(fd, F_GETFL);
401     ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
402     if (ret == -1) {
403         error_setg_errno(errp, errno, "failed to make file '%s' non-blocking",
404                          path);
405         fclose(fh);
406         return -1;
407     }
408 
409     handle = guest_file_handle_add(fh, errp);
410     if (handle < 0) {
411         fclose(fh);
412         return -1;
413     }
414 
415     slog("guest-file-open, handle: %" PRId64, handle);
416     return handle;
417 }
418 
419 void qmp_guest_file_close(int64_t handle, Error **errp)
420 {
421     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
422     int ret;
423 
424     slog("guest-file-close called, handle: %" PRId64, handle);
425     if (!gfh) {
426         return;
427     }
428 
429     ret = fclose(gfh->fh);
430     if (ret == EOF) {
431         error_setg_errno(errp, errno, "failed to close handle");
432         return;
433     }
434 
435     QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
436     g_free(gfh);
437 }
438 
439 struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
440                                           int64_t count, Error **errp)
441 {
442     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
443     GuestFileRead *read_data = NULL;
444     guchar *buf;
445     FILE *fh;
446     size_t read_count;
447 
448     if (!gfh) {
449         return NULL;
450     }
451 
452     if (!has_count) {
453         count = QGA_READ_COUNT_DEFAULT;
454     } else if (count < 0) {
455         error_setg(errp, "value '%" PRId64 "' is invalid for argument count",
456                    count);
457         return NULL;
458     }
459 
460     fh = gfh->fh;
461     buf = g_malloc0(count+1);
462     read_count = fread(buf, 1, count, fh);
463     if (ferror(fh)) {
464         error_setg_errno(errp, errno, "failed to read file");
465         slog("guest-file-read failed, handle: %" PRId64, handle);
466     } else {
467         buf[read_count] = 0;
468         read_data = g_malloc0(sizeof(GuestFileRead));
469         read_data->count = read_count;
470         read_data->eof = feof(fh);
471         if (read_count) {
472             read_data->buf_b64 = g_base64_encode(buf, read_count);
473         }
474     }
475     g_free(buf);
476     clearerr(fh);
477 
478     return read_data;
479 }
480 
481 GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
482                                      bool has_count, int64_t count,
483                                      Error **errp)
484 {
485     GuestFileWrite *write_data = NULL;
486     guchar *buf;
487     gsize buf_len;
488     int write_count;
489     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
490     FILE *fh;
491 
492     if (!gfh) {
493         return NULL;
494     }
495 
496     fh = gfh->fh;
497     buf = g_base64_decode(buf_b64, &buf_len);
498 
499     if (!has_count) {
500         count = buf_len;
501     } else if (count < 0 || count > buf_len) {
502         error_setg(errp, "value '%" PRId64 "' is invalid for argument count",
503                    count);
504         g_free(buf);
505         return NULL;
506     }
507 
508     write_count = fwrite(buf, 1, count, fh);
509     if (ferror(fh)) {
510         error_setg_errno(errp, errno, "failed to write to file");
511         slog("guest-file-write failed, handle: %" PRId64, handle);
512     } else {
513         write_data = g_malloc0(sizeof(GuestFileWrite));
514         write_data->count = write_count;
515         write_data->eof = feof(fh);
516     }
517     g_free(buf);
518     clearerr(fh);
519 
520     return write_data;
521 }
522 
523 struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
524                                           int64_t whence, Error **errp)
525 {
526     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
527     GuestFileSeek *seek_data = NULL;
528     FILE *fh;
529     int ret;
530 
531     if (!gfh) {
532         return NULL;
533     }
534 
535     fh = gfh->fh;
536     ret = fseek(fh, offset, whence);
537     if (ret == -1) {
538         error_setg_errno(errp, errno, "failed to seek file");
539     } else {
540         seek_data = g_new0(GuestFileSeek, 1);
541         seek_data->position = ftell(fh);
542         seek_data->eof = feof(fh);
543     }
544     clearerr(fh);
545 
546     return seek_data;
547 }
548 
549 void qmp_guest_file_flush(int64_t handle, Error **errp)
550 {
551     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
552     FILE *fh;
553     int ret;
554 
555     if (!gfh) {
556         return;
557     }
558 
559     fh = gfh->fh;
560     ret = fflush(fh);
561     if (ret == EOF) {
562         error_setg_errno(errp, errno, "failed to flush file");
563     }
564 }
565 
566 static void guest_file_init(void)
567 {
568     QTAILQ_INIT(&guest_file_state.filehandles);
569 }
570 
571 /* linux-specific implementations. avoid this if at all possible. */
572 #if defined(__linux__)
573 
574 #if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
575 typedef struct FsMount {
576     char *dirname;
577     char *devtype;
578     QTAILQ_ENTRY(FsMount) next;
579 } FsMount;
580 
581 typedef QTAILQ_HEAD(FsMountList, FsMount) FsMountList;
582 
583 static void free_fs_mount_list(FsMountList *mounts)
584 {
585      FsMount *mount, *temp;
586 
587      if (!mounts) {
588          return;
589      }
590 
591      QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) {
592          QTAILQ_REMOVE(mounts, mount, next);
593          g_free(mount->dirname);
594          g_free(mount->devtype);
595          g_free(mount);
596      }
597 }
598 
599 /*
600  * Walk the mount table and build a list of local file systems
601  */
602 static void build_fs_mount_list(FsMountList *mounts, Error **errp)
603 {
604     struct mntent *ment;
605     FsMount *mount;
606     char const *mtab = "/proc/self/mounts";
607     FILE *fp;
608 
609     fp = setmntent(mtab, "r");
610     if (!fp) {
611         error_setg(errp, "failed to open mtab file: '%s'", mtab);
612         return;
613     }
614 
615     while ((ment = getmntent(fp))) {
616         /*
617          * An entry which device name doesn't start with a '/' is
618          * either a dummy file system or a network file system.
619          * Add special handling for smbfs and cifs as is done by
620          * coreutils as well.
621          */
622         if ((ment->mnt_fsname[0] != '/') ||
623             (strcmp(ment->mnt_type, "smbfs") == 0) ||
624             (strcmp(ment->mnt_type, "cifs") == 0)) {
625             continue;
626         }
627 
628         mount = g_malloc0(sizeof(FsMount));
629         mount->dirname = g_strdup(ment->mnt_dir);
630         mount->devtype = g_strdup(ment->mnt_type);
631 
632         QTAILQ_INSERT_TAIL(mounts, mount, next);
633     }
634 
635     endmntent(fp);
636 }
637 #endif
638 
639 #if defined(CONFIG_FSFREEZE)
640 
641 typedef enum {
642     FSFREEZE_HOOK_THAW = 0,
643     FSFREEZE_HOOK_FREEZE,
644 } FsfreezeHookArg;
645 
646 const char *fsfreeze_hook_arg_string[] = {
647     "thaw",
648     "freeze",
649 };
650 
651 static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **errp)
652 {
653     int status;
654     pid_t pid;
655     const char *hook;
656     const char *arg_str = fsfreeze_hook_arg_string[arg];
657     Error *local_err = NULL;
658 
659     hook = ga_fsfreeze_hook(ga_state);
660     if (!hook) {
661         return;
662     }
663     if (access(hook, X_OK) != 0) {
664         error_setg_errno(errp, errno, "can't access fsfreeze hook '%s'", hook);
665         return;
666     }
667 
668     slog("executing fsfreeze hook with arg '%s'", arg_str);
669     pid = fork();
670     if (pid == 0) {
671         setsid();
672         reopen_fd_to_null(0);
673         reopen_fd_to_null(1);
674         reopen_fd_to_null(2);
675 
676         execle(hook, hook, arg_str, NULL, environ);
677         _exit(EXIT_FAILURE);
678     } else if (pid < 0) {
679         error_setg_errno(errp, errno, "failed to create child process");
680         return;
681     }
682 
683     ga_wait_child(pid, &status, &local_err);
684     if (local_err) {
685         error_propagate(errp, local_err);
686         return;
687     }
688 
689     if (!WIFEXITED(status)) {
690         error_setg(errp, "fsfreeze hook has terminated abnormally");
691         return;
692     }
693 
694     status = WEXITSTATUS(status);
695     if (status) {
696         error_setg(errp, "fsfreeze hook has failed with status %d", status);
697         return;
698     }
699 }
700 
701 /*
702  * Return status of freeze/thaw
703  */
704 GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
705 {
706     if (ga_is_frozen(ga_state)) {
707         return GUEST_FSFREEZE_STATUS_FROZEN;
708     }
709 
710     return GUEST_FSFREEZE_STATUS_THAWED;
711 }
712 
713 /*
714  * Walk list of mounted file systems in the guest, and freeze the ones which
715  * are real local file systems.
716  */
717 int64_t qmp_guest_fsfreeze_freeze(Error **errp)
718 {
719     int ret = 0, i = 0;
720     FsMountList mounts;
721     struct FsMount *mount;
722     Error *local_err = NULL;
723     int fd;
724 
725     slog("guest-fsfreeze called");
726 
727     execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err);
728     if (local_err) {
729         error_propagate(errp, local_err);
730         return -1;
731     }
732 
733     QTAILQ_INIT(&mounts);
734     build_fs_mount_list(&mounts, &local_err);
735     if (local_err) {
736         error_propagate(errp, local_err);
737         return -1;
738     }
739 
740     /* cannot risk guest agent blocking itself on a write in this state */
741     ga_set_frozen(ga_state);
742 
743     QTAILQ_FOREACH_REVERSE(mount, &mounts, FsMountList, next) {
744         fd = qemu_open(mount->dirname, O_RDONLY);
745         if (fd == -1) {
746             error_setg_errno(errp, errno, "failed to open %s", mount->dirname);
747             goto error;
748         }
749 
750         /* we try to cull filesytems we know won't work in advance, but other
751          * filesytems may not implement fsfreeze for less obvious reasons.
752          * these will report EOPNOTSUPP. we simply ignore these when tallying
753          * the number of frozen filesystems.
754          *
755          * any other error means a failure to freeze a filesystem we
756          * expect to be freezable, so return an error in those cases
757          * and return system to thawed state.
758          */
759         ret = ioctl(fd, FIFREEZE);
760         if (ret == -1) {
761             if (errno != EOPNOTSUPP) {
762                 error_setg_errno(errp, errno, "failed to freeze %s",
763                                  mount->dirname);
764                 close(fd);
765                 goto error;
766             }
767         } else {
768             i++;
769         }
770         close(fd);
771     }
772 
773     free_fs_mount_list(&mounts);
774     return i;
775 
776 error:
777     free_fs_mount_list(&mounts);
778     qmp_guest_fsfreeze_thaw(NULL);
779     return 0;
780 }
781 
782 /*
783  * Walk list of frozen file systems in the guest, and thaw them.
784  */
785 int64_t qmp_guest_fsfreeze_thaw(Error **errp)
786 {
787     int ret;
788     FsMountList mounts;
789     FsMount *mount;
790     int fd, i = 0, logged;
791     Error *local_err = NULL;
792 
793     QTAILQ_INIT(&mounts);
794     build_fs_mount_list(&mounts, &local_err);
795     if (local_err) {
796         error_propagate(errp, local_err);
797         return 0;
798     }
799 
800     QTAILQ_FOREACH(mount, &mounts, next) {
801         logged = false;
802         fd = qemu_open(mount->dirname, O_RDONLY);
803         if (fd == -1) {
804             continue;
805         }
806         /* we have no way of knowing whether a filesystem was actually unfrozen
807          * as a result of a successful call to FITHAW, only that if an error
808          * was returned the filesystem was *not* unfrozen by that particular
809          * call.
810          *
811          * since multiple preceding FIFREEZEs require multiple calls to FITHAW
812          * to unfreeze, continuing issuing FITHAW until an error is returned,
813          * in which case either the filesystem is in an unfreezable state, or,
814          * more likely, it was thawed previously (and remains so afterward).
815          *
816          * also, since the most recent successful call is the one that did
817          * the actual unfreeze, we can use this to provide an accurate count
818          * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which
819          * may * be useful for determining whether a filesystem was unfrozen
820          * during the freeze/thaw phase by a process other than qemu-ga.
821          */
822         do {
823             ret = ioctl(fd, FITHAW);
824             if (ret == 0 && !logged) {
825                 i++;
826                 logged = true;
827             }
828         } while (ret == 0);
829         close(fd);
830     }
831 
832     ga_unset_frozen(ga_state);
833     free_fs_mount_list(&mounts);
834 
835     execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, errp);
836 
837     return i;
838 }
839 
840 static void guest_fsfreeze_cleanup(void)
841 {
842     Error *err = NULL;
843 
844     if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
845         qmp_guest_fsfreeze_thaw(&err);
846         if (err) {
847             slog("failed to clean up frozen filesystems: %s",
848                  error_get_pretty(err));
849             error_free(err);
850         }
851     }
852 }
853 #endif /* CONFIG_FSFREEZE */
854 
855 #if defined(CONFIG_FSTRIM)
856 /*
857  * Walk list of mounted file systems in the guest, and trim them.
858  */
859 void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
860 {
861     int ret = 0;
862     FsMountList mounts;
863     struct FsMount *mount;
864     int fd;
865     Error *local_err = NULL;
866     struct fstrim_range r = {
867         .start = 0,
868         .len = -1,
869         .minlen = has_minimum ? minimum : 0,
870     };
871 
872     slog("guest-fstrim called");
873 
874     QTAILQ_INIT(&mounts);
875     build_fs_mount_list(&mounts, &local_err);
876     if (local_err) {
877         error_propagate(errp, local_err);
878         return;
879     }
880 
881     QTAILQ_FOREACH(mount, &mounts, next) {
882         fd = qemu_open(mount->dirname, O_RDONLY);
883         if (fd == -1) {
884             error_setg_errno(errp, errno, "failed to open %s", mount->dirname);
885             goto error;
886         }
887 
888         /* We try to cull filesytems we know won't work in advance, but other
889          * filesytems may not implement fstrim for less obvious reasons.  These
890          * will report EOPNOTSUPP; we simply ignore these errors.  Any other
891          * error means an unexpected error, so return it in those cases.  In
892          * some other cases ENOTTY will be reported (e.g. CD-ROMs).
893          */
894         ret = ioctl(fd, FITRIM, &r);
895         if (ret == -1) {
896             if (errno != ENOTTY && errno != EOPNOTSUPP) {
897                 error_setg_errno(errp, errno, "failed to trim %s",
898                                  mount->dirname);
899                 close(fd);
900                 goto error;
901             }
902         }
903         close(fd);
904     }
905 
906 error:
907     free_fs_mount_list(&mounts);
908 }
909 #endif /* CONFIG_FSTRIM */
910 
911 
912 #define LINUX_SYS_STATE_FILE "/sys/power/state"
913 #define SUSPEND_SUPPORTED 0
914 #define SUSPEND_NOT_SUPPORTED 1
915 
916 static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
917                                const char *sysfile_str, Error **errp)
918 {
919     Error *local_err = NULL;
920     char *pmutils_path;
921     pid_t pid;
922     int status;
923 
924     pmutils_path = g_find_program_in_path(pmutils_bin);
925 
926     pid = fork();
927     if (!pid) {
928         char buf[32]; /* hopefully big enough */
929         ssize_t ret;
930         int fd;
931 
932         setsid();
933         reopen_fd_to_null(0);
934         reopen_fd_to_null(1);
935         reopen_fd_to_null(2);
936 
937         if (pmutils_path) {
938             execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
939         }
940 
941         /*
942          * If we get here either pm-utils is not installed or execle() has
943          * failed. Let's try the manual method if the caller wants it.
944          */
945 
946         if (!sysfile_str) {
947             _exit(SUSPEND_NOT_SUPPORTED);
948         }
949 
950         fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
951         if (fd < 0) {
952             _exit(SUSPEND_NOT_SUPPORTED);
953         }
954 
955         ret = read(fd, buf, sizeof(buf)-1);
956         if (ret <= 0) {
957             _exit(SUSPEND_NOT_SUPPORTED);
958         }
959         buf[ret] = '\0';
960 
961         if (strstr(buf, sysfile_str)) {
962             _exit(SUSPEND_SUPPORTED);
963         }
964 
965         _exit(SUSPEND_NOT_SUPPORTED);
966     } else if (pid < 0) {
967         error_setg_errno(errp, errno, "failed to create child process");
968         goto out;
969     }
970 
971     ga_wait_child(pid, &status, &local_err);
972     if (local_err) {
973         error_propagate(errp, local_err);
974         goto out;
975     }
976 
977     if (!WIFEXITED(status)) {
978         error_setg(errp, "child process has terminated abnormally");
979         goto out;
980     }
981 
982     switch (WEXITSTATUS(status)) {
983     case SUSPEND_SUPPORTED:
984         goto out;
985     case SUSPEND_NOT_SUPPORTED:
986         error_setg(errp,
987                    "the requested suspend mode is not supported by the guest");
988         goto out;
989     default:
990         error_setg(errp,
991                    "the helper program '%s' returned an unexpected exit status"
992                    " code (%d)", pmutils_path, WEXITSTATUS(status));
993         goto out;
994     }
995 
996 out:
997     g_free(pmutils_path);
998 }
999 
1000 static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
1001                           Error **errp)
1002 {
1003     Error *local_err = NULL;
1004     char *pmutils_path;
1005     pid_t pid;
1006     int status;
1007 
1008     pmutils_path = g_find_program_in_path(pmutils_bin);
1009 
1010     pid = fork();
1011     if (pid == 0) {
1012         /* child */
1013         int fd;
1014 
1015         setsid();
1016         reopen_fd_to_null(0);
1017         reopen_fd_to_null(1);
1018         reopen_fd_to_null(2);
1019 
1020         if (pmutils_path) {
1021             execle(pmutils_path, pmutils_bin, NULL, environ);
1022         }
1023 
1024         /*
1025          * If we get here either pm-utils is not installed or execle() has
1026          * failed. Let's try the manual method if the caller wants it.
1027          */
1028 
1029         if (!sysfile_str) {
1030             _exit(EXIT_FAILURE);
1031         }
1032 
1033         fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
1034         if (fd < 0) {
1035             _exit(EXIT_FAILURE);
1036         }
1037 
1038         if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
1039             _exit(EXIT_FAILURE);
1040         }
1041 
1042         _exit(EXIT_SUCCESS);
1043     } else if (pid < 0) {
1044         error_setg_errno(errp, errno, "failed to create child process");
1045         goto out;
1046     }
1047 
1048     ga_wait_child(pid, &status, &local_err);
1049     if (local_err) {
1050         error_propagate(errp, local_err);
1051         goto out;
1052     }
1053 
1054     if (!WIFEXITED(status)) {
1055         error_setg(errp, "child process has terminated abnormally");
1056         goto out;
1057     }
1058 
1059     if (WEXITSTATUS(status)) {
1060         error_setg(errp, "child process has failed to suspend");
1061         goto out;
1062     }
1063 
1064 out:
1065     g_free(pmutils_path);
1066 }
1067 
1068 void qmp_guest_suspend_disk(Error **errp)
1069 {
1070     Error *local_err = NULL;
1071 
1072     bios_supports_mode("pm-is-supported", "--hibernate", "disk", &local_err);
1073     if (local_err) {
1074         error_propagate(errp, local_err);
1075         return;
1076     }
1077 
1078     guest_suspend("pm-hibernate", "disk", errp);
1079 }
1080 
1081 void qmp_guest_suspend_ram(Error **errp)
1082 {
1083     Error *local_err = NULL;
1084 
1085     bios_supports_mode("pm-is-supported", "--suspend", "mem", &local_err);
1086     if (local_err) {
1087         error_propagate(errp, local_err);
1088         return;
1089     }
1090 
1091     guest_suspend("pm-suspend", "mem", errp);
1092 }
1093 
1094 void qmp_guest_suspend_hybrid(Error **errp)
1095 {
1096     Error *local_err = NULL;
1097 
1098     bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL,
1099                        &local_err);
1100     if (local_err) {
1101         error_propagate(errp, local_err);
1102         return;
1103     }
1104 
1105     guest_suspend("pm-suspend-hybrid", NULL, errp);
1106 }
1107 
1108 static GuestNetworkInterfaceList *
1109 guest_find_interface(GuestNetworkInterfaceList *head,
1110                      const char *name)
1111 {
1112     for (; head; head = head->next) {
1113         if (strcmp(head->value->name, name) == 0) {
1114             break;
1115         }
1116     }
1117 
1118     return head;
1119 }
1120 
1121 /*
1122  * Build information about guest interfaces
1123  */
1124 GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
1125 {
1126     GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
1127     struct ifaddrs *ifap, *ifa;
1128 
1129     if (getifaddrs(&ifap) < 0) {
1130         error_setg_errno(errp, errno, "getifaddrs failed");
1131         goto error;
1132     }
1133 
1134     for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1135         GuestNetworkInterfaceList *info;
1136         GuestIpAddressList **address_list = NULL, *address_item = NULL;
1137         char addr4[INET_ADDRSTRLEN];
1138         char addr6[INET6_ADDRSTRLEN];
1139         int sock;
1140         struct ifreq ifr;
1141         unsigned char *mac_addr;
1142         void *p;
1143 
1144         g_debug("Processing %s interface", ifa->ifa_name);
1145 
1146         info = guest_find_interface(head, ifa->ifa_name);
1147 
1148         if (!info) {
1149             info = g_malloc0(sizeof(*info));
1150             info->value = g_malloc0(sizeof(*info->value));
1151             info->value->name = g_strdup(ifa->ifa_name);
1152 
1153             if (!cur_item) {
1154                 head = cur_item = info;
1155             } else {
1156                 cur_item->next = info;
1157                 cur_item = info;
1158             }
1159         }
1160 
1161         if (!info->value->has_hardware_address &&
1162             ifa->ifa_flags & SIOCGIFHWADDR) {
1163             /* we haven't obtained HW address yet */
1164             sock = socket(PF_INET, SOCK_STREAM, 0);
1165             if (sock == -1) {
1166                 error_setg_errno(errp, errno, "failed to create socket");
1167                 goto error;
1168             }
1169 
1170             memset(&ifr, 0, sizeof(ifr));
1171             pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->value->name);
1172             if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
1173                 error_setg_errno(errp, errno,
1174                                  "failed to get MAC address of %s",
1175                                  ifa->ifa_name);
1176                 close(sock);
1177                 goto error;
1178             }
1179 
1180             close(sock);
1181             mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
1182 
1183             info->value->hardware_address =
1184                 g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x",
1185                                 (int) mac_addr[0], (int) mac_addr[1],
1186                                 (int) mac_addr[2], (int) mac_addr[3],
1187                                 (int) mac_addr[4], (int) mac_addr[5]);
1188 
1189             info->value->has_hardware_address = true;
1190         }
1191 
1192         if (ifa->ifa_addr &&
1193             ifa->ifa_addr->sa_family == AF_INET) {
1194             /* interface with IPv4 address */
1195             p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
1196             if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
1197                 error_setg_errno(errp, errno, "inet_ntop failed");
1198                 goto error;
1199             }
1200 
1201             address_item = g_malloc0(sizeof(*address_item));
1202             address_item->value = g_malloc0(sizeof(*address_item->value));
1203             address_item->value->ip_address = g_strdup(addr4);
1204             address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
1205 
1206             if (ifa->ifa_netmask) {
1207                 /* Count the number of set bits in netmask.
1208                  * This is safe as '1' and '0' cannot be shuffled in netmask. */
1209                 p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
1210                 address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
1211             }
1212         } else if (ifa->ifa_addr &&
1213                    ifa->ifa_addr->sa_family == AF_INET6) {
1214             /* interface with IPv6 address */
1215             p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
1216             if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
1217                 error_setg_errno(errp, errno, "inet_ntop failed");
1218                 goto error;
1219             }
1220 
1221             address_item = g_malloc0(sizeof(*address_item));
1222             address_item->value = g_malloc0(sizeof(*address_item->value));
1223             address_item->value->ip_address = g_strdup(addr6);
1224             address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
1225 
1226             if (ifa->ifa_netmask) {
1227                 /* Count the number of set bits in netmask.
1228                  * This is safe as '1' and '0' cannot be shuffled in netmask. */
1229                 p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
1230                 address_item->value->prefix =
1231                     ctpop32(((uint32_t *) p)[0]) +
1232                     ctpop32(((uint32_t *) p)[1]) +
1233                     ctpop32(((uint32_t *) p)[2]) +
1234                     ctpop32(((uint32_t *) p)[3]);
1235             }
1236         }
1237 
1238         if (!address_item) {
1239             continue;
1240         }
1241 
1242         address_list = &info->value->ip_addresses;
1243 
1244         while (*address_list && (*address_list)->next) {
1245             address_list = &(*address_list)->next;
1246         }
1247 
1248         if (!*address_list) {
1249             *address_list = address_item;
1250         } else {
1251             (*address_list)->next = address_item;
1252         }
1253 
1254         info->value->has_ip_addresses = true;
1255 
1256 
1257     }
1258 
1259     freeifaddrs(ifap);
1260     return head;
1261 
1262 error:
1263     freeifaddrs(ifap);
1264     qapi_free_GuestNetworkInterfaceList(head);
1265     return NULL;
1266 }
1267 
1268 #define SYSCONF_EXACT(name, errp) sysconf_exact((name), #name, (errp))
1269 
1270 static long sysconf_exact(int name, const char *name_str, Error **errp)
1271 {
1272     long ret;
1273 
1274     errno = 0;
1275     ret = sysconf(name);
1276     if (ret == -1) {
1277         if (errno == 0) {
1278             error_setg(errp, "sysconf(%s): value indefinite", name_str);
1279         } else {
1280             error_setg_errno(errp, errno, "sysconf(%s)", name_str);
1281         }
1282     }
1283     return ret;
1284 }
1285 
1286 /* Transfer online/offline status between @vcpu and the guest system.
1287  *
1288  * On input either @errp or *@errp must be NULL.
1289  *
1290  * In system-to-@vcpu direction, the following @vcpu fields are accessed:
1291  * - R: vcpu->logical_id
1292  * - W: vcpu->online
1293  * - W: vcpu->can_offline
1294  *
1295  * In @vcpu-to-system direction, the following @vcpu fields are accessed:
1296  * - R: vcpu->logical_id
1297  * - R: vcpu->online
1298  *
1299  * Written members remain unmodified on error.
1300  */
1301 static void transfer_vcpu(GuestLogicalProcessor *vcpu, bool sys2vcpu,
1302                           Error **errp)
1303 {
1304     char *dirpath;
1305     int dirfd;
1306 
1307     dirpath = g_strdup_printf("/sys/devices/system/cpu/cpu%" PRId64 "/",
1308                               vcpu->logical_id);
1309     dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
1310     if (dirfd == -1) {
1311         error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
1312     } else {
1313         static const char fn[] = "online";
1314         int fd;
1315         int res;
1316 
1317         fd = openat(dirfd, fn, sys2vcpu ? O_RDONLY : O_RDWR);
1318         if (fd == -1) {
1319             if (errno != ENOENT) {
1320                 error_setg_errno(errp, errno, "open(\"%s/%s\")", dirpath, fn);
1321             } else if (sys2vcpu) {
1322                 vcpu->online = true;
1323                 vcpu->can_offline = false;
1324             } else if (!vcpu->online) {
1325                 error_setg(errp, "logical processor #%" PRId64 " can't be "
1326                            "offlined", vcpu->logical_id);
1327             } /* otherwise pretend successful re-onlining */
1328         } else {
1329             unsigned char status;
1330 
1331             res = pread(fd, &status, 1, 0);
1332             if (res == -1) {
1333                 error_setg_errno(errp, errno, "pread(\"%s/%s\")", dirpath, fn);
1334             } else if (res == 0) {
1335                 error_setg(errp, "pread(\"%s/%s\"): unexpected EOF", dirpath,
1336                            fn);
1337             } else if (sys2vcpu) {
1338                 vcpu->online = (status != '0');
1339                 vcpu->can_offline = true;
1340             } else if (vcpu->online != (status != '0')) {
1341                 status = '0' + vcpu->online;
1342                 if (pwrite(fd, &status, 1, 0) == -1) {
1343                     error_setg_errno(errp, errno, "pwrite(\"%s/%s\")", dirpath,
1344                                      fn);
1345                 }
1346             } /* otherwise pretend successful re-(on|off)-lining */
1347 
1348             res = close(fd);
1349             g_assert(res == 0);
1350         }
1351 
1352         res = close(dirfd);
1353         g_assert(res == 0);
1354     }
1355 
1356     g_free(dirpath);
1357 }
1358 
1359 GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
1360 {
1361     int64_t current;
1362     GuestLogicalProcessorList *head, **link;
1363     long sc_max;
1364     Error *local_err = NULL;
1365 
1366     current = 0;
1367     head = NULL;
1368     link = &head;
1369     sc_max = SYSCONF_EXACT(_SC_NPROCESSORS_CONF, &local_err);
1370 
1371     while (local_err == NULL && current < sc_max) {
1372         GuestLogicalProcessor *vcpu;
1373         GuestLogicalProcessorList *entry;
1374 
1375         vcpu = g_malloc0(sizeof *vcpu);
1376         vcpu->logical_id = current++;
1377         vcpu->has_can_offline = true; /* lolspeak ftw */
1378         transfer_vcpu(vcpu, true, &local_err);
1379 
1380         entry = g_malloc0(sizeof *entry);
1381         entry->value = vcpu;
1382 
1383         *link = entry;
1384         link = &entry->next;
1385     }
1386 
1387     if (local_err == NULL) {
1388         /* there's no guest with zero VCPUs */
1389         g_assert(head != NULL);
1390         return head;
1391     }
1392 
1393     qapi_free_GuestLogicalProcessorList(head);
1394     error_propagate(errp, local_err);
1395     return NULL;
1396 }
1397 
1398 int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
1399 {
1400     int64_t processed;
1401     Error *local_err = NULL;
1402 
1403     processed = 0;
1404     while (vcpus != NULL) {
1405         transfer_vcpu(vcpus->value, false, &local_err);
1406         if (local_err != NULL) {
1407             break;
1408         }
1409         ++processed;
1410         vcpus = vcpus->next;
1411     }
1412 
1413     if (local_err != NULL) {
1414         if (processed == 0) {
1415             error_propagate(errp, local_err);
1416         } else {
1417             error_free(local_err);
1418         }
1419     }
1420 
1421     return processed;
1422 }
1423 
1424 #else /* defined(__linux__) */
1425 
1426 void qmp_guest_suspend_disk(Error **errp)
1427 {
1428     error_set(errp, QERR_UNSUPPORTED);
1429 }
1430 
1431 void qmp_guest_suspend_ram(Error **errp)
1432 {
1433     error_set(errp, QERR_UNSUPPORTED);
1434 }
1435 
1436 void qmp_guest_suspend_hybrid(Error **errp)
1437 {
1438     error_set(errp, QERR_UNSUPPORTED);
1439 }
1440 
1441 GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
1442 {
1443     error_set(errp, QERR_UNSUPPORTED);
1444     return NULL;
1445 }
1446 
1447 GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
1448 {
1449     error_set(errp, QERR_UNSUPPORTED);
1450     return NULL;
1451 }
1452 
1453 int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
1454 {
1455     error_set(errp, QERR_UNSUPPORTED);
1456     return -1;
1457 }
1458 
1459 #endif
1460 
1461 #if !defined(CONFIG_FSFREEZE)
1462 
1463 GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
1464 {
1465     error_set(errp, QERR_UNSUPPORTED);
1466 
1467     return 0;
1468 }
1469 
1470 int64_t qmp_guest_fsfreeze_freeze(Error **errp)
1471 {
1472     error_set(errp, QERR_UNSUPPORTED);
1473 
1474     return 0;
1475 }
1476 
1477 int64_t qmp_guest_fsfreeze_thaw(Error **errp)
1478 {
1479     error_set(errp, QERR_UNSUPPORTED);
1480 
1481     return 0;
1482 }
1483 #endif /* CONFIG_FSFREEZE */
1484 
1485 #if !defined(CONFIG_FSTRIM)
1486 void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
1487 {
1488     error_set(errp, QERR_UNSUPPORTED);
1489 }
1490 #endif
1491 
1492 /* register init/cleanup routines for stateful command groups */
1493 void ga_command_state_init(GAState *s, GACommandState *cs)
1494 {
1495 #if defined(CONFIG_FSFREEZE)
1496     ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
1497 #endif
1498     ga_command_state_add(cs, guest_file_init, NULL);
1499 }
1500