135e83f3eSSaqib Khan #include <fstream> 2204e1e74SAdriana Kobylak #include <queue> 3b77551cdSAdriana Kobylak #include <set> 4ec1b41c4SGunnar Mills #include <string> 52ce7da29SGunnar Mills #include <phosphor-logging/log.hpp> 6dcbfa04aSSaqib Khan #include <phosphor-logging/elog.hpp> 7dcbfa04aSSaqib Khan #include <elog-errors.hpp> 8dcbfa04aSSaqib Khan #include <xyz/openbmc_project/Software/Version/error.hpp> 9ec1b41c4SGunnar Mills #include "config.h" 102ce7da29SGunnar Mills #include "item_updater.hpp" 112ce7da29SGunnar Mills #include "xyz/openbmc_project/Software/Version/server.hpp" 1235e83f3eSSaqib Khan #include <experimental/filesystem> 13705f1bfcSSaqib Khan #include "version.hpp" 145d532675SSaqib Khan #include "serialize.hpp" 151be8d500SLei YU #include "images.hpp" 16ec1b41c4SGunnar Mills 17ec1b41c4SGunnar Mills namespace phosphor 18ec1b41c4SGunnar Mills { 19ec1b41c4SGunnar Mills namespace software 20ec1b41c4SGunnar Mills { 21ec1b41c4SGunnar Mills namespace updater 22ec1b41c4SGunnar Mills { 23ec1b41c4SGunnar Mills 242ce7da29SGunnar Mills // When you see server:: you know we're referencing our base class 252ce7da29SGunnar Mills namespace server = sdbusplus::xyz::openbmc_project::Software::server; 260129d926SMichael Tritz namespace control = sdbusplus::xyz::openbmc_project::Control::server; 272ce7da29SGunnar Mills 282ce7da29SGunnar Mills using namespace phosphor::logging; 29dcbfa04aSSaqib Khan using namespace sdbusplus::xyz::openbmc_project::Software::Version::Error; 302ab9b109SJayanth Othayoth using namespace phosphor::software::image; 3135e83f3eSSaqib Khan namespace fs = std::experimental::filesystem; 3235e83f3eSSaqib Khan 33e75d10f5SPatrick Williams void ItemUpdater::createActivation(sdbusplus::message::message& msg) 34ec1b41c4SGunnar Mills { 3584a0e693SSaqib Khan 3684a0e693SSaqib Khan using SVersion = server::Version; 3784a0e693SSaqib Khan using VersionPurpose = SVersion::VersionPurpose; 389a782243SGunnar Mills using VersionClass = phosphor::software::manager::Version; 3984a0e693SSaqib Khan namespace mesg = sdbusplus::message; 4084a0e693SSaqib Khan namespace variant_ns = mesg::variant_ns; 4184a0e693SSaqib Khan 4284a0e693SSaqib Khan mesg::object_path objPath; 4384a0e693SSaqib Khan auto purpose = VersionPurpose::Unknown; 44705f1bfcSSaqib Khan std::string version; 452285fe0fSAdriana Kobylak std::map<std::string, std::map<std::string, mesg::variant<std::string>>> 462285fe0fSAdriana Kobylak interfaces; 47e75d10f5SPatrick Williams msg.read(objPath, interfaces); 482ce7da29SGunnar Mills std::string path(std::move(objPath)); 4919177d3eSSaqib Khan std::string filePath; 502ce7da29SGunnar Mills 512ce7da29SGunnar Mills for (const auto& intf : interfaces) 522ce7da29SGunnar Mills { 53705f1bfcSSaqib Khan if (intf.first == VERSION_IFACE) 542ce7da29SGunnar Mills { 552ce7da29SGunnar Mills for (const auto& property : intf.second) 562ce7da29SGunnar Mills { 57705f1bfcSSaqib Khan if (property.first == "Purpose") 582ce7da29SGunnar Mills { 5984a0e693SSaqib Khan auto value = SVersion::convertVersionPurposeFromString( 6084a0e693SSaqib Khan variant_ns::get<std::string>(property.second)); 6184a0e693SSaqib Khan if (value == VersionPurpose::BMC || 6284a0e693SSaqib Khan value == VersionPurpose::System) 6384a0e693SSaqib Khan { 6484a0e693SSaqib Khan purpose = value; 6584a0e693SSaqib Khan } 66705f1bfcSSaqib Khan } 67705f1bfcSSaqib Khan else if (property.first == "Version") 68705f1bfcSSaqib Khan { 6984a0e693SSaqib Khan version = variant_ns::get<std::string>(property.second); 70705f1bfcSSaqib Khan } 71705f1bfcSSaqib Khan } 72705f1bfcSSaqib Khan } 7319177d3eSSaqib Khan else if (intf.first == FILEPATH_IFACE) 7419177d3eSSaqib Khan { 7519177d3eSSaqib Khan for (const auto& property : intf.second) 7619177d3eSSaqib Khan { 7719177d3eSSaqib Khan if (property.first == "Path") 7819177d3eSSaqib Khan { 7984a0e693SSaqib Khan filePath = variant_ns::get<std::string>(property.second); 8019177d3eSSaqib Khan } 8119177d3eSSaqib Khan } 8219177d3eSSaqib Khan } 83705f1bfcSSaqib Khan } 842285fe0fSAdriana Kobylak if (version.empty() || filePath.empty() || 8584a0e693SSaqib Khan purpose == VersionPurpose::Unknown) 862ce7da29SGunnar Mills { 87e75d10f5SPatrick Williams return; 882ce7da29SGunnar Mills } 892ce7da29SGunnar Mills 902ce7da29SGunnar Mills // Version id is the last item in the path 912ce7da29SGunnar Mills auto pos = path.rfind("/"); 922ce7da29SGunnar Mills if (pos == std::string::npos) 932ce7da29SGunnar Mills { 942ce7da29SGunnar Mills log<level::ERR>("No version id found in object path", 95596466b8SAdriana Kobylak entry("OBJPATH=%s", path.c_str())); 96e75d10f5SPatrick Williams return; 972ce7da29SGunnar Mills } 982ce7da29SGunnar Mills 992ce7da29SGunnar Mills auto versionId = path.substr(pos + 1); 1002ce7da29SGunnar Mills 101e75d10f5SPatrick Williams if (activations.find(versionId) == activations.end()) 1022ce7da29SGunnar Mills { 10335e83f3eSSaqib Khan // Determine the Activation state by processing the given image dir. 10435e83f3eSSaqib Khan auto activationState = server::Activation::Activations::Invalid; 1059a782243SGunnar Mills ItemUpdater::ActivationStatus result = 1069a782243SGunnar Mills ItemUpdater::validateSquashFSImage(filePath); 10743b25cdeSGunnar Mills AssociationList associations = {}; 10843b25cdeSGunnar Mills 10935e83f3eSSaqib Khan if (result == ItemUpdater::ActivationStatus::ready) 11035e83f3eSSaqib Khan { 11135e83f3eSSaqib Khan activationState = server::Activation::Activations::Ready; 112b60add1eSGunnar Mills // Create an association to the BMC inventory item 1132285fe0fSAdriana Kobylak associations.emplace_back( 1142285fe0fSAdriana Kobylak std::make_tuple(ACTIVATION_FWD_ASSOCIATION, 1152285fe0fSAdriana Kobylak ACTIVATION_REV_ASSOCIATION, bmcInventoryPath)); 11643b25cdeSGunnar Mills } 117b60add1eSGunnar Mills 118ee13e831SSaqib Khan activations.insert(std::make_pair( 119ee13e831SSaqib Khan versionId, 1202285fe0fSAdriana Kobylak std::make_unique<Activation>(bus, path, *this, versionId, 1212285fe0fSAdriana Kobylak activationState, associations))); 1224254beceSMichael Tritz 123ee13e831SSaqib Khan auto versionPtr = std::make_unique<VersionClass>( 1242285fe0fSAdriana Kobylak bus, path, version, purpose, filePath, 1252285fe0fSAdriana Kobylak std::bind(&ItemUpdater::erase, this, std::placeholders::_1)); 126ee13e831SSaqib Khan versionPtr->deleteObject = 1272285fe0fSAdriana Kobylak std::make_unique<phosphor::software::manager::Delete>(bus, path, 1282285fe0fSAdriana Kobylak *versionPtr); 129ee13e831SSaqib Khan versions.insert(std::make_pair(versionId, std::move(versionPtr))); 1302ce7da29SGunnar Mills } 131e75d10f5SPatrick Williams return; 132ec1b41c4SGunnar Mills } 133ec1b41c4SGunnar Mills 134ba239881SSaqib Khan void ItemUpdater::processBMCImage() 135ba239881SSaqib Khan { 13688e8a325SGunnar Mills using VersionClass = phosphor::software::manager::Version; 137*269bff30SLei YU 138*269bff30SLei YU // Check MEDIA_DIR and create if it does not exist 139*269bff30SLei YU try 140*269bff30SLei YU { 141*269bff30SLei YU if (!fs::is_directory(MEDIA_DIR)) 142*269bff30SLei YU { 143*269bff30SLei YU fs::create_directory(MEDIA_DIR); 144*269bff30SLei YU } 145*269bff30SLei YU } 146*269bff30SLei YU catch (const fs::filesystem_error& e) 147*269bff30SLei YU { 148*269bff30SLei YU log<level::ERR>("Failed to prepare dir", entry("ERR=%s", e.what())); 149*269bff30SLei YU return; 150*269bff30SLei YU } 151*269bff30SLei YU 15288e8a325SGunnar Mills // Read os-release from /etc/ to get the functional BMC version 15388e8a325SGunnar Mills auto functionalVersion = VersionClass::getBMCVersion(OS_RELEASE_FILE); 15488e8a325SGunnar Mills 1551eef62deSSaqib Khan // Read os-release from folders under /media/ to get 1561eef62deSSaqib Khan // BMC Software Versions. 1571eef62deSSaqib Khan for (const auto& iter : fs::directory_iterator(MEDIA_DIR)) 1581eef62deSSaqib Khan { 1591eef62deSSaqib Khan auto activationState = server::Activation::Activations::Active; 1606fab70daSSaqib Khan static const auto BMC_RO_PREFIX_LEN = strlen(BMC_ROFS_PREFIX); 1611eef62deSSaqib Khan 1621eef62deSSaqib Khan // Check if the BMC_RO_PREFIXis the prefix of the iter.path 1632285fe0fSAdriana Kobylak if (0 == 1642285fe0fSAdriana Kobylak iter.path().native().compare(0, BMC_RO_PREFIX_LEN, BMC_ROFS_PREFIX)) 1651eef62deSSaqib Khan { 166021c365bSSaqib Khan // The versionId is extracted from the path 167021c365bSSaqib Khan // for example /media/ro-2a1022fe. 168021c365bSSaqib Khan auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN); 1691eef62deSSaqib Khan auto osRelease = iter.path() / OS_RELEASE_FILE; 1701eef62deSSaqib Khan if (!fs::is_regular_file(osRelease)) 1711eef62deSSaqib Khan { 1722285fe0fSAdriana Kobylak log<level::ERR>( 1732285fe0fSAdriana Kobylak "Failed to read osRelease", 174596466b8SAdriana Kobylak entry("FILENAME=%s", osRelease.string().c_str())); 175021c365bSSaqib Khan ItemUpdater::erase(id); 176021c365bSSaqib Khan continue; 1771eef62deSSaqib Khan } 17888e8a325SGunnar Mills auto version = VersionClass::getBMCVersion(osRelease); 1791eef62deSSaqib Khan if (version.empty()) 1801eef62deSSaqib Khan { 1812285fe0fSAdriana Kobylak log<level::ERR>( 1822285fe0fSAdriana Kobylak "Failed to read version from osRelease", 183596466b8SAdriana Kobylak entry("FILENAME=%s", osRelease.string().c_str())); 1841eef62deSSaqib Khan activationState = server::Activation::Activations::Invalid; 1851eef62deSSaqib Khan } 186021c365bSSaqib Khan 1871eef62deSSaqib Khan auto purpose = server::Version::VersionPurpose::BMC; 1881eef62deSSaqib Khan auto path = fs::path(SOFTWARE_OBJPATH) / id; 1891eef62deSSaqib Khan 190*269bff30SLei YU // Create functional association if this is the functional 191*269bff30SLei YU // version 19288e8a325SGunnar Mills if (version.compare(functionalVersion) == 0) 19388e8a325SGunnar Mills { 19488e8a325SGunnar Mills createFunctionalAssociation(path); 19588e8a325SGunnar Mills } 19688e8a325SGunnar Mills 19743b25cdeSGunnar Mills AssociationList associations = {}; 19843b25cdeSGunnar Mills 19943b25cdeSGunnar Mills if (activationState == server::Activation::Activations::Active) 20043b25cdeSGunnar Mills { 20143b25cdeSGunnar Mills // Create an association to the BMC inventory item 20243b25cdeSGunnar Mills associations.emplace_back(std::make_tuple( 2032285fe0fSAdriana Kobylak ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION, 20443b25cdeSGunnar Mills bmcInventoryPath)); 20543b25cdeSGunnar Mills 20643b25cdeSGunnar Mills // Create an active association since this image is active 20743b25cdeSGunnar Mills createActiveAssociation(path); 20843b25cdeSGunnar Mills } 20943b25cdeSGunnar Mills 210ee590c74SAdriana Kobylak // Create Version instance for this version. 211ee590c74SAdriana Kobylak auto versionPtr = std::make_unique<VersionClass>( 2122285fe0fSAdriana Kobylak bus, path, version, purpose, "", 2132285fe0fSAdriana Kobylak std::bind(&ItemUpdater::erase, this, std::placeholders::_1)); 214ee590c74SAdriana Kobylak auto isVersionFunctional = versionPtr->isFunctional(); 215ee13e831SSaqib Khan if (!isVersionFunctional) 216ee13e831SSaqib Khan { 217ee13e831SSaqib Khan versionPtr->deleteObject = 218ee13e831SSaqib Khan std::make_unique<phosphor::software::manager::Delete>( 219ee13e831SSaqib Khan bus, path, *versionPtr); 220ee13e831SSaqib Khan } 2212285fe0fSAdriana Kobylak versions.insert(std::make_pair(id, std::move(versionPtr))); 222ee590c74SAdriana Kobylak 2231eef62deSSaqib Khan // Create Activation instance for this version. 224ee13e831SSaqib Khan activations.insert(std::make_pair( 2252285fe0fSAdriana Kobylak id, std::make_unique<Activation>( 2262285fe0fSAdriana Kobylak bus, path, *this, id, activationState, associations))); 2271eef62deSSaqib Khan 228*269bff30SLei YU // If Active, create RedundancyPriority instance for this 229*269bff30SLei YU // version. 2301eef62deSSaqib Khan if (activationState == server::Activation::Activations::Active) 2311eef62deSSaqib Khan { 2321eef62deSSaqib Khan uint8_t priority = std::numeric_limits<uint8_t>::max(); 2331eef62deSSaqib Khan if (!restoreFromFile(id, priority)) 2341eef62deSSaqib Khan { 235ee590c74SAdriana Kobylak if (isVersionFunctional) 236ee590c74SAdriana Kobylak { 237ee590c74SAdriana Kobylak priority = 0; 238ee590c74SAdriana Kobylak } 239ee590c74SAdriana Kobylak else 240ee590c74SAdriana Kobylak { 2411eef62deSSaqib Khan log<level::ERR>("Unable to restore priority from file.", 242596466b8SAdriana Kobylak entry("VERSIONID=%s", id.c_str())); 2431eef62deSSaqib Khan } 244ee590c74SAdriana Kobylak } 2451eef62deSSaqib Khan activations.find(id)->second->redundancyPriority = 2461eef62deSSaqib Khan std::make_unique<RedundancyPriority>( 2472285fe0fSAdriana Kobylak bus, path, *(activations.find(id)->second), priority, 248b77551cdSAdriana Kobylak false); 2491eef62deSSaqib Khan } 2501eef62deSSaqib Khan } 2511eef62deSSaqib Khan } 252dcbfa04aSSaqib Khan 253dcbfa04aSSaqib Khan // If there is no ubi volume for bmc version then read the /etc/os-release 254dcbfa04aSSaqib Khan // and create rofs-<versionId> under /media 255dcbfa04aSSaqib Khan if (activations.size() == 0) 256dcbfa04aSSaqib Khan { 257d16bcbd5SGunnar Mills auto version = VersionClass::getBMCVersion(OS_RELEASE_FILE); 258dcbfa04aSSaqib Khan auto id = phosphor::software::manager::Version::getId(version); 259dcbfa04aSSaqib Khan auto versionFileDir = BMC_ROFS_PREFIX + id + "/etc/"; 260dcbfa04aSSaqib Khan try 261dcbfa04aSSaqib Khan { 262dcbfa04aSSaqib Khan if (!fs::is_directory(versionFileDir)) 263dcbfa04aSSaqib Khan { 264dcbfa04aSSaqib Khan fs::create_directories(versionFileDir); 265dcbfa04aSSaqib Khan } 266dcbfa04aSSaqib Khan auto versionFilePath = BMC_ROFS_PREFIX + id + OS_RELEASE_FILE; 267dcbfa04aSSaqib Khan fs::create_directory_symlink(OS_RELEASE_FILE, versionFilePath); 268dcbfa04aSSaqib Khan ItemUpdater::processBMCImage(); 269dcbfa04aSSaqib Khan } 270dcbfa04aSSaqib Khan catch (const std::exception& e) 271dcbfa04aSSaqib Khan { 272dcbfa04aSSaqib Khan log<level::ERR>(e.what()); 273dcbfa04aSSaqib Khan } 274dcbfa04aSSaqib Khan } 275eaa1ee05SEddie James 276eaa1ee05SEddie James mirrorUbootToAlt(); 277ba239881SSaqib Khan return; 278ba239881SSaqib Khan } 279ba239881SSaqib Khan 2803526ef73SLeonel Gonzalez void ItemUpdater::erase(std::string entryId) 2813526ef73SLeonel Gonzalez { 2826d873715SEddie James // Find entry in versions map 2836d873715SEddie James auto it = versions.find(entryId); 2846d873715SEddie James if (it != versions.end()) 2856d873715SEddie James { 2866d873715SEddie James if (it->second->isFunctional()) 2876d873715SEddie James { 2882285fe0fSAdriana Kobylak log<level::ERR>("Error: Version is currently running on the BMC. " 2892285fe0fSAdriana Kobylak "Unable to remove.", 2902285fe0fSAdriana Kobylak entry("VERSIONID=%s", entryId.c_str())); 2916d873715SEddie James return; 2926d873715SEddie James } 2936d873715SEddie James 2946d873715SEddie James // Delete ReadOnly partitions if it's not active 2953526ef73SLeonel Gonzalez removeReadOnlyPartition(entryId); 2961eef62deSSaqib Khan removeFile(entryId); 297ee13e831SSaqib Khan 298ee13e831SSaqib Khan // Removing entry in versions map 299ee13e831SSaqib Khan this->versions.erase(entryId); 3006d873715SEddie James } 3016d873715SEddie James else 3026d873715SEddie James { 3036d873715SEddie James // Delete ReadOnly partitions even if we can't find the version 3046d873715SEddie James removeReadOnlyPartition(entryId); 3056d873715SEddie James removeFile(entryId); 3066d873715SEddie James 3072285fe0fSAdriana Kobylak log<level::ERR>("Error: Failed to find version in item updater " 3082285fe0fSAdriana Kobylak "versions map. Unable to remove.", 3092285fe0fSAdriana Kobylak entry("VERSIONID=%s", entryId.c_str())); 3106d873715SEddie James } 3111eef62deSSaqib Khan 31256aaf454SLei YU helper.clearEntry(entryId); 3133526ef73SLeonel Gonzalez 3143526ef73SLeonel Gonzalez // Removing entry in activations map 3153526ef73SLeonel Gonzalez auto ita = activations.find(entryId); 3163526ef73SLeonel Gonzalez if (ita == activations.end()) 3173526ef73SLeonel Gonzalez { 3182285fe0fSAdriana Kobylak log<level::ERR>("Error: Failed to find version in item updater " 3192285fe0fSAdriana Kobylak "activations map. Unable to remove.", 3202285fe0fSAdriana Kobylak entry("VERSIONID=%s", entryId.c_str())); 3213526ef73SLeonel Gonzalez } 322ee13e831SSaqib Khan else 323ee13e831SSaqib Khan { 3243526ef73SLeonel Gonzalez this->activations.erase(entryId); 325ee13e831SSaqib Khan } 32649446ae9SSaqib Khan ItemUpdater::resetUbootEnvVars(); 327ee13e831SSaqib Khan return; 3283526ef73SLeonel Gonzalez } 3293526ef73SLeonel Gonzalez 330bc1bf3afSMichael Tritz void ItemUpdater::deleteAll() 331bc1bf3afSMichael Tritz { 33283cd21fbSAdriana Kobylak std::vector<std::string> deletableVersions; 33383cd21fbSAdriana Kobylak 334bc1bf3afSMichael Tritz for (const auto& versionIt : versions) 335bc1bf3afSMichael Tritz { 336bc1bf3afSMichael Tritz if (!versionIt.second->isFunctional()) 337bc1bf3afSMichael Tritz { 33883cd21fbSAdriana Kobylak deletableVersions.push_back(versionIt.first); 339bc1bf3afSMichael Tritz } 340bc1bf3afSMichael Tritz } 341bc1bf3afSMichael Tritz 34283cd21fbSAdriana Kobylak for (const auto& deletableIt : deletableVersions) 34383cd21fbSAdriana Kobylak { 34483cd21fbSAdriana Kobylak ItemUpdater::erase(deletableIt); 34583cd21fbSAdriana Kobylak } 34683cd21fbSAdriana Kobylak 34756aaf454SLei YU helper.cleanup(); 348bc1bf3afSMichael Tritz } 349bc1bf3afSMichael Tritz 3502285fe0fSAdriana Kobylak ItemUpdater::ActivationStatus 3512285fe0fSAdriana Kobylak ItemUpdater::validateSquashFSImage(const std::string& filePath) 35235e83f3eSSaqib Khan { 353b1cfdf99SMichael Tritz bool invalid = false; 35435e83f3eSSaqib Khan 355b1cfdf99SMichael Tritz for (auto& bmcImage : bmcImages) 356b1cfdf99SMichael Tritz { 35719177d3eSSaqib Khan fs::path file(filePath); 35835e83f3eSSaqib Khan file /= bmcImage; 35935e83f3eSSaqib Khan std::ifstream efile(file.c_str()); 360b1cfdf99SMichael Tritz if (efile.good() != 1) 36135e83f3eSSaqib Khan { 362b1cfdf99SMichael Tritz log<level::ERR>("Failed to find the BMC image.", 363b1cfdf99SMichael Tritz entry("IMAGE=%s", bmcImage.c_str())); 364b1cfdf99SMichael Tritz invalid = true; 36535e83f3eSSaqib Khan } 366b1cfdf99SMichael Tritz } 367b1cfdf99SMichael Tritz 368b1cfdf99SMichael Tritz if (invalid) 36935e83f3eSSaqib Khan { 37035e83f3eSSaqib Khan return ItemUpdater::ActivationStatus::invalid; 37135e83f3eSSaqib Khan } 372b1cfdf99SMichael Tritz 373b1cfdf99SMichael Tritz return ItemUpdater::ActivationStatus::ready; 37435e83f3eSSaqib Khan } 37535e83f3eSSaqib Khan 376bbcb7be1SAdriana Kobylak void ItemUpdater::savePriority(const std::string& versionId, uint8_t value) 377bbcb7be1SAdriana Kobylak { 378bbcb7be1SAdriana Kobylak storeToFile(versionId, value); 379bbcb7be1SAdriana Kobylak helper.setEntry(versionId, value); 380bbcb7be1SAdriana Kobylak } 381bbcb7be1SAdriana Kobylak 382b9da6634SSaqib Khan void ItemUpdater::freePriority(uint8_t value, const std::string& versionId) 3834c1aec09SSaqib Khan { 384b77551cdSAdriana Kobylak std::map<std::string, uint8_t> priorityMap; 385b77551cdSAdriana Kobylak 386b77551cdSAdriana Kobylak // Insert the requested version and priority, it may not exist yet. 387b77551cdSAdriana Kobylak priorityMap.insert(std::make_pair(versionId, value)); 388b77551cdSAdriana Kobylak 3894c1aec09SSaqib Khan for (const auto& intf : activations) 3904c1aec09SSaqib Khan { 3914c1aec09SSaqib Khan if (intf.second->redundancyPriority) 3924c1aec09SSaqib Khan { 393b77551cdSAdriana Kobylak priorityMap.insert(std::make_pair( 3942285fe0fSAdriana Kobylak intf.first, intf.second->redundancyPriority.get()->priority())); 395b77551cdSAdriana Kobylak } 396b77551cdSAdriana Kobylak } 397b77551cdSAdriana Kobylak 398b77551cdSAdriana Kobylak // Lambda function to compare 2 priority values, use <= to allow duplicates 3992285fe0fSAdriana Kobylak typedef std::function<bool(std::pair<std::string, uint8_t>, 4002285fe0fSAdriana Kobylak std::pair<std::string, uint8_t>)> 4012285fe0fSAdriana Kobylak cmpPriority; 4022285fe0fSAdriana Kobylak cmpPriority cmpPriorityFunc = 4032285fe0fSAdriana Kobylak [](std::pair<std::string, uint8_t> priority1, 4042285fe0fSAdriana Kobylak std::pair<std::string, uint8_t> priority2) { 405b77551cdSAdriana Kobylak return priority1.second <= priority2.second; 406b77551cdSAdriana Kobylak }; 407b77551cdSAdriana Kobylak 408b77551cdSAdriana Kobylak // Sort versions by ascending priority 409b77551cdSAdriana Kobylak std::set<std::pair<std::string, uint8_t>, cmpPriority> prioritySet( 410b77551cdSAdriana Kobylak priorityMap.begin(), priorityMap.end(), cmpPriorityFunc); 411b77551cdSAdriana Kobylak 412b77551cdSAdriana Kobylak auto freePriorityValue = value; 413b77551cdSAdriana Kobylak for (auto& element : prioritySet) 414b77551cdSAdriana Kobylak { 415b77551cdSAdriana Kobylak if (element.first == versionId) 416b77551cdSAdriana Kobylak { 417b77551cdSAdriana Kobylak continue; 418b77551cdSAdriana Kobylak } 419b77551cdSAdriana Kobylak if (element.second == freePriorityValue) 420b77551cdSAdriana Kobylak { 421b77551cdSAdriana Kobylak ++freePriorityValue; 422b77551cdSAdriana Kobylak auto it = activations.find(element.first); 423b77551cdSAdriana Kobylak it->second->redundancyPriority.get()->sdbusPriority( 424b77551cdSAdriana Kobylak freePriorityValue); 4254c1aec09SSaqib Khan } 4264c1aec09SSaqib Khan } 427b77551cdSAdriana Kobylak 428b77551cdSAdriana Kobylak auto lowestVersion = prioritySet.begin()->first; 429b77551cdSAdriana Kobylak if (value == prioritySet.begin()->second) 430b77551cdSAdriana Kobylak { 431b77551cdSAdriana Kobylak lowestVersion = versionId; 4324c1aec09SSaqib Khan } 433b77551cdSAdriana Kobylak updateUbootEnvVars(lowestVersion); 4344c1aec09SSaqib Khan } 4354c1aec09SSaqib Khan 43637a59043SMichael Tritz void ItemUpdater::reset() 43737a59043SMichael Tritz { 43856aaf454SLei YU helper.factoryReset(); 43937a59043SMichael Tritz 44037a59043SMichael Tritz log<level::INFO>("BMC factory reset will take effect upon reboot."); 44137a59043SMichael Tritz } 44237a59043SMichael Tritz 4433526ef73SLeonel Gonzalez void ItemUpdater::removeReadOnlyPartition(std::string versionId) 4443526ef73SLeonel Gonzalez { 44556aaf454SLei YU helper.removeVersion(versionId); 4463526ef73SLeonel Gonzalez } 4473526ef73SLeonel Gonzalez 4480129d926SMichael Tritz bool ItemUpdater::fieldModeEnabled(bool value) 4490129d926SMichael Tritz { 4500129d926SMichael Tritz // enabling field mode is intended to be one way: false -> true 4510129d926SMichael Tritz if (value && !control::FieldMode::fieldModeEnabled()) 4520129d926SMichael Tritz { 4530129d926SMichael Tritz control::FieldMode::fieldModeEnabled(value); 4540129d926SMichael Tritz 45556aaf454SLei YU helper.enableFieldMode(); 4560129d926SMichael Tritz } 4570129d926SMichael Tritz 4580129d926SMichael Tritz return control::FieldMode::fieldModeEnabled(); 4590129d926SMichael Tritz } 4600129d926SMichael Tritz 4610129d926SMichael Tritz void ItemUpdater::restoreFieldModeStatus() 4620129d926SMichael Tritz { 463ff0b421dSMichael Tritz std::ifstream input("/dev/mtd/u-boot-env"); 4640129d926SMichael Tritz std::string envVar; 4650129d926SMichael Tritz std::getline(input, envVar); 4660129d926SMichael Tritz 4670129d926SMichael Tritz if (envVar.find("fieldmode=true") != std::string::npos) 4680129d926SMichael Tritz { 4690129d926SMichael Tritz ItemUpdater::fieldModeEnabled(true); 4700129d926SMichael Tritz } 4710129d926SMichael Tritz } 4720129d926SMichael Tritz 473b60add1eSGunnar Mills void ItemUpdater::setBMCInventoryPath() 474b60add1eSGunnar Mills { 475b60add1eSGunnar Mills auto depth = 0; 4762285fe0fSAdriana Kobylak auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH, 4772285fe0fSAdriana Kobylak MAPPER_INTERFACE, "GetSubTreePaths"); 478b60add1eSGunnar Mills 4791254c628SAdriana Kobylak mapperCall.append(INVENTORY_PATH); 480b60add1eSGunnar Mills mapperCall.append(depth); 4811254c628SAdriana Kobylak std::vector<std::string> filter = {BMC_INVENTORY_INTERFACE}; 482b60add1eSGunnar Mills mapperCall.append(filter); 483b60add1eSGunnar Mills 48487c78173SEd Tanous try 485b60add1eSGunnar Mills { 48687c78173SEd Tanous auto response = bus.call(mapperCall); 487b60add1eSGunnar Mills 488b60add1eSGunnar Mills using ObjectPaths = std::vector<std::string>; 489b60add1eSGunnar Mills ObjectPaths result; 490b60add1eSGunnar Mills response.read(result); 491b60add1eSGunnar Mills 4921254c628SAdriana Kobylak if (!result.empty()) 493b60add1eSGunnar Mills { 4941254c628SAdriana Kobylak bmcInventoryPath = result.front(); 495b60add1eSGunnar Mills } 49687c78173SEd Tanous } 49787c78173SEd Tanous catch (const sdbusplus::exception::SdBusError& e) 49887c78173SEd Tanous { 49987c78173SEd Tanous log<level::ERR>("Error in mapper GetSubTreePath"); 50087c78173SEd Tanous return; 50187c78173SEd Tanous } 502b60add1eSGunnar Mills 503b60add1eSGunnar Mills return; 504b60add1eSGunnar Mills } 505b60add1eSGunnar Mills 506f10b2326SGunnar Mills void ItemUpdater::createActiveAssociation(const std::string& path) 507ded875dcSGunnar Mills { 5082285fe0fSAdriana Kobylak assocs.emplace_back( 5092285fe0fSAdriana Kobylak std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path)); 510ded875dcSGunnar Mills associations(assocs); 511ded875dcSGunnar Mills } 512ded875dcSGunnar Mills 51388e8a325SGunnar Mills void ItemUpdater::createFunctionalAssociation(const std::string& path) 51488e8a325SGunnar Mills { 51588e8a325SGunnar Mills assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION, 5162285fe0fSAdriana Kobylak FUNCTIONAL_REV_ASSOCIATION, path)); 51788e8a325SGunnar Mills associations(assocs); 51888e8a325SGunnar Mills } 51988e8a325SGunnar Mills 520f10b2326SGunnar Mills void ItemUpdater::removeActiveAssociation(const std::string& path) 521ded875dcSGunnar Mills { 522ded875dcSGunnar Mills for (auto iter = assocs.begin(); iter != assocs.end();) 523ded875dcSGunnar Mills { 52488e8a325SGunnar Mills // Since there could be multiple associations to the same path, 52588e8a325SGunnar Mills // only remove ones that have an active forward association. 52688e8a325SGunnar Mills if ((std::get<0>(*iter)).compare(ACTIVE_FWD_ASSOCIATION) == 0 && 52788e8a325SGunnar Mills (std::get<2>(*iter)).compare(path) == 0) 528ded875dcSGunnar Mills { 529ded875dcSGunnar Mills iter = assocs.erase(iter); 530ded875dcSGunnar Mills associations(assocs); 531ded875dcSGunnar Mills } 532ded875dcSGunnar Mills else 533ded875dcSGunnar Mills { 534ded875dcSGunnar Mills ++iter; 535ded875dcSGunnar Mills } 536ded875dcSGunnar Mills } 537ded875dcSGunnar Mills } 538ded875dcSGunnar Mills 539b9da6634SSaqib Khan bool ItemUpdater::isLowestPriority(uint8_t value) 540b9da6634SSaqib Khan { 541b9da6634SSaqib Khan for (const auto& intf : activations) 542b9da6634SSaqib Khan { 543b9da6634SSaqib Khan if (intf.second->redundancyPriority) 544b9da6634SSaqib Khan { 545b9da6634SSaqib Khan if (intf.second->redundancyPriority.get()->priority() < value) 546b9da6634SSaqib Khan { 547b9da6634SSaqib Khan return false; 548b9da6634SSaqib Khan } 549b9da6634SSaqib Khan } 550b9da6634SSaqib Khan } 551b9da6634SSaqib Khan return true; 552b9da6634SSaqib Khan } 553b9da6634SSaqib Khan 554b77551cdSAdriana Kobylak void ItemUpdater::updateUbootEnvVars(const std::string& versionId) 555b77551cdSAdriana Kobylak { 55656aaf454SLei YU helper.updateUbootVersionId(versionId); 557b77551cdSAdriana Kobylak } 558b77551cdSAdriana Kobylak 55949446ae9SSaqib Khan void ItemUpdater::resetUbootEnvVars() 56049446ae9SSaqib Khan { 56149446ae9SSaqib Khan decltype(activations.begin()->second->redundancyPriority.get()->priority()) 56249446ae9SSaqib Khan lowestPriority = std::numeric_limits<uint8_t>::max(); 56349446ae9SSaqib Khan decltype(activations.begin()->second->versionId) lowestPriorityVersion; 56449446ae9SSaqib Khan for (const auto& intf : activations) 56549446ae9SSaqib Khan { 56649446ae9SSaqib Khan if (!intf.second->redundancyPriority.get()) 56749446ae9SSaqib Khan { 56849446ae9SSaqib Khan // Skip this version if the redundancyPriority is not initialized. 56949446ae9SSaqib Khan continue; 57049446ae9SSaqib Khan } 57149446ae9SSaqib Khan 5722285fe0fSAdriana Kobylak if (intf.second->redundancyPriority.get()->priority() <= lowestPriority) 57349446ae9SSaqib Khan { 57449446ae9SSaqib Khan lowestPriority = intf.second->redundancyPriority.get()->priority(); 57549446ae9SSaqib Khan lowestPriorityVersion = intf.second->versionId; 57649446ae9SSaqib Khan } 57749446ae9SSaqib Khan } 57849446ae9SSaqib Khan 579f0382c35SSaqib Khan // Update the U-boot environment variable to point to the lowest priority 580b77551cdSAdriana Kobylak updateUbootEnvVars(lowestPriorityVersion); 58149446ae9SSaqib Khan } 58249446ae9SSaqib Khan 583204e1e74SAdriana Kobylak void ItemUpdater::freeSpace() 584204e1e74SAdriana Kobylak { 585204e1e74SAdriana Kobylak // Versions with the highest priority in front 586204e1e74SAdriana Kobylak std::priority_queue<std::pair<int, std::string>, 587204e1e74SAdriana Kobylak std::vector<std::pair<int, std::string>>, 5882285fe0fSAdriana Kobylak std::less<std::pair<int, std::string>>> 5892285fe0fSAdriana Kobylak versionsPQ; 590204e1e74SAdriana Kobylak 591204e1e74SAdriana Kobylak std::size_t count = 0; 592204e1e74SAdriana Kobylak for (const auto& iter : activations) 593204e1e74SAdriana Kobylak { 594204e1e74SAdriana Kobylak if ((iter.second.get()->activation() == 595204e1e74SAdriana Kobylak server::Activation::Activations::Active) || 596204e1e74SAdriana Kobylak (iter.second.get()->activation() == 597204e1e74SAdriana Kobylak server::Activation::Activations::Failed)) 598204e1e74SAdriana Kobylak { 599204e1e74SAdriana Kobylak count++; 600204e1e74SAdriana Kobylak // Don't put the functional version on the queue since we can't 601204e1e74SAdriana Kobylak // remove the "running" BMC version. 602204e1e74SAdriana Kobylak if (versions.find(iter.second->versionId)->second->isFunctional()) 603204e1e74SAdriana Kobylak { 604204e1e74SAdriana Kobylak continue; 605204e1e74SAdriana Kobylak } 606204e1e74SAdriana Kobylak versionsPQ.push(std::make_pair( 607204e1e74SAdriana Kobylak iter.second->redundancyPriority.get()->priority(), 608204e1e74SAdriana Kobylak iter.second->versionId)); 609204e1e74SAdriana Kobylak } 610204e1e74SAdriana Kobylak } 611204e1e74SAdriana Kobylak 612204e1e74SAdriana Kobylak // If the number of BMC versions is over ACTIVE_BMC_MAX_ALLOWED -1, 613204e1e74SAdriana Kobylak // remove the highest priority one(s). 614204e1e74SAdriana Kobylak while ((count >= ACTIVE_BMC_MAX_ALLOWED) && (!versionsPQ.empty())) 615204e1e74SAdriana Kobylak { 616204e1e74SAdriana Kobylak erase(versionsPQ.top().second); 617204e1e74SAdriana Kobylak versionsPQ.pop(); 618204e1e74SAdriana Kobylak count--; 619204e1e74SAdriana Kobylak } 620204e1e74SAdriana Kobylak } 621204e1e74SAdriana Kobylak 622eaa1ee05SEddie James void ItemUpdater::mirrorUbootToAlt() 623eaa1ee05SEddie James { 62456aaf454SLei YU helper.mirrorAlt(); 625eaa1ee05SEddie James } 626eaa1ee05SEddie James 627ec1b41c4SGunnar Mills } // namespace updater 628ec1b41c4SGunnar Mills } // namespace software 629ec1b41c4SGunnar Mills } // namespace phosphor 630