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