blob: bbef66dc6a47b0be3d0cd3f046e7685d4bb62a7d [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>
Michael Rothe3d4d252011-07-19 15:41:55 -050015#include <sys/types.h>
16#include <sys/ioctl.h>
Luiz Capitulino2c02cbf2012-05-23 15:48:05 -030017#include <sys/wait.h>
Michael Rothe3d4d252011-07-19 15:41:55 -050018#include "qga/guest-agent-core.h"
19#include "qga-qmp-commands.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010020#include "qapi/qmp/qerror.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010021#include "qemu/queue.h"
22#include "qemu/host-utils.h"
Michael Rothe3d4d252011-07-19 15:41:55 -050023
Luiz Capitulino2c02cbf2012-05-23 15:48:05 -030024#ifndef CONFIG_HAS_ENVIRON
Andreas Färbereecae142012-05-27 17:02:20 +020025#ifdef __APPLE__
26#include <crt_externs.h>
27#define environ (*_NSGetEnviron())
28#else
Luiz Capitulino2c02cbf2012-05-23 15:48:05 -030029extern char **environ;
30#endif
Andreas Färbereecae142012-05-27 17:02:20 +020031#endif
Luiz Capitulino2c02cbf2012-05-23 15:48:05 -030032
Michael Rothe72c3f22012-03-25 13:59:41 -050033#if defined(__linux__)
34#include <mntent.h>
35#include <linux/fs.h>
36#include <ifaddrs.h>
37#include <arpa/inet.h>
38#include <sys/socket.h>
39#include <net/if.h>
Michael Rothe72c3f22012-03-25 13:59:41 -050040
Paolo Bonzinieab5fd52012-06-13 07:41:28 +020041#ifdef FIFREEZE
Michael Rothe72c3f22012-03-25 13:59:41 -050042#define CONFIG_FSFREEZE
43#endif
Paolo Bonzinieab5fd52012-06-13 07:41:28 +020044#ifdef FITRIM
45#define CONFIG_FSTRIM
46#endif
Michael Rothe72c3f22012-03-25 13:59:41 -050047#endif
48
Michael Rothe3d4d252011-07-19 15:41:55 -050049void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
50{
Michael Rothe3d4d252011-07-19 15:41:55 -050051 const char *shutdown_flag;
Luiz Capitulinod5dd3492012-05-11 16:19:47 -030052 pid_t rpid, pid;
Luiz Capitulino36748382012-05-14 15:25:20 -030053 int status;
Michael Rothe3d4d252011-07-19 15:41:55 -050054
55 slog("guest-shutdown called, mode: %s", mode);
56 if (!has_mode || strcmp(mode, "powerdown") == 0) {
57 shutdown_flag = "-P";
58 } else if (strcmp(mode, "halt") == 0) {
59 shutdown_flag = "-H";
60 } else if (strcmp(mode, "reboot") == 0) {
61 shutdown_flag = "-r";
62 } else {
63 error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode",
64 "halt|powerdown|reboot");
65 return;
66 }
67
Luiz Capitulinod5dd3492012-05-11 16:19:47 -030068 pid = fork();
69 if (pid == 0) {
Michael Rothe3d4d252011-07-19 15:41:55 -050070 /* child, start the shutdown */
71 setsid();
Luiz Capitulino36748382012-05-14 15:25:20 -030072 reopen_fd_to_null(0);
73 reopen_fd_to_null(1);
74 reopen_fd_to_null(2);
Michael Rothe3d4d252011-07-19 15:41:55 -050075
Luiz Capitulino36748382012-05-14 15:25:20 -030076 execle("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
77 "hypervisor initiated shutdown", (char*)NULL, environ);
78 _exit(EXIT_FAILURE);
Luiz Capitulinod5dd3492012-05-11 16:19:47 -030079 } else if (pid < 0) {
80 goto exit_err;
Michael Rothe3d4d252011-07-19 15:41:55 -050081 }
Luiz Capitulinod5dd3492012-05-11 16:19:47 -030082
83 do {
84 rpid = waitpid(pid, &status, 0);
85 } while (rpid == -1 && errno == EINTR);
86 if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
87 return;
88 }
89
90exit_err:
91 error_set(err, QERR_UNDEFINED_ERROR);
Michael Rothe3d4d252011-07-19 15:41:55 -050092}
93
94typedef struct GuestFileHandle {
95 uint64_t id;
96 FILE *fh;
97 QTAILQ_ENTRY(GuestFileHandle) next;
98} GuestFileHandle;
99
100static struct {
101 QTAILQ_HEAD(, GuestFileHandle) filehandles;
102} guest_file_state;
103
104static void guest_file_handle_add(FILE *fh)
105{
106 GuestFileHandle *gfh;
107
Anthony Liguori7267c092011-08-20 22:09:37 -0500108 gfh = g_malloc0(sizeof(GuestFileHandle));
Michael Rothe3d4d252011-07-19 15:41:55 -0500109 gfh->id = fileno(fh);
110 gfh->fh = fh;
111 QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
112}
113
Luiz Capitulinoa9de6d02012-11-27 11:01:55 -0200114static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err)
Michael Rothe3d4d252011-07-19 15:41:55 -0500115{
116 GuestFileHandle *gfh;
117
118 QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
119 {
120 if (gfh->id == id) {
121 return gfh;
122 }
123 }
124
Luiz Capitulinoa9de6d02012-11-27 11:01:55 -0200125 error_setg(err, "handle '%" PRId64 "' has not been found", id);
Michael Rothe3d4d252011-07-19 15:41:55 -0500126 return NULL;
127}
128
129int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
130{
131 FILE *fh;
132 int fd;
133 int64_t ret = -1;
134
135 if (!has_mode) {
136 mode = "r";
137 }
138 slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
139 fh = fopen(path, mode);
140 if (!fh) {
141 error_set(err, QERR_OPEN_FILE_FAILED, path);
142 return -1;
143 }
144
145 /* set fd non-blocking to avoid common use cases (like reading from a
146 * named pipe) from hanging the agent
147 */
148 fd = fileno(fh);
149 ret = fcntl(fd, F_GETFL);
150 ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
151 if (ret == -1) {
152 error_set(err, QERR_QGA_COMMAND_FAILED, "fcntl() failed");
153 fclose(fh);
154 return -1;
155 }
156
157 guest_file_handle_add(fh);
158 slog("guest-file-open, handle: %d", fd);
159 return fd;
160}
161
162void qmp_guest_file_close(int64_t handle, Error **err)
163{
Luiz Capitulinoa9de6d02012-11-27 11:01:55 -0200164 GuestFileHandle *gfh = guest_file_handle_find(handle, err);
Michael Rothe3d4d252011-07-19 15:41:55 -0500165 int ret;
166
167 slog("guest-file-close called, handle: %ld", handle);
168 if (!gfh) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500169 return;
170 }
171
172 ret = fclose(gfh->fh);
173 if (ret == -1) {
174 error_set(err, QERR_QGA_COMMAND_FAILED, "fclose() failed");
175 return;
176 }
177
178 QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
Anthony Liguori7267c092011-08-20 22:09:37 -0500179 g_free(gfh);
Michael Rothe3d4d252011-07-19 15:41:55 -0500180}
181
182struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
183 int64_t count, Error **err)
184{
Luiz Capitulinoa9de6d02012-11-27 11:01:55 -0200185 GuestFileHandle *gfh = guest_file_handle_find(handle, err);
Michael Rothe3d4d252011-07-19 15:41:55 -0500186 GuestFileRead *read_data = NULL;
187 guchar *buf;
188 FILE *fh;
189 size_t read_count;
190
191 if (!gfh) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500192 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;
Luiz Capitulinoa9de6d02012-11-27 11:01:55 -0200230 GuestFileHandle *gfh = guest_file_handle_find(handle, err);
Michael Rothe3d4d252011-07-19 15:41:55 -0500231 FILE *fh;
232
233 if (!gfh) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500234 return NULL;
235 }
236
237 fh = gfh->fh;
238 buf = g_base64_decode(buf_b64, &buf_len);
239
240 if (!has_count) {
241 count = buf_len;
242 } else if (count < 0 || count > buf_len) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500243 g_free(buf);
Michael Rothe3d4d252011-07-19 15:41:55 -0500244 error_set(err, QERR_INVALID_PARAMETER, "count");
245 return NULL;
246 }
247
248 write_count = fwrite(buf, 1, count, fh);
249 if (ferror(fh)) {
250 slog("guest-file-write failed, handle: %ld", handle);
251 error_set(err, QERR_QGA_COMMAND_FAILED, "fwrite() error");
252 } else {
Anthony Liguori7267c092011-08-20 22:09:37 -0500253 write_data = g_malloc0(sizeof(GuestFileWrite));
Michael Rothe3d4d252011-07-19 15:41:55 -0500254 write_data->count = write_count;
255 write_data->eof = feof(fh);
256 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500257 g_free(buf);
Michael Rothe3d4d252011-07-19 15:41:55 -0500258 clearerr(fh);
259
260 return write_data;
261}
262
263struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
264 int64_t whence, Error **err)
265{
Luiz Capitulinoa9de6d02012-11-27 11:01:55 -0200266 GuestFileHandle *gfh = guest_file_handle_find(handle, err);
Michael Rothe3d4d252011-07-19 15:41:55 -0500267 GuestFileSeek *seek_data = NULL;
268 FILE *fh;
269 int ret;
270
271 if (!gfh) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500272 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 {
Anthony Liguori7267c092011-08-20 22:09:37 -0500280 seek_data = g_malloc0(sizeof(GuestFileRead));
Michael Rothe3d4d252011-07-19 15:41:55 -0500281 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{
Luiz Capitulinoa9de6d02012-11-27 11:01:55 -0200291 GuestFileHandle *gfh = guest_file_handle_find(handle, err);
Michael Rothe3d4d252011-07-19 15:41:55 -0500292 FILE *fh;
293 int ret;
294
295 if (!gfh) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500296 return;
297 }
298
299 fh = gfh->fh;
300 ret = fflush(fh);
301 if (ret == EOF) {
302 error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
303 }
304}
305
306static void guest_file_init(void)
307{
308 QTAILQ_INIT(&guest_file_state.filehandles);
309}
310
Michael Rothe72c3f22012-03-25 13:59:41 -0500311/* linux-specific implementations. avoid this if at all possible. */
312#if defined(__linux__)
313
Paolo Bonzinieab5fd52012-06-13 07:41:28 +0200314#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
Paolo Bonziniaf022032012-06-13 07:41:27 +0200315typedef struct FsMount {
Michael Rothe3d4d252011-07-19 15:41:55 -0500316 char *dirname;
317 char *devtype;
Paolo Bonziniaf022032012-06-13 07:41:27 +0200318 QTAILQ_ENTRY(FsMount) next;
319} FsMount;
Michael Rothe3d4d252011-07-19 15:41:55 -0500320
Paolo Bonziniaf022032012-06-13 07:41:27 +0200321typedef QTAILQ_HEAD(, FsMount) FsMountList;
Michael Roth9e8aded432012-04-16 19:52:17 -0500322
Paolo Bonziniaf022032012-06-13 07:41:27 +0200323static void free_fs_mount_list(FsMountList *mounts)
Michael Roth9e8aded432012-04-16 19:52:17 -0500324{
Paolo Bonziniaf022032012-06-13 07:41:27 +0200325 FsMount *mount, *temp;
Michael Roth9e8aded432012-04-16 19:52:17 -0500326
327 if (!mounts) {
328 return;
329 }
330
331 QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) {
332 QTAILQ_REMOVE(mounts, mount, next);
333 g_free(mount->dirname);
334 g_free(mount->devtype);
335 g_free(mount);
336 }
337}
338
Michael Rothe3d4d252011-07-19 15:41:55 -0500339/*
340 * Walk the mount table and build a list of local file systems
341 */
Paolo Bonziniaf022032012-06-13 07:41:27 +0200342static int build_fs_mount_list(FsMountList *mounts)
Michael Rothe3d4d252011-07-19 15:41:55 -0500343{
344 struct mntent *ment;
Paolo Bonziniaf022032012-06-13 07:41:27 +0200345 FsMount *mount;
Michael Roth9e2fa412012-05-29 10:08:50 -0500346 char const *mtab = "/proc/self/mounts";
Michael Rothe3d4d252011-07-19 15:41:55 -0500347 FILE *fp;
348
Michael Rothe3d4d252011-07-19 15:41:55 -0500349 fp = setmntent(mtab, "r");
350 if (!fp) {
351 g_warning("fsfreeze: unable to read mtab");
352 return -1;
353 }
354
355 while ((ment = getmntent(fp))) {
356 /*
357 * An entry which device name doesn't start with a '/' is
358 * either a dummy file system or a network file system.
359 * Add special handling for smbfs and cifs as is done by
360 * coreutils as well.
361 */
362 if ((ment->mnt_fsname[0] != '/') ||
363 (strcmp(ment->mnt_type, "smbfs") == 0) ||
364 (strcmp(ment->mnt_type, "cifs") == 0)) {
365 continue;
366 }
367
Paolo Bonziniaf022032012-06-13 07:41:27 +0200368 mount = g_malloc0(sizeof(FsMount));
Anthony Liguori7267c092011-08-20 22:09:37 -0500369 mount->dirname = g_strdup(ment->mnt_dir);
370 mount->devtype = g_strdup(ment->mnt_type);
Michael Rothe3d4d252011-07-19 15:41:55 -0500371
Michael Roth9e8aded432012-04-16 19:52:17 -0500372 QTAILQ_INSERT_TAIL(mounts, mount, next);
Michael Rothe3d4d252011-07-19 15:41:55 -0500373 }
374
375 endmntent(fp);
376
377 return 0;
378}
Paolo Bonzinieab5fd52012-06-13 07:41:28 +0200379#endif
380
381#if defined(CONFIG_FSFREEZE)
Michael Rothe3d4d252011-07-19 15:41:55 -0500382
383/*
384 * Return status of freeze/thaw
385 */
386GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
387{
Michael Rothf22d85e2012-04-17 19:01:45 -0500388 if (ga_is_frozen(ga_state)) {
389 return GUEST_FSFREEZE_STATUS_FROZEN;
390 }
391
392 return GUEST_FSFREEZE_STATUS_THAWED;
Michael Rothe3d4d252011-07-19 15:41:55 -0500393}
394
395/*
396 * Walk list of mounted file systems in the guest, and freeze the ones which
397 * are real local file systems.
398 */
399int64_t qmp_guest_fsfreeze_freeze(Error **err)
400{
401 int ret = 0, i = 0;
Paolo Bonziniaf022032012-06-13 07:41:27 +0200402 FsMountList mounts;
403 struct FsMount *mount;
Michael Rothe3d4d252011-07-19 15:41:55 -0500404 int fd;
405 char err_msg[512];
406
407 slog("guest-fsfreeze called");
408
Michael Roth9e8aded432012-04-16 19:52:17 -0500409 QTAILQ_INIT(&mounts);
Paolo Bonziniaf022032012-06-13 07:41:27 +0200410 ret = build_fs_mount_list(&mounts);
Michael Rothe3d4d252011-07-19 15:41:55 -0500411 if (ret < 0) {
412 return ret;
413 }
414
415 /* cannot risk guest agent blocking itself on a write in this state */
Michael Rothf22d85e2012-04-17 19:01:45 -0500416 ga_set_frozen(ga_state);
Michael Rothe3d4d252011-07-19 15:41:55 -0500417
Michael Roth9e8aded432012-04-16 19:52:17 -0500418 QTAILQ_FOREACH(mount, &mounts, next) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500419 fd = qemu_open(mount->dirname, O_RDONLY);
420 if (fd == -1) {
Michael Roth9e8aded432012-04-16 19:52:17 -0500421 sprintf(err_msg, "failed to open %s, %s", mount->dirname,
422 strerror(errno));
Michael Rothe3d4d252011-07-19 15:41:55 -0500423 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
424 goto error;
425 }
426
427 /* we try to cull filesytems we know won't work in advance, but other
428 * filesytems may not implement fsfreeze for less obvious reasons.
Michael Roth9e8aded432012-04-16 19:52:17 -0500429 * these will report EOPNOTSUPP. we simply ignore these when tallying
430 * the number of frozen filesystems.
431 *
432 * any other error means a failure to freeze a filesystem we
433 * expect to be freezable, so return an error in those cases
434 * and return system to thawed state.
Michael Rothe3d4d252011-07-19 15:41:55 -0500435 */
436 ret = ioctl(fd, FIFREEZE);
Michael Roth9e8aded432012-04-16 19:52:17 -0500437 if (ret == -1) {
438 if (errno != EOPNOTSUPP) {
439 sprintf(err_msg, "failed to freeze %s, %s",
440 mount->dirname, strerror(errno));
441 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
442 close(fd);
443 goto error;
444 }
445 } else {
446 i++;
Michael Rothe3d4d252011-07-19 15:41:55 -0500447 }
448 close(fd);
Michael Rothe3d4d252011-07-19 15:41:55 -0500449 }
450
Paolo Bonziniaf022032012-06-13 07:41:27 +0200451 free_fs_mount_list(&mounts);
Michael Rothe3d4d252011-07-19 15:41:55 -0500452 return i;
453
454error:
Paolo Bonziniaf022032012-06-13 07:41:27 +0200455 free_fs_mount_list(&mounts);
Michael Roth9e8aded432012-04-16 19:52:17 -0500456 qmp_guest_fsfreeze_thaw(NULL);
Michael Rothe3d4d252011-07-19 15:41:55 -0500457 return 0;
458}
459
460/*
461 * Walk list of frozen file systems in the guest, and thaw them.
462 */
463int64_t qmp_guest_fsfreeze_thaw(Error **err)
464{
465 int ret;
Paolo Bonziniaf022032012-06-13 07:41:27 +0200466 FsMountList mounts;
467 FsMount *mount;
Michael Roth9e8aded432012-04-16 19:52:17 -0500468 int fd, i = 0, logged;
Michael Rothe3d4d252011-07-19 15:41:55 -0500469
Michael Roth9e8aded432012-04-16 19:52:17 -0500470 QTAILQ_INIT(&mounts);
Paolo Bonziniaf022032012-06-13 07:41:27 +0200471 ret = build_fs_mount_list(&mounts);
Michael Roth9e8aded432012-04-16 19:52:17 -0500472 if (ret) {
473 error_set(err, QERR_QGA_COMMAND_FAILED,
474 "failed to enumerate filesystems");
475 return 0;
476 }
477
478 QTAILQ_FOREACH(mount, &mounts, next) {
479 logged = false;
Michael Rothe3d4d252011-07-19 15:41:55 -0500480 fd = qemu_open(mount->dirname, O_RDONLY);
481 if (fd == -1) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500482 continue;
483 }
Michael Roth9e8aded432012-04-16 19:52:17 -0500484 /* we have no way of knowing whether a filesystem was actually unfrozen
485 * as a result of a successful call to FITHAW, only that if an error
486 * was returned the filesystem was *not* unfrozen by that particular
487 * call.
488 *
Jim Meyeringa31f0532012-05-09 05:12:04 +0000489 * since multiple preceding FIFREEZEs require multiple calls to FITHAW
Michael Roth9e8aded432012-04-16 19:52:17 -0500490 * to unfreeze, continuing issuing FITHAW until an error is returned,
491 * in which case either the filesystem is in an unfreezable state, or,
492 * more likely, it was thawed previously (and remains so afterward).
493 *
494 * also, since the most recent successful call is the one that did
495 * the actual unfreeze, we can use this to provide an accurate count
496 * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which
497 * may * be useful for determining whether a filesystem was unfrozen
498 * during the freeze/thaw phase by a process other than qemu-ga.
499 */
500 do {
501 ret = ioctl(fd, FITHAW);
502 if (ret == 0 && !logged) {
503 i++;
504 logged = true;
505 }
506 } while (ret == 0);
Michael Rothe3d4d252011-07-19 15:41:55 -0500507 close(fd);
Michael Rothe3d4d252011-07-19 15:41:55 -0500508 }
509
Michael Rothf22d85e2012-04-17 19:01:45 -0500510 ga_unset_frozen(ga_state);
Paolo Bonziniaf022032012-06-13 07:41:27 +0200511 free_fs_mount_list(&mounts);
Michael Rothe3d4d252011-07-19 15:41:55 -0500512 return i;
513}
514
Michael Rothe3d4d252011-07-19 15:41:55 -0500515static void guest_fsfreeze_cleanup(void)
516{
517 int64_t ret;
518 Error *err = NULL;
519
Michael Rothf22d85e2012-04-17 19:01:45 -0500520 if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500521 ret = qmp_guest_fsfreeze_thaw(&err);
522 if (ret < 0 || err) {
523 slog("failed to clean up frozen filesystems");
524 }
525 }
526}
Michael Rothe72c3f22012-03-25 13:59:41 -0500527#endif /* CONFIG_FSFREEZE */
Michael Rothe3d4d252011-07-19 15:41:55 -0500528
Paolo Bonzinieab5fd52012-06-13 07:41:28 +0200529#if defined(CONFIG_FSTRIM)
530/*
531 * Walk list of mounted file systems in the guest, and trim them.
532 */
533void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err)
534{
535 int ret = 0;
536 FsMountList mounts;
537 struct FsMount *mount;
538 int fd;
539 char err_msg[512];
540 struct fstrim_range r = {
541 .start = 0,
542 .len = -1,
543 .minlen = has_minimum ? minimum : 0,
544 };
545
546 slog("guest-fstrim called");
547
548 QTAILQ_INIT(&mounts);
549 ret = build_fs_mount_list(&mounts);
550 if (ret < 0) {
551 return;
552 }
553
554 QTAILQ_FOREACH(mount, &mounts, next) {
555 fd = qemu_open(mount->dirname, O_RDONLY);
556 if (fd == -1) {
557 sprintf(err_msg, "failed to open %s, %s", mount->dirname,
558 strerror(errno));
559 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
560 goto error;
561 }
562
563 /* We try to cull filesytems we know won't work in advance, but other
564 * filesytems may not implement fstrim for less obvious reasons. These
565 * will report EOPNOTSUPP; we simply ignore these errors. Any other
566 * error means an unexpected error, so return it in those cases. In
567 * some other cases ENOTTY will be reported (e.g. CD-ROMs).
568 */
569 ret = ioctl(fd, FITRIM, &r);
570 if (ret == -1) {
571 if (errno != ENOTTY && errno != EOPNOTSUPP) {
572 sprintf(err_msg, "failed to trim %s, %s",
573 mount->dirname, strerror(errno));
574 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
575 close(fd);
576 goto error;
577 }
578 }
579 close(fd);
580 }
581
582error:
583 free_fs_mount_list(&mounts);
584}
585#endif /* CONFIG_FSTRIM */
586
587
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300588#define LINUX_SYS_STATE_FILE "/sys/power/state"
589#define SUSPEND_SUPPORTED 0
590#define SUSPEND_NOT_SUPPORTED 1
591
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300592static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
593 const char *sysfile_str, Error **err)
594{
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300595 char *pmutils_path;
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300596 pid_t pid, rpid;
597 int status;
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300598
599 pmutils_path = g_find_program_in_path(pmutils_bin);
600
601 pid = fork();
602 if (!pid) {
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300603 char buf[32]; /* hopefully big enough */
604 ssize_t ret;
605 int fd;
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300606
607 setsid();
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300608 reopen_fd_to_null(0);
609 reopen_fd_to_null(1);
610 reopen_fd_to_null(2);
611
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300612 if (pmutils_path) {
613 execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
614 }
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300615
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300616 /*
617 * If we get here either pm-utils is not installed or execle() has
618 * failed. Let's try the manual method if the caller wants it.
619 */
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300620
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300621 if (!sysfile_str) {
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300622 _exit(SUSPEND_NOT_SUPPORTED);
623 }
624
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300625 fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
626 if (fd < 0) {
627 _exit(SUSPEND_NOT_SUPPORTED);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300628 }
629
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300630 ret = read(fd, buf, sizeof(buf)-1);
631 if (ret <= 0) {
632 _exit(SUSPEND_NOT_SUPPORTED);
633 }
634 buf[ret] = '\0';
635
636 if (strstr(buf, sysfile_str)) {
637 _exit(SUSPEND_SUPPORTED);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300638 }
639
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300640 _exit(SUSPEND_NOT_SUPPORTED);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300641 }
642
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300643 g_free(pmutils_path);
644
645 if (pid < 0) {
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300646 goto undef_err;
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300647 }
648
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300649 do {
650 rpid = waitpid(pid, &status, 0);
651 } while (rpid == -1 && errno == EINTR);
652 if (rpid == pid && WIFEXITED(status)) {
653 switch (WEXITSTATUS(status)) {
654 case SUSPEND_SUPPORTED:
655 return;
656 case SUSPEND_NOT_SUPPORTED:
657 error_set(err, QERR_UNSUPPORTED);
658 return;
659 default:
660 goto undef_err;
661 }
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300662 }
663
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300664undef_err:
665 error_set(err, QERR_UNDEFINED_ERROR);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300666}
667
668static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
669 Error **err)
670{
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300671 char *pmutils_path;
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300672 pid_t rpid, pid;
673 int status;
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300674
675 pmutils_path = g_find_program_in_path(pmutils_bin);
676
677 pid = fork();
678 if (pid == 0) {
679 /* child */
680 int fd;
681
682 setsid();
683 reopen_fd_to_null(0);
684 reopen_fd_to_null(1);
685 reopen_fd_to_null(2);
686
687 if (pmutils_path) {
688 execle(pmutils_path, pmutils_bin, NULL, environ);
689 }
690
691 /*
692 * If we get here either pm-utils is not installed or execle() has
693 * failed. Let's try the manual method if the caller wants it.
694 */
695
696 if (!sysfile_str) {
697 _exit(EXIT_FAILURE);
698 }
699
700 fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
701 if (fd < 0) {
702 _exit(EXIT_FAILURE);
703 }
704
705 if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
706 _exit(EXIT_FAILURE);
707 }
708
709 _exit(EXIT_SUCCESS);
710 }
711
712 g_free(pmutils_path);
713
714 if (pid < 0) {
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300715 goto exit_err;
716 }
717
718 do {
719 rpid = waitpid(pid, &status, 0);
720 } while (rpid == -1 && errno == EINTR);
721 if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300722 return;
723 }
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300724
725exit_err:
726 error_set(err, QERR_UNDEFINED_ERROR);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300727}
728
729void qmp_guest_suspend_disk(Error **err)
730{
731 bios_supports_mode("pm-is-supported", "--hibernate", "disk", err);
732 if (error_is_set(err)) {
733 return;
734 }
735
736 guest_suspend("pm-hibernate", "disk", err);
737}
738
Luiz Capitulinofbf42212012-02-28 11:03:04 -0300739void qmp_guest_suspend_ram(Error **err)
740{
741 bios_supports_mode("pm-is-supported", "--suspend", "mem", err);
742 if (error_is_set(err)) {
743 return;
744 }
745
746 guest_suspend("pm-suspend", "mem", err);
747}
748
Luiz Capitulino95f4f402012-02-28 11:03:05 -0300749void qmp_guest_suspend_hybrid(Error **err)
750{
751 bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err);
752 if (error_is_set(err)) {
753 return;
754 }
755
756 guest_suspend("pm-suspend-hybrid", NULL, err);
757}
758
Michal Privoznik3424fc92012-02-29 17:02:23 +0100759static GuestNetworkInterfaceList *
760guest_find_interface(GuestNetworkInterfaceList *head,
761 const char *name)
762{
763 for (; head; head = head->next) {
764 if (strcmp(head->value->name, name) == 0) {
765 break;
766 }
767 }
768
769 return head;
770}
771
772/*
773 * Build information about guest interfaces
774 */
775GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
776{
777 GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
778 struct ifaddrs *ifap, *ifa;
779 char err_msg[512];
780
781 if (getifaddrs(&ifap) < 0) {
782 snprintf(err_msg, sizeof(err_msg),
783 "getifaddrs failed: %s", strerror(errno));
784 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
785 goto error;
786 }
787
788 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
789 GuestNetworkInterfaceList *info;
790 GuestIpAddressList **address_list = NULL, *address_item = NULL;
791 char addr4[INET_ADDRSTRLEN];
792 char addr6[INET6_ADDRSTRLEN];
793 int sock;
794 struct ifreq ifr;
795 unsigned char *mac_addr;
796 void *p;
797
798 g_debug("Processing %s interface", ifa->ifa_name);
799
800 info = guest_find_interface(head, ifa->ifa_name);
801
802 if (!info) {
803 info = g_malloc0(sizeof(*info));
804 info->value = g_malloc0(sizeof(*info->value));
805 info->value->name = g_strdup(ifa->ifa_name);
806
807 if (!cur_item) {
808 head = cur_item = info;
809 } else {
810 cur_item->next = info;
811 cur_item = info;
812 }
813 }
814
815 if (!info->value->has_hardware_address &&
816 ifa->ifa_flags & SIOCGIFHWADDR) {
817 /* we haven't obtained HW address yet */
818 sock = socket(PF_INET, SOCK_STREAM, 0);
819 if (sock == -1) {
820 snprintf(err_msg, sizeof(err_msg),
821 "failed to create socket: %s", strerror(errno));
822 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
823 goto error;
824 }
825
826 memset(&ifr, 0, sizeof(ifr));
Jim Meyering1ab516e2012-10-04 13:09:58 +0200827 pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->value->name);
Michal Privoznik3424fc92012-02-29 17:02:23 +0100828 if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
829 snprintf(err_msg, sizeof(err_msg),
Jim Meyeringa31f0532012-05-09 05:12:04 +0000830 "failed to get MAC address of %s: %s",
Michal Privoznik3424fc92012-02-29 17:02:23 +0100831 ifa->ifa_name,
832 strerror(errno));
833 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
834 goto error;
835 }
836
837 mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
838
839 if (asprintf(&info->value->hardware_address,
840 "%02x:%02x:%02x:%02x:%02x:%02x",
841 (int) mac_addr[0], (int) mac_addr[1],
842 (int) mac_addr[2], (int) mac_addr[3],
843 (int) mac_addr[4], (int) mac_addr[5]) == -1) {
844 snprintf(err_msg, sizeof(err_msg),
845 "failed to format MAC: %s", strerror(errno));
846 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
847 goto error;
848 }
849
850 info->value->has_hardware_address = true;
851 close(sock);
852 }
853
854 if (ifa->ifa_addr &&
855 ifa->ifa_addr->sa_family == AF_INET) {
856 /* interface with IPv4 address */
857 address_item = g_malloc0(sizeof(*address_item));
858 address_item->value = g_malloc0(sizeof(*address_item->value));
859 p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
860 if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
861 snprintf(err_msg, sizeof(err_msg),
862 "inet_ntop failed : %s", strerror(errno));
863 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
864 goto error;
865 }
866
867 address_item->value->ip_address = g_strdup(addr4);
868 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
869
870 if (ifa->ifa_netmask) {
871 /* Count the number of set bits in netmask.
872 * This is safe as '1' and '0' cannot be shuffled in netmask. */
873 p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
874 address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
875 }
876 } else if (ifa->ifa_addr &&
877 ifa->ifa_addr->sa_family == AF_INET6) {
878 /* interface with IPv6 address */
879 address_item = g_malloc0(sizeof(*address_item));
880 address_item->value = g_malloc0(sizeof(*address_item->value));
881 p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
882 if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
883 snprintf(err_msg, sizeof(err_msg),
884 "inet_ntop failed : %s", strerror(errno));
885 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
886 goto error;
887 }
888
889 address_item->value->ip_address = g_strdup(addr6);
890 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
891
892 if (ifa->ifa_netmask) {
893 /* Count the number of set bits in netmask.
894 * This is safe as '1' and '0' cannot be shuffled in netmask. */
895 p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
896 address_item->value->prefix =
897 ctpop32(((uint32_t *) p)[0]) +
898 ctpop32(((uint32_t *) p)[1]) +
899 ctpop32(((uint32_t *) p)[2]) +
900 ctpop32(((uint32_t *) p)[3]);
901 }
902 }
903
904 if (!address_item) {
905 continue;
906 }
907
908 address_list = &info->value->ip_addresses;
909
910 while (*address_list && (*address_list)->next) {
911 address_list = &(*address_list)->next;
912 }
913
914 if (!*address_list) {
915 *address_list = address_item;
916 } else {
917 (*address_list)->next = address_item;
918 }
919
920 info->value->has_ip_addresses = true;
921
922
923 }
924
925 freeifaddrs(ifap);
926 return head;
927
928error:
929 freeifaddrs(ifap);
930 qapi_free_GuestNetworkInterfaceList(head);
931 return NULL;
932}
933
Michael Rothe72c3f22012-03-25 13:59:41 -0500934#else /* defined(__linux__) */
935
Michael Rothe72c3f22012-03-25 13:59:41 -0500936void qmp_guest_suspend_disk(Error **err)
937{
938 error_set(err, QERR_UNSUPPORTED);
939}
940
941void qmp_guest_suspend_ram(Error **err)
942{
943 error_set(err, QERR_UNSUPPORTED);
944}
945
946void qmp_guest_suspend_hybrid(Error **err)
947{
948 error_set(err, QERR_UNSUPPORTED);
949}
950
951GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
952{
953 error_set(errp, QERR_UNSUPPORTED);
954 return NULL;
955}
956
957#endif
958
Michael Rothd35d4cb2012-04-13 21:07:36 -0500959#if !defined(CONFIG_FSFREEZE)
960
961GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
962{
963 error_set(err, QERR_UNSUPPORTED);
964
965 return 0;
966}
967
968int64_t qmp_guest_fsfreeze_freeze(Error **err)
969{
970 error_set(err, QERR_UNSUPPORTED);
971
972 return 0;
973}
974
975int64_t qmp_guest_fsfreeze_thaw(Error **err)
976{
977 error_set(err, QERR_UNSUPPORTED);
978
979 return 0;
980}
Paolo Bonzinieab5fd52012-06-13 07:41:28 +0200981#endif /* CONFIG_FSFREEZE */
Michael Rothd35d4cb2012-04-13 21:07:36 -0500982
Paolo Bonzinieab5fd52012-06-13 07:41:28 +0200983#if !defined(CONFIG_FSTRIM)
984void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err)
985{
986 error_set(err, QERR_UNSUPPORTED);
Paolo Bonzinieab5fd52012-06-13 07:41:28 +0200987}
Michael Rothd35d4cb2012-04-13 21:07:36 -0500988#endif
989
Michael Rothe3d4d252011-07-19 15:41:55 -0500990/* register init/cleanup routines for stateful command groups */
991void ga_command_state_init(GAState *s, GACommandState *cs)
992{
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500993#if defined(CONFIG_FSFREEZE)
Michael Rothf22d85e2012-04-17 19:01:45 -0500994 ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500995#endif
Michael Rothe3d4d252011-07-19 15:41:55 -0500996 ga_command_state_add(cs, guest_file_init, NULL);
997}