aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.android1
-rw-r--r--android/console.c135
-rw-r--r--monitor.c6
-rw-r--r--monitor.h2
-rw-r--r--outputchannel.c61
-rw-r--r--outputchannel.h38
-rw-r--r--savevm.c99
-rw-r--r--sysemu.h5
8 files changed, 303 insertions, 44 deletions
diff --git a/Makefile.android b/Makefile.android
index 69538b7..1cc904a 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -650,6 +650,7 @@ CORE_MISC_SOURCES = vl-android.c \
monitor.c \
readline.c \
qemu-char-android.c \
+ outputchannel.c \
qemu-error.c \
qerror.c \
disas.c \
diff --git a/android/console.c b/android/console.c
index af22fc6..4f1a976 100644
--- a/android/console.c
+++ b/android/console.c
@@ -36,6 +36,7 @@
#include "android/utils/bufprint.h"
#include "android/utils/debug.h"
#include "android/utils/stralloc.h"
+#include "android/config/config.h"
#include "tcpdump.h"
#include "net.h"
#include "monitor.h"
@@ -251,18 +252,25 @@ static void control_control_write( ControlClient client, const char* buff, in
}
}
-static void control_write( ControlClient client, const char* format, ... )
+static int control_vwrite( ControlClient client, const char* format, va_list args )
{
static char temp[1024];
- va_list args;
+ int ret = vsnprintf( temp, sizeof(temp), format, args );
+ temp[ sizeof(temp)-1 ] = 0;
+ control_control_write( client, temp, -1 );
+
+ return ret;
+}
+static int control_write( ControlClient client, const char* format, ... )
+{
+ int ret;
+ va_list args;
va_start(args, format);
- vsnprintf( temp, sizeof(temp), format, args );
+ ret = control_vwrite(client, format, args);
va_end(args);
- temp[ sizeof(temp)-1 ] = 0;
-
- control_control_write( client, temp, -1 );
+ return ret;
}
@@ -1929,6 +1937,109 @@ static const CommandDefRec event_commands[] =
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
+#if CONFIG_ANDROID_SNAPSHOTS
+
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** S N A P S H O T C O M M A N D S ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static int
+control_write_out_cb(void* opaque, const char* fmt, va_list ap)
+{
+ ControlClient client = opaque;
+ int ret = control_vwrite(client, fmt, ap);
+ return ret;
+}
+
+static int
+control_write_err_cb(void* opaque, const char* fmt, va_list ap)
+{
+ int ret = 0;
+ ControlClient client = opaque;
+ ret += control_write(client, "KO: ");
+ ret += control_vwrite(client, fmt, ap);
+ return ret;
+}
+
+static int
+do_snapshot_list( ControlClient client, char* args )
+{
+ int ret;
+ OutputChannel *out = output_channel_alloc(client, control_write_out_cb);
+ OutputChannel *err = output_channel_alloc(client, control_write_err_cb);
+ do_info_snapshots_oc(out, err);
+ ret = output_channel_written(err);
+ output_channel_free(out);
+ output_channel_free(err);
+
+ return ret > 0;
+}
+
+static int
+do_snapshot_save( ControlClient client, char* args )
+{
+ int ret;
+ OutputChannel *err = output_channel_alloc(client, control_write_err_cb);
+ do_savevm_oc(err, args);
+ ret = output_channel_written(err);
+ output_channel_free(err);
+
+ return ret > 0; // no output on error channel indicates success
+}
+
+static int
+do_snapshot_load( ControlClient client, char* args )
+{
+ int ret;
+ OutputChannel *err = output_channel_alloc(client, control_write_err_cb);
+ do_loadvm_oc(err, args);
+ ret = output_channel_written(err);
+ output_channel_free(err);
+
+ return ret > 0;
+}
+
+static int
+do_snapshot_del( ControlClient client, char* args )
+{
+ int ret;
+ OutputChannel *err = output_channel_alloc(client, control_write_err_cb);
+ do_delvm_oc(err, args);
+ ret = output_channel_written(err);
+ output_channel_free(err);
+
+ return ret > 0;
+}
+
+static const CommandDefRec snapshot_commands[] =
+{
+ { "list", "list available state snapshots",
+ "'avd snapshot list' will show a list of all state snapshots that can be loaded\r\n",
+ NULL, do_snapshot_list, NULL },
+
+ { "save", "save state snapshot",
+ "'avd snapshot save <name>' will save the current (run-time) state to a snapshot with the given name\r\n",
+ NULL, do_snapshot_save, NULL },
+
+ { "load", "load state snapshot",
+ "'avd snapshot load <name>' will load the state snapshot of the given name\r\n",
+ NULL, do_snapshot_load, NULL },
+
+ { "del", "delete state snapshot",
+ "'avd snapshot del <name>' will delete the state snapshot with the given name\r\n",
+ NULL, do_snapshot_del, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+
+#endif
+
/********************************************************************************************/
/********************************************************************************************/
@@ -1985,13 +2096,19 @@ static const CommandDefRec vm_commands[] =
NULL, do_avd_start, NULL },
{ "status", "query virtual device status",
- "'avd status' will indicate wether the virtual device is running or not\r\n",
+ "'avd status' will indicate whether the virtual device is running or not\r\n",
NULL, do_avd_status, NULL },
{ "name", "query virtual device name",
"'avd name' will return the name of this virtual device\r\n",
NULL, do_avd_name, NULL },
+#if CONFIG_ANDROID_SNAPSHOTS
+ { "snapshot", "state snapshot commands",
+ "allows you to save and restore the virtual device state in snapshots\r\n",
+ NULL, NULL, snapshot_commands },
+#endif
+
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -2313,8 +2430,8 @@ static const CommandDefRec main_commands[] =
"allows you to simulate an inbound SMS\r\n", NULL,
NULL, sms_commands },
- { "avd", "manager virtual device state",
- "allows to change (e.g. start/stop) the virtual device state\r\n", NULL,
+ { "avd", "control virtual device execution",
+ "allows you to control (e.g. start/stop) the execution of the virtual device\r\n", NULL,
NULL, vm_commands },
{ "window", "manage emulator window",
diff --git a/monitor.c b/monitor.c
index 9de414a..b0b6a7e 100644
--- a/monitor.c
+++ b/monitor.c
@@ -165,11 +165,13 @@ static void monitor_puts(Monitor *mon, const char *str)
}
}
-void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
+int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
{
char buf[4096];
- vsnprintf(buf, sizeof(buf), fmt, ap);
+ int ret = vsnprintf(buf, sizeof(buf), fmt, ap);
monitor_puts(mon, buf);
+
+ return ret;
}
void monitor_printf(Monitor *mon, const char *fmt, ...)
diff --git a/monitor.h b/monitor.h
index 2d478fc..fc80bcb 100644
--- a/monitor.h
+++ b/monitor.h
@@ -53,7 +53,7 @@ int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
int monitor_get_fd(Monitor *mon, const char *fdname);
-void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap);
+int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap);
void monitor_printf(Monitor *mon, const char *fmt, ...)
__attribute__ ((__format__ (__printf__, 2, 3)));
void monitor_print_filename(Monitor *mon, const char *filename);
diff --git a/outputchannel.c b/outputchannel.c
new file mode 100644
index 0000000..a58c767
--- /dev/null
+++ b/outputchannel.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "outputchannel.h"
+#include "qemu-common.h"
+
+struct OutputChannel {
+ void* opaque; /* caller-specific information */
+ OutputChannelPrintf printf; /* callback function to do the printing */
+ unsigned int written; /* number of bytes written to the channel */
+};
+
+OutputChannel* output_channel_alloc(void* opaque, OutputChannelPrintf cb)
+{
+ OutputChannel* oc = qemu_mallocz(sizeof(oc));
+ oc->printf = cb;
+ oc->opaque = opaque;
+ oc->written = 0;
+
+ return oc;
+}
+
+int output_channel_printf(OutputChannel* oc, const char* fmt, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, fmt);
+ ret = oc->printf(oc->opaque, fmt, ap);
+ va_end(ap);
+
+ /* Don't count errors and no-ops towards number of bytes written */
+ if (ret > 0) {
+ oc->written += ret;
+ }
+
+ return ret;
+}
+
+void output_channel_free(OutputChannel* oc)
+{
+ free(oc);
+}
+
+unsigned int output_channel_written(OutputChannel* oc)
+{
+ return oc->written;
+}
diff --git a/outputchannel.h b/outputchannel.h
new file mode 100644
index 0000000..4dece8d
--- /dev/null
+++ b/outputchannel.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _OUTPUTCHANNEL_H
+#define _OUTPUTCHANNEL_H
+
+#include <stdarg.h>
+
+/* Callback function to print a printf-formatted string to a channel */
+typedef int (*OutputChannelPrintf) (void* opaque, const char* fmt, va_list ap);
+
+typedef struct OutputChannel OutputChannel;
+
+/* Allocates a new output channel */
+OutputChannel* output_channel_alloc(void* opaque, OutputChannelPrintf cb);
+
+/* Prints a printf-formatted string to the output channel */
+int output_channel_printf(OutputChannel* oc, const char* fmt, ...);
+
+/* Frees an output channel */
+void output_channel_free(OutputChannel* oc);
+
+/* Returns the number of bytes written to the channel */
+unsigned int output_channel_written(OutputChannel* oc);
+
+#endif /* _OUTPUTCHANNEL_H */
diff --git a/savevm.c b/savevm.c
index ee90805..0e908f3 100644
--- a/savevm.c
+++ b/savevm.c
@@ -86,6 +86,7 @@
#include "sysemu.h"
#include "qemu-timer.h"
#include "qemu-char.h"
+#include "outputchannel.h"
#include "block.h"
#include "audio/audio.h"
#include "migration.h"
@@ -1162,8 +1163,22 @@ static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
return ret;
}
+static int
+monitor_output_channel_cb(void* opaque, const char* fmt, va_list ap)
+{
+ return monitor_vprintf((Monitor*) opaque, fmt, ap);
+}
+
+
void do_savevm(Monitor *mon, const char *name)
{
+ OutputChannel *oc = output_channel_alloc(mon, monitor_output_channel_cb);
+ do_savevm_oc(oc, name);
+ output_channel_free(oc);
+}
+
+void do_savevm_oc(OutputChannel *err, const char *name)
+{
BlockDriverState *bs, *bs1;
QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
int must_delete, ret, i;
@@ -1179,7 +1194,7 @@ void do_savevm(Monitor *mon, const char *name)
bs = get_bs_snapshots();
if (!bs) {
- monitor_printf(mon, "No block device can accept snapshots\n");
+ output_channel_printf(err, "No block device can accept snapshots\n");
return;
}
@@ -1218,22 +1233,22 @@ void do_savevm(Monitor *mon, const char *name)
sn->vm_clock_nsec = qemu_get_clock(vm_clock);
if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
- monitor_printf(mon, "Device %s does not support VM state snapshots\n",
- bdrv_get_device_name(bs));
+ output_channel_printf(err, "Device %s does not support VM state snapshots\n",
+ bdrv_get_device_name(bs));
goto the_end;
}
/* save the VM state */
f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 1);
if (!f) {
- monitor_printf(mon, "Could not open VM state file\n");
+ output_channel_printf(err, "Could not open VM state file\n");
goto the_end;
}
ret = qemu_savevm_state(f);
vm_state_size = qemu_ftell(f);
qemu_fclose(f);
if (ret < 0) {
- monitor_printf(mon, "Error %d while writing VM\n", ret);
+ output_channel_printf(err, "Error %d while writing VM\n", ret);
goto the_end;
}
@@ -1245,17 +1260,17 @@ void do_savevm(Monitor *mon, const char *name)
if (must_delete) {
ret = bdrv_snapshot_delete(bs1, old_sn->id_str);
if (ret < 0) {
- monitor_printf(mon,
- "Error while deleting snapshot on '%s'\n",
- bdrv_get_device_name(bs1));
+ output_channel_printf(err,
+ "Error while deleting snapshot on '%s'\n",
+ bdrv_get_device_name(bs1));
}
}
/* Write VM state size only to the image that contains the state */
sn->vm_state_size = (bs == bs1 ? vm_state_size : 0);
ret = bdrv_snapshot_create(bs1, sn);
if (ret < 0) {
- monitor_printf(mon, "Error while creating snapshot on '%s'\n",
- bdrv_get_device_name(bs1));
+ output_channel_printf(err, "Error while creating snapshot on '%s'\n",
+ bdrv_get_device_name(bs1));
}
}
}
@@ -1267,6 +1282,13 @@ void do_savevm(Monitor *mon, const char *name)
void do_loadvm(Monitor *mon, const char *name)
{
+ OutputChannel *oc = output_channel_alloc(mon, monitor_output_channel_cb);
+ do_loadvm_oc(oc, name);
+ output_channel_free(oc);
+}
+
+void do_loadvm_oc(OutputChannel *err, const char *name)
+{
BlockDriverState *bs, *bs1;
BlockDriverInfo bdi1, *bdi = &bdi1;
QEMUSnapshotInfo sn;
@@ -1276,7 +1298,7 @@ void do_loadvm(Monitor *mon, const char *name)
bs = get_bs_snapshots();
if (!bs) {
- monitor_printf(mon, "No block device supports snapshots\n");
+ output_channel_printf(err, "No block device supports snapshots\n");
return;
}
@@ -1292,20 +1314,20 @@ void do_loadvm(Monitor *mon, const char *name)
ret = bdrv_snapshot_goto(bs1, name);
if (ret < 0) {
if (bs != bs1)
- monitor_printf(mon, "Warning: ");
+ output_channel_printf(err, "Warning: ");
switch(ret) {
case -ENOTSUP:
- monitor_printf(mon,
+ output_channel_printf(err,
"Snapshots not supported on device '%s'\n",
bdrv_get_device_name(bs1));
break;
case -ENOENT:
- monitor_printf(mon, "Could not find snapshot '%s' on "
+ output_channel_printf(err, "Could not find snapshot '%s' on "
"device '%s'\n",
name, bdrv_get_device_name(bs1));
break;
default:
- monitor_printf(mon, "Error %d while activating snapshot on"
+ output_channel_printf(err, "Error %d while activating snapshot on"
" '%s'\n", ret, bdrv_get_device_name(bs1));
break;
}
@@ -1317,7 +1339,7 @@ void do_loadvm(Monitor *mon, const char *name)
}
if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
- monitor_printf(mon, "Device %s does not support VM state snapshots\n",
+ output_channel_printf(err, "Device %s does not support VM state snapshots\n",
bdrv_get_device_name(bs));
return;
}
@@ -1330,13 +1352,13 @@ void do_loadvm(Monitor *mon, const char *name)
/* restore the VM state */
f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 0);
if (!f) {
- monitor_printf(mon, "Could not open VM state file\n");
+ output_channel_printf(err, "Could not open VM state file\n");
goto the_end;
}
ret = qemu_loadvm_state(f);
qemu_fclose(f);
if (ret < 0) {
- monitor_printf(mon, "Error %d while loading VM state\n", ret);
+ output_channel_printf(err, "Error %d while loading VM state\n", ret);
}
the_end:
if (saved_vm_running)
@@ -1345,12 +1367,18 @@ void do_loadvm(Monitor *mon, const char *name)
void do_delvm(Monitor *mon, const char *name)
{
+ OutputChannel *oc = output_channel_alloc(mon, monitor_output_channel_cb);
+ do_delvm_oc(oc, name);
+ output_channel_free(oc);
+}
+void do_delvm_oc(OutputChannel *err, const char *name)
+{
BlockDriverState *bs, *bs1;
int i, ret;
bs = get_bs_snapshots();
if (!bs) {
- monitor_printf(mon, "No block device supports snapshots\n");
+ output_channel_printf(err, "No block device supports snapshots\n");
return;
}
@@ -1360,12 +1388,12 @@ void do_delvm(Monitor *mon, const char *name)
ret = bdrv_snapshot_delete(bs1, name);
if (ret < 0) {
if (ret == -ENOTSUP)
- monitor_printf(mon,
- "Snapshots not supported on device '%s'\n",
- bdrv_get_device_name(bs1));
+ output_channel_printf(err,
+ "Snapshots not supported on device '%s'\n",
+ bdrv_get_device_name(bs1));
else
- monitor_printf(mon, "Error %d while deleting snapshot on "
- "'%s'\n", ret, bdrv_get_device_name(bs1));
+ output_channel_printf(err, "Error %d while deleting snapshot on "
+ "'%s'\n", ret, bdrv_get_device_name(bs1));
}
}
}
@@ -1373,6 +1401,13 @@ void do_delvm(Monitor *mon, const char *name)
void do_info_snapshots(Monitor *mon)
{
+ OutputChannel *oc = output_channel_alloc(mon, monitor_output_channel_cb);
+ do_info_snapshots_oc(oc, oc);
+ output_channel_free(oc);
+}
+
+void do_info_snapshots_oc(OutputChannel *out, OutputChannel *err)
+{
BlockDriverState *bs, *bs1;
QEMUSnapshotInfo *sn_tab, *sn;
int nb_sns, i;
@@ -1380,30 +1415,30 @@ void do_info_snapshots(Monitor *mon)
bs = get_bs_snapshots();
if (!bs) {
- monitor_printf(mon, "No available block device supports snapshots\n");
+ output_channel_printf(err, "No available block device supports snapshots\n");
return;
}
- monitor_printf(mon, "Snapshot devices:");
+ output_channel_printf(out, "Snapshot devices:");
for(i = 0; i <= nb_drives; i++) {
bs1 = drives_table[i].bdrv;
if (bdrv_can_snapshot(bs1)) {
if (bs == bs1)
- monitor_printf(mon, " %s", bdrv_get_device_name(bs1));
+ output_channel_printf(out, " %s", bdrv_get_device_name(bs1));
}
}
- monitor_printf(mon, "\n");
+ output_channel_printf(out, "\n");
nb_sns = bdrv_snapshot_list(bs, &sn_tab);
if (nb_sns < 0) {
- monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
+ output_channel_printf(err, "bdrv_snapshot_list: error %d\n", nb_sns);
return;
}
- monitor_printf(mon, "Snapshot list (from %s):\n",
+ output_channel_printf(out, "Snapshot list (from %s):\n",
bdrv_get_device_name(bs));
- monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
+ output_channel_printf(out, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
for(i = 0; i < nb_sns; i++) {
sn = &sn_tab[i];
- monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
+ output_channel_printf(out, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
}
qemu_free(sn_tab);
}
diff --git a/sysemu.h b/sysemu.h
index 0c57d5d..fadf908 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -8,6 +8,7 @@
#include "qemu-timer.h"
#include "qdict.h"
#include "qerror.h"
+#include "outputchannel.h"
#ifdef _WIN32
#include <windows.h>
@@ -61,9 +62,13 @@ void qemu_system_powerdown(void);
void qemu_system_reset(void);
void do_savevm(Monitor *mon, const char *name);
+void do_savevm_oc(OutputChannel *err, const char *name);
void do_loadvm(Monitor *mon, const char *name);
+void do_loadvm_oc(OutputChannel *err, const char *name);
void do_delvm(Monitor *mon, const char *name);
+void do_delvm_oc(OutputChannel *err, const char *name);
void do_info_snapshots(Monitor *mon);
+void do_info_snapshots_oc(OutputChannel *out, OutputChannel *err);
void qemu_announce_self(void);