]> git.proxmox.com Git - mirror_qemu.git/blame - qga/commands-posix.c
qga: introduce guest-get-vcpus / guest-set-vcpus with stubs
[mirror_qemu.git] / qga / commands-posix.c
CommitLineData
e3d4d252 1/*
42074a9d 2 * QEMU Guest Agent POSIX-specific command implementations
e3d4d252
MR
3 *
4 * Copyright IBM Corp. 2011
5 *
6 * Authors:
7 * Michael Roth <mdroth@linux.vnet.ibm.com>
3424fc9f 8 * Michal Privoznik <mprivozn@redhat.com>
e3d4d252
MR
9 *
10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
11 * See the COPYING file in the top-level directory.
12 */
13
14#include <glib.h>
e72c3f2e
MR
15#include <sys/types.h>
16#include <sys/ioctl.h>
2c02cbf6 17#include <sys/wait.h>
e72c3f2e
MR
18#include "qga/guest-agent-core.h"
19#include "qga-qmp-commands.h"
7b1b5d19 20#include "qapi/qmp/qerror.h"
1de7afc9
PB
21#include "qemu/queue.h"
22#include "qemu/host-utils.h"
4eb36d40 23
2c02cbf6 24#ifndef CONFIG_HAS_ENVIRON
eecae147
AF
25#ifdef __APPLE__
26#include <crt_externs.h>
27#define environ (*_NSGetEnviron())
28#else
2c02cbf6
LC
29extern char **environ;
30#endif
eecae147 31#endif
2c02cbf6 32
4eb36d40 33#if defined(__linux__)
e3d4d252 34#include <mntent.h>
7006b9cf 35#include <linux/fs.h>
3424fc9f
MP
36#include <ifaddrs.h>
37#include <arpa/inet.h>
38#include <sys/socket.h>
39#include <net/if.h>
e3d4d252 40
eab5fd59 41#ifdef FIFREEZE
e72c3f2e
MR
42#define CONFIG_FSFREEZE
43#endif
eab5fd59
PB
44#ifdef FITRIM
45#define CONFIG_FSTRIM
46#endif
e72c3f2e
MR
47#endif
48
d220a6df
LC
49static void ga_wait_child(pid_t pid, int *status, Error **err)
50{
51 pid_t rpid;
52
53 *status = 0;
54
55 do {
56 rpid = waitpid(pid, status, 0);
57 } while (rpid == -1 && errno == EINTR);
58
59 if (rpid == -1) {
60 error_setg_errno(err, errno, "failed to wait for child (pid: %d)", pid);
61 return;
62 }
63
64 g_assert(rpid == pid);
65}
66
e3d4d252
MR
67void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
68{
e3d4d252 69 const char *shutdown_flag;
d220a6df
LC
70 Error *local_err = NULL;
71 pid_t pid;
3674838c 72 int status;
e3d4d252
MR
73
74 slog("guest-shutdown called, mode: %s", mode);
75 if (!has_mode || strcmp(mode, "powerdown") == 0) {
76 shutdown_flag = "-P";
77 } else if (strcmp(mode, "halt") == 0) {
78 shutdown_flag = "-H";
79 } else if (strcmp(mode, "reboot") == 0) {
80 shutdown_flag = "-r";
81 } else {
d220a6df
LC
82 error_setg(err,
83 "mode is invalid (valid values are: halt|powerdown|reboot");
e3d4d252
MR
84 return;
85 }
86
d5dd3498
LC
87 pid = fork();
88 if (pid == 0) {
e3d4d252
MR
89 /* child, start the shutdown */
90 setsid();
3674838c
LC
91 reopen_fd_to_null(0);
92 reopen_fd_to_null(1);
93 reopen_fd_to_null(2);
e3d4d252 94
3674838c
LC
95 execle("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
96 "hypervisor initiated shutdown", (char*)NULL, environ);
97 _exit(EXIT_FAILURE);
d5dd3498 98 } else if (pid < 0) {
d220a6df
LC
99 error_setg_errno(err, errno, "failed to create child process");
100 return;
e3d4d252 101 }
d5dd3498 102
d220a6df
LC
103 ga_wait_child(pid, &status, &local_err);
104 if (error_is_set(&local_err)) {
105 error_propagate(err, local_err);
106 return;
107 }
108
109 if (!WIFEXITED(status)) {
110 error_setg(err, "child process has terminated abnormally");
111 return;
112 }
113
114 if (WEXITSTATUS(status)) {
115 error_setg(err, "child process has failed to shutdown");
d5dd3498
LC
116 return;
117 }
118
d220a6df 119 /* succeded */
e3d4d252
MR
120}
121
6912e6a9
LL
122int64_t qmp_guest_get_time(Error **errp)
123{
124 int ret;
125 qemu_timeval tq;
126 int64_t time_ns;
127
128 ret = qemu_gettimeofday(&tq);
129 if (ret < 0) {
130 error_setg_errno(errp, errno, "Failed to get time");
131 return -1;
132 }
133
134 time_ns = tq.tv_sec * 1000000000LL + tq.tv_usec * 1000;
135 return time_ns;
136}
137
a1bca57f
LL
138void qmp_guest_set_time(int64_t time_ns, Error **errp)
139{
140 int ret;
141 int status;
142 pid_t pid;
143 Error *local_err = NULL;
144 struct timeval tv;
145
146 /* year-2038 will overflow in case time_t is 32bit */
147 if (time_ns / 1000000000 != (time_t)(time_ns / 1000000000)) {
148 error_setg(errp, "Time %" PRId64 " is too large", time_ns);
149 return;
150 }
151
152 tv.tv_sec = time_ns / 1000000000;
153 tv.tv_usec = (time_ns % 1000000000) / 1000;
154
155 ret = settimeofday(&tv, NULL);
156 if (ret < 0) {
157 error_setg_errno(errp, errno, "Failed to set time to guest");
158 return;
159 }
160
161 /* Set the Hardware Clock to the current System Time. */
162 pid = fork();
163 if (pid == 0) {
164 setsid();
165 reopen_fd_to_null(0);
166 reopen_fd_to_null(1);
167 reopen_fd_to_null(2);
168
169 execle("/sbin/hwclock", "hwclock", "-w", NULL, environ);
170 _exit(EXIT_FAILURE);
171 } else if (pid < 0) {
172 error_setg_errno(errp, errno, "failed to create child process");
173 return;
174 }
175
176 ga_wait_child(pid, &status, &local_err);
177 if (error_is_set(&local_err)) {
178 error_propagate(errp, local_err);
179 return;
180 }
181
182 if (!WIFEXITED(status)) {
183 error_setg(errp, "child process has terminated abnormally");
184 return;
185 }
186
187 if (WEXITSTATUS(status)) {
188 error_setg(errp, "hwclock failed to set hardware clock to system time");
189 return;
190 }
191}
192
e3d4d252
MR
193typedef struct GuestFileHandle {
194 uint64_t id;
195 FILE *fh;
196 QTAILQ_ENTRY(GuestFileHandle) next;
197} GuestFileHandle;
198
199static struct {
200 QTAILQ_HEAD(, GuestFileHandle) filehandles;
201} guest_file_state;
202
39097daf 203static int64_t guest_file_handle_add(FILE *fh, Error **errp)
e3d4d252
MR
204{
205 GuestFileHandle *gfh;
39097daf
MR
206 int64_t handle;
207
208 handle = ga_get_fd_handle(ga_state, errp);
209 if (error_is_set(errp)) {
210 return 0;
211 }
e3d4d252 212
7267c094 213 gfh = g_malloc0(sizeof(GuestFileHandle));
39097daf 214 gfh->id = handle;
e3d4d252
MR
215 gfh->fh = fh;
216 QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
39097daf
MR
217
218 return handle;
e3d4d252
MR
219}
220
a9de6d01 221static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err)
e3d4d252
MR
222{
223 GuestFileHandle *gfh;
224
225 QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
226 {
227 if (gfh->id == id) {
228 return gfh;
229 }
230 }
231
a9de6d01 232 error_setg(err, "handle '%" PRId64 "' has not been found", id);
e3d4d252
MR
233 return NULL;
234}
235
236int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
237{
238 FILE *fh;
239 int fd;
39097daf 240 int64_t ret = -1, handle;
e3d4d252
MR
241
242 if (!has_mode) {
243 mode = "r";
244 }
245 slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
246 fh = fopen(path, mode);
247 if (!fh) {
db3edb66
LC
248 error_setg_errno(err, errno, "failed to open file '%s' (mode: '%s')",
249 path, mode);
e3d4d252
MR
250 return -1;
251 }
252
253 /* set fd non-blocking to avoid common use cases (like reading from a
254 * named pipe) from hanging the agent
255 */
256 fd = fileno(fh);
257 ret = fcntl(fd, F_GETFL);
258 ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
259 if (ret == -1) {
db3edb66
LC
260 error_setg_errno(err, errno, "failed to make file '%s' non-blocking",
261 path);
e3d4d252
MR
262 fclose(fh);
263 return -1;
264 }
265
39097daf
MR
266 handle = guest_file_handle_add(fh, err);
267 if (error_is_set(err)) {
268 fclose(fh);
269 return -1;
270 }
271
272 slog("guest-file-open, handle: %d", handle);
273 return handle;
e3d4d252
MR
274}
275
276void qmp_guest_file_close(int64_t handle, Error **err)
277{
a9de6d01 278 GuestFileHandle *gfh = guest_file_handle_find(handle, err);
e3d4d252
MR
279 int ret;
280
281 slog("guest-file-close called, handle: %ld", handle);
282 if (!gfh) {
e3d4d252
MR
283 return;
284 }
285
286 ret = fclose(gfh->fh);
3ac4b7c5 287 if (ret == EOF) {
db3edb66 288 error_setg_errno(err, errno, "failed to close handle");
e3d4d252
MR
289 return;
290 }
291
292 QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
7267c094 293 g_free(gfh);
e3d4d252
MR
294}
295
296struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
297 int64_t count, Error **err)
298{
a9de6d01 299 GuestFileHandle *gfh = guest_file_handle_find(handle, err);
e3d4d252
MR
300 GuestFileRead *read_data = NULL;
301 guchar *buf;
302 FILE *fh;
303 size_t read_count;
304
305 if (!gfh) {
e3d4d252
MR
306 return NULL;
307 }
308
309 if (!has_count) {
310 count = QGA_READ_COUNT_DEFAULT;
311 } else if (count < 0) {
db3edb66
LC
312 error_setg(err, "value '%" PRId64 "' is invalid for argument count",
313 count);
e3d4d252
MR
314 return NULL;
315 }
316
317 fh = gfh->fh;
7267c094 318 buf = g_malloc0(count+1);
e3d4d252
MR
319 read_count = fread(buf, 1, count, fh);
320 if (ferror(fh)) {
db3edb66 321 error_setg_errno(err, errno, "failed to read file");
e3d4d252 322 slog("guest-file-read failed, handle: %ld", handle);
e3d4d252
MR
323 } else {
324 buf[read_count] = 0;
7267c094 325 read_data = g_malloc0(sizeof(GuestFileRead));
e3d4d252
MR
326 read_data->count = read_count;
327 read_data->eof = feof(fh);
328 if (read_count) {
329 read_data->buf_b64 = g_base64_encode(buf, read_count);
330 }
331 }
7267c094 332 g_free(buf);
e3d4d252
MR
333 clearerr(fh);
334
335 return read_data;
336}
337
338GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
339 bool has_count, int64_t count, Error **err)
340{
341 GuestFileWrite *write_data = NULL;
342 guchar *buf;
343 gsize buf_len;
344 int write_count;
a9de6d01 345 GuestFileHandle *gfh = guest_file_handle_find(handle, err);
e3d4d252
MR
346 FILE *fh;
347
348 if (!gfh) {
e3d4d252
MR
349 return NULL;
350 }
351
352 fh = gfh->fh;
353 buf = g_base64_decode(buf_b64, &buf_len);
354
355 if (!has_count) {
356 count = buf_len;
357 } else if (count < 0 || count > buf_len) {
db3edb66
LC
358 error_setg(err, "value '%" PRId64 "' is invalid for argument count",
359 count);
7267c094 360 g_free(buf);
e3d4d252
MR
361 return NULL;
362 }
363
364 write_count = fwrite(buf, 1, count, fh);
365 if (ferror(fh)) {
db3edb66 366 error_setg_errno(err, errno, "failed to write to file");
e3d4d252 367 slog("guest-file-write failed, handle: %ld", handle);
e3d4d252 368 } else {
7267c094 369 write_data = g_malloc0(sizeof(GuestFileWrite));
e3d4d252
MR
370 write_data->count = write_count;
371 write_data->eof = feof(fh);
372 }
7267c094 373 g_free(buf);
e3d4d252
MR
374 clearerr(fh);
375
376 return write_data;
377}
378
379struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
380 int64_t whence, Error **err)
381{
a9de6d01 382 GuestFileHandle *gfh = guest_file_handle_find(handle, err);
e3d4d252
MR
383 GuestFileSeek *seek_data = NULL;
384 FILE *fh;
385 int ret;
386
387 if (!gfh) {
e3d4d252
MR
388 return NULL;
389 }
390
391 fh = gfh->fh;
392 ret = fseek(fh, offset, whence);
393 if (ret == -1) {
db3edb66 394 error_setg_errno(err, errno, "failed to seek file");
e3d4d252 395 } else {
7267c094 396 seek_data = g_malloc0(sizeof(GuestFileRead));
e3d4d252
MR
397 seek_data->position = ftell(fh);
398 seek_data->eof = feof(fh);
399 }
400 clearerr(fh);
401
402 return seek_data;
403}
404
405void qmp_guest_file_flush(int64_t handle, Error **err)
406{
a9de6d01 407 GuestFileHandle *gfh = guest_file_handle_find(handle, err);
e3d4d252
MR
408 FILE *fh;
409 int ret;
410
411 if (!gfh) {
e3d4d252
MR
412 return;
413 }
414
415 fh = gfh->fh;
416 ret = fflush(fh);
417 if (ret == EOF) {
db3edb66 418 error_setg_errno(err, errno, "failed to flush file");
e3d4d252
MR
419 }
420}
421
422static void guest_file_init(void)
423{
424 QTAILQ_INIT(&guest_file_state.filehandles);
425}
426
e72c3f2e
MR
427/* linux-specific implementations. avoid this if at all possible. */
428#if defined(__linux__)
429
eab5fd59 430#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
af02203f 431typedef struct FsMount {
e3d4d252
MR
432 char *dirname;
433 char *devtype;
af02203f
PB
434 QTAILQ_ENTRY(FsMount) next;
435} FsMount;
e3d4d252 436
af02203f 437typedef QTAILQ_HEAD(, FsMount) FsMountList;
9e8aded4 438
af02203f 439static void free_fs_mount_list(FsMountList *mounts)
9e8aded4 440{
af02203f 441 FsMount *mount, *temp;
9e8aded4
MR
442
443 if (!mounts) {
444 return;
445 }
446
447 QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) {
448 QTAILQ_REMOVE(mounts, mount, next);
449 g_free(mount->dirname);
450 g_free(mount->devtype);
451 g_free(mount);
452 }
453}
454
e3d4d252
MR
455/*
456 * Walk the mount table and build a list of local file systems
457 */
261551d1 458static void build_fs_mount_list(FsMountList *mounts, Error **err)
e3d4d252
MR
459{
460 struct mntent *ment;
af02203f 461 FsMount *mount;
9e2fa418 462 char const *mtab = "/proc/self/mounts";
e3d4d252
MR
463 FILE *fp;
464
e3d4d252
MR
465 fp = setmntent(mtab, "r");
466 if (!fp) {
261551d1
LC
467 error_setg(err, "failed to open mtab file: '%s'", mtab);
468 return;
e3d4d252
MR
469 }
470
471 while ((ment = getmntent(fp))) {
472 /*
473 * An entry which device name doesn't start with a '/' is
474 * either a dummy file system or a network file system.
475 * Add special handling for smbfs and cifs as is done by
476 * coreutils as well.
477 */
478 if ((ment->mnt_fsname[0] != '/') ||
479 (strcmp(ment->mnt_type, "smbfs") == 0) ||
480 (strcmp(ment->mnt_type, "cifs") == 0)) {
481 continue;
482 }
483
af02203f 484 mount = g_malloc0(sizeof(FsMount));
7267c094
AL
485 mount->dirname = g_strdup(ment->mnt_dir);
486 mount->devtype = g_strdup(ment->mnt_type);
e3d4d252 487
9e8aded4 488 QTAILQ_INSERT_TAIL(mounts, mount, next);
e3d4d252
MR
489 }
490
491 endmntent(fp);
e3d4d252 492}
eab5fd59
PB
493#endif
494
495#if defined(CONFIG_FSFREEZE)
e3d4d252 496
ec0f694c
TS
497typedef enum {
498 FSFREEZE_HOOK_THAW = 0,
499 FSFREEZE_HOOK_FREEZE,
500} FsfreezeHookArg;
501
502const char *fsfreeze_hook_arg_string[] = {
503 "thaw",
504 "freeze",
505};
506
507static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **err)
508{
509 int status;
510 pid_t pid;
511 const char *hook;
512 const char *arg_str = fsfreeze_hook_arg_string[arg];
513 Error *local_err = NULL;
514
515 hook = ga_fsfreeze_hook(ga_state);
516 if (!hook) {
517 return;
518 }
519 if (access(hook, X_OK) != 0) {
520 error_setg_errno(err, errno, "can't access fsfreeze hook '%s'", hook);
521 return;
522 }
523
524 slog("executing fsfreeze hook with arg '%s'", arg_str);
525 pid = fork();
526 if (pid == 0) {
527 setsid();
528 reopen_fd_to_null(0);
529 reopen_fd_to_null(1);
530 reopen_fd_to_null(2);
531
532 execle(hook, hook, arg_str, NULL, environ);
533 _exit(EXIT_FAILURE);
534 } else if (pid < 0) {
535 error_setg_errno(err, errno, "failed to create child process");
536 return;
537 }
538
539 ga_wait_child(pid, &status, &local_err);
540 if (error_is_set(&local_err)) {
541 error_propagate(err, local_err);
542 return;
543 }
544
545 if (!WIFEXITED(status)) {
546 error_setg(err, "fsfreeze hook has terminated abnormally");
547 return;
548 }
549
550 status = WEXITSTATUS(status);
551 if (status) {
552 error_setg(err, "fsfreeze hook has failed with status %d", status);
553 return;
554 }
555}
556
e3d4d252
MR
557/*
558 * Return status of freeze/thaw
559 */
560GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
561{
f22d85e9
MR
562 if (ga_is_frozen(ga_state)) {
563 return GUEST_FSFREEZE_STATUS_FROZEN;
564 }
565
566 return GUEST_FSFREEZE_STATUS_THAWED;
e3d4d252
MR
567}
568
569/*
570 * Walk list of mounted file systems in the guest, and freeze the ones which
571 * are real local file systems.
572 */
573int64_t qmp_guest_fsfreeze_freeze(Error **err)
574{
575 int ret = 0, i = 0;
af02203f
PB
576 FsMountList mounts;
577 struct FsMount *mount;
261551d1 578 Error *local_err = NULL;
e3d4d252 579 int fd;
e3d4d252
MR
580
581 slog("guest-fsfreeze called");
582
ec0f694c
TS
583 execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err);
584 if (error_is_set(&local_err)) {
585 error_propagate(err, local_err);
586 return -1;
587 }
588
9e8aded4 589 QTAILQ_INIT(&mounts);
261551d1
LC
590 build_fs_mount_list(&mounts, &local_err);
591 if (error_is_set(&local_err)) {
592 error_propagate(err, local_err);
593 return -1;
e3d4d252
MR
594 }
595
596 /* cannot risk guest agent blocking itself on a write in this state */
f22d85e9 597 ga_set_frozen(ga_state);
e3d4d252 598
9e8aded4 599 QTAILQ_FOREACH(mount, &mounts, next) {
e3d4d252
MR
600 fd = qemu_open(mount->dirname, O_RDONLY);
601 if (fd == -1) {
617fbbc1 602 error_setg_errno(err, errno, "failed to open %s", mount->dirname);
e3d4d252
MR
603 goto error;
604 }
605
606 /* we try to cull filesytems we know won't work in advance, but other
607 * filesytems may not implement fsfreeze for less obvious reasons.
9e8aded4
MR
608 * these will report EOPNOTSUPP. we simply ignore these when tallying
609 * the number of frozen filesystems.
610 *
611 * any other error means a failure to freeze a filesystem we
612 * expect to be freezable, so return an error in those cases
613 * and return system to thawed state.
e3d4d252
MR
614 */
615 ret = ioctl(fd, FIFREEZE);
9e8aded4
MR
616 if (ret == -1) {
617 if (errno != EOPNOTSUPP) {
617fbbc1
LC
618 error_setg_errno(err, errno, "failed to freeze %s",
619 mount->dirname);
9e8aded4
MR
620 close(fd);
621 goto error;
622 }
623 } else {
624 i++;
e3d4d252
MR
625 }
626 close(fd);
e3d4d252
MR
627 }
628
af02203f 629 free_fs_mount_list(&mounts);
e3d4d252
MR
630 return i;
631
632error:
af02203f 633 free_fs_mount_list(&mounts);
9e8aded4 634 qmp_guest_fsfreeze_thaw(NULL);
e3d4d252
MR
635 return 0;
636}
637
638/*
639 * Walk list of frozen file systems in the guest, and thaw them.
640 */
641int64_t qmp_guest_fsfreeze_thaw(Error **err)
642{
643 int ret;
af02203f
PB
644 FsMountList mounts;
645 FsMount *mount;
9e8aded4 646 int fd, i = 0, logged;
261551d1 647 Error *local_err = NULL;
9e8aded4
MR
648
649 QTAILQ_INIT(&mounts);
261551d1
LC
650 build_fs_mount_list(&mounts, &local_err);
651 if (error_is_set(&local_err)) {
652 error_propagate(err, local_err);
9e8aded4
MR
653 return 0;
654 }
e3d4d252 655
9e8aded4
MR
656 QTAILQ_FOREACH(mount, &mounts, next) {
657 logged = false;
e3d4d252
MR
658 fd = qemu_open(mount->dirname, O_RDONLY);
659 if (fd == -1) {
e3d4d252
MR
660 continue;
661 }
9e8aded4
MR
662 /* we have no way of knowing whether a filesystem was actually unfrozen
663 * as a result of a successful call to FITHAW, only that if an error
664 * was returned the filesystem was *not* unfrozen by that particular
665 * call.
666 *
a31f0531 667 * since multiple preceding FIFREEZEs require multiple calls to FITHAW
9e8aded4
MR
668 * to unfreeze, continuing issuing FITHAW until an error is returned,
669 * in which case either the filesystem is in an unfreezable state, or,
670 * more likely, it was thawed previously (and remains so afterward).
671 *
672 * also, since the most recent successful call is the one that did
673 * the actual unfreeze, we can use this to provide an accurate count
674 * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which
675 * may * be useful for determining whether a filesystem was unfrozen
676 * during the freeze/thaw phase by a process other than qemu-ga.
677 */
678 do {
679 ret = ioctl(fd, FITHAW);
680 if (ret == 0 && !logged) {
681 i++;
682 logged = true;
683 }
684 } while (ret == 0);
e3d4d252 685 close(fd);
e3d4d252
MR
686 }
687
f22d85e9 688 ga_unset_frozen(ga_state);
af02203f 689 free_fs_mount_list(&mounts);
ec0f694c
TS
690
691 execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, err);
692
e3d4d252
MR
693 return i;
694}
695
e3d4d252
MR
696static void guest_fsfreeze_cleanup(void)
697{
e3d4d252
MR
698 Error *err = NULL;
699
f22d85e9 700 if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
6f686749
MA
701 qmp_guest_fsfreeze_thaw(&err);
702 if (err) {
703 slog("failed to clean up frozen filesystems: %s",
704 error_get_pretty(err));
705 error_free(err);
e3d4d252
MR
706 }
707 }
708}
e72c3f2e 709#endif /* CONFIG_FSFREEZE */
e3d4d252 710
eab5fd59
PB
711#if defined(CONFIG_FSTRIM)
712/*
713 * Walk list of mounted file systems in the guest, and trim them.
714 */
715void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err)
716{
717 int ret = 0;
718 FsMountList mounts;
719 struct FsMount *mount;
720 int fd;
261551d1 721 Error *local_err = NULL;
eab5fd59
PB
722 struct fstrim_range r = {
723 .start = 0,
724 .len = -1,
725 .minlen = has_minimum ? minimum : 0,
726 };
727
728 slog("guest-fstrim called");
729
730 QTAILQ_INIT(&mounts);
261551d1
LC
731 build_fs_mount_list(&mounts, &local_err);
732 if (error_is_set(&local_err)) {
733 error_propagate(err, local_err);
eab5fd59
PB
734 return;
735 }
736
737 QTAILQ_FOREACH(mount, &mounts, next) {
738 fd = qemu_open(mount->dirname, O_RDONLY);
739 if (fd == -1) {
071673b0 740 error_setg_errno(err, errno, "failed to open %s", mount->dirname);
eab5fd59
PB
741 goto error;
742 }
743
744 /* We try to cull filesytems we know won't work in advance, but other
745 * filesytems may not implement fstrim for less obvious reasons. These
746 * will report EOPNOTSUPP; we simply ignore these errors. Any other
747 * error means an unexpected error, so return it in those cases. In
748 * some other cases ENOTTY will be reported (e.g. CD-ROMs).
749 */
750 ret = ioctl(fd, FITRIM, &r);
751 if (ret == -1) {
752 if (errno != ENOTTY && errno != EOPNOTSUPP) {
071673b0
LC
753 error_setg_errno(err, errno, "failed to trim %s",
754 mount->dirname);
eab5fd59
PB
755 close(fd);
756 goto error;
757 }
758 }
759 close(fd);
760 }
761
762error:
763 free_fs_mount_list(&mounts);
764}
765#endif /* CONFIG_FSTRIM */
766
767
11d0f125
LC
768#define LINUX_SYS_STATE_FILE "/sys/power/state"
769#define SUSPEND_SUPPORTED 0
770#define SUSPEND_NOT_SUPPORTED 1
771
11d0f125
LC
772static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
773 const char *sysfile_str, Error **err)
774{
6b26e837 775 Error *local_err = NULL;
11d0f125 776 char *pmutils_path;
6b26e837 777 pid_t pid;
dc8764f0 778 int status;
11d0f125
LC
779
780 pmutils_path = g_find_program_in_path(pmutils_bin);
781
782 pid = fork();
783 if (!pid) {
dc8764f0
LC
784 char buf[32]; /* hopefully big enough */
785 ssize_t ret;
786 int fd;
11d0f125
LC
787
788 setsid();
11d0f125
LC
789 reopen_fd_to_null(0);
790 reopen_fd_to_null(1);
791 reopen_fd_to_null(2);
792
dc8764f0
LC
793 if (pmutils_path) {
794 execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
795 }
11d0f125 796
dc8764f0
LC
797 /*
798 * If we get here either pm-utils is not installed or execle() has
799 * failed. Let's try the manual method if the caller wants it.
800 */
11d0f125 801
dc8764f0
LC
802 if (!sysfile_str) {
803 _exit(SUSPEND_NOT_SUPPORTED);
804 }
11d0f125 805
dc8764f0
LC
806 fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
807 if (fd < 0) {
11d0f125
LC
808 _exit(SUSPEND_NOT_SUPPORTED);
809 }
810
dc8764f0
LC
811 ret = read(fd, buf, sizeof(buf)-1);
812 if (ret <= 0) {
813 _exit(SUSPEND_NOT_SUPPORTED);
11d0f125 814 }
dc8764f0 815 buf[ret] = '\0';
11d0f125 816
dc8764f0
LC
817 if (strstr(buf, sysfile_str)) {
818 _exit(SUSPEND_SUPPORTED);
11d0f125
LC
819 }
820
dc8764f0 821 _exit(SUSPEND_NOT_SUPPORTED);
6b26e837
LC
822 } else if (pid < 0) {
823 error_setg_errno(err, errno, "failed to create child process");
824 goto out;
11d0f125
LC
825 }
826
6b26e837
LC
827 ga_wait_child(pid, &status, &local_err);
828 if (error_is_set(&local_err)) {
829 error_propagate(err, local_err);
830 goto out;
831 }
11d0f125 832
6b26e837
LC
833 if (!WIFEXITED(status)) {
834 error_setg(err, "child process has terminated abnormally");
835 goto out;
dc8764f0
LC
836 }
837
6b26e837
LC
838 switch (WEXITSTATUS(status)) {
839 case SUSPEND_SUPPORTED:
840 goto out;
841 case SUSPEND_NOT_SUPPORTED:
842 error_setg(err,
843 "the requested suspend mode is not supported by the guest");
844 goto out;
845 default:
846 error_setg(err,
847 "the helper program '%s' returned an unexpected exit status"
848 " code (%d)", pmutils_path, WEXITSTATUS(status));
849 goto out;
11d0f125
LC
850 }
851
6b26e837
LC
852out:
853 g_free(pmutils_path);
11d0f125
LC
854}
855
856static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
857 Error **err)
858{
7b376087 859 Error *local_err = NULL;
11d0f125 860 char *pmutils_path;
7b376087 861 pid_t pid;
dc8764f0 862 int status;
11d0f125
LC
863
864 pmutils_path = g_find_program_in_path(pmutils_bin);
865
866 pid = fork();
867 if (pid == 0) {
868 /* child */
869 int fd;
870
871 setsid();
872 reopen_fd_to_null(0);
873 reopen_fd_to_null(1);
874 reopen_fd_to_null(2);
875
876 if (pmutils_path) {
877 execle(pmutils_path, pmutils_bin, NULL, environ);
878 }
879
880 /*
881 * If we get here either pm-utils is not installed or execle() has
882 * failed. Let's try the manual method if the caller wants it.
883 */
884
885 if (!sysfile_str) {
886 _exit(EXIT_FAILURE);
887 }
888
889 fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
890 if (fd < 0) {
891 _exit(EXIT_FAILURE);
892 }
893
894 if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
895 _exit(EXIT_FAILURE);
896 }
897
898 _exit(EXIT_SUCCESS);
7b376087
LC
899 } else if (pid < 0) {
900 error_setg_errno(err, errno, "failed to create child process");
901 goto out;
11d0f125
LC
902 }
903
7b376087
LC
904 ga_wait_child(pid, &status, &local_err);
905 if (error_is_set(&local_err)) {
906 error_propagate(err, local_err);
907 goto out;
908 }
11d0f125 909
7b376087
LC
910 if (!WIFEXITED(status)) {
911 error_setg(err, "child process has terminated abnormally");
912 goto out;
dc8764f0
LC
913 }
914
7b376087
LC
915 if (WEXITSTATUS(status)) {
916 error_setg(err, "child process has failed to suspend");
917 goto out;
11d0f125 918 }
dc8764f0 919
7b376087
LC
920out:
921 g_free(pmutils_path);
11d0f125
LC
922}
923
924void qmp_guest_suspend_disk(Error **err)
925{
926 bios_supports_mode("pm-is-supported", "--hibernate", "disk", err);
927 if (error_is_set(err)) {
928 return;
929 }
930
931 guest_suspend("pm-hibernate", "disk", err);
932}
933
fbf42210
LC
934void qmp_guest_suspend_ram(Error **err)
935{
936 bios_supports_mode("pm-is-supported", "--suspend", "mem", err);
937 if (error_is_set(err)) {
938 return;
939 }
940
941 guest_suspend("pm-suspend", "mem", err);
942}
943
95f4f404
LC
944void qmp_guest_suspend_hybrid(Error **err)
945{
946 bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err);
947 if (error_is_set(err)) {
948 return;
949 }
950
951 guest_suspend("pm-suspend-hybrid", NULL, err);
952}
953
3424fc9f
MP
954static GuestNetworkInterfaceList *
955guest_find_interface(GuestNetworkInterfaceList *head,
956 const char *name)
957{
958 for (; head; head = head->next) {
959 if (strcmp(head->value->name, name) == 0) {
960 break;
961 }
962 }
963
964 return head;
965}
966
967/*
968 * Build information about guest interfaces
969 */
970GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
971{
972 GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
973 struct ifaddrs *ifap, *ifa;
3424fc9f
MP
974
975 if (getifaddrs(&ifap) < 0) {
878a0ae0 976 error_setg_errno(errp, errno, "getifaddrs failed");
3424fc9f
MP
977 goto error;
978 }
979
980 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
981 GuestNetworkInterfaceList *info;
982 GuestIpAddressList **address_list = NULL, *address_item = NULL;
983 char addr4[INET_ADDRSTRLEN];
984 char addr6[INET6_ADDRSTRLEN];
985 int sock;
986 struct ifreq ifr;
987 unsigned char *mac_addr;
988 void *p;
989
990 g_debug("Processing %s interface", ifa->ifa_name);
991
992 info = guest_find_interface(head, ifa->ifa_name);
993
994 if (!info) {
995 info = g_malloc0(sizeof(*info));
996 info->value = g_malloc0(sizeof(*info->value));
997 info->value->name = g_strdup(ifa->ifa_name);
998
999 if (!cur_item) {
1000 head = cur_item = info;
1001 } else {
1002 cur_item->next = info;
1003 cur_item = info;
1004 }
1005 }
1006
1007 if (!info->value->has_hardware_address &&
1008 ifa->ifa_flags & SIOCGIFHWADDR) {
1009 /* we haven't obtained HW address yet */
1010 sock = socket(PF_INET, SOCK_STREAM, 0);
1011 if (sock == -1) {
878a0ae0 1012 error_setg_errno(errp, errno, "failed to create socket");
3424fc9f
MP
1013 goto error;
1014 }
1015
1016 memset(&ifr, 0, sizeof(ifr));
1ab516ed 1017 pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->value->name);
3424fc9f 1018 if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
878a0ae0
LC
1019 error_setg_errno(errp, errno,
1020 "failed to get MAC address of %s",
1021 ifa->ifa_name);
10a2158f 1022 close(sock);
3424fc9f
MP
1023 goto error;
1024 }
1025
10a2158f 1026 close(sock);
3424fc9f
MP
1027 mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
1028
e4ada482
SW
1029 info->value->hardware_address =
1030 g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x",
1031 (int) mac_addr[0], (int) mac_addr[1],
1032 (int) mac_addr[2], (int) mac_addr[3],
1033 (int) mac_addr[4], (int) mac_addr[5]);
3424fc9f
MP
1034
1035 info->value->has_hardware_address = true;
3424fc9f
MP
1036 }
1037
1038 if (ifa->ifa_addr &&
1039 ifa->ifa_addr->sa_family == AF_INET) {
1040 /* interface with IPv4 address */
3424fc9f
MP
1041 p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
1042 if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
878a0ae0 1043 error_setg_errno(errp, errno, "inet_ntop failed");
3424fc9f
MP
1044 goto error;
1045 }
1046
10a2158f
MA
1047 address_item = g_malloc0(sizeof(*address_item));
1048 address_item->value = g_malloc0(sizeof(*address_item->value));
3424fc9f
MP
1049 address_item->value->ip_address = g_strdup(addr4);
1050 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
1051
1052 if (ifa->ifa_netmask) {
1053 /* Count the number of set bits in netmask.
1054 * This is safe as '1' and '0' cannot be shuffled in netmask. */
1055 p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
1056 address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
1057 }
1058 } else if (ifa->ifa_addr &&
1059 ifa->ifa_addr->sa_family == AF_INET6) {
1060 /* interface with IPv6 address */
3424fc9f
MP
1061 p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
1062 if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
878a0ae0 1063 error_setg_errno(errp, errno, "inet_ntop failed");
3424fc9f
MP
1064 goto error;
1065 }
1066
10a2158f
MA
1067 address_item = g_malloc0(sizeof(*address_item));
1068 address_item->value = g_malloc0(sizeof(*address_item->value));
3424fc9f
MP
1069 address_item->value->ip_address = g_strdup(addr6);
1070 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
1071
1072 if (ifa->ifa_netmask) {
1073 /* Count the number of set bits in netmask.
1074 * This is safe as '1' and '0' cannot be shuffled in netmask. */
1075 p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
1076 address_item->value->prefix =
1077 ctpop32(((uint32_t *) p)[0]) +
1078 ctpop32(((uint32_t *) p)[1]) +
1079 ctpop32(((uint32_t *) p)[2]) +
1080 ctpop32(((uint32_t *) p)[3]);
1081 }
1082 }
1083
1084 if (!address_item) {
1085 continue;
1086 }
1087
1088 address_list = &info->value->ip_addresses;
1089
1090 while (*address_list && (*address_list)->next) {
1091 address_list = &(*address_list)->next;
1092 }
1093
1094 if (!*address_list) {
1095 *address_list = address_item;
1096 } else {
1097 (*address_list)->next = address_item;
1098 }
1099
1100 info->value->has_ip_addresses = true;
1101
1102
1103 }
1104
1105 freeifaddrs(ifap);
1106 return head;
1107
1108error:
1109 freeifaddrs(ifap);
1110 qapi_free_GuestNetworkInterfaceList(head);
1111 return NULL;
1112}
1113
e72c3f2e
MR
1114#else /* defined(__linux__) */
1115
d35d4cb5 1116void qmp_guest_suspend_disk(Error **err)
e72c3f2e
MR
1117{
1118 error_set(err, QERR_UNSUPPORTED);
e72c3f2e
MR
1119}
1120
d35d4cb5 1121void qmp_guest_suspend_ram(Error **err)
e72c3f2e
MR
1122{
1123 error_set(err, QERR_UNSUPPORTED);
e72c3f2e
MR
1124}
1125
d35d4cb5 1126void qmp_guest_suspend_hybrid(Error **err)
e72c3f2e
MR
1127{
1128 error_set(err, QERR_UNSUPPORTED);
e72c3f2e
MR
1129}
1130
d35d4cb5 1131GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
e72c3f2e 1132{
d35d4cb5
MR
1133 error_set(errp, QERR_UNSUPPORTED);
1134 return NULL;
e72c3f2e
MR
1135}
1136
d35d4cb5
MR
1137#endif
1138
1139#if !defined(CONFIG_FSFREEZE)
1140
1141GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
e72c3f2e
MR
1142{
1143 error_set(err, QERR_UNSUPPORTED);
d35d4cb5
MR
1144
1145 return 0;
e72c3f2e
MR
1146}
1147
d35d4cb5 1148int64_t qmp_guest_fsfreeze_freeze(Error **err)
e72c3f2e
MR
1149{
1150 error_set(err, QERR_UNSUPPORTED);
d35d4cb5
MR
1151
1152 return 0;
e72c3f2e
MR
1153}
1154
d35d4cb5 1155int64_t qmp_guest_fsfreeze_thaw(Error **err)
e72c3f2e 1156{
d35d4cb5
MR
1157 error_set(err, QERR_UNSUPPORTED);
1158
1159 return 0;
e72c3f2e 1160}
eab5fd59
PB
1161#endif /* CONFIG_FSFREEZE */
1162
1163#if !defined(CONFIG_FSTRIM)
1164void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err)
1165{
1166 error_set(err, QERR_UNSUPPORTED);
eab5fd59 1167}
e72c3f2e
MR
1168#endif
1169
70e133a7
LE
1170GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
1171{
1172 error_set(errp, QERR_UNSUPPORTED);
1173 return NULL;
1174}
1175
1176int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
1177{
1178 error_set(errp, QERR_UNSUPPORTED);
1179 return -1;
1180}
1181
e3d4d252
MR
1182/* register init/cleanup routines for stateful command groups */
1183void ga_command_state_init(GAState *s, GACommandState *cs)
1184{
7006b9cf 1185#if defined(CONFIG_FSFREEZE)
f22d85e9 1186 ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
7006b9cf 1187#endif
e3d4d252
MR
1188 ga_command_state_add(cs, guest_file_init, NULL);
1189}