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 } 1407b5010f2SSaqib Khan else 1417b5010f2SSaqib Khan { 1427b5010f2SSaqib Khan log<level::INFO>("Software Object with the same version already exists", 1437b5010f2SSaqib Khan entry("VERSION_ID=%s", versionId)); 1447b5010f2SSaqib Khan } 145e75d10f5SPatrick Williams return; 146ec1b41c4SGunnar Mills } 147ec1b41c4SGunnar Mills 148ba239881SSaqib Khan void ItemUpdater::processBMCImage() 149ba239881SSaqib Khan { 15088e8a325SGunnar Mills using VersionClass = phosphor::software::manager::Version; 15188e8a325SGunnar Mills // Read os-release from /etc/ to get the functional BMC version 15288e8a325SGunnar Mills auto functionalVersion = VersionClass::getBMCVersion(OS_RELEASE_FILE); 15388e8a325SGunnar Mills 1541eef62deSSaqib Khan // Read os-release from folders under /media/ to get 1551eef62deSSaqib Khan // BMC Software Versions. 1561eef62deSSaqib Khan for (const auto& iter : fs::directory_iterator(MEDIA_DIR)) 1571eef62deSSaqib Khan { 1581eef62deSSaqib Khan auto activationState = server::Activation::Activations::Active; 1596fab70daSSaqib Khan static const auto BMC_RO_PREFIX_LEN = strlen(BMC_ROFS_PREFIX); 1601eef62deSSaqib Khan 1611eef62deSSaqib Khan // Check if the BMC_RO_PREFIXis the prefix of the iter.path 1621eef62deSSaqib Khan if (0 == iter.path().native().compare(0, BMC_RO_PREFIX_LEN, 1636fab70daSSaqib Khan BMC_ROFS_PREFIX)) 1641eef62deSSaqib Khan { 165021c365bSSaqib Khan // The versionId is extracted from the path 166021c365bSSaqib Khan // for example /media/ro-2a1022fe. 167021c365bSSaqib Khan auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN); 1681eef62deSSaqib Khan auto osRelease = iter.path() / OS_RELEASE_FILE; 1691eef62deSSaqib Khan if (!fs::is_regular_file(osRelease)) 1701eef62deSSaqib Khan { 1711eef62deSSaqib Khan log<level::ERR>("Failed to read osRelease\n", 1721eef62deSSaqib Khan entry("FileName=%s", osRelease.string())); 173021c365bSSaqib Khan ItemUpdater::erase(id); 174021c365bSSaqib Khan continue; 1751eef62deSSaqib Khan } 17688e8a325SGunnar Mills auto version = VersionClass::getBMCVersion(osRelease); 1771eef62deSSaqib Khan if (version.empty()) 1781eef62deSSaqib Khan { 1791eef62deSSaqib Khan log<level::ERR>("Failed to read version from osRelease", 1801eef62deSSaqib Khan entry("FILENAME=%s", osRelease.string())); 1811eef62deSSaqib Khan activationState = server::Activation::Activations::Invalid; 1821eef62deSSaqib Khan } 183021c365bSSaqib Khan 1841eef62deSSaqib Khan auto purpose = server::Version::VersionPurpose::BMC; 1851eef62deSSaqib Khan auto path = fs::path(SOFTWARE_OBJPATH) / id; 1861eef62deSSaqib Khan 18788e8a325SGunnar Mills // Create functional association if this is the functional version 18888e8a325SGunnar Mills if (version.compare(functionalVersion) == 0) 18988e8a325SGunnar Mills { 19088e8a325SGunnar Mills createFunctionalAssociation(path); 19188e8a325SGunnar Mills } 19288e8a325SGunnar Mills 19343b25cdeSGunnar Mills AssociationList associations = {}; 19443b25cdeSGunnar Mills 19543b25cdeSGunnar Mills if (activationState == server::Activation::Activations::Active) 19643b25cdeSGunnar Mills { 19743b25cdeSGunnar Mills // Create an association to the BMC inventory item 19843b25cdeSGunnar Mills associations.emplace_back(std::make_tuple( 19943b25cdeSGunnar Mills ACTIVATION_FWD_ASSOCIATION, 20043b25cdeSGunnar Mills ACTIVATION_REV_ASSOCIATION, 20143b25cdeSGunnar Mills bmcInventoryPath)); 20243b25cdeSGunnar Mills 20343b25cdeSGunnar Mills // Create an active association since this image is active 20443b25cdeSGunnar Mills createActiveAssociation(path); 20543b25cdeSGunnar Mills } 20643b25cdeSGunnar Mills 207ee590c74SAdriana Kobylak // Create Version instance for this version. 208ee590c74SAdriana Kobylak auto versionPtr = std::make_unique<VersionClass>( 209ee590c74SAdriana Kobylak bus, 210ee590c74SAdriana Kobylak path, 211ee590c74SAdriana Kobylak version, 212ee590c74SAdriana Kobylak purpose, 213ee590c74SAdriana Kobylak ""); 214ee590c74SAdriana Kobylak auto isVersionFunctional = versionPtr->isFunctional(); 215ee590c74SAdriana Kobylak versions.insert(std::make_pair( 216ee590c74SAdriana Kobylak id, 217ee590c74SAdriana Kobylak std::move(versionPtr))); 218ee590c74SAdriana Kobylak 2191eef62deSSaqib Khan // Create Activation instance for this version. 220ba239881SSaqib Khan activations.insert(std::make_pair( 221ba239881SSaqib Khan id, 222ba239881SSaqib Khan std::make_unique<Activation>( 223ba239881SSaqib Khan bus, 224ba239881SSaqib Khan path, 2254c1aec09SSaqib Khan *this, 226ba239881SSaqib Khan id, 227b60add1eSGunnar Mills server::Activation::Activations::Active, 228b60add1eSGunnar Mills associations))); 2291eef62deSSaqib Khan 2301eef62deSSaqib Khan // If Active, create RedundancyPriority instance for this version. 2311eef62deSSaqib Khan if (activationState == server::Activation::Activations::Active) 2321eef62deSSaqib Khan { 2331eef62deSSaqib Khan uint8_t priority = std::numeric_limits<uint8_t>::max(); 2341eef62deSSaqib Khan if (!restoreFromFile(id, priority)) 2351eef62deSSaqib Khan { 236ee590c74SAdriana Kobylak if (isVersionFunctional) 237ee590c74SAdriana Kobylak { 238ee590c74SAdriana Kobylak priority = 0; 239ee590c74SAdriana Kobylak } 240ee590c74SAdriana Kobylak else 241ee590c74SAdriana Kobylak { 2421eef62deSSaqib Khan log<level::ERR>("Unable to restore priority from file.", 2431eef62deSSaqib Khan entry("VERSIONID=%s", id)); 2441eef62deSSaqib Khan } 245ee590c74SAdriana Kobylak } 2461eef62deSSaqib Khan activations.find(id)->second->redundancyPriority = 2471eef62deSSaqib Khan std::make_unique<RedundancyPriority>( 2481eef62deSSaqib Khan bus, 2491eef62deSSaqib Khan path, 2501eef62deSSaqib Khan *(activations.find(id)->second), 2511eef62deSSaqib Khan priority); 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 { 260*d16bcbd5SGunnar 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 } 278ba239881SSaqib Khan return; 279ba239881SSaqib Khan } 280ba239881SSaqib Khan 2813526ef73SLeonel Gonzalez void ItemUpdater::erase(std::string entryId) 2823526ef73SLeonel Gonzalez { 2836d873715SEddie James // Find entry in versions map 2846d873715SEddie James auto it = versions.find(entryId); 2856d873715SEddie James if (it != versions.end()) 2866d873715SEddie James { 2876d873715SEddie James if (it->second->isFunctional()) 2886d873715SEddie James { 2896d873715SEddie James log<level::ERR>(("Error: Version " + entryId + \ 2906d873715SEddie James " is currently running on the BMC." \ 2916d873715SEddie James " Unable to remove.").c_str()); 2926d873715SEddie James return; 2936d873715SEddie James } 2946d873715SEddie James 2956d873715SEddie James // Delete ReadOnly partitions if it's not active 2963526ef73SLeonel Gonzalez removeReadOnlyPartition(entryId); 2971eef62deSSaqib Khan removeFile(entryId); 2986d873715SEddie James } 2996d873715SEddie James else 3006d873715SEddie James { 3016d873715SEddie James // Delete ReadOnly partitions even if we can't find the version 3026d873715SEddie James removeReadOnlyPartition(entryId); 3036d873715SEddie James removeFile(entryId); 3046d873715SEddie James 3056d873715SEddie James log<level::ERR>(("Error: Failed to find version " + entryId + \ 3066d873715SEddie James " in item updater versions map." \ 3076d873715SEddie James " Unable to remove.").c_str()); 3086d873715SEddie James return; 3096d873715SEddie James } 3101eef62deSSaqib Khan 3111eef62deSSaqib Khan // Remove the priority environment variable. 3121eef62deSSaqib Khan auto serviceFile = "obmc-flash-bmc-setenv@" + entryId + ".service"; 3131eef62deSSaqib Khan auto method = bus.new_method_call( 3141eef62deSSaqib Khan SYSTEMD_BUSNAME, 3151eef62deSSaqib Khan SYSTEMD_PATH, 3161eef62deSSaqib Khan SYSTEMD_INTERFACE, 3171eef62deSSaqib Khan "StartUnit"); 3181eef62deSSaqib Khan method.append(serviceFile, "replace"); 3191eef62deSSaqib Khan bus.call_noreply(method); 3203526ef73SLeonel Gonzalez 3213526ef73SLeonel Gonzalez // Removing entry in versions map 3223526ef73SLeonel Gonzalez this->versions.erase(entryId); 3233526ef73SLeonel Gonzalez 3243526ef73SLeonel Gonzalez // Removing entry in activations map 3253526ef73SLeonel Gonzalez auto ita = activations.find(entryId); 3263526ef73SLeonel Gonzalez if (ita == activations.end()) 3273526ef73SLeonel Gonzalez { 3283526ef73SLeonel Gonzalez log<level::ERR>(("Error: Failed to find version " + entryId + \ 3293526ef73SLeonel Gonzalez " in item updater activations map." \ 3303526ef73SLeonel Gonzalez " Unable to remove.").c_str()); 3313526ef73SLeonel Gonzalez return; 3323526ef73SLeonel Gonzalez } 3333526ef73SLeonel Gonzalez 3343526ef73SLeonel Gonzalez this->activations.erase(entryId); 3353526ef73SLeonel Gonzalez } 3363526ef73SLeonel Gonzalez 337bc1bf3afSMichael Tritz void ItemUpdater::deleteAll() 338bc1bf3afSMichael Tritz { 339bc1bf3afSMichael Tritz std::vector<std::string> deletableVersions; 340bc1bf3afSMichael Tritz 341bc1bf3afSMichael Tritz for (const auto& versionIt : versions) 342bc1bf3afSMichael Tritz { 343bc1bf3afSMichael Tritz if (!versionIt.second->isFunctional()) 344bc1bf3afSMichael Tritz { 345bc1bf3afSMichael Tritz deletableVersions.push_back(versionIt.first); 346bc1bf3afSMichael Tritz } 347bc1bf3afSMichael Tritz } 348bc1bf3afSMichael Tritz 349bc1bf3afSMichael Tritz for (const auto& deletableIt : deletableVersions) 350bc1bf3afSMichael Tritz { 351bc1bf3afSMichael Tritz ItemUpdater::erase(deletableIt); 352bc1bf3afSMichael Tritz } 353bc1bf3afSMichael Tritz 354bc1bf3afSMichael Tritz // Remove any volumes that do not match current versions. 355bc1bf3afSMichael Tritz auto method = bus.new_method_call( 356bc1bf3afSMichael Tritz SYSTEMD_BUSNAME, 357bc1bf3afSMichael Tritz SYSTEMD_PATH, 358bc1bf3afSMichael Tritz SYSTEMD_INTERFACE, 359bc1bf3afSMichael Tritz "StartUnit"); 360bc1bf3afSMichael Tritz method.append("obmc-flash-bmc-cleanup.service", "replace"); 361bc1bf3afSMichael Tritz bus.call_noreply(method); 362bc1bf3afSMichael Tritz } 363bc1bf3afSMichael Tritz 36435e83f3eSSaqib Khan ItemUpdater::ActivationStatus ItemUpdater::validateSquashFSImage( 36519177d3eSSaqib Khan const std::string& filePath) 36635e83f3eSSaqib Khan { 367b1cfdf99SMichael Tritz bool invalid = false; 36835e83f3eSSaqib Khan 369b1cfdf99SMichael Tritz for (auto& bmcImage : bmcImages) 370b1cfdf99SMichael Tritz { 37119177d3eSSaqib Khan fs::path file(filePath); 37235e83f3eSSaqib Khan file /= bmcImage; 37335e83f3eSSaqib Khan std::ifstream efile(file.c_str()); 374b1cfdf99SMichael Tritz if (efile.good() != 1) 37535e83f3eSSaqib Khan { 376b1cfdf99SMichael Tritz log<level::ERR>("Failed to find the BMC image.", 377b1cfdf99SMichael Tritz entry("IMAGE=%s", bmcImage.c_str())); 378b1cfdf99SMichael Tritz invalid = true; 37935e83f3eSSaqib Khan } 380b1cfdf99SMichael Tritz } 381b1cfdf99SMichael Tritz 382b1cfdf99SMichael Tritz if (invalid) 38335e83f3eSSaqib Khan { 38435e83f3eSSaqib Khan return ItemUpdater::ActivationStatus::invalid; 38535e83f3eSSaqib Khan } 386b1cfdf99SMichael Tritz 387b1cfdf99SMichael Tritz return ItemUpdater::ActivationStatus::ready; 38835e83f3eSSaqib Khan } 38935e83f3eSSaqib Khan 390b9da6634SSaqib Khan void ItemUpdater::freePriority(uint8_t value, const std::string& versionId) 3914c1aec09SSaqib Khan { 3924c1aec09SSaqib Khan //TODO openbmc/openbmc#1896 Improve the performance of this function 3934c1aec09SSaqib Khan for (const auto& intf : activations) 3944c1aec09SSaqib Khan { 3954c1aec09SSaqib Khan if (intf.second->redundancyPriority) 3964c1aec09SSaqib Khan { 397b9da6634SSaqib Khan if (intf.second->redundancyPriority.get()->priority() == value && 398b9da6634SSaqib Khan intf.second->versionId != versionId) 3994c1aec09SSaqib Khan { 4004c1aec09SSaqib Khan intf.second->redundancyPriority.get()->priority(value + 1); 4014c1aec09SSaqib Khan } 4024c1aec09SSaqib Khan } 4034c1aec09SSaqib Khan } 4044c1aec09SSaqib Khan } 4054c1aec09SSaqib Khan 40637a59043SMichael Tritz void ItemUpdater::reset() 40737a59043SMichael Tritz { 40837a59043SMichael Tritz // Mark the read-write partition for recreation upon reboot. 40937a59043SMichael Tritz auto method = bus.new_method_call( 41037a59043SMichael Tritz SYSTEMD_BUSNAME, 41137a59043SMichael Tritz SYSTEMD_PATH, 41237a59043SMichael Tritz SYSTEMD_INTERFACE, 41337a59043SMichael Tritz "StartUnit"); 4140129d926SMichael Tritz method.append("obmc-flash-bmc-setenv@rwreset\\x3dtrue.service", "replace"); 41537a59043SMichael Tritz bus.call_noreply(method); 41637a59043SMichael Tritz 41737a59043SMichael Tritz log<level::INFO>("BMC factory reset will take effect upon reboot."); 41837a59043SMichael Tritz 41937a59043SMichael Tritz return; 42037a59043SMichael Tritz } 42137a59043SMichael Tritz 4223526ef73SLeonel Gonzalez void ItemUpdater::removeReadOnlyPartition(std::string versionId) 4233526ef73SLeonel Gonzalez { 4243526ef73SLeonel Gonzalez auto serviceFile = "obmc-flash-bmc-ubiro-remove@" + versionId + 4253526ef73SLeonel Gonzalez ".service"; 4263526ef73SLeonel Gonzalez 4273526ef73SLeonel Gonzalez // Remove the read-only partitions. 4283526ef73SLeonel Gonzalez auto method = bus.new_method_call( 4293526ef73SLeonel Gonzalez SYSTEMD_BUSNAME, 4303526ef73SLeonel Gonzalez SYSTEMD_PATH, 4313526ef73SLeonel Gonzalez SYSTEMD_INTERFACE, 4323526ef73SLeonel Gonzalez "StartUnit"); 4333526ef73SLeonel Gonzalez method.append(serviceFile, "replace"); 4343526ef73SLeonel Gonzalez bus.call_noreply(method); 4353526ef73SLeonel Gonzalez } 4363526ef73SLeonel Gonzalez 4370129d926SMichael Tritz bool ItemUpdater::fieldModeEnabled(bool value) 4380129d926SMichael Tritz { 4390129d926SMichael Tritz // enabling field mode is intended to be one way: false -> true 4400129d926SMichael Tritz if (value && !control::FieldMode::fieldModeEnabled()) 4410129d926SMichael Tritz { 4420129d926SMichael Tritz control::FieldMode::fieldModeEnabled(value); 4430129d926SMichael Tritz 4440129d926SMichael Tritz auto method = bus.new_method_call( 4450129d926SMichael Tritz SYSTEMD_BUSNAME, 4460129d926SMichael Tritz SYSTEMD_PATH, 4470129d926SMichael Tritz SYSTEMD_INTERFACE, 4480129d926SMichael Tritz "StartUnit"); 4490129d926SMichael Tritz method.append("obmc-flash-bmc-setenv@fieldmode\\x3dtrue.service", 4500129d926SMichael Tritz "replace"); 4510129d926SMichael Tritz bus.call_noreply(method); 4520129d926SMichael Tritz 4530129d926SMichael Tritz method = bus.new_method_call( 4540129d926SMichael Tritz SYSTEMD_BUSNAME, 4550129d926SMichael Tritz SYSTEMD_PATH, 4560129d926SMichael Tritz SYSTEMD_INTERFACE, 4570129d926SMichael Tritz "StopUnit"); 4580129d926SMichael Tritz method.append("usr-local.mount", "replace"); 4590129d926SMichael Tritz bus.call_noreply(method); 4600129d926SMichael Tritz 4610129d926SMichael Tritz std::vector<std::string> usrLocal = {"usr-local.mount"}; 4620129d926SMichael Tritz 4630129d926SMichael Tritz method = bus.new_method_call( 4640129d926SMichael Tritz SYSTEMD_BUSNAME, 4650129d926SMichael Tritz SYSTEMD_PATH, 4660129d926SMichael Tritz SYSTEMD_INTERFACE, 4670129d926SMichael Tritz "MaskUnitFiles"); 4680129d926SMichael Tritz method.append(usrLocal, false, true); 4690129d926SMichael Tritz bus.call_noreply(method); 4700129d926SMichael Tritz } 4710129d926SMichael Tritz 4720129d926SMichael Tritz return control::FieldMode::fieldModeEnabled(); 4730129d926SMichael Tritz } 4740129d926SMichael Tritz 4750129d926SMichael Tritz void ItemUpdater::restoreFieldModeStatus() 4760129d926SMichael Tritz { 4770129d926SMichael Tritz std::ifstream input("/run/fw_env"); 4780129d926SMichael Tritz std::string envVar; 4790129d926SMichael Tritz std::getline(input, envVar); 4800129d926SMichael Tritz 4810129d926SMichael Tritz if (envVar.find("fieldmode=true") != std::string::npos) 4820129d926SMichael Tritz { 4830129d926SMichael Tritz ItemUpdater::fieldModeEnabled(true); 4840129d926SMichael Tritz } 4850129d926SMichael Tritz } 4860129d926SMichael Tritz 487b60add1eSGunnar Mills void ItemUpdater::setBMCInventoryPath() 488b60add1eSGunnar Mills { 489b60add1eSGunnar Mills //TODO: openbmc/openbmc#1786 - Get the BMC path by looking for objects 490b60add1eSGunnar Mills // that implement the BMC inventory interface 491b60add1eSGunnar Mills auto depth = 0; 492b60add1eSGunnar Mills auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, 493b60add1eSGunnar Mills MAPPER_PATH, 494b60add1eSGunnar Mills MAPPER_INTERFACE, 495b60add1eSGunnar Mills "GetSubTreePaths"); 496b60add1eSGunnar Mills 497b60add1eSGunnar Mills mapperCall.append(CHASSIS_INVENTORY_PATH); 498b60add1eSGunnar Mills mapperCall.append(depth); 499b60add1eSGunnar Mills 500b60add1eSGunnar Mills // TODO: openbmc/openbmc#2226 - Add Inventory Item filter when 501b60add1eSGunnar Mills // mapper is fixed. 502b60add1eSGunnar Mills std::vector<std::string> filter = {}; 503b60add1eSGunnar Mills mapperCall.append(filter); 504b60add1eSGunnar Mills 505b60add1eSGunnar Mills auto response = bus.call(mapperCall); 506b60add1eSGunnar Mills if (response.is_method_error()) 507b60add1eSGunnar Mills { 508b60add1eSGunnar Mills log<level::ERR>("Error in mapper GetSubTreePath"); 509b60add1eSGunnar Mills return; 510b60add1eSGunnar Mills } 511b60add1eSGunnar Mills 512b60add1eSGunnar Mills using ObjectPaths = std::vector<std::string>; 513b60add1eSGunnar Mills ObjectPaths result; 514b60add1eSGunnar Mills response.read(result); 515b60add1eSGunnar Mills 516b60add1eSGunnar Mills if (result.empty()) 517b60add1eSGunnar Mills { 518b60add1eSGunnar Mills log<level::ERR>("Invalid response from mapper"); 519b60add1eSGunnar Mills return; 520b60add1eSGunnar Mills } 521b60add1eSGunnar Mills 522b60add1eSGunnar Mills for (auto& iter : result) 523b60add1eSGunnar Mills { 524b60add1eSGunnar Mills const auto& path = iter; 525b60add1eSGunnar Mills if (path.substr(path.find_last_of('/') + 1).compare("bmc") == 0) 526b60add1eSGunnar Mills { 527b60add1eSGunnar Mills bmcInventoryPath = path; 528b60add1eSGunnar Mills return; 529b60add1eSGunnar Mills } 530b60add1eSGunnar Mills } 531b60add1eSGunnar Mills } 532b60add1eSGunnar Mills 533f10b2326SGunnar Mills void ItemUpdater::createActiveAssociation(const std::string& path) 534ded875dcSGunnar Mills { 535ded875dcSGunnar Mills assocs.emplace_back(std::make_tuple(ACTIVE_FWD_ASSOCIATION, 536ded875dcSGunnar Mills ACTIVE_REV_ASSOCIATION, 537ded875dcSGunnar Mills path)); 538ded875dcSGunnar Mills associations(assocs); 539ded875dcSGunnar Mills } 540ded875dcSGunnar Mills 54188e8a325SGunnar Mills void ItemUpdater::createFunctionalAssociation(const std::string& path) 54288e8a325SGunnar Mills { 54388e8a325SGunnar Mills assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION, 54488e8a325SGunnar Mills FUNCTIONAL_REV_ASSOCIATION, 54588e8a325SGunnar Mills path)); 54688e8a325SGunnar Mills associations(assocs); 54788e8a325SGunnar Mills } 54888e8a325SGunnar Mills 549f10b2326SGunnar Mills void ItemUpdater::removeActiveAssociation(const std::string& path) 550ded875dcSGunnar Mills { 551ded875dcSGunnar Mills for (auto iter = assocs.begin(); iter != assocs.end();) 552ded875dcSGunnar Mills { 55388e8a325SGunnar Mills // Since there could be multiple associations to the same path, 55488e8a325SGunnar Mills // only remove ones that have an active forward association. 55588e8a325SGunnar Mills if ((std::get<0>(*iter)).compare(ACTIVE_FWD_ASSOCIATION) == 0 && 55688e8a325SGunnar Mills (std::get<2>(*iter)).compare(path) == 0) 557ded875dcSGunnar Mills { 558ded875dcSGunnar Mills iter = assocs.erase(iter); 559ded875dcSGunnar Mills associations(assocs); 560ded875dcSGunnar Mills } 561ded875dcSGunnar Mills else 562ded875dcSGunnar Mills { 563ded875dcSGunnar Mills ++iter; 564ded875dcSGunnar Mills } 565ded875dcSGunnar Mills } 566ded875dcSGunnar Mills } 567ded875dcSGunnar Mills 568b9da6634SSaqib Khan bool ItemUpdater::isLowestPriority(uint8_t value) 569b9da6634SSaqib Khan { 570b9da6634SSaqib Khan for (const auto& intf : activations) 571b9da6634SSaqib Khan { 572b9da6634SSaqib Khan if (intf.second->redundancyPriority) 573b9da6634SSaqib Khan { 574b9da6634SSaqib Khan if (intf.second->redundancyPriority.get()->priority() < value) 575b9da6634SSaqib Khan { 576b9da6634SSaqib Khan return false; 577b9da6634SSaqib Khan } 578b9da6634SSaqib Khan } 579b9da6634SSaqib Khan } 580b9da6634SSaqib Khan return true; 581b9da6634SSaqib Khan } 582b9da6634SSaqib Khan 583ec1b41c4SGunnar Mills } // namespace updater 584ec1b41c4SGunnar Mills } // namespace software 585ec1b41c4SGunnar Mills } // namespace phosphor 586