aboutsummaryrefslogtreecommitdiffstats
path: root/android/snaphost-android.c
diff options
context:
space:
mode:
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);
+}