blob: dab3bf9c9875629806f930cc46693d3f6a8b19de [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"
20#include "qerror.h"
21#include "qemu-queue.h"
Michal Privoznik3424fc92012-02-29 17:02:23 +010022#include "host-utils.h"
Michael Rothe3d4d252011-07-19 15:41:55 -050023
Luiz Capitulino2c02cbf2012-05-23 15:48:05 -030024#ifndef CONFIG_HAS_ENVIRON
25extern char **environ;
26#endif
27
Michael Rothe72c3f22012-03-25 13:59:41 -050028#if defined(__linux__)
29#include <mntent.h>
30#include <linux/fs.h>
31#include <ifaddrs.h>
32#include <arpa/inet.h>
33#include <sys/socket.h>
34#include <net/if.h>
Michael Rothe72c3f22012-03-25 13:59:41 -050035
36#if defined(__linux__) && defined(FIFREEZE)
37#define CONFIG_FSFREEZE
38#endif
39#endif
40
Michael Rothe3d4d252011-07-19 15:41:55 -050041void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
42{
Michael Rothe3d4d252011-07-19 15:41:55 -050043 const char *shutdown_flag;
Luiz Capitulinod5dd3492012-05-11 16:19:47 -030044 pid_t rpid, pid;
Luiz Capitulino36748382012-05-14 15:25:20 -030045 int status;
Michael Rothe3d4d252011-07-19 15:41:55 -050046
47 slog("guest-shutdown called, mode: %s", mode);
48 if (!has_mode || strcmp(mode, "powerdown") == 0) {
49 shutdown_flag = "-P";
50 } else if (strcmp(mode, "halt") == 0) {
51 shutdown_flag = "-H";
52 } else if (strcmp(mode, "reboot") == 0) {
53 shutdown_flag = "-r";
54 } else {
55 error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode",
56 "halt|powerdown|reboot");
57 return;
58 }
59
Luiz Capitulinod5dd3492012-05-11 16:19:47 -030060 pid = fork();
61 if (pid == 0) {
Michael Rothe3d4d252011-07-19 15:41:55 -050062 /* child, start the shutdown */
63 setsid();
Luiz Capitulino36748382012-05-14 15:25:20 -030064 reopen_fd_to_null(0);
65 reopen_fd_to_null(1);
66 reopen_fd_to_null(2);
Michael Rothe3d4d252011-07-19 15:41:55 -050067
Luiz Capitulino36748382012-05-14 15:25:20 -030068 execle("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
69 "hypervisor initiated shutdown", (char*)NULL, environ);
70 _exit(EXIT_FAILURE);
Luiz Capitulinod5dd3492012-05-11 16:19:47 -030071 } else if (pid < 0) {
72 goto exit_err;
Michael Rothe3d4d252011-07-19 15:41:55 -050073 }
Luiz Capitulinod5dd3492012-05-11 16:19:47 -030074
75 do {
76 rpid = waitpid(pid, &status, 0);
77 } while (rpid == -1 && errno == EINTR);
78 if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
79 return;
80 }
81
82exit_err:
83 error_set(err, QERR_UNDEFINED_ERROR);
Michael Rothe3d4d252011-07-19 15:41:55 -050084}
85
86typedef struct GuestFileHandle {
87 uint64_t id;
88 FILE *fh;
89 QTAILQ_ENTRY(GuestFileHandle) next;
90} GuestFileHandle;
91
92static struct {
93 QTAILQ_HEAD(, GuestFileHandle) filehandles;
94} guest_file_state;
95
96static void guest_file_handle_add(FILE *fh)
97{
98 GuestFileHandle *gfh;
99
Anthony Liguori7267c092011-08-20 22:09:37 -0500100 gfh = g_malloc0(sizeof(GuestFileHandle));
Michael Rothe3d4d252011-07-19 15:41:55 -0500101 gfh->id = fileno(fh);
102 gfh->fh = fh;
103 QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
104}
105
106static GuestFileHandle *guest_file_handle_find(int64_t id)
107{
108 GuestFileHandle *gfh;
109
110 QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
111 {
112 if (gfh->id == id) {
113 return gfh;
114 }
115 }
116
117 return NULL;
118}
119
120int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
121{
122 FILE *fh;
123 int fd;
124 int64_t ret = -1;
125
126 if (!has_mode) {
127 mode = "r";
128 }
129 slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
130 fh = fopen(path, mode);
131 if (!fh) {
132 error_set(err, QERR_OPEN_FILE_FAILED, path);
133 return -1;
134 }
135
136 /* set fd non-blocking to avoid common use cases (like reading from a
137 * named pipe) from hanging the agent
138 */
139 fd = fileno(fh);
140 ret = fcntl(fd, F_GETFL);
141 ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
142 if (ret == -1) {
143 error_set(err, QERR_QGA_COMMAND_FAILED, "fcntl() failed");
144 fclose(fh);
145 return -1;
146 }
147
148 guest_file_handle_add(fh);
149 slog("guest-file-open, handle: %d", fd);
150 return fd;
151}
152
153void qmp_guest_file_close(int64_t handle, Error **err)
154{
155 GuestFileHandle *gfh = guest_file_handle_find(handle);
156 int ret;
157
158 slog("guest-file-close called, handle: %ld", handle);
159 if (!gfh) {
160 error_set(err, QERR_FD_NOT_FOUND, "handle");
161 return;
162 }
163
164 ret = fclose(gfh->fh);
165 if (ret == -1) {
166 error_set(err, QERR_QGA_COMMAND_FAILED, "fclose() failed");
167 return;
168 }
169
170 QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
Anthony Liguori7267c092011-08-20 22:09:37 -0500171 g_free(gfh);
Michael Rothe3d4d252011-07-19 15:41:55 -0500172}
173
174struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
175 int64_t count, Error **err)
176{
177 GuestFileHandle *gfh = guest_file_handle_find(handle);
178 GuestFileRead *read_data = NULL;
179 guchar *buf;
180 FILE *fh;
181 size_t read_count;
182
183 if (!gfh) {
184 error_set(err, QERR_FD_NOT_FOUND, "handle");
185 return NULL;
186 }
187
188 if (!has_count) {
189 count = QGA_READ_COUNT_DEFAULT;
190 } else if (count < 0) {
191 error_set(err, QERR_INVALID_PARAMETER, "count");
192 return NULL;
193 }
194
195 fh = gfh->fh;
Anthony Liguori7267c092011-08-20 22:09:37 -0500196 buf = g_malloc0(count+1);
Michael Rothe3d4d252011-07-19 15:41:55 -0500197 read_count = fread(buf, 1, count, fh);
198 if (ferror(fh)) {
199 slog("guest-file-read failed, handle: %ld", handle);
200 error_set(err, QERR_QGA_COMMAND_FAILED, "fread() failed");
201 } else {
202 buf[read_count] = 0;
Anthony Liguori7267c092011-08-20 22:09:37 -0500203 read_data = g_malloc0(sizeof(GuestFileRead));
Michael Rothe3d4d252011-07-19 15:41:55 -0500204 read_data->count = read_count;
205 read_data->eof = feof(fh);
206 if (read_count) {
207 read_data->buf_b64 = g_base64_encode(buf, read_count);
208 }
209 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500210 g_free(buf);
Michael Rothe3d4d252011-07-19 15:41:55 -0500211 clearerr(fh);
212
213 return read_data;
214}
215
216GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
217 bool has_count, int64_t count, Error **err)
218{
219 GuestFileWrite *write_data = NULL;
220 guchar *buf;
221 gsize buf_len;
222 int write_count;
223 GuestFileHandle *gfh = guest_file_handle_find(handle);
224 FILE *fh;
225
226 if (!gfh) {
227 error_set(err, QERR_FD_NOT_FOUND, "handle");
228 return NULL;
229 }
230
231 fh = gfh->fh;
232 buf = g_base64_decode(buf_b64, &buf_len);
233
234 if (!has_count) {
235 count = buf_len;
236 } else if (count < 0 || count > buf_len) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500237 g_free(buf);
Michael Rothe3d4d252011-07-19 15:41:55 -0500238 error_set(err, QERR_INVALID_PARAMETER, "count");
239 return NULL;
240 }
241
242 write_count = fwrite(buf, 1, count, fh);
243 if (ferror(fh)) {
244 slog("guest-file-write failed, handle: %ld", handle);
245 error_set(err, QERR_QGA_COMMAND_FAILED, "fwrite() error");
246 } else {
Anthony Liguori7267c092011-08-20 22:09:37 -0500247 write_data = g_malloc0(sizeof(GuestFileWrite));
Michael Rothe3d4d252011-07-19 15:41:55 -0500248 write_data->count = write_count;
249 write_data->eof = feof(fh);
250 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500251 g_free(buf);
Michael Rothe3d4d252011-07-19 15:41:55 -0500252 clearerr(fh);
253
254 return write_data;
255}
256
257struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
258 int64_t whence, Error **err)
259{
260 GuestFileHandle *gfh = guest_file_handle_find(handle);
261 GuestFileSeek *seek_data = NULL;
262 FILE *fh;
263 int ret;
264
265 if (!gfh) {
266 error_set(err, QERR_FD_NOT_FOUND, "handle");
267 return NULL;
268 }
269
270 fh = gfh->fh;
271 ret = fseek(fh, offset, whence);
272 if (ret == -1) {
273 error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
274 } else {
Anthony Liguori7267c092011-08-20 22:09:37 -0500275 seek_data = g_malloc0(sizeof(GuestFileRead));
Michael Rothe3d4d252011-07-19 15:41:55 -0500276 seek_data->position = ftell(fh);
277 seek_data->eof = feof(fh);
278 }
279 clearerr(fh);
280
281 return seek_data;
282}
283
284void qmp_guest_file_flush(int64_t handle, Error **err)
285{
286 GuestFileHandle *gfh = guest_file_handle_find(handle);
287 FILE *fh;
288 int ret;
289
290 if (!gfh) {
291 error_set(err, QERR_FD_NOT_FOUND, "handle");
292 return;
293 }
294
295 fh = gfh->fh;
296 ret = fflush(fh);
297 if (ret == EOF) {
298 error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
299 }
300}
301
302static void guest_file_init(void)
303{
304 QTAILQ_INIT(&guest_file_state.filehandles);
305}
306
Michael Rothe72c3f22012-03-25 13:59:41 -0500307/* linux-specific implementations. avoid this if at all possible. */
308#if defined(__linux__)
309
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500310#if defined(CONFIG_FSFREEZE)
Michael Rothe72c3f22012-03-25 13:59:41 -0500311
Michael Rothe3d4d252011-07-19 15:41:55 -0500312typedef struct GuestFsfreezeMount {
313 char *dirname;
314 char *devtype;
315 QTAILQ_ENTRY(GuestFsfreezeMount) next;
316} GuestFsfreezeMount;
317
Michael Roth9e8aded432012-04-16 19:52:17 -0500318typedef QTAILQ_HEAD(, GuestFsfreezeMount) GuestFsfreezeMountList;
319
Michael Roth9e8aded432012-04-16 19:52:17 -0500320static void guest_fsfreeze_free_mount_list(GuestFsfreezeMountList *mounts)
321{
322 GuestFsfreezeMount *mount, *temp;
323
324 if (!mounts) {
325 return;
326 }
327
328 QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) {
329 QTAILQ_REMOVE(mounts, mount, next);
330 g_free(mount->dirname);
331 g_free(mount->devtype);
332 g_free(mount);
333 }
334}
335
Michael Rothe3d4d252011-07-19 15:41:55 -0500336/*
337 * Walk the mount table and build a list of local file systems
338 */
Michael Roth9e8aded432012-04-16 19:52:17 -0500339static int guest_fsfreeze_build_mount_list(GuestFsfreezeMountList *mounts)
Michael Rothe3d4d252011-07-19 15:41:55 -0500340{
341 struct mntent *ment;
Michael Roth9e8aded432012-04-16 19:52:17 -0500342 GuestFsfreezeMount *mount;
Michael Rothe3d4d252011-07-19 15:41:55 -0500343 char const *mtab = MOUNTED;
344 FILE *fp;
345
Michael Rothe3d4d252011-07-19 15:41:55 -0500346 fp = setmntent(mtab, "r");
347 if (!fp) {
348 g_warning("fsfreeze: unable to read mtab");
349 return -1;
350 }
351
352 while ((ment = getmntent(fp))) {
353 /*
354 * An entry which device name doesn't start with a '/' is
355 * either a dummy file system or a network file system.
356 * Add special handling for smbfs and cifs as is done by
357 * coreutils as well.
358 */
359 if ((ment->mnt_fsname[0] != '/') ||
360 (strcmp(ment->mnt_type, "smbfs") == 0) ||
361 (strcmp(ment->mnt_type, "cifs") == 0)) {
362 continue;
363 }
364
Anthony Liguori7267c092011-08-20 22:09:37 -0500365 mount = g_malloc0(sizeof(GuestFsfreezeMount));
366 mount->dirname = g_strdup(ment->mnt_dir);
367 mount->devtype = g_strdup(ment->mnt_type);
Michael Rothe3d4d252011-07-19 15:41:55 -0500368
Michael Roth9e8aded432012-04-16 19:52:17 -0500369 QTAILQ_INSERT_TAIL(mounts, mount, next);
Michael Rothe3d4d252011-07-19 15:41:55 -0500370 }
371
372 endmntent(fp);
373
374 return 0;
375}
376
377/*
378 * Return status of freeze/thaw
379 */
380GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
381{
Michael Rothf22d85e2012-04-17 19:01:45 -0500382 if (ga_is_frozen(ga_state)) {
383 return GUEST_FSFREEZE_STATUS_FROZEN;
384 }
385
386 return GUEST_FSFREEZE_STATUS_THAWED;
Michael Rothe3d4d252011-07-19 15:41:55 -0500387}
388
389/*
390 * Walk list of mounted file systems in the guest, and freeze the ones which
391 * are real local file systems.
392 */
393int64_t qmp_guest_fsfreeze_freeze(Error **err)
394{
395 int ret = 0, i = 0;
Michael Roth9e8aded432012-04-16 19:52:17 -0500396 GuestFsfreezeMountList mounts;
397 struct GuestFsfreezeMount *mount;
Michael Rothe3d4d252011-07-19 15:41:55 -0500398 int fd;
399 char err_msg[512];
400
401 slog("guest-fsfreeze called");
402
Michael Roth9e8aded432012-04-16 19:52:17 -0500403 QTAILQ_INIT(&mounts);
404 ret = guest_fsfreeze_build_mount_list(&mounts);
Michael Rothe3d4d252011-07-19 15:41:55 -0500405 if (ret < 0) {
406 return ret;
407 }
408
409 /* cannot risk guest agent blocking itself on a write in this state */
Michael Rothf22d85e2012-04-17 19:01:45 -0500410 ga_set_frozen(ga_state);
Michael Rothe3d4d252011-07-19 15:41:55 -0500411
Michael Roth9e8aded432012-04-16 19:52:17 -0500412 QTAILQ_FOREACH(mount, &mounts, next) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500413 fd = qemu_open(mount->dirname, O_RDONLY);
414 if (fd == -1) {
Michael Roth9e8aded432012-04-16 19:52:17 -0500415 sprintf(err_msg, "failed to open %s, %s", mount->dirname,
416 strerror(errno));
Michael Rothe3d4d252011-07-19 15:41:55 -0500417 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
418 goto error;
419 }
420
421 /* we try to cull filesytems we know won't work in advance, but other
422 * filesytems may not implement fsfreeze for less obvious reasons.
Michael Roth9e8aded432012-04-16 19:52:17 -0500423 * these will report EOPNOTSUPP. we simply ignore these when tallying
424 * the number of frozen filesystems.
425 *
426 * any other error means a failure to freeze a filesystem we
427 * expect to be freezable, so return an error in those cases
428 * and return system to thawed state.
Michael Rothe3d4d252011-07-19 15:41:55 -0500429 */
430 ret = ioctl(fd, FIFREEZE);
Michael Roth9e8aded432012-04-16 19:52:17 -0500431 if (ret == -1) {
432 if (errno != EOPNOTSUPP) {
433 sprintf(err_msg, "failed to freeze %s, %s",
434 mount->dirname, strerror(errno));
435 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
436 close(fd);
437 goto error;
438 }
439 } else {
440 i++;
Michael Rothe3d4d252011-07-19 15:41:55 -0500441 }
442 close(fd);
Michael Rothe3d4d252011-07-19 15:41:55 -0500443 }
444
Michael Roth9e8aded432012-04-16 19:52:17 -0500445 guest_fsfreeze_free_mount_list(&mounts);
Michael Rothe3d4d252011-07-19 15:41:55 -0500446 return i;
447
448error:
Michael Roth9e8aded432012-04-16 19:52:17 -0500449 guest_fsfreeze_free_mount_list(&mounts);
450 qmp_guest_fsfreeze_thaw(NULL);
Michael Rothe3d4d252011-07-19 15:41:55 -0500451 return 0;
452}
453
454/*
455 * Walk list of frozen file systems in the guest, and thaw them.
456 */
457int64_t qmp_guest_fsfreeze_thaw(Error **err)
458{
459 int ret;
Michael Roth9e8aded432012-04-16 19:52:17 -0500460 GuestFsfreezeMountList mounts;
461 GuestFsfreezeMount *mount;
462 int fd, i = 0, logged;
Michael Rothe3d4d252011-07-19 15:41:55 -0500463
Michael Roth9e8aded432012-04-16 19:52:17 -0500464 QTAILQ_INIT(&mounts);
465 ret = guest_fsfreeze_build_mount_list(&mounts);
466 if (ret) {
467 error_set(err, QERR_QGA_COMMAND_FAILED,
468 "failed to enumerate filesystems");
469 return 0;
470 }
471
472 QTAILQ_FOREACH(mount, &mounts, next) {
473 logged = false;
Michael Rothe3d4d252011-07-19 15:41:55 -0500474 fd = qemu_open(mount->dirname, O_RDONLY);
475 if (fd == -1) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500476 continue;
477 }
Michael Roth9e8aded432012-04-16 19:52:17 -0500478 /* we have no way of knowing whether a filesystem was actually unfrozen
479 * as a result of a successful call to FITHAW, only that if an error
480 * was returned the filesystem was *not* unfrozen by that particular
481 * call.
482 *
Jim Meyeringa31f0532012-05-09 05:12:04 +0000483 * since multiple preceding FIFREEZEs require multiple calls to FITHAW
Michael Roth9e8aded432012-04-16 19:52:17 -0500484 * to unfreeze, continuing issuing FITHAW until an error is returned,
485 * in which case either the filesystem is in an unfreezable state, or,
486 * more likely, it was thawed previously (and remains so afterward).
487 *
488 * also, since the most recent successful call is the one that did
489 * the actual unfreeze, we can use this to provide an accurate count
490 * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which
491 * may * be useful for determining whether a filesystem was unfrozen
492 * during the freeze/thaw phase by a process other than qemu-ga.
493 */
494 do {
495 ret = ioctl(fd, FITHAW);
496 if (ret == 0 && !logged) {
497 i++;
498 logged = true;
499 }
500 } while (ret == 0);
Michael Rothe3d4d252011-07-19 15:41:55 -0500501 close(fd);
Michael Rothe3d4d252011-07-19 15:41:55 -0500502 }
503
Michael Rothf22d85e2012-04-17 19:01:45 -0500504 ga_unset_frozen(ga_state);
Michael Roth9e8aded432012-04-16 19:52:17 -0500505 guest_fsfreeze_free_mount_list(&mounts);
Michael Rothe3d4d252011-07-19 15:41:55 -0500506 return i;
507}
508
Michael Rothe3d4d252011-07-19 15:41:55 -0500509static void guest_fsfreeze_cleanup(void)
510{
511 int64_t ret;
512 Error *err = NULL;
513
Michael Rothf22d85e2012-04-17 19:01:45 -0500514 if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500515 ret = qmp_guest_fsfreeze_thaw(&err);
516 if (ret < 0 || err) {
517 slog("failed to clean up frozen filesystems");
518 }
519 }
520}
Michael Rothe72c3f22012-03-25 13:59:41 -0500521#endif /* CONFIG_FSFREEZE */
Michael Rothe3d4d252011-07-19 15:41:55 -0500522
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300523#define LINUX_SYS_STATE_FILE "/sys/power/state"
524#define SUSPEND_SUPPORTED 0
525#define SUSPEND_NOT_SUPPORTED 1
526
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300527static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
528 const char *sysfile_str, Error **err)
529{
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300530 char *pmutils_path;
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300531 pid_t pid, rpid;
532 int status;
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300533
534 pmutils_path = g_find_program_in_path(pmutils_bin);
535
536 pid = fork();
537 if (!pid) {
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300538 char buf[32]; /* hopefully big enough */
539 ssize_t ret;
540 int fd;
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300541
542 setsid();
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300543 reopen_fd_to_null(0);
544 reopen_fd_to_null(1);
545 reopen_fd_to_null(2);
546
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300547 if (pmutils_path) {
548 execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
549 }
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300550
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300551 /*
552 * If we get here either pm-utils is not installed or execle() has
553 * failed. Let's try the manual method if the caller wants it.
554 */
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300555
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300556 if (!sysfile_str) {
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300557 _exit(SUSPEND_NOT_SUPPORTED);
558 }
559
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300560 fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
561 if (fd < 0) {
562 _exit(SUSPEND_NOT_SUPPORTED);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300563 }
564
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300565 ret = read(fd, buf, sizeof(buf)-1);
566 if (ret <= 0) {
567 _exit(SUSPEND_NOT_SUPPORTED);
568 }
569 buf[ret] = '\0';
570
571 if (strstr(buf, sysfile_str)) {
572 _exit(SUSPEND_SUPPORTED);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300573 }
574
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300575 _exit(SUSPEND_NOT_SUPPORTED);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300576 }
577
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300578 g_free(pmutils_path);
579
580 if (pid < 0) {
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300581 goto undef_err;
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300582 }
583
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300584 do {
585 rpid = waitpid(pid, &status, 0);
586 } while (rpid == -1 && errno == EINTR);
587 if (rpid == pid && WIFEXITED(status)) {
588 switch (WEXITSTATUS(status)) {
589 case SUSPEND_SUPPORTED:
590 return;
591 case SUSPEND_NOT_SUPPORTED:
592 error_set(err, QERR_UNSUPPORTED);
593 return;
594 default:
595 goto undef_err;
596 }
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300597 }
598
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300599undef_err:
600 error_set(err, QERR_UNDEFINED_ERROR);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300601}
602
603static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
604 Error **err)
605{
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300606 char *pmutils_path;
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300607 pid_t rpid, pid;
608 int status;
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300609
610 pmutils_path = g_find_program_in_path(pmutils_bin);
611
612 pid = fork();
613 if (pid == 0) {
614 /* child */
615 int fd;
616
617 setsid();
618 reopen_fd_to_null(0);
619 reopen_fd_to_null(1);
620 reopen_fd_to_null(2);
621
622 if (pmutils_path) {
623 execle(pmutils_path, pmutils_bin, NULL, environ);
624 }
625
626 /*
627 * If we get here either pm-utils is not installed or execle() has
628 * failed. Let's try the manual method if the caller wants it.
629 */
630
631 if (!sysfile_str) {
632 _exit(EXIT_FAILURE);
633 }
634
635 fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
636 if (fd < 0) {
637 _exit(EXIT_FAILURE);
638 }
639
640 if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
641 _exit(EXIT_FAILURE);
642 }
643
644 _exit(EXIT_SUCCESS);
645 }
646
647 g_free(pmutils_path);
648
649 if (pid < 0) {
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300650 goto exit_err;
651 }
652
653 do {
654 rpid = waitpid(pid, &status, 0);
655 } while (rpid == -1 && errno == EINTR);
656 if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300657 return;
658 }
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300659
660exit_err:
661 error_set(err, QERR_UNDEFINED_ERROR);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300662}
663
664void qmp_guest_suspend_disk(Error **err)
665{
666 bios_supports_mode("pm-is-supported", "--hibernate", "disk", err);
667 if (error_is_set(err)) {
668 return;
669 }
670
671 guest_suspend("pm-hibernate", "disk", err);
672}
673
Luiz Capitulinofbf42212012-02-28 11:03:04 -0300674void qmp_guest_suspend_ram(Error **err)
675{
676 bios_supports_mode("pm-is-supported", "--suspend", "mem", err);
677 if (error_is_set(err)) {
678 return;
679 }
680
681 guest_suspend("pm-suspend", "mem", err);
682}
683
Luiz Capitulino95f4f402012-02-28 11:03:05 -0300684void qmp_guest_suspend_hybrid(Error **err)
685{
686 bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err);
687 if (error_is_set(err)) {
688 return;
689 }
690
691 guest_suspend("pm-suspend-hybrid", NULL, err);
692}
693
Michal Privoznik3424fc92012-02-29 17:02:23 +0100694static GuestNetworkInterfaceList *
695guest_find_interface(GuestNetworkInterfaceList *head,
696 const char *name)
697{
698 for (; head; head = head->next) {
699 if (strcmp(head->value->name, name) == 0) {
700 break;
701 }
702 }
703
704 return head;
705}
706
707/*
708 * Build information about guest interfaces
709 */
710GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
711{
712 GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
713 struct ifaddrs *ifap, *ifa;
714 char err_msg[512];
715
716 if (getifaddrs(&ifap) < 0) {
717 snprintf(err_msg, sizeof(err_msg),
718 "getifaddrs failed: %s", strerror(errno));
719 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
720 goto error;
721 }
722
723 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
724 GuestNetworkInterfaceList *info;
725 GuestIpAddressList **address_list = NULL, *address_item = NULL;
726 char addr4[INET_ADDRSTRLEN];
727 char addr6[INET6_ADDRSTRLEN];
728 int sock;
729 struct ifreq ifr;
730 unsigned char *mac_addr;
731 void *p;
732
733 g_debug("Processing %s interface", ifa->ifa_name);
734
735 info = guest_find_interface(head, ifa->ifa_name);
736
737 if (!info) {
738 info = g_malloc0(sizeof(*info));
739 info->value = g_malloc0(sizeof(*info->value));
740 info->value->name = g_strdup(ifa->ifa_name);
741
742 if (!cur_item) {
743 head = cur_item = info;
744 } else {
745 cur_item->next = info;
746 cur_item = info;
747 }
748 }
749
750 if (!info->value->has_hardware_address &&
751 ifa->ifa_flags & SIOCGIFHWADDR) {
752 /* we haven't obtained HW address yet */
753 sock = socket(PF_INET, SOCK_STREAM, 0);
754 if (sock == -1) {
755 snprintf(err_msg, sizeof(err_msg),
756 "failed to create socket: %s", strerror(errno));
757 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
758 goto error;
759 }
760
761 memset(&ifr, 0, sizeof(ifr));
762 strncpy(ifr.ifr_name, info->value->name, IF_NAMESIZE);
763 if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
764 snprintf(err_msg, sizeof(err_msg),
Jim Meyeringa31f0532012-05-09 05:12:04 +0000765 "failed to get MAC address of %s: %s",
Michal Privoznik3424fc92012-02-29 17:02:23 +0100766 ifa->ifa_name,
767 strerror(errno));
768 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
769 goto error;
770 }
771
772 mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
773
774 if (asprintf(&info->value->hardware_address,
775 "%02x:%02x:%02x:%02x:%02x:%02x",
776 (int) mac_addr[0], (int) mac_addr[1],
777 (int) mac_addr[2], (int) mac_addr[3],
778 (int) mac_addr[4], (int) mac_addr[5]) == -1) {
779 snprintf(err_msg, sizeof(err_msg),
780 "failed to format MAC: %s", strerror(errno));
781 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
782 goto error;
783 }
784
785 info->value->has_hardware_address = true;
786 close(sock);
787 }
788
789 if (ifa->ifa_addr &&
790 ifa->ifa_addr->sa_family == AF_INET) {
791 /* interface with IPv4 address */
792 address_item = g_malloc0(sizeof(*address_item));
793 address_item->value = g_malloc0(sizeof(*address_item->value));
794 p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
795 if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
796 snprintf(err_msg, sizeof(err_msg),
797 "inet_ntop failed : %s", strerror(errno));
798 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
799 goto error;
800 }
801
802 address_item->value->ip_address = g_strdup(addr4);
803 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
804
805 if (ifa->ifa_netmask) {
806 /* Count the number of set bits in netmask.
807 * This is safe as '1' and '0' cannot be shuffled in netmask. */
808 p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
809 address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
810 }
811 } else if (ifa->ifa_addr &&
812 ifa->ifa_addr->sa_family == AF_INET6) {
813 /* interface with IPv6 address */
814 address_item = g_malloc0(sizeof(*address_item));
815 address_item->value = g_malloc0(sizeof(*address_item->value));
816 p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
817 if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
818 snprintf(err_msg, sizeof(err_msg),
819 "inet_ntop failed : %s", strerror(errno));
820 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
821 goto error;
822 }
823
824 address_item->value->ip_address = g_strdup(addr6);
825 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
826
827 if (ifa->ifa_netmask) {
828 /* Count the number of set bits in netmask.
829 * This is safe as '1' and '0' cannot be shuffled in netmask. */
830 p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
831 address_item->value->prefix =
832 ctpop32(((uint32_t *) p)[0]) +
833 ctpop32(((uint32_t *) p)[1]) +
834 ctpop32(((uint32_t *) p)[2]) +
835 ctpop32(((uint32_t *) p)[3]);
836 }
837 }
838
839 if (!address_item) {
840 continue;
841 }
842
843 address_list = &info->value->ip_addresses;
844
845 while (*address_list && (*address_list)->next) {
846 address_list = &(*address_list)->next;
847 }
848
849 if (!*address_list) {
850 *address_list = address_item;
851 } else {
852 (*address_list)->next = address_item;
853 }
854
855 info->value->has_ip_addresses = true;
856
857
858 }
859
860 freeifaddrs(ifap);
861 return head;
862
863error:
864 freeifaddrs(ifap);
865 qapi_free_GuestNetworkInterfaceList(head);
866 return NULL;
867}
868
Michael Rothe72c3f22012-03-25 13:59:41 -0500869#else /* defined(__linux__) */
870
Michael Rothe72c3f22012-03-25 13:59:41 -0500871void qmp_guest_suspend_disk(Error **err)
872{
873 error_set(err, QERR_UNSUPPORTED);
874}
875
876void qmp_guest_suspend_ram(Error **err)
877{
878 error_set(err, QERR_UNSUPPORTED);
879}
880
881void qmp_guest_suspend_hybrid(Error **err)
882{
883 error_set(err, QERR_UNSUPPORTED);
884}
885
886GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
887{
888 error_set(errp, QERR_UNSUPPORTED);
889 return NULL;
890}
891
892#endif
893
Michael Rothd35d4cb2012-04-13 21:07:36 -0500894#if !defined(CONFIG_FSFREEZE)
895
896GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
897{
898 error_set(err, QERR_UNSUPPORTED);
899
900 return 0;
901}
902
903int64_t qmp_guest_fsfreeze_freeze(Error **err)
904{
905 error_set(err, QERR_UNSUPPORTED);
906
907 return 0;
908}
909
910int64_t qmp_guest_fsfreeze_thaw(Error **err)
911{
912 error_set(err, QERR_UNSUPPORTED);
913
914 return 0;
915}
916
917#endif
918
Michael Rothe3d4d252011-07-19 15:41:55 -0500919/* register init/cleanup routines for stateful command groups */
920void ga_command_state_init(GAState *s, GACommandState *cs)
921{
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500922#if defined(CONFIG_FSFREEZE)
Michael Rothf22d85e2012-04-17 19:01:45 -0500923 ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500924#endif
Michael Rothe3d4d252011-07-19 15:41:55 -0500925 ga_command_state_add(cs, guest_file_init, NULL);
926}