1b0ce996aSGunnar Mills #include "config.h" 2b0ce996aSGunnar Mills 3b0ce996aSGunnar Mills #include "item_updater.hpp" 4b0ce996aSGunnar Mills 5b0ce996aSGunnar Mills #include "images.hpp" 6b0ce996aSGunnar Mills #include "serialize.hpp" 7b0ce996aSGunnar Mills #include "version.hpp" 8b0ce996aSGunnar Mills #include "xyz/openbmc_project/Software/Version/server.hpp" 9b0ce996aSGunnar Mills 10b0ce996aSGunnar Mills #include <elog-errors.hpp> 11b0ce996aSGunnar Mills #include <experimental/filesystem> 1235e83f3eSSaqib Khan #include <fstream> 13b0ce996aSGunnar Mills #include <phosphor-logging/elog.hpp> 14b0ce996aSGunnar Mills #include <phosphor-logging/log.hpp> 15204e1e74SAdriana Kobylak #include <queue> 16b77551cdSAdriana Kobylak #include <set> 17ec1b41c4SGunnar Mills #include <string> 18dcbfa04aSSaqib Khan #include <xyz/openbmc_project/Software/Version/error.hpp> 19ec1b41c4SGunnar Mills 20ec1b41c4SGunnar Mills namespace phosphor 21ec1b41c4SGunnar Mills { 22ec1b41c4SGunnar Mills namespace software 23ec1b41c4SGunnar Mills { 24ec1b41c4SGunnar Mills namespace updater 25ec1b41c4SGunnar Mills { 26ec1b41c4SGunnar Mills 272ce7da29SGunnar Mills // When you see server:: you know we're referencing our base class 282ce7da29SGunnar Mills namespace server = sdbusplus::xyz::openbmc_project::Software::server; 290129d926SMichael Tritz namespace control = sdbusplus::xyz::openbmc_project::Control::server; 302ce7da29SGunnar Mills 312ce7da29SGunnar Mills using namespace phosphor::logging; 32dcbfa04aSSaqib Khan using namespace sdbusplus::xyz::openbmc_project::Software::Version::Error; 332ab9b109SJayanth Othayoth using namespace phosphor::software::image; 3435e83f3eSSaqib Khan namespace fs = std::experimental::filesystem; 3535e83f3eSSaqib Khan 36e75d10f5SPatrick Williams void ItemUpdater::createActivation(sdbusplus::message::message& msg) 37ec1b41c4SGunnar Mills { 3884a0e693SSaqib Khan 3984a0e693SSaqib Khan using SVersion = server::Version; 4084a0e693SSaqib Khan using VersionPurpose = SVersion::VersionPurpose; 419a782243SGunnar Mills using VersionClass = phosphor::software::manager::Version; 4284a0e693SSaqib Khan namespace mesg = sdbusplus::message; 4384a0e693SSaqib Khan namespace variant_ns = mesg::variant_ns; 4484a0e693SSaqib Khan 4584a0e693SSaqib Khan mesg::object_path objPath; 4684a0e693SSaqib Khan auto purpose = VersionPurpose::Unknown; 47705f1bfcSSaqib Khan std::string version; 482285fe0fSAdriana Kobylak std::map<std::string, std::map<std::string, mesg::variant<std::string>>> 492285fe0fSAdriana Kobylak interfaces; 50e75d10f5SPatrick Williams msg.read(objPath, interfaces); 512ce7da29SGunnar Mills std::string path(std::move(objPath)); 5219177d3eSSaqib Khan std::string filePath; 532ce7da29SGunnar Mills 542ce7da29SGunnar Mills for (const auto& intf : interfaces) 552ce7da29SGunnar Mills { 56705f1bfcSSaqib Khan if (intf.first == VERSION_IFACE) 572ce7da29SGunnar Mills { 582ce7da29SGunnar Mills for (const auto& property : intf.second) 592ce7da29SGunnar Mills { 60705f1bfcSSaqib Khan if (property.first == "Purpose") 612ce7da29SGunnar Mills { 6284a0e693SSaqib Khan auto value = SVersion::convertVersionPurposeFromString( 6384a0e693SSaqib Khan variant_ns::get<std::string>(property.second)); 6484a0e693SSaqib Khan if (value == VersionPurpose::BMC || 6584a0e693SSaqib Khan value == VersionPurpose::System) 6684a0e693SSaqib Khan { 6784a0e693SSaqib Khan purpose = value; 6884a0e693SSaqib Khan } 69705f1bfcSSaqib Khan } 70705f1bfcSSaqib Khan else if (property.first == "Version") 71705f1bfcSSaqib Khan { 7284a0e693SSaqib Khan version = variant_ns::get<std::string>(property.second); 73705f1bfcSSaqib Khan } 74705f1bfcSSaqib Khan } 75705f1bfcSSaqib Khan } 7619177d3eSSaqib Khan else if (intf.first == FILEPATH_IFACE) 7719177d3eSSaqib Khan { 7819177d3eSSaqib Khan for (const auto& property : intf.second) 7919177d3eSSaqib Khan { 8019177d3eSSaqib Khan if (property.first == "Path") 8119177d3eSSaqib Khan { 8284a0e693SSaqib Khan filePath = variant_ns::get<std::string>(property.second); 8319177d3eSSaqib Khan } 8419177d3eSSaqib Khan } 8519177d3eSSaqib Khan } 86705f1bfcSSaqib Khan } 872285fe0fSAdriana Kobylak if (version.empty() || 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", 98596466b8SAdriana Kobylak entry("OBJPATH=%s", path.c_str())); 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 1162285fe0fSAdriana Kobylak associations.emplace_back( 1172285fe0fSAdriana Kobylak std::make_tuple(ACTIVATION_FWD_ASSOCIATION, 1182285fe0fSAdriana Kobylak ACTIVATION_REV_ASSOCIATION, bmcInventoryPath)); 11943b25cdeSGunnar Mills } 120b60add1eSGunnar Mills 121ee13e831SSaqib Khan activations.insert(std::make_pair( 122ee13e831SSaqib Khan versionId, 1232285fe0fSAdriana Kobylak std::make_unique<Activation>(bus, path, *this, versionId, 1242285fe0fSAdriana Kobylak activationState, associations))); 1254254beceSMichael Tritz 126ee13e831SSaqib Khan auto versionPtr = std::make_unique<VersionClass>( 1272285fe0fSAdriana Kobylak bus, path, version, purpose, filePath, 1282285fe0fSAdriana Kobylak std::bind(&ItemUpdater::erase, this, std::placeholders::_1)); 129ee13e831SSaqib Khan versionPtr->deleteObject = 1302285fe0fSAdriana Kobylak std::make_unique<phosphor::software::manager::Delete>(bus, path, 1312285fe0fSAdriana Kobylak *versionPtr); 132ee13e831SSaqib Khan versions.insert(std::make_pair(versionId, std::move(versionPtr))); 1332ce7da29SGunnar Mills } 134e75d10f5SPatrick Williams return; 135ec1b41c4SGunnar Mills } 136ec1b41c4SGunnar Mills 137ba239881SSaqib Khan void ItemUpdater::processBMCImage() 138ba239881SSaqib Khan { 13988e8a325SGunnar Mills using VersionClass = phosphor::software::manager::Version; 140269bff30SLei YU 141269bff30SLei YU // Check MEDIA_DIR and create if it does not exist 142269bff30SLei YU try 143269bff30SLei YU { 144269bff30SLei YU if (!fs::is_directory(MEDIA_DIR)) 145269bff30SLei YU { 146269bff30SLei YU fs::create_directory(MEDIA_DIR); 147269bff30SLei YU } 148269bff30SLei YU } 149269bff30SLei YU catch (const fs::filesystem_error& e) 150269bff30SLei YU { 151269bff30SLei YU log<level::ERR>("Failed to prepare dir", entry("ERR=%s", e.what())); 152269bff30SLei YU return; 153269bff30SLei YU } 154269bff30SLei YU 15588e8a325SGunnar Mills // Read os-release from /etc/ to get the functional BMC version 15688e8a325SGunnar Mills auto functionalVersion = VersionClass::getBMCVersion(OS_RELEASE_FILE); 15788e8a325SGunnar Mills 1581eef62deSSaqib Khan // Read os-release from folders under /media/ to get 1591eef62deSSaqib Khan // BMC Software Versions. 1601eef62deSSaqib Khan for (const auto& iter : fs::directory_iterator(MEDIA_DIR)) 1611eef62deSSaqib Khan { 1621eef62deSSaqib Khan auto activationState = server::Activation::Activations::Active; 1636fab70daSSaqib Khan static const auto BMC_RO_PREFIX_LEN = strlen(BMC_ROFS_PREFIX); 1641eef62deSSaqib Khan 1651eef62deSSaqib Khan // Check if the BMC_RO_PREFIXis the prefix of the iter.path 1662285fe0fSAdriana Kobylak if (0 == 1672285fe0fSAdriana Kobylak iter.path().native().compare(0, BMC_RO_PREFIX_LEN, BMC_ROFS_PREFIX)) 1681eef62deSSaqib Khan { 169021c365bSSaqib Khan // The versionId is extracted from the path 170021c365bSSaqib Khan // for example /media/ro-2a1022fe. 171021c365bSSaqib Khan auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN); 1721eef62deSSaqib Khan auto osRelease = iter.path() / OS_RELEASE_FILE; 1731eef62deSSaqib Khan if (!fs::is_regular_file(osRelease)) 1741eef62deSSaqib Khan { 1752285fe0fSAdriana Kobylak log<level::ERR>( 1762285fe0fSAdriana Kobylak "Failed to read osRelease", 177596466b8SAdriana Kobylak entry("FILENAME=%s", osRelease.string().c_str())); 178021c365bSSaqib Khan ItemUpdater::erase(id); 179021c365bSSaqib Khan continue; 1801eef62deSSaqib Khan } 18188e8a325SGunnar Mills auto version = VersionClass::getBMCVersion(osRelease); 1821eef62deSSaqib Khan if (version.empty()) 1831eef62deSSaqib Khan { 1842285fe0fSAdriana Kobylak log<level::ERR>( 1852285fe0fSAdriana Kobylak "Failed to read version from osRelease", 186596466b8SAdriana Kobylak entry("FILENAME=%s", osRelease.string().c_str())); 1871eef62deSSaqib Khan activationState = server::Activation::Activations::Invalid; 1881eef62deSSaqib Khan } 189021c365bSSaqib Khan 1901eef62deSSaqib Khan auto purpose = server::Version::VersionPurpose::BMC; 1911eef62deSSaqib Khan auto path = fs::path(SOFTWARE_OBJPATH) / id; 1921eef62deSSaqib Khan 193269bff30SLei YU // Create functional association if this is the functional 194269bff30SLei YU // version 19588e8a325SGunnar Mills if (version.compare(functionalVersion) == 0) 19688e8a325SGunnar Mills { 19788e8a325SGunnar Mills createFunctionalAssociation(path); 19888e8a325SGunnar Mills } 19988e8a325SGunnar Mills 20043b25cdeSGunnar Mills AssociationList associations = {}; 20143b25cdeSGunnar Mills 20243b25cdeSGunnar Mills if (activationState == server::Activation::Activations::Active) 20343b25cdeSGunnar Mills { 20443b25cdeSGunnar Mills // Create an association to the BMC inventory item 20543b25cdeSGunnar Mills associations.emplace_back(std::make_tuple( 2062285fe0fSAdriana Kobylak ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION, 20743b25cdeSGunnar Mills bmcInventoryPath)); 20843b25cdeSGunnar Mills 20943b25cdeSGunnar Mills // Create an active association since this image is active 21043b25cdeSGunnar Mills createActiveAssociation(path); 21143b25cdeSGunnar Mills } 21243b25cdeSGunnar Mills 213ee590c74SAdriana Kobylak // Create Version instance for this version. 214ee590c74SAdriana Kobylak auto versionPtr = std::make_unique<VersionClass>( 2152285fe0fSAdriana Kobylak bus, path, version, purpose, "", 2162285fe0fSAdriana Kobylak std::bind(&ItemUpdater::erase, this, std::placeholders::_1)); 217ee590c74SAdriana Kobylak auto isVersionFunctional = versionPtr->isFunctional(); 218ee13e831SSaqib Khan if (!isVersionFunctional) 219ee13e831SSaqib Khan { 220ee13e831SSaqib Khan versionPtr->deleteObject = 221ee13e831SSaqib Khan std::make_unique<phosphor::software::manager::Delete>( 222ee13e831SSaqib Khan bus, path, *versionPtr); 223ee13e831SSaqib Khan } 2242285fe0fSAdriana Kobylak versions.insert(std::make_pair(id, std::move(versionPtr))); 225ee590c74SAdriana Kobylak 2261eef62deSSaqib Khan // Create Activation instance for this version. 227ee13e831SSaqib Khan activations.insert(std::make_pair( 2282285fe0fSAdriana Kobylak id, std::make_unique<Activation>( 2292285fe0fSAdriana Kobylak bus, path, *this, id, activationState, associations))); 2301eef62deSSaqib Khan 231269bff30SLei YU // If Active, create RedundancyPriority instance for this 232269bff30SLei YU // version. 2331eef62deSSaqib Khan if (activationState == server::Activation::Activations::Active) 2341eef62deSSaqib Khan { 2351eef62deSSaqib Khan uint8_t priority = std::numeric_limits<uint8_t>::max(); 2361eef62deSSaqib Khan if (!restoreFromFile(id, priority)) 2371eef62deSSaqib Khan { 238ee590c74SAdriana Kobylak if (isVersionFunctional) 239ee590c74SAdriana Kobylak { 240ee590c74SAdriana Kobylak priority = 0; 241ee590c74SAdriana Kobylak } 242ee590c74SAdriana Kobylak else 243ee590c74SAdriana Kobylak { 2441eef62deSSaqib Khan log<level::ERR>("Unable to restore priority from file.", 245596466b8SAdriana Kobylak entry("VERSIONID=%s", id.c_str())); 2461eef62deSSaqib Khan } 247ee590c74SAdriana Kobylak } 2481eef62deSSaqib Khan activations.find(id)->second->redundancyPriority = 2491eef62deSSaqib Khan std::make_unique<RedundancyPriority>( 2502285fe0fSAdriana Kobylak bus, path, *(activations.find(id)->second), priority, 251b77551cdSAdriana Kobylak false); 2521eef62deSSaqib Khan } 2531eef62deSSaqib Khan } 2541eef62deSSaqib Khan } 255dcbfa04aSSaqib Khan 256dcbfa04aSSaqib Khan // If there is no ubi volume for bmc version then read the /etc/os-release 257dcbfa04aSSaqib Khan // and create rofs-<versionId> under /media 258dcbfa04aSSaqib Khan if (activations.size() == 0) 259dcbfa04aSSaqib Khan { 260d16bcbd5SGunnar Mills auto version = VersionClass::getBMCVersion(OS_RELEASE_FILE); 261dcbfa04aSSaqib Khan auto id = phosphor::software::manager::Version::getId(version); 262dcbfa04aSSaqib Khan auto versionFileDir = BMC_ROFS_PREFIX + id + "/etc/"; 263dcbfa04aSSaqib Khan try 264dcbfa04aSSaqib Khan { 265dcbfa04aSSaqib Khan if (!fs::is_directory(versionFileDir)) 266dcbfa04aSSaqib Khan { 267dcbfa04aSSaqib Khan fs::create_directories(versionFileDir); 268dcbfa04aSSaqib Khan } 269dcbfa04aSSaqib Khan auto versionFilePath = BMC_ROFS_PREFIX + id + OS_RELEASE_FILE; 270dcbfa04aSSaqib Khan fs::create_directory_symlink(OS_RELEASE_FILE, versionFilePath); 271dcbfa04aSSaqib Khan ItemUpdater::processBMCImage(); 272dcbfa04aSSaqib Khan } 273dcbfa04aSSaqib Khan catch (const std::exception& e) 274dcbfa04aSSaqib Khan { 275dcbfa04aSSaqib Khan log<level::ERR>(e.what()); 276dcbfa04aSSaqib Khan } 277dcbfa04aSSaqib Khan } 278eaa1ee05SEddie James 279eaa1ee05SEddie James mirrorUbootToAlt(); 280ba239881SSaqib Khan return; 281ba239881SSaqib Khan } 282ba239881SSaqib Khan 2833526ef73SLeonel Gonzalez void ItemUpdater::erase(std::string entryId) 2843526ef73SLeonel Gonzalez { 2856d873715SEddie James // Find entry in versions map 2866d873715SEddie James auto it = versions.find(entryId); 2876d873715SEddie James if (it != versions.end()) 2886d873715SEddie James { 2890f88b5afSLei YU if (it->second->isFunctional() && ACTIVE_BMC_MAX_ALLOWED > 1) 2906d873715SEddie James { 2912285fe0fSAdriana Kobylak log<level::ERR>("Error: Version is currently running on the BMC. " 2922285fe0fSAdriana Kobylak "Unable to remove.", 2932285fe0fSAdriana Kobylak entry("VERSIONID=%s", entryId.c_str())); 2946d873715SEddie James return; 2956d873715SEddie James } 2966d873715SEddie James 2976d873715SEddie James // Delete ReadOnly partitions if it's not active 2983526ef73SLeonel Gonzalez removeReadOnlyPartition(entryId); 2991eef62deSSaqib Khan removeFile(entryId); 300ee13e831SSaqib Khan 301ee13e831SSaqib Khan // Removing entry in versions map 302ee13e831SSaqib Khan this->versions.erase(entryId); 3036d873715SEddie James } 3046d873715SEddie James else 3056d873715SEddie James { 3066d873715SEddie James // Delete ReadOnly partitions even if we can't find the version 3076d873715SEddie James removeReadOnlyPartition(entryId); 3086d873715SEddie James removeFile(entryId); 3096d873715SEddie James 3102285fe0fSAdriana Kobylak log<level::ERR>("Error: Failed to find version in item updater " 3112285fe0fSAdriana Kobylak "versions map. Unable to remove.", 3122285fe0fSAdriana Kobylak entry("VERSIONID=%s", entryId.c_str())); 3136d873715SEddie James } 3141eef62deSSaqib Khan 31556aaf454SLei YU helper.clearEntry(entryId); 3163526ef73SLeonel Gonzalez 3173526ef73SLeonel Gonzalez // Removing entry in activations map 3183526ef73SLeonel Gonzalez auto ita = activations.find(entryId); 3193526ef73SLeonel Gonzalez if (ita == activations.end()) 3203526ef73SLeonel Gonzalez { 3212285fe0fSAdriana Kobylak log<level::ERR>("Error: Failed to find version in item updater " 3222285fe0fSAdriana Kobylak "activations map. Unable to remove.", 3232285fe0fSAdriana Kobylak entry("VERSIONID=%s", entryId.c_str())); 3243526ef73SLeonel Gonzalez } 325ee13e831SSaqib Khan else 326ee13e831SSaqib Khan { 3273526ef73SLeonel Gonzalez this->activations.erase(entryId); 328ee13e831SSaqib Khan } 32949446ae9SSaqib Khan ItemUpdater::resetUbootEnvVars(); 330ee13e831SSaqib Khan return; 3313526ef73SLeonel Gonzalez } 3323526ef73SLeonel Gonzalez 333bc1bf3afSMichael Tritz void ItemUpdater::deleteAll() 334bc1bf3afSMichael Tritz { 33583cd21fbSAdriana Kobylak std::vector<std::string> deletableVersions; 33683cd21fbSAdriana Kobylak 337bc1bf3afSMichael Tritz for (const auto& versionIt : versions) 338bc1bf3afSMichael Tritz { 339bc1bf3afSMichael Tritz if (!versionIt.second->isFunctional()) 340bc1bf3afSMichael Tritz { 34183cd21fbSAdriana Kobylak deletableVersions.push_back(versionIt.first); 342bc1bf3afSMichael Tritz } 343bc1bf3afSMichael Tritz } 344bc1bf3afSMichael Tritz 34583cd21fbSAdriana Kobylak for (const auto& deletableIt : deletableVersions) 34683cd21fbSAdriana Kobylak { 34783cd21fbSAdriana Kobylak ItemUpdater::erase(deletableIt); 34883cd21fbSAdriana Kobylak } 34983cd21fbSAdriana Kobylak 35056aaf454SLei YU helper.cleanup(); 351bc1bf3afSMichael Tritz } 352bc1bf3afSMichael Tritz 3532285fe0fSAdriana Kobylak ItemUpdater::ActivationStatus 3542285fe0fSAdriana Kobylak ItemUpdater::validateSquashFSImage(const std::string& filePath) 35535e83f3eSSaqib Khan { 356b1cfdf99SMichael Tritz bool invalid = false; 35735e83f3eSSaqib Khan 358b1cfdf99SMichael Tritz for (auto& bmcImage : bmcImages) 359b1cfdf99SMichael Tritz { 36019177d3eSSaqib Khan fs::path file(filePath); 36135e83f3eSSaqib Khan file /= bmcImage; 36235e83f3eSSaqib Khan std::ifstream efile(file.c_str()); 363b1cfdf99SMichael Tritz if (efile.good() != 1) 36435e83f3eSSaqib Khan { 365b1cfdf99SMichael Tritz log<level::ERR>("Failed to find the BMC image.", 366b1cfdf99SMichael Tritz entry("IMAGE=%s", bmcImage.c_str())); 367b1cfdf99SMichael Tritz invalid = true; 36835e83f3eSSaqib Khan } 369b1cfdf99SMichael Tritz } 370b1cfdf99SMichael Tritz 371b1cfdf99SMichael Tritz if (invalid) 37235e83f3eSSaqib Khan { 37335e83f3eSSaqib Khan return ItemUpdater::ActivationStatus::invalid; 37435e83f3eSSaqib Khan } 375b1cfdf99SMichael Tritz 376b1cfdf99SMichael Tritz return ItemUpdater::ActivationStatus::ready; 37735e83f3eSSaqib Khan } 37835e83f3eSSaqib Khan 379bbcb7be1SAdriana Kobylak void ItemUpdater::savePriority(const std::string& versionId, uint8_t value) 380bbcb7be1SAdriana Kobylak { 381bbcb7be1SAdriana Kobylak storeToFile(versionId, value); 382bbcb7be1SAdriana Kobylak helper.setEntry(versionId, value); 383bbcb7be1SAdriana Kobylak } 384bbcb7be1SAdriana Kobylak 385b9da6634SSaqib Khan void ItemUpdater::freePriority(uint8_t value, const std::string& versionId) 3864c1aec09SSaqib Khan { 387b77551cdSAdriana Kobylak std::map<std::string, uint8_t> priorityMap; 388b77551cdSAdriana Kobylak 389b77551cdSAdriana Kobylak // Insert the requested version and priority, it may not exist yet. 390b77551cdSAdriana Kobylak priorityMap.insert(std::make_pair(versionId, value)); 391b77551cdSAdriana Kobylak 3924c1aec09SSaqib Khan for (const auto& intf : activations) 3934c1aec09SSaqib Khan { 3944c1aec09SSaqib Khan if (intf.second->redundancyPriority) 3954c1aec09SSaqib Khan { 396b77551cdSAdriana Kobylak priorityMap.insert(std::make_pair( 3972285fe0fSAdriana Kobylak intf.first, intf.second->redundancyPriority.get()->priority())); 398b77551cdSAdriana Kobylak } 399b77551cdSAdriana Kobylak } 400b77551cdSAdriana Kobylak 401b77551cdSAdriana Kobylak // Lambda function to compare 2 priority values, use <= to allow duplicates 4022285fe0fSAdriana Kobylak typedef std::function<bool(std::pair<std::string, uint8_t>, 4032285fe0fSAdriana Kobylak std::pair<std::string, uint8_t>)> 4042285fe0fSAdriana Kobylak cmpPriority; 4052285fe0fSAdriana Kobylak cmpPriority cmpPriorityFunc = 4062285fe0fSAdriana Kobylak [](std::pair<std::string, uint8_t> priority1, 4072285fe0fSAdriana Kobylak std::pair<std::string, uint8_t> priority2) { 408b77551cdSAdriana Kobylak return priority1.second <= priority2.second; 409b77551cdSAdriana Kobylak }; 410b77551cdSAdriana Kobylak 411b77551cdSAdriana Kobylak // Sort versions by ascending priority 412b77551cdSAdriana Kobylak std::set<std::pair<std::string, uint8_t>, cmpPriority> prioritySet( 413b77551cdSAdriana Kobylak priorityMap.begin(), priorityMap.end(), cmpPriorityFunc); 414b77551cdSAdriana Kobylak 415b77551cdSAdriana Kobylak auto freePriorityValue = value; 416b77551cdSAdriana Kobylak for (auto& element : prioritySet) 417b77551cdSAdriana Kobylak { 418b77551cdSAdriana Kobylak if (element.first == versionId) 419b77551cdSAdriana Kobylak { 420b77551cdSAdriana Kobylak continue; 421b77551cdSAdriana Kobylak } 422b77551cdSAdriana Kobylak if (element.second == freePriorityValue) 423b77551cdSAdriana Kobylak { 424b77551cdSAdriana Kobylak ++freePriorityValue; 425b77551cdSAdriana Kobylak auto it = activations.find(element.first); 426b77551cdSAdriana Kobylak it->second->redundancyPriority.get()->sdbusPriority( 427b77551cdSAdriana Kobylak freePriorityValue); 4284c1aec09SSaqib Khan } 4294c1aec09SSaqib Khan } 430b77551cdSAdriana Kobylak 431b77551cdSAdriana Kobylak auto lowestVersion = prioritySet.begin()->first; 432b77551cdSAdriana Kobylak if (value == prioritySet.begin()->second) 433b77551cdSAdriana Kobylak { 434b77551cdSAdriana Kobylak lowestVersion = versionId; 4354c1aec09SSaqib Khan } 436b77551cdSAdriana Kobylak updateUbootEnvVars(lowestVersion); 4374c1aec09SSaqib Khan } 4384c1aec09SSaqib Khan 43937a59043SMichael Tritz void ItemUpdater::reset() 44037a59043SMichael Tritz { 44156aaf454SLei YU helper.factoryReset(); 44237a59043SMichael Tritz 44337a59043SMichael Tritz log<level::INFO>("BMC factory reset will take effect upon reboot."); 44437a59043SMichael Tritz } 44537a59043SMichael Tritz 4463526ef73SLeonel Gonzalez void ItemUpdater::removeReadOnlyPartition(std::string versionId) 4473526ef73SLeonel Gonzalez { 44856aaf454SLei YU helper.removeVersion(versionId); 4493526ef73SLeonel Gonzalez } 4503526ef73SLeonel Gonzalez 4510129d926SMichael Tritz bool ItemUpdater::fieldModeEnabled(bool value) 4520129d926SMichael Tritz { 4530129d926SMichael Tritz // enabling field mode is intended to be one way: false -> true 4540129d926SMichael Tritz if (value && !control::FieldMode::fieldModeEnabled()) 4550129d926SMichael Tritz { 4560129d926SMichael Tritz control::FieldMode::fieldModeEnabled(value); 4570129d926SMichael Tritz 45856aaf454SLei YU helper.enableFieldMode(); 4590129d926SMichael Tritz } 4600129d926SMichael Tritz 4610129d926SMichael Tritz return control::FieldMode::fieldModeEnabled(); 4620129d926SMichael Tritz } 4630129d926SMichael Tritz 4640129d926SMichael Tritz void ItemUpdater::restoreFieldModeStatus() 4650129d926SMichael Tritz { 466ff0b421dSMichael Tritz std::ifstream input("/dev/mtd/u-boot-env"); 4670129d926SMichael Tritz std::string envVar; 4680129d926SMichael Tritz std::getline(input, envVar); 4690129d926SMichael Tritz 4700129d926SMichael Tritz if (envVar.find("fieldmode=true") != std::string::npos) 4710129d926SMichael Tritz { 4720129d926SMichael Tritz ItemUpdater::fieldModeEnabled(true); 4730129d926SMichael Tritz } 4740129d926SMichael Tritz } 4750129d926SMichael Tritz 476b60add1eSGunnar Mills void ItemUpdater::setBMCInventoryPath() 477b60add1eSGunnar Mills { 478b60add1eSGunnar Mills auto depth = 0; 4792285fe0fSAdriana Kobylak auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH, 4802285fe0fSAdriana Kobylak MAPPER_INTERFACE, "GetSubTreePaths"); 481b60add1eSGunnar Mills 4821254c628SAdriana Kobylak mapperCall.append(INVENTORY_PATH); 483b60add1eSGunnar Mills mapperCall.append(depth); 4841254c628SAdriana Kobylak std::vector<std::string> filter = {BMC_INVENTORY_INTERFACE}; 485b60add1eSGunnar Mills mapperCall.append(filter); 486b60add1eSGunnar Mills 48787c78173SEd Tanous try 488b60add1eSGunnar Mills { 48987c78173SEd Tanous auto response = bus.call(mapperCall); 490b60add1eSGunnar Mills 491b60add1eSGunnar Mills using ObjectPaths = std::vector<std::string>; 492b60add1eSGunnar Mills ObjectPaths result; 493b60add1eSGunnar Mills response.read(result); 494b60add1eSGunnar Mills 4951254c628SAdriana Kobylak if (!result.empty()) 496b60add1eSGunnar Mills { 4971254c628SAdriana Kobylak bmcInventoryPath = result.front(); 498b60add1eSGunnar Mills } 49987c78173SEd Tanous } 50087c78173SEd Tanous catch (const sdbusplus::exception::SdBusError& e) 50187c78173SEd Tanous { 50287c78173SEd Tanous log<level::ERR>("Error in mapper GetSubTreePath"); 50387c78173SEd Tanous return; 50487c78173SEd Tanous } 505b60add1eSGunnar Mills 506b60add1eSGunnar Mills return; 507b60add1eSGunnar Mills } 508b60add1eSGunnar Mills 509f10b2326SGunnar Mills void ItemUpdater::createActiveAssociation(const std::string& path) 510ded875dcSGunnar Mills { 5112285fe0fSAdriana Kobylak assocs.emplace_back( 5122285fe0fSAdriana Kobylak std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path)); 513ded875dcSGunnar Mills associations(assocs); 514ded875dcSGunnar Mills } 515ded875dcSGunnar Mills 51688e8a325SGunnar Mills void ItemUpdater::createFunctionalAssociation(const std::string& path) 51788e8a325SGunnar Mills { 51888e8a325SGunnar Mills assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION, 5192285fe0fSAdriana Kobylak FUNCTIONAL_REV_ASSOCIATION, path)); 52088e8a325SGunnar Mills associations(assocs); 52188e8a325SGunnar Mills } 52288e8a325SGunnar Mills 523f10b2326SGunnar Mills void ItemUpdater::removeActiveAssociation(const std::string& path) 524ded875dcSGunnar Mills { 525ded875dcSGunnar Mills for (auto iter = assocs.begin(); iter != assocs.end();) 526ded875dcSGunnar Mills { 52788e8a325SGunnar Mills // Since there could be multiple associations to the same path, 52888e8a325SGunnar Mills // only remove ones that have an active forward association. 52988e8a325SGunnar Mills if ((std::get<0>(*iter)).compare(ACTIVE_FWD_ASSOCIATION) == 0 && 53088e8a325SGunnar Mills (std::get<2>(*iter)).compare(path) == 0) 531ded875dcSGunnar Mills { 532ded875dcSGunnar Mills iter = assocs.erase(iter); 533ded875dcSGunnar Mills associations(assocs); 534ded875dcSGunnar Mills } 535ded875dcSGunnar Mills else 536ded875dcSGunnar Mills { 537ded875dcSGunnar Mills ++iter; 538ded875dcSGunnar Mills } 539ded875dcSGunnar Mills } 540ded875dcSGunnar Mills } 541ded875dcSGunnar Mills 542b9da6634SSaqib Khan bool ItemUpdater::isLowestPriority(uint8_t value) 543b9da6634SSaqib Khan { 544b9da6634SSaqib Khan for (const auto& intf : activations) 545b9da6634SSaqib Khan { 546b9da6634SSaqib Khan if (intf.second->redundancyPriority) 547b9da6634SSaqib Khan { 548b9da6634SSaqib Khan if (intf.second->redundancyPriority.get()->priority() < value) 549b9da6634SSaqib Khan { 550b9da6634SSaqib Khan return false; 551b9da6634SSaqib Khan } 552b9da6634SSaqib Khan } 553b9da6634SSaqib Khan } 554b9da6634SSaqib Khan return true; 555b9da6634SSaqib Khan } 556b9da6634SSaqib Khan 557b77551cdSAdriana Kobylak void ItemUpdater::updateUbootEnvVars(const std::string& versionId) 558b77551cdSAdriana Kobylak { 55956aaf454SLei YU helper.updateUbootVersionId(versionId); 560b77551cdSAdriana Kobylak } 561b77551cdSAdriana Kobylak 56249446ae9SSaqib Khan void ItemUpdater::resetUbootEnvVars() 56349446ae9SSaqib Khan { 56449446ae9SSaqib Khan decltype(activations.begin()->second->redundancyPriority.get()->priority()) 56549446ae9SSaqib Khan lowestPriority = std::numeric_limits<uint8_t>::max(); 56649446ae9SSaqib Khan decltype(activations.begin()->second->versionId) lowestPriorityVersion; 56749446ae9SSaqib Khan for (const auto& intf : activations) 56849446ae9SSaqib Khan { 56949446ae9SSaqib Khan if (!intf.second->redundancyPriority.get()) 57049446ae9SSaqib Khan { 57149446ae9SSaqib Khan // Skip this version if the redundancyPriority is not initialized. 57249446ae9SSaqib Khan continue; 57349446ae9SSaqib Khan } 57449446ae9SSaqib Khan 5752285fe0fSAdriana Kobylak if (intf.second->redundancyPriority.get()->priority() <= lowestPriority) 57649446ae9SSaqib Khan { 57749446ae9SSaqib Khan lowestPriority = intf.second->redundancyPriority.get()->priority(); 57849446ae9SSaqib Khan lowestPriorityVersion = intf.second->versionId; 57949446ae9SSaqib Khan } 58049446ae9SSaqib Khan } 58149446ae9SSaqib Khan 582f0382c35SSaqib Khan // Update the U-boot environment variable to point to the lowest priority 583b77551cdSAdriana Kobylak updateUbootEnvVars(lowestPriorityVersion); 58449446ae9SSaqib Khan } 58549446ae9SSaqib Khan 586*a6963590SAdriana Kobylak void ItemUpdater::freeSpace(Activation& caller) 587204e1e74SAdriana Kobylak { 588204e1e74SAdriana Kobylak // Versions with the highest priority in front 589204e1e74SAdriana Kobylak std::priority_queue<std::pair<int, std::string>, 590204e1e74SAdriana Kobylak std::vector<std::pair<int, std::string>>, 5912285fe0fSAdriana Kobylak std::less<std::pair<int, std::string>>> 5922285fe0fSAdriana Kobylak versionsPQ; 593204e1e74SAdriana Kobylak 594204e1e74SAdriana Kobylak std::size_t count = 0; 595204e1e74SAdriana Kobylak for (const auto& iter : activations) 596204e1e74SAdriana Kobylak { 597204e1e74SAdriana Kobylak if ((iter.second.get()->activation() == 598204e1e74SAdriana Kobylak server::Activation::Activations::Active) || 599204e1e74SAdriana Kobylak (iter.second.get()->activation() == 600204e1e74SAdriana Kobylak server::Activation::Activations::Failed)) 601204e1e74SAdriana Kobylak { 602204e1e74SAdriana Kobylak count++; 603204e1e74SAdriana Kobylak // Don't put the functional version on the queue since we can't 604204e1e74SAdriana Kobylak // remove the "running" BMC version. 6050f88b5afSLei YU // If ACTIVE_BMC_MAX_ALLOWED <= 1, there is only one active BMC, 6060f88b5afSLei YU // so remove functional version as well. 607*a6963590SAdriana Kobylak // Don't delete the the Activation object that called this function. 608*a6963590SAdriana Kobylak if ((versions.find(iter.second->versionId) 609*a6963590SAdriana Kobylak ->second->isFunctional() && 610*a6963590SAdriana Kobylak ACTIVE_BMC_MAX_ALLOWED > 1) || 611*a6963590SAdriana Kobylak (iter.second->versionId == caller.versionId)) 612204e1e74SAdriana Kobylak { 613204e1e74SAdriana Kobylak continue; 614204e1e74SAdriana Kobylak } 615*a6963590SAdriana Kobylak 616*a6963590SAdriana Kobylak // Failed activations don't have priority, assign them a large value 617*a6963590SAdriana Kobylak // for sorting purposes. 618*a6963590SAdriana Kobylak auto priority = 999; 619*a6963590SAdriana Kobylak if (iter.second.get()->activation() == 620*a6963590SAdriana Kobylak server::Activation::Activations::Active) 621*a6963590SAdriana Kobylak { 622*a6963590SAdriana Kobylak priority = iter.second->redundancyPriority.get()->priority(); 623*a6963590SAdriana Kobylak } 624*a6963590SAdriana Kobylak 625*a6963590SAdriana Kobylak versionsPQ.push(std::make_pair(priority, iter.second->versionId)); 626204e1e74SAdriana Kobylak } 627204e1e74SAdriana Kobylak } 628204e1e74SAdriana Kobylak 629204e1e74SAdriana Kobylak // If the number of BMC versions is over ACTIVE_BMC_MAX_ALLOWED -1, 630204e1e74SAdriana Kobylak // remove the highest priority one(s). 631204e1e74SAdriana Kobylak while ((count >= ACTIVE_BMC_MAX_ALLOWED) && (!versionsPQ.empty())) 632204e1e74SAdriana Kobylak { 633204e1e74SAdriana Kobylak erase(versionsPQ.top().second); 634204e1e74SAdriana Kobylak versionsPQ.pop(); 635204e1e74SAdriana Kobylak count--; 636204e1e74SAdriana Kobylak } 637204e1e74SAdriana Kobylak } 638204e1e74SAdriana Kobylak 639eaa1ee05SEddie James void ItemUpdater::mirrorUbootToAlt() 640eaa1ee05SEddie James { 64156aaf454SLei YU helper.mirrorAlt(); 642eaa1ee05SEddie James } 643eaa1ee05SEddie James 644ec1b41c4SGunnar Mills } // namespace updater 645ec1b41c4SGunnar Mills } // namespace software 646ec1b41c4SGunnar Mills } // namespace phosphor 647