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> 1843699ca7SAdriana Kobylak #include <xyz/openbmc_project/Software/Image/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; 3243699ca7SAdriana Kobylak using namespace sdbusplus::xyz::openbmc_project::Software::Image::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 { 327*991af7ecSAdriana Kobylak removeAssociations(ita->second->path); 3283526ef73SLeonel Gonzalez this->activations.erase(entryId); 329ee13e831SSaqib Khan } 33049446ae9SSaqib Khan ItemUpdater::resetUbootEnvVars(); 331ee13e831SSaqib Khan return; 3323526ef73SLeonel Gonzalez } 3333526ef73SLeonel Gonzalez 334bc1bf3afSMichael Tritz void ItemUpdater::deleteAll() 335bc1bf3afSMichael Tritz { 33683cd21fbSAdriana Kobylak std::vector<std::string> deletableVersions; 33783cd21fbSAdriana Kobylak 338bc1bf3afSMichael Tritz for (const auto& versionIt : versions) 339bc1bf3afSMichael Tritz { 340bc1bf3afSMichael Tritz if (!versionIt.second->isFunctional()) 341bc1bf3afSMichael Tritz { 34283cd21fbSAdriana Kobylak deletableVersions.push_back(versionIt.first); 343bc1bf3afSMichael Tritz } 344bc1bf3afSMichael Tritz } 345bc1bf3afSMichael Tritz 34683cd21fbSAdriana Kobylak for (const auto& deletableIt : deletableVersions) 34783cd21fbSAdriana Kobylak { 34883cd21fbSAdriana Kobylak ItemUpdater::erase(deletableIt); 34983cd21fbSAdriana Kobylak } 35083cd21fbSAdriana Kobylak 35156aaf454SLei YU helper.cleanup(); 352bc1bf3afSMichael Tritz } 353bc1bf3afSMichael Tritz 3542285fe0fSAdriana Kobylak ItemUpdater::ActivationStatus 3552285fe0fSAdriana Kobylak ItemUpdater::validateSquashFSImage(const std::string& filePath) 35635e83f3eSSaqib Khan { 357b1cfdf99SMichael Tritz bool invalid = false; 35835e83f3eSSaqib Khan 359b1cfdf99SMichael Tritz for (auto& bmcImage : bmcImages) 360b1cfdf99SMichael Tritz { 36119177d3eSSaqib Khan fs::path file(filePath); 36235e83f3eSSaqib Khan file /= bmcImage; 36335e83f3eSSaqib Khan std::ifstream efile(file.c_str()); 364b1cfdf99SMichael Tritz if (efile.good() != 1) 36535e83f3eSSaqib Khan { 366b1cfdf99SMichael Tritz log<level::ERR>("Failed to find the BMC image.", 367b1cfdf99SMichael Tritz entry("IMAGE=%s", bmcImage.c_str())); 368b1cfdf99SMichael Tritz invalid = true; 36935e83f3eSSaqib Khan } 370b1cfdf99SMichael Tritz } 371b1cfdf99SMichael Tritz 372b1cfdf99SMichael Tritz if (invalid) 37335e83f3eSSaqib Khan { 37435e83f3eSSaqib Khan return ItemUpdater::ActivationStatus::invalid; 37535e83f3eSSaqib Khan } 376b1cfdf99SMichael Tritz 377b1cfdf99SMichael Tritz return ItemUpdater::ActivationStatus::ready; 37835e83f3eSSaqib Khan } 37935e83f3eSSaqib Khan 380bbcb7be1SAdriana Kobylak void ItemUpdater::savePriority(const std::string& versionId, uint8_t value) 381bbcb7be1SAdriana Kobylak { 382bbcb7be1SAdriana Kobylak storeToFile(versionId, value); 383bbcb7be1SAdriana Kobylak helper.setEntry(versionId, value); 384bbcb7be1SAdriana Kobylak } 385bbcb7be1SAdriana Kobylak 386b9da6634SSaqib Khan void ItemUpdater::freePriority(uint8_t value, const std::string& versionId) 3874c1aec09SSaqib Khan { 388b77551cdSAdriana Kobylak std::map<std::string, uint8_t> priorityMap; 389b77551cdSAdriana Kobylak 390b77551cdSAdriana Kobylak // Insert the requested version and priority, it may not exist yet. 391b77551cdSAdriana Kobylak priorityMap.insert(std::make_pair(versionId, value)); 392b77551cdSAdriana Kobylak 3934c1aec09SSaqib Khan for (const auto& intf : activations) 3944c1aec09SSaqib Khan { 3954c1aec09SSaqib Khan if (intf.second->redundancyPriority) 3964c1aec09SSaqib Khan { 397b77551cdSAdriana Kobylak priorityMap.insert(std::make_pair( 3982285fe0fSAdriana Kobylak intf.first, intf.second->redundancyPriority.get()->priority())); 399b77551cdSAdriana Kobylak } 400b77551cdSAdriana Kobylak } 401b77551cdSAdriana Kobylak 402b77551cdSAdriana Kobylak // Lambda function to compare 2 priority values, use <= to allow duplicates 4032285fe0fSAdriana Kobylak typedef std::function<bool(std::pair<std::string, uint8_t>, 4042285fe0fSAdriana Kobylak std::pair<std::string, uint8_t>)> 4052285fe0fSAdriana Kobylak cmpPriority; 4062285fe0fSAdriana Kobylak cmpPriority cmpPriorityFunc = 4072285fe0fSAdriana Kobylak [](std::pair<std::string, uint8_t> priority1, 4082285fe0fSAdriana Kobylak std::pair<std::string, uint8_t> priority2) { 409b77551cdSAdriana Kobylak return priority1.second <= priority2.second; 410b77551cdSAdriana Kobylak }; 411b77551cdSAdriana Kobylak 412b77551cdSAdriana Kobylak // Sort versions by ascending priority 413b77551cdSAdriana Kobylak std::set<std::pair<std::string, uint8_t>, cmpPriority> prioritySet( 414b77551cdSAdriana Kobylak priorityMap.begin(), priorityMap.end(), cmpPriorityFunc); 415b77551cdSAdriana Kobylak 416b77551cdSAdriana Kobylak auto freePriorityValue = value; 417b77551cdSAdriana Kobylak for (auto& element : prioritySet) 418b77551cdSAdriana Kobylak { 419b77551cdSAdriana Kobylak if (element.first == versionId) 420b77551cdSAdriana Kobylak { 421b77551cdSAdriana Kobylak continue; 422b77551cdSAdriana Kobylak } 423b77551cdSAdriana Kobylak if (element.second == freePriorityValue) 424b77551cdSAdriana Kobylak { 425b77551cdSAdriana Kobylak ++freePriorityValue; 426b77551cdSAdriana Kobylak auto it = activations.find(element.first); 427b77551cdSAdriana Kobylak it->second->redundancyPriority.get()->sdbusPriority( 428b77551cdSAdriana Kobylak freePriorityValue); 4294c1aec09SSaqib Khan } 4304c1aec09SSaqib Khan } 431b77551cdSAdriana Kobylak 432b77551cdSAdriana Kobylak auto lowestVersion = prioritySet.begin()->first; 433b77551cdSAdriana Kobylak if (value == prioritySet.begin()->second) 434b77551cdSAdriana Kobylak { 435b77551cdSAdriana Kobylak lowestVersion = versionId; 4364c1aec09SSaqib Khan } 437b77551cdSAdriana Kobylak updateUbootEnvVars(lowestVersion); 4384c1aec09SSaqib Khan } 4394c1aec09SSaqib Khan 44037a59043SMichael Tritz void ItemUpdater::reset() 44137a59043SMichael Tritz { 44256aaf454SLei YU helper.factoryReset(); 44337a59043SMichael Tritz 44437a59043SMichael Tritz log<level::INFO>("BMC factory reset will take effect upon reboot."); 44537a59043SMichael Tritz } 44637a59043SMichael Tritz 4473526ef73SLeonel Gonzalez void ItemUpdater::removeReadOnlyPartition(std::string versionId) 4483526ef73SLeonel Gonzalez { 44956aaf454SLei YU helper.removeVersion(versionId); 4503526ef73SLeonel Gonzalez } 4513526ef73SLeonel Gonzalez 4520129d926SMichael Tritz bool ItemUpdater::fieldModeEnabled(bool value) 4530129d926SMichael Tritz { 4540129d926SMichael Tritz // enabling field mode is intended to be one way: false -> true 4550129d926SMichael Tritz if (value && !control::FieldMode::fieldModeEnabled()) 4560129d926SMichael Tritz { 4570129d926SMichael Tritz control::FieldMode::fieldModeEnabled(value); 4580129d926SMichael Tritz 45956aaf454SLei YU helper.enableFieldMode(); 4600129d926SMichael Tritz } 4610129d926SMichael Tritz 4620129d926SMichael Tritz return control::FieldMode::fieldModeEnabled(); 4630129d926SMichael Tritz } 4640129d926SMichael Tritz 4650129d926SMichael Tritz void ItemUpdater::restoreFieldModeStatus() 4660129d926SMichael Tritz { 467ff0b421dSMichael Tritz std::ifstream input("/dev/mtd/u-boot-env"); 4680129d926SMichael Tritz std::string envVar; 4690129d926SMichael Tritz std::getline(input, envVar); 4700129d926SMichael Tritz 4710129d926SMichael Tritz if (envVar.find("fieldmode=true") != std::string::npos) 4720129d926SMichael Tritz { 4730129d926SMichael Tritz ItemUpdater::fieldModeEnabled(true); 4740129d926SMichael Tritz } 4750129d926SMichael Tritz } 4760129d926SMichael Tritz 477b60add1eSGunnar Mills void ItemUpdater::setBMCInventoryPath() 478b60add1eSGunnar Mills { 479b60add1eSGunnar Mills auto depth = 0; 4802285fe0fSAdriana Kobylak auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH, 4812285fe0fSAdriana Kobylak MAPPER_INTERFACE, "GetSubTreePaths"); 482b60add1eSGunnar Mills 4831254c628SAdriana Kobylak mapperCall.append(INVENTORY_PATH); 484b60add1eSGunnar Mills mapperCall.append(depth); 4851254c628SAdriana Kobylak std::vector<std::string> filter = {BMC_INVENTORY_INTERFACE}; 486b60add1eSGunnar Mills mapperCall.append(filter); 487b60add1eSGunnar Mills 48887c78173SEd Tanous try 489b60add1eSGunnar Mills { 49087c78173SEd Tanous auto response = bus.call(mapperCall); 491b60add1eSGunnar Mills 492b60add1eSGunnar Mills using ObjectPaths = std::vector<std::string>; 493b60add1eSGunnar Mills ObjectPaths result; 494b60add1eSGunnar Mills response.read(result); 495b60add1eSGunnar Mills 4961254c628SAdriana Kobylak if (!result.empty()) 497b60add1eSGunnar Mills { 4981254c628SAdriana Kobylak bmcInventoryPath = result.front(); 499b60add1eSGunnar Mills } 50087c78173SEd Tanous } 50187c78173SEd Tanous catch (const sdbusplus::exception::SdBusError& e) 50287c78173SEd Tanous { 50387c78173SEd Tanous log<level::ERR>("Error in mapper GetSubTreePath"); 50487c78173SEd Tanous return; 50587c78173SEd Tanous } 506b60add1eSGunnar Mills 507b60add1eSGunnar Mills return; 508b60add1eSGunnar Mills } 509b60add1eSGunnar Mills 510f10b2326SGunnar Mills void ItemUpdater::createActiveAssociation(const std::string& path) 511ded875dcSGunnar Mills { 5122285fe0fSAdriana Kobylak assocs.emplace_back( 5132285fe0fSAdriana Kobylak std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path)); 514ded875dcSGunnar Mills associations(assocs); 515ded875dcSGunnar Mills } 516ded875dcSGunnar Mills 51788e8a325SGunnar Mills void ItemUpdater::createFunctionalAssociation(const std::string& path) 51888e8a325SGunnar Mills { 51988e8a325SGunnar Mills assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION, 5202285fe0fSAdriana Kobylak FUNCTIONAL_REV_ASSOCIATION, path)); 52188e8a325SGunnar Mills associations(assocs); 52288e8a325SGunnar Mills } 52388e8a325SGunnar Mills 524*991af7ecSAdriana Kobylak void ItemUpdater::removeAssociations(const std::string& path) 525ded875dcSGunnar Mills { 526ded875dcSGunnar Mills for (auto iter = assocs.begin(); iter != assocs.end();) 527ded875dcSGunnar Mills { 528*991af7ecSAdriana Kobylak if ((std::get<2>(*iter)).compare(path) == 0) 529ded875dcSGunnar Mills { 530ded875dcSGunnar Mills iter = assocs.erase(iter); 531ded875dcSGunnar Mills associations(assocs); 532ded875dcSGunnar Mills } 533ded875dcSGunnar Mills else 534ded875dcSGunnar Mills { 535ded875dcSGunnar Mills ++iter; 536ded875dcSGunnar Mills } 537ded875dcSGunnar Mills } 538ded875dcSGunnar Mills } 539ded875dcSGunnar Mills 540b9da6634SSaqib Khan bool ItemUpdater::isLowestPriority(uint8_t value) 541b9da6634SSaqib Khan { 542b9da6634SSaqib Khan for (const auto& intf : activations) 543b9da6634SSaqib Khan { 544b9da6634SSaqib Khan if (intf.second->redundancyPriority) 545b9da6634SSaqib Khan { 546b9da6634SSaqib Khan if (intf.second->redundancyPriority.get()->priority() < value) 547b9da6634SSaqib Khan { 548b9da6634SSaqib Khan return false; 549b9da6634SSaqib Khan } 550b9da6634SSaqib Khan } 551b9da6634SSaqib Khan } 552b9da6634SSaqib Khan return true; 553b9da6634SSaqib Khan } 554b9da6634SSaqib Khan 555b77551cdSAdriana Kobylak void ItemUpdater::updateUbootEnvVars(const std::string& versionId) 556b77551cdSAdriana Kobylak { 55756aaf454SLei YU helper.updateUbootVersionId(versionId); 558b77551cdSAdriana Kobylak } 559b77551cdSAdriana Kobylak 56049446ae9SSaqib Khan void ItemUpdater::resetUbootEnvVars() 56149446ae9SSaqib Khan { 56249446ae9SSaqib Khan decltype(activations.begin()->second->redundancyPriority.get()->priority()) 56349446ae9SSaqib Khan lowestPriority = std::numeric_limits<uint8_t>::max(); 56449446ae9SSaqib Khan decltype(activations.begin()->second->versionId) lowestPriorityVersion; 56549446ae9SSaqib Khan for (const auto& intf : activations) 56649446ae9SSaqib Khan { 56749446ae9SSaqib Khan if (!intf.second->redundancyPriority.get()) 56849446ae9SSaqib Khan { 56949446ae9SSaqib Khan // Skip this version if the redundancyPriority is not initialized. 57049446ae9SSaqib Khan continue; 57149446ae9SSaqib Khan } 57249446ae9SSaqib Khan 5732285fe0fSAdriana Kobylak if (intf.second->redundancyPriority.get()->priority() <= lowestPriority) 57449446ae9SSaqib Khan { 57549446ae9SSaqib Khan lowestPriority = intf.second->redundancyPriority.get()->priority(); 57649446ae9SSaqib Khan lowestPriorityVersion = intf.second->versionId; 57749446ae9SSaqib Khan } 57849446ae9SSaqib Khan } 57949446ae9SSaqib Khan 580f0382c35SSaqib Khan // Update the U-boot environment variable to point to the lowest priority 581b77551cdSAdriana Kobylak updateUbootEnvVars(lowestPriorityVersion); 58249446ae9SSaqib Khan } 58349446ae9SSaqib Khan 584a6963590SAdriana Kobylak void ItemUpdater::freeSpace(Activation& caller) 585204e1e74SAdriana Kobylak { 586204e1e74SAdriana Kobylak // Versions with the highest priority in front 587204e1e74SAdriana Kobylak std::priority_queue<std::pair<int, std::string>, 588204e1e74SAdriana Kobylak std::vector<std::pair<int, std::string>>, 5892285fe0fSAdriana Kobylak std::less<std::pair<int, std::string>>> 5902285fe0fSAdriana Kobylak versionsPQ; 591204e1e74SAdriana Kobylak 592204e1e74SAdriana Kobylak std::size_t count = 0; 593204e1e74SAdriana Kobylak for (const auto& iter : activations) 594204e1e74SAdriana Kobylak { 595204e1e74SAdriana Kobylak if ((iter.second.get()->activation() == 596204e1e74SAdriana Kobylak server::Activation::Activations::Active) || 597204e1e74SAdriana Kobylak (iter.second.get()->activation() == 598204e1e74SAdriana Kobylak server::Activation::Activations::Failed)) 599204e1e74SAdriana Kobylak { 600204e1e74SAdriana Kobylak count++; 601204e1e74SAdriana Kobylak // Don't put the functional version on the queue since we can't 602204e1e74SAdriana Kobylak // remove the "running" BMC version. 6030f88b5afSLei YU // If ACTIVE_BMC_MAX_ALLOWED <= 1, there is only one active BMC, 6040f88b5afSLei YU // so remove functional version as well. 605a6963590SAdriana Kobylak // Don't delete the the Activation object that called this function. 606a6963590SAdriana Kobylak if ((versions.find(iter.second->versionId) 607a6963590SAdriana Kobylak ->second->isFunctional() && 608a6963590SAdriana Kobylak ACTIVE_BMC_MAX_ALLOWED > 1) || 609a6963590SAdriana Kobylak (iter.second->versionId == caller.versionId)) 610204e1e74SAdriana Kobylak { 611204e1e74SAdriana Kobylak continue; 612204e1e74SAdriana Kobylak } 613a6963590SAdriana Kobylak 614a6963590SAdriana Kobylak // Failed activations don't have priority, assign them a large value 615a6963590SAdriana Kobylak // for sorting purposes. 616a6963590SAdriana Kobylak auto priority = 999; 617a6963590SAdriana Kobylak if (iter.second.get()->activation() == 618a6963590SAdriana Kobylak server::Activation::Activations::Active) 619a6963590SAdriana Kobylak { 620a6963590SAdriana Kobylak priority = iter.second->redundancyPriority.get()->priority(); 621a6963590SAdriana Kobylak } 622a6963590SAdriana Kobylak 623a6963590SAdriana Kobylak versionsPQ.push(std::make_pair(priority, iter.second->versionId)); 624204e1e74SAdriana Kobylak } 625204e1e74SAdriana Kobylak } 626204e1e74SAdriana Kobylak 627204e1e74SAdriana Kobylak // If the number of BMC versions is over ACTIVE_BMC_MAX_ALLOWED -1, 628204e1e74SAdriana Kobylak // remove the highest priority one(s). 629204e1e74SAdriana Kobylak while ((count >= ACTIVE_BMC_MAX_ALLOWED) && (!versionsPQ.empty())) 630204e1e74SAdriana Kobylak { 631204e1e74SAdriana Kobylak erase(versionsPQ.top().second); 632204e1e74SAdriana Kobylak versionsPQ.pop(); 633204e1e74SAdriana Kobylak count--; 634204e1e74SAdriana Kobylak } 635204e1e74SAdriana Kobylak } 636204e1e74SAdriana Kobylak 637eaa1ee05SEddie James void ItemUpdater::mirrorUbootToAlt() 638eaa1ee05SEddie James { 63956aaf454SLei YU helper.mirrorAlt(); 640eaa1ee05SEddie James } 641eaa1ee05SEddie James 642ec1b41c4SGunnar Mills } // namespace updater 643ec1b41c4SGunnar Mills } // namespace software 644ec1b41c4SGunnar Mills } // namespace phosphor 645