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