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