135e83f3eSSaqib Khan #include <fstream> 2ec1b41c4SGunnar Mills #include <string> 32ce7da29SGunnar Mills #include <phosphor-logging/log.hpp> 4dcbfa04aSSaqib Khan #include <phosphor-logging/elog.hpp> 5dcbfa04aSSaqib Khan #include <elog-errors.hpp> 6dcbfa04aSSaqib Khan #include <xyz/openbmc_project/Software/Version/error.hpp> 7ec1b41c4SGunnar Mills #include "config.h" 82ce7da29SGunnar Mills #include "item_updater.hpp" 92ce7da29SGunnar Mills #include "xyz/openbmc_project/Software/Version/server.hpp" 1035e83f3eSSaqib Khan #include <experimental/filesystem> 11705f1bfcSSaqib Khan #include "version.hpp" 125d532675SSaqib Khan #include "serialize.hpp" 13ec1b41c4SGunnar Mills 14ec1b41c4SGunnar Mills namespace phosphor 15ec1b41c4SGunnar Mills { 16ec1b41c4SGunnar Mills namespace software 17ec1b41c4SGunnar Mills { 18ec1b41c4SGunnar Mills namespace updater 19ec1b41c4SGunnar Mills { 20ec1b41c4SGunnar Mills 212ce7da29SGunnar Mills // When you see server:: you know we're referencing our base class 222ce7da29SGunnar Mills namespace server = sdbusplus::xyz::openbmc_project::Software::server; 230129d926SMichael Tritz namespace control = sdbusplus::xyz::openbmc_project::Control::server; 242ce7da29SGunnar Mills 252ce7da29SGunnar Mills using namespace phosphor::logging; 26dcbfa04aSSaqib Khan using namespace sdbusplus::xyz::openbmc_project::Software::Version::Error; 2735e83f3eSSaqib Khan namespace fs = std::experimental::filesystem; 2835e83f3eSSaqib Khan 29b1cfdf99SMichael Tritz const std::vector<std::string> bmcImages = { "image-kernel", 30b1cfdf99SMichael Tritz "image-rofs", 31b1cfdf99SMichael Tritz "image-rwfs", 32b1cfdf99SMichael Tritz "image-u-boot" }; 332ce7da29SGunnar Mills 34e75d10f5SPatrick Williams void ItemUpdater::createActivation(sdbusplus::message::message& msg) 35ec1b41c4SGunnar Mills { 3684a0e693SSaqib Khan 3784a0e693SSaqib Khan using SVersion = server::Version; 3884a0e693SSaqib Khan using VersionPurpose = SVersion::VersionPurpose; 399a782243SGunnar Mills using VersionClass = phosphor::software::manager::Version; 4084a0e693SSaqib Khan namespace mesg = sdbusplus::message; 4184a0e693SSaqib Khan namespace variant_ns = mesg::variant_ns; 4284a0e693SSaqib Khan 4384a0e693SSaqib Khan mesg::object_path objPath; 4484a0e693SSaqib Khan auto purpose = VersionPurpose::Unknown; 45705f1bfcSSaqib Khan std::string version; 462ce7da29SGunnar Mills std::map<std::string, 472ce7da29SGunnar Mills std::map<std::string, 4884a0e693SSaqib Khan mesg::variant<std::string>>> interfaces; 49e75d10f5SPatrick Williams msg.read(objPath, interfaces); 502ce7da29SGunnar Mills std::string path(std::move(objPath)); 5119177d3eSSaqib Khan std::string filePath; 522ce7da29SGunnar Mills 532ce7da29SGunnar Mills for (const auto& intf : interfaces) 542ce7da29SGunnar Mills { 55705f1bfcSSaqib Khan if (intf.first == VERSION_IFACE) 562ce7da29SGunnar Mills { 572ce7da29SGunnar Mills for (const auto& property : intf.second) 582ce7da29SGunnar Mills { 59705f1bfcSSaqib Khan if (property.first == "Purpose") 602ce7da29SGunnar Mills { 6184a0e693SSaqib Khan auto value = SVersion::convertVersionPurposeFromString( 6284a0e693SSaqib Khan variant_ns::get<std::string>(property.second)); 6384a0e693SSaqib Khan if (value == VersionPurpose::BMC || 6484a0e693SSaqib Khan value == VersionPurpose::System) 6584a0e693SSaqib Khan { 6684a0e693SSaqib Khan purpose = value; 6784a0e693SSaqib Khan } 68705f1bfcSSaqib Khan } 69705f1bfcSSaqib Khan else if (property.first == "Version") 70705f1bfcSSaqib Khan { 7184a0e693SSaqib Khan version = variant_ns::get<std::string>(property.second); 72705f1bfcSSaqib Khan } 73705f1bfcSSaqib Khan } 74705f1bfcSSaqib Khan } 7519177d3eSSaqib Khan else if (intf.first == FILEPATH_IFACE) 7619177d3eSSaqib Khan { 7719177d3eSSaqib Khan for (const auto& property : intf.second) 7819177d3eSSaqib Khan { 7919177d3eSSaqib Khan if (property.first == "Path") 8019177d3eSSaqib Khan { 8184a0e693SSaqib Khan filePath = variant_ns::get<std::string>(property.second); 8219177d3eSSaqib Khan } 8319177d3eSSaqib Khan } 8419177d3eSSaqib Khan } 85705f1bfcSSaqib Khan } 86705f1bfcSSaqib Khan if (version.empty() || 8719177d3eSSaqib Khan filePath.empty() || 8884a0e693SSaqib Khan purpose == VersionPurpose::Unknown) 892ce7da29SGunnar Mills { 90e75d10f5SPatrick Williams return; 912ce7da29SGunnar Mills } 922ce7da29SGunnar Mills 932ce7da29SGunnar Mills // Version id is the last item in the path 942ce7da29SGunnar Mills auto pos = path.rfind("/"); 952ce7da29SGunnar Mills if (pos == std::string::npos) 962ce7da29SGunnar Mills { 972ce7da29SGunnar Mills log<level::ERR>("No version id found in object path", 982ce7da29SGunnar Mills entry("OBJPATH=%s", path)); 99e75d10f5SPatrick Williams return; 1002ce7da29SGunnar Mills } 1012ce7da29SGunnar Mills 1022ce7da29SGunnar Mills auto versionId = path.substr(pos + 1); 1032ce7da29SGunnar Mills 104e75d10f5SPatrick Williams if (activations.find(versionId) == activations.end()) 1052ce7da29SGunnar Mills { 10635e83f3eSSaqib Khan // Determine the Activation state by processing the given image dir. 10735e83f3eSSaqib Khan auto activationState = server::Activation::Activations::Invalid; 1089a782243SGunnar Mills ItemUpdater::ActivationStatus result = 1099a782243SGunnar Mills ItemUpdater::validateSquashFSImage(filePath); 11043b25cdeSGunnar Mills AssociationList associations = {}; 11143b25cdeSGunnar Mills 11235e83f3eSSaqib Khan if (result == ItemUpdater::ActivationStatus::ready) 11335e83f3eSSaqib Khan { 11435e83f3eSSaqib Khan activationState = server::Activation::Activations::Ready; 115b60add1eSGunnar Mills // Create an association to the BMC inventory item 11643b25cdeSGunnar Mills associations.emplace_back(std::make_tuple( 117b60add1eSGunnar Mills ACTIVATION_FWD_ASSOCIATION, 118b60add1eSGunnar Mills ACTIVATION_REV_ASSOCIATION, 11943b25cdeSGunnar Mills bmcInventoryPath)); 12043b25cdeSGunnar Mills } 121b60add1eSGunnar Mills 122*4254beceSMichael Tritz auto activationPtr = std::make_unique<Activation>( 12335e83f3eSSaqib Khan bus, 12435e83f3eSSaqib Khan path, 1254c1aec09SSaqib Khan *this, 12635e83f3eSSaqib Khan versionId, 127b60add1eSGunnar Mills activationState, 128*4254beceSMichael Tritz associations); 129*4254beceSMichael Tritz 130*4254beceSMichael Tritz activationPtr->deleteObject = 131*4254beceSMichael Tritz std::make_unique<Delete>(bus, path, *activationPtr); 132*4254beceSMichael Tritz 133*4254beceSMichael Tritz activations.insert(std::make_pair(versionId, std::move(activationPtr))); 134*4254beceSMichael Tritz 135705f1bfcSSaqib Khan versions.insert(std::make_pair( 136705f1bfcSSaqib Khan versionId, 1379a782243SGunnar Mills std::make_unique<VersionClass>( 138705f1bfcSSaqib Khan bus, 139705f1bfcSSaqib Khan path, 140705f1bfcSSaqib Khan version, 141705f1bfcSSaqib Khan purpose, 1429440f491SEddie James filePath))); 1432ce7da29SGunnar Mills } 144e75d10f5SPatrick Williams return; 145ec1b41c4SGunnar Mills } 146ec1b41c4SGunnar Mills 147ba239881SSaqib Khan void ItemUpdater::processBMCImage() 148ba239881SSaqib Khan { 14988e8a325SGunnar Mills using VersionClass = phosphor::software::manager::Version; 15088e8a325SGunnar Mills // Read os-release from /etc/ to get the functional BMC version 15188e8a325SGunnar Mills auto functionalVersion = VersionClass::getBMCVersion(OS_RELEASE_FILE); 15288e8a325SGunnar Mills 1531eef62deSSaqib Khan // Read os-release from folders under /media/ to get 1541eef62deSSaqib Khan // BMC Software Versions. 1551eef62deSSaqib Khan for (const auto& iter : fs::directory_iterator(MEDIA_DIR)) 1561eef62deSSaqib Khan { 1571eef62deSSaqib Khan auto activationState = server::Activation::Activations::Active; 1586fab70daSSaqib Khan static const auto BMC_RO_PREFIX_LEN = strlen(BMC_ROFS_PREFIX); 1591eef62deSSaqib Khan 1601eef62deSSaqib Khan // Check if the BMC_RO_PREFIXis the prefix of the iter.path 1611eef62deSSaqib Khan if (0 == iter.path().native().compare(0, BMC_RO_PREFIX_LEN, 1626fab70daSSaqib Khan BMC_ROFS_PREFIX)) 1631eef62deSSaqib Khan { 164021c365bSSaqib Khan // The versionId is extracted from the path 165021c365bSSaqib Khan // for example /media/ro-2a1022fe. 166021c365bSSaqib Khan auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN); 1671eef62deSSaqib Khan auto osRelease = iter.path() / OS_RELEASE_FILE; 1681eef62deSSaqib Khan if (!fs::is_regular_file(osRelease)) 1691eef62deSSaqib Khan { 1702ad1b55fSGunnar Mills log<level::ERR>("Failed to read osRelease", 1712ad1b55fSGunnar Mills entry("FILENAME=%s", osRelease.string())); 172021c365bSSaqib Khan ItemUpdater::erase(id); 173021c365bSSaqib Khan continue; 1741eef62deSSaqib Khan } 17588e8a325SGunnar Mills auto version = VersionClass::getBMCVersion(osRelease); 1761eef62deSSaqib Khan if (version.empty()) 1771eef62deSSaqib Khan { 1781eef62deSSaqib Khan log<level::ERR>("Failed to read version from osRelease", 1791eef62deSSaqib Khan entry("FILENAME=%s", osRelease.string())); 1801eef62deSSaqib Khan activationState = server::Activation::Activations::Invalid; 1811eef62deSSaqib Khan } 182021c365bSSaqib Khan 1831eef62deSSaqib Khan auto purpose = server::Version::VersionPurpose::BMC; 1841eef62deSSaqib Khan auto path = fs::path(SOFTWARE_OBJPATH) / id; 1851eef62deSSaqib Khan 18688e8a325SGunnar Mills // Create functional association if this is the functional version 18788e8a325SGunnar Mills if (version.compare(functionalVersion) == 0) 18888e8a325SGunnar Mills { 18988e8a325SGunnar Mills createFunctionalAssociation(path); 19088e8a325SGunnar Mills } 19188e8a325SGunnar Mills 19243b25cdeSGunnar Mills AssociationList associations = {}; 19343b25cdeSGunnar Mills 19443b25cdeSGunnar Mills if (activationState == server::Activation::Activations::Active) 19543b25cdeSGunnar Mills { 19643b25cdeSGunnar Mills // Create an association to the BMC inventory item 19743b25cdeSGunnar Mills associations.emplace_back(std::make_tuple( 19843b25cdeSGunnar Mills ACTIVATION_FWD_ASSOCIATION, 19943b25cdeSGunnar Mills ACTIVATION_REV_ASSOCIATION, 20043b25cdeSGunnar Mills bmcInventoryPath)); 20143b25cdeSGunnar Mills 20243b25cdeSGunnar Mills // Create an active association since this image is active 20343b25cdeSGunnar Mills createActiveAssociation(path); 20443b25cdeSGunnar Mills } 20543b25cdeSGunnar Mills 206ee590c74SAdriana Kobylak // Create Version instance for this version. 207ee590c74SAdriana Kobylak auto versionPtr = std::make_unique<VersionClass>( 208ee590c74SAdriana Kobylak bus, 209ee590c74SAdriana Kobylak path, 210ee590c74SAdriana Kobylak version, 211ee590c74SAdriana Kobylak purpose, 212ee590c74SAdriana Kobylak ""); 213ee590c74SAdriana Kobylak auto isVersionFunctional = versionPtr->isFunctional(); 214ee590c74SAdriana Kobylak versions.insert(std::make_pair( 215ee590c74SAdriana Kobylak id, 216ee590c74SAdriana Kobylak std::move(versionPtr))); 217ee590c74SAdriana Kobylak 2181eef62deSSaqib Khan // Create Activation instance for this version. 219*4254beceSMichael Tritz auto activationPtr = std::make_unique<Activation>( 220ba239881SSaqib Khan bus, 221ba239881SSaqib Khan path, 2224c1aec09SSaqib Khan *this, 223ba239881SSaqib Khan id, 224*4254beceSMichael Tritz activationState, 225*4254beceSMichael Tritz associations); 226*4254beceSMichael Tritz 227*4254beceSMichael Tritz // Add Delete() if this isn't the functional version 228*4254beceSMichael Tritz if (!isVersionFunctional) 229*4254beceSMichael Tritz { 230*4254beceSMichael Tritz activationPtr->deleteObject = 231*4254beceSMichael Tritz std::make_unique<Delete>(bus, path, *activationPtr); 232*4254beceSMichael Tritz } 233*4254beceSMichael Tritz 234*4254beceSMichael Tritz activations.insert(std::make_pair(id, std::move(activationPtr))); 2351eef62deSSaqib Khan 2361eef62deSSaqib Khan // If Active, create RedundancyPriority instance for this version. 2371eef62deSSaqib Khan if (activationState == server::Activation::Activations::Active) 2381eef62deSSaqib Khan { 2391eef62deSSaqib Khan uint8_t priority = std::numeric_limits<uint8_t>::max(); 2401eef62deSSaqib Khan if (!restoreFromFile(id, priority)) 2411eef62deSSaqib Khan { 242ee590c74SAdriana Kobylak if (isVersionFunctional) 243ee590c74SAdriana Kobylak { 244ee590c74SAdriana Kobylak priority = 0; 245ee590c74SAdriana Kobylak } 246ee590c74SAdriana Kobylak else 247ee590c74SAdriana Kobylak { 2481eef62deSSaqib Khan log<level::ERR>("Unable to restore priority from file.", 2491eef62deSSaqib Khan entry("VERSIONID=%s", id)); 2501eef62deSSaqib Khan } 251ee590c74SAdriana Kobylak } 2521eef62deSSaqib Khan activations.find(id)->second->redundancyPriority = 2531eef62deSSaqib Khan std::make_unique<RedundancyPriority>( 2541eef62deSSaqib Khan bus, 2551eef62deSSaqib Khan path, 2561eef62deSSaqib Khan *(activations.find(id)->second), 2571eef62deSSaqib Khan priority); 2581eef62deSSaqib Khan } 2591eef62deSSaqib Khan } 2601eef62deSSaqib Khan } 261dcbfa04aSSaqib Khan 262dcbfa04aSSaqib Khan // If there is no ubi volume for bmc version then read the /etc/os-release 263dcbfa04aSSaqib Khan // and create rofs-<versionId> under /media 264dcbfa04aSSaqib Khan if (activations.size() == 0) 265dcbfa04aSSaqib Khan { 266d16bcbd5SGunnar Mills auto version = VersionClass::getBMCVersion(OS_RELEASE_FILE); 267dcbfa04aSSaqib Khan auto id = phosphor::software::manager::Version::getId(version); 268dcbfa04aSSaqib Khan auto versionFileDir = BMC_ROFS_PREFIX + id + "/etc/"; 269dcbfa04aSSaqib Khan try 270dcbfa04aSSaqib Khan { 271dcbfa04aSSaqib Khan if (!fs::is_directory(versionFileDir)) 272dcbfa04aSSaqib Khan { 273dcbfa04aSSaqib Khan fs::create_directories(versionFileDir); 274dcbfa04aSSaqib Khan } 275dcbfa04aSSaqib Khan auto versionFilePath = BMC_ROFS_PREFIX + id + OS_RELEASE_FILE; 276dcbfa04aSSaqib Khan fs::create_directory_symlink(OS_RELEASE_FILE, versionFilePath); 277dcbfa04aSSaqib Khan ItemUpdater::processBMCImage(); 278dcbfa04aSSaqib Khan } 279dcbfa04aSSaqib Khan catch (const std::exception& e) 280dcbfa04aSSaqib Khan { 281dcbfa04aSSaqib Khan log<level::ERR>(e.what()); 282dcbfa04aSSaqib Khan } 283dcbfa04aSSaqib Khan } 284ba239881SSaqib Khan return; 285ba239881SSaqib Khan } 286ba239881SSaqib Khan 2873526ef73SLeonel Gonzalez void ItemUpdater::erase(std::string entryId) 2883526ef73SLeonel Gonzalez { 2896d873715SEddie James // Find entry in versions map 2906d873715SEddie James auto it = versions.find(entryId); 2916d873715SEddie James if (it != versions.end()) 2926d873715SEddie James { 2936d873715SEddie James if (it->second->isFunctional()) 2946d873715SEddie James { 2956d873715SEddie James log<level::ERR>(("Error: Version " + entryId + \ 2966d873715SEddie James " is currently running on the BMC." \ 2976d873715SEddie James " Unable to remove.").c_str()); 2986d873715SEddie James return; 2996d873715SEddie James } 3006d873715SEddie James 3016d873715SEddie James // Delete ReadOnly partitions if it's not active 3023526ef73SLeonel Gonzalez removeReadOnlyPartition(entryId); 3031eef62deSSaqib Khan removeFile(entryId); 3046d873715SEddie James } 3056d873715SEddie James else 3066d873715SEddie James { 3076d873715SEddie James // Delete ReadOnly partitions even if we can't find the version 3086d873715SEddie James removeReadOnlyPartition(entryId); 3096d873715SEddie James removeFile(entryId); 3106d873715SEddie James 3116d873715SEddie James log<level::ERR>(("Error: Failed to find version " + entryId + \ 3126d873715SEddie James " in item updater versions map." \ 3136d873715SEddie James " Unable to remove.").c_str()); 3146d873715SEddie James return; 3156d873715SEddie James } 3161eef62deSSaqib Khan 3171eef62deSSaqib Khan // Remove the priority environment variable. 3181eef62deSSaqib Khan auto serviceFile = "obmc-flash-bmc-setenv@" + entryId + ".service"; 3191eef62deSSaqib Khan auto method = bus.new_method_call( 3201eef62deSSaqib Khan SYSTEMD_BUSNAME, 3211eef62deSSaqib Khan SYSTEMD_PATH, 3221eef62deSSaqib Khan SYSTEMD_INTERFACE, 3231eef62deSSaqib Khan "StartUnit"); 3241eef62deSSaqib Khan method.append(serviceFile, "replace"); 3251eef62deSSaqib Khan bus.call_noreply(method); 3263526ef73SLeonel Gonzalez 3273526ef73SLeonel Gonzalez // Removing entry in versions map 3283526ef73SLeonel Gonzalez this->versions.erase(entryId); 3293526ef73SLeonel Gonzalez 3303526ef73SLeonel Gonzalez // Removing entry in activations map 3313526ef73SLeonel Gonzalez auto ita = activations.find(entryId); 3323526ef73SLeonel Gonzalez if (ita == activations.end()) 3333526ef73SLeonel Gonzalez { 3343526ef73SLeonel Gonzalez log<level::ERR>(("Error: Failed to find version " + entryId + \ 3353526ef73SLeonel Gonzalez " in item updater activations map." \ 3363526ef73SLeonel Gonzalez " Unable to remove.").c_str()); 3373526ef73SLeonel Gonzalez return; 3383526ef73SLeonel Gonzalez } 3393526ef73SLeonel Gonzalez 3403526ef73SLeonel Gonzalez this->activations.erase(entryId); 34149446ae9SSaqib Khan ItemUpdater::resetUbootEnvVars(); 3423526ef73SLeonel Gonzalez } 3433526ef73SLeonel Gonzalez 344bc1bf3afSMichael Tritz void ItemUpdater::deleteAll() 345bc1bf3afSMichael Tritz { 346bc1bf3afSMichael Tritz std::vector<std::string> deletableVersions; 347bc1bf3afSMichael Tritz 348bc1bf3afSMichael Tritz for (const auto& versionIt : versions) 349bc1bf3afSMichael Tritz { 350bc1bf3afSMichael Tritz if (!versionIt.second->isFunctional()) 351bc1bf3afSMichael Tritz { 352bc1bf3afSMichael Tritz deletableVersions.push_back(versionIt.first); 353bc1bf3afSMichael Tritz } 354bc1bf3afSMichael Tritz } 355bc1bf3afSMichael Tritz 356bc1bf3afSMichael Tritz for (const auto& deletableIt : deletableVersions) 357bc1bf3afSMichael Tritz { 358bc1bf3afSMichael Tritz ItemUpdater::erase(deletableIt); 359bc1bf3afSMichael Tritz } 360bc1bf3afSMichael Tritz 361bc1bf3afSMichael Tritz // Remove any volumes that do not match current versions. 362bc1bf3afSMichael Tritz auto method = bus.new_method_call( 363bc1bf3afSMichael Tritz SYSTEMD_BUSNAME, 364bc1bf3afSMichael Tritz SYSTEMD_PATH, 365bc1bf3afSMichael Tritz SYSTEMD_INTERFACE, 366bc1bf3afSMichael Tritz "StartUnit"); 367bc1bf3afSMichael Tritz method.append("obmc-flash-bmc-cleanup.service", "replace"); 368bc1bf3afSMichael Tritz bus.call_noreply(method); 369bc1bf3afSMichael Tritz } 370bc1bf3afSMichael Tritz 37135e83f3eSSaqib Khan ItemUpdater::ActivationStatus ItemUpdater::validateSquashFSImage( 37219177d3eSSaqib Khan const std::string& filePath) 37335e83f3eSSaqib Khan { 374b1cfdf99SMichael Tritz bool invalid = false; 37535e83f3eSSaqib Khan 376b1cfdf99SMichael Tritz for (auto& bmcImage : bmcImages) 377b1cfdf99SMichael Tritz { 37819177d3eSSaqib Khan fs::path file(filePath); 37935e83f3eSSaqib Khan file /= bmcImage; 38035e83f3eSSaqib Khan std::ifstream efile(file.c_str()); 381b1cfdf99SMichael Tritz if (efile.good() != 1) 38235e83f3eSSaqib Khan { 383b1cfdf99SMichael Tritz log<level::ERR>("Failed to find the BMC image.", 384b1cfdf99SMichael Tritz entry("IMAGE=%s", bmcImage.c_str())); 385b1cfdf99SMichael Tritz invalid = true; 38635e83f3eSSaqib Khan } 387b1cfdf99SMichael Tritz } 388b1cfdf99SMichael Tritz 389b1cfdf99SMichael Tritz if (invalid) 39035e83f3eSSaqib Khan { 39135e83f3eSSaqib Khan return ItemUpdater::ActivationStatus::invalid; 39235e83f3eSSaqib Khan } 393b1cfdf99SMichael Tritz 394b1cfdf99SMichael Tritz return ItemUpdater::ActivationStatus::ready; 39535e83f3eSSaqib Khan } 39635e83f3eSSaqib Khan 397b9da6634SSaqib Khan void ItemUpdater::freePriority(uint8_t value, const std::string& versionId) 3984c1aec09SSaqib Khan { 3994c1aec09SSaqib Khan //TODO openbmc/openbmc#1896 Improve the performance of this function 4004c1aec09SSaqib Khan for (const auto& intf : activations) 4014c1aec09SSaqib Khan { 4024c1aec09SSaqib Khan if (intf.second->redundancyPriority) 4034c1aec09SSaqib Khan { 404b9da6634SSaqib Khan if (intf.second->redundancyPriority.get()->priority() == value && 405b9da6634SSaqib Khan intf.second->versionId != versionId) 4064c1aec09SSaqib Khan { 4074c1aec09SSaqib Khan intf.second->redundancyPriority.get()->priority(value + 1); 4084c1aec09SSaqib Khan } 4094c1aec09SSaqib Khan } 4104c1aec09SSaqib Khan } 4114c1aec09SSaqib Khan } 4124c1aec09SSaqib Khan 41337a59043SMichael Tritz void ItemUpdater::reset() 41437a59043SMichael Tritz { 41537a59043SMichael Tritz // Mark the read-write partition for recreation upon reboot. 41637a59043SMichael Tritz auto method = bus.new_method_call( 41737a59043SMichael Tritz SYSTEMD_BUSNAME, 41837a59043SMichael Tritz SYSTEMD_PATH, 41937a59043SMichael Tritz SYSTEMD_INTERFACE, 42037a59043SMichael Tritz "StartUnit"); 4210129d926SMichael Tritz method.append("obmc-flash-bmc-setenv@rwreset\\x3dtrue.service", "replace"); 42237a59043SMichael Tritz bus.call_noreply(method); 42337a59043SMichael Tritz 42437a59043SMichael Tritz log<level::INFO>("BMC factory reset will take effect upon reboot."); 42537a59043SMichael Tritz 42637a59043SMichael Tritz return; 42737a59043SMichael Tritz } 42837a59043SMichael Tritz 4293526ef73SLeonel Gonzalez void ItemUpdater::removeReadOnlyPartition(std::string versionId) 4303526ef73SLeonel Gonzalez { 4313526ef73SLeonel Gonzalez auto serviceFile = "obmc-flash-bmc-ubiro-remove@" + versionId + 4323526ef73SLeonel Gonzalez ".service"; 4333526ef73SLeonel Gonzalez 4343526ef73SLeonel Gonzalez // Remove the read-only partitions. 4353526ef73SLeonel Gonzalez auto method = bus.new_method_call( 4363526ef73SLeonel Gonzalez SYSTEMD_BUSNAME, 4373526ef73SLeonel Gonzalez SYSTEMD_PATH, 4383526ef73SLeonel Gonzalez SYSTEMD_INTERFACE, 4393526ef73SLeonel Gonzalez "StartUnit"); 4403526ef73SLeonel Gonzalez method.append(serviceFile, "replace"); 4413526ef73SLeonel Gonzalez bus.call_noreply(method); 4423526ef73SLeonel Gonzalez } 4433526ef73SLeonel Gonzalez 4440129d926SMichael Tritz bool ItemUpdater::fieldModeEnabled(bool value) 4450129d926SMichael Tritz { 4460129d926SMichael Tritz // enabling field mode is intended to be one way: false -> true 4470129d926SMichael Tritz if (value && !control::FieldMode::fieldModeEnabled()) 4480129d926SMichael Tritz { 4490129d926SMichael Tritz control::FieldMode::fieldModeEnabled(value); 4500129d926SMichael Tritz 4510129d926SMichael Tritz auto method = bus.new_method_call( 4520129d926SMichael Tritz SYSTEMD_BUSNAME, 4530129d926SMichael Tritz SYSTEMD_PATH, 4540129d926SMichael Tritz SYSTEMD_INTERFACE, 4550129d926SMichael Tritz "StartUnit"); 4560129d926SMichael Tritz method.append("obmc-flash-bmc-setenv@fieldmode\\x3dtrue.service", 4570129d926SMichael Tritz "replace"); 4580129d926SMichael Tritz bus.call_noreply(method); 4590129d926SMichael Tritz 4600129d926SMichael Tritz method = bus.new_method_call( 4610129d926SMichael Tritz SYSTEMD_BUSNAME, 4620129d926SMichael Tritz SYSTEMD_PATH, 4630129d926SMichael Tritz SYSTEMD_INTERFACE, 4640129d926SMichael Tritz "StopUnit"); 4650129d926SMichael Tritz method.append("usr-local.mount", "replace"); 4660129d926SMichael Tritz bus.call_noreply(method); 4670129d926SMichael Tritz 4680129d926SMichael Tritz std::vector<std::string> usrLocal = {"usr-local.mount"}; 4690129d926SMichael Tritz 4700129d926SMichael Tritz method = bus.new_method_call( 4710129d926SMichael Tritz SYSTEMD_BUSNAME, 4720129d926SMichael Tritz SYSTEMD_PATH, 4730129d926SMichael Tritz SYSTEMD_INTERFACE, 4740129d926SMichael Tritz "MaskUnitFiles"); 4750129d926SMichael Tritz method.append(usrLocal, false, true); 4760129d926SMichael Tritz bus.call_noreply(method); 4770129d926SMichael Tritz } 4780129d926SMichael Tritz 4790129d926SMichael Tritz return control::FieldMode::fieldModeEnabled(); 4800129d926SMichael Tritz } 4810129d926SMichael Tritz 4820129d926SMichael Tritz void ItemUpdater::restoreFieldModeStatus() 4830129d926SMichael Tritz { 484ff0b421dSMichael Tritz std::ifstream input("/dev/mtd/u-boot-env"); 4850129d926SMichael Tritz std::string envVar; 4860129d926SMichael Tritz std::getline(input, envVar); 4870129d926SMichael Tritz 4880129d926SMichael Tritz if (envVar.find("fieldmode=true") != std::string::npos) 4890129d926SMichael Tritz { 4900129d926SMichael Tritz ItemUpdater::fieldModeEnabled(true); 4910129d926SMichael Tritz } 4920129d926SMichael Tritz } 4930129d926SMichael Tritz 494b60add1eSGunnar Mills void ItemUpdater::setBMCInventoryPath() 495b60add1eSGunnar Mills { 496b60add1eSGunnar Mills //TODO: openbmc/openbmc#1786 - Get the BMC path by looking for objects 497b60add1eSGunnar Mills // that implement the BMC inventory interface 498b60add1eSGunnar Mills auto depth = 0; 499b60add1eSGunnar Mills auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, 500b60add1eSGunnar Mills MAPPER_PATH, 501b60add1eSGunnar Mills MAPPER_INTERFACE, 502b60add1eSGunnar Mills "GetSubTreePaths"); 503b60add1eSGunnar Mills 504b60add1eSGunnar Mills mapperCall.append(CHASSIS_INVENTORY_PATH); 505b60add1eSGunnar Mills mapperCall.append(depth); 506b60add1eSGunnar Mills 507b60add1eSGunnar Mills // TODO: openbmc/openbmc#2226 - Add Inventory Item filter when 508b60add1eSGunnar Mills // mapper is fixed. 509b60add1eSGunnar Mills std::vector<std::string> filter = {}; 510b60add1eSGunnar Mills mapperCall.append(filter); 511b60add1eSGunnar Mills 512b60add1eSGunnar Mills auto response = bus.call(mapperCall); 513b60add1eSGunnar Mills if (response.is_method_error()) 514b60add1eSGunnar Mills { 515b60add1eSGunnar Mills log<level::ERR>("Error in mapper GetSubTreePath"); 516b60add1eSGunnar Mills return; 517b60add1eSGunnar Mills } 518b60add1eSGunnar Mills 519b60add1eSGunnar Mills using ObjectPaths = std::vector<std::string>; 520b60add1eSGunnar Mills ObjectPaths result; 521b60add1eSGunnar Mills response.read(result); 522b60add1eSGunnar Mills 523b60add1eSGunnar Mills if (result.empty()) 524b60add1eSGunnar Mills { 525b60add1eSGunnar Mills log<level::ERR>("Invalid response from mapper"); 526b60add1eSGunnar Mills return; 527b60add1eSGunnar Mills } 528b60add1eSGunnar Mills 529b60add1eSGunnar Mills for (auto& iter : result) 530b60add1eSGunnar Mills { 531b60add1eSGunnar Mills const auto& path = iter; 532b60add1eSGunnar Mills if (path.substr(path.find_last_of('/') + 1).compare("bmc") == 0) 533b60add1eSGunnar Mills { 534b60add1eSGunnar Mills bmcInventoryPath = path; 535b60add1eSGunnar Mills return; 536b60add1eSGunnar Mills } 537b60add1eSGunnar Mills } 538b60add1eSGunnar Mills } 539b60add1eSGunnar Mills 540f10b2326SGunnar Mills void ItemUpdater::createActiveAssociation(const std::string& path) 541ded875dcSGunnar Mills { 542ded875dcSGunnar Mills assocs.emplace_back(std::make_tuple(ACTIVE_FWD_ASSOCIATION, 543ded875dcSGunnar Mills ACTIVE_REV_ASSOCIATION, 544ded875dcSGunnar Mills path)); 545ded875dcSGunnar Mills associations(assocs); 546ded875dcSGunnar Mills } 547ded875dcSGunnar Mills 54888e8a325SGunnar Mills void ItemUpdater::createFunctionalAssociation(const std::string& path) 54988e8a325SGunnar Mills { 55088e8a325SGunnar Mills assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION, 55188e8a325SGunnar Mills FUNCTIONAL_REV_ASSOCIATION, 55288e8a325SGunnar Mills path)); 55388e8a325SGunnar Mills associations(assocs); 55488e8a325SGunnar Mills } 55588e8a325SGunnar Mills 556f10b2326SGunnar Mills void ItemUpdater::removeActiveAssociation(const std::string& path) 557ded875dcSGunnar Mills { 558ded875dcSGunnar Mills for (auto iter = assocs.begin(); iter != assocs.end();) 559ded875dcSGunnar Mills { 56088e8a325SGunnar Mills // Since there could be multiple associations to the same path, 56188e8a325SGunnar Mills // only remove ones that have an active forward association. 56288e8a325SGunnar Mills if ((std::get<0>(*iter)).compare(ACTIVE_FWD_ASSOCIATION) == 0 && 56388e8a325SGunnar Mills (std::get<2>(*iter)).compare(path) == 0) 564ded875dcSGunnar Mills { 565ded875dcSGunnar Mills iter = assocs.erase(iter); 566ded875dcSGunnar Mills associations(assocs); 567ded875dcSGunnar Mills } 568ded875dcSGunnar Mills else 569ded875dcSGunnar Mills { 570ded875dcSGunnar Mills ++iter; 571ded875dcSGunnar Mills } 572ded875dcSGunnar Mills } 573ded875dcSGunnar Mills } 574ded875dcSGunnar Mills 575b9da6634SSaqib Khan bool ItemUpdater::isLowestPriority(uint8_t value) 576b9da6634SSaqib Khan { 577b9da6634SSaqib Khan for (const auto& intf : activations) 578b9da6634SSaqib Khan { 579b9da6634SSaqib Khan if (intf.second->redundancyPriority) 580b9da6634SSaqib Khan { 581b9da6634SSaqib Khan if (intf.second->redundancyPriority.get()->priority() < value) 582b9da6634SSaqib Khan { 583b9da6634SSaqib Khan return false; 584b9da6634SSaqib Khan } 585b9da6634SSaqib Khan } 586b9da6634SSaqib Khan } 587b9da6634SSaqib Khan return true; 588b9da6634SSaqib Khan } 589b9da6634SSaqib Khan 59049446ae9SSaqib Khan void ItemUpdater::resetUbootEnvVars() 59149446ae9SSaqib Khan { 59249446ae9SSaqib Khan decltype(activations.begin()->second->redundancyPriority.get()->priority()) 59349446ae9SSaqib Khan lowestPriority = std::numeric_limits<uint8_t>::max(); 59449446ae9SSaqib Khan decltype(activations.begin()->second->versionId) lowestPriorityVersion; 59549446ae9SSaqib Khan for (const auto& intf : activations) 59649446ae9SSaqib Khan { 59749446ae9SSaqib Khan if (!intf.second->redundancyPriority.get()) 59849446ae9SSaqib Khan { 59949446ae9SSaqib Khan // Skip this version if the redundancyPriority is not initialized. 60049446ae9SSaqib Khan continue; 60149446ae9SSaqib Khan } 60249446ae9SSaqib Khan 60349446ae9SSaqib Khan if (intf.second->redundancyPriority.get()->priority() 60449446ae9SSaqib Khan <= lowestPriority) 60549446ae9SSaqib Khan { 60649446ae9SSaqib Khan lowestPriority = intf.second->redundancyPriority.get()->priority(); 60749446ae9SSaqib Khan lowestPriorityVersion = intf.second->versionId; 60849446ae9SSaqib Khan } 60949446ae9SSaqib Khan } 61049446ae9SSaqib Khan 611f0382c35SSaqib Khan // Update the U-boot environment variable to point to the lowest priority 612f0382c35SSaqib Khan auto it = activations.find(lowestPriorityVersion); 613f0382c35SSaqib Khan it->second->updateUbootEnvVars(); 61449446ae9SSaqib Khan } 61549446ae9SSaqib Khan 616ec1b41c4SGunnar Mills } // namespace updater 617ec1b41c4SGunnar Mills } // namespace software 618ec1b41c4SGunnar Mills } // namespace phosphor 619