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