blob: 7664be10a0c96ec7037ac9ad422a3a1261948ad9 [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>
Michael Rothe3d4d252011-07-19 15:41:55 -050017#include "qga/guest-agent-core.h"
18#include "qga-qmp-commands.h"
19#include "qerror.h"
20#include "qemu-queue.h"
Michal Privoznik3424fc92012-02-29 17:02:23 +010021#include "host-utils.h"
Michael Rothe3d4d252011-07-19 15:41:55 -050022
Michael Rothe72c3f22012-03-25 13:59:41 -050023#if defined(__linux__)
24#include <mntent.h>
25#include <linux/fs.h>
26#include <ifaddrs.h>
27#include <arpa/inet.h>
28#include <sys/socket.h>
29#include <net/if.h>
30#include <sys/wait.h>
31
32#if defined(__linux__) && defined(FIFREEZE)
33#define CONFIG_FSFREEZE
34#endif
35#endif
36
Michael Rothe3d4d252011-07-19 15:41:55 -050037void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
38{
Michael Rothe3d4d252011-07-19 15:41:55 -050039 const char *shutdown_flag;
Luiz Capitulinod5dd3492012-05-11 16:19:47 -030040 pid_t rpid, pid;
Luiz Capitulino36748382012-05-14 15:25:20 -030041 int status;
Michael Rothe3d4d252011-07-19 15:41:55 -050042
43 slog("guest-shutdown called, mode: %s", mode);
44 if (!has_mode || strcmp(mode, "powerdown") == 0) {
45 shutdown_flag = "-P";
46 } else if (strcmp(mode, "halt") == 0) {
47 shutdown_flag = "-H";
48 } else if (strcmp(mode, "reboot") == 0) {
49 shutdown_flag = "-r";
50 } else {
51 error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode",
52 "halt|powerdown|reboot");
53 return;
54 }
55
Luiz Capitulinod5dd3492012-05-11 16:19:47 -030056 pid = fork();
57 if (pid == 0) {
Michael Rothe3d4d252011-07-19 15:41:55 -050058 /* child, start the shutdown */
59 setsid();
Luiz Capitulino36748382012-05-14 15:25:20 -030060 reopen_fd_to_null(0);
61 reopen_fd_to_null(1);
62 reopen_fd_to_null(2);
Michael Rothe3d4d252011-07-19 15:41:55 -050063
Luiz Capitulino36748382012-05-14 15:25:20 -030064 execle("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
65 "hypervisor initiated shutdown", (char*)NULL, environ);
66 _exit(EXIT_FAILURE);
Luiz Capitulinod5dd3492012-05-11 16:19:47 -030067 } else if (pid < 0) {
68 goto exit_err;
Michael Rothe3d4d252011-07-19 15:41:55 -050069 }
Luiz Capitulinod5dd3492012-05-11 16:19:47 -030070
71 do {
72 rpid = waitpid(pid, &status, 0);
73 } while (rpid == -1 && errno == EINTR);
74 if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
75 return;
76 }
77
78exit_err:
79 error_set(err, QERR_UNDEFINED_ERROR);
Michael Rothe3d4d252011-07-19 15:41:55 -050080}
81
82typedef struct GuestFileHandle {
83 uint64_t id;
84 FILE *fh;
85 QTAILQ_ENTRY(GuestFileHandle) next;
86} GuestFileHandle;
87
88static struct {
89 QTAILQ_HEAD(, GuestFileHandle) filehandles;
90} guest_file_state;
91
92static void guest_file_handle_add(FILE *fh)
93{
94 GuestFileHandle *gfh;
95
Anthony Liguori7267c092011-08-20 22:09:37 -050096 gfh = g_malloc0(sizeof(GuestFileHandle));
Michael Rothe3d4d252011-07-19 15:41:55 -050097 gfh->id = fileno(fh);
98 gfh->fh = fh;
99 QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
100}
101
102static GuestFileHandle *guest_file_handle_find(int64_t id)
103{
104 GuestFileHandle *gfh;
105
106 QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next)
107 {
108 if (gfh->id == id) {
109 return gfh;
110 }
111 }
112
113 return NULL;
114}
115
116int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, Error **err)
117{
118 FILE *fh;
119 int fd;
120 int64_t ret = -1;
121
122 if (!has_mode) {
123 mode = "r";
124 }
125 slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
126 fh = fopen(path, mode);
127 if (!fh) {
128 error_set(err, QERR_OPEN_FILE_FAILED, path);
129 return -1;
130 }
131
132 /* set fd non-blocking to avoid common use cases (like reading from a
133 * named pipe) from hanging the agent
134 */
135 fd = fileno(fh);
136 ret = fcntl(fd, F_GETFL);
137 ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
138 if (ret == -1) {
139 error_set(err, QERR_QGA_COMMAND_FAILED, "fcntl() failed");
140 fclose(fh);
141 return -1;
142 }
143
144 guest_file_handle_add(fh);
145 slog("guest-file-open, handle: %d", fd);
146 return fd;
147}
148
149void qmp_guest_file_close(int64_t handle, Error **err)
150{
151 GuestFileHandle *gfh = guest_file_handle_find(handle);
152 int ret;
153
154 slog("guest-file-close called, handle: %ld", handle);
155 if (!gfh) {
156 error_set(err, QERR_FD_NOT_FOUND, "handle");
157 return;
158 }
159
160 ret = fclose(gfh->fh);
161 if (ret == -1) {
162 error_set(err, QERR_QGA_COMMAND_FAILED, "fclose() failed");
163 return;
164 }
165
166 QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
Anthony Liguori7267c092011-08-20 22:09:37 -0500167 g_free(gfh);
Michael Rothe3d4d252011-07-19 15:41:55 -0500168}
169
170struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
171 int64_t count, Error **err)
172{
173 GuestFileHandle *gfh = guest_file_handle_find(handle);
174 GuestFileRead *read_data = NULL;
175 guchar *buf;
176 FILE *fh;
177 size_t read_count;
178
179 if (!gfh) {
180 error_set(err, QERR_FD_NOT_FOUND, "handle");
181 return NULL;
182 }
183
184 if (!has_count) {
185 count = QGA_READ_COUNT_DEFAULT;
186 } else if (count < 0) {
187 error_set(err, QERR_INVALID_PARAMETER, "count");
188 return NULL;
189 }
190
191 fh = gfh->fh;
Anthony Liguori7267c092011-08-20 22:09:37 -0500192 buf = g_malloc0(count+1);
Michael Rothe3d4d252011-07-19 15:41:55 -0500193 read_count = fread(buf, 1, count, fh);
194 if (ferror(fh)) {
195 slog("guest-file-read failed, handle: %ld", handle);
196 error_set(err, QERR_QGA_COMMAND_FAILED, "fread() failed");
197 } else {
198 buf[read_count] = 0;
Anthony Liguori7267c092011-08-20 22:09:37 -0500199 read_data = g_malloc0(sizeof(GuestFileRead));
Michael Rothe3d4d252011-07-19 15:41:55 -0500200 read_data->count = read_count;
201 read_data->eof = feof(fh);
202 if (read_count) {
203 read_data->buf_b64 = g_base64_encode(buf, read_count);
204 }
205 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500206 g_free(buf);
Michael Rothe3d4d252011-07-19 15:41:55 -0500207 clearerr(fh);
208
209 return read_data;
210}
211
212GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
213 bool has_count, int64_t count, Error **err)
214{
215 GuestFileWrite *write_data = NULL;
216 guchar *buf;
217 gsize buf_len;
218 int write_count;
219 GuestFileHandle *gfh = guest_file_handle_find(handle);
220 FILE *fh;
221
222 if (!gfh) {
223 error_set(err, QERR_FD_NOT_FOUND, "handle");
224 return NULL;
225 }
226
227 fh = gfh->fh;
228 buf = g_base64_decode(buf_b64, &buf_len);
229
230 if (!has_count) {
231 count = buf_len;
232 } else if (count < 0 || count > buf_len) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500233 g_free(buf);
Michael Rothe3d4d252011-07-19 15:41:55 -0500234 error_set(err, QERR_INVALID_PARAMETER, "count");
235 return NULL;
236 }
237
238 write_count = fwrite(buf, 1, count, fh);
239 if (ferror(fh)) {
240 slog("guest-file-write failed, handle: %ld", handle);
241 error_set(err, QERR_QGA_COMMAND_FAILED, "fwrite() error");
242 } else {
Anthony Liguori7267c092011-08-20 22:09:37 -0500243 write_data = g_malloc0(sizeof(GuestFileWrite));
Michael Rothe3d4d252011-07-19 15:41:55 -0500244 write_data->count = write_count;
245 write_data->eof = feof(fh);
246 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500247 g_free(buf);
Michael Rothe3d4d252011-07-19 15:41:55 -0500248 clearerr(fh);
249
250 return write_data;
251}
252
253struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
254 int64_t whence, Error **err)
255{
256 GuestFileHandle *gfh = guest_file_handle_find(handle);
257 GuestFileSeek *seek_data = NULL;
258 FILE *fh;
259 int ret;
260
261 if (!gfh) {
262 error_set(err, QERR_FD_NOT_FOUND, "handle");
263 return NULL;
264 }
265
266 fh = gfh->fh;
267 ret = fseek(fh, offset, whence);
268 if (ret == -1) {
269 error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
270 } else {
Anthony Liguori7267c092011-08-20 22:09:37 -0500271 seek_data = g_malloc0(sizeof(GuestFileRead));
Michael Rothe3d4d252011-07-19 15:41:55 -0500272 seek_data->position = ftell(fh);
273 seek_data->eof = feof(fh);
274 }
275 clearerr(fh);
276
277 return seek_data;
278}
279
280void qmp_guest_file_flush(int64_t handle, Error **err)
281{
282 GuestFileHandle *gfh = guest_file_handle_find(handle);
283 FILE *fh;
284 int ret;
285
286 if (!gfh) {
287 error_set(err, QERR_FD_NOT_FOUND, "handle");
288 return;
289 }
290
291 fh = gfh->fh;
292 ret = fflush(fh);
293 if (ret == EOF) {
294 error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
295 }
296}
297
298static void guest_file_init(void)
299{
300 QTAILQ_INIT(&guest_file_state.filehandles);
301}
302
Michael Rothe72c3f22012-03-25 13:59:41 -0500303/* linux-specific implementations. avoid this if at all possible. */
304#if defined(__linux__)
305
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500306#if defined(CONFIG_FSFREEZE)
Michael Rothe72c3f22012-03-25 13:59:41 -0500307
Michael Rothe3d4d252011-07-19 15:41:55 -0500308typedef struct GuestFsfreezeMount {
309 char *dirname;
310 char *devtype;
311 QTAILQ_ENTRY(GuestFsfreezeMount) next;
312} GuestFsfreezeMount;
313
Michael Roth9e8aded432012-04-16 19:52:17 -0500314typedef QTAILQ_HEAD(, GuestFsfreezeMount) GuestFsfreezeMountList;
315
Michael Roth9e8aded432012-04-16 19:52:17 -0500316static void guest_fsfreeze_free_mount_list(GuestFsfreezeMountList *mounts)
317{
318 GuestFsfreezeMount *mount, *temp;
319
320 if (!mounts) {
321 return;
322 }
323
324 QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) {
325 QTAILQ_REMOVE(mounts, mount, next);
326 g_free(mount->dirname);
327 g_free(mount->devtype);
328 g_free(mount);
329 }
330}
331
Michael Rothe3d4d252011-07-19 15:41:55 -0500332/*
333 * Walk the mount table and build a list of local file systems
334 */
Michael Roth9e8aded432012-04-16 19:52:17 -0500335static int guest_fsfreeze_build_mount_list(GuestFsfreezeMountList *mounts)
Michael Rothe3d4d252011-07-19 15:41:55 -0500336{
337 struct mntent *ment;
Michael Roth9e8aded432012-04-16 19:52:17 -0500338 GuestFsfreezeMount *mount;
Michael Rothe3d4d252011-07-19 15:41:55 -0500339 char const *mtab = MOUNTED;
340 FILE *fp;
341
Michael Rothe3d4d252011-07-19 15:41:55 -0500342 fp = setmntent(mtab, "r");
343 if (!fp) {
344 g_warning("fsfreeze: unable to read mtab");
345 return -1;
346 }
347
348 while ((ment = getmntent(fp))) {
349 /*
350 * An entry which device name doesn't start with a '/' is
351 * either a dummy file system or a network file system.
352 * Add special handling for smbfs and cifs as is done by
353 * coreutils as well.
354 */
355 if ((ment->mnt_fsname[0] != '/') ||
356 (strcmp(ment->mnt_type, "smbfs") == 0) ||
357 (strcmp(ment->mnt_type, "cifs") == 0)) {
358 continue;
359 }
360
Anthony Liguori7267c092011-08-20 22:09:37 -0500361 mount = g_malloc0(sizeof(GuestFsfreezeMount));
362 mount->dirname = g_strdup(ment->mnt_dir);
363 mount->devtype = g_strdup(ment->mnt_type);
Michael Rothe3d4d252011-07-19 15:41:55 -0500364
Michael Roth9e8aded432012-04-16 19:52:17 -0500365 QTAILQ_INSERT_TAIL(mounts, mount, next);
Michael Rothe3d4d252011-07-19 15:41:55 -0500366 }
367
368 endmntent(fp);
369
370 return 0;
371}
372
373/*
374 * Return status of freeze/thaw
375 */
376GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
377{
Michael Rothf22d85e2012-04-17 19:01:45 -0500378 if (ga_is_frozen(ga_state)) {
379 return GUEST_FSFREEZE_STATUS_FROZEN;
380 }
381
382 return GUEST_FSFREEZE_STATUS_THAWED;
Michael Rothe3d4d252011-07-19 15:41:55 -0500383}
384
385/*
386 * Walk list of mounted file systems in the guest, and freeze the ones which
387 * are real local file systems.
388 */
389int64_t qmp_guest_fsfreeze_freeze(Error **err)
390{
391 int ret = 0, i = 0;
Michael Roth9e8aded432012-04-16 19:52:17 -0500392 GuestFsfreezeMountList mounts;
393 struct GuestFsfreezeMount *mount;
Michael Rothe3d4d252011-07-19 15:41:55 -0500394 int fd;
395 char err_msg[512];
396
397 slog("guest-fsfreeze called");
398
Michael Roth9e8aded432012-04-16 19:52:17 -0500399 QTAILQ_INIT(&mounts);
400 ret = guest_fsfreeze_build_mount_list(&mounts);
Michael Rothe3d4d252011-07-19 15:41:55 -0500401 if (ret < 0) {
402 return ret;
403 }
404
405 /* cannot risk guest agent blocking itself on a write in this state */
Michael Rothf22d85e2012-04-17 19:01:45 -0500406 ga_set_frozen(ga_state);
Michael Rothe3d4d252011-07-19 15:41:55 -0500407
Michael Roth9e8aded432012-04-16 19:52:17 -0500408 QTAILQ_FOREACH(mount, &mounts, next) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500409 fd = qemu_open(mount->dirname, O_RDONLY);
410 if (fd == -1) {
Michael Roth9e8aded432012-04-16 19:52:17 -0500411 sprintf(err_msg, "failed to open %s, %s", mount->dirname,
412 strerror(errno));
Michael Rothe3d4d252011-07-19 15:41:55 -0500413 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
414 goto error;
415 }
416
417 /* we try to cull filesytems we know won't work in advance, but other
418 * filesytems may not implement fsfreeze for less obvious reasons.
Michael Roth9e8aded432012-04-16 19:52:17 -0500419 * these will report EOPNOTSUPP. we simply ignore these when tallying
420 * the number of frozen filesystems.
421 *
422 * any other error means a failure to freeze a filesystem we
423 * expect to be freezable, so return an error in those cases
424 * and return system to thawed state.
Michael Rothe3d4d252011-07-19 15:41:55 -0500425 */
426 ret = ioctl(fd, FIFREEZE);
Michael Roth9e8aded432012-04-16 19:52:17 -0500427 if (ret == -1) {
428 if (errno != EOPNOTSUPP) {
429 sprintf(err_msg, "failed to freeze %s, %s",
430 mount->dirname, strerror(errno));
431 error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
432 close(fd);
433 goto error;
434 }
435 } else {
436 i++;
Michael Rothe3d4d252011-07-19 15:41:55 -0500437 }
438 close(fd);
Michael Rothe3d4d252011-07-19 15:41:55 -0500439 }
440
Michael Roth9e8aded432012-04-16 19:52:17 -0500441 guest_fsfreeze_free_mount_list(&mounts);
Michael Rothe3d4d252011-07-19 15:41:55 -0500442 return i;
443
444error:
Michael Roth9e8aded432012-04-16 19:52:17 -0500445 guest_fsfreeze_free_mount_list(&mounts);
446 qmp_guest_fsfreeze_thaw(NULL);
Michael Rothe3d4d252011-07-19 15:41:55 -0500447 return 0;
448}
449
450/*
451 * Walk list of frozen file systems in the guest, and thaw them.
452 */
453int64_t qmp_guest_fsfreeze_thaw(Error **err)
454{
455 int ret;
Michael Roth9e8aded432012-04-16 19:52:17 -0500456 GuestFsfreezeMountList mounts;
457 GuestFsfreezeMount *mount;
458 int fd, i = 0, logged;
Michael Rothe3d4d252011-07-19 15:41:55 -0500459
Michael Roth9e8aded432012-04-16 19:52:17 -0500460 QTAILQ_INIT(&mounts);
461 ret = guest_fsfreeze_build_mount_list(&mounts);
462 if (ret) {
463 error_set(err, QERR_QGA_COMMAND_FAILED,
464 "failed to enumerate filesystems");
465 return 0;
466 }
467
468 QTAILQ_FOREACH(mount, &mounts, next) {
469 logged = false;
Michael Rothe3d4d252011-07-19 15:41:55 -0500470 fd = qemu_open(mount->dirname, O_RDONLY);
471 if (fd == -1) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500472 continue;
473 }
Michael Roth9e8aded432012-04-16 19:52:17 -0500474 /* we have no way of knowing whether a filesystem was actually unfrozen
475 * as a result of a successful call to FITHAW, only that if an error
476 * was returned the filesystem was *not* unfrozen by that particular
477 * call.
478 *
Jim Meyeringa31f0532012-05-09 05:12:04 +0000479 * since multiple preceding FIFREEZEs require multiple calls to FITHAW
Michael Roth9e8aded432012-04-16 19:52:17 -0500480 * to unfreeze, continuing issuing FITHAW until an error is returned,
481 * in which case either the filesystem is in an unfreezable state, or,
482 * more likely, it was thawed previously (and remains so afterward).
483 *
484 * also, since the most recent successful call is the one that did
485 * the actual unfreeze, we can use this to provide an accurate count
486 * of the number of filesystems unfrozen by guest-fsfreeze-thaw, which
487 * may * be useful for determining whether a filesystem was unfrozen
488 * during the freeze/thaw phase by a process other than qemu-ga.
489 */
490 do {
491 ret = ioctl(fd, FITHAW);
492 if (ret == 0 && !logged) {
493 i++;
494 logged = true;
495 }
496 } while (ret == 0);
Michael Rothe3d4d252011-07-19 15:41:55 -0500497 close(fd);
Michael Rothe3d4d252011-07-19 15:41:55 -0500498 }
499
Michael Rothf22d85e2012-04-17 19:01:45 -0500500 ga_unset_frozen(ga_state);
Michael Roth9e8aded432012-04-16 19:52:17 -0500501 guest_fsfreeze_free_mount_list(&mounts);
Michael Rothe3d4d252011-07-19 15:41:55 -0500502 return i;
503}
504
Michael Rothe3d4d252011-07-19 15:41:55 -0500505static void guest_fsfreeze_cleanup(void)
506{
507 int64_t ret;
508 Error *err = NULL;
509
Michael Rothf22d85e2012-04-17 19:01:45 -0500510 if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
Michael Rothe3d4d252011-07-19 15:41:55 -0500511 ret = qmp_guest_fsfreeze_thaw(&err);
512 if (ret < 0 || err) {
513 slog("failed to clean up frozen filesystems");
514 }
515 }
516}
Michael Rothe72c3f22012-03-25 13:59:41 -0500517#endif /* CONFIG_FSFREEZE */
Michael Rothe3d4d252011-07-19 15:41:55 -0500518
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300519#define LINUX_SYS_STATE_FILE "/sys/power/state"
520#define SUSPEND_SUPPORTED 0
521#define SUSPEND_NOT_SUPPORTED 1
522
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300523static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
524 const char *sysfile_str, Error **err)
525{
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300526 char *pmutils_path;
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300527 pid_t pid, rpid;
528 int status;
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300529
530 pmutils_path = g_find_program_in_path(pmutils_bin);
531
532 pid = fork();
533 if (!pid) {
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300534 char buf[32]; /* hopefully big enough */
535 ssize_t ret;
536 int fd;
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300537
538 setsid();
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300539 reopen_fd_to_null(0);
540 reopen_fd_to_null(1);
541 reopen_fd_to_null(2);
542
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300543 if (pmutils_path) {
544 execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
545 }
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300546
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300547 /*
548 * If we get here either pm-utils is not installed or execle() has
549 * failed. Let's try the manual method if the caller wants it.
550 */
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300551
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300552 if (!sysfile_str) {
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300553 _exit(SUSPEND_NOT_SUPPORTED);
554 }
555
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300556 fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
557 if (fd < 0) {
558 _exit(SUSPEND_NOT_SUPPORTED);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300559 }
560
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300561 ret = read(fd, buf, sizeof(buf)-1);
562 if (ret <= 0) {
563 _exit(SUSPEND_NOT_SUPPORTED);
564 }
565 buf[ret] = '\0';
566
567 if (strstr(buf, sysfile_str)) {
568 _exit(SUSPEND_SUPPORTED);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300569 }
570
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300571 _exit(SUSPEND_NOT_SUPPORTED);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300572 }
573
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300574 g_free(pmutils_path);
575
576 if (pid < 0) {
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300577 goto undef_err;
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300578 }
579
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300580 do {
581 rpid = waitpid(pid, &status, 0);
582 } while (rpid == -1 && errno == EINTR);
583 if (rpid == pid && WIFEXITED(status)) {
584 switch (WEXITSTATUS(status)) {
585 case SUSPEND_SUPPORTED:
586 return;
587 case SUSPEND_NOT_SUPPORTED:
588 error_set(err, QERR_UNSUPPORTED);
589 return;
590 default:
591 goto undef_err;
592 }
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300593 }
594
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300595undef_err:
596 error_set(err, QERR_UNDEFINED_ERROR);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300597}
598
599static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
600 Error **err)
601{
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300602 char *pmutils_path;
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300603 pid_t rpid, pid;
604 int status;
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300605
606 pmutils_path = g_find_program_in_path(pmutils_bin);
607
608 pid = fork();
609 if (pid == 0) {
610 /* child */
611 int fd;
612
613 setsid();
614 reopen_fd_to_null(0);
615 reopen_fd_to_null(1);
616 reopen_fd_to_null(2);
617
618 if (pmutils_path) {
619 execle(pmutils_path, pmutils_bin, NULL, environ);
620 }
621
622 /*
623 * If we get here either pm-utils is not installed or execle() has
624 * failed. Let's try the manual method if the caller wants it.
625 */
626
627 if (!sysfile_str) {
628 _exit(EXIT_FAILURE);
629 }
630
631 fd = open(LINUX_SYS_STATE_FILE, O_WRONLY);
632 if (fd < 0) {
633 _exit(EXIT_FAILURE);
634 }
635
636 if (write(fd, sysfile_str, strlen(sysfile_str)) < 0) {
637 _exit(EXIT_FAILURE);
638 }
639
640 _exit(EXIT_SUCCESS);
641 }
642
643 g_free(pmutils_path);
644
645 if (pid < 0) {
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300646 goto exit_err;
647 }
648
649 do {
650 rpid = waitpid(pid, &status, 0);
651 } while (rpid == -1 && errno == EINTR);
652 if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300653 return;
654 }
Luiz Capitulinodc8764f02012-05-11 16:19:46 -0300655
656exit_err:
657 error_set(err, QERR_UNDEFINED_ERROR);
Luiz Capitulino11d0f122012-02-28 11:03:03 -0300658}
659
660void qmp_guest_suspend_disk(Error **err)
661{
662 bios_supports_mode("pm-is-supported", "--hibernate", "disk", err);
663 if (error_is_set(err)) {
664 return;
665 }
666
667 guest_suspend("pm-hibernate", "disk", err);
668}
669
Luiz Capitulinofbf42212012-02-28 11:03:04 -0300670void qmp_guest_suspend_ram(Error **err)
671{
672 bios_supports_mode("pm-is-supported", "--suspend", "mem", err);
673 if (error_is_set(err)) {
674 return;
675 }
676
677 guest_suspend("pm-suspend", "mem", err);
678}
679
Luiz Capitulino95f4f402012-02-28 11:03:05 -0300680void qmp_guest_suspend_hybrid(Error **err)
681{
682 bios_supports_mode("pm-is-supported", "--suspend-hybrid", NULL, err);
683 if (error_is_set(err)) {
684 return;
685 }
686
687 guest_suspend("pm-suspend-hybrid", NULL, err);
688}
689
Michal Privoznik3424fc92012-02-29 17:02:23 +0100690static GuestNetworkInterfaceList *
691guest_find_interface(GuestNetworkInterfaceList *head,
692 const char *name)
693{
694 for (; head; head = head->next) {
695 if (strcmp(head->value->name, name) == 0) {
696 break;
697 }
698 }
699
700 return head;
701}
702
703/*
704 * Build information about guest interfaces
705 */
706GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
707{
708 GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
709 struct ifaddrs *ifap, *ifa;
710 char err_msg[512];
711
712 if (getifaddrs(&ifap) < 0) {
713 snprintf(err_msg, sizeof(err_msg),
714 "getifaddrs failed: %s", strerror(errno));
715 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
716 goto error;
717 }
718
719 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
720 GuestNetworkInterfaceList *info;
721 GuestIpAddressList **address_list = NULL, *address_item = NULL;
722 char addr4[INET_ADDRSTRLEN];
723 char addr6[INET6_ADDRSTRLEN];
724 int sock;
725 struct ifreq ifr;
726 unsigned char *mac_addr;
727 void *p;
728
729 g_debug("Processing %s interface", ifa->ifa_name);
730
731 info = guest_find_interface(head, ifa->ifa_name);
732
733 if (!info) {
734 info = g_malloc0(sizeof(*info));
735 info->value = g_malloc0(sizeof(*info->value));
736 info->value->name = g_strdup(ifa->ifa_name);
737
738 if (!cur_item) {
739 head = cur_item = info;
740 } else {
741 cur_item->next = info;
742 cur_item = info;
743 }
744 }
745
746 if (!info->value->has_hardware_address &&
747 ifa->ifa_flags & SIOCGIFHWADDR) {
748 /* we haven't obtained HW address yet */
749 sock = socket(PF_INET, SOCK_STREAM, 0);
750 if (sock == -1) {
751 snprintf(err_msg, sizeof(err_msg),
752 "failed to create socket: %s", strerror(errno));
753 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
754 goto error;
755 }
756
757 memset(&ifr, 0, sizeof(ifr));
758 strncpy(ifr.ifr_name, info->value->name, IF_NAMESIZE);
759 if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
760 snprintf(err_msg, sizeof(err_msg),
Jim Meyeringa31f0532012-05-09 05:12:04 +0000761 "failed to get MAC address of %s: %s",
Michal Privoznik3424fc92012-02-29 17:02:23 +0100762 ifa->ifa_name,
763 strerror(errno));
764 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
765 goto error;
766 }
767
768 mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
769
770 if (asprintf(&info->value->hardware_address,
771 "%02x:%02x:%02x:%02x:%02x:%02x",
772 (int) mac_addr[0], (int) mac_addr[1],
773 (int) mac_addr[2], (int) mac_addr[3],
774 (int) mac_addr[4], (int) mac_addr[5]) == -1) {
775 snprintf(err_msg, sizeof(err_msg),
776 "failed to format MAC: %s", strerror(errno));
777 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
778 goto error;
779 }
780
781 info->value->has_hardware_address = true;
782 close(sock);
783 }
784
785 if (ifa->ifa_addr &&
786 ifa->ifa_addr->sa_family == AF_INET) {
787 /* interface with IPv4 address */
788 address_item = g_malloc0(sizeof(*address_item));
789 address_item->value = g_malloc0(sizeof(*address_item->value));
790 p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
791 if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
792 snprintf(err_msg, sizeof(err_msg),
793 "inet_ntop failed : %s", strerror(errno));
794 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
795 goto error;
796 }
797
798 address_item->value->ip_address = g_strdup(addr4);
799 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
800
801 if (ifa->ifa_netmask) {
802 /* Count the number of set bits in netmask.
803 * This is safe as '1' and '0' cannot be shuffled in netmask. */
804 p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
805 address_item->value->prefix = ctpop32(((uint32_t *) p)[0]);
806 }
807 } else if (ifa->ifa_addr &&
808 ifa->ifa_addr->sa_family == AF_INET6) {
809 /* interface with IPv6 address */
810 address_item = g_malloc0(sizeof(*address_item));
811 address_item->value = g_malloc0(sizeof(*address_item->value));
812 p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
813 if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
814 snprintf(err_msg, sizeof(err_msg),
815 "inet_ntop failed : %s", strerror(errno));
816 error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
817 goto error;
818 }
819
820 address_item->value->ip_address = g_strdup(addr6);
821 address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
822
823 if (ifa->ifa_netmask) {
824 /* Count the number of set bits in netmask.
825 * This is safe as '1' and '0' cannot be shuffled in netmask. */
826 p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
827 address_item->value->prefix =
828 ctpop32(((uint32_t *) p)[0]) +
829 ctpop32(((uint32_t *) p)[1]) +
830 ctpop32(((uint32_t *) p)[2]) +
831 ctpop32(((uint32_t *) p)[3]);
832 }
833 }
834
835 if (!address_item) {
836 continue;
837 }
838
839 address_list = &info->value->ip_addresses;
840
841 while (*address_list && (*address_list)->next) {
842 address_list = &(*address_list)->next;
843 }
844
845 if (!*address_list) {
846 *address_list = address_item;
847 } else {
848 (*address_list)->next = address_item;
849 }
850
851 info->value->has_ip_addresses = true;
852
853
854 }
855
856 freeifaddrs(ifap);
857 return head;
858
859error:
860 freeifaddrs(ifap);
861 qapi_free_GuestNetworkInterfaceList(head);
862 return NULL;
863}
864
Michael Rothe72c3f22012-03-25 13:59:41 -0500865#else /* defined(__linux__) */
866
Michael Rothe72c3f22012-03-25 13:59:41 -0500867void qmp_guest_suspend_disk(Error **err)
868{
869 error_set(err, QERR_UNSUPPORTED);
870}
871
872void qmp_guest_suspend_ram(Error **err)
873{
874 error_set(err, QERR_UNSUPPORTED);
875}
876
877void qmp_guest_suspend_hybrid(Error **err)
878{
879 error_set(err, QERR_UNSUPPORTED);
880}
881
882GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
883{
884 error_set(errp, QERR_UNSUPPORTED);
885 return NULL;
886}
887
888#endif
889
Michael Rothd35d4cb2012-04-13 21:07:36 -0500890#if !defined(CONFIG_FSFREEZE)
891
892GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
893{
894 error_set(err, QERR_UNSUPPORTED);
895
896 return 0;
897}
898
899int64_t qmp_guest_fsfreeze_freeze(Error **err)
900{
901 error_set(err, QERR_UNSUPPORTED);
902
903 return 0;
904}
905
906int64_t qmp_guest_fsfreeze_thaw(Error **err)
907{
908 error_set(err, QERR_UNSUPPORTED);
909
910 return 0;
911}
912
913#endif
914
Michael Rothe3d4d252011-07-19 15:41:55 -0500915/* register init/cleanup routines for stateful command groups */
916void ga_command_state_init(GAState *s, GACommandState *cs)
917{
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500918#if defined(CONFIG_FSFREEZE)
Michael Rothf22d85e2012-04-17 19:01:45 -0500919 ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
Anthony Liguori7006b9c2011-07-22 14:14:17 -0500920#endif
Michael Rothe3d4d252011-07-19 15:41:55 -0500921 ga_command_state_add(cs, guest_file_init, NULL);
922}