xref: /openbmc/qemu/qga/commands-posix.c (revision 61b9251a)
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 <dirent.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <inttypes.h>
26 #include "qga/guest-agent-core.h"
27 #include "qga-qmp-commands.h"
28 #include "qapi/qmp/qerror.h"
29 #include "qemu/queue.h"
30 #include "qemu/host-utils.h"
31 #include "qemu/sockets.h"
32 
33 #ifndef CONFIG_HAS_ENVIRON
34 #ifdef __APPLE__
35 #include <crt_externs.h>
36 #define environ (*_NSGetEnviron())
37 #else
38 extern char **environ;
39 #endif
40 #endif
41 
42 #if defined(__linux__)
43 #include <mntent.h>
44 #include <linux/fs.h>
45 #include <ifaddrs.h>
46 #include <arpa/inet.h>
47 #include <sys/socket.h>
48 #include <net/if.h>
49 
50 #ifdef FIFREEZE
51 #define CONFIG_FSFREEZE
52 #endif
53 #ifdef FITRIM
54 #define CONFIG_FSTRIM
55 #endif
56 #endif
57 
58 static void ga_wait_child(pid_t pid, int *status, Error **errp)
59 {
60     pid_t rpid;
61 
62     *status = 0;
63 
64     do {
65         rpid = waitpid(pid, status, 0);
66     } while (rpid == -1 && errno == EINTR);
67 
68     if (rpid == -1) {
69         error_setg_errno(errp, errno, "failed to wait for child (pid: %d)",
70                          pid);
71         return;
72     }
73 
74     g_assert(rpid == pid);
75 }
76 
77 void qmp_guest_shutdown(bool has_mode, const char *mode, Error **errp)
78 {
79     const char *shutdown_flag;
80     Error *local_err = NULL;
81     pid_t pid;
82     int status;
83 
84     slog("guest-shutdown called, mode: %s", mode);
85     if (!has_mode || strcmp(mode, "powerdown") == 0) {
86         shutdown_flag = "-P";
87     } else if (strcmp(mode, "halt") == 0) {
88         shutdown_flag = "-H";
89     } else if (strcmp(mode, "reboot") == 0) {
90         shutdown_flag = "-r";
91     } else {
92         error_setg(errp,
93                    "mode is invalid (valid values are: halt|powerdown|reboot");
94         return;
95     }
96 
97     pid = fork();
98     if (pid == 0) {
99         /* child, start the shutdown */
100         setsid();
101         reopen_fd_to_null(0);
102         reopen_fd_to_null(1);
103         reopen_fd_to_null(2);
104 
105         execle("/sbin/shutdown", "shutdown", "-h", shutdown_flag, "+0",
106                "hypervisor initiated shutdown", (char*)NULL, environ);
107         _exit(EXIT_FAILURE);
108     } else if (pid < 0) {
109         error_setg_errno(errp, errno, "failed to create child process");
110         return;
111     }
112 
113     ga_wait_child(pid, &status, &local_err);
114     if (local_err) {
115         error_propagate(errp, local_err);
116         return;
117     }
118 
119     if (!WIFEXITED(status)) {
120         error_setg(errp, "child process has terminated abnormally");
121         return;
122     }
123 
124     if (WEXITSTATUS(status)) {
125         error_setg(errp, "child process has failed to shutdown");
126         return;
127     }
128 
129     /* succeeded */
130 }
131 
132 int64_t qmp_guest_get_time(Error **errp)
133 {
134    int ret;
135    qemu_timeval tq;
136    int64_t time_ns;
137 
138    ret = qemu_gettimeofday(&tq);
139    if (ret < 0) {
140        error_setg_errno(errp, errno, "Failed to get time");
141        return -1;
142    }
143 
144    time_ns = tq.tv_sec * 1000000000LL + tq.tv_usec * 1000;
145    return time_ns;
146 }
147 
148 void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
149 {
150     int ret;
151     int status;
152     pid_t pid;
153     Error *local_err = NULL;
154     struct timeval tv;
155 
156     /* If user has passed a time, validate and set it. */
157     if (has_time) {
158         GDate date = { 0, };
159 
160         /* year-2038 will overflow in case time_t is 32bit */
161         if (time_ns / 1000000000 != (time_t)(time_ns / 1000000000)) {
162             error_setg(errp, "Time %" PRId64 " is too large", time_ns);
163             return;
164         }
165 
166         tv.tv_sec = time_ns / 1000000000;
167         tv.tv_usec = (time_ns % 1000000000) / 1000;
168         g_date_set_time_t(&date, tv.tv_sec);
169         if (date.year < 1970 || date.year >= 2070) {
170             error_setg_errno(errp, errno, "Invalid time");
171             return;
172         }
173 
174         ret = settimeofday(&tv, NULL);
175         if (ret < 0) {
176             error_setg_errno(errp, errno, "Failed to set time to guest");
177             return;
178         }
179     }
180 
181     /* Now, if user has passed a time to set and the system time is set, we
182      * just need to synchronize the hardware clock. However, if no time was
183      * passed, user is requesting the opposite: set the system time from the
184      * hardware clock (RTC). */
185     pid = fork();
186     if (pid == 0) {
187         setsid();
188         reopen_fd_to_null(0);
189         reopen_fd_to_null(1);
190         reopen_fd_to_null(2);
191 
192         /* Use '/sbin/hwclock -w' to set RTC from the system time,
193          * or '/sbin/hwclock -s' to set the system time from RTC. */
194         execle("/sbin/hwclock", "hwclock", has_time ? "-w" : "-s",
195                NULL, environ);
196         _exit(EXIT_FAILURE);
197     } else if (pid < 0) {
198         error_setg_errno(errp, errno, "failed to create child process");
199         return;
200     }
201 
202     ga_wait_child(pid, &status, &local_err);
203     if (local_err) {
204         error_propagate(errp, local_err);
205         return;
206     }
207 
208     if (!WIFEXITED(status)) {
209         error_setg(errp, "child process has terminated abnormally");
210         return;
211     }
212 
213     if (WEXITSTATUS(status)) {
214         error_setg(errp, "hwclock failed to set hardware clock to system time");
215         return;
216     }
217 }
218 
219 typedef struct GuestFileHandle {
220     uint64_t id;
221     FILE *fh;
222     QTAILQ_ENTRY(GuestFileHandle) next;
223 } GuestFileHandle;
224 
225 static struct {
226     QTAILQ_HEAD(, GuestFileHandle) filehandles;
227 } guest_file_state = {
228     .filehandles = QTAILQ_HEAD_INITIALIZER(guest_file_state.filehandles),
229 };
230 
231 static int64_t guest_file_handle_add(FILE *fh, Error **errp)
232 {
233     GuestFileHandle *gfh;
234     int64_t handle;
235 
236     handle = ga_get_fd_handle(ga_state, errp);
237     if (handle < 0) {
238         return -1;
239     }
240 
241     gfh = g_new0(GuestFileHandle, 1);
242     gfh->id = handle;
243     gfh->fh = fh;
244     QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
245 
246     return handle;
247 }
248 
249 static GuestFileHandle *guest_file_handle_find(int64_t id, Error **errp)
250 {
251     GuestFileHandle *gfh;
252 
253     QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
254     {
255         if (gfh->id == id) {
256             return gfh;
257         }
258     }
259 
260     error_setg(errp, "handle '%" PRId64 "' has not been found", id);
261     return NULL;
262 }
263 
264 typedef const char * const ccpc;
265 
266 #ifndef O_BINARY
267 #define O_BINARY 0
268 #endif
269 
270 /* http://pubs.opengroup.org/onlinepubs/9699919799/functions/fopen.html */
271 static const struct {
272     ccpc *forms;
273     int oflag_base;
274 } guest_file_open_modes[] = {
275     { (ccpc[]){ "r",          NULL }, O_RDONLY                                 },
276     { (ccpc[]){ "rb",         NULL }, O_RDONLY                      | O_BINARY },
277     { (ccpc[]){ "w",          NULL }, O_WRONLY | O_CREAT | O_TRUNC             },
278     { (ccpc[]){ "wb",         NULL }, O_WRONLY | O_CREAT | O_TRUNC  | O_BINARY },
279     { (ccpc[]){ "a",          NULL }, O_WRONLY | O_CREAT | O_APPEND            },
280     { (ccpc[]){ "ab",         NULL }, O_WRONLY | O_CREAT | O_APPEND | O_BINARY },
281     { (ccpc[]){ "r+",         NULL }, O_RDWR                                   },
282     { (ccpc[]){ "rb+", "r+b", NULL }, O_RDWR                        | O_BINARY },
283     { (ccpc[]){ "w+",         NULL }, O_RDWR   | O_CREAT | O_TRUNC             },
284     { (ccpc[]){ "wb+", "w+b", NULL }, O_RDWR   | O_CREAT | O_TRUNC  | O_BINARY },
285     { (ccpc[]){ "a+",         NULL }, O_RDWR   | O_CREAT | O_APPEND            },
286     { (ccpc[]){ "ab+", "a+b", NULL }, O_RDWR   | O_CREAT | O_APPEND | O_BINARY }
287 };
288 
289 static int
290 find_open_flag(const char *mode_str, Error **errp)
291 {
292     unsigned mode;
293 
294     for (mode = 0; mode < ARRAY_SIZE(guest_file_open_modes); ++mode) {
295         ccpc *form;
296 
297         form = guest_file_open_modes[mode].forms;
298         while (*form != NULL && strcmp(*form, mode_str) != 0) {
299             ++form;
300         }
301         if (*form != NULL) {
302             break;
303         }
304     }
305 
306     if (mode == ARRAY_SIZE(guest_file_open_modes)) {
307         error_setg(errp, "invalid file open mode '%s'", mode_str);
308         return -1;
309     }
310     return guest_file_open_modes[mode].oflag_base | O_NOCTTY | O_NONBLOCK;
311 }
312 
313 #define DEFAULT_NEW_FILE_MODE (S_IRUSR | S_IWUSR | \
314                                S_IRGRP | S_IWGRP | \
315                                S_IROTH | S_IWOTH)
316 
317 static FILE *
318 safe_open_or_create(const char *path, const char *mode, Error **errp)
319 {
320     Error *local_err = NULL;
321     int oflag;
322 
323     oflag = find_open_flag(mode, &local_err);
324     if (local_err == NULL) {
325         int fd;
326 
327         /* If the caller wants / allows creation of a new file, we implement it
328          * with a two step process: open() + (open() / fchmod()).
329          *
330          * First we insist on creating the file exclusively as a new file. If
331          * that succeeds, we're free to set any file-mode bits on it. (The
332          * motivation is that we want to set those file-mode bits independently
333          * of the current umask.)
334          *
335          * If the exclusive creation fails because the file already exists
336          * (EEXIST is not possible for any other reason), we just attempt to
337          * open the file, but in this case we won't be allowed to change the
338          * file-mode bits on the preexistent file.
339          *
340          * The pathname should never disappear between the two open()s in
341          * practice. If it happens, then someone very likely tried to race us.
342          * In this case just go ahead and report the ENOENT from the second
343          * open() to the caller.
344          *
345          * If the caller wants to open a preexistent file, then the first
346          * open() is decisive and its third argument is ignored, and the second
347          * open() and the fchmod() are never called.
348          */
349         fd = open(path, oflag | ((oflag & O_CREAT) ? O_EXCL : 0), 0);
350         if (fd == -1 && errno == EEXIST) {
351             oflag &= ~(unsigned)O_CREAT;
352             fd = open(path, oflag);
353         }
354 
355         if (fd == -1) {
356             error_setg_errno(&local_err, errno, "failed to open file '%s' "
357                              "(mode: '%s')", path, mode);
358         } else {
359             qemu_set_cloexec(fd);
360 
361             if ((oflag & O_CREAT) && fchmod(fd, DEFAULT_NEW_FILE_MODE) == -1) {
362                 error_setg_errno(&local_err, errno, "failed to set permission "
363                                  "0%03o on new file '%s' (mode: '%s')",
364                                  (unsigned)DEFAULT_NEW_FILE_MODE, path, mode);
365             } else {
366                 FILE *f;
367 
368                 f = fdopen(fd, mode);
369                 if (f == NULL) {
370                     error_setg_errno(&local_err, errno, "failed to associate "
371                                      "stdio stream with file descriptor %d, "
372                                      "file '%s' (mode: '%s')", fd, path, mode);
373                 } else {
374                     return f;
375                 }
376             }
377 
378             close(fd);
379             if (oflag & O_CREAT) {
380                 unlink(path);
381             }
382         }
383     }
384 
385     error_propagate(errp, local_err);
386     return NULL;
387 }
388 
389 int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode,
390                             Error **errp)
391 {
392     FILE *fh;
393     Error *local_err = NULL;
394     int64_t handle;
395 
396     if (!has_mode) {
397         mode = "r";
398     }
399     slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
400     fh = safe_open_or_create(path, mode, &local_err);
401     if (local_err != NULL) {
402         error_propagate(errp, local_err);
403         return -1;
404     }
405 
406     /* set fd non-blocking to avoid common use cases (like reading from a
407      * named pipe) from hanging the agent
408      */
409     qemu_set_nonblock(fileno(fh));
410 
411     handle = guest_file_handle_add(fh, errp);
412     if (handle < 0) {
413         fclose(fh);
414         return -1;
415     }
416 
417     slog("guest-file-open, handle: %" PRId64, handle);
418     return handle;
419 }
420 
421 void qmp_guest_file_close(int64_t handle, Error **errp)
422 {
423     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
424     int ret;
425 
426     slog("guest-file-close called, handle: %" PRId64, handle);
427     if (!gfh) {
428         return;
429     }
430 
431     ret = fclose(gfh->fh);
432     if (ret == EOF) {
433         error_setg_errno(errp, errno, "failed to close handle");
434         return;
435     }
436 
437     QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
438     g_free(gfh);
439 }
440 
441 struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
442                                           int64_t count, Error **errp)
443 {
444     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
445     GuestFileRead *read_data = NULL;
446     guchar *buf;
447     FILE *fh;
448     size_t read_count;
449 
450     if (!gfh) {
451         return NULL;
452     }
453 
454     if (!has_count) {
455         count = QGA_READ_COUNT_DEFAULT;
456     } else if (count < 0) {
457         error_setg(errp, "value '%" PRId64 "' is invalid for argument count",
458                    count);
459         return NULL;
460     }
461 
462     fh = gfh->fh;
463     buf = g_malloc0(count+1);
464     read_count = fread(buf, 1, count, fh);
465     if (ferror(fh)) {
466         error_setg_errno(errp, errno, "failed to read file");
467         slog("guest-file-read failed, handle: %" PRId64, handle);
468     } else {
469         buf[read_count] = 0;
470         read_data = g_new0(GuestFileRead, 1);
471         read_data->count = read_count;
472         read_data->eof = feof(fh);
473         if (read_count) {
474             read_data->buf_b64 = g_base64_encode(buf, read_count);
475         }
476     }
477     g_free(buf);
478     clearerr(fh);
479 
480     return read_data;
481 }
482 
483 GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
484                                      bool has_count, int64_t count,
485                                      Error **errp)
486 {
487     GuestFileWrite *write_data = NULL;
488     guchar *buf;
489     gsize buf_len;
490     int write_count;
491     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
492     FILE *fh;
493 
494     if (!gfh) {
495         return NULL;
496     }
497 
498     fh = gfh->fh;
499     buf = g_base64_decode(buf_b64, &buf_len);
500 
501     if (!has_count) {
502         count = buf_len;
503     } else if (count < 0 || count > buf_len) {
504         error_setg(errp, "value '%" PRId64 "' is invalid for argument count",
505                    count);
506         g_free(buf);
507         return NULL;
508     }
509 
510     write_count = fwrite(buf, 1, count, fh);
511     if (ferror(fh)) {
512         error_setg_errno(errp, errno, "failed to write to file");
513         slog("guest-file-write failed, handle: %" PRId64, handle);
514     } else {
515         write_data = g_new0(GuestFileWrite, 1);
516         write_data->count = write_count;
517         write_data->eof = feof(fh);
518     }
519     g_free(buf);
520     clearerr(fh);
521 
522     return write_data;
523 }
524 
525 struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
526                                           int64_t whence, Error **errp)
527 {
528     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
529     GuestFileSeek *seek_data = NULL;
530     FILE *fh;
531     int ret;
532 
533     if (!gfh) {
534         return NULL;
535     }
536 
537     fh = gfh->fh;
538     ret = fseek(fh, offset, whence);
539     if (ret == -1) {
540         error_setg_errno(errp, errno, "failed to seek file");
541     } else {
542         seek_data = g_new0(GuestFileSeek, 1);
543         seek_data->position = ftell(fh);
544         seek_data->eof = feof(fh);
545     }
546     clearerr(fh);
547 
548     return seek_data;
549 }
550 
551 void qmp_guest_file_flush(int64_t handle, Error **errp)
552 {
553     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
554     FILE *fh;
555     int ret;
556 
557     if (!gfh) {
558         return;
559     }
560 
561     fh = gfh->fh;
562     ret = fflush(fh);
563     if (ret == EOF) {
564         error_setg_errno(errp, errno, "failed to flush file");
565     }
566 }
567 
568 /* linux-specific implementations. avoid this if at all possible. */
569 #if defined(__linux__)
570 
571 #if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
572 typedef struct FsMount {
573     char *dirname;
574     char *devtype;
575     unsigned int devmajor, devminor;
576     QTAILQ_ENTRY(FsMount) next;
577 } FsMount;
578 
579 typedef QTAILQ_HEAD(FsMountList, FsMount) FsMountList;
580 
581 static void free_fs_mount_list(FsMountList *mounts)
582 {
583      FsMount *mount, *temp;
584 
585      if (!mounts) {
586          return;
587      }
588 
589      QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) {
590          QTAILQ_REMOVE(mounts, mount, next);
591          g_free(mount->dirname);
592          g_free(mount->devtype);
593          g_free(mount);
594      }
595 }
596 
597 static int dev_major_minor(const char *devpath,
598                            unsigned int *devmajor, unsigned int *devminor)
599 {
600     struct stat st;
601 
602     *devmajor = 0;
603     *devminor = 0;
604 
605     if (stat(devpath, &st) < 0) {
606         slog("failed to stat device file '%s': %s", devpath, strerror(errno));
607         return -1;
608     }
609     if (S_ISDIR(st.st_mode)) {
610         /* It is bind mount */
611         return -2;
612     }
613     if (S_ISBLK(st.st_mode)) {
614         *devmajor = major(st.st_rdev);
615         *devminor = minor(st.st_rdev);
616         return 0;
617     }
618     return -1;
619 }
620 
621 /*
622  * Walk the mount table and build a list of local file systems
623  */
624 static void build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp)
625 {
626     struct mntent *ment;
627     FsMount *mount;
628     char const *mtab = "/proc/self/mounts";
629     FILE *fp;
630     unsigned int devmajor, devminor;
631 
632     fp = setmntent(mtab, "r");
633     if (!fp) {
634         error_setg(errp, "failed to open mtab file: '%s'", mtab);
635         return;
636     }
637 
638     while ((ment = getmntent(fp))) {
639         /*
640          * An entry which device name doesn't start with a '/' is
641          * either a dummy file system or a network file system.
642          * Add special handling for smbfs and cifs as is done by
643          * coreutils as well.
644          */
645         if ((ment->mnt_fsname[0] != '/') ||
646             (strcmp(ment->mnt_type, "smbfs") == 0) ||
647             (strcmp(ment->mnt_type, "cifs") == 0)) {
648             continue;
649         }
650         if (dev_major_minor(ment->mnt_fsname, &devmajor, &devminor) == -2) {
651             /* Skip bind mounts */
652             continue;
653         }
654 
655         mount = g_new0(FsMount, 1);
656         mount->dirname = g_strdup(ment->mnt_dir);
657         mount->devtype = g_strdup(ment->mnt_type);
658         mount->devmajor = devmajor;
659         mount->devminor = devminor;
660 
661         QTAILQ_INSERT_TAIL(mounts, mount, next);
662     }
663 
664     endmntent(fp);
665 }
666 
667 static void decode_mntname(char *name, int len)
668 {
669     int i, j = 0;
670     for (i = 0; i <= len; i++) {
671         if (name[i] != '\\') {
672             name[j++] = name[i];
673         } else if (name[i + 1] == '\\') {
674             name[j++] = '\\';
675             i++;
676         } else if (name[i + 1] >= '0' && name[i + 1] <= '3' &&
677                    name[i + 2] >= '0' && name[i + 2] <= '7' &&
678                    name[i + 3] >= '0' && name[i + 3] <= '7') {
679             name[j++] = (name[i + 1] - '0') * 64 +
680                         (name[i + 2] - '0') * 8 +
681                         (name[i + 3] - '0');
682             i += 3;
683         } else {
684             name[j++] = name[i];
685         }
686     }
687 }
688 
689 static void build_fs_mount_list(FsMountList *mounts, Error **errp)
690 {
691     FsMount *mount;
692     char const *mountinfo = "/proc/self/mountinfo";
693     FILE *fp;
694     char *line = NULL, *dash;
695     size_t n;
696     char check;
697     unsigned int devmajor, devminor;
698     int ret, dir_s, dir_e, type_s, type_e, dev_s, dev_e;
699 
700     fp = fopen(mountinfo, "r");
701     if (!fp) {
702         build_fs_mount_list_from_mtab(mounts, errp);
703         return;
704     }
705 
706     while (getline(&line, &n, fp) != -1) {
707         ret = sscanf(line, "%*u %*u %u:%u %*s %n%*s%n%c",
708                      &devmajor, &devminor, &dir_s, &dir_e, &check);
709         if (ret < 3) {
710             continue;
711         }
712         dash = strstr(line + dir_e, " - ");
713         if (!dash) {
714             continue;
715         }
716         ret = sscanf(dash, " - %n%*s%n %n%*s%n%c",
717                      &type_s, &type_e, &dev_s, &dev_e, &check);
718         if (ret < 1) {
719             continue;
720         }
721         line[dir_e] = 0;
722         dash[type_e] = 0;
723         dash[dev_e] = 0;
724         decode_mntname(line + dir_s, dir_e - dir_s);
725         decode_mntname(dash + dev_s, dev_e - dev_s);
726         if (devmajor == 0) {
727             /* btrfs reports major number = 0 */
728             if (strcmp("btrfs", dash + type_s) != 0 ||
729                 dev_major_minor(dash + dev_s, &devmajor, &devminor) < 0) {
730                 continue;
731             }
732         }
733 
734         mount = g_new0(FsMount, 1);
735         mount->dirname = g_strdup(line + dir_s);
736         mount->devtype = g_strdup(dash + type_s);
737         mount->devmajor = devmajor;
738         mount->devminor = devminor;
739 
740         QTAILQ_INSERT_TAIL(mounts, mount, next);
741     }
742     free(line);
743 
744     fclose(fp);
745 }
746 #endif
747 
748 #if defined(CONFIG_FSFREEZE)
749 
750 static char *get_pci_driver(char const *syspath, int pathlen, Error **errp)
751 {
752     char *path;
753     char *dpath;
754     char *driver = NULL;
755     char buf[PATH_MAX];
756     ssize_t len;
757 
758     path = g_strndup(syspath, pathlen);
759     dpath = g_strdup_printf("%s/driver", path);
760     len = readlink(dpath, buf, sizeof(buf) - 1);
761     if (len != -1) {
762         buf[len] = 0;
763         driver = g_strdup(basename(buf));
764     }
765     g_free(dpath);
766     g_free(path);
767     return driver;
768 }
769 
770 static int compare_uint(const void *_a, const void *_b)
771 {
772     unsigned int a = *(unsigned int *)_a;
773     unsigned int b = *(unsigned int *)_b;
774 
775     return a < b ? -1 : a > b ? 1 : 0;
776 }
777 
778 /* Walk the specified sysfs and build a sorted list of host or ata numbers */
779 static int build_hosts(char const *syspath, char const *host, bool ata,
780                        unsigned int *hosts, int hosts_max, Error **errp)
781 {
782     char *path;
783     DIR *dir;
784     struct dirent *entry;
785     int i = 0;
786 
787     path = g_strndup(syspath, host - syspath);
788     dir = opendir(path);
789     if (!dir) {
790         error_setg_errno(errp, errno, "opendir(\"%s\")", path);
791         g_free(path);
792         return -1;
793     }
794 
795     while (i < hosts_max) {
796         entry = readdir(dir);
797         if (!entry) {
798             break;
799         }
800         if (ata && sscanf(entry->d_name, "ata%d", hosts + i) == 1) {
801             ++i;
802         } else if (!ata && sscanf(entry->d_name, "host%d", hosts + i) == 1) {
803             ++i;
804         }
805     }
806 
807     qsort(hosts, i, sizeof(hosts[0]), compare_uint);
808 
809     g_free(path);
810     closedir(dir);
811     return i;
812 }
813 
814 /* Store disk device info specified by @sysfs into @fs */
815 static void build_guest_fsinfo_for_real_device(char const *syspath,
816                                                GuestFilesystemInfo *fs,
817                                                Error **errp)
818 {
819     unsigned int pci[4], host, hosts[8], tgt[3];
820     int i, nhosts = 0, pcilen;
821     GuestDiskAddress *disk;
822     GuestPCIAddress *pciaddr;
823     GuestDiskAddressList *list = NULL;
824     bool has_ata = false, has_host = false, has_tgt = false;
825     char *p, *q, *driver = NULL;
826 
827     p = strstr(syspath, "/devices/pci");
828     if (!p || sscanf(p + 12, "%*x:%*x/%x:%x:%x.%x%n",
829                      pci, pci + 1, pci + 2, pci + 3, &pcilen) < 4) {
830         g_debug("only pci device is supported: sysfs path \"%s\"", syspath);
831         return;
832     }
833 
834     driver = get_pci_driver(syspath, (p + 12 + pcilen) - syspath, errp);
835     if (!driver) {
836         goto cleanup;
837     }
838 
839     p = strstr(syspath, "/target");
840     if (p && sscanf(p + 7, "%*u:%*u:%*u/%*u:%u:%u:%u",
841                     tgt, tgt + 1, tgt + 2) == 3) {
842         has_tgt = true;
843     }
844 
845     p = strstr(syspath, "/ata");
846     if (p) {
847         q = p + 4;
848         has_ata = true;
849     } else {
850         p = strstr(syspath, "/host");
851         q = p + 5;
852     }
853     if (p && sscanf(q, "%u", &host) == 1) {
854         has_host = true;
855         nhosts = build_hosts(syspath, p, has_ata, hosts,
856                              sizeof(hosts) / sizeof(hosts[0]), errp);
857         if (nhosts < 0) {
858             goto cleanup;
859         }
860     }
861 
862     pciaddr = g_malloc0(sizeof(*pciaddr));
863     pciaddr->domain = pci[0];
864     pciaddr->bus = pci[1];
865     pciaddr->slot = pci[2];
866     pciaddr->function = pci[3];
867 
868     disk = g_malloc0(sizeof(*disk));
869     disk->pci_controller = pciaddr;
870 
871     list = g_malloc0(sizeof(*list));
872     list->value = disk;
873 
874     if (strcmp(driver, "ata_piix") == 0) {
875         /* a host per ide bus, target*:0:<unit>:0 */
876         if (!has_host || !has_tgt) {
877             g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
878             goto cleanup;
879         }
880         for (i = 0; i < nhosts; i++) {
881             if (host == hosts[i]) {
882                 disk->bus_type = GUEST_DISK_BUS_TYPE_IDE;
883                 disk->bus = i;
884                 disk->unit = tgt[1];
885                 break;
886             }
887         }
888         if (i >= nhosts) {
889             g_debug("no host for '%s' (driver '%s')", syspath, driver);
890             goto cleanup;
891         }
892     } else if (strcmp(driver, "sym53c8xx") == 0) {
893         /* scsi(LSI Logic): target*:0:<unit>:0 */
894         if (!has_tgt) {
895             g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
896             goto cleanup;
897         }
898         disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
899         disk->unit = tgt[1];
900     } else if (strcmp(driver, "virtio-pci") == 0) {
901         if (has_tgt) {
902             /* virtio-scsi: target*:0:0:<unit> */
903             disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
904             disk->unit = tgt[2];
905         } else {
906             /* virtio-blk: 1 disk per 1 device */
907             disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO;
908         }
909     } else if (strcmp(driver, "ahci") == 0) {
910         /* ahci: 1 host per 1 unit */
911         if (!has_host || !has_tgt) {
912             g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
913             goto cleanup;
914         }
915         for (i = 0; i < nhosts; i++) {
916             if (host == hosts[i]) {
917                 disk->unit = i;
918                 disk->bus_type = GUEST_DISK_BUS_TYPE_SATA;
919                 break;
920             }
921         }
922         if (i >= nhosts) {
923             g_debug("no host for '%s' (driver '%s')", syspath, driver);
924             goto cleanup;
925         }
926     } else {
927         g_debug("unknown driver '%s' (sysfs path '%s')", driver, syspath);
928         goto cleanup;
929     }
930 
931     list->next = fs->disk;
932     fs->disk = list;
933     g_free(driver);
934     return;
935 
936 cleanup:
937     if (list) {
938         qapi_free_GuestDiskAddressList(list);
939     }
940     g_free(driver);
941 }
942 
943 static void build_guest_fsinfo_for_device(char const *devpath,
944                                           GuestFilesystemInfo *fs,
945                                           Error **errp);
946 
947 /* Store a list of slave devices of virtual volume specified by @syspath into
948  * @fs */
949 static void build_guest_fsinfo_for_virtual_device(char const *syspath,
950                                                   GuestFilesystemInfo *fs,
951                                                   Error **errp)
952 {
953     DIR *dir;
954     char *dirpath;
955     struct dirent *entry;
956 
957     dirpath = g_strdup_printf("%s/slaves", syspath);
958     dir = opendir(dirpath);
959     if (!dir) {
960         error_setg_errno(errp, errno, "opendir(\"%s\")", dirpath);
961         g_free(dirpath);
962         return;
963     }
964 
965     for (;;) {
966         errno = 0;
967         entry = readdir(dir);
968         if (entry == NULL) {
969             if (errno) {
970                 error_setg_errno(errp, errno, "readdir(\"%s\")", dirpath);
971             }
972             break;
973         }
974 
975         if (entry->d_type == DT_LNK) {
976             char *path;
977 
978             g_debug(" slave device '%s'", entry->d_name);
979             path = g_strdup_printf("%s/slaves/%s", syspath, entry->d_name);
980             build_guest_fsinfo_for_device(path, fs, errp);
981             g_free(path);
982 
983             if (*errp) {
984                 break;
985             }
986         }
987     }
988 
989     g_free(dirpath);
990     closedir(dir);
991 }
992 
993 /* Dispatch to functions for virtual/real device */
994 static void build_guest_fsinfo_for_device(char const *devpath,
995                                           GuestFilesystemInfo *fs,
996                                           Error **errp)
997 {
998     char *syspath = realpath(devpath, NULL);
999 
1000     if (!syspath) {
1001         error_setg_errno(errp, errno, "realpath(\"%s\")", devpath);
1002         return;
1003     }
1004 
1005     if (!fs->name) {
1006         fs->name = g_strdup(basename(syspath));
1007     }
1008 
1009     g_debug("  parse sysfs path '%s'", syspath);
1010 
1011     if (strstr(syspath, "/devices/virtual/block/")) {
1012         build_guest_fsinfo_for_virtual_device(syspath, fs, errp);
1013     } else {
1014         build_guest_fsinfo_for_real_device(syspath, fs, errp);
1015     }
1016 
1017     free(syspath);
1018 }
1019 
1020 /* Return a list of the disk device(s)' info which @mount lies on */
1021 static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount,
1022                                                Error **errp)
1023 {
1024     GuestFilesystemInfo *fs = g_malloc0(sizeof(*fs));
1025     char *devpath = g_strdup_printf("/sys/dev/block/%u:%u",
1026                                     mount->devmajor, mount->devminor);
1027 
1028     fs->mountpoint = g_strdup(mount->dirname);
1029     fs->type = g_strdup(mount->devtype);
1030     build_guest_fsinfo_for_device(devpath, fs, errp);
1031 
1032     g_free(devpath);
1033     return fs;
1034 }
1035 
1036 GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
1037 {
1038     FsMountList mounts;
1039     struct FsMount *mount;
1040     GuestFilesystemInfoList *new, *ret = NULL;
1041     Error *local_err = NULL;
1042 
1043     QTAILQ_INIT(&mounts);
1044     build_fs_mount_list(&mounts, &local_err);
1045     if (local_err) {
1046         error_propagate(errp, local_err);
1047         return NULL;
1048     }
1049 
1050     QTAILQ_FOREACH(mount, &mounts, next) {
1051         g_debug("Building guest fsinfo for '%s'", mount->dirname);
1052 
1053         new = g_malloc0(sizeof(*ret));
1054         new->value = build_guest_fsinfo(mount, &local_err);
1055         new->next = ret;
1056         ret = new;
1057         if (local_err) {
1058             error_propagate(errp, local_err);
1059             qapi_free_GuestFilesystemInfoList(ret);
1060             ret = NULL;
1061             break;
1062         }
1063     }
1064 
1065     free_fs_mount_list(&mounts);
1066     return ret;
1067 }
1068 
1069 
1070 typedef enum {
1071     FSFREEZE_HOOK_THAW = 0,
1072     FSFREEZE_HOOK_FREEZE,
1073 } FsfreezeHookArg;
1074 
1075 static const char *fsfreeze_hook_arg_string[] = {
1076     "thaw",
1077     "freeze",
1078 };
1079 
1080 static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **errp)
1081 {
1082     int status;
1083     pid_t pid;
1084     const char *hook;
1085     const char *arg_str = fsfreeze_hook_arg_string[arg];
1086     Error *local_err = NULL;
1087 
1088     hook = ga_fsfreeze_hook(ga_state);
1089     if (!hook) {
1090         return;
1091     }
1092     if (access(hook, X_OK) != 0) {
1093         error_setg_errno(errp, errno, "can't access fsfreeze hook '%s'", hook);
1094         return;
1095     }
1096 
1097     slog("executing fsfreeze hook with arg '%s'", arg_str);
1098     pid = fork();
1099     if (pid == 0) {
1100         setsid();
1101         reopen_fd_to_null(0);
1102         reopen_fd_to_null(1);
1103         reopen_fd_to_null(2);
1104 
1105         execle(hook, hook, arg_str, NULL, environ);
1106         _exit(EXIT_FAILURE);
1107     } else if (pid < 0) {
1108         error_setg_errno(errp, errno, "failed to create child process");
1109         return;
1110     }
1111 
1112     ga_wait_child(pid, &status, &local_err);
1113     if (local_err) {
1114         error_propagate(errp, local_err);
1115         return;
1116     }
1117 
1118     if (!WIFEXITED(status)) {
1119         error_setg(errp, "fsfreeze hook has terminated abnormally");
1120         return;
1121     }
1122 
1123     status = WEXITSTATUS(status);
1124     if (status) {
1125         error_setg(errp, "fsfreeze hook has failed with status %d", status);
1126         return;
1127     }
1128 }
1129 
1130 /*
1131  * Return status of freeze/thaw
1132  */
1133 GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
1134 {
1135     if (ga_is_frozen(ga_state)) {
1136         return GUEST_FSFREEZE_STATUS_FROZEN;
1137     }
1138 
1139     return GUEST_FSFREEZE_STATUS_THAWED;
1140 }
1141 
1142 int64_t qmp_guest_fsfreeze_freeze(Error **errp)
1143 {
1144     return qmp_guest_fsfreeze_freeze_list(false, NULL, errp);
1145 }
1146 
1147 /*
1148  * Walk list of mounted file systems in the guest, and freeze the ones which
1149  * are real local file systems.
1150  */
1151 int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
1152                                        strList *mountpoints,
1153                                        Error **errp)
1154 {
1155     int ret = 0, i = 0;
1156     strList *list;
1157     FsMountList mounts;
1158     struct FsMount *mount;
1159     Error *local_err = NULL;
1160     int fd;
1161 
1162     slog("guest-fsfreeze called");
1163 
1164     execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err);
1165     if (local_err) {
1166         error_propagate(errp, local_err);
1167         return -1;
1168     }
1169 
1170     QTAILQ_INIT(&mounts);
1171     build_fs_mount_list(&mounts, &local_err);
1172     if (local_err) {
1173         error_propagate(errp, local_err);
1174         return -1;
1175     }
1176 
1177     /* cannot risk guest agent blocking itself on a write in this state */
1178     ga_set_frozen(ga_state);
1179 
1180     QTAILQ_FOREACH_REVERSE(mount, &mounts, FsMountList, next) {
1181         /* To issue fsfreeze in the reverse order of mounts, check if the
1182          * mount is listed in the list here */
1183         if (has_mountpoints) {
1184             for (list = mountpoints; list; list = list->next) {
1185                 if (strcmp(list->value, mount->dirname) == 0) {
1186                     break;
1187                 }
1188             }
1189             if (!list) {
1190                 continue;
1191             }
1192         }
1193 
1194         fd = qemu_open(mount->dirname, O_RDONLY);
1195         if (fd == -1) {
1196             error_setg_errno(errp, errno, "failed to open %s", mount->dirname);
1197             goto error;
1198         }
1199 
1200         /* we try to cull filesytems we know won't work in advance, but other
1201          * filesytems may not implement fsfreeze for less obvious reasons.
1202          * these will report EOPNOTSUPP. we simply ignore these when tallying
1203          * the number of frozen filesystems.
1204          *
1205          * any other error means a failure to freeze a filesystem we
1206          * expect to be freezable, so return an error in those cases
1207          * and return system to thawed state.
1208          */
1209         ret = ioctl(fd, FIFREEZE);
1210         if (ret == -1) {
1211             if (errno != EOPNOTSUPP) {
1212                 error_setg_errno(errp, errno, "failed to freeze %s",
1213                                  mount->dirname);
1214                 close(fd);
1215                 goto error;
1216             }
1217         } else {
1218             i++;
1219         }
1220         close(fd);
1221     }
1222 
1223     free_fs_mount_list(&mounts);
1224     return i;
1225 
1226 error:
1227     free_fs_mount_list(&mounts);
1228     qmp_guest_fsfreeze_thaw(NULL);
1229     return 0;
1230 }
1231 
1232 /*
1233  * Walk list of frozen file systems in the guest, and thaw them.
1234  */
1235 int64_t qmp_guest_fsfreeze_thaw(Error **errp)
1236 {
1237     int ret;
1238     FsMountList mounts;
1239     FsMount *mount;
1240     int fd, i = 0, logged;
1241     Error *local_err = NULL;
1242 
1243     QTAILQ_INIT(&mounts);
1244     build_fs_mount_list(&mounts, &local_err);
1245     if (local_err) {
1246         error_propagate(errp, local_err);
1247         return 0;
1248     }
1249 
1250     QTAILQ_FOREACH(mount, &mounts, next) {
1251         logged = false;
1252         fd = qemu_open(mount->dirname, O_RDONLY);
1253         if (fd == -1) {
1254             continue;
1255         }
1256         /* we have no way of knowing whether a filesystem was actually unfrozen
1257          * as a result of a successful call to FITHAW, only that if an error
1258          * was returned the filesystem was *not* unfrozen by that particular
1259          * call.
1260          *
1261          * since multiple preceding FIFREEZEs require multiple calls to FITHAW
1262          * to unfreeze, continuing issuing FITHAW until an error is returned,
1263          * in which case either the filesystem is in an unfreezable state, or,
1264          * more likely, it was thawed previously (and remains so afterward).
1265          *
1266          * also, since the most recent successful call is the one that did
1267          * the actual unfreeze, we can use this to provide an accurate count
1268          * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which
1269          * may * be useful for determining whether a filesystem was unfrozen
1270          * during the freeze/thaw phase by a process other than qemu-ga.
1271          */
1272         do {
1273             ret = ioctl(fd, FITHAW);
1274             if (ret == 0 && !logged) {
1275                 i++;
1276                 logged = true;
1277             }
1278         } while (ret == 0);
1279         close(fd);
1280     }
1281 
1282     ga_unset_frozen(ga_state);
1283     free_fs_mount_list(&mounts);
1284 
1285     execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, errp);
1286 
1287     return i;
1288 }
1289 
1290 static void guest_fsfreeze_cleanup(void)
1291 {
1292     Error *err = NULL;
1293 
1294     if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
1295         qmp_guest_fsfreeze_thaw(&err);
1296         if (err) {
1297             slog("failed to clean up frozen filesystems: %s",
1298                  error_get_pretty(err));
1299             error_free(err);
1300         }
1301     }
1302 }
1303 #endif /* CONFIG_FSFREEZE */
1304 
1305 #if defined(CONFIG_FSTRIM)
1306 /*
1307  * Walk list of mounted file systems in the guest, and trim them.
1308  */
1309 GuestFilesystemTrimResponse *
1310 qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
1311 {
1312     GuestFilesystemTrimResponse *response;
1313     GuestFilesystemTrimResultList *list;
1314     GuestFilesystemTrimResult *result;
1315     int ret = 0;
1316     FsMountList mounts;
1317     struct FsMount *mount;
1318     int fd;
1319     Error *local_err = NULL;
1320     struct fstrim_range r;
1321 
1322     slog("guest-fstrim called");
1323 
1324     QTAILQ_INIT(&mounts);
1325     build_fs_mount_list(&mounts, &local_err);
1326     if (local_err) {
1327         error_propagate(errp, local_err);
1328         return NULL;
1329     }
1330 
1331     response = g_malloc0(sizeof(*response));
1332 
1333     QTAILQ_FOREACH(mount, &mounts, next) {
1334         result = g_malloc0(sizeof(*result));
1335         result->path = g_strdup(mount->dirname);
1336 
1337         list = g_malloc0(sizeof(*list));
1338         list->value = result;
1339         list->next = response->paths;
1340         response->paths = list;
1341 
1342         fd = qemu_open(mount->dirname, O_RDONLY);
1343         if (fd == -1) {
1344             result->error = g_strdup_printf("failed to open: %s",
1345                                             strerror(errno));
1346             result->has_error = true;
1347             continue;
1348         }
1349 
1350         /* We try to cull filesytems we know won't work in advance, but other
1351          * filesytems may not implement fstrim for less obvious reasons.  These
1352          * will report EOPNOTSUPP; while in some other cases ENOTTY will be
1353          * reported (e.g. CD-ROMs).
1354          * Any other error means an unexpected error.
1355          */
1356         r.start = 0;
1357         r.len = -1;
1358         r.minlen = has_minimum ? minimum : 0;
1359         ret = ioctl(fd, FITRIM, &r);
1360         if (ret == -1) {
1361             result->has_error = true;
1362             if (errno == ENOTTY || errno == EOPNOTSUPP) {
1363                 result->error = g_strdup("trim not supported");
1364             } else {
1365                 result->error = g_strdup_printf("failed to trim: %s",
1366                                                 strerror(errno));
1367             }
1368             close(fd);
1369             continue;
1370         }
1371 
1372         result->has_minimum = true;
1373         result->minimum = r.minlen;
1374         result->has_trimmed = true;
1375         result->trimmed = r.len;
1376         close(fd);
1377     }
1378 
1379     free_fs_mount_list(&mounts);
1380     return response;
1381 }
1382 #endif /* CONFIG_FSTRIM */
1383 
1384 
1385 #define LINUX_SYS_STATE_FILE "/sys/power/state"
1386 #define SUSPEND_SUPPORTED 0
1387 #define SUSPEND_NOT_SUPPORTED 1
1388 
1389 static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
1390                                const char *sysfile_str, Error **errp)
1391 {
1392     Error *local_err = NULL;
1393     char *pmutils_path;
1394     pid_t pid;
1395     int status;
1396 
1397     pmutils_path = g_find_program_in_path(pmutils_bin);
1398 
1399     pid = fork();
1400     if (!pid) {
1401         char buf[32]; /* hopefully big enough */
1402         ssize_t ret;
1403         int fd;
1404 
1405         setsid();
1406         reopen_fd_to_null(0);
1407         reopen_fd_to_null(1);
1408         reopen_fd_to_null(2);
1409 
1410         if (pmutils_path) {
1411             execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
1412         }
1413 
1414         /*
1415          * If we get here either pm-utils is not installed or execle() has
1416          * failed. Let's try the manual method if the caller wants it.
1417          */
1418 
1419         if (!sysfile_str) {
1420             _exit(SUSPEND_NOT_SUPPORTED);
1421         }
1422 
1423         fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
1424         if (fd < 0) {
1425             _exit(SUSPEND_NOT_SUPPORTED);
1426         }
1427 
1428         ret = read(fd, buf, sizeof(buf)-1);
1429         if (ret <= 0) {
1430             _exit(SUSPEND_NOT_SUPPORTED);
1431         }
1432         buf[ret] = '\0';
1433 
1434         if (strstr(buf, sysfile_str)) {
1435             _exit(SUSPEND_SUPPORTED);
1436         }
1437 
1438         _exit(SUSPEND_NOT_SUPPORTED);
1439     } else if (pid < 0) {
1440         error_setg_errno(errp, errno, "failed to create child process");
1441         goto out;
1442     }
1443 
1444     ga_wait_child(pid, &status, &local_err);
1445     if (local_err) {
1446         error_propagate(errp, local_err);
1447         goto out;
1448     }
1449 
1450     if (!WIFEXITED(status)) {
1451         error_setg(errp, "child process has terminated abnormally");
1452         goto out;
1453     }
1454 
1455     switch (WEXITSTATUS(status)) {
1456     case SUSPEND_SUPPORTED:
1457         goto out;
1458     case SUSPEND_NOT_SUPPORTED:
1459         error_setg(errp,
1460                    "the requested suspend mode is not supported by the guest");
1461         goto out;
1462     default:
1463         error_setg(errp,
1464                    "the helper program '%s' returned an unexpected exit status"
1465                    " code (%d)", pmutils_path, WEXITSTATUS(status));
1466         goto out;
1467     }
1468 
1469 out:
1470     g_free(pmutils_path);
1471 }
1472 
1473 static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
1474                           Error **errp)
1475 {
1476     Error *local_err = NULL;
1477     char *pmutils_path;
1478     pid_t pid;
1479     int status;
1480 
1481     pmutils_path = g_find_program_in_path(pmutils_bin);
1482 
1483     pid = fork();
1484     if (pid == 0) {
1485         /* child */
1486         int fd;
1487 
1488         setsid();
1489         reopen_fd_to_null(0);
1490         reopen_fd_to_null(1);
1491         reopen_fd_to_null(2);
1492 
1493         if (pmutils_path) {
1494             execle(pmutils_path, pmutils_bin, NULL, environ);
1495         }
1496 
1497         /*
1498          * If we get here either pm-utils is not installed or execle() has
1499          * failed. Let's try the manual method if the caller wants it.
1500          */
1501 
1502         if (!sysfile_str) {
1503             _exit(EXIT_FAILURE);
1504         }
1505 
1506         fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
1507         if (fd < 0) {
1508             _exit(EXIT_FAILURE);
1509         }
1510 
1511         if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
1512             _exit(EXIT_FAILURE);
1513         }
1514 
1515         _exit(EXIT_SUCCESS);
1516     } else if (pid < 0) {
1517         error_setg_errno(errp, errno, "failed to create child process");
1518         goto out;
1519     }
1520 
1521     ga_wait_child(pid, &status, &local_err);
1522     if (local_err) {
1523         error_propagate(errp, local_err);
1524         goto out;
1525     }
1526 
1527     if (!WIFEXITED(status)) {
1528         error_setg(errp, "child process has terminated abnormally");
1529         goto out;
1530     }
1531 
1532     if (WEXITSTATUS(status)) {
1533         error_setg(errp, "child process has failed to suspend");
1534         goto out;
1535     }
1536 
1537 out:
1538     g_free(pmutils_path);
1539 }
1540 
1541 void qmp_guest_suspend_disk(Error **errp)
1542 {
1543     Error *local_err = NULL;
1544 
1545     bios_supports_mode("pm-is-supported", "--hibernate", "disk", &local_err);
1546     if (local_err) {
1547         error_propagate(errp, local_err);
1548         return;
1549     }
1550 
1551     guest_suspend("pm-hibernate", "disk", errp);
1552 }
1553 
1554 void qmp_guest_suspend_ram(Error **errp)
1555 {
1556     Error *local_err = NULL;
1557 
1558     bios_supports_mode("pm-is-supported", "--suspend", "mem", &local_err);
1559     if (local_err) {
1560         error_propagate(errp, local_err);
1561         return;
1562     }
1563 
1564     guest_suspend("pm-suspend", "mem", errp);
1565 }
1566 
1567 void qmp_guest_suspend_hybrid(Error **errp)
1568 {
1569     Error *local_err = NULL;
1570 
1571     bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL,
1572                        &local_err);
1573     if (local_err) {
1574         error_propagate(errp, local_err);
1575         return;
1576     }
1577 
1578     guest_suspend("pm-suspend-hybrid", NULL, errp);
1579 }
1580 
1581 static GuestNetworkInterfaceList *
1582 guest_find_interface(GuestNetworkInterfaceList *head,
1583                      const char *name)
1584 {
1585     for (; head; head = head->next) {
1586         if (strcmp(head->value->name, name) == 0) {
1587             break;
1588         }
1589     }
1590 
1591     return head;
1592 }
1593 
1594 /*
1595  * Build information about guest interfaces
1596  */
1597 GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
1598 {
1599     GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
1600     struct ifaddrs *ifap, *ifa;
1601 
1602     if (getifaddrs(&ifap) < 0) {
1603         error_setg_errno(errp, errno, "getifaddrs failed");
1604         goto error;
1605     }
1606 
1607     for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1608         GuestNetworkInterfaceList *info;
1609         GuestIpAddressList **address_list = NULL, *address_item = NULL;
1610         char addr4[INET_ADDRSTRLEN];
1611         char addr6[INET6_ADDRSTRLEN];
1612         int sock;
1613         struct ifreq ifr;
1614         unsigned char *mac_addr;
1615         void *p;
1616 
1617         g_debug("Processing %s interface", ifa->ifa_name);
1618 
1619         info = guest_find_interface(head, ifa->ifa_name);
1620 
1621         if (!info) {
1622             info = g_malloc0(sizeof(*info));
1623             info->value = g_malloc0(sizeof(*info->value));
1624             info->value->name = g_strdup(ifa->ifa_name);
1625 
1626             if (!cur_item) {
1627                 head = cur_item = info;
1628             } else {
1629                 cur_item->next = info;
1630                 cur_item = info;
1631             }
1632         }
1633 
1634         if (!info->value->has_hardware_address &&
1635             ifa->ifa_flags & SIOCGIFHWADDR) {
1636             /* we haven't obtained HW address yet */
1637             sock = socket(PF_INET, SOCK_STREAM, 0);
1638             if (sock == -1) {
1639                 error_setg_errno(errp, errno, "failed to create socket");
1640                 goto error;
1641             }
1642 
1643             memset(&ifr, 0, sizeof(ifr));
1644             pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->value->name);
1645             if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
1646                 error_setg_errno(errp, errno,
1647                                  "failed to get MAC address of %s",
1648                                  ifa->ifa_name);
1649                 close(sock);
1650                 goto error;
1651             }
1652 
1653             close(sock);
1654             mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
1655 
1656             info->value->hardware_address =
1657                 g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x",
1658                                 (int) mac_addr[0], (int) mac_addr[1],
1659                                 (int) mac_addr[2], (int) mac_addr[3],
1660                                 (int) mac_addr[4], (int) mac_addr[5]);
1661 
1662             info->value->has_hardware_address = true;
1663         }
1664 
1665         if (ifa->ifa_addr &&
1666             ifa->ifa_addr->sa_family == AF_INET) {
1667             /* interface with IPv4 address */
1668             p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
1669             if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
1670                 error_setg_errno(errp, errno, "inet_ntop failed");
1671                 goto error;
1672             }
1673 
1674             address_item = g_malloc0(sizeof(*address_item));
1675             address_item->value = g_malloc0(sizeof(*address_item->value));
1676             address_item->value->ip_address = g_strdup(addr4);
1677             address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
1678 
1679             if (ifa->ifa_netmask) {
1680                 /* Count the number of set bits in netmask.
1681                  * This is safe as '1' and '0' cannot be shuffled in netmask. */
1682                 p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
1683                 address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
1684             }
1685         } else if (ifa->ifa_addr &&
1686                    ifa->ifa_addr->sa_family == AF_INET6) {
1687             /* interface with IPv6 address */
1688             p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
1689             if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
1690                 error_setg_errno(errp, errno, "inet_ntop failed");
1691                 goto error;
1692             }
1693 
1694             address_item = g_malloc0(sizeof(*address_item));
1695             address_item->value = g_malloc0(sizeof(*address_item->value));
1696             address_item->value->ip_address = g_strdup(addr6);
1697             address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
1698 
1699             if (ifa->ifa_netmask) {
1700                 /* Count the number of set bits in netmask.
1701                  * This is safe as '1' and '0' cannot be shuffled in netmask. */
1702                 p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
1703                 address_item->value->prefix =
1704                     ctpop32(((uint32_t *) p)[0]) +
1705                     ctpop32(((uint32_t *) p)[1]) +
1706                     ctpop32(((uint32_t *) p)[2]) +
1707                     ctpop32(((uint32_t *) p)[3]);
1708             }
1709         }
1710 
1711         if (!address_item) {
1712             continue;
1713         }
1714 
1715         address_list = &info->value->ip_addresses;
1716 
1717         while (*address_list && (*address_list)->next) {
1718             address_list = &(*address_list)->next;
1719         }
1720 
1721         if (!*address_list) {
1722             *address_list = address_item;
1723         } else {
1724             (*address_list)->next = address_item;
1725         }
1726 
1727         info->value->has_ip_addresses = true;
1728 
1729 
1730     }
1731 
1732     freeifaddrs(ifap);
1733     return head;
1734 
1735 error:
1736     freeifaddrs(ifap);
1737     qapi_free_GuestNetworkInterfaceList(head);
1738     return NULL;
1739 }
1740 
1741 #define SYSCONF_EXACT(name, errp) sysconf_exact((name), #name, (errp))
1742 
1743 static long sysconf_exact(int name, const char *name_str, Error **errp)
1744 {
1745     long ret;
1746 
1747     errno = 0;
1748     ret = sysconf(name);
1749     if (ret == -1) {
1750         if (errno == 0) {
1751             error_setg(errp, "sysconf(%s): value indefinite", name_str);
1752         } else {
1753             error_setg_errno(errp, errno, "sysconf(%s)", name_str);
1754         }
1755     }
1756     return ret;
1757 }
1758 
1759 /* Transfer online/offline status between @vcpu and the guest system.
1760  *
1761  * On input either @errp or *@errp must be NULL.
1762  *
1763  * In system-to-@vcpu direction, the following @vcpu fields are accessed:
1764  * - R: vcpu->logical_id
1765  * - W: vcpu->online
1766  * - W: vcpu->can_offline
1767  *
1768  * In @vcpu-to-system direction, the following @vcpu fields are accessed:
1769  * - R: vcpu->logical_id
1770  * - R: vcpu->online
1771  *
1772  * Written members remain unmodified on error.
1773  */
1774 static void transfer_vcpu(GuestLogicalProcessor *vcpu, bool sys2vcpu,
1775                           Error **errp)
1776 {
1777     char *dirpath;
1778     int dirfd;
1779 
1780     dirpath = g_strdup_printf("/sys/devices/system/cpu/cpu%" PRId64 "/",
1781                               vcpu->logical_id);
1782     dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
1783     if (dirfd == -1) {
1784         error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
1785     } else {
1786         static const char fn[] = "online";
1787         int fd;
1788         int res;
1789 
1790         fd = openat(dirfd, fn, sys2vcpu ? O_RDONLY : O_RDWR);
1791         if (fd == -1) {
1792             if (errno != ENOENT) {
1793                 error_setg_errno(errp, errno, "open(\"%s/%s\")", dirpath, fn);
1794             } else if (sys2vcpu) {
1795                 vcpu->online = true;
1796                 vcpu->can_offline = false;
1797             } else if (!vcpu->online) {
1798                 error_setg(errp, "logical processor #%" PRId64 " can't be "
1799                            "offlined", vcpu->logical_id);
1800             } /* otherwise pretend successful re-onlining */
1801         } else {
1802             unsigned char status;
1803 
1804             res = pread(fd, &status, 1, 0);
1805             if (res == -1) {
1806                 error_setg_errno(errp, errno, "pread(\"%s/%s\")", dirpath, fn);
1807             } else if (res == 0) {
1808                 error_setg(errp, "pread(\"%s/%s\"): unexpected EOF", dirpath,
1809                            fn);
1810             } else if (sys2vcpu) {
1811                 vcpu->online = (status != '0');
1812                 vcpu->can_offline = true;
1813             } else if (vcpu->online != (status != '0')) {
1814                 status = '0' + vcpu->online;
1815                 if (pwrite(fd, &status, 1, 0) == -1) {
1816                     error_setg_errno(errp, errno, "pwrite(\"%s/%s\")", dirpath,
1817                                      fn);
1818                 }
1819             } /* otherwise pretend successful re-(on|off)-lining */
1820 
1821             res = close(fd);
1822             g_assert(res == 0);
1823         }
1824 
1825         res = close(dirfd);
1826         g_assert(res == 0);
1827     }
1828 
1829     g_free(dirpath);
1830 }
1831 
1832 GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
1833 {
1834     int64_t current;
1835     GuestLogicalProcessorList *head, **link;
1836     long sc_max;
1837     Error *local_err = NULL;
1838 
1839     current = 0;
1840     head = NULL;
1841     link = &head;
1842     sc_max = SYSCONF_EXACT(_SC_NPROCESSORS_CONF, &local_err);
1843 
1844     while (local_err == NULL && current < sc_max) {
1845         GuestLogicalProcessor *vcpu;
1846         GuestLogicalProcessorList *entry;
1847 
1848         vcpu = g_malloc0(sizeof *vcpu);
1849         vcpu->logical_id = current++;
1850         vcpu->has_can_offline = true; /* lolspeak ftw */
1851         transfer_vcpu(vcpu, true, &local_err);
1852 
1853         entry = g_malloc0(sizeof *entry);
1854         entry->value = vcpu;
1855 
1856         *link = entry;
1857         link = &entry->next;
1858     }
1859 
1860     if (local_err == NULL) {
1861         /* there's no guest with zero VCPUs */
1862         g_assert(head != NULL);
1863         return head;
1864     }
1865 
1866     qapi_free_GuestLogicalProcessorList(head);
1867     error_propagate(errp, local_err);
1868     return NULL;
1869 }
1870 
1871 int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
1872 {
1873     int64_t processed;
1874     Error *local_err = NULL;
1875 
1876     processed = 0;
1877     while (vcpus != NULL) {
1878         transfer_vcpu(vcpus->value, false, &local_err);
1879         if (local_err != NULL) {
1880             break;
1881         }
1882         ++processed;
1883         vcpus = vcpus->next;
1884     }
1885 
1886     if (local_err != NULL) {
1887         if (processed == 0) {
1888             error_propagate(errp, local_err);
1889         } else {
1890             error_free(local_err);
1891         }
1892     }
1893 
1894     return processed;
1895 }
1896 
1897 void qmp_guest_set_user_password(const char *username,
1898                                  const char *password,
1899                                  bool crypted,
1900                                  Error **errp)
1901 {
1902     Error *local_err = NULL;
1903     char *passwd_path = NULL;
1904     pid_t pid;
1905     int status;
1906     int datafd[2] = { -1, -1 };
1907     char *rawpasswddata = NULL;
1908     size_t rawpasswdlen;
1909     char *chpasswddata = NULL;
1910     size_t chpasswdlen;
1911 
1912     rawpasswddata = (char *)g_base64_decode(password, &rawpasswdlen);
1913     rawpasswddata = g_renew(char, rawpasswddata, rawpasswdlen + 1);
1914     rawpasswddata[rawpasswdlen] = '\0';
1915 
1916     if (strchr(rawpasswddata, '\n')) {
1917         error_setg(errp, "forbidden characters in raw password");
1918         goto out;
1919     }
1920 
1921     if (strchr(username, '\n') ||
1922         strchr(username, ':')) {
1923         error_setg(errp, "forbidden characters in username");
1924         goto out;
1925     }
1926 
1927     chpasswddata = g_strdup_printf("%s:%s\n", username, rawpasswddata);
1928     chpasswdlen = strlen(chpasswddata);
1929 
1930     passwd_path = g_find_program_in_path("chpasswd");
1931 
1932     if (!passwd_path) {
1933         error_setg(errp, "cannot find 'passwd' program in PATH");
1934         goto out;
1935     }
1936 
1937     if (pipe(datafd) < 0) {
1938         error_setg(errp, "cannot create pipe FDs");
1939         goto out;
1940     }
1941 
1942     pid = fork();
1943     if (pid == 0) {
1944         close(datafd[1]);
1945         /* child */
1946         setsid();
1947         dup2(datafd[0], 0);
1948         reopen_fd_to_null(1);
1949         reopen_fd_to_null(2);
1950 
1951         if (crypted) {
1952             execle(passwd_path, "chpasswd", "-e", NULL, environ);
1953         } else {
1954             execle(passwd_path, "chpasswd", NULL, environ);
1955         }
1956         _exit(EXIT_FAILURE);
1957     } else if (pid < 0) {
1958         error_setg_errno(errp, errno, "failed to create child process");
1959         goto out;
1960     }
1961     close(datafd[0]);
1962     datafd[0] = -1;
1963 
1964     if (qemu_write_full(datafd[1], chpasswddata, chpasswdlen) != chpasswdlen) {
1965         error_setg_errno(errp, errno, "cannot write new account password");
1966         goto out;
1967     }
1968     close(datafd[1]);
1969     datafd[1] = -1;
1970 
1971     ga_wait_child(pid, &status, &local_err);
1972     if (local_err) {
1973         error_propagate(errp, local_err);
1974         goto out;
1975     }
1976 
1977     if (!WIFEXITED(status)) {
1978         error_setg(errp, "child process has terminated abnormally");
1979         goto out;
1980     }
1981 
1982     if (WEXITSTATUS(status)) {
1983         error_setg(errp, "child process has failed to set user password");
1984         goto out;
1985     }
1986 
1987 out:
1988     g_free(chpasswddata);
1989     g_free(rawpasswddata);
1990     g_free(passwd_path);
1991     if (datafd[0] != -1) {
1992         close(datafd[0]);
1993     }
1994     if (datafd[1] != -1) {
1995         close(datafd[1]);
1996     }
1997 }
1998 
1999 static void ga_read_sysfs_file(int dirfd, const char *pathname, char *buf,
2000                                int size, Error **errp)
2001 {
2002     int fd;
2003     int res;
2004 
2005     errno = 0;
2006     fd = openat(dirfd, pathname, O_RDONLY);
2007     if (fd == -1) {
2008         error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
2009         return;
2010     }
2011 
2012     res = pread(fd, buf, size, 0);
2013     if (res == -1) {
2014         error_setg_errno(errp, errno, "pread sysfs file \"%s\"", pathname);
2015     } else if (res == 0) {
2016         error_setg(errp, "pread sysfs file \"%s\": unexpected EOF", pathname);
2017     }
2018     close(fd);
2019 }
2020 
2021 static void ga_write_sysfs_file(int dirfd, const char *pathname,
2022                                 const char *buf, int size, Error **errp)
2023 {
2024     int fd;
2025 
2026     errno = 0;
2027     fd = openat(dirfd, pathname, O_WRONLY);
2028     if (fd == -1) {
2029         error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
2030         return;
2031     }
2032 
2033     if (pwrite(fd, buf, size, 0) == -1) {
2034         error_setg_errno(errp, errno, "pwrite sysfs file \"%s\"", pathname);
2035     }
2036 
2037     close(fd);
2038 }
2039 
2040 /* Transfer online/offline status between @mem_blk and the guest system.
2041  *
2042  * On input either @errp or *@errp must be NULL.
2043  *
2044  * In system-to-@mem_blk direction, the following @mem_blk fields are accessed:
2045  * - R: mem_blk->phys_index
2046  * - W: mem_blk->online
2047  * - W: mem_blk->can_offline
2048  *
2049  * In @mem_blk-to-system direction, the following @mem_blk fields are accessed:
2050  * - R: mem_blk->phys_index
2051  * - R: mem_blk->online
2052  *-  R: mem_blk->can_offline
2053  * Written members remain unmodified on error.
2054  */
2055 static void transfer_memory_block(GuestMemoryBlock *mem_blk, bool sys2memblk,
2056                                   GuestMemoryBlockResponse *result,
2057                                   Error **errp)
2058 {
2059     char *dirpath;
2060     int dirfd;
2061     char *status;
2062     Error *local_err = NULL;
2063 
2064     if (!sys2memblk) {
2065         DIR *dp;
2066 
2067         if (!result) {
2068             error_setg(errp, "Internal error, 'result' should not be NULL");
2069             return;
2070         }
2071         errno = 0;
2072         dp = opendir("/sys/devices/system/memory/");
2073          /* if there is no 'memory' directory in sysfs,
2074          * we think this VM does not support online/offline memory block,
2075          * any other solution?
2076          */
2077         if (!dp && errno == ENOENT) {
2078             result->response =
2079                 GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
2080             goto out1;
2081         }
2082         closedir(dp);
2083     }
2084 
2085     dirpath = g_strdup_printf("/sys/devices/system/memory/memory%" PRId64 "/",
2086                               mem_blk->phys_index);
2087     dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
2088     if (dirfd == -1) {
2089         if (sys2memblk) {
2090             error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
2091         } else {
2092             if (errno == ENOENT) {
2093                 result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_NOT_FOUND;
2094             } else {
2095                 result->response =
2096                     GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
2097             }
2098         }
2099         g_free(dirpath);
2100         goto out1;
2101     }
2102     g_free(dirpath);
2103 
2104     status = g_malloc0(10);
2105     ga_read_sysfs_file(dirfd, "state", status, 10, &local_err);
2106     if (local_err) {
2107         /* treat with sysfs file that not exist in old kernel */
2108         if (errno == ENOENT) {
2109             error_free(local_err);
2110             if (sys2memblk) {
2111                 mem_blk->online = true;
2112                 mem_blk->can_offline = false;
2113             } else if (!mem_blk->online) {
2114                 result->response =
2115                     GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
2116             }
2117         } else {
2118             if (sys2memblk) {
2119                 error_propagate(errp, local_err);
2120             } else {
2121                 result->response =
2122                     GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
2123             }
2124         }
2125         goto out2;
2126     }
2127 
2128     if (sys2memblk) {
2129         char removable = '0';
2130 
2131         mem_blk->online = (strncmp(status, "online", 6) == 0);
2132 
2133         ga_read_sysfs_file(dirfd, "removable", &removable, 1, &local_err);
2134         if (local_err) {
2135             /* if no 'removable' file, it doesn't support offline mem blk */
2136             if (errno == ENOENT) {
2137                 error_free(local_err);
2138                 mem_blk->can_offline = false;
2139             } else {
2140                 error_propagate(errp, local_err);
2141             }
2142         } else {
2143             mem_blk->can_offline = (removable != '0');
2144         }
2145     } else {
2146         if (mem_blk->online != (strncmp(status, "online", 6) == 0)) {
2147             char *new_state = mem_blk->online ? g_strdup("online") :
2148                                                 g_strdup("offline");
2149 
2150             ga_write_sysfs_file(dirfd, "state", new_state, strlen(new_state),
2151                                 &local_err);
2152             g_free(new_state);
2153             if (local_err) {
2154                 error_free(local_err);
2155                 result->response =
2156                     GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
2157                 goto out2;
2158             }
2159 
2160             result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_SUCCESS;
2161             result->has_error_code = false;
2162         } /* otherwise pretend successful re-(on|off)-lining */
2163     }
2164     g_free(status);
2165     close(dirfd);
2166     return;
2167 
2168 out2:
2169     g_free(status);
2170     close(dirfd);
2171 out1:
2172     if (!sys2memblk) {
2173         result->has_error_code = true;
2174         result->error_code = errno;
2175     }
2176 }
2177 
2178 GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
2179 {
2180     GuestMemoryBlockList *head, **link;
2181     Error *local_err = NULL;
2182     struct dirent *de;
2183     DIR *dp;
2184 
2185     head = NULL;
2186     link = &head;
2187 
2188     dp = opendir("/sys/devices/system/memory/");
2189     if (!dp) {
2190         /* it's ok if this happens to be a system that doesn't expose
2191          * memory blocks via sysfs, but otherwise we should report
2192          * an error
2193          */
2194         if (errno != ENOENT) {
2195             error_setg_errno(errp, errno, "Can't open directory"
2196                              "\"/sys/devices/system/memory/\"\n");
2197         }
2198         return NULL;
2199     }
2200 
2201     /* Note: the phys_index of memory block may be discontinuous,
2202      * this is because a memblk is the unit of the Sparse Memory design, which
2203      * allows discontinuous memory ranges (ex. NUMA), so here we should
2204      * traverse the memory block directory.
2205      */
2206     while ((de = readdir(dp)) != NULL) {
2207         GuestMemoryBlock *mem_blk;
2208         GuestMemoryBlockList *entry;
2209 
2210         if ((strncmp(de->d_name, "memory", 6) != 0) ||
2211             !(de->d_type & DT_DIR)) {
2212             continue;
2213         }
2214 
2215         mem_blk = g_malloc0(sizeof *mem_blk);
2216         /* The d_name is "memoryXXX",  phys_index is block id, same as XXX */
2217         mem_blk->phys_index = strtoul(&de->d_name[6], NULL, 10);
2218         mem_blk->has_can_offline = true; /* lolspeak ftw */
2219         transfer_memory_block(mem_blk, true, NULL, &local_err);
2220 
2221         entry = g_malloc0(sizeof *entry);
2222         entry->value = mem_blk;
2223 
2224         *link = entry;
2225         link = &entry->next;
2226     }
2227 
2228     closedir(dp);
2229     if (local_err == NULL) {
2230         /* there's no guest with zero memory blocks */
2231         if (head == NULL) {
2232             error_setg(errp, "guest reported zero memory blocks!");
2233         }
2234         return head;
2235     }
2236 
2237     qapi_free_GuestMemoryBlockList(head);
2238     error_propagate(errp, local_err);
2239     return NULL;
2240 }
2241 
2242 GuestMemoryBlockResponseList *
2243 qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
2244 {
2245     GuestMemoryBlockResponseList *head, **link;
2246     Error *local_err = NULL;
2247 
2248     head = NULL;
2249     link = &head;
2250 
2251     while (mem_blks != NULL) {
2252         GuestMemoryBlockResponse *result;
2253         GuestMemoryBlockResponseList *entry;
2254         GuestMemoryBlock *current_mem_blk = mem_blks->value;
2255 
2256         result = g_malloc0(sizeof(*result));
2257         result->phys_index = current_mem_blk->phys_index;
2258         transfer_memory_block(current_mem_blk, false, result, &local_err);
2259         if (local_err) { /* should never happen */
2260             goto err;
2261         }
2262         entry = g_malloc0(sizeof *entry);
2263         entry->value = result;
2264 
2265         *link = entry;
2266         link = &entry->next;
2267         mem_blks = mem_blks->next;
2268     }
2269 
2270     return head;
2271 err:
2272     qapi_free_GuestMemoryBlockResponseList(head);
2273     error_propagate(errp, local_err);
2274     return NULL;
2275 }
2276 
2277 GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
2278 {
2279     Error *local_err = NULL;
2280     char *dirpath;
2281     int dirfd;
2282     char *buf;
2283     GuestMemoryBlockInfo *info;
2284 
2285     dirpath = g_strdup_printf("/sys/devices/system/memory/");
2286     dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
2287     if (dirfd == -1) {
2288         error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
2289         g_free(dirpath);
2290         return NULL;
2291     }
2292     g_free(dirpath);
2293 
2294     buf = g_malloc0(20);
2295     ga_read_sysfs_file(dirfd, "block_size_bytes", buf, 20, &local_err);
2296     close(dirfd);
2297     if (local_err) {
2298         g_free(buf);
2299         error_propagate(errp, local_err);
2300         return NULL;
2301     }
2302 
2303     info = g_new0(GuestMemoryBlockInfo, 1);
2304     info->size = strtol(buf, NULL, 16); /* the unit is bytes */
2305 
2306     g_free(buf);
2307 
2308     return info;
2309 }
2310 
2311 #else /* defined(__linux__) */
2312 
2313 void qmp_guest_suspend_disk(Error **errp)
2314 {
2315     error_setg(errp, QERR_UNSUPPORTED);
2316 }
2317 
2318 void qmp_guest_suspend_ram(Error **errp)
2319 {
2320     error_setg(errp, QERR_UNSUPPORTED);
2321 }
2322 
2323 void qmp_guest_suspend_hybrid(Error **errp)
2324 {
2325     error_setg(errp, QERR_UNSUPPORTED);
2326 }
2327 
2328 GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
2329 {
2330     error_setg(errp, QERR_UNSUPPORTED);
2331     return NULL;
2332 }
2333 
2334 GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
2335 {
2336     error_setg(errp, QERR_UNSUPPORTED);
2337     return NULL;
2338 }
2339 
2340 int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
2341 {
2342     error_setg(errp, QERR_UNSUPPORTED);
2343     return -1;
2344 }
2345 
2346 void qmp_guest_set_user_password(const char *username,
2347                                  const char *password,
2348                                  bool crypted,
2349                                  Error **errp)
2350 {
2351     error_setg(errp, QERR_UNSUPPORTED);
2352 }
2353 
2354 GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
2355 {
2356     error_setg(errp, QERR_UNSUPPORTED);
2357     return NULL;
2358 }
2359 
2360 GuestMemoryBlockResponseList *
2361 qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
2362 {
2363     error_setg(errp, QERR_UNSUPPORTED);
2364     return NULL;
2365 }
2366 
2367 GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
2368 {
2369     error_setg(errp, QERR_UNSUPPORTED);
2370     return NULL;
2371 }
2372 
2373 #endif
2374 
2375 #if !defined(CONFIG_FSFREEZE)
2376 
2377 GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
2378 {
2379     error_setg(errp, QERR_UNSUPPORTED);
2380     return NULL;
2381 }
2382 
2383 GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
2384 {
2385     error_setg(errp, QERR_UNSUPPORTED);
2386 
2387     return 0;
2388 }
2389 
2390 int64_t qmp_guest_fsfreeze_freeze(Error **errp)
2391 {
2392     error_setg(errp, QERR_UNSUPPORTED);
2393 
2394     return 0;
2395 }
2396 
2397 int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
2398                                        strList *mountpoints,
2399                                        Error **errp)
2400 {
2401     error_setg(errp, QERR_UNSUPPORTED);
2402 
2403     return 0;
2404 }
2405 
2406 int64_t qmp_guest_fsfreeze_thaw(Error **errp)
2407 {
2408     error_setg(errp, QERR_UNSUPPORTED);
2409 
2410     return 0;
2411 }
2412 #endif /* CONFIG_FSFREEZE */
2413 
2414 #if !defined(CONFIG_FSTRIM)
2415 GuestFilesystemTrimResponse *
2416 qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
2417 {
2418     error_setg(errp, QERR_UNSUPPORTED);
2419     return NULL;
2420 }
2421 #endif
2422 
2423 /* add unsupported commands to the blacklist */
2424 GList *ga_command_blacklist_init(GList *blacklist)
2425 {
2426 #if !defined(__linux__)
2427     {
2428         const char *list[] = {
2429             "guest-suspend-disk", "guest-suspend-ram",
2430             "guest-suspend-hybrid", "guest-network-get-interfaces",
2431             "guest-get-vcpus", "guest-set-vcpus",
2432             "guest-get-memory-blocks", "guest-set-memory-blocks",
2433             "guest-get-memory-block-size", NULL};
2434         char **p = (char **)list;
2435 
2436         while (*p) {
2437             blacklist = g_list_append(blacklist, g_strdup(*p++));
2438         }
2439     }
2440 #endif
2441 
2442 #if !defined(CONFIG_FSFREEZE)
2443     {
2444         const char *list[] = {
2445             "guest-get-fsinfo", "guest-fsfreeze-status",
2446             "guest-fsfreeze-freeze", "guest-fsfreeze-freeze-list",
2447             "guest-fsfreeze-thaw", "guest-get-fsinfo", NULL};
2448         char **p = (char **)list;
2449 
2450         while (*p) {
2451             blacklist = g_list_append(blacklist, g_strdup(*p++));
2452         }
2453     }
2454 #endif
2455 
2456 #if !defined(CONFIG_FSTRIM)
2457     blacklist = g_list_append(blacklist, g_strdup("guest-fstrim"));
2458 #endif
2459 
2460     return blacklist;
2461 }
2462 
2463 /* register init/cleanup routines for stateful command groups */
2464 void ga_command_state_init(GAState *s, GACommandState *cs)
2465 {
2466 #if defined(CONFIG_FSFREEZE)
2467     ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
2468 #endif
2469 }
2470