aboutsummaryrefslogtreecommitdiffstats
path: root/android/snaphost-android.c
diff options
context:
space:
mode:
authorVladimir Chtchetkine <vchtchetkine@google.com>2012-01-12 13:37:40 -0800
committerVladimir Chtchetkine <vchtchetkine@google.com>2012-01-13 08:16:05 -0800
commitdb450d73092add519efddcd6d55c7a0e7541ec70 (patch)
treea4de5f7d4c9d1fb35a376dcd198da8c06c846b4f /android/snaphost-android.c
parentaa1af37d8b3c3a21eb4cac4a225225425b50d08c (diff)
downloadexternal_qemu-db450d73092add519efddcd6d55c7a0e7541ec70.zip
external_qemu-db450d73092add519efddcd6d55c7a0e7541ec70.tar.gz
external_qemu-db450d73092add519efddcd6d55c7a0e7541ec70.tar.bz2
Respect HW configs when loading VM from snapshots.
Changing HW configuration properties may cause emulator / guest system crash on condition that VM has been loaded from a snapshot. This CL addresses this issue in the following way: 1. Each time a snapshot is saved, a backup copy of HW config is saved with it. 2. Each time a snapshot is loaded, emulator finds an appropriate HW config backup, and compares current HW config with the one that was saved in the backup, and if configs are different, emulator exits with an appropriate error. Change-Id: I730bec0afbe166e88189fdcc4804b76e109e4422
Diffstat (limited to 'android/snaphost-android.c')
-rw-r--r--android/snaphost-android.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/android/snaphost-android.c b/android/snaphost-android.c
new file mode 100644
index 0000000..205531c
--- /dev/null
+++ b/android/snaphost-android.c
@@ -0,0 +1,180 @@
+/* Copyright (C) 2012 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+
+#include "qemu-common.h"
+#include "android/globals.h"
+#include "android/snaphost-android.h"
+#include "android/utils/debug.h"
+
+#define E(...) derror(__VA_ARGS__)
+#define W(...) dwarning(__VA_ARGS__)
+#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
+
+/* Compares two instance of an ini file.
+ * This routine compares all entries (key,value pairs) found in one ini file
+ * against entries in another file. The files are considered to be equal if:
+ * 1. Number of entries in each file is equal.
+ * 2. Each entry in one file has a corresponded entry in another file, and their
+ * values are equal.
+ * Param:
+ * current - Ini file containing the current configuration.
+ * saved - Ini file containing a previously saved configuration.
+ * Return:
+ * 0 if files are equal, or 1 if they are not equal, or -1 if an error has
+ * occurred.
+ */
+static int
+_cmp_hw_config(IniFile* current, IniFile* saved)
+{
+ int n, ret = 0;
+ const int num_pairs = iniFile_getPairCount(current);
+
+ /* Check 1: must contain same number of entries. */
+ if (num_pairs != iniFile_getPairCount(saved)) {
+ D("Different numbers of entries in the HW config files. Current contans %d, while saved contains %d entries.",
+ num_pairs, iniFile_getPairCount(saved));
+ return -1;
+ }
+
+ /* Iterate through the entries in the current file, comparing them to entries
+ * in the saved file. */
+ for (n = 0; n < num_pairs && ret == 0; n++) {
+ char* key, *value1, *value2;
+
+ if (iniFile_getEntry(current, n, &key, &value1)) {
+ D("Unable to obtain entry %d from the current HW config file", n);
+ return -1;
+ }
+
+ value2 = iniFile_getString(saved, key, "");
+ if (value2 == NULL) {
+ D("Saved HW config file is missing entry ('%s', '%s') found in the current HW config.",
+ key, value1);
+ free(key);
+ free(value1);
+ return 1;
+ }
+
+ ret = strcmp(value1, value2);
+ if (ret) {
+ D("HW config value mismatch for a key '%s': current is '%s' while saved was '%s'",
+ key, value1, value2);
+ }
+
+ free(value2);
+ free(value1);
+ free(key);
+ }
+
+ return ret ? 1 : 0;
+}
+
+/* Builds path to the HW config backup file that is used to store HW config
+ * settings used for that snapshot. The backup path is a concatenation of the
+ * snapshot storage file path, snapshot name, and an 'ini' extension. This
+ * way we can track HW configuration for different snapshot names store in
+ * different storage files.
+ * Param:
+ * name - Name of the snapshot inside the snapshot storage file.
+ * Return:
+ * Path to the HW config backup file on success, or NULL on an error.
+ */
+static char*
+_build_hwcfg_path(const char* name)
+{
+ const int path_len = strlen(android_hw->disk_snapStorage_path) +
+ strlen(name) + 6;
+ char* bkp_path = malloc(path_len);
+ if (bkp_path == NULL) {
+ E("Unable to allocate %d bytes for HW config path!", path_len);
+ return NULL;
+ }
+
+ snprintf(bkp_path, path_len, "%s.%s.ini",
+ android_hw->disk_snapStorage_path, name);
+
+ return bkp_path;
+}
+
+int
+snaphost_match_configs(IniFile* hw_ini, const char* name)
+{
+ /* Make sure that snapshot storage path is valid. */
+ if (android_hw->disk_snapStorage_path == NULL ||
+ *android_hw->disk_snapStorage_path == '\0') {
+ return 1;
+ }
+
+ /* Build path to the HW config for the loading VM. */
+ char* bkp_path = _build_hwcfg_path(name);
+ if (bkp_path == NULL) {
+ return 0;
+ }
+
+ /* Load HW config from the previous emulator launch. */
+ IniFile* hwcfg_bkp = iniFile_newFromFile(bkp_path);
+
+ if (hwcfg_bkp != NULL) {
+ if (_cmp_hw_config(hw_ini, hwcfg_bkp)) {
+ E("Unable to load VM from snapshot. The snapshot has been saved for a different hardware configuration.");
+ free(bkp_path);
+ return 0;
+ }
+ iniFile_free(hwcfg_bkp);
+ } else {
+ /* It could be that a snapshot file has been copied from another
+ * location without copying the backup file, or snapshot file has not
+ * been created yet. In either case we can't do much checking here,
+ * so, lets be hopefull that user knows what (s)he is doing. */
+ D("Missing HW config backup file '%s'", bkp_path);
+ }
+
+ free(bkp_path);
+
+ return 1;
+}
+
+void
+snaphost_save_config(const char* name)
+{
+ /* Make sure that snapshot storage path is valid. */
+ if (android_hw->disk_snapStorage_path == NULL ||
+ *android_hw->disk_snapStorage_path == '\0') {
+ return;
+ }
+
+ /* Build path to the HW config for the saving VM. */
+ char* bkp_path = _build_hwcfg_path(name);
+ if (bkp_path == NULL) {
+ return;
+ }
+
+ /* Create HW config backup file from the current HW config settings. */
+ IniFile* hwcfg_bkp = iniFile_newFromMemory("", bkp_path);
+ if (hwcfg_bkp == NULL) {
+ W("Unable to create backup HW config file '%s'. Error: %s",
+ bkp_path, strerror(errno));
+ return;
+ }
+ androidHwConfig_write(android_hw, hwcfg_bkp);
+
+ /* Save backup file. */
+ if (!iniFile_saveToFileClean(hwcfg_bkp, bkp_path)) {
+ D("HW config has been backed up to '%s'", bkp_path);
+ } else {
+ /* Treat this as a "soft" error. Yes, we couldn't save the backup, but
+ * this should not cancel snapshot saving. */
+ W("Unable to save HW config file '%s'. Error: %s", bkp_path, strerror(errno));
+ }
+ iniFile_free(hwcfg_bkp);
+ free(bkp_path);
+}