135e83f3eSSaqib Khan #include <fstream> 2ec1b41c4SGunnar Mills #include <string> 32ce7da29SGunnar Mills #include <phosphor-logging/log.hpp> 4dcbfa04aSSaqib Khan #include <phosphor-logging/elog.hpp> 5dcbfa04aSSaqib Khan #include <elog-errors.hpp> 6dcbfa04aSSaqib Khan #include <xyz/openbmc_project/Software/Version/error.hpp> 7ec1b41c4SGunnar Mills #include "config.h" 82ce7da29SGunnar Mills #include "item_updater.hpp" 92ce7da29SGunnar Mills #include "xyz/openbmc_project/Software/Version/server.hpp" 1035e83f3eSSaqib Khan #include <experimental/filesystem> 11705f1bfcSSaqib Khan #include "version.hpp" 125d532675SSaqib Khan #include "serialize.hpp" 13ec1b41c4SGunnar Mills 14ec1b41c4SGunnar Mills namespace phosphor 15ec1b41c4SGunnar Mills { 16ec1b41c4SGunnar Mills namespace software 17ec1b41c4SGunnar Mills { 18ec1b41c4SGunnar Mills namespace updater 19ec1b41c4SGunnar Mills { 20ec1b41c4SGunnar Mills 212ce7da29SGunnar Mills // When you see server:: you know we're referencing our base class 222ce7da29SGunnar Mills namespace server = sdbusplus::xyz::openbmc_project::Software::server; 230129d926SMichael Tritz namespace control = sdbusplus::xyz::openbmc_project::Control::server; 242ce7da29SGunnar Mills 252ce7da29SGunnar Mills using namespace phosphor::logging; 26dcbfa04aSSaqib Khan using namespace sdbusplus::xyz::openbmc_project::Software::Version::Error; 2735e83f3eSSaqib Khan namespace fs = std::experimental::filesystem; 2835e83f3eSSaqib Khan 29b1cfdf99SMichael Tritz const std::vector<std::string> bmcImages = { "image-kernel", 30b1cfdf99SMichael Tritz "image-rofs", 31b1cfdf99SMichael Tritz "image-rwfs", 32b1cfdf99SMichael Tritz "image-u-boot" }; 332ce7da29SGunnar Mills 34e75d10f5SPatrick Williams void ItemUpdater::createActivation(sdbusplus::message::message& msg) 35ec1b41c4SGunnar Mills { 3684a0e693SSaqib Khan 3784a0e693SSaqib Khan using SVersion = server::Version; 3884a0e693SSaqib Khan using VersionPurpose = SVersion::VersionPurpose; 399a782243SGunnar Mills using VersionClass = phosphor::software::manager::Version; 4084a0e693SSaqib Khan namespace mesg = sdbusplus::message; 4184a0e693SSaqib Khan namespace variant_ns = mesg::variant_ns; 4284a0e693SSaqib Khan 4384a0e693SSaqib Khan mesg::object_path objPath; 4484a0e693SSaqib Khan auto purpose = VersionPurpose::Unknown; 45705f1bfcSSaqib Khan std::string version; 462ce7da29SGunnar Mills std::map<std::string, 472ce7da29SGunnar Mills std::map<std::string, 4884a0e693SSaqib Khan mesg::variant<std::string>>> interfaces; 49e75d10f5SPatrick Williams msg.read(objPath, interfaces); 502ce7da29SGunnar Mills std::string path(std::move(objPath)); 5119177d3eSSaqib Khan std::string filePath; 522ce7da29SGunnar Mills 532ce7da29SGunnar Mills for (const auto& intf : interfaces) 542ce7da29SGunnar Mills { 55705f1bfcSSaqib Khan if (intf.first == VERSION_IFACE) 562ce7da29SGunnar Mills { 572ce7da29SGunnar Mills for (const auto& property : intf.second) 582ce7da29SGunnar Mills { 59705f1bfcSSaqib Khan if (property.first == "Purpose") 602ce7da29SGunnar Mills { 6184a0e693SSaqib Khan auto value = SVersion::convertVersionPurposeFromString( 6284a0e693SSaqib Khan variant_ns::get<std::string>(property.second)); 6384a0e693SSaqib Khan if (value == VersionPurpose::BMC || 6484a0e693SSaqib Khan value == VersionPurpose::System) 6584a0e693SSaqib Khan { 6684a0e693SSaqib Khan purpose = value; 6784a0e693SSaqib Khan } 68705f1bfcSSaqib Khan } 69705f1bfcSSaqib Khan else if (property.first == "Version") 70705f1bfcSSaqib Khan { 7184a0e693SSaqib Khan version = variant_ns::get<std::string>(property.second); 72705f1bfcSSaqib Khan } 73705f1bfcSSaqib Khan } 74705f1bfcSSaqib Khan } 7519177d3eSSaqib Khan else if (intf.first == FILEPATH_IFACE) 7619177d3eSSaqib Khan { 7719177d3eSSaqib Khan for (const auto& property : intf.second) 7819177d3eSSaqib Khan { 7919177d3eSSaqib Khan if (property.first == "Path") 8019177d3eSSaqib Khan { 8184a0e693SSaqib Khan filePath = variant_ns::get<std::string>(property.second); 8219177d3eSSaqib Khan } 8319177d3eSSaqib Khan } 8419177d3eSSaqib Khan } 85705f1bfcSSaqib Khan } 86705f1bfcSSaqib Khan if (version.empty() || 8719177d3eSSaqib Khan filePath.empty() || 8884a0e693SSaqib Khan purpose == VersionPurpose::Unknown) 892ce7da29SGunnar Mills { 90e75d10f5SPatrick Williams return; 912ce7da29SGunnar Mills } 922ce7da29SGunnar Mills 932ce7da29SGunnar Mills // Version id is the last item in the path 942ce7da29SGunnar Mills auto pos = path.rfind("/"); 952ce7da29SGunnar Mills if (pos == std::string::npos) 962ce7da29SGunnar Mills { 972ce7da29SGunnar Mills log<level::ERR>("No version id found in object path", 982ce7da29SGunnar Mills entry("OBJPATH=%s", path)); 99e75d10f5SPatrick Williams return; 1002ce7da29SGunnar Mills } 1012ce7da29SGunnar Mills 1022ce7da29SGunnar Mills auto versionId = path.substr(pos + 1); 1032ce7da29SGunnar Mills 104e75d10f5SPatrick Williams if (activations.find(versionId) == activations.end()) 1052ce7da29SGunnar Mills { 10635e83f3eSSaqib Khan // Determine the Activation state by processing the given image dir. 10735e83f3eSSaqib Khan auto activationState = server::Activation::Activations::Invalid; 1089a782243SGunnar Mills ItemUpdater::ActivationStatus result = 1099a782243SGunnar Mills ItemUpdater::validateSquashFSImage(filePath); 11043b25cdeSGunnar Mills AssociationList associations = {}; 11143b25cdeSGunnar Mills 11235e83f3eSSaqib Khan if (result == ItemUpdater::ActivationStatus::ready) 11335e83f3eSSaqib Khan { 11435e83f3eSSaqib Khan activationState = server::Activation::Activations::Ready; 115b60add1eSGunnar Mills // Create an association to the BMC inventory item 11643b25cdeSGunnar Mills associations.emplace_back(std::make_tuple( 117b60add1eSGunnar Mills ACTIVATION_FWD_ASSOCIATION, 118b60add1eSGunnar Mills ACTIVATION_REV_ASSOCIATION, 11943b25cdeSGunnar Mills bmcInventoryPath)); 12043b25cdeSGunnar Mills } 121b60add1eSGunnar Mills 12235e83f3eSSaqib Khan activations.insert(std::make_pair( 1232ce7da29SGunnar Mills versionId, 124ec1b41c4SGunnar Mills std::make_unique<Activation>( 12535e83f3eSSaqib Khan bus, 12635e83f3eSSaqib Khan path, 1274c1aec09SSaqib Khan *this, 12835e83f3eSSaqib Khan versionId, 129b60add1eSGunnar Mills activationState, 130b60add1eSGunnar Mills associations))); 131705f1bfcSSaqib Khan versions.insert(std::make_pair( 132705f1bfcSSaqib Khan versionId, 1339a782243SGunnar Mills std::make_unique<VersionClass>( 134705f1bfcSSaqib Khan bus, 135705f1bfcSSaqib Khan path, 136705f1bfcSSaqib Khan version, 137705f1bfcSSaqib Khan purpose, 1389440f491SEddie James filePath))); 1392ce7da29SGunnar Mills } 140e75d10f5SPatrick Williams return; 141ec1b41c4SGunnar Mills } 142ec1b41c4SGunnar Mills 143ba239881SSaqib Khan void ItemUpdater::processBMCImage() 144ba239881SSaqib Khan { 14588e8a325SGunnar Mills using VersionClass = phosphor::software::manager::Version; 14688e8a325SGunnar Mills // Read os-release from /etc/ to get the functional BMC version 14788e8a325SGunnar Mills auto functionalVersion = VersionClass::getBMCVersion(OS_RELEASE_FILE); 14888e8a325SGunnar Mills 1491eef62deSSaqib Khan // Read os-release from folders under /media/ to get 1501eef62deSSaqib Khan // BMC Software Versions. 1511eef62deSSaqib Khan for (const auto& iter : fs::directory_iterator(MEDIA_DIR)) 1521eef62deSSaqib Khan { 1531eef62deSSaqib Khan auto activationState = server::Activation::Activations::Active; 1546fab70daSSaqib Khan static const auto BMC_RO_PREFIX_LEN = strlen(BMC_ROFS_PREFIX); 1551eef62deSSaqib Khan 1561eef62deSSaqib Khan // Check if the BMC_RO_PREFIXis the prefix of the iter.path 1571eef62deSSaqib Khan if (0 == iter.path().native().compare(0, BMC_RO_PREFIX_LEN, 1586fab70daSSaqib Khan BMC_ROFS_PREFIX)) 1591eef62deSSaqib Khan { 160021c365bSSaqib Khan // The versionId is extracted from the path 161021c365bSSaqib Khan // for example /media/ro-2a1022fe. 162021c365bSSaqib Khan auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN); 1631eef62deSSaqib Khan auto osRelease = iter.path() / OS_RELEASE_FILE; 1641eef62deSSaqib Khan if (!fs::is_regular_file(osRelease)) 1651eef62deSSaqib Khan { 1662ad1b55fSGunnar Mills log<level::ERR>("Failed to read osRelease", 1672ad1b55fSGunnar Mills entry("FILENAME=%s", osRelease.string())); 168021c365bSSaqib Khan ItemUpdater::erase(id); 169021c365bSSaqib Khan continue; 1701eef62deSSaqib Khan } 17188e8a325SGunnar Mills auto version = VersionClass::getBMCVersion(osRelease); 1721eef62deSSaqib Khan if (version.empty()) 1731eef62deSSaqib Khan { 1741eef62deSSaqib Khan log<level::ERR>("Failed to read version from osRelease", 1751eef62deSSaqib Khan entry("FILENAME=%s", osRelease.string())); 1761eef62deSSaqib Khan activationState = server::Activation::Activations::Invalid; 1771eef62deSSaqib Khan } 178021c365bSSaqib Khan 1791eef62deSSaqib Khan auto purpose = server::Version::VersionPurpose::BMC; 1801eef62deSSaqib Khan auto path = fs::path(SOFTWARE_OBJPATH) / id; 1811eef62deSSaqib Khan 18288e8a325SGunnar Mills // Create functional association if this is the functional version 18388e8a325SGunnar Mills if (version.compare(functionalVersion) == 0) 18488e8a325SGunnar Mills { 18588e8a325SGunnar Mills createFunctionalAssociation(path); 18688e8a325SGunnar Mills } 18788e8a325SGunnar Mills 18843b25cdeSGunnar Mills AssociationList associations = {}; 18943b25cdeSGunnar Mills 19043b25cdeSGunnar Mills if (activationState == server::Activation::Activations::Active) 19143b25cdeSGunnar Mills { 19243b25cdeSGunnar Mills // Create an association to the BMC inventory item 19343b25cdeSGunnar Mills associations.emplace_back(std::make_tuple( 19443b25cdeSGunnar Mills ACTIVATION_FWD_ASSOCIATION, 19543b25cdeSGunnar Mills ACTIVATION_REV_ASSOCIATION, 19643b25cdeSGunnar Mills bmcInventoryPath)); 19743b25cdeSGunnar Mills 19843b25cdeSGunnar Mills // Create an active association since this image is active 19943b25cdeSGunnar Mills createActiveAssociation(path); 20043b25cdeSGunnar Mills } 20143b25cdeSGunnar Mills 202ee590c74SAdriana Kobylak // Create Version instance for this version. 203ee590c74SAdriana Kobylak auto versionPtr = std::make_unique<VersionClass>( 204ee590c74SAdriana Kobylak bus, 205ee590c74SAdriana Kobylak path, 206ee590c74SAdriana Kobylak version, 207ee590c74SAdriana Kobylak purpose, 208ee590c74SAdriana Kobylak ""); 209ee590c74SAdriana Kobylak auto isVersionFunctional = versionPtr->isFunctional(); 210ee590c74SAdriana Kobylak versions.insert(std::make_pair( 211ee590c74SAdriana Kobylak id, 212ee590c74SAdriana Kobylak std::move(versionPtr))); 213ee590c74SAdriana Kobylak 2141eef62deSSaqib Khan // Create Activation instance for this version. 215ba239881SSaqib Khan activations.insert(std::make_pair( 216ba239881SSaqib Khan id, 217ba239881SSaqib Khan std::make_unique<Activation>( 218ba239881SSaqib Khan bus, 219ba239881SSaqib Khan path, 2204c1aec09SSaqib Khan *this, 221ba239881SSaqib Khan id, 222b60add1eSGunnar Mills server::Activation::Activations::Active, 223b60add1eSGunnar Mills associations))); 2241eef62deSSaqib Khan 2251eef62deSSaqib Khan // If Active, create RedundancyPriority instance for this version. 2261eef62deSSaqib Khan if (activationState == server::Activation::Activations::Active) 2271eef62deSSaqib Khan { 2281eef62deSSaqib Khan uint8_t priority = std::numeric_limits<uint8_t>::max(); 2291eef62deSSaqib Khan if (!restoreFromFile(id, priority)) 2301eef62deSSaqib Khan { 231ee590c74SAdriana Kobylak if (isVersionFunctional) 232ee590c74SAdriana Kobylak { 233ee590c74SAdriana Kobylak priority = 0; 234ee590c74SAdriana Kobylak } 235ee590c74SAdriana Kobylak else 236ee590c74SAdriana Kobylak { 2371eef62deSSaqib Khan log<level::ERR>("Unable to restore priority from file.", 2381eef62deSSaqib Khan entry("VERSIONID=%s", id)); 2391eef62deSSaqib Khan } 240ee590c74SAdriana Kobylak } 2411eef62deSSaqib Khan activations.find(id)->second->redundancyPriority = 2421eef62deSSaqib Khan std::make_unique<RedundancyPriority>( 2431eef62deSSaqib Khan bus, 2441eef62deSSaqib Khan path, 2451eef62deSSaqib Khan *(activations.find(id)->second), 2461eef62deSSaqib Khan priority); 2471eef62deSSaqib Khan } 2481eef62deSSaqib Khan } 2491eef62deSSaqib Khan } 250dcbfa04aSSaqib Khan 251dcbfa04aSSaqib Khan // If there is no ubi volume for bmc version then read the /etc/os-release 252dcbfa04aSSaqib Khan // and create rofs-<versionId> under /media 253dcbfa04aSSaqib Khan if (activations.size() == 0) 254dcbfa04aSSaqib Khan { 255d16bcbd5SGunnar Mills auto version = VersionClass::getBMCVersion(OS_RELEASE_FILE); 256dcbfa04aSSaqib Khan auto id = phosphor::software::manager::Version::getId(version); 257dcbfa04aSSaqib Khan auto versionFileDir = BMC_ROFS_PREFIX + id + "/etc/"; 258dcbfa04aSSaqib Khan try 259dcbfa04aSSaqib Khan { 260dcbfa04aSSaqib Khan if (!fs::is_directory(versionFileDir)) 261dcbfa04aSSaqib Khan { 262dcbfa04aSSaqib Khan fs::create_directories(versionFileDir); 263dcbfa04aSSaqib Khan } 264dcbfa04aSSaqib Khan auto versionFilePath = BMC_ROFS_PREFIX + id + OS_RELEASE_FILE; 265dcbfa04aSSaqib Khan fs::create_directory_symlink(OS_RELEASE_FILE, versionFilePath); 266dcbfa04aSSaqib Khan ItemUpdater::processBMCImage(); 267dcbfa04aSSaqib Khan } 268dcbfa04aSSaqib Khan catch (const std::exception& e) 269dcbfa04aSSaqib Khan { 270dcbfa04aSSaqib Khan log<level::ERR>(e.what()); 271dcbfa04aSSaqib Khan } 272dcbfa04aSSaqib Khan } 273ba239881SSaqib Khan return; 274ba239881SSaqib Khan } 275ba239881SSaqib Khan 2763526ef73SLeonel Gonzalez void ItemUpdater::erase(std::string entryId) 2773526ef73SLeonel Gonzalez { 2786d873715SEddie James // Find entry in versions map 2796d873715SEddie James auto it = versions.find(entryId); 2806d873715SEddie James if (it != versions.end()) 2816d873715SEddie James { 2826d873715SEddie James if (it->second->isFunctional()) 2836d873715SEddie James { 2846d873715SEddie James log<level::ERR>(("Error: Version " + entryId + \ 2856d873715SEddie James " is currently running on the BMC." \ 2866d873715SEddie James " Unable to remove.").c_str()); 2876d873715SEddie James return; 2886d873715SEddie James } 2896d873715SEddie James 2906d873715SEddie James // Delete ReadOnly partitions if it's not active 2913526ef73SLeonel Gonzalez removeReadOnlyPartition(entryId); 2921eef62deSSaqib Khan removeFile(entryId); 2936d873715SEddie James } 2946d873715SEddie James else 2956d873715SEddie James { 2966d873715SEddie James // Delete ReadOnly partitions even if we can't find the version 2976d873715SEddie James removeReadOnlyPartition(entryId); 2986d873715SEddie James removeFile(entryId); 2996d873715SEddie James 3006d873715SEddie James log<level::ERR>(("Error: Failed to find version " + entryId + \ 3016d873715SEddie James " in item updater versions map." \ 3026d873715SEddie James " Unable to remove.").c_str()); 3036d873715SEddie James return; 3046d873715SEddie James } 3051eef62deSSaqib Khan 3061eef62deSSaqib Khan // Remove the priority environment variable. 3071eef62deSSaqib Khan auto serviceFile = "obmc-flash-bmc-setenv@" + entryId + ".service"; 3081eef62deSSaqib Khan auto method = bus.new_method_call( 3091eef62deSSaqib Khan SYSTEMD_BUSNAME, 3101eef62deSSaqib Khan SYSTEMD_PATH, 3111eef62deSSaqib Khan SYSTEMD_INTERFACE, 3121eef62deSSaqib Khan "StartUnit"); 3131eef62deSSaqib Khan method.append(serviceFile, "replace"); 3141eef62deSSaqib Khan bus.call_noreply(method); 3153526ef73SLeonel Gonzalez 3163526ef73SLeonel Gonzalez // Removing entry in versions map 3173526ef73SLeonel Gonzalez this->versions.erase(entryId); 3183526ef73SLeonel Gonzalez 3193526ef73SLeonel Gonzalez // Removing entry in activations map 3203526ef73SLeonel Gonzalez auto ita = activations.find(entryId); 3213526ef73SLeonel Gonzalez if (ita == activations.end()) 3223526ef73SLeonel Gonzalez { 3233526ef73SLeonel Gonzalez log<level::ERR>(("Error: Failed to find version " + entryId + \ 3243526ef73SLeonel Gonzalez " in item updater activations map." \ 3253526ef73SLeonel Gonzalez " Unable to remove.").c_str()); 3263526ef73SLeonel Gonzalez return; 3273526ef73SLeonel Gonzalez } 3283526ef73SLeonel Gonzalez 3293526ef73SLeonel Gonzalez this->activations.erase(entryId); 33049446ae9SSaqib Khan ItemUpdater::resetUbootEnvVars(); 3313526ef73SLeonel Gonzalez } 3323526ef73SLeonel Gonzalez 333bc1bf3afSMichael Tritz void ItemUpdater::deleteAll() 334bc1bf3afSMichael Tritz { 335bc1bf3afSMichael Tritz std::vector<std::string> deletableVersions; 336bc1bf3afSMichael Tritz 337bc1bf3afSMichael Tritz for (const auto& versionIt : versions) 338bc1bf3afSMichael Tritz { 339bc1bf3afSMichael Tritz if (!versionIt.second->isFunctional()) 340bc1bf3afSMichael Tritz { 341bc1bf3afSMichael Tritz deletableVersions.push_back(versionIt.first); 342bc1bf3afSMichael Tritz } 343bc1bf3afSMichael Tritz } 344bc1bf3afSMichael Tritz 345bc1bf3afSMichael Tritz for (const auto& deletableIt : deletableVersions) 346bc1bf3afSMichael Tritz { 347bc1bf3afSMichael Tritz ItemUpdater::erase(deletableIt); 348bc1bf3afSMichael Tritz } 349bc1bf3afSMichael Tritz 350bc1bf3afSMichael Tritz // Remove any volumes that do not match current versions. 351bc1bf3afSMichael Tritz auto method = bus.new_method_call( 352bc1bf3afSMichael Tritz SYSTEMD_BUSNAME, 353bc1bf3afSMichael Tritz SYSTEMD_PATH, 354bc1bf3afSMichael Tritz SYSTEMD_INTERFACE, 355bc1bf3afSMichael Tritz "StartUnit"); 356bc1bf3afSMichael Tritz method.append("obmc-flash-bmc-cleanup.service", "replace"); 357bc1bf3afSMichael Tritz bus.call_noreply(method); 358bc1bf3afSMichael Tritz } 359bc1bf3afSMichael Tritz 36035e83f3eSSaqib Khan ItemUpdater::ActivationStatus ItemUpdater::validateSquashFSImage( 36119177d3eSSaqib Khan const std::string& filePath) 36235e83f3eSSaqib Khan { 363b1cfdf99SMichael Tritz bool invalid = false; 36435e83f3eSSaqib Khan 365b1cfdf99SMichael Tritz for (auto& bmcImage : bmcImages) 366b1cfdf99SMichael Tritz { 36719177d3eSSaqib Khan fs::path file(filePath); 36835e83f3eSSaqib Khan file /= bmcImage; 36935e83f3eSSaqib Khan std::ifstream efile(file.c_str()); 370b1cfdf99SMichael Tritz if (efile.good() != 1) 37135e83f3eSSaqib Khan { 372b1cfdf99SMichael Tritz log<level::ERR>("Failed to find the BMC image.", 373b1cfdf99SMichael Tritz entry("IMAGE=%s", bmcImage.c_str())); 374b1cfdf99SMichael Tritz invalid = true; 37535e83f3eSSaqib Khan } 376b1cfdf99SMichael Tritz } 377b1cfdf99SMichael Tritz 378b1cfdf99SMichael Tritz if (invalid) 37935e83f3eSSaqib Khan { 38035e83f3eSSaqib Khan return ItemUpdater::ActivationStatus::invalid; 38135e83f3eSSaqib Khan } 382b1cfdf99SMichael Tritz 383b1cfdf99SMichael Tritz return ItemUpdater::ActivationStatus::ready; 38435e83f3eSSaqib Khan } 38535e83f3eSSaqib Khan 386b9da6634SSaqib Khan void ItemUpdater::freePriority(uint8_t value, const std::string& versionId) 3874c1aec09SSaqib Khan { 3884c1aec09SSaqib Khan //TODO openbmc/openbmc#1896 Improve the performance of this function 3894c1aec09SSaqib Khan for (const auto& intf : activations) 3904c1aec09SSaqib Khan { 3914c1aec09SSaqib Khan if (intf.second->redundancyPriority) 3924c1aec09SSaqib Khan { 393b9da6634SSaqib Khan if (intf.second->redundancyPriority.get()->priority() == value && 394b9da6634SSaqib Khan intf.second->versionId != versionId) 3954c1aec09SSaqib Khan { 3964c1aec09SSaqib Khan intf.second->redundancyPriority.get()->priority(value + 1); 3974c1aec09SSaqib Khan } 3984c1aec09SSaqib Khan } 3994c1aec09SSaqib Khan } 4004c1aec09SSaqib Khan } 4014c1aec09SSaqib Khan 40237a59043SMichael Tritz void ItemUpdater::reset() 40337a59043SMichael Tritz { 40437a59043SMichael Tritz // Mark the read-write partition for recreation upon reboot. 40537a59043SMichael Tritz auto method = bus.new_method_call( 40637a59043SMichael Tritz SYSTEMD_BUSNAME, 40737a59043SMichael Tritz SYSTEMD_PATH, 40837a59043SMichael Tritz SYSTEMD_INTERFACE, 40937a59043SMichael Tritz "StartUnit"); 4100129d926SMichael Tritz method.append("obmc-flash-bmc-setenv@rwreset\\x3dtrue.service", "replace"); 41137a59043SMichael Tritz bus.call_noreply(method); 41237a59043SMichael Tritz 41337a59043SMichael Tritz log<level::INFO>("BMC factory reset will take effect upon reboot."); 41437a59043SMichael Tritz 41537a59043SMichael Tritz return; 41637a59043SMichael Tritz } 41737a59043SMichael Tritz 4183526ef73SLeonel Gonzalez void ItemUpdater::removeReadOnlyPartition(std::string versionId) 4193526ef73SLeonel Gonzalez { 4203526ef73SLeonel Gonzalez auto serviceFile = "obmc-flash-bmc-ubiro-remove@" + versionId + 4213526ef73SLeonel Gonzalez ".service"; 4223526ef73SLeonel Gonzalez 4233526ef73SLeonel Gonzalez // Remove the read-only partitions. 4243526ef73SLeonel Gonzalez auto method = bus.new_method_call( 4253526ef73SLeonel Gonzalez SYSTEMD_BUSNAME, 4263526ef73SLeonel Gonzalez SYSTEMD_PATH, 4273526ef73SLeonel Gonzalez SYSTEMD_INTERFACE, 4283526ef73SLeonel Gonzalez "StartUnit"); 4293526ef73SLeonel Gonzalez method.append(serviceFile, "replace"); 4303526ef73SLeonel Gonzalez bus.call_noreply(method); 4313526ef73SLeonel Gonzalez } 4323526ef73SLeonel Gonzalez 4330129d926SMichael Tritz bool ItemUpdater::fieldModeEnabled(bool value) 4340129d926SMichael Tritz { 4350129d926SMichael Tritz // enabling field mode is intended to be one way: false -> true 4360129d926SMichael Tritz if (value && !control::FieldMode::fieldModeEnabled()) 4370129d926SMichael Tritz { 4380129d926SMichael Tritz control::FieldMode::fieldModeEnabled(value); 4390129d926SMichael Tritz 4400129d926SMichael Tritz auto method = bus.new_method_call( 4410129d926SMichael Tritz SYSTEMD_BUSNAME, 4420129d926SMichael Tritz SYSTEMD_PATH, 4430129d926SMichael Tritz SYSTEMD_INTERFACE, 4440129d926SMichael Tritz "StartUnit"); 4450129d926SMichael Tritz method.append("obmc-flash-bmc-setenv@fieldmode\\x3dtrue.service", 4460129d926SMichael Tritz "replace"); 4470129d926SMichael Tritz bus.call_noreply(method); 4480129d926SMichael Tritz 4490129d926SMichael Tritz method = bus.new_method_call( 4500129d926SMichael Tritz SYSTEMD_BUSNAME, 4510129d926SMichael Tritz SYSTEMD_PATH, 4520129d926SMichael Tritz SYSTEMD_INTERFACE, 4530129d926SMichael Tritz "StopUnit"); 4540129d926SMichael Tritz method.append("usr-local.mount", "replace"); 4550129d926SMichael Tritz bus.call_noreply(method); 4560129d926SMichael Tritz 4570129d926SMichael Tritz std::vector<std::string> usrLocal = {"usr-local.mount"}; 4580129d926SMichael Tritz 4590129d926SMichael Tritz method = bus.new_method_call( 4600129d926SMichael Tritz SYSTEMD_BUSNAME, 4610129d926SMichael Tritz SYSTEMD_PATH, 4620129d926SMichael Tritz SYSTEMD_INTERFACE, 4630129d926SMichael Tritz "MaskUnitFiles"); 4640129d926SMichael Tritz method.append(usrLocal, false, true); 4650129d926SMichael Tritz bus.call_noreply(method); 4660129d926SMichael Tritz } 4670129d926SMichael Tritz 4680129d926SMichael Tritz return control::FieldMode::fieldModeEnabled(); 4690129d926SMichael Tritz } 4700129d926SMichael Tritz 4710129d926SMichael Tritz void ItemUpdater::restoreFieldModeStatus() 4720129d926SMichael Tritz { 473*ff0b421dSMichael Tritz std::ifstream input("/dev/mtd/u-boot-env"); 4740129d926SMichael Tritz std::string envVar; 4750129d926SMichael Tritz std::getline(input, envVar); 4760129d926SMichael Tritz 4770129d926SMichael Tritz if (envVar.find("fieldmode=true") != std::string::npos) 4780129d926SMichael Tritz { 4790129d926SMichael Tritz ItemUpdater::fieldModeEnabled(true); 4800129d926SMichael Tritz } 4810129d926SMichael Tritz } 4820129d926SMichael Tritz 483b60add1eSGunnar Mills void ItemUpdater::setBMCInventoryPath() 484b60add1eSGunnar Mills { 485b60add1eSGunnar Mills //TODO: openbmc/openbmc#1786 - Get the BMC path by looking for objects 486b60add1eSGunnar Mills // that implement the BMC inventory interface 487b60add1eSGunnar Mills auto depth = 0; 488b60add1eSGunnar Mills auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, 489b60add1eSGunnar Mills MAPPER_PATH, 490b60add1eSGunnar Mills MAPPER_INTERFACE, 491b60add1eSGunnar Mills "GetSubTreePaths"); 492b60add1eSGunnar Mills 493b60add1eSGunnar Mills mapperCall.append(CHASSIS_INVENTORY_PATH); 494b60add1eSGunnar Mills mapperCall.append(depth); 495b60add1eSGunnar Mills 496b60add1eSGunnar Mills // TODO: openbmc/openbmc#2226 - Add Inventory Item filter when 497b60add1eSGunnar Mills // mapper is fixed. 498b60add1eSGunnar Mills std::vector<std::string> filter = {}; 499b60add1eSGunnar Mills mapperCall.append(filter); 500b60add1eSGunnar Mills 501b60add1eSGunnar Mills auto response = bus.call(mapperCall); 502b60add1eSGunnar Mills if (response.is_method_error()) 503b60add1eSGunnar Mills { 504b60add1eSGunnar Mills log<level::ERR>("Error in mapper GetSubTreePath"); 505b60add1eSGunnar Mills return; 506b60add1eSGunnar Mills } 507b60add1eSGunnar Mills 508b60add1eSGunnar Mills using ObjectPaths = std::vector<std::string>; 509b60add1eSGunnar Mills ObjectPaths result; 510b60add1eSGunnar Mills response.read(result); 511b60add1eSGunnar Mills 512b60add1eSGunnar Mills if (result.empty()) 513b60add1eSGunnar Mills { 514b60add1eSGunnar Mills log<level::ERR>("Invalid response from mapper"); 515b60add1eSGunnar Mills return; 516b60add1eSGunnar Mills } 517b60add1eSGunnar Mills 518b60add1eSGunnar Mills for (auto& iter : result) 519b60add1eSGunnar Mills { 520b60add1eSGunnar Mills const auto& path = iter; 521b60add1eSGunnar Mills if (path.substr(path.find_last_of('/') + 1).compare("bmc") == 0) 522b60add1eSGunnar Mills { 523b60add1eSGunnar Mills bmcInventoryPath = path; 524b60add1eSGunnar Mills return; 525b60add1eSGunnar Mills } 526b60add1eSGunnar Mills } 527b60add1eSGunnar Mills } 528b60add1eSGunnar Mills 529f10b2326SGunnar Mills void ItemUpdater::createActiveAssociation(const std::string& path) 530ded875dcSGunnar Mills { 531ded875dcSGunnar Mills assocs.emplace_back(std::make_tuple(ACTIVE_FWD_ASSOCIATION, 532ded875dcSGunnar Mills ACTIVE_REV_ASSOCIATION, 533ded875dcSGunnar Mills path)); 534ded875dcSGunnar Mills associations(assocs); 535ded875dcSGunnar Mills } 536ded875dcSGunnar Mills 53788e8a325SGunnar Mills void ItemUpdater::createFunctionalAssociation(const std::string& path) 53888e8a325SGunnar Mills { 53988e8a325SGunnar Mills assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION, 54088e8a325SGunnar Mills FUNCTIONAL_REV_ASSOCIATION, 54188e8a325SGunnar Mills path)); 54288e8a325SGunnar Mills associations(assocs); 54388e8a325SGunnar Mills } 54488e8a325SGunnar Mills 545f10b2326SGunnar Mills void ItemUpdater::removeActiveAssociation(const std::string& path) 546ded875dcSGunnar Mills { 547ded875dcSGunnar Mills for (auto iter = assocs.begin(); iter != assocs.end();) 548ded875dcSGunnar Mills { 54988e8a325SGunnar Mills // Since there could be multiple associations to the same path, 55088e8a325SGunnar Mills // only remove ones that have an active forward association. 55188e8a325SGunnar Mills if ((std::get<0>(*iter)).compare(ACTIVE_FWD_ASSOCIATION) == 0 && 55288e8a325SGunnar Mills (std::get<2>(*iter)).compare(path) == 0) 553ded875dcSGunnar Mills { 554ded875dcSGunnar Mills iter = assocs.erase(iter); 555ded875dcSGunnar Mills associations(assocs); 556ded875dcSGunnar Mills } 557ded875dcSGunnar Mills else 558ded875dcSGunnar Mills { 559ded875dcSGunnar Mills ++iter; 560ded875dcSGunnar Mills } 561ded875dcSGunnar Mills } 562ded875dcSGunnar Mills } 563ded875dcSGunnar Mills 564b9da6634SSaqib Khan bool ItemUpdater::isLowestPriority(uint8_t value) 565b9da6634SSaqib Khan { 566b9da6634SSaqib Khan for (const auto& intf : activations) 567b9da6634SSaqib Khan { 568b9da6634SSaqib Khan if (intf.second->redundancyPriority) 569b9da6634SSaqib Khan { 570b9da6634SSaqib Khan if (intf.second->redundancyPriority.get()->priority() < value) 571b9da6634SSaqib Khan { 572b9da6634SSaqib Khan return false; 573b9da6634SSaqib Khan } 574b9da6634SSaqib Khan } 575b9da6634SSaqib Khan } 576b9da6634SSaqib Khan return true; 577b9da6634SSaqib Khan } 578b9da6634SSaqib Khan 57949446ae9SSaqib Khan void ItemUpdater::resetUbootEnvVars() 58049446ae9SSaqib Khan { 58149446ae9SSaqib Khan decltype(activations.begin()->second->redundancyPriority.get()->priority()) 58249446ae9SSaqib Khan lowestPriority = std::numeric_limits<uint8_t>::max(); 58349446ae9SSaqib Khan decltype(activations.begin()->second->versionId) lowestPriorityVersion; 58449446ae9SSaqib Khan for (const auto& intf : activations) 58549446ae9SSaqib Khan { 58649446ae9SSaqib Khan if (!intf.second->redundancyPriority.get()) 58749446ae9SSaqib Khan { 58849446ae9SSaqib Khan // Skip this version if the redundancyPriority is not initialized. 58949446ae9SSaqib Khan continue; 59049446ae9SSaqib Khan } 59149446ae9SSaqib Khan 59249446ae9SSaqib Khan if (intf.second->redundancyPriority.get()->priority() 59349446ae9SSaqib Khan <= lowestPriority) 59449446ae9SSaqib Khan { 59549446ae9SSaqib Khan lowestPriority = intf.second->redundancyPriority.get()->priority(); 59649446ae9SSaqib Khan lowestPriorityVersion = intf.second->versionId; 59749446ae9SSaqib Khan } 59849446ae9SSaqib Khan } 59949446ae9SSaqib Khan 600f0382c35SSaqib Khan // Update the U-boot environment variable to point to the lowest priority 601f0382c35SSaqib Khan auto it = activations.find(lowestPriorityVersion); 602f0382c35SSaqib Khan it->second->updateUbootEnvVars(); 60349446ae9SSaqib Khan } 60449446ae9SSaqib Khan 605ec1b41c4SGunnar Mills } // namespace updater 606ec1b41c4SGunnar Mills } // namespace software 607ec1b41c4SGunnar Mills } // namespace phosphor 608