diff --git a/MigrationPreparer/CHANGELOG.md b/MigrationPreparer/CHANGELOG.md index c9f953030e..d542be7832 100644 --- a/MigrationPreparer/CHANGELOG.md +++ b/MigrationPreparer/CHANGELOG.md @@ -14,6 +14,9 @@ All notable changes to this RDK Service will be documented in this file. For more details, refer to versioning section under Main README. +## [1.0.2] - 2025-09-11 +- Changes to ensure data integrity of migration data store file. + ## [1.0.1] - 2025-20-01 - Changes to avoid any "value" field from getting printed in MigrationPreparer related logs. diff --git a/MigrationPreparer/MigrationPreparer.cpp b/MigrationPreparer/MigrationPreparer.cpp index c3f2d0d4a0..eed0c997c0 100644 --- a/MigrationPreparer/MigrationPreparer.cpp +++ b/MigrationPreparer/MigrationPreparer.cpp @@ -21,7 +21,7 @@ #define API_VERSION_NUMBER_MAJOR 1 #define API_VERSION_NUMBER_MINOR 0 -#define API_VERSION_NUMBER_PATCH 1 +#define API_VERSION_NUMBER_PATCH 2 namespace WPEFramework { diff --git a/MigrationPreparer/MigrationPreparerImplementation.cpp b/MigrationPreparer/MigrationPreparerImplementation.cpp index 0eb56c0890..4ebf70a88a 100644 --- a/MigrationPreparer/MigrationPreparerImplementation.cpp +++ b/MigrationPreparer/MigrationPreparerImplementation.cpp @@ -25,17 +25,18 @@ namespace Plugin { SERVICE_REGISTRATION(MigrationPreparerImplementation, 1, 0); MigrationPreparerImplementation::MigrationPreparerImplementation() - : _adminLock() + : _adminLock(), + _fileExist(false) { LOGINFO("Create MigrationPreparerImplementation Instance"); - // Init - _fileExist = false; - WPEFramework::Core::File dataStore; - dataStore = string("/opt/secure/migration/migration_data_store.json"); - if(dataStore.Exists()) { - _fileExist = true; - storeKeys(); - } + sanityStatus status = doSanityCheck(); + if(status != PASS) { + if(status != FAIL_DIR) { + backupDataStore(); + } + LOGWARN("Deleting DataStore and Migrationready files - reason: file corruption"); + reset("RESET_ALL"); + } } MigrationPreparerImplementation::~MigrationPreparerImplementation() @@ -76,26 +77,86 @@ namespace Plugin { return escapedString; } - void MigrationPreparerImplementation::storeKeys(void) { + MigrationPreparerImplementation::sanityStatus MigrationPreparerImplementation::doSanityCheck(void){ + WPEFramework::Core::File dataStore; + dataStore = string("/opt/secure/migration/migration_data_store.json"); + WPEFramework::Core::OptionalType error; + JsonObject dataStoreJB; + sanityStatus status = sanityStatus::PASS; + string dataStoreSchema; + + if(dataStore.Exists()) { + _fileExist = true; + if(!dataStore.IsDirectory()) { + if(dataStore.Open()){ + if(dataStoreJB.IElement::FromFile(dataStore, error)) { + dataStore.Close(); + dataStoreSchema = dataStoreJB["schemaVersion"].String(); + dataStoreJB.Clear(); + if(!storeKeys()) { + status = sanityStatus::FAIL_STORE; + } + } else { + status = sanityStatus::FAIL_JSON; + LOGERR("DataStore file json parsing failed: %s", WPEFramework::Core::JSON::ErrorDisplayMessage(error.Value()).c_str()); + } + } else { + status = sanityStatus::FAIL_OPEN; + LOGERR("DataStore file open failed"); + } + } else { + status = sanityStatus::FAIL_DIR; + LOGERR("DataStore file became a directory"); + } + + if(status == sanityStatus::PASS) + LOGINFO("DataStore file sanity check - Success, json schema version: %s", dataStoreSchema.c_str()); + else + LOGERR("DataStore file could be corrupted"); + } + return status; + } + + void MigrationPreparerImplementation::backupDataStore(void) { + // copy dataStore file to /opt/persistent/odm-data/corrupted-migration/ + WPEFramework::Core::Directory postMortemDir(POSTMORTEM_DIR); + + if(!postMortemDir.Exists()) { + postMortemDir.Create(); + } + int result = v_secure_system("/bin/cp %s %s", DATASTORE_PATH, POSTMORTEM_DIR); + if (result != -1 && WIFEXITED(result)) { + LOGINFO("Copying corrupted datastore file into %s - Success", POSTMORTEM_DIR); + } + else{ + LOGERR("Copying corrupted datastore file into %s - Failed", POSTMORTEM_DIR); + } + } + + bool MigrationPreparerImplementation::storeKeys(void) { _dataStoreMutex.lock(); std::ifstream inputFile(DATASTORE_PATH); string key, line; size_t start, end, colPos; LINE_NUMBER_TYPE lineIndex = 1; + bool status = true; while(std::getline(inputFile, line)) { // trim white space, new line and comma from the line start = line.find_first_not_of(" \n"); end = line.find_last_not_of(" \n,"); - line = line.substr(start, end-start+1); if(start == string::npos || end == string::npos) { - LOGWARN("Invalid line in dataStore file, skipping"); + LOGERR("DataStore file could be tampered - empty line or key:value pair is missing in line: %lld", lineIndex); + status = false; + break; + } + + line = line.substr(start, end-start+1); + + // if line is { or } continue + if(line == "{" || line == "}"){ continue; } - ASSERT(start > end); - // if line is empty or { or } continue - if(line.empty() || line == "{" || line == "}") - continue; - + // increment line index lineIndex++; //extract key @@ -105,6 +166,12 @@ namespace Plugin { // "key2":value2 // } colPos = line.find(":"); + if(colPos == string::npos) { + LOGERR("DataStore file could be corrupted - missing colon in key:value pair in line: %lld", lineIndex); + status = false; + break; + } + key = line.substr(1,colPos-2); //add key to the map @@ -116,9 +183,9 @@ namespace Plugin { // update the last line index _curLineIndex = lineIndex; _dataStoreMutex.unlock(); + return status; } - bool MigrationPreparerImplementation::resetDatastore(void){ WPEFramework::Core::File dataStore; dataStore = string("/opt/secure/migration/migration_data_store.json"); @@ -128,6 +195,7 @@ namespace Plugin { } _dataStoreMutex.lock(); // remove dataStore file + LOGWARN("Deleting dataStore file"); if(!dataStore.Destroy()){ LOGERR("Unable to delete dataStore file"); return false; @@ -223,10 +291,10 @@ namespace Plugin { _curLineIndex = 1; if(!dataStore.Exists()) { // check if the directory exist - if(!dataStoreDir.Exists()) + if(!dataStoreDir.Exists()) { // assuming /opt/secure path already exist and "migration" folder needs to be under /opt/secure/ dataStoreDir.Create(); - + } if(!dataStore.Create()) { LOGERR("Failed to create migration datastore %s, errno: %d, reason: %s", DATASTORE_PATH, errno, strerror(errno)); _dataStoreMutex.unlock(); diff --git a/MigrationPreparer/MigrationPreparerImplementation.h b/MigrationPreparer/MigrationPreparerImplementation.h index f340840347..ebc0d527dd 100644 --- a/MigrationPreparer/MigrationPreparerImplementation.h +++ b/MigrationPreparer/MigrationPreparerImplementation.h @@ -41,6 +41,8 @@ #define TR181_MIGRATION_READY "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Bootstrap.MigrationReady" #define MIGRATIONREADY_PATH _T("/opt/secure/migration/migrationready.txt") #define MIGRATIONREADY_DIR _T("/opt/secure/migration/") +#define POSTMORTEM_DIR _T("/opt/secure/corrupted-migration/") + // PLUGIN SPECIFIC CUSTOM ERROR CODES #define ERROR_CREATE 4 @@ -110,7 +112,7 @@ namespace Plugin { enum sedType {PATTERN, REPLACEMENT}; string escapeSed(string, enum sedType); // Fn. to store the keys and their line numbers from dataStore to lineNumber map - void storeKeys(void); + bool storeKeys(void); // Fn. to delete dataStore bool resetDatastore(void); //Fn. to populate list with values from a string @@ -122,7 +124,16 @@ namespace Plugin { int8_t join(string& value, std::list& list, std::string delimiter = "_"); bool isDuplicate(string& searchString, std::list& list); bool resetMigrationready(void); + enum sanityStatus { + PASS, + FAIL_OPEN, + FAIL_DIR, + FAIL_JSON, + FAIL_STORE + }; + sanityStatus doSanityCheck(void); + void backupDataStore(void); /*Helpers: End*/ }; } // namespace Plugin -} // namespace WPEFramework \ No newline at end of file +} // namespace WPEFramework diff --git a/SystemServices/CHANGELOG.md b/SystemServices/CHANGELOG.md index 9ccf8b3620..357a5b7142 100644 --- a/SystemServices/CHANGELOG.md +++ b/SystemServices/CHANGELOG.md @@ -16,6 +16,10 @@ All notable changes to this RDK Service will be documented in this file. * For more details, refer to [versioning](https://github.com/rdkcentral/rdkservices#versioning) section under Main README. +## [1.6.1] - 2023-07-05 +### Added +- Added API to get the boot Type information + ## [1.6.0] - 2023-07-05 ### Added - Added API to get and set friendly name of the device diff --git a/SystemServices/System.json b/SystemServices/System.json index 088611e3ed..e7b67f74f8 100644 --- a/SystemServices/System.json +++ b/SystemServices/System.json @@ -882,6 +882,24 @@ ] } }, + "getBootTypeInfo":{ + "summary": "Getting Boot Type", + "result": { + "type": "object", + "properties": { + "boottype": { + "$ref": "#/definitions/boottype" + }, + "success":{ + "$ref": "#/common/success" + } + }, + "required": [ + "boottype", + "success" + ] + } + }, "getPowerState":{ "summary": "Returns the power state of the device.", "result": { diff --git a/SystemServices/SystemServices.cpp b/SystemServices/SystemServices.cpp index 6dec06e709..908ee43fff 100644 --- a/SystemServices/SystemServices.cpp +++ b/SystemServices/SystemServices.cpp @@ -67,7 +67,7 @@ using namespace std; #define API_VERSION_NUMBER_MAJOR 1 #define API_VERSION_NUMBER_MINOR 6 -#define API_VERSION_NUMBER_PATCH 0 +#define API_VERSION_NUMBER_PATCH 1 #define MAX_REBOOT_DELAY 86400 /* 24Hr = 86400 sec */ #define TR181_FW_DELAY_REBOOT "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.AutoReboot.fwDelayReboot" @@ -97,6 +97,7 @@ using namespace std; #define LOG_UPLOAD_STATUS_SUCCESS "UPLOAD_SUCCESS" #define LOG_UPLOAD_STATUS_FAILURE "UPLOAD_FAILURE" #define LOG_UPLOAD_STATUS_ABORTED "UPLOAD_ABORTED" +#define BOOT_TYPE_FILE "/tmp/bootType" /** * @struct firmwareUpdate @@ -492,7 +493,7 @@ namespace WPEFramework { &SystemServices::getPlatformConfiguration, this); registerMethod("getFriendlyName", &SystemServices::getFriendlyName, this); registerMethod("setFriendlyName", &SystemServices::setFriendlyName, this); - + registerMethod("getBootTypeInfo", &SystemServices::getBootTypeInfo, this); } SystemServices::~SystemServices() @@ -4700,6 +4701,33 @@ namespace WPEFramework { return Core::ERROR_NONE; } + + /** + * @brief : API to query BootType details + * + * @param1[in] : {"params":{}}} + * @param2[out] : "result":{:,"success":} + * @return : Core:: + + */ + + uint32_t SystemServices::getBootTypeInfo(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + bool status = true; + if(Utils::fileExists(BOOT_TYPE_FILE)){ + ifstream inFile(BOOT_TYPE_FILE); + string str; + getline (inFile, str); + response["bootType"] = str; + LOGINFO("Current Boot Type is %s\n", str.c_str()); + } + else{ + status = false; + LOGERR("Failed to read Boot Type"); + } + returnResponse(status); + } } /* namespace Plugin */ } /* namespace WPEFramework */ diff --git a/SystemServices/SystemServices.h b/SystemServices/SystemServices.h index 2ac1dadb1c..51af267567 100644 --- a/SystemServices/SystemServices.h +++ b/SystemServices/SystemServices.h @@ -302,6 +302,7 @@ namespace WPEFramework { uint32_t setWakeupSrcConfiguration(const JsonObject& parameters, JsonObject& response); uint32_t getWakeupSrcConfiguration(const JsonObject& parameters, JsonObject& response); uint32_t getPlatformConfiguration(const JsonObject& parameters, PlatformCaps& response); + uint32_t getBootTypeInfo(const JsonObject& parameters, JsonObject& response); }; /* end of system service class */ } /* end of plugin */ } /* end of wpeframework */