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