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