Home | History | Annotate | Download | only in android
      1 /* Copyright (C) 2012 The Android Open Source Project
      2 **
      3 ** This software is licensed under the terms of the GNU General Public
      4 ** License version 2, as published by the Free Software Foundation, and
      5 ** may be copied, distributed, and modified under those terms.
      6 **
      7 ** This program is distributed in the hope that it will be useful,
      8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 ** GNU General Public License for more details.
     11 */
     12 
     13 #include "qemu-common.h"
     14 #include "android/globals.h"
     15 #include "android/snaphost-android.h"
     16 #include "android/utils/debug.h"
     17 
     18 #define  E(...)    derror(__VA_ARGS__)
     19 #define  W(...)    dwarning(__VA_ARGS__)
     20 #define  D(...)    VERBOSE_PRINT(init,__VA_ARGS__)
     21 
     22 /* Compares two instance of an ini file.
     23  * This routine compares all entries (key,value pairs) found in one ini file
     24  * against entries in another file. The files are considered to be equal if:
     25  * 1. Number of entries in each file is equal.
     26  * 2. Each entry in one file has a corresponded entry in another file, and their
     27  *    values are equal.
     28  * Param:
     29  *  current - Ini file containing the current configuration.
     30  *  saved - Ini file containing a previously saved configuration.
     31  * Return:
     32  *  0 if files are equal, or 1 if they are not equal, or -1 if an error has
     33  * occurred.
     34  */
     35 static int
     36 _cmp_hw_config(IniFile* current, IniFile* saved)
     37 {
     38     int n, ret = 0;
     39     const int num_pairs = iniFile_getPairCount(current);
     40 
     41     /* Check 1: must contain same number of entries. */
     42     if (num_pairs != iniFile_getPairCount(saved)) {
     43         D("Different numbers of entries in the HW config files. Current contans %d, while saved contains %d entries.",
     44           num_pairs, iniFile_getPairCount(saved));
     45         return -1;
     46     }
     47 
     48     /* Iterate through the entries in the current file, comparing them to entries
     49      * in the saved file. */
     50     for (n = 0; n < num_pairs && ret == 0; n++) {
     51         char* key, *value1, *value2;
     52 
     53         if (iniFile_getEntry(current, n, &key, &value1)) {
     54             D("Unable to obtain entry %d from the current HW config file", n);
     55             return -1;
     56         }
     57 
     58         value2 = iniFile_getString(saved, key, "");
     59         if (value2 == NULL) {
     60             D("Saved HW config file is missing entry ('%s', '%s') found in the current HW config.",
     61               key, value1);
     62             free(key);
     63             free(value1);
     64             return 1;
     65         }
     66 
     67         ret = strcmp(value1, value2);
     68         if (ret) {
     69             D("HW config value mismatch for a key '%s': current is '%s' while saved was '%s'",
     70               key, value1, value2);
     71         }
     72 
     73         free(value2);
     74         free(value1);
     75         free(key);
     76     }
     77 
     78     return ret ? 1 : 0;
     79 }
     80 
     81 /* Builds path to the HW config backup file that is used to store HW config
     82  * settings used for that snapshot. The backup path is a concatenation of the
     83  * snapshot storage file path, snapshot name, and an 'ini' extension. This
     84  * way we can track HW configuration for different snapshot names store in
     85  * different storage files.
     86  * Param:
     87  *  name - Name of the snapshot inside the snapshot storage file.
     88  * Return:
     89  *  Path to the HW config backup file on success, or NULL on an error.
     90  */
     91 static char*
     92 _build_hwcfg_path(const char* name)
     93 {
     94     const int path_len = strlen(android_hw->disk_snapStorage_path) +
     95                          strlen(name) + 6;
     96     char* bkp_path = malloc(path_len);
     97     if (bkp_path == NULL) {
     98         E("Unable to allocate %d bytes for HW config path!", path_len);
     99         return NULL;
    100     }
    101 
    102     snprintf(bkp_path, path_len, "%s.%s.ini",
    103              android_hw->disk_snapStorage_path, name);
    104 
    105     return bkp_path;
    106 }
    107 
    108 int
    109 snaphost_match_configs(IniFile* hw_ini, const char* name)
    110 {
    111     /* Make sure that snapshot storage path is valid. */
    112     if (android_hw->disk_snapStorage_path == NULL ||
    113         *android_hw->disk_snapStorage_path == '\0') {
    114         return 1;
    115     }
    116 
    117     /* Build path to the HW config for the loading VM. */
    118     char* bkp_path = _build_hwcfg_path(name);
    119     if (bkp_path == NULL) {
    120         return 0;
    121     }
    122 
    123     /* Load HW config from the previous emulator launch. */
    124     IniFile* hwcfg_bkp = iniFile_newFromFile(bkp_path);
    125 
    126     if (hwcfg_bkp != NULL) {
    127         if (_cmp_hw_config(hw_ini, hwcfg_bkp)) {
    128             E("Unable to load VM from snapshot. The snapshot has been saved for a different hardware configuration.");
    129             free(bkp_path);
    130             return 0;
    131         }
    132         iniFile_free(hwcfg_bkp);
    133     } else {
    134         /* It could be that a snapshot file has been copied from another
    135          * location without copying the backup file, or snapshot file has not
    136          * been created yet. In either case we can't do much checking here,
    137          * so, lets be hopefull that user knows what (s)he is doing. */
    138         D("Missing HW config backup file '%s'", bkp_path);
    139     }
    140 
    141     free(bkp_path);
    142 
    143     return 1;
    144 }
    145 
    146 void
    147 snaphost_save_config(const char* name)
    148 {
    149     /* Make sure that snapshot storage path is valid. */
    150     if (android_hw->disk_snapStorage_path == NULL ||
    151         *android_hw->disk_snapStorage_path == '\0') {
    152         return;
    153     }
    154 
    155     /* Build path to the HW config for the saving VM. */
    156     char* bkp_path = _build_hwcfg_path(name);
    157     if (bkp_path == NULL) {
    158         return;
    159     }
    160 
    161     /* Create HW config backup file from the current HW config settings. */
    162     IniFile* hwcfg_bkp = iniFile_newFromMemory("", bkp_path);
    163     if (hwcfg_bkp == NULL) {
    164         W("Unable to create backup HW config file '%s'. Error: %s",
    165           bkp_path, strerror(errno));
    166         return;
    167     }
    168     androidHwConfig_write(android_hw, hwcfg_bkp);
    169 
    170     /* Invalidate data partition initialization path in the backup copy of HW
    171      * config. The reason we need to do this is that we want the system loading
    172      * from the snapshot to be in sync with the data partition the snapshot was
    173      * saved for. For that we must disalow overwritting it on snapshot load. In
    174      * other words, we should allow snapshot loading only on condition
    175      * that disk.dataPartition.initPath is empty. */
    176     iniFile_setValue(hwcfg_bkp, "disk.dataPartition.initPath", "");
    177 
    178     /* Save backup file. */
    179     if (!iniFile_saveToFileClean(hwcfg_bkp, bkp_path)) {
    180         D("HW config has been backed up to '%s'", bkp_path);
    181     } else {
    182         /* Treat this as a "soft" error. Yes, we couldn't save the backup, but
    183          * this should not cancel snapshot saving. */
    184         W("Unable to save HW config file '%s'. Error: %s", bkp_path, strerror(errno));
    185     }
    186     iniFile_free(hwcfg_bkp);
    187     free(bkp_path);
    188 }
    189