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" 81fd6dddfSChanh Nguyen #include "xyz/openbmc_project/Software/ExtendedVersion/server.hpp" 9b0ce996aSGunnar Mills #include "xyz/openbmc_project/Software/Version/server.hpp" 10b0ce996aSGunnar Mills 11d5b8f75cSAdriana Kobylak #include <phosphor-logging/elog-errors.hpp> 12b0ce996aSGunnar Mills #include <phosphor-logging/elog.hpp> 13c9bb6425SPatrick Williams #include <phosphor-logging/lg2.hpp> 1458aa7508SAdriana Kobylak #include <xyz/openbmc_project/Common/error.hpp> 1558aa7508SAdriana Kobylak #include <xyz/openbmc_project/Software/Image/error.hpp> 1658aa7508SAdriana Kobylak 1758aa7508SAdriana Kobylak #include <filesystem> 1858aa7508SAdriana Kobylak #include <fstream> 19204e1e74SAdriana Kobylak #include <queue> 20b77551cdSAdriana Kobylak #include <set> 21ec1b41c4SGunnar Mills #include <string> 22ec1b41c4SGunnar Mills 23ec1b41c4SGunnar Mills namespace phosphor 24ec1b41c4SGunnar Mills { 25ec1b41c4SGunnar Mills namespace software 26ec1b41c4SGunnar Mills { 27ec1b41c4SGunnar Mills namespace updater 28ec1b41c4SGunnar Mills { 29ec1b41c4SGunnar Mills 302ce7da29SGunnar Mills // When you see server:: you know we're referencing our base class 312ce7da29SGunnar Mills namespace server = sdbusplus::xyz::openbmc_project::Software::server; 320129d926SMichael Tritz namespace control = sdbusplus::xyz::openbmc_project::Control::server; 332ce7da29SGunnar Mills 34c9bb6425SPatrick Williams PHOSPHOR_LOG2_USING; 352ce7da29SGunnar Mills using namespace phosphor::logging; 3643699ca7SAdriana Kobylak using namespace sdbusplus::xyz::openbmc_project::Software::Image::Error; 372ab9b109SJayanth Othayoth using namespace phosphor::software::image; 38c98d912eSAdriana Kobylak namespace fs = std::filesystem; 39d5b8f75cSAdriana Kobylak using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed; 4035e83f3eSSaqib Khan 41e75d10f5SPatrick Williams void ItemUpdater::createActivation(sdbusplus::message::message& msg) 42ec1b41c4SGunnar Mills { 4384a0e693SSaqib Khan 4484a0e693SSaqib Khan using SVersion = server::Version; 4584a0e693SSaqib Khan using VersionPurpose = SVersion::VersionPurpose; 469a782243SGunnar Mills using VersionClass = phosphor::software::manager::Version; 4784a0e693SSaqib Khan 48bc1facd7SPatrick Williams sdbusplus::message::object_path objPath; 4984a0e693SSaqib Khan auto purpose = VersionPurpose::Unknown; 501fd6dddfSChanh Nguyen std::string extendedVersion; 51705f1bfcSSaqib Khan std::string version; 52bc1facd7SPatrick Williams std::map<std::string, std::map<std::string, std::variant<std::string>>> 532285fe0fSAdriana Kobylak interfaces; 54e75d10f5SPatrick Williams msg.read(objPath, interfaces); 552ce7da29SGunnar Mills std::string path(std::move(objPath)); 5619177d3eSSaqib Khan std::string filePath; 572ce7da29SGunnar Mills 582ce7da29SGunnar Mills for (const auto& intf : interfaces) 592ce7da29SGunnar Mills { 60705f1bfcSSaqib Khan if (intf.first == VERSION_IFACE) 612ce7da29SGunnar Mills { 622ce7da29SGunnar Mills for (const auto& property : intf.second) 632ce7da29SGunnar Mills { 64705f1bfcSSaqib Khan if (property.first == "Purpose") 652ce7da29SGunnar Mills { 6684a0e693SSaqib Khan auto value = SVersion::convertVersionPurposeFromString( 67e883fb8bSPatrick Williams std::get<std::string>(property.second)); 6884a0e693SSaqib Khan if (value == VersionPurpose::BMC || 69e9f6c845SVijay Khemka #ifdef HOST_BIOS_UPGRADE 70e9f6c845SVijay Khemka value == VersionPurpose::Host || 71e9f6c845SVijay Khemka #endif 7284a0e693SSaqib Khan value == VersionPurpose::System) 7384a0e693SSaqib Khan { 7484a0e693SSaqib Khan purpose = value; 7584a0e693SSaqib Khan } 76705f1bfcSSaqib Khan } 77705f1bfcSSaqib Khan else if (property.first == "Version") 78705f1bfcSSaqib Khan { 79e883fb8bSPatrick Williams version = std::get<std::string>(property.second); 80705f1bfcSSaqib Khan } 81705f1bfcSSaqib Khan } 82705f1bfcSSaqib Khan } 8319177d3eSSaqib Khan else if (intf.first == FILEPATH_IFACE) 8419177d3eSSaqib Khan { 8519177d3eSSaqib Khan for (const auto& property : intf.second) 8619177d3eSSaqib Khan { 8719177d3eSSaqib Khan if (property.first == "Path") 8819177d3eSSaqib Khan { 89e883fb8bSPatrick Williams filePath = std::get<std::string>(property.second); 9019177d3eSSaqib Khan } 9119177d3eSSaqib Khan } 9219177d3eSSaqib Khan } 931fd6dddfSChanh Nguyen else if (intf.first == EXTENDED_VERSION_IFACE) 941fd6dddfSChanh Nguyen { 951fd6dddfSChanh Nguyen for (const auto& property : intf.second) 961fd6dddfSChanh Nguyen { 971fd6dddfSChanh Nguyen if (property.first == "ExtendedVersion") 981fd6dddfSChanh Nguyen { 991fd6dddfSChanh Nguyen extendedVersion = std::get<std::string>(property.second); 1001fd6dddfSChanh Nguyen } 1011fd6dddfSChanh Nguyen } 1021fd6dddfSChanh Nguyen } 103705f1bfcSSaqib Khan } 1042285fe0fSAdriana Kobylak if (version.empty() || filePath.empty() || 10584a0e693SSaqib Khan purpose == VersionPurpose::Unknown) 1062ce7da29SGunnar Mills { 107e75d10f5SPatrick Williams return; 1082ce7da29SGunnar Mills } 1092ce7da29SGunnar Mills 1102ce7da29SGunnar Mills // Version id is the last item in the path 1112ce7da29SGunnar Mills auto pos = path.rfind("/"); 1122ce7da29SGunnar Mills if (pos == std::string::npos) 1132ce7da29SGunnar Mills { 114c9bb6425SPatrick Williams error("No version id found in object path: {PATH}", "PATH", path); 115e75d10f5SPatrick Williams return; 1162ce7da29SGunnar Mills } 1172ce7da29SGunnar Mills 1182ce7da29SGunnar Mills auto versionId = path.substr(pos + 1); 1192ce7da29SGunnar Mills 120e75d10f5SPatrick Williams if (activations.find(versionId) == activations.end()) 1212ce7da29SGunnar Mills { 12235e83f3eSSaqib Khan // Determine the Activation state by processing the given image dir. 12335e83f3eSSaqib Khan auto activationState = server::Activation::Activations::Invalid; 124e9f6c845SVijay Khemka ItemUpdater::ActivationStatus result; 125e9f6c845SVijay Khemka if (purpose == VersionPurpose::BMC || purpose == VersionPurpose::System) 126e9f6c845SVijay Khemka result = ItemUpdater::validateSquashFSImage(filePath); 127e9f6c845SVijay Khemka else 128e9f6c845SVijay Khemka result = ItemUpdater::ActivationStatus::ready; 129e9f6c845SVijay Khemka 13043b25cdeSGunnar Mills AssociationList associations = {}; 13143b25cdeSGunnar Mills 13235e83f3eSSaqib Khan if (result == ItemUpdater::ActivationStatus::ready) 13335e83f3eSSaqib Khan { 13435e83f3eSSaqib Khan activationState = server::Activation::Activations::Ready; 135b60add1eSGunnar Mills // Create an association to the BMC inventory item 1362285fe0fSAdriana Kobylak associations.emplace_back( 1372285fe0fSAdriana Kobylak std::make_tuple(ACTIVATION_FWD_ASSOCIATION, 1382285fe0fSAdriana Kobylak ACTIVATION_REV_ASSOCIATION, bmcInventoryPath)); 13943b25cdeSGunnar Mills } 140b60add1eSGunnar Mills 141ee13e831SSaqib Khan activations.insert(std::make_pair( 142ee13e831SSaqib Khan versionId, 1432285fe0fSAdriana Kobylak std::make_unique<Activation>(bus, path, *this, versionId, 1442285fe0fSAdriana Kobylak activationState, associations))); 1454254beceSMichael Tritz 146ee13e831SSaqib Khan auto versionPtr = std::make_unique<VersionClass>( 1471fd6dddfSChanh Nguyen bus, path, version, purpose, extendedVersion, filePath, 1482285fe0fSAdriana Kobylak std::bind(&ItemUpdater::erase, this, std::placeholders::_1)); 149ee13e831SSaqib Khan versionPtr->deleteObject = 1502285fe0fSAdriana Kobylak std::make_unique<phosphor::software::manager::Delete>(bus, path, 1512285fe0fSAdriana Kobylak *versionPtr); 152ee13e831SSaqib Khan versions.insert(std::make_pair(versionId, std::move(versionPtr))); 1532ce7da29SGunnar Mills } 154e75d10f5SPatrick Williams return; 155ec1b41c4SGunnar Mills } 156ec1b41c4SGunnar Mills 157ba239881SSaqib Khan void ItemUpdater::processBMCImage() 158ba239881SSaqib Khan { 15988e8a325SGunnar Mills using VersionClass = phosphor::software::manager::Version; 160269bff30SLei YU 161269bff30SLei YU // Check MEDIA_DIR and create if it does not exist 162269bff30SLei YU try 163269bff30SLei YU { 164269bff30SLei YU if (!fs::is_directory(MEDIA_DIR)) 165269bff30SLei YU { 166269bff30SLei YU fs::create_directory(MEDIA_DIR); 167269bff30SLei YU } 168269bff30SLei YU } 169269bff30SLei YU catch (const fs::filesystem_error& e) 170269bff30SLei YU { 171c9bb6425SPatrick Williams error("Failed to prepare dir: {ERROR}", "ERROR", e); 172269bff30SLei YU return; 173269bff30SLei YU } 174269bff30SLei YU 17588e8a325SGunnar Mills // Read os-release from /etc/ to get the functional BMC version 17688e8a325SGunnar Mills auto functionalVersion = VersionClass::getBMCVersion(OS_RELEASE_FILE); 17788e8a325SGunnar Mills 1781eef62deSSaqib Khan // Read os-release from folders under /media/ to get 1791eef62deSSaqib Khan // BMC Software Versions. 1801eef62deSSaqib Khan for (const auto& iter : fs::directory_iterator(MEDIA_DIR)) 1811eef62deSSaqib Khan { 1821eef62deSSaqib Khan auto activationState = server::Activation::Activations::Active; 1836fab70daSSaqib Khan static const auto BMC_RO_PREFIX_LEN = strlen(BMC_ROFS_PREFIX); 1841eef62deSSaqib Khan 1851eef62deSSaqib Khan // Check if the BMC_RO_PREFIXis the prefix of the iter.path 1862285fe0fSAdriana Kobylak if (0 == 1872285fe0fSAdriana Kobylak iter.path().native().compare(0, BMC_RO_PREFIX_LEN, BMC_ROFS_PREFIX)) 1881eef62deSSaqib Khan { 189716cd78dSAdriana Kobylak // Get the version to calculate the id 19024a8d83dSAdriana Kobylak fs::path releaseFile(OS_RELEASE_FILE); 19124a8d83dSAdriana Kobylak auto osRelease = iter.path() / releaseFile.relative_path(); 1921eef62deSSaqib Khan if (!fs::is_regular_file(osRelease)) 1931eef62deSSaqib Khan { 194c9bb6425SPatrick Williams error("Failed to read osRelease: {PATH}", "PATH", osRelease); 195716cd78dSAdriana Kobylak 196716cd78dSAdriana Kobylak // Try to get the version id from the mount directory name and 197716cd78dSAdriana Kobylak // call to delete it as this version may be corrupted. Dynamic 198716cd78dSAdriana Kobylak // volumes created by the UBI layout for example have the id in 199716cd78dSAdriana Kobylak // the mount directory name. The worst that can happen is that 200716cd78dSAdriana Kobylak // erase() is called with an non-existent id and returns. 201716cd78dSAdriana Kobylak auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN); 202021c365bSSaqib Khan ItemUpdater::erase(id); 203716cd78dSAdriana Kobylak 204021c365bSSaqib Khan continue; 2051eef62deSSaqib Khan } 20688e8a325SGunnar Mills auto version = VersionClass::getBMCVersion(osRelease); 2071eef62deSSaqib Khan if (version.empty()) 2081eef62deSSaqib Khan { 209c9bb6425SPatrick Williams error("Failed to read version from osRelease: {PATH}", "PATH", 210c9bb6425SPatrick Williams osRelease); 211716cd78dSAdriana Kobylak 212716cd78dSAdriana Kobylak // Try to delete the version, same as above if the 213716cd78dSAdriana Kobylak // OS_RELEASE_FILE does not exist. 214716cd78dSAdriana Kobylak auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN); 215716cd78dSAdriana Kobylak ItemUpdater::erase(id); 216716cd78dSAdriana Kobylak 217716cd78dSAdriana Kobylak continue; 2181eef62deSSaqib Khan } 219021c365bSSaqib Khan 220716cd78dSAdriana Kobylak auto id = VersionClass::getId(version); 221716cd78dSAdriana Kobylak 222f383d27aSAdriana Kobylak // Check if the id has already been added. This can happen if the 223f383d27aSAdriana Kobylak // BMC partitions / devices were manually flashed with the same 224f383d27aSAdriana Kobylak // image. 225f383d27aSAdriana Kobylak if (versions.find(id) != versions.end()) 226f383d27aSAdriana Kobylak { 227f383d27aSAdriana Kobylak continue; 228f383d27aSAdriana Kobylak } 229f383d27aSAdriana Kobylak 2301eef62deSSaqib Khan auto purpose = server::Version::VersionPurpose::BMC; 231ec4eec34SAdriana Kobylak restorePurpose(id, purpose); 232ec4eec34SAdriana Kobylak 2331fd6dddfSChanh Nguyen // Read os-release from /etc/ to get the BMC extended version 2341fd6dddfSChanh Nguyen std::string extendedVersion = 2351fd6dddfSChanh Nguyen VersionClass::getBMCExtendedVersion(osRelease); 2361fd6dddfSChanh Nguyen 2371eef62deSSaqib Khan auto path = fs::path(SOFTWARE_OBJPATH) / id; 2381eef62deSSaqib Khan 239269bff30SLei YU // Create functional association if this is the functional 240269bff30SLei YU // version 24188e8a325SGunnar Mills if (version.compare(functionalVersion) == 0) 24288e8a325SGunnar Mills { 24388e8a325SGunnar Mills createFunctionalAssociation(path); 24488e8a325SGunnar Mills } 24588e8a325SGunnar Mills 24643b25cdeSGunnar Mills AssociationList associations = {}; 24743b25cdeSGunnar Mills 24843b25cdeSGunnar Mills if (activationState == server::Activation::Activations::Active) 24943b25cdeSGunnar Mills { 25043b25cdeSGunnar Mills // Create an association to the BMC inventory item 25143b25cdeSGunnar Mills associations.emplace_back(std::make_tuple( 2522285fe0fSAdriana Kobylak ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION, 25343b25cdeSGunnar Mills bmcInventoryPath)); 25443b25cdeSGunnar Mills 25543b25cdeSGunnar Mills // Create an active association since this image is active 25643b25cdeSGunnar Mills createActiveAssociation(path); 25743b25cdeSGunnar Mills } 25843b25cdeSGunnar Mills 259bbebec79SAppaRao Puli // All updateable firmware components must expose the updateable 260bbebec79SAppaRao Puli // association. 261bbebec79SAppaRao Puli createUpdateableAssociation(path); 262bbebec79SAppaRao Puli 263ee590c74SAdriana Kobylak // Create Version instance for this version. 264ee590c74SAdriana Kobylak auto versionPtr = std::make_unique<VersionClass>( 2651fd6dddfSChanh Nguyen bus, path, version, purpose, extendedVersion, "", 2662285fe0fSAdriana Kobylak std::bind(&ItemUpdater::erase, this, std::placeholders::_1)); 267ee590c74SAdriana Kobylak auto isVersionFunctional = versionPtr->isFunctional(); 268ee13e831SSaqib Khan if (!isVersionFunctional) 269ee13e831SSaqib Khan { 270ee13e831SSaqib Khan versionPtr->deleteObject = 271ee13e831SSaqib Khan std::make_unique<phosphor::software::manager::Delete>( 272ee13e831SSaqib Khan bus, path, *versionPtr); 273ee13e831SSaqib Khan } 2742285fe0fSAdriana Kobylak versions.insert(std::make_pair(id, std::move(versionPtr))); 275ee590c74SAdriana Kobylak 2761eef62deSSaqib Khan // Create Activation instance for this version. 277ee13e831SSaqib Khan activations.insert(std::make_pair( 2782285fe0fSAdriana Kobylak id, std::make_unique<Activation>( 2792285fe0fSAdriana Kobylak bus, path, *this, id, activationState, associations))); 2801eef62deSSaqib Khan 281269bff30SLei YU // If Active, create RedundancyPriority instance for this 282269bff30SLei YU // version. 2831eef62deSSaqib Khan if (activationState == server::Activation::Activations::Active) 2841eef62deSSaqib Khan { 2851eef62deSSaqib Khan uint8_t priority = std::numeric_limits<uint8_t>::max(); 286687e75e2SAdriana Kobylak if (!restorePriority(id, priority)) 2871eef62deSSaqib Khan { 288ee590c74SAdriana Kobylak if (isVersionFunctional) 289ee590c74SAdriana Kobylak { 290ee590c74SAdriana Kobylak priority = 0; 291ee590c74SAdriana Kobylak } 292ee590c74SAdriana Kobylak else 293ee590c74SAdriana Kobylak { 294c9bb6425SPatrick Williams error( 295c9bb6425SPatrick Williams "Unable to restore priority from file for {VERSIONID}", 296c9bb6425SPatrick Williams "VERSIONID", id); 2971eef62deSSaqib Khan } 298ee590c74SAdriana Kobylak } 2991eef62deSSaqib Khan activations.find(id)->second->redundancyPriority = 3001eef62deSSaqib Khan std::make_unique<RedundancyPriority>( 3012285fe0fSAdriana Kobylak bus, path, *(activations.find(id)->second), priority, 302b77551cdSAdriana Kobylak false); 3031eef62deSSaqib Khan } 3041eef62deSSaqib Khan } 3051eef62deSSaqib Khan } 306dcbfa04aSSaqib Khan 307716cd78dSAdriana Kobylak // If there are no bmc versions mounted under MEDIA_DIR, then read the 308716cd78dSAdriana Kobylak // /etc/os-release and create rofs-<versionId> under MEDIA_DIR, then call 309716cd78dSAdriana Kobylak // again processBMCImage() to create the D-Bus interface for it. 310dcbfa04aSSaqib Khan if (activations.size() == 0) 311dcbfa04aSSaqib Khan { 312d16bcbd5SGunnar Mills auto version = VersionClass::getBMCVersion(OS_RELEASE_FILE); 313dcbfa04aSSaqib Khan auto id = phosphor::software::manager::Version::getId(version); 314dcbfa04aSSaqib Khan auto versionFileDir = BMC_ROFS_PREFIX + id + "/etc/"; 315dcbfa04aSSaqib Khan try 316dcbfa04aSSaqib Khan { 317dcbfa04aSSaqib Khan if (!fs::is_directory(versionFileDir)) 318dcbfa04aSSaqib Khan { 319dcbfa04aSSaqib Khan fs::create_directories(versionFileDir); 320dcbfa04aSSaqib Khan } 321dcbfa04aSSaqib Khan auto versionFilePath = BMC_ROFS_PREFIX + id + OS_RELEASE_FILE; 322dcbfa04aSSaqib Khan fs::create_directory_symlink(OS_RELEASE_FILE, versionFilePath); 323dcbfa04aSSaqib Khan ItemUpdater::processBMCImage(); 324dcbfa04aSSaqib Khan } 325dcbfa04aSSaqib Khan catch (const std::exception& e) 326dcbfa04aSSaqib Khan { 327c9bb6425SPatrick Williams error("Exception during processing: {ERROR}", "ERROR", e); 328dcbfa04aSSaqib Khan } 329dcbfa04aSSaqib Khan } 330eaa1ee05SEddie James 331eaa1ee05SEddie James mirrorUbootToAlt(); 332ba239881SSaqib Khan return; 333ba239881SSaqib Khan } 334ba239881SSaqib Khan 3353526ef73SLeonel Gonzalez void ItemUpdater::erase(std::string entryId) 3363526ef73SLeonel Gonzalez { 3376d873715SEddie James // Find entry in versions map 3386d873715SEddie James auto it = versions.find(entryId); 3396d873715SEddie James if (it != versions.end()) 3406d873715SEddie James { 3410f88b5afSLei YU if (it->second->isFunctional() && ACTIVE_BMC_MAX_ALLOWED > 1) 3426d873715SEddie James { 343c9bb6425SPatrick Williams error( 344c9bb6425SPatrick Williams "Version ({VERSIONID}) is currently running on the BMC; unable to remove.", 345c9bb6425SPatrick Williams "VERSIONID", entryId); 3466d873715SEddie James return; 3476d873715SEddie James } 348d1a55adcSAdriana Kobylak } 3496d873715SEddie James 350d1a55adcSAdriana Kobylak // First call resetUbootEnvVars() so that the BMC points to a valid image to 351d1a55adcSAdriana Kobylak // boot from. If resetUbootEnvVars() is called after the image is actually 352d1a55adcSAdriana Kobylak // deleted from the BMC flash, there'd be a time window where the BMC would 353d1a55adcSAdriana Kobylak // be pointing to a non-existent image to boot from. 354d1a55adcSAdriana Kobylak // Need to remove the entries from the activations map before that call so 355d1a55adcSAdriana Kobylak // that resetUbootEnvVars() doesn't use the version to be deleted. 356d1a55adcSAdriana Kobylak auto iteratorActivations = activations.find(entryId); 357d1a55adcSAdriana Kobylak if (iteratorActivations == activations.end()) 358d1a55adcSAdriana Kobylak { 359c9bb6425SPatrick Williams error( 360c9bb6425SPatrick Williams "Failed to find version ({VERSIONID}) in item updater activations map; unable to remove.", 361c9bb6425SPatrick Williams "VERSIONID", entryId); 362d1a55adcSAdriana Kobylak } 363d1a55adcSAdriana Kobylak else 364d1a55adcSAdriana Kobylak { 365d1a55adcSAdriana Kobylak removeAssociations(iteratorActivations->second->path); 366d1a55adcSAdriana Kobylak this->activations.erase(entryId); 367d1a55adcSAdriana Kobylak } 368d1a55adcSAdriana Kobylak ItemUpdater::resetUbootEnvVars(); 369d1a55adcSAdriana Kobylak 370d1a55adcSAdriana Kobylak if (it != versions.end()) 371d1a55adcSAdriana Kobylak { 3726d873715SEddie James // Delete ReadOnly partitions if it's not active 3733526ef73SLeonel Gonzalez removeReadOnlyPartition(entryId); 374687e75e2SAdriana Kobylak removePersistDataDirectory(entryId); 375ee13e831SSaqib Khan 376ee13e831SSaqib Khan // Removing entry in versions map 377ee13e831SSaqib Khan this->versions.erase(entryId); 3786d873715SEddie James } 3796d873715SEddie James else 3806d873715SEddie James { 3816d873715SEddie James // Delete ReadOnly partitions even if we can't find the version 3826d873715SEddie James removeReadOnlyPartition(entryId); 383687e75e2SAdriana Kobylak removePersistDataDirectory(entryId); 3846d873715SEddie James 385c9bb6425SPatrick Williams error( 386c9bb6425SPatrick Williams "Failed to find version ({VERSIONID}) in item updater versions map; unable to remove.", 387c9bb6425SPatrick Williams "VERSIONID", entryId); 3886d873715SEddie James } 3891eef62deSSaqib Khan 39056aaf454SLei YU helper.clearEntry(entryId); 3913526ef73SLeonel Gonzalez 392ee13e831SSaqib Khan return; 3933526ef73SLeonel Gonzalez } 3943526ef73SLeonel Gonzalez 395bc1bf3afSMichael Tritz void ItemUpdater::deleteAll() 396bc1bf3afSMichael Tritz { 39783cd21fbSAdriana Kobylak std::vector<std::string> deletableVersions; 39883cd21fbSAdriana Kobylak 399bc1bf3afSMichael Tritz for (const auto& versionIt : versions) 400bc1bf3afSMichael Tritz { 401bc1bf3afSMichael Tritz if (!versionIt.second->isFunctional()) 402bc1bf3afSMichael Tritz { 40383cd21fbSAdriana Kobylak deletableVersions.push_back(versionIt.first); 404bc1bf3afSMichael Tritz } 405bc1bf3afSMichael Tritz } 406bc1bf3afSMichael Tritz 40783cd21fbSAdriana Kobylak for (const auto& deletableIt : deletableVersions) 40883cd21fbSAdriana Kobylak { 40983cd21fbSAdriana Kobylak ItemUpdater::erase(deletableIt); 41083cd21fbSAdriana Kobylak } 41183cd21fbSAdriana Kobylak 41256aaf454SLei YU helper.cleanup(); 413bc1bf3afSMichael Tritz } 414bc1bf3afSMichael Tritz 4152285fe0fSAdriana Kobylak ItemUpdater::ActivationStatus 4162285fe0fSAdriana Kobylak ItemUpdater::validateSquashFSImage(const std::string& filePath) 41735e83f3eSSaqib Khan { 4188e9ccfe7SBright Cheng bool valid = true; 41935e83f3eSSaqib Khan 4208e9ccfe7SBright Cheng // Record the images which are being updated 4218e9ccfe7SBright Cheng // First check for the fullimage, then check for images with partitions 4228e9ccfe7SBright Cheng imageUpdateList.push_back(bmcFullImages); 4238e9ccfe7SBright Cheng valid = checkImage(filePath, imageUpdateList); 4248e9ccfe7SBright Cheng if (!valid) 425b1cfdf99SMichael Tritz { 4268e9ccfe7SBright Cheng imageUpdateList.clear(); 4278e9ccfe7SBright Cheng imageUpdateList.assign(bmcImages.begin(), bmcImages.end()); 4288e9ccfe7SBright Cheng valid = checkImage(filePath, imageUpdateList); 4298e9ccfe7SBright Cheng if (!valid) 43035e83f3eSSaqib Khan { 431c9bb6425SPatrick Williams error("Failed to find the needed BMC images."); 43235e83f3eSSaqib Khan return ItemUpdater::ActivationStatus::invalid; 43335e83f3eSSaqib Khan } 4348e9ccfe7SBright Cheng } 435b1cfdf99SMichael Tritz 436b1cfdf99SMichael Tritz return ItemUpdater::ActivationStatus::ready; 43735e83f3eSSaqib Khan } 43835e83f3eSSaqib Khan 439bbcb7be1SAdriana Kobylak void ItemUpdater::savePriority(const std::string& versionId, uint8_t value) 440bbcb7be1SAdriana Kobylak { 441687e75e2SAdriana Kobylak storePriority(versionId, value); 442bbcb7be1SAdriana Kobylak helper.setEntry(versionId, value); 443bbcb7be1SAdriana Kobylak } 444bbcb7be1SAdriana Kobylak 445b9da6634SSaqib Khan void ItemUpdater::freePriority(uint8_t value, const std::string& versionId) 4464c1aec09SSaqib Khan { 447b77551cdSAdriana Kobylak std::map<std::string, uint8_t> priorityMap; 448b77551cdSAdriana Kobylak 449b77551cdSAdriana Kobylak // Insert the requested version and priority, it may not exist yet. 450b77551cdSAdriana Kobylak priorityMap.insert(std::make_pair(versionId, value)); 451b77551cdSAdriana Kobylak 4524c1aec09SSaqib Khan for (const auto& intf : activations) 4534c1aec09SSaqib Khan { 4544c1aec09SSaqib Khan if (intf.second->redundancyPriority) 4554c1aec09SSaqib Khan { 456b77551cdSAdriana Kobylak priorityMap.insert(std::make_pair( 4572285fe0fSAdriana Kobylak intf.first, intf.second->redundancyPriority.get()->priority())); 458b77551cdSAdriana Kobylak } 459b77551cdSAdriana Kobylak } 460b77551cdSAdriana Kobylak 461b77551cdSAdriana Kobylak // Lambda function to compare 2 priority values, use <= to allow duplicates 4622285fe0fSAdriana Kobylak typedef std::function<bool(std::pair<std::string, uint8_t>, 4632285fe0fSAdriana Kobylak std::pair<std::string, uint8_t>)> 4642285fe0fSAdriana Kobylak cmpPriority; 4652285fe0fSAdriana Kobylak cmpPriority cmpPriorityFunc = 4662285fe0fSAdriana Kobylak [](std::pair<std::string, uint8_t> priority1, 4672285fe0fSAdriana Kobylak std::pair<std::string, uint8_t> priority2) { 468b77551cdSAdriana Kobylak return priority1.second <= priority2.second; 469b77551cdSAdriana Kobylak }; 470b77551cdSAdriana Kobylak 471b77551cdSAdriana Kobylak // Sort versions by ascending priority 472b77551cdSAdriana Kobylak std::set<std::pair<std::string, uint8_t>, cmpPriority> prioritySet( 473b77551cdSAdriana Kobylak priorityMap.begin(), priorityMap.end(), cmpPriorityFunc); 474b77551cdSAdriana Kobylak 475b77551cdSAdriana Kobylak auto freePriorityValue = value; 476b77551cdSAdriana Kobylak for (auto& element : prioritySet) 477b77551cdSAdriana Kobylak { 478b77551cdSAdriana Kobylak if (element.first == versionId) 479b77551cdSAdriana Kobylak { 480b77551cdSAdriana Kobylak continue; 481b77551cdSAdriana Kobylak } 482b77551cdSAdriana Kobylak if (element.second == freePriorityValue) 483b77551cdSAdriana Kobylak { 484b77551cdSAdriana Kobylak ++freePriorityValue; 485b77551cdSAdriana Kobylak auto it = activations.find(element.first); 486b77551cdSAdriana Kobylak it->second->redundancyPriority.get()->sdbusPriority( 487b77551cdSAdriana Kobylak freePriorityValue); 4884c1aec09SSaqib Khan } 4894c1aec09SSaqib Khan } 490b77551cdSAdriana Kobylak 491b77551cdSAdriana Kobylak auto lowestVersion = prioritySet.begin()->first; 492b77551cdSAdriana Kobylak if (value == prioritySet.begin()->second) 493b77551cdSAdriana Kobylak { 494b77551cdSAdriana Kobylak lowestVersion = versionId; 4954c1aec09SSaqib Khan } 496b77551cdSAdriana Kobylak updateUbootEnvVars(lowestVersion); 4974c1aec09SSaqib Khan } 4984c1aec09SSaqib Khan 49937a59043SMichael Tritz void ItemUpdater::reset() 50037a59043SMichael Tritz { 50156aaf454SLei YU helper.factoryReset(); 50237a59043SMichael Tritz 503c9bb6425SPatrick Williams info("BMC factory reset will take effect upon reboot."); 50437a59043SMichael Tritz } 50537a59043SMichael Tritz 5063526ef73SLeonel Gonzalez void ItemUpdater::removeReadOnlyPartition(std::string versionId) 5073526ef73SLeonel Gonzalez { 50856aaf454SLei YU helper.removeVersion(versionId); 5093526ef73SLeonel Gonzalez } 5103526ef73SLeonel Gonzalez 5110129d926SMichael Tritz bool ItemUpdater::fieldModeEnabled(bool value) 5120129d926SMichael Tritz { 5130129d926SMichael Tritz // enabling field mode is intended to be one way: false -> true 5140129d926SMichael Tritz if (value && !control::FieldMode::fieldModeEnabled()) 5150129d926SMichael Tritz { 5160129d926SMichael Tritz control::FieldMode::fieldModeEnabled(value); 5170129d926SMichael Tritz 51822848eceSAdriana Kobylak auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, 51922848eceSAdriana Kobylak SYSTEMD_INTERFACE, "StartUnit"); 52022848eceSAdriana Kobylak method.append("obmc-flash-bmc-setenv@fieldmode\\x3dtrue.service", 52122848eceSAdriana Kobylak "replace"); 52222848eceSAdriana Kobylak bus.call_noreply(method); 52322848eceSAdriana Kobylak 52422848eceSAdriana Kobylak method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, 52522848eceSAdriana Kobylak SYSTEMD_INTERFACE, "StopUnit"); 52622848eceSAdriana Kobylak method.append("usr-local.mount", "replace"); 52722848eceSAdriana Kobylak bus.call_noreply(method); 52822848eceSAdriana Kobylak 52922848eceSAdriana Kobylak std::vector<std::string> usrLocal = {"usr-local.mount"}; 53022848eceSAdriana Kobylak 53122848eceSAdriana Kobylak method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, 53222848eceSAdriana Kobylak SYSTEMD_INTERFACE, "MaskUnitFiles"); 53322848eceSAdriana Kobylak method.append(usrLocal, false, true); 53422848eceSAdriana Kobylak bus.call_noreply(method); 5350129d926SMichael Tritz } 536d5b8f75cSAdriana Kobylak else if (!value && control::FieldMode::fieldModeEnabled()) 537d5b8f75cSAdriana Kobylak { 538d5b8f75cSAdriana Kobylak elog<NotAllowed>(xyz::openbmc_project::Common::NotAllowed::REASON( 539d5b8f75cSAdriana Kobylak "FieldMode is not allowed to be cleared")); 540d5b8f75cSAdriana Kobylak } 5410129d926SMichael Tritz 5420129d926SMichael Tritz return control::FieldMode::fieldModeEnabled(); 5430129d926SMichael Tritz } 5440129d926SMichael Tritz 5450129d926SMichael Tritz void ItemUpdater::restoreFieldModeStatus() 5460129d926SMichael Tritz { 547ff0b421dSMichael Tritz std::ifstream input("/dev/mtd/u-boot-env"); 5480129d926SMichael Tritz std::string envVar; 5490129d926SMichael Tritz std::getline(input, envVar); 5500129d926SMichael Tritz 5510129d926SMichael Tritz if (envVar.find("fieldmode=true") != std::string::npos) 5520129d926SMichael Tritz { 5530129d926SMichael Tritz ItemUpdater::fieldModeEnabled(true); 5540129d926SMichael Tritz } 5550129d926SMichael Tritz } 5560129d926SMichael Tritz 557b60add1eSGunnar Mills void ItemUpdater::setBMCInventoryPath() 558b60add1eSGunnar Mills { 559b60add1eSGunnar Mills auto depth = 0; 5602285fe0fSAdriana Kobylak auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH, 5612285fe0fSAdriana Kobylak MAPPER_INTERFACE, "GetSubTreePaths"); 562b60add1eSGunnar Mills 5631254c628SAdriana Kobylak mapperCall.append(INVENTORY_PATH); 564b60add1eSGunnar Mills mapperCall.append(depth); 5651254c628SAdriana Kobylak std::vector<std::string> filter = {BMC_INVENTORY_INTERFACE}; 566b60add1eSGunnar Mills mapperCall.append(filter); 567b60add1eSGunnar Mills 56887c78173SEd Tanous try 569b60add1eSGunnar Mills { 57087c78173SEd Tanous auto response = bus.call(mapperCall); 571b60add1eSGunnar Mills 572b60add1eSGunnar Mills using ObjectPaths = std::vector<std::string>; 573b60add1eSGunnar Mills ObjectPaths result; 574b60add1eSGunnar Mills response.read(result); 575b60add1eSGunnar Mills 5761254c628SAdriana Kobylak if (!result.empty()) 577b60add1eSGunnar Mills { 5781254c628SAdriana Kobylak bmcInventoryPath = result.front(); 579b60add1eSGunnar Mills } 58087c78173SEd Tanous } 581*4ce901c5SPatrick Williams catch (const sdbusplus::exception::exception& e) 58287c78173SEd Tanous { 583c9bb6425SPatrick Williams error("Error in mapper GetSubTreePath: {ERROR}", "ERROR", e); 58487c78173SEd Tanous return; 58587c78173SEd Tanous } 586b60add1eSGunnar Mills 587b60add1eSGunnar Mills return; 588b60add1eSGunnar Mills } 589b60add1eSGunnar Mills 590f10b2326SGunnar Mills void ItemUpdater::createActiveAssociation(const std::string& path) 591ded875dcSGunnar Mills { 5922285fe0fSAdriana Kobylak assocs.emplace_back( 5932285fe0fSAdriana Kobylak std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path)); 594ded875dcSGunnar Mills associations(assocs); 595ded875dcSGunnar Mills } 596ded875dcSGunnar Mills 59788e8a325SGunnar Mills void ItemUpdater::createFunctionalAssociation(const std::string& path) 59888e8a325SGunnar Mills { 59988e8a325SGunnar Mills assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION, 6002285fe0fSAdriana Kobylak FUNCTIONAL_REV_ASSOCIATION, path)); 60188e8a325SGunnar Mills associations(assocs); 60288e8a325SGunnar Mills } 60388e8a325SGunnar Mills 604bbebec79SAppaRao Puli void ItemUpdater::createUpdateableAssociation(const std::string& path) 605bbebec79SAppaRao Puli { 606bbebec79SAppaRao Puli assocs.emplace_back(std::make_tuple(UPDATEABLE_FWD_ASSOCIATION, 607bbebec79SAppaRao Puli UPDATEABLE_REV_ASSOCIATION, path)); 608bbebec79SAppaRao Puli associations(assocs); 609bbebec79SAppaRao Puli } 610bbebec79SAppaRao Puli 611991af7ecSAdriana Kobylak void ItemUpdater::removeAssociations(const std::string& path) 612ded875dcSGunnar Mills { 613ded875dcSGunnar Mills for (auto iter = assocs.begin(); iter != assocs.end();) 614ded875dcSGunnar Mills { 615991af7ecSAdriana Kobylak if ((std::get<2>(*iter)).compare(path) == 0) 616ded875dcSGunnar Mills { 617ded875dcSGunnar Mills iter = assocs.erase(iter); 618ded875dcSGunnar Mills associations(assocs); 619ded875dcSGunnar Mills } 620ded875dcSGunnar Mills else 621ded875dcSGunnar Mills { 622ded875dcSGunnar Mills ++iter; 623ded875dcSGunnar Mills } 624ded875dcSGunnar Mills } 625ded875dcSGunnar Mills } 626ded875dcSGunnar Mills 627b9da6634SSaqib Khan bool ItemUpdater::isLowestPriority(uint8_t value) 628b9da6634SSaqib Khan { 629b9da6634SSaqib Khan for (const auto& intf : activations) 630b9da6634SSaqib Khan { 631b9da6634SSaqib Khan if (intf.second->redundancyPriority) 632b9da6634SSaqib Khan { 633b9da6634SSaqib Khan if (intf.second->redundancyPriority.get()->priority() < value) 634b9da6634SSaqib Khan { 635b9da6634SSaqib Khan return false; 636b9da6634SSaqib Khan } 637b9da6634SSaqib Khan } 638b9da6634SSaqib Khan } 639b9da6634SSaqib Khan return true; 640b9da6634SSaqib Khan } 641b9da6634SSaqib Khan 642b77551cdSAdriana Kobylak void ItemUpdater::updateUbootEnvVars(const std::string& versionId) 643b77551cdSAdriana Kobylak { 64456aaf454SLei YU helper.updateUbootVersionId(versionId); 645b77551cdSAdriana Kobylak } 646b77551cdSAdriana Kobylak 64749446ae9SSaqib Khan void ItemUpdater::resetUbootEnvVars() 64849446ae9SSaqib Khan { 64949446ae9SSaqib Khan decltype(activations.begin()->second->redundancyPriority.get()->priority()) 65049446ae9SSaqib Khan lowestPriority = std::numeric_limits<uint8_t>::max(); 65149446ae9SSaqib Khan decltype(activations.begin()->second->versionId) lowestPriorityVersion; 65249446ae9SSaqib Khan for (const auto& intf : activations) 65349446ae9SSaqib Khan { 65449446ae9SSaqib Khan if (!intf.second->redundancyPriority.get()) 65549446ae9SSaqib Khan { 65649446ae9SSaqib Khan // Skip this version if the redundancyPriority is not initialized. 65749446ae9SSaqib Khan continue; 65849446ae9SSaqib Khan } 65949446ae9SSaqib Khan 6602285fe0fSAdriana Kobylak if (intf.second->redundancyPriority.get()->priority() <= lowestPriority) 66149446ae9SSaqib Khan { 66249446ae9SSaqib Khan lowestPriority = intf.second->redundancyPriority.get()->priority(); 66349446ae9SSaqib Khan lowestPriorityVersion = intf.second->versionId; 66449446ae9SSaqib Khan } 66549446ae9SSaqib Khan } 66649446ae9SSaqib Khan 667f0382c35SSaqib Khan // Update the U-boot environment variable to point to the lowest priority 668b77551cdSAdriana Kobylak updateUbootEnvVars(lowestPriorityVersion); 66949446ae9SSaqib Khan } 67049446ae9SSaqib Khan 671a6963590SAdriana Kobylak void ItemUpdater::freeSpace(Activation& caller) 672204e1e74SAdriana Kobylak { 673204e1e74SAdriana Kobylak // Versions with the highest priority in front 674204e1e74SAdriana Kobylak std::priority_queue<std::pair<int, std::string>, 675204e1e74SAdriana Kobylak std::vector<std::pair<int, std::string>>, 6762285fe0fSAdriana Kobylak std::less<std::pair<int, std::string>>> 6772285fe0fSAdriana Kobylak versionsPQ; 678204e1e74SAdriana Kobylak 679204e1e74SAdriana Kobylak std::size_t count = 0; 680204e1e74SAdriana Kobylak for (const auto& iter : activations) 681204e1e74SAdriana Kobylak { 682204e1e74SAdriana Kobylak if ((iter.second.get()->activation() == 683204e1e74SAdriana Kobylak server::Activation::Activations::Active) || 684204e1e74SAdriana Kobylak (iter.second.get()->activation() == 685204e1e74SAdriana Kobylak server::Activation::Activations::Failed)) 686204e1e74SAdriana Kobylak { 687204e1e74SAdriana Kobylak count++; 688204e1e74SAdriana Kobylak // Don't put the functional version on the queue since we can't 689204e1e74SAdriana Kobylak // remove the "running" BMC version. 6900f88b5afSLei YU // If ACTIVE_BMC_MAX_ALLOWED <= 1, there is only one active BMC, 6910f88b5afSLei YU // so remove functional version as well. 692a6963590SAdriana Kobylak // Don't delete the the Activation object that called this function. 693a6963590SAdriana Kobylak if ((versions.find(iter.second->versionId) 694a6963590SAdriana Kobylak ->second->isFunctional() && 695a6963590SAdriana Kobylak ACTIVE_BMC_MAX_ALLOWED > 1) || 696a6963590SAdriana Kobylak (iter.second->versionId == caller.versionId)) 697204e1e74SAdriana Kobylak { 698204e1e74SAdriana Kobylak continue; 699204e1e74SAdriana Kobylak } 700a6963590SAdriana Kobylak 701a6963590SAdriana Kobylak // Failed activations don't have priority, assign them a large value 702a6963590SAdriana Kobylak // for sorting purposes. 703a6963590SAdriana Kobylak auto priority = 999; 704a6963590SAdriana Kobylak if (iter.second.get()->activation() == 705cfb4b209SLei YU server::Activation::Activations::Active && 706cfb4b209SLei YU iter.second->redundancyPriority) 707a6963590SAdriana Kobylak { 708a6963590SAdriana Kobylak priority = iter.second->redundancyPriority.get()->priority(); 709a6963590SAdriana Kobylak } 710a6963590SAdriana Kobylak 711a6963590SAdriana Kobylak versionsPQ.push(std::make_pair(priority, iter.second->versionId)); 712204e1e74SAdriana Kobylak } 713204e1e74SAdriana Kobylak } 714204e1e74SAdriana Kobylak 715204e1e74SAdriana Kobylak // If the number of BMC versions is over ACTIVE_BMC_MAX_ALLOWED -1, 716204e1e74SAdriana Kobylak // remove the highest priority one(s). 717204e1e74SAdriana Kobylak while ((count >= ACTIVE_BMC_MAX_ALLOWED) && (!versionsPQ.empty())) 718204e1e74SAdriana Kobylak { 719204e1e74SAdriana Kobylak erase(versionsPQ.top().second); 720204e1e74SAdriana Kobylak versionsPQ.pop(); 721204e1e74SAdriana Kobylak count--; 722204e1e74SAdriana Kobylak } 723204e1e74SAdriana Kobylak } 724204e1e74SAdriana Kobylak 725eaa1ee05SEddie James void ItemUpdater::mirrorUbootToAlt() 726eaa1ee05SEddie James { 72756aaf454SLei YU helper.mirrorAlt(); 728eaa1ee05SEddie James } 729eaa1ee05SEddie James 7308e9ccfe7SBright Cheng bool ItemUpdater::checkImage(const std::string& filePath, 7318e9ccfe7SBright Cheng const std::vector<std::string>& imageList) 7328e9ccfe7SBright Cheng { 7338e9ccfe7SBright Cheng bool valid = true; 7348e9ccfe7SBright Cheng 7358e9ccfe7SBright Cheng for (auto& bmcImage : imageList) 7368e9ccfe7SBright Cheng { 7378e9ccfe7SBright Cheng fs::path file(filePath); 7388e9ccfe7SBright Cheng file /= bmcImage; 7398e9ccfe7SBright Cheng std::ifstream efile(file.c_str()); 7408e9ccfe7SBright Cheng if (efile.good() != 1) 7418e9ccfe7SBright Cheng { 7428e9ccfe7SBright Cheng valid = false; 7438e9ccfe7SBright Cheng break; 7448e9ccfe7SBright Cheng } 7458e9ccfe7SBright Cheng } 7468e9ccfe7SBright Cheng 7478e9ccfe7SBright Cheng return valid; 7488e9ccfe7SBright Cheng } 7498e9ccfe7SBright Cheng 7506e9fb1d6SLei YU #ifdef HOST_BIOS_UPGRADE 7516e9fb1d6SLei YU void ItemUpdater::createBIOSObject() 7526e9fb1d6SLei YU { 7536e9fb1d6SLei YU std::string path = BIOS_OBJPATH; 7546e9fb1d6SLei YU // Get version id from last item in the path 7556e9fb1d6SLei YU auto pos = path.rfind("/"); 7566e9fb1d6SLei YU if (pos == std::string::npos) 7576e9fb1d6SLei YU { 758c9bb6425SPatrick Williams error("No version id found in object path {PATH}", "PATH", path); 7596e9fb1d6SLei YU return; 7606e9fb1d6SLei YU } 7616e9fb1d6SLei YU 7626e9fb1d6SLei YU createActiveAssociation(path); 7636e9fb1d6SLei YU createFunctionalAssociation(path); 7646e9fb1d6SLei YU 7656e9fb1d6SLei YU auto versionId = path.substr(pos + 1); 7666e9fb1d6SLei YU auto version = "null"; 7676e9fb1d6SLei YU AssociationList assocs = {}; 7686e9fb1d6SLei YU biosActivation = std::make_unique<Activation>( 7696e9fb1d6SLei YU bus, path, *this, versionId, server::Activation::Activations::Active, 7706e9fb1d6SLei YU assocs); 7716e9fb1d6SLei YU auto dummyErase = [](std::string /*entryId*/) { 7726e9fb1d6SLei YU // Do nothing; 7736e9fb1d6SLei YU }; 7746e9fb1d6SLei YU biosVersion = std::make_unique<VersionClass>( 7756e9fb1d6SLei YU bus, path, version, VersionPurpose::Host, "", "", 7766e9fb1d6SLei YU std::bind(dummyErase, std::placeholders::_1)); 7776e9fb1d6SLei YU biosVersion->deleteObject = 7786e9fb1d6SLei YU std::make_unique<phosphor::software::manager::Delete>(bus, path, 7796e9fb1d6SLei YU *biosVersion); 7806e9fb1d6SLei YU } 7816e9fb1d6SLei YU #endif 7826e9fb1d6SLei YU 783ec1b41c4SGunnar Mills } // namespace updater 784ec1b41c4SGunnar Mills } // namespace software 785ec1b41c4SGunnar Mills } // namespace phosphor 786