2 * QEMU Guest Agent commands
4 * Copyright IBM Corp. 2011
7 * Michael Roth <mdroth@linux.vnet.ibm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
15 #include <sys/types.h>
16 #include <sys/ioctl.h>
18 #include "qga/guest-agent-core.h"
19 #include "qga-qmp-commands.h"
21 #include "qemu-queue.h"
23 static GAState
*ga_state
;
25 static void disable_logging(void)
27 ga_disable_logging(ga_state
);
30 static void enable_logging(void)
32 ga_enable_logging(ga_state
);
35 /* Note: in some situations, like with the fsfreeze, logging may be
36 * temporarilly disabled. if it is necessary that a command be able
37 * to log for accounting purposes, check ga_logging_enabled() beforehand,
38 * and use the QERR_QGA_LOGGING_DISABLED to generate an error
40 static void slog(const char *fmt
, ...)
45 g_logv("syslog", G_LOG_LEVEL_INFO
, fmt
, ap
);
49 int64_t qmp_guest_sync(int64_t id
, Error
**errp
)
54 void qmp_guest_ping(Error
**err
)
56 slog("guest-ping called");
59 struct GuestAgentInfo
*qmp_guest_info(Error
**err
)
61 GuestAgentInfo
*info
= qemu_mallocz(sizeof(GuestAgentInfo
));
63 info
->version
= g_strdup(QGA_VERSION
);
68 void qmp_guest_shutdown(bool has_mode
, const char *mode
, Error
**err
)
71 const char *shutdown_flag
;
73 slog("guest-shutdown called, mode: %s", mode
);
74 if (!has_mode
|| strcmp(mode
, "powerdown") == 0) {
76 } else if (strcmp(mode
, "halt") == 0) {
78 } else if (strcmp(mode
, "reboot") == 0) {
81 error_set(err
, QERR_INVALID_PARAMETER_VALUE
, "mode",
82 "halt|powerdown|reboot");
88 /* child, start the shutdown */
94 ret
= execl("/sbin/shutdown", "shutdown", shutdown_flag
, "+0",
95 "hypervisor initiated shutdown", (char*)NULL
);
97 slog("guest-shutdown failed: %s", strerror(errno
));
100 } else if (ret
< 0) {
101 error_set(err
, QERR_UNDEFINED_ERROR
);
105 typedef struct GuestFileHandle
{
108 QTAILQ_ENTRY(GuestFileHandle
) next
;
112 QTAILQ_HEAD(, GuestFileHandle
) filehandles
;
115 static void guest_file_handle_add(FILE *fh
)
117 GuestFileHandle
*gfh
;
119 gfh
= qemu_mallocz(sizeof(GuestFileHandle
));
120 gfh
->id
= fileno(fh
);
122 QTAILQ_INSERT_TAIL(&guest_file_state
.filehandles
, gfh
, next
);
125 static GuestFileHandle
*guest_file_handle_find(int64_t id
)
127 GuestFileHandle
*gfh
;
129 QTAILQ_FOREACH(gfh
, &guest_file_state
.filehandles
, next
)
139 int64_t qmp_guest_file_open(const char *path
, bool has_mode
, const char *mode
, Error
**err
)
148 slog("guest-file-open called, filepath: %s, mode: %s", path
, mode
);
149 fh
= fopen(path
, mode
);
151 error_set(err
, QERR_OPEN_FILE_FAILED
, path
);
155 /* set fd non-blocking to avoid common use cases (like reading from a
156 * named pipe) from hanging the agent
159 ret
= fcntl(fd
, F_GETFL
);
160 ret
= fcntl(fd
, F_SETFL
, ret
| O_NONBLOCK
);
162 error_set(err
, QERR_QGA_COMMAND_FAILED
, "fcntl() failed");
167 guest_file_handle_add(fh
);
168 slog("guest-file-open, handle: %d", fd
);
172 void qmp_guest_file_close(int64_t handle
, Error
**err
)
174 GuestFileHandle
*gfh
= guest_file_handle_find(handle
);
177 slog("guest-file-close called, handle: %ld", handle
);
179 error_set(err
, QERR_FD_NOT_FOUND
, "handle");
183 ret
= fclose(gfh
->fh
);
185 error_set(err
, QERR_QGA_COMMAND_FAILED
, "fclose() failed");
189 QTAILQ_REMOVE(&guest_file_state
.filehandles
, gfh
, next
);
193 struct GuestFileRead
*qmp_guest_file_read(int64_t handle
, bool has_count
,
194 int64_t count
, Error
**err
)
196 GuestFileHandle
*gfh
= guest_file_handle_find(handle
);
197 GuestFileRead
*read_data
= NULL
;
203 error_set(err
, QERR_FD_NOT_FOUND
, "handle");
208 count
= QGA_READ_COUNT_DEFAULT
;
209 } else if (count
< 0) {
210 error_set(err
, QERR_INVALID_PARAMETER
, "count");
215 buf
= qemu_mallocz(count
+1);
216 read_count
= fread(buf
, 1, count
, fh
);
218 slog("guest-file-read failed, handle: %ld", handle
);
219 error_set(err
, QERR_QGA_COMMAND_FAILED
, "fread() failed");
222 read_data
= qemu_mallocz(sizeof(GuestFileRead
));
223 read_data
->count
= read_count
;
224 read_data
->eof
= feof(fh
);
226 read_data
->buf_b64
= g_base64_encode(buf
, read_count
);
235 GuestFileWrite
*qmp_guest_file_write(int64_t handle
, const char *buf_b64
,
236 bool has_count
, int64_t count
, Error
**err
)
238 GuestFileWrite
*write_data
= NULL
;
242 GuestFileHandle
*gfh
= guest_file_handle_find(handle
);
246 error_set(err
, QERR_FD_NOT_FOUND
, "handle");
251 buf
= g_base64_decode(buf_b64
, &buf_len
);
255 } else if (count
< 0 || count
> buf_len
) {
257 error_set(err
, QERR_INVALID_PARAMETER
, "count");
261 write_count
= fwrite(buf
, 1, count
, fh
);
263 slog("guest-file-write failed, handle: %ld", handle
);
264 error_set(err
, QERR_QGA_COMMAND_FAILED
, "fwrite() error");
266 write_data
= qemu_mallocz(sizeof(GuestFileWrite
));
267 write_data
->count
= write_count
;
268 write_data
->eof
= feof(fh
);
276 struct GuestFileSeek
*qmp_guest_file_seek(int64_t handle
, int64_t offset
,
277 int64_t whence
, Error
**err
)
279 GuestFileHandle
*gfh
= guest_file_handle_find(handle
);
280 GuestFileSeek
*seek_data
= NULL
;
285 error_set(err
, QERR_FD_NOT_FOUND
, "handle");
290 ret
= fseek(fh
, offset
, whence
);
292 error_set(err
, QERR_QGA_COMMAND_FAILED
, strerror(errno
));
294 seek_data
= qemu_mallocz(sizeof(GuestFileRead
));
295 seek_data
->position
= ftell(fh
);
296 seek_data
->eof
= feof(fh
);
303 void qmp_guest_file_flush(int64_t handle
, Error
**err
)
305 GuestFileHandle
*gfh
= guest_file_handle_find(handle
);
310 error_set(err
, QERR_FD_NOT_FOUND
, "handle");
317 error_set(err
, QERR_QGA_COMMAND_FAILED
, strerror(errno
));
321 static void guest_file_init(void)
323 QTAILQ_INIT(&guest_file_state
.filehandles
);
326 typedef struct GuestFsfreezeMount
{
329 QTAILQ_ENTRY(GuestFsfreezeMount
) next
;
330 } GuestFsfreezeMount
;
333 GuestFsfreezeStatus status
;
334 QTAILQ_HEAD(, GuestFsfreezeMount
) mount_list
;
335 } guest_fsfreeze_state
;
338 * Walk the mount table and build a list of local file systems
340 static int guest_fsfreeze_build_mount_list(void)
343 GuestFsfreezeMount
*mount
, *temp
;
344 char const *mtab
= MOUNTED
;
347 QTAILQ_FOREACH_SAFE(mount
, &guest_fsfreeze_state
.mount_list
, next
, temp
) {
348 QTAILQ_REMOVE(&guest_fsfreeze_state
.mount_list
, mount
, next
);
349 qemu_free(mount
->dirname
);
350 qemu_free(mount
->devtype
);
354 fp
= setmntent(mtab
, "r");
356 g_warning("fsfreeze: unable to read mtab");
360 while ((ment
= getmntent(fp
))) {
362 * An entry which device name doesn't start with a '/' is
363 * either a dummy file system or a network file system.
364 * Add special handling for smbfs and cifs as is done by
367 if ((ment
->mnt_fsname
[0] != '/') ||
368 (strcmp(ment
->mnt_type
, "smbfs") == 0) ||
369 (strcmp(ment
->mnt_type
, "cifs") == 0)) {
373 mount
= qemu_mallocz(sizeof(GuestFsfreezeMount
));
374 mount
->dirname
= qemu_strdup(ment
->mnt_dir
);
375 mount
->devtype
= qemu_strdup(ment
->mnt_type
);
377 QTAILQ_INSERT_TAIL(&guest_fsfreeze_state
.mount_list
, mount
, next
);
386 * Return status of freeze/thaw
388 GuestFsfreezeStatus
qmp_guest_fsfreeze_status(Error
**err
)
390 return guest_fsfreeze_state
.status
;
394 * Walk list of mounted file systems in the guest, and freeze the ones which
395 * are real local file systems.
397 int64_t qmp_guest_fsfreeze_freeze(Error
**err
)
400 struct GuestFsfreezeMount
*mount
, *temp
;
404 slog("guest-fsfreeze called");
406 if (guest_fsfreeze_state
.status
== GUEST_FSFREEZE_STATUS_FROZEN
) {
410 ret
= guest_fsfreeze_build_mount_list();
415 /* cannot risk guest agent blocking itself on a write in this state */
418 QTAILQ_FOREACH_SAFE(mount
, &guest_fsfreeze_state
.mount_list
, next
, temp
) {
419 fd
= qemu_open(mount
->dirname
, O_RDONLY
);
421 sprintf(err_msg
, "failed to open %s, %s", mount
->dirname
, strerror(errno
));
422 error_set(err
, QERR_QGA_COMMAND_FAILED
, err_msg
);
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.
428 * these will report EOPNOTSUPP, so we simply ignore them. when
429 * thawing, these filesystems will return an EINVAL instead, due to
430 * not being in a frozen state. Other filesystem-specific
431 * errors may result in EINVAL, however, so the user should check the
432 * number * of filesystems returned here against those returned by the
433 * thaw operation to determine whether everything completed
436 ret
= ioctl(fd
, FIFREEZE
);
437 if (ret
< 0 && errno
!= EOPNOTSUPP
) {
438 sprintf(err_msg
, "failed to freeze %s, %s", mount
->dirname
, strerror(errno
));
439 error_set(err
, QERR_QGA_COMMAND_FAILED
, err_msg
);
448 guest_fsfreeze_state
.status
= GUEST_FSFREEZE_STATUS_FROZEN
;
453 qmp_guest_fsfreeze_thaw(NULL
);
459 * Walk list of frozen file systems in the guest, and thaw them.
461 int64_t qmp_guest_fsfreeze_thaw(Error
**err
)
464 GuestFsfreezeMount
*mount
, *temp
;
466 bool has_error
= false;
468 QTAILQ_FOREACH_SAFE(mount
, &guest_fsfreeze_state
.mount_list
, next
, temp
) {
469 fd
= qemu_open(mount
->dirname
, O_RDONLY
);
474 ret
= ioctl(fd
, FITHAW
);
475 if (ret
< 0 && errno
!= EOPNOTSUPP
&& errno
!= EINVAL
) {
485 guest_fsfreeze_state
.status
= GUEST_FSFREEZE_STATUS_ERROR
;
487 guest_fsfreeze_state
.status
= GUEST_FSFREEZE_STATUS_THAWED
;
493 static void guest_fsfreeze_init(void)
495 guest_fsfreeze_state
.status
= GUEST_FSFREEZE_STATUS_THAWED
;
496 QTAILQ_INIT(&guest_fsfreeze_state
.mount_list
);
499 static void guest_fsfreeze_cleanup(void)
504 if (guest_fsfreeze_state
.status
== GUEST_FSFREEZE_STATUS_FROZEN
) {
505 ret
= qmp_guest_fsfreeze_thaw(&err
);
506 if (ret
< 0 || err
) {
507 slog("failed to clean up frozen filesystems");
512 /* register init/cleanup routines for stateful command groups */
513 void ga_command_state_init(GAState
*s
, GACommandState
*cs
)
516 ga_command_state_add(cs
, guest_fsfreeze_init
, guest_fsfreeze_cleanup
);
517 ga_command_state_add(cs
, guest_file_init
, NULL
);