blob: 5b77fa9eee79c378fdd1be5f2e2992c03a97730b [file] [log] [blame]
Michael Rothe3d4d252011-07-19 15:41:55 -05001/*
Michael Roth42074a92012-01-19 22:19:27 -06002 * QEMU Guest Agent POSIX-specific command implementations
Michael Rothe3d4d252011-07-19 15:41:55 -05003 *
4 * Copyright IBM Corp. 2011
5 *
6 * Authors:
7 * Michael Roth <mdroth@linux.vnet.ibm.com>
Michal Privoznik3424fc92012-02-29 17:02:23 +01008 * Michal Privoznik <mprivozn@redhat.com>
Michael Rothe3d4d252011-07-19 15:41:55 -05009 *
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>
Anthony Liguori4eb36d42011-07-23 16:14:37 -050015
16#if defined(__linux__)
Michael Rothe3d4d252011-07-19 15:41:55 -050017#include <mntent.h>
Anthony Liguori7006b9c2011-07-22 14:14:17 -050018#include <linux/fs.h>
Anthony Liguori4eb36d42011-07-23 16:14:37 -050019
20#if defined(__linux__) && defined(FIFREEZE)
21#define CONFIG_FSFREEZE
Anthony Liguori7006b9c2011-07-22 14:14:17 -050022#endif
Anthony Liguori4eb36d42011-07-23 16:14:37 -050023#endif
24
Michael Rothe3d4d252011-07-19 15:41:55 -050025#include <sys/types.h>
26#include <sys/ioctl.h>
Michal Privoznik3424fc92012-02-29 17:02:23 +010027#include <ifaddrs.h>
28#include <arpa/inet.h>
29#include <sys/socket.h>
30#include <net/if.h>
Luiz Capitulino11d0f122012-02-28 11:03:03 -030031#include <sys/wait.h>
Michael Rothe3d4d252011-07-19 15:41:55 -050032#include "qga/guest-agent-core.h"
33#include "qga-qmp-commands.h"
34#include "qerror.h"
35#include "qemu-queue.h"
Michal Privoznik3424fc92012-02-29 17:02:23 +010036#include "host-utils.h"
Michael Rothe3d4d252011-07-19 15:41:55 -050037
38static GAState *ga_state;
39
Luiz Capitulino11d0f122012-02-28 11:03:03 -030040static void reopen_fd_to_null(int fd)
41{
42 int nullfd;
43
44 nullfd = open("/dev/null", O_RDWR);
45 if (nullfd < 0) {
46 return;
47 }
48
49 dup2(nullfd, fd);
50
51 if (nullfd != fd) {
52 close(nullfd);
53 }
54}
55
Michael Rothe3d4d252011-07-19 15:41:55 -050056void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
57{
58 int ret;
59 const char *shutdown_flag;
60
61 slog("guest-shutdown called, mode: %s", mode);
62 if (!has_mode || strcmp(mode, "powerdown") == 0) {
63 shutdown_flag = "-P";
64 } else if (strcmp(mode, "halt") == 0) {
65 shutdown_flag = "-H";
66 } else if (strcmp(mode, "reboot") == 0) {
67 shutdown_flag = "-r";
68 } else {
69 error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode",
70 "halt|powerdown|reboot");
71 return;
72 }
73
74 ret = fork();
75 if (ret == 0) {
76 /* child, start the shutdown */
77 setsid();
78 fclose(stdin);
79 fclose(stdout);
80 fclose(stderr);
81
82 ret = execl("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
83 "hypervisor initiated shutdown", (char*)NULL);
84 if (ret) {
85 slog("guest-shutdown failed: %s", strerror(errno));
86 }
87 exit(!!ret);
88 } else if (ret < 0) {
89 error_set(err, QERR_UNDEFINED_ERROR);
90 }
91}
92
93typedef struct GuestFileHandle {
94 uint64_t id;
95 FILE *fh;
96 QTAILQ_ENTRY(GuestFileHandle) next;
97} GuestFileHandle;
98
99static struct {
100 QTAILQ_HEAD(, GuestFileHandle) filehandles;
101} guest_file_state;
102
103static void guest_file_handle_add(FILE *fh)
104{
105 GuestFileHandle *gfh;
106
Anthony Liguori7267c092011-08-20 22:09:37 -0500107 gfh = g_malloc0(sizeof(GuestFileHandle));
Michael Rothe3d4d252011-07-19 15:41:55 -0500108 gfh->id = fileno(fh);
109 gfh->fh = fh;
110 QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
111}
112
113static GuestFileHandle *guest_file_handle_find(int64_t id)
114{
115 GuestFileHandle *gfh;
116
117 QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
118 {
119 if (gfh->id == id) {
120 return gfh;
121 }
122 }
123
124 return NULL;
125}
126
127int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
128{
129 FILE *fh;
130 int fd;
131 int64_t ret = -1;
132
133 if (!has_mode) {
134 mode = "r";
135 }
136 slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
137 fh = fopen(path, mode);
138 if (!fh) {
139 error_set(err, QERR_OPEN_FILE_FAILED, path);
140 return -1;
141 }
142
143 /* set fd non-blocking to avoid common use cases (like reading from a
144 * named pipe) from hanging the agent
145 */
146 fd = fileno(fh);
147 ret = fcntl(fd, F_GETFL);
148 ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
149 if (ret == -1) {
150 error_set(err, QERR_QGA_COMMAND_FAILED, "fcntl() failed");
151 fclose(fh);
152 return -1;
153 }
154
155 guest_file_handle_add(fh);
156 slog("guest-file-open, handle: %d", fd);
157 return fd;
158}
159
160void qmp_guest_file_close(int64_t handle, Error **err)
161{
162 GuestFileHandle *gfh = guest_file_handle_find(handle);
163 int ret;
164
165 slog("guest-file-close called, handle: %ld", handle);
166 if (!gfh) {
167 error_set(err, QERR_FD_NOT_FOUND, "handle");
168 return;
169 }
170
171 ret = fclose(gfh->fh);
172 if (ret == -1) {
173 error_set(err, QERR_QGA_COMMAND_FAILED, "fclose() failed");
174 return;
175 }
176
177 QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
Anthony Liguori7267c092011-08-20 22:09:37 -0500178 g_free(gfh);
Michael Rothe3d4d252011-07-19 15:41:55 -0500179}
180
181struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
182 int64_t count, Error **err)
183{
184 GuestFileHandle *gfh = guest_file_handle_find(handle);
185 GuestFileRead *read_data = NULL;
186 guchar *buf;
187 FILE *fh;
188 size_t read_count;
189
190 if (!gfh) {
191 error_set(err, QERR_FD_NOT_FOUND, "handle");
192 return NULL;
193 }
194
195 if (!has_count) {
196 count = QGA_READ_COUNT_DEFAULT;
197 } else if (count < 0) {
198 error_set(err, QERR_INVALID_PARAMETER, "count");
199 return NULL;
200 }
201
202 fh = gfh->fh;
Anthony Liguori7267c092011-08-20 22:09:37 -0500203 buf = g_malloc0(count+1);
Michael Rothe3d4d252011-07-19 15:41:55 -0500204 read_count = fread(buf, 1, count, fh);
205 if (ferror(fh)) {
206 slog("guest-file-read failed, handle: %ld", handle);
207 error_set(err, QERR_QGA_COMMAND_FAILED, "fread() failed");
208 } else {
209 buf[read_count] = 0;
Anthony Liguori7267c092011-08-20 22:09:37 -0500210 read_data = g_malloc0(sizeof(GuestFileRead));
Michael Rothe3d4d252011-07-19 15:41:55 -0500211 read_data->count = read_count;
212 read_data->eof = feof(fh);
213 if (read_count) {
214 read_data->buf_b64 = g_base64_encode(buf, read_count);
215 }
216 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500217 g_free(buf);
Michael Rothe3d4d252011-07-19 15:41:55 -0500218 clearerr(fh);
219
220 return read_data;
221}
222
223GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
224 bool has_count, int64_t count, Error **err)
225{
226 GuestFileWrite *write_data = NULL;
227 guchar *buf;
228 gsize buf_len;
229 int write_count;
230 GuestFileHandle *gfh = guest_file_handle_find(handle);
231 FILE *fh;
232
233 if (!gfh) {
234 error_set(err, QERR_FD_NOT_FOUND, "handle");
235 return NULL;
236 }
237
238 fh = gfh->fh;
239 buf = g_base64_decode(buf_b64, &buf_len);
240
241 if (!has_count) {
242 count = buf_len;
243 } else if (count < 0 || count > buf_len) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500244 g_free(buf);
Michael Rothe3d4d252011-07-19 15:41:55 -0500245 error_set(err, QERR_INVALID_PARAMETER, "count");
246 return NULL;
247 }
248
249 write_count = fwrite(buf, 1, count, fh);
250 if (ferror(fh)) {
251 slog("guest-file-write failed, handle: %ld", handle);
252 error_set(err, QERR_QGA_COMMAND_FAILED, "fwrite() error");
253 } else {
Anthony Liguori7267c092011-08-20 22:09:37 -0500254 write_data = g_malloc0(sizeof(GuestFileWrite));
Michael Rothe3d4d252011-07-19 15:41:55 -0500255 write_data->count = write_count;
256 write_data->eof = feof(fh);
257 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500258 g_free(buf);
Michael Rothe3d4d252011-07-19 15:41:55 -0500259 clearerr(fh);
260
261 return write_data;
262}
263
264struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
265 int64_t whence, Error **err)
266{
267 GuestFileHandle *gfh = guest_file_handle_find(handle);
268 GuestFileSeek *seek_data = NULL;
269 FILE *fh;
270 int ret;
271
272 if (!gfh) {
273 error_set(err, QERR_FD_NOT_FOUND, "handle");
274 return NULL;
275 }
276
277 fh = gfh->fh;
278 ret = fseek(fh, offset, whence);
279 if (ret == -1) {
280 error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
281 } else {
Anthony Liguori7267c092011-08-20 22:09:37 -0500282 seek_data = g_malloc0(sizeof(GuestFileRead));
Michael Rothe3d4d252011-07-19 15:41:55 -0500283 seek_data->position = ftell(fh);
284 seek_data->eof = feof(fh);
285 }
286 clearerr(fh);
287
288 return seek_data;
289}
290
291void qmp_guest_file_flush(int64_t handle, Error **err)
292{
293 GuestFileHandle *gfh = guest_file_handle_find(handle);
294 FILE *fh;
295 int ret;
296
297 if (!gfh) {
298 error_set(err, QERR_FD_NOT_FOUND, "handle");
299 return;
300 }
301
302 fh = gfh->fh;
303 ret = fflush(fh);
304 if (ret == EOF) {
305 error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
306 }
307}
308
309static void guest_file_init(void)
310{
311 QTAILQ_INIT(&guest_file_state.filehandles);
312}
313
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500314#if defined(CONFIG_FSFREEZE)
315static void disable_logging(void)
316{
317 ga_disable_logging(ga_state);
318}
319
320static void enable_logging(void)
321{
322 ga_enable_logging(ga_state);
323}
324
Michael Rothe3d4d252011-07-19 15:41:55 -0500325typedef struct GuestFsfreezeMount {
326 char *dirname;
327 char *devtype;
328 QTAILQ_ENTRY(GuestFsfreezeMount) next;
329} GuestFsfreezeMount;
330
331struct {
332 GuestFsfreezeStatus status;
333 QTAILQ_HEAD(, GuestFsfreezeMount) mount_list;
334} guest_fsfreeze_state;
335
336/*
337 * Walk the mount table and build a list of local file systems
338 */
339static int guest_fsfreeze_build_mount_list(void)
340{
341 struct mntent *ment;
342 GuestFsfreezeMount *mount, *temp;
343 char const *mtab = MOUNTED;
344 FILE *fp;
345
346 QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) {
347 QTAILQ_REMOVE(&guest_fsfreeze_state.mount_list, mount, next);
Anthony Liguori7267c092011-08-20 22:09:37 -0500348 g_free(mount->dirname);
349 g_free(mount->devtype);
350 g_free(mount);
Michael Rothe3d4d252011-07-19 15:41:55 -0500351 }
352
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
Anthony Liguori7267c092011-08-20 22:09:37 -0500372 mount = g_malloc0(sizeof(GuestFsfreezeMount));
373 mount->dirname = g_strdup(ment->mnt_dir);
374 mount->devtype = g_strdup(ment->mnt_type);
Michael Rothe3d4d252011-07-19 15:41:55 -0500375
376 QTAILQ_INSERT_TAIL(&guest_fsfreeze_state.mount_list, mount, next);
377 }
378
379 endmntent(fp);
380
381 return 0;
382}
383
384/*
385 * Return status of freeze/thaw
386 */
387GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
388{
389 return guest_fsfreeze_state.status;
390}
391
392/*
393 * Walk list of mounted file systems in the guest, and freeze the ones which
394 * are real local file systems.
395 */
396int64_t qmp_guest_fsfreeze_freeze(Error **err)
397{
398 int ret = 0, i = 0;
399 struct GuestFsfreezeMount *mount, *temp;
400 int fd;
401 char err_msg[512];
402
403 slog("guest-fsfreeze called");
404
405 if (guest_fsfreeze_state.status == GUEST_FSFREEZE_STATUS_FROZEN) {
406 return 0;
407 }
408
409 ret = guest_fsfreeze_build_mount_list();
410 if (ret < 0) {
411 return ret;
412 }
413
414 /* cannot risk guest agent blocking itself on a write in this state */
415 disable_logging();
416
417 QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) {
418 fd = qemu_open(mount->dirname, O_RDONLY);
419 if (fd == -1) {
420 sprintf(err_msg, "failed to open %s, %s", mount->dirname, strerror(errno));
421 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
422 goto error;
423 }
424
425 /* we try to cull filesytems we know won't work in advance, but other
426 * filesytems may not implement fsfreeze for less obvious reasons.
427 * these will report EOPNOTSUPP, so we simply ignore them. when
428 * thawing, these filesystems will return an EINVAL instead, due to
429 * not being in a frozen state. Other filesystem-specific
430 * errors may result in EINVAL, however, so the user should check the
431 * number * of filesystems returned here against those returned by the
432 * thaw operation to determine whether everything completed
433 * successfully
434 */
435 ret = ioctl(fd, FIFREEZE);
436 if (ret < 0 && errno != EOPNOTSUPP) {
437 sprintf(err_msg, "failed to freeze %s, %s", mount->dirname, strerror(errno));
438 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
439 close(fd);
440 goto error;
441 }
442 close(fd);
443
444 i++;
445 }
446
447 guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_FROZEN;
448 return i;
449
450error:
451 if (i > 0) {
452 qmp_guest_fsfreeze_thaw(NULL);
453 }
454 return 0;
455}
456
457/*
458 * Walk list of frozen file systems in the guest, and thaw them.
459 */
460int64_t qmp_guest_fsfreeze_thaw(Error **err)
461{
462 int ret;
463 GuestFsfreezeMount *mount, *temp;
464 int fd, i = 0;
465 bool has_error = false;
466
467 QTAILQ_FOREACH_SAFE(mount, &guest_fsfreeze_state.mount_list, next, temp) {
468 fd = qemu_open(mount->dirname, O_RDONLY);
469 if (fd == -1) {
470 has_error = true;
471 continue;
472 }
473 ret = ioctl(fd, FITHAW);
474 if (ret < 0 && errno != EOPNOTSUPP && errno != EINVAL) {
475 has_error = true;
476 close(fd);
477 continue;
478 }
479 close(fd);
480 i++;
481 }
482
483 if (has_error) {
484 guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_ERROR;
485 } else {
486 guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_THAWED;
487 }
488 enable_logging();
489 return i;
490}
491
492static void guest_fsfreeze_init(void)
493{
494 guest_fsfreeze_state.status = GUEST_FSFREEZE_STATUS_THAWED;
495 QTAILQ_INIT(&guest_fsfreeze_state.mount_list);
496}
497
498static void guest_fsfreeze_cleanup(void)
499{
500 int64_t ret;
501 Error *err = NULL;
502
503 if (guest_fsfreeze_state.status == GUEST_FSFREEZE_STATUS_FROZEN) {
504 ret = qmp_guest_fsfreeze_thaw(&err);
505 if (ret < 0 || err) {
506 slog("failed to clean up frozen filesystems");
507 }
508 }
509}
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500510#else
511/*
512 * Return status of freeze/thaw
513 */
514GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
515{
Michael Roth9af99f12011-07-22 16:42:00 -0500516 error_set(err, QERR_UNSUPPORTED);
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500517
518 return 0;
519}
520
521/*
522 * Walk list of mounted file systems in the guest, and freeze the ones which
523 * are real local file systems.
524 */
525int64_t qmp_guest_fsfreeze_freeze(Error **err)
526{
Michael Roth9af99f12011-07-22 16:42:00 -0500527 error_set(err, QERR_UNSUPPORTED);
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500528
529 return 0;
530}
531
532/*
533 * Walk list of frozen file systems in the guest, and thaw them.
534 */
535int64_t qmp_guest_fsfreeze_thaw(Error **err)
536{
Michael Roth9af99f12011-07-22 16:42:00 -0500537 error_set(err, QERR_UNSUPPORTED);
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500538
539 return 0;
540}
541#endif
Michael Rothe3d4d252011-07-19 15:41:55 -0500542
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300543#define LINUX_SYS_STATE_FILE "/sys/power/state"
544#define SUSPEND_SUPPORTED 0
545#define SUSPEND_NOT_SUPPORTED 1
546
547/**
548 * This function forks twice and the information about the mode support
549 * status is passed to the qemu-ga process via a pipe.
550 *
551 * This approach allows us to keep the way we reap terminated children
552 * in qemu-ga quite simple.
553 */
554static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
555 const char *sysfile_str, Error **err)
556{
557 pid_t pid;
558 ssize_t ret;
559 char *pmutils_path;
560 int status, pipefds[2];
561
562 if (pipe(pipefds) < 0) {
563 error_set(err, QERR_UNDEFINED_ERROR);
564 return;
565 }
566
567 pmutils_path = g_find_program_in_path(pmutils_bin);
568
569 pid = fork();
570 if (!pid) {
571 struct sigaction act;
572
573 memset(&act, 0, sizeof(act));
574 act.sa_handler = SIG_DFL;
575 sigaction(SIGCHLD, &act, NULL);
576
577 setsid();
578 close(pipefds[0]);
579 reopen_fd_to_null(0);
580 reopen_fd_to_null(1);
581 reopen_fd_to_null(2);
582
583 pid = fork();
584 if (!pid) {
585 int fd;
586 char buf[32]; /* hopefully big enough */
587
588 if (pmutils_path) {
589 execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
590 }
591
592 /*
593 * If we get here either pm-utils is not installed or execle() has
594 * failed. Let's try the manual method if the caller wants it.
595 */
596
597 if (!sysfile_str) {
598 _exit(SUSPEND_NOT_SUPPORTED);
599 }
600
601 fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
602 if (fd < 0) {
603 _exit(SUSPEND_NOT_SUPPORTED);
604 }
605
606 ret = read(fd, buf, sizeof(buf)-1);
607 if (ret <= 0) {
608 _exit(SUSPEND_NOT_SUPPORTED);
609 }
610 buf[ret] = '\0';
611
612 if (strstr(buf, sysfile_str)) {
613 _exit(SUSPEND_SUPPORTED);
614 }
615
616 _exit(SUSPEND_NOT_SUPPORTED);
617 }
618
619 if (pid > 0) {
620 wait(&status);
621 } else {
622 status = SUSPEND_NOT_SUPPORTED;
623 }
624
625 ret = write(pipefds[1], &status, sizeof(status));
626 if (ret != sizeof(status)) {
627 _exit(EXIT_FAILURE);
628 }
629
630 _exit(EXIT_SUCCESS);
631 }
632
633 close(pipefds[1]);
634 g_free(pmutils_path);
635
636 if (pid < 0) {
637 error_set(err, QERR_UNDEFINED_ERROR);
638 goto out;
639 }
640
641 ret = read(pipefds[0], &status, sizeof(status));
642 if (ret == sizeof(status) && WIFEXITED(status) &&
643 WEXITSTATUS(status) == SUSPEND_SUPPORTED) {
644 goto out;
645 }
646
647 error_set(err, QERR_UNSUPPORTED);
648
649out:
650 close(pipefds[0]);
651}
652
653static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
654 Error **err)
655{
656 pid_t pid;
657 char *pmutils_path;
658
659 pmutils_path = g_find_program_in_path(pmutils_bin);
660
661 pid = fork();
662 if (pid == 0) {
663 /* child */
664 int fd;
665
666 setsid();
667 reopen_fd_to_null(0);
668 reopen_fd_to_null(1);
669 reopen_fd_to_null(2);
670
671 if (pmutils_path) {
672 execle(pmutils_path, pmutils_bin, NULL, environ);
673 }
674
675 /*
676 * If we get here either pm-utils is not installed or execle() has
677 * failed. Let's try the manual method if the caller wants it.
678 */
679
680 if (!sysfile_str) {
681 _exit(EXIT_FAILURE);
682 }
683
684 fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
685 if (fd < 0) {
686 _exit(EXIT_FAILURE);
687 }
688
689 if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
690 _exit(EXIT_FAILURE);
691 }
692
693 _exit(EXIT_SUCCESS);
694 }
695
696 g_free(pmutils_path);
697
698 if (pid < 0) {
699 error_set(err, QERR_UNDEFINED_ERROR);
700 return;
701 }
702}
703
704void qmp_guest_suspend_disk(Error **err)
705{
706 bios_supports_mode("pm-is-supported", "--hibernate", "disk", err);
707 if (error_is_set(err)) {
708 return;
709 }
710
711 guest_suspend("pm-hibernate", "disk", err);
712}
713
Luiz Capitulinofbf42212012-02-28 11:03:04 -0300714void qmp_guest_suspend_ram(Error **err)
715{
716 bios_supports_mode("pm-is-supported", "--suspend", "mem", err);
717 if (error_is_set(err)) {
718 return;
719 }
720
721 guest_suspend("pm-suspend", "mem", err);
722}
723
Luiz Capitulino95f4f402012-02-28 11:03:05 -0300724void qmp_guest_suspend_hybrid(Error **err)
725{
726 bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err);
727 if (error_is_set(err)) {
728 return;
729 }
730
731 guest_suspend("pm-suspend-hybrid", NULL, err);
732}
733
Michal Privoznik3424fc92012-02-29 17:02:23 +0100734static GuestNetworkInterfaceList *
735guest_find_interface(GuestNetworkInterfaceList *head,
736 const char *name)
737{
738 for (; head; head = head->next) {
739 if (strcmp(head->value->name, name) == 0) {
740 break;
741 }
742 }
743
744 return head;
745}
746
747/*
748 * Build information about guest interfaces
749 */
750GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
751{
752 GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
753 struct ifaddrs *ifap, *ifa;
754 char err_msg[512];
755
756 if (getifaddrs(&ifap) < 0) {
757 snprintf(err_msg, sizeof(err_msg),
758 "getifaddrs failed: %s", strerror(errno));
759 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
760 goto error;
761 }
762
763 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
764 GuestNetworkInterfaceList *info;
765 GuestIpAddressList **address_list = NULL, *address_item = NULL;
766 char addr4[INET_ADDRSTRLEN];
767 char addr6[INET6_ADDRSTRLEN];
768 int sock;
769 struct ifreq ifr;
770 unsigned char *mac_addr;
771 void *p;
772
773 g_debug("Processing %s interface", ifa->ifa_name);
774
775 info = guest_find_interface(head, ifa->ifa_name);
776
777 if (!info) {
778 info = g_malloc0(sizeof(*info));
779 info->value = g_malloc0(sizeof(*info->value));
780 info->value->name = g_strdup(ifa->ifa_name);
781
782 if (!cur_item) {
783 head = cur_item = info;
784 } else {
785 cur_item->next = info;
786 cur_item = info;
787 }
788 }
789
790 if (!info->value->has_hardware_address &&
791 ifa->ifa_flags & SIOCGIFHWADDR) {
792 /* we haven't obtained HW address yet */
793 sock = socket(PF_INET, SOCK_STREAM, 0);
794 if (sock == -1) {
795 snprintf(err_msg, sizeof(err_msg),
796 "failed to create socket: %s", strerror(errno));
797 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
798 goto error;
799 }
800
801 memset(&ifr, 0, sizeof(ifr));
802 strncpy(ifr.ifr_name, info->value->name, IF_NAMESIZE);
803 if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
804 snprintf(err_msg, sizeof(err_msg),
805 "failed to get MAC addres of %s: %s",
806 ifa->ifa_name,
807 strerror(errno));
808 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
809 goto error;
810 }
811
812 mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
813
814 if (asprintf(&info->value->hardware_address,
815 "%02x:%02x:%02x:%02x:%02x:%02x",
816 (int) mac_addr[0], (int) mac_addr[1],
817 (int) mac_addr[2], (int) mac_addr[3],
818 (int) mac_addr[4], (int) mac_addr[5]) == -1) {
819 snprintf(err_msg, sizeof(err_msg),
820 "failed to format MAC: %s", strerror(errno));
821 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
822 goto error;
823 }
824
825 info->value->has_hardware_address = true;
826 close(sock);
827 }
828
829 if (ifa->ifa_addr &&
830 ifa->ifa_addr->sa_family == AF_INET) {
831 /* interface with IPv4 address */
832 address_item = g_malloc0(sizeof(*address_item));
833 address_item->value = g_malloc0(sizeof(*address_item->value));
834 p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
835 if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
836 snprintf(err_msg, sizeof(err_msg),
837 "inet_ntop failed : %s", strerror(errno));
838 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
839 goto error;
840 }
841
842 address_item->value->ip_address = g_strdup(addr4);
843 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
844
845 if (ifa->ifa_netmask) {
846 /* Count the number of set bits in netmask.
847 * This is safe as '1' and '0' cannot be shuffled in netmask. */
848 p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
849 address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
850 }
851 } else if (ifa->ifa_addr &&
852 ifa->ifa_addr->sa_family == AF_INET6) {
853 /* interface with IPv6 address */
854 address_item = g_malloc0(sizeof(*address_item));
855 address_item->value = g_malloc0(sizeof(*address_item->value));
856 p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
857 if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
858 snprintf(err_msg, sizeof(err_msg),
859 "inet_ntop failed : %s", strerror(errno));
860 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
861 goto error;
862 }
863
864 address_item->value->ip_address = g_strdup(addr6);
865 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
866
867 if (ifa->ifa_netmask) {
868 /* Count the number of set bits in netmask.
869 * This is safe as '1' and '0' cannot be shuffled in netmask. */
870 p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
871 address_item->value->prefix =
872 ctpop32(((uint32_t *) p)[0]) +
873 ctpop32(((uint32_t *) p)[1]) +
874 ctpop32(((uint32_t *) p)[2]) +
875 ctpop32(((uint32_t *) p)[3]);
876 }
877 }
878
879 if (!address_item) {
880 continue;
881 }
882
883 address_list = &info->value->ip_addresses;
884
885 while (*address_list && (*address_list)->next) {
886 address_list = &(*address_list)->next;
887 }
888
889 if (!*address_list) {
890 *address_list = address_item;
891 } else {
892 (*address_list)->next = address_item;
893 }
894
895 info->value->has_ip_addresses = true;
896
897
898 }
899
900 freeifaddrs(ifap);
901 return head;
902
903error:
904 freeifaddrs(ifap);
905 qapi_free_GuestNetworkInterfaceList(head);
906 return NULL;
907}
908
Michael Rothe3d4d252011-07-19 15:41:55 -0500909/* register init/cleanup routines for stateful command groups */
910void ga_command_state_init(GAState *s, GACommandState *cs)
911{
912 ga_state = s;
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500913#if defined(CONFIG_FSFREEZE)
Michael Rothe3d4d252011-07-19 15:41:55 -0500914 ga_command_state_add(cs, guest_fsfreeze_init, guest_fsfreeze_cleanup);
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500915#endif
Michael Rothe3d4d252011-07-19 15:41:55 -0500916 ga_command_state_add(cs, guest_file_init, NULL);
917}