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