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