blob: 4a71c27c4a20172f6cd7576d7b803df82ef5b664 [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
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
41#if defined(__linux__) && defined(FIFREEZE)
42#define CONFIG_FSFREEZE
43#endif
44#endif
45
Michael Rothe3d4d252011-07-19 15:41:55 -050046void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
47{
Michael Rothe3d4d252011-07-19 15:41:55 -050048 const char *shutdown_flag;
Luiz Capitulinod5dd3492012-05-11 16:19:47 -030049 pid_t rpid, pid;
Luiz Capitulino36748382012-05-14 15:25:20 -030050 int status;
Michael Rothe3d4d252011-07-19 15:41:55 -050051
52 slog("guest-shutdown called, mode: %s", mode);
53 if (!has_mode || strcmp(mode, "powerdown") == 0) {
54 shutdown_flag = "-P";
55 } else if (strcmp(mode, "halt") == 0) {
56 shutdown_flag = "-H";
57 } else if (strcmp(mode, "reboot") == 0) {
58 shutdown_flag = "-r";
59 } else {
60 error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode",
61 "halt|powerdown|reboot");
62 return;
63 }
64
Luiz Capitulinod5dd3492012-05-11 16:19:47 -030065 pid = fork();
66 if (pid == 0) {
Michael Rothe3d4d252011-07-19 15:41:55 -050067 /* child, start the shutdown */
68 setsid();
Luiz Capitulino36748382012-05-14 15:25:20 -030069 reopen_fd_to_null(0);
70 reopen_fd_to_null(1);
71 reopen_fd_to_null(2);
Michael Rothe3d4d252011-07-19 15:41:55 -050072
Luiz Capitulino36748382012-05-14 15:25:20 -030073 execle("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
74 "hypervisor initiated shutdown", (char*)NULL, environ);
75 _exit(EXIT_FAILURE);
Luiz Capitulinod5dd3492012-05-11 16:19:47 -030076 } else if (pid < 0) {
77 goto exit_err;
Michael Rothe3d4d252011-07-19 15:41:55 -050078 }
Luiz Capitulinod5dd3492012-05-11 16:19:47 -030079
80 do {
81 rpid = waitpid(pid, &status, 0);
82 } while (rpid == -1 && errno == EINTR);
83 if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
84 return;
85 }
86
87exit_err:
88 error_set(err, QERR_UNDEFINED_ERROR);
Michael Rothe3d4d252011-07-19 15:41:55 -050089}
90
91typedef struct GuestFileHandle {
92 uint64_t id;
93 FILE *fh;
94 QTAILQ_ENTRY(GuestFileHandle) next;
95} GuestFileHandle;
96
97static struct {
98 QTAILQ_HEAD(, GuestFileHandle) filehandles;
99} guest_file_state;
100
101static void guest_file_handle_add(FILE *fh)
102{
103 GuestFileHandle *gfh;
104
Anthony Liguori7267c092011-08-20 22:09:37 -0500105 gfh = g_malloc0(sizeof(GuestFileHandle));
Michael Rothe3d4d252011-07-19 15:41:55 -0500106 gfh->id = fileno(fh);
107 gfh->fh = fh;
108 QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
109}
110
111static GuestFileHandle *guest_file_handle_find(int64_t id)
112{
113 GuestFileHandle *gfh;
114
115 QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
116 {
117 if (gfh->id == id) {
118 return gfh;
119 }
120 }
121
122 return NULL;
123}
124
125int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
126{
127 FILE *fh;
128 int fd;
129 int64_t ret = -1;
130
131 if (!has_mode) {
132 mode = "r";
133 }
134 slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
135 fh = fopen(path, mode);
136 if (!fh) {
137 error_set(err, QERR_OPEN_FILE_FAILED, path);
138 return -1;
139 }
140
141 /* set fd non-blocking to avoid common use cases (like reading from a
142 * named pipe) from hanging the agent
143 */
144 fd = fileno(fh);
145 ret = fcntl(fd, F_GETFL);
146 ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
147 if (ret == -1) {
148 error_set(err, QERR_QGA_COMMAND_FAILED, "fcntl() failed");
149 fclose(fh);
150 return -1;
151 }
152
153 guest_file_handle_add(fh);
154 slog("guest-file-open, handle: %d", fd);
155 return fd;
156}
157
158void qmp_guest_file_close(int64_t handle, Error **err)
159{
160 GuestFileHandle *gfh = guest_file_handle_find(handle);
161 int ret;
162
163 slog("guest-file-close called, handle: %ld", handle);
164 if (!gfh) {
165 error_set(err, QERR_FD_NOT_FOUND, "handle");
166 return;
167 }
168
169 ret = fclose(gfh->fh);
170 if (ret == -1) {
171 error_set(err, QERR_QGA_COMMAND_FAILED, "fclose() failed");
172 return;
173 }
174
175 QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
Anthony Liguori7267c092011-08-20 22:09:37 -0500176 g_free(gfh);
Michael Rothe3d4d252011-07-19 15:41:55 -0500177}
178
179struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
180 int64_t count, Error **err)
181{
182 GuestFileHandle *gfh = guest_file_handle_find(handle);
183 GuestFileRead *read_data = NULL;
184 guchar *buf;
185 FILE *fh;
186 size_t read_count;
187
188 if (!gfh) {
189 error_set(err, QERR_FD_NOT_FOUND, "handle");
190 return NULL;
191 }
192
193 if (!has_count) {
194 count = QGA_READ_COUNT_DEFAULT;
195 } else if (count < 0) {
196 error_set(err, QERR_INVALID_PARAMETER, "count");
197 return NULL;
198 }
199
200 fh = gfh->fh;
Anthony Liguori7267c092011-08-20 22:09:37 -0500201 buf = g_malloc0(count+1);
Michael Rothe3d4d252011-07-19 15:41:55 -0500202 read_count = fread(buf, 1, count, fh);
203 if (ferror(fh)) {
204 slog("guest-file-read failed, handle: %ld", handle);
205 error_set(err, QERR_QGA_COMMAND_FAILED, "fread() failed");
206 } else {
207 buf[read_count] = 0;
Anthony Liguori7267c092011-08-20 22:09:37 -0500208 read_data = g_malloc0(sizeof(GuestFileRead));
Michael Rothe3d4d252011-07-19 15:41:55 -0500209 read_data->count = read_count;
210 read_data->eof = feof(fh);
211 if (read_count) {
212 read_data->buf_b64 = g_base64_encode(buf, read_count);
213 }
214 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500215 g_free(buf);
Michael Rothe3d4d252011-07-19 15:41:55 -0500216 clearerr(fh);
217
218 return read_data;
219}
220
221GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
222 bool has_count, int64_t count, Error **err)
223{
224 GuestFileWrite *write_data = NULL;
225 guchar *buf;
226 gsize buf_len;
227 int write_count;
228 GuestFileHandle *gfh = guest_file_handle_find(handle);
229 FILE *fh;
230
231 if (!gfh) {
232 error_set(err, QERR_FD_NOT_FOUND, "handle");
233 return NULL;
234 }
235
236 fh = gfh->fh;
237 buf = g_base64_decode(buf_b64, &buf_len);
238
239 if (!has_count) {
240 count = buf_len;
241 } else if (count < 0 || count > buf_len) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500242 g_free(buf);
Michael Rothe3d4d252011-07-19 15:41:55 -0500243 error_set(err, QERR_INVALID_PARAMETER, "count");
244 return NULL;
245 }
246
247 write_count = fwrite(buf, 1, count, fh);
248 if (ferror(fh)) {
249 slog("guest-file-write failed, handle: %ld", handle);
250 error_set(err, QERR_QGA_COMMAND_FAILED, "fwrite() error");
251 } else {
Anthony Liguori7267c092011-08-20 22:09:37 -0500252 write_data = g_malloc0(sizeof(GuestFileWrite));
Michael Rothe3d4d252011-07-19 15:41:55 -0500253 write_data->count = write_count;
254 write_data->eof = feof(fh);
255 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500256 g_free(buf);
Michael Rothe3d4d252011-07-19 15:41:55 -0500257 clearerr(fh);
258
259 return write_data;
260}
261
262struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
263 int64_t whence, Error **err)
264{
265 GuestFileHandle *gfh = guest_file_handle_find(handle);
266 GuestFileSeek *seek_data = NULL;
267 FILE *fh;
268 int ret;
269
270 if (!gfh) {
271 error_set(err, QERR_FD_NOT_FOUND, "handle");
272 return NULL;
273 }
274
275 fh = gfh->fh;
276 ret = fseek(fh, offset, whence);
277 if (ret == -1) {
278 error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
279 } else {
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{
291 GuestFileHandle *gfh = guest_file_handle_find(handle);
292 FILE *fh;
293 int ret;
294
295 if (!gfh) {
296 error_set(err, QERR_FD_NOT_FOUND, "handle");
297 return;
298 }
299
300 fh = gfh->fh;
301 ret = fflush(fh);
302 if (ret == EOF) {
303 error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
304 }
305}
306
307static void guest_file_init(void)
308{
309 QTAILQ_INIT(&guest_file_state.filehandles);
310}
311
Michael Rothe72c3f22012-03-25 13:59:41 -0500312/* linux-specific implementations. avoid this if at all possible. */
313#if defined(__linux__)
314
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500315#if defined(CONFIG_FSFREEZE)
Michael Rothe72c3f22012-03-25 13:59:41 -0500316
Michael Rothe3d4d252011-07-19 15:41:55 -0500317typedef struct GuestFsfreezeMount {
318 char *dirname;
319 char *devtype;
320 QTAILQ_ENTRY(GuestFsfreezeMount) next;
321} GuestFsfreezeMount;
322
Michael Roth9e8aded432012-04-16 19:52:17 -0500323typedef QTAILQ_HEAD(, GuestFsfreezeMount) GuestFsfreezeMountList;
324
Michael Roth9e8aded432012-04-16 19:52:17 -0500325static void guest_fsfreeze_free_mount_list(GuestFsfreezeMountList *mounts)
326{
327 GuestFsfreezeMount *mount, *temp;
328
329 if (!mounts) {
330 return;
331 }
332
333 QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) {
334 QTAILQ_REMOVE(mounts, mount, next);
335 g_free(mount->dirname);
336 g_free(mount->devtype);
337 g_free(mount);
338 }
339}
340
Michael Rothe3d4d252011-07-19 15:41:55 -0500341/*
342 * Walk the mount table and build a list of local file systems
343 */
Michael Roth9e8aded432012-04-16 19:52:17 -0500344static int guest_fsfreeze_build_mount_list(GuestFsfreezeMountList *mounts)
Michael Rothe3d4d252011-07-19 15:41:55 -0500345{
346 struct mntent *ment;
Michael Roth9e8aded432012-04-16 19:52:17 -0500347 GuestFsfreezeMount *mount;
Michael Rothe3d4d252011-07-19 15:41:55 -0500348 char const *mtab = MOUNTED;
349 FILE *fp;
350
Michael Rothe3d4d252011-07-19 15:41:55 -0500351 fp = setmntent(mtab, "r");
352 if (!fp) {
353 g_warning("fsfreeze: unable to read mtab");
354 return -1;
355 }
356
357 while ((ment = getmntent(fp))) {
358 /*
359 * An entry which device name doesn't start with a '/' is
360 * either a dummy file system or a network file system.
361 * Add special handling for smbfs and cifs as is done by
362 * coreutils as well.
363 */
364 if ((ment->mnt_fsname[0] != '/') ||
365 (strcmp(ment->mnt_type, "smbfs") == 0) ||
366 (strcmp(ment->mnt_type, "cifs") == 0)) {
367 continue;
368 }
369
Anthony Liguori7267c092011-08-20 22:09:37 -0500370 mount = g_malloc0(sizeof(GuestFsfreezeMount));
371 mount->dirname = g_strdup(ment->mnt_dir);
372 mount->devtype = g_strdup(ment->mnt_type);
Michael Rothe3d4d252011-07-19 15:41:55 -0500373
Michael Roth9e8aded432012-04-16 19:52:17 -0500374 QTAILQ_INSERT_TAIL(mounts, mount, next);
Michael Rothe3d4d252011-07-19 15:41:55 -0500375 }
376
377 endmntent(fp);
378
379 return 0;
380}
381
382/*
383 * Return status of freeze/thaw
384 */
385GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
386{
Michael Rothf22d85e2012-04-17 19:01:45 -0500387 if (ga_is_frozen(ga_state)) {
388 return GUEST_FSFREEZE_STATUS_FROZEN;
389 }
390
391 return GUEST_FSFREEZE_STATUS_THAWED;
Michael Rothe3d4d252011-07-19 15:41:55 -0500392}
393
394/*
395 * Walk list of mounted file systems in the guest, and freeze the ones which
396 * are real local file systems.
397 */
398int64_t qmp_guest_fsfreeze_freeze(Error **err)
399{
400 int ret = 0, i = 0;
Michael Roth9e8aded432012-04-16 19:52:17 -0500401 GuestFsfreezeMountList mounts;
402 struct GuestFsfreezeMount *mount;
Michael Rothe3d4d252011-07-19 15:41:55 -0500403 int fd;
404 char err_msg[512];
405
406 slog("guest-fsfreeze called");
407
Michael Roth9e8aded432012-04-16 19:52:17 -0500408 QTAILQ_INIT(&mounts);
409 ret = guest_fsfreeze_build_mount_list(&mounts);
Michael Rothe3d4d252011-07-19 15:41:55 -0500410 if (ret < 0) {
411 return ret;
412 }
413
414 /* cannot risk guest agent blocking itself on a write in this state */
Michael Rothf22d85e2012-04-17 19:01:45 -0500415 ga_set_frozen(ga_state);
Michael Rothe3d4d252011-07-19 15:41:55 -0500416
Michael Roth9e8aded432012-04-16 19:52:17 -0500417 QTAILQ_FOREACH(mount, &mounts, next) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500418 fd = qemu_open(mount->dirname, O_RDONLY);
419 if (fd == -1) {
Michael Roth9e8aded432012-04-16 19:52:17 -0500420 sprintf(err_msg, "failed to open %s, %s", mount->dirname,
421 strerror(errno));
Michael Rothe3d4d252011-07-19 15:41:55 -0500422 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
423 goto error;
424 }
425
426 /* we try to cull filesytems we know won't work in advance, but other
427 * filesytems may not implement fsfreeze for less obvious reasons.
Michael Roth9e8aded432012-04-16 19:52:17 -0500428 * these will report EOPNOTSUPP. we simply ignore these when tallying
429 * the number of frozen filesystems.
430 *
431 * any other error means a failure to freeze a filesystem we
432 * expect to be freezable, so return an error in those cases
433 * and return system to thawed state.
Michael Rothe3d4d252011-07-19 15:41:55 -0500434 */
435 ret = ioctl(fd, FIFREEZE);
Michael Roth9e8aded432012-04-16 19:52:17 -0500436 if (ret == -1) {
437 if (errno != EOPNOTSUPP) {
438 sprintf(err_msg, "failed to freeze %s, %s",
439 mount->dirname, strerror(errno));
440 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
441 close(fd);
442 goto error;
443 }
444 } else {
445 i++;
Michael Rothe3d4d252011-07-19 15:41:55 -0500446 }
447 close(fd);
Michael Rothe3d4d252011-07-19 15:41:55 -0500448 }
449
Michael Roth9e8aded432012-04-16 19:52:17 -0500450 guest_fsfreeze_free_mount_list(&mounts);
Michael Rothe3d4d252011-07-19 15:41:55 -0500451 return i;
452
453error:
Michael Roth9e8aded432012-04-16 19:52:17 -0500454 guest_fsfreeze_free_mount_list(&mounts);
455 qmp_guest_fsfreeze_thaw(NULL);
Michael Rothe3d4d252011-07-19 15:41:55 -0500456 return 0;
457}
458
459/*
460 * Walk list of frozen file systems in the guest, and thaw them.
461 */
462int64_t qmp_guest_fsfreeze_thaw(Error **err)
463{
464 int ret;
Michael Roth9e8aded432012-04-16 19:52:17 -0500465 GuestFsfreezeMountList mounts;
466 GuestFsfreezeMount *mount;
467 int fd, i = 0, logged;
Michael Rothe3d4d252011-07-19 15:41:55 -0500468
Michael Roth9e8aded432012-04-16 19:52:17 -0500469 QTAILQ_INIT(&mounts);
470 ret = guest_fsfreeze_build_mount_list(&mounts);
471 if (ret) {
472 error_set(err, QERR_QGA_COMMAND_FAILED,
473 "failed to enumerate filesystems");
474 return 0;
475 }
476
477 QTAILQ_FOREACH(mount, &mounts, next) {
478 logged = false;
Michael Rothe3d4d252011-07-19 15:41:55 -0500479 fd = qemu_open(mount->dirname, O_RDONLY);
480 if (fd == -1) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500481 continue;
482 }
Michael Roth9e8aded432012-04-16 19:52:17 -0500483 /* we have no way of knowing whether a filesystem was actually unfrozen
484 * as a result of a successful call to FITHAW, only that if an error
485 * was returned the filesystem was *not* unfrozen by that particular
486 * call.
487 *
Jim Meyeringa31f0532012-05-09 05:12:04 +0000488 * since multiple preceding FIFREEZEs require multiple calls to FITHAW
Michael Roth9e8aded432012-04-16 19:52:17 -0500489 * to unfreeze, continuing issuing FITHAW until an error is returned,
490 * in which case either the filesystem is in an unfreezable state, or,
491 * more likely, it was thawed previously (and remains so afterward).
492 *
493 * also, since the most recent successful call is the one that did
494 * the actual unfreeze, we can use this to provide an accurate count
495 * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which
496 * may * be useful for determining whether a filesystem was unfrozen
497 * during the freeze/thaw phase by a process other than qemu-ga.
498 */
499 do {
500 ret = ioctl(fd, FITHAW);
501 if (ret == 0 && !logged) {
502 i++;
503 logged = true;
504 }
505 } while (ret == 0);
Michael Rothe3d4d252011-07-19 15:41:55 -0500506 close(fd);
Michael Rothe3d4d252011-07-19 15:41:55 -0500507 }
508
Michael Rothf22d85e2012-04-17 19:01:45 -0500509 ga_unset_frozen(ga_state);
Michael Roth9e8aded432012-04-16 19:52:17 -0500510 guest_fsfreeze_free_mount_list(&mounts);
Michael Rothe3d4d252011-07-19 15:41:55 -0500511 return i;
512}
513
Michael Rothe3d4d252011-07-19 15:41:55 -0500514static void guest_fsfreeze_cleanup(void)
515{
516 int64_t ret;
517 Error *err = NULL;
518
Michael Rothf22d85e2012-04-17 19:01:45 -0500519 if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500520 ret = qmp_guest_fsfreeze_thaw(&err);
521 if (ret < 0 || err) {
522 slog("failed to clean up frozen filesystems");
523 }
524 }
525}
Michael Rothe72c3f22012-03-25 13:59:41 -0500526#endif /* CONFIG_FSFREEZE */
Michael Rothe3d4d252011-07-19 15:41:55 -0500527
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300528#define LINUX_SYS_STATE_FILE "/sys/power/state"
529#define SUSPEND_SUPPORTED 0
530#define SUSPEND_NOT_SUPPORTED 1
531
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300532static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
533 const char *sysfile_str, Error **err)
534{
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300535 char *pmutils_path;
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300536 pid_t pid, rpid;
537 int status;
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300538
539 pmutils_path = g_find_program_in_path(pmutils_bin);
540
541 pid = fork();
542 if (!pid) {
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300543 char buf[32]; /* hopefully big enough */
544 ssize_t ret;
545 int fd;
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300546
547 setsid();
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300548 reopen_fd_to_null(0);
549 reopen_fd_to_null(1);
550 reopen_fd_to_null(2);
551
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300552 if (pmutils_path) {
553 execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
554 }
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300555
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300556 /*
557 * If we get here either pm-utils is not installed or execle() has
558 * failed. Let's try the manual method if the caller wants it.
559 */
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300560
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300561 if (!sysfile_str) {
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300562 _exit(SUSPEND_NOT_SUPPORTED);
563 }
564
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300565 fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
566 if (fd < 0) {
567 _exit(SUSPEND_NOT_SUPPORTED);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300568 }
569
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300570 ret = read(fd, buf, sizeof(buf)-1);
571 if (ret <= 0) {
572 _exit(SUSPEND_NOT_SUPPORTED);
573 }
574 buf[ret] = '\0';
575
576 if (strstr(buf, sysfile_str)) {
577 _exit(SUSPEND_SUPPORTED);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300578 }
579
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300580 _exit(SUSPEND_NOT_SUPPORTED);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300581 }
582
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300583 g_free(pmutils_path);
584
585 if (pid < 0) {
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300586 goto undef_err;
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300587 }
588
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300589 do {
590 rpid = waitpid(pid, &status, 0);
591 } while (rpid == -1 && errno == EINTR);
592 if (rpid == pid && WIFEXITED(status)) {
593 switch (WEXITSTATUS(status)) {
594 case SUSPEND_SUPPORTED:
595 return;
596 case SUSPEND_NOT_SUPPORTED:
597 error_set(err, QERR_UNSUPPORTED);
598 return;
599 default:
600 goto undef_err;
601 }
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300602 }
603
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300604undef_err:
605 error_set(err, QERR_UNDEFINED_ERROR);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300606}
607
608static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
609 Error **err)
610{
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300611 char *pmutils_path;
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300612 pid_t rpid, pid;
613 int status;
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300614
615 pmutils_path = g_find_program_in_path(pmutils_bin);
616
617 pid = fork();
618 if (pid == 0) {
619 /* child */
620 int fd;
621
622 setsid();
623 reopen_fd_to_null(0);
624 reopen_fd_to_null(1);
625 reopen_fd_to_null(2);
626
627 if (pmutils_path) {
628 execle(pmutils_path, pmutils_bin, NULL, environ);
629 }
630
631 /*
632 * If we get here either pm-utils is not installed or execle() has
633 * failed. Let's try the manual method if the caller wants it.
634 */
635
636 if (!sysfile_str) {
637 _exit(EXIT_FAILURE);
638 }
639
640 fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
641 if (fd < 0) {
642 _exit(EXIT_FAILURE);
643 }
644
645 if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
646 _exit(EXIT_FAILURE);
647 }
648
649 _exit(EXIT_SUCCESS);
650 }
651
652 g_free(pmutils_path);
653
654 if (pid < 0) {
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300655 goto exit_err;
656 }
657
658 do {
659 rpid = waitpid(pid, &status, 0);
660 } while (rpid == -1 && errno == EINTR);
661 if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300662 return;
663 }
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300664
665exit_err:
666 error_set(err, QERR_UNDEFINED_ERROR);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300667}
668
669void qmp_guest_suspend_disk(Error **err)
670{
671 bios_supports_mode("pm-is-supported", "--hibernate", "disk", err);
672 if (error_is_set(err)) {
673 return;
674 }
675
676 guest_suspend("pm-hibernate", "disk", err);
677}
678
Luiz Capitulinofbf42212012-02-28 11:03:04 -0300679void qmp_guest_suspend_ram(Error **err)
680{
681 bios_supports_mode("pm-is-supported", "--suspend", "mem", err);
682 if (error_is_set(err)) {
683 return;
684 }
685
686 guest_suspend("pm-suspend", "mem", err);
687}
688
Luiz Capitulino95f4f402012-02-28 11:03:05 -0300689void qmp_guest_suspend_hybrid(Error **err)
690{
691 bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err);
692 if (error_is_set(err)) {
693 return;
694 }
695
696 guest_suspend("pm-suspend-hybrid", NULL, err);
697}
698
Michal Privoznik3424fc92012-02-29 17:02:23 +0100699static GuestNetworkInterfaceList *
700guest_find_interface(GuestNetworkInterfaceList *head,
701 const char *name)
702{
703 for (; head; head = head->next) {
704 if (strcmp(head->value->name, name) == 0) {
705 break;
706 }
707 }
708
709 return head;
710}
711
712/*
713 * Build information about guest interfaces
714 */
715GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
716{
717 GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
718 struct ifaddrs *ifap, *ifa;
719 char err_msg[512];
720
721 if (getifaddrs(&ifap) < 0) {
722 snprintf(err_msg, sizeof(err_msg),
723 "getifaddrs failed: %s", strerror(errno));
724 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
725 goto error;
726 }
727
728 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
729 GuestNetworkInterfaceList *info;
730 GuestIpAddressList **address_list = NULL, *address_item = NULL;
731 char addr4[INET_ADDRSTRLEN];
732 char addr6[INET6_ADDRSTRLEN];
733 int sock;
734 struct ifreq ifr;
735 unsigned char *mac_addr;
736 void *p;
737
738 g_debug("Processing %s interface", ifa->ifa_name);
739
740 info = guest_find_interface(head, ifa->ifa_name);
741
742 if (!info) {
743 info = g_malloc0(sizeof(*info));
744 info->value = g_malloc0(sizeof(*info->value));
745 info->value->name = g_strdup(ifa->ifa_name);
746
747 if (!cur_item) {
748 head = cur_item = info;
749 } else {
750 cur_item->next = info;
751 cur_item = info;
752 }
753 }
754
755 if (!info->value->has_hardware_address &&
756 ifa->ifa_flags & SIOCGIFHWADDR) {
757 /* we haven't obtained HW address yet */
758 sock = socket(PF_INET, SOCK_STREAM, 0);
759 if (sock == -1) {
760 snprintf(err_msg, sizeof(err_msg),
761 "failed to create socket: %s", strerror(errno));
762 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
763 goto error;
764 }
765
766 memset(&ifr, 0, sizeof(ifr));
767 strncpy(ifr.ifr_name, info->value->name, IF_NAMESIZE);
768 if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
769 snprintf(err_msg, sizeof(err_msg),
Jim Meyeringa31f0532012-05-09 05:12:04 +0000770 "failed to get MAC address of %s: %s",
Michal Privoznik3424fc92012-02-29 17:02:23 +0100771 ifa->ifa_name,
772 strerror(errno));
773 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
774 goto error;
775 }
776
777 mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
778
779 if (asprintf(&info->value->hardware_address,
780 "%02x:%02x:%02x:%02x:%02x:%02x",
781 (int) mac_addr[0], (int) mac_addr[1],
782 (int) mac_addr[2], (int) mac_addr[3],
783 (int) mac_addr[4], (int) mac_addr[5]) == -1) {
784 snprintf(err_msg, sizeof(err_msg),
785 "failed to format MAC: %s", strerror(errno));
786 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
787 goto error;
788 }
789
790 info->value->has_hardware_address = true;
791 close(sock);
792 }
793
794 if (ifa->ifa_addr &&
795 ifa->ifa_addr->sa_family == AF_INET) {
796 /* interface with IPv4 address */
797 address_item = g_malloc0(sizeof(*address_item));
798 address_item->value = g_malloc0(sizeof(*address_item->value));
799 p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
800 if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
801 snprintf(err_msg, sizeof(err_msg),
802 "inet_ntop failed : %s", strerror(errno));
803 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
804 goto error;
805 }
806
807 address_item->value->ip_address = g_strdup(addr4);
808 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
809
810 if (ifa->ifa_netmask) {
811 /* Count the number of set bits in netmask.
812 * This is safe as '1' and '0' cannot be shuffled in netmask. */
813 p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
814 address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
815 }
816 } else if (ifa->ifa_addr &&
817 ifa->ifa_addr->sa_family == AF_INET6) {
818 /* interface with IPv6 address */
819 address_item = g_malloc0(sizeof(*address_item));
820 address_item->value = g_malloc0(sizeof(*address_item->value));
821 p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
822 if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
823 snprintf(err_msg, sizeof(err_msg),
824 "inet_ntop failed : %s", strerror(errno));
825 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
826 goto error;
827 }
828
829 address_item->value->ip_address = g_strdup(addr6);
830 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
831
832 if (ifa->ifa_netmask) {
833 /* Count the number of set bits in netmask.
834 * This is safe as '1' and '0' cannot be shuffled in netmask. */
835 p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
836 address_item->value->prefix =
837 ctpop32(((uint32_t *) p)[0]) +
838 ctpop32(((uint32_t *) p)[1]) +
839 ctpop32(((uint32_t *) p)[2]) +
840 ctpop32(((uint32_t *) p)[3]);
841 }
842 }
843
844 if (!address_item) {
845 continue;
846 }
847
848 address_list = &info->value->ip_addresses;
849
850 while (*address_list && (*address_list)->next) {
851 address_list = &(*address_list)->next;
852 }
853
854 if (!*address_list) {
855 *address_list = address_item;
856 } else {
857 (*address_list)->next = address_item;
858 }
859
860 info->value->has_ip_addresses = true;
861
862
863 }
864
865 freeifaddrs(ifap);
866 return head;
867
868error:
869 freeifaddrs(ifap);
870 qapi_free_GuestNetworkInterfaceList(head);
871 return NULL;
872}
873
Michael Rothe72c3f22012-03-25 13:59:41 -0500874#else /* defined(__linux__) */
875
Michael Rothe72c3f22012-03-25 13:59:41 -0500876void qmp_guest_suspend_disk(Error **err)
877{
878 error_set(err, QERR_UNSUPPORTED);
879}
880
881void qmp_guest_suspend_ram(Error **err)
882{
883 error_set(err, QERR_UNSUPPORTED);
884}
885
886void qmp_guest_suspend_hybrid(Error **err)
887{
888 error_set(err, QERR_UNSUPPORTED);
889}
890
891GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
892{
893 error_set(errp, QERR_UNSUPPORTED);
894 return NULL;
895}
896
897#endif
898
Michael Rothd35d4cb2012-04-13 21:07:36 -0500899#if !defined(CONFIG_FSFREEZE)
900
901GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
902{
903 error_set(err, QERR_UNSUPPORTED);
904
905 return 0;
906}
907
908int64_t qmp_guest_fsfreeze_freeze(Error **err)
909{
910 error_set(err, QERR_UNSUPPORTED);
911
912 return 0;
913}
914
915int64_t qmp_guest_fsfreeze_thaw(Error **err)
916{
917 error_set(err, QERR_UNSUPPORTED);
918
919 return 0;
920}
921
922#endif
923
Michael Rothe3d4d252011-07-19 15:41:55 -0500924/* register init/cleanup routines for stateful command groups */
925void ga_command_state_init(GAState *s, GACommandState *cs)
926{
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500927#if defined(CONFIG_FSFREEZE)
Michael Rothf22d85e2012-04-17 19:01:45 -0500928 ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500929#endif
Michael Rothe3d4d252011-07-19 15:41:55 -0500930 ga_command_state_add(cs, guest_file_init, NULL);
931}