Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions MigrationPreparer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion MigrationPreparer/MigrationPreparer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
108 changes: 88 additions & 20 deletions MigrationPreparer/MigrationPreparerImplementation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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<WPEFramework::Core::JSON::Error> 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
Expand All @@ -105,6 +166,12 @@ namespace Plugin {
// <space>"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
Expand All @@ -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");
Expand All @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
15 changes: 13 additions & 2 deletions MigrationPreparer/MigrationPreparerImplementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -122,7 +124,16 @@ namespace Plugin {
int8_t join(string& value, std::list<string>& list, std::string delimiter = "_");
bool isDuplicate(string& searchString, std::list<string>& 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
} // namespace WPEFramework
4 changes: 4 additions & 0 deletions SystemServices/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions SystemServices/System.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
32 changes: 30 additions & 2 deletions SystemServices/SystemServices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -4700,6 +4701,33 @@ namespace WPEFramework {

return Core::ERROR_NONE;
}

/**
* @brief : API to query BootType details
*
* @param1[in] : {"params":{}}}
* @param2[out] : "result":{<key>:<BootType Info Details>,"success":<bool>}
* @return : Core::<StatusCode>

*/

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 */

1 change: 1 addition & 0 deletions SystemServices/SystemServices.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
Loading