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