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         auto versionPtr = std::make_unique<VersionClass>(
1421fd6dddfSChanh Nguyen             bus, path, version, purpose, extendedVersion, filePath,
14359b640b0SAdriana Kobylak             std::bind(&ItemUpdater::erase, this, std::placeholders::_1),
14459b640b0SAdriana Kobylak             versionId);
145ee13e831SSaqib Khan         versionPtr->deleteObject =
1462285fe0fSAdriana Kobylak             std::make_unique<phosphor::software::manager::Delete>(bus, path,
1472285fe0fSAdriana Kobylak                                                                   *versionPtr);
148ee13e831SSaqib Khan         versions.insert(std::make_pair(versionId, std::move(versionPtr)));
14988ba1f9eSAdriana Kobylak 
15088ba1f9eSAdriana Kobylak         activations.insert(std::make_pair(
15188ba1f9eSAdriana Kobylak             versionId,
15288ba1f9eSAdriana Kobylak             std::make_unique<Activation>(bus, path, *this, versionId,
15388ba1f9eSAdriana Kobylak                                          activationState, associations)));
1542ce7da29SGunnar Mills     }
155e75d10f5SPatrick Williams     return;
156ec1b41c4SGunnar Mills }
157ec1b41c4SGunnar Mills 
158ba239881SSaqib Khan void ItemUpdater::processBMCImage()
159ba239881SSaqib Khan {
16088e8a325SGunnar Mills     using VersionClass = phosphor::software::manager::Version;
161269bff30SLei YU 
162269bff30SLei YU     // Check MEDIA_DIR and create if it does not exist
163269bff30SLei YU     try
164269bff30SLei YU     {
165269bff30SLei YU         if (!fs::is_directory(MEDIA_DIR))
166269bff30SLei YU         {
167269bff30SLei YU             fs::create_directory(MEDIA_DIR);
168269bff30SLei YU         }
169269bff30SLei YU     }
170269bff30SLei YU     catch (const fs::filesystem_error& e)
171269bff30SLei YU     {
172c9bb6425SPatrick Williams         error("Failed to prepare dir: {ERROR}", "ERROR", e);
173269bff30SLei YU         return;
174269bff30SLei YU     }
175269bff30SLei YU 
1761e81f23cSAdriana Kobylak     // Functional images are mounted as rofs-<location>-functional
1771e81f23cSAdriana Kobylak     constexpr auto functionalSuffix = "-functional";
178d474d9cdSLei YU     bool functionalFound = false;
17988e8a325SGunnar Mills 
1801eef62deSSaqib Khan     // Read os-release from folders under /media/ to get
1811eef62deSSaqib Khan     // BMC Software Versions.
1821eef62deSSaqib Khan     for (const auto& iter : fs::directory_iterator(MEDIA_DIR))
1831eef62deSSaqib Khan     {
1841eef62deSSaqib Khan         auto activationState = server::Activation::Activations::Active;
1856fab70daSSaqib Khan         static const auto BMC_RO_PREFIX_LEN = strlen(BMC_ROFS_PREFIX);
1861eef62deSSaqib Khan 
1871eef62deSSaqib Khan         // Check if the BMC_RO_PREFIXis the prefix of the iter.path
1882285fe0fSAdriana Kobylak         if (0 ==
1892285fe0fSAdriana Kobylak             iter.path().native().compare(0, BMC_RO_PREFIX_LEN, BMC_ROFS_PREFIX))
1901eef62deSSaqib Khan         {
191716cd78dSAdriana Kobylak             // Get the version to calculate the id
19224a8d83dSAdriana Kobylak             fs::path releaseFile(OS_RELEASE_FILE);
19324a8d83dSAdriana Kobylak             auto osRelease = iter.path() / releaseFile.relative_path();
1941eef62deSSaqib Khan             if (!fs::is_regular_file(osRelease))
1951eef62deSSaqib Khan             {
196e56bf878SLei YU #ifdef BMC_STATIC_DUAL_IMAGE
197e56bf878SLei YU                 // For dual image, it is possible that the secondary image is
198e56bf878SLei YU                 // empty or contains invalid data, ignore such case.
199e56bf878SLei YU                 info("Unable to find osRelease: {PATH}", "PATH", osRelease);
200e56bf878SLei YU #else
201c9bb6425SPatrick Williams                 error("Failed to read osRelease: {PATH}", "PATH", osRelease);
202716cd78dSAdriana Kobylak 
203716cd78dSAdriana Kobylak                 // Try to get the version id from the mount directory name and
204716cd78dSAdriana Kobylak                 // call to delete it as this version may be corrupted. Dynamic
205716cd78dSAdriana Kobylak                 // volumes created by the UBI layout for example have the id in
206716cd78dSAdriana Kobylak                 // the mount directory name. The worst that can happen is that
207716cd78dSAdriana Kobylak                 // erase() is called with an non-existent id and returns.
208716cd78dSAdriana Kobylak                 auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN);
209021c365bSSaqib Khan                 ItemUpdater::erase(id);
210e56bf878SLei YU #endif
211716cd78dSAdriana Kobylak 
212021c365bSSaqib Khan                 continue;
2131eef62deSSaqib Khan             }
21488e8a325SGunnar Mills             auto version = VersionClass::getBMCVersion(osRelease);
2151eef62deSSaqib Khan             if (version.empty())
2161eef62deSSaqib Khan             {
217c9bb6425SPatrick Williams                 error("Failed to read version from osRelease: {PATH}", "PATH",
218c9bb6425SPatrick Williams                       osRelease);
219716cd78dSAdriana Kobylak 
220716cd78dSAdriana Kobylak                 // Try to delete the version, same as above if the
221716cd78dSAdriana Kobylak                 // OS_RELEASE_FILE does not exist.
222716cd78dSAdriana Kobylak                 auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN);
223716cd78dSAdriana Kobylak                 ItemUpdater::erase(id);
224716cd78dSAdriana Kobylak 
225716cd78dSAdriana Kobylak                 continue;
2261eef62deSSaqib Khan             }
227021c365bSSaqib Khan 
22859b640b0SAdriana Kobylak             // The flash location is part of the mount name: rofs-<location>
22959b640b0SAdriana Kobylak             auto flashId = iter.path().native().substr(BMC_RO_PREFIX_LEN);
23059b640b0SAdriana Kobylak 
23159b640b0SAdriana Kobylak             auto id = VersionClass::getId(version + flashId);
232716cd78dSAdriana Kobylak 
233f383d27aSAdriana Kobylak             // Check if the id has already been added. This can happen if the
234f383d27aSAdriana Kobylak             // BMC partitions / devices were manually flashed with the same
235f383d27aSAdriana Kobylak             // image.
236f383d27aSAdriana Kobylak             if (versions.find(id) != versions.end())
237f383d27aSAdriana Kobylak             {
238f383d27aSAdriana Kobylak                 continue;
239f383d27aSAdriana Kobylak             }
240f383d27aSAdriana Kobylak 
2411e81f23cSAdriana Kobylak             auto functional = false;
2421e81f23cSAdriana Kobylak             if (iter.path().native().find(functionalSuffix) !=
2431e81f23cSAdriana Kobylak                 std::string::npos)
2441e81f23cSAdriana Kobylak             {
2451e81f23cSAdriana Kobylak                 // Set functional to true and remove the functional suffix
2461e81f23cSAdriana Kobylak                 functional = true;
2471e81f23cSAdriana Kobylak                 flashId.erase(flashId.length() - strlen(functionalSuffix));
248d474d9cdSLei YU                 functionalFound = true;
2491e81f23cSAdriana Kobylak             }
250780220f2SAdriana Kobylak 
2511eef62deSSaqib Khan             auto purpose = server::Version::VersionPurpose::BMC;
252780220f2SAdriana Kobylak             restorePurpose(flashId, purpose);
253ec4eec34SAdriana Kobylak 
2541fd6dddfSChanh Nguyen             // Read os-release from /etc/ to get the BMC extended version
2551fd6dddfSChanh Nguyen             std::string extendedVersion =
2561fd6dddfSChanh Nguyen                 VersionClass::getBMCExtendedVersion(osRelease);
2571fd6dddfSChanh Nguyen 
2581eef62deSSaqib Khan             auto path = fs::path(SOFTWARE_OBJPATH) / id;
2591eef62deSSaqib Khan 
260269bff30SLei YU             // Create functional association if this is the functional
261269bff30SLei YU             // version
2621e81f23cSAdriana Kobylak             if (functional)
26388e8a325SGunnar Mills             {
26488e8a325SGunnar Mills                 createFunctionalAssociation(path);
26588e8a325SGunnar Mills             }
26688e8a325SGunnar Mills 
26743b25cdeSGunnar Mills             AssociationList associations = {};
26843b25cdeSGunnar Mills 
26943b25cdeSGunnar Mills             if (activationState == server::Activation::Activations::Active)
27043b25cdeSGunnar Mills             {
27143b25cdeSGunnar Mills                 // Create an association to the BMC inventory item
27243b25cdeSGunnar Mills                 associations.emplace_back(std::make_tuple(
2732285fe0fSAdriana Kobylak                     ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
27443b25cdeSGunnar Mills                     bmcInventoryPath));
27543b25cdeSGunnar Mills 
27643b25cdeSGunnar Mills                 // Create an active association since this image is active
27743b25cdeSGunnar Mills                 createActiveAssociation(path);
27843b25cdeSGunnar Mills             }
27943b25cdeSGunnar Mills 
280bbebec79SAppaRao Puli             // All updateable firmware components must expose the updateable
281bbebec79SAppaRao Puli             // association.
282bbebec79SAppaRao Puli             createUpdateableAssociation(path);
283bbebec79SAppaRao Puli 
284ee590c74SAdriana Kobylak             // Create Version instance for this version.
285ee590c74SAdriana Kobylak             auto versionPtr = std::make_unique<VersionClass>(
286a84f06d2SAdriana Kobylak                 bus, path, version, purpose, extendedVersion, flashId,
28759b640b0SAdriana Kobylak                 std::bind(&ItemUpdater::erase, this, std::placeholders::_1),
28859b640b0SAdriana Kobylak                 id);
2891e81f23cSAdriana Kobylak             if (functional)
2901e81f23cSAdriana Kobylak             {
2911e81f23cSAdriana Kobylak                 versionPtr->setFunctional(true);
2921e81f23cSAdriana Kobylak             }
2931e81f23cSAdriana Kobylak             else
294ee13e831SSaqib Khan             {
295ee13e831SSaqib Khan                 versionPtr->deleteObject =
296ee13e831SSaqib Khan                     std::make_unique<phosphor::software::manager::Delete>(
297ee13e831SSaqib Khan                         bus, path, *versionPtr);
298ee13e831SSaqib Khan             }
2992285fe0fSAdriana Kobylak             versions.insert(std::make_pair(id, std::move(versionPtr)));
300ee590c74SAdriana Kobylak 
3011eef62deSSaqib Khan             // Create Activation instance for this version.
302ee13e831SSaqib Khan             activations.insert(std::make_pair(
3032285fe0fSAdriana Kobylak                 id, std::make_unique<Activation>(
3042285fe0fSAdriana Kobylak                         bus, path, *this, id, activationState, associations)));
3051eef62deSSaqib Khan 
306bdf2d6ceSLei YU #ifdef BMC_STATIC_DUAL_IMAGE
307bdf2d6ceSLei YU             uint8_t priority;
308bdf2d6ceSLei YU             if ((functional && (runningImageSlot == 0)) ||
309bdf2d6ceSLei YU                 (!functional && (runningImageSlot == 1)))
310bdf2d6ceSLei YU             {
311bdf2d6ceSLei YU                 priority = 0;
312bdf2d6ceSLei YU             }
313bdf2d6ceSLei YU             else
314bdf2d6ceSLei YU             {
315bdf2d6ceSLei YU                 priority = 1;
316bdf2d6ceSLei YU             }
317bdf2d6ceSLei YU             activations.find(id)->second->redundancyPriority =
318bdf2d6ceSLei YU                 std::make_unique<RedundancyPriority>(
319bdf2d6ceSLei YU                     bus, path, *(activations.find(id)->second), priority,
320bdf2d6ceSLei YU                     false);
321bdf2d6ceSLei YU #else
322269bff30SLei YU             // If Active, create RedundancyPriority instance for this
323269bff30SLei YU             // version.
3241eef62deSSaqib Khan             if (activationState == server::Activation::Activations::Active)
3251eef62deSSaqib Khan             {
3261eef62deSSaqib Khan                 uint8_t priority = std::numeric_limits<uint8_t>::max();
327780220f2SAdriana Kobylak                 if (!restorePriority(flashId, priority))
3281eef62deSSaqib Khan                 {
3291e81f23cSAdriana Kobylak                     if (functional)
330ee590c74SAdriana Kobylak                     {
331ee590c74SAdriana Kobylak                         priority = 0;
332ee590c74SAdriana Kobylak                     }
333ee590c74SAdriana Kobylak                     else
334ee590c74SAdriana Kobylak                     {
335c9bb6425SPatrick Williams                         error(
336c9bb6425SPatrick Williams                             "Unable to restore priority from file for {VERSIONID}",
337c9bb6425SPatrick Williams                             "VERSIONID", id);
3381eef62deSSaqib Khan                     }
339ee590c74SAdriana Kobylak                 }
3401eef62deSSaqib Khan                 activations.find(id)->second->redundancyPriority =
3411eef62deSSaqib Khan                     std::make_unique<RedundancyPriority>(
3422285fe0fSAdriana Kobylak                         bus, path, *(activations.find(id)->second), priority,
343b77551cdSAdriana Kobylak                         false);
3441eef62deSSaqib Khan             }
345bdf2d6ceSLei YU #endif
3461eef62deSSaqib Khan         }
3471eef62deSSaqib Khan     }
348dcbfa04aSSaqib Khan 
349d474d9cdSLei YU     if (!functionalFound)
350dcbfa04aSSaqib Khan     {
351d474d9cdSLei YU         // If there is no functional version found, read the /etc/os-release and
352d474d9cdSLei YU         // create rofs-<versionId>-functional under MEDIA_DIR, then call again
353d474d9cdSLei YU         // processBMCImage() to create the D-Bus interface for it.
354d16bcbd5SGunnar Mills         auto version = VersionClass::getBMCVersion(OS_RELEASE_FILE);
35559b640b0SAdriana Kobylak         auto id = phosphor::software::manager::Version::getId(version +
35659b640b0SAdriana Kobylak                                                               functionalSuffix);
3571e81f23cSAdriana Kobylak         auto versionFileDir = BMC_ROFS_PREFIX + id + functionalSuffix + "/etc/";
358dcbfa04aSSaqib Khan         try
359dcbfa04aSSaqib Khan         {
360dcbfa04aSSaqib Khan             if (!fs::is_directory(versionFileDir))
361dcbfa04aSSaqib Khan             {
362dcbfa04aSSaqib Khan                 fs::create_directories(versionFileDir);
363dcbfa04aSSaqib Khan             }
3641e81f23cSAdriana Kobylak             auto versionFilePath =
3651e81f23cSAdriana Kobylak                 BMC_ROFS_PREFIX + id + functionalSuffix + OS_RELEASE_FILE;
366dcbfa04aSSaqib Khan             fs::create_directory_symlink(OS_RELEASE_FILE, versionFilePath);
367dcbfa04aSSaqib Khan             ItemUpdater::processBMCImage();
368dcbfa04aSSaqib Khan         }
369dcbfa04aSSaqib Khan         catch (const std::exception& e)
370dcbfa04aSSaqib Khan         {
371c9bb6425SPatrick Williams             error("Exception during processing: {ERROR}", "ERROR", e);
372dcbfa04aSSaqib Khan         }
373dcbfa04aSSaqib Khan     }
374eaa1ee05SEddie James 
375eaa1ee05SEddie James     mirrorUbootToAlt();
376ba239881SSaqib Khan     return;
377ba239881SSaqib Khan }
378ba239881SSaqib Khan 
3793526ef73SLeonel Gonzalez void ItemUpdater::erase(std::string entryId)
3803526ef73SLeonel Gonzalez {
3816d873715SEddie James     // Find entry in versions map
3826d873715SEddie James     auto it = versions.find(entryId);
3836d873715SEddie James     if (it != versions.end())
3846d873715SEddie James     {
3850f88b5afSLei YU         if (it->second->isFunctional() && ACTIVE_BMC_MAX_ALLOWED > 1)
3866d873715SEddie James         {
387c9bb6425SPatrick Williams             error(
388c9bb6425SPatrick Williams                 "Version ({VERSIONID}) is currently running on the BMC; unable to remove.",
389c9bb6425SPatrick Williams                 "VERSIONID", entryId);
3906d873715SEddie James             return;
3916d873715SEddie James         }
392d1a55adcSAdriana Kobylak     }
3936d873715SEddie James 
394d1a55adcSAdriana Kobylak     // First call resetUbootEnvVars() so that the BMC points to a valid image to
395d1a55adcSAdriana Kobylak     // boot from. If resetUbootEnvVars() is called after the image is actually
396d1a55adcSAdriana Kobylak     // deleted from the BMC flash, there'd be a time window where the BMC would
397d1a55adcSAdriana Kobylak     // be pointing to a non-existent image to boot from.
398d1a55adcSAdriana Kobylak     // Need to remove the entries from the activations map before that call so
399d1a55adcSAdriana Kobylak     // that resetUbootEnvVars() doesn't use the version to be deleted.
400d1a55adcSAdriana Kobylak     auto iteratorActivations = activations.find(entryId);
401d1a55adcSAdriana Kobylak     if (iteratorActivations == activations.end())
402d1a55adcSAdriana Kobylak     {
403c9bb6425SPatrick Williams         error(
404c9bb6425SPatrick Williams             "Failed to find version ({VERSIONID}) in item updater activations map; unable to remove.",
405c9bb6425SPatrick Williams             "VERSIONID", entryId);
406d1a55adcSAdriana Kobylak     }
407d1a55adcSAdriana Kobylak     else
408d1a55adcSAdriana Kobylak     {
409d1a55adcSAdriana Kobylak         removeAssociations(iteratorActivations->second->path);
410ae06d76aSZami Seck         iteratorActivations->second->deleteImageManagerObject();
411d1a55adcSAdriana Kobylak         this->activations.erase(entryId);
412d1a55adcSAdriana Kobylak     }
413d1a55adcSAdriana Kobylak     ItemUpdater::resetUbootEnvVars();
414d1a55adcSAdriana Kobylak 
415d1a55adcSAdriana Kobylak     if (it != versions.end())
416d1a55adcSAdriana Kobylak     {
417780220f2SAdriana Kobylak         auto flashId = it->second->path();
418780220f2SAdriana Kobylak 
41925773a7eSAdriana Kobylak         // Delete version data if it has been installed on flash (path is not
42025773a7eSAdriana Kobylak         // the upload directory)
42125773a7eSAdriana Kobylak         if (flashId.find(IMG_UPLOAD_DIR) == std::string::npos)
42225773a7eSAdriana Kobylak         {
4233526ef73SLeonel Gonzalez             removeReadOnlyPartition(entryId);
424780220f2SAdriana Kobylak             removePersistDataDirectory(flashId);
42525773a7eSAdriana Kobylak             helper.clearEntry(flashId);
42625773a7eSAdriana Kobylak         }
427ee13e831SSaqib Khan 
428ee13e831SSaqib Khan         // Removing entry in versions map
429ee13e831SSaqib Khan         this->versions.erase(entryId);
4306d873715SEddie James     }
4313526ef73SLeonel Gonzalez 
432ee13e831SSaqib Khan     return;
4333526ef73SLeonel Gonzalez }
4343526ef73SLeonel Gonzalez 
435bc1bf3afSMichael Tritz void ItemUpdater::deleteAll()
436bc1bf3afSMichael Tritz {
43783cd21fbSAdriana Kobylak     std::vector<std::string> deletableVersions;
43883cd21fbSAdriana Kobylak 
439bc1bf3afSMichael Tritz     for (const auto& versionIt : versions)
440bc1bf3afSMichael Tritz     {
441bc1bf3afSMichael Tritz         if (!versionIt.second->isFunctional())
442bc1bf3afSMichael Tritz         {
44383cd21fbSAdriana Kobylak             deletableVersions.push_back(versionIt.first);
444bc1bf3afSMichael Tritz         }
445bc1bf3afSMichael Tritz     }
446bc1bf3afSMichael Tritz 
44783cd21fbSAdriana Kobylak     for (const auto& deletableIt : deletableVersions)
44883cd21fbSAdriana Kobylak     {
44983cd21fbSAdriana Kobylak         ItemUpdater::erase(deletableIt);
45083cd21fbSAdriana Kobylak     }
45183cd21fbSAdriana Kobylak 
45256aaf454SLei YU     helper.cleanup();
453bc1bf3afSMichael Tritz }
454bc1bf3afSMichael Tritz 
4552285fe0fSAdriana Kobylak ItemUpdater::ActivationStatus
4562285fe0fSAdriana Kobylak     ItemUpdater::validateSquashFSImage(const std::string& filePath)
45735e83f3eSSaqib Khan {
4588e9ccfe7SBright Cheng     bool valid = true;
45935e83f3eSSaqib Khan 
4608e9ccfe7SBright Cheng     // Record the images which are being updated
4618e9ccfe7SBright Cheng     // First check for the fullimage, then check for images with partitions
4628e9ccfe7SBright Cheng     imageUpdateList.push_back(bmcFullImages);
4638e9ccfe7SBright Cheng     valid = checkImage(filePath, imageUpdateList);
4648e9ccfe7SBright Cheng     if (!valid)
465b1cfdf99SMichael Tritz     {
4668e9ccfe7SBright Cheng         imageUpdateList.clear();
4678e9ccfe7SBright Cheng         imageUpdateList.assign(bmcImages.begin(), bmcImages.end());
4688e9ccfe7SBright Cheng         valid = checkImage(filePath, imageUpdateList);
4698e9ccfe7SBright Cheng         if (!valid)
47035e83f3eSSaqib Khan         {
471c9bb6425SPatrick Williams             error("Failed to find the needed BMC images.");
47235e83f3eSSaqib Khan             return ItemUpdater::ActivationStatus::invalid;
47335e83f3eSSaqib Khan         }
4748e9ccfe7SBright Cheng     }
475b1cfdf99SMichael Tritz 
476b1cfdf99SMichael Tritz     return ItemUpdater::ActivationStatus::ready;
47735e83f3eSSaqib Khan }
47835e83f3eSSaqib Khan 
479bbcb7be1SAdriana Kobylak void ItemUpdater::savePriority(const std::string& versionId, uint8_t value)
480bbcb7be1SAdriana Kobylak {
481780220f2SAdriana Kobylak     auto flashId = versions.find(versionId)->second->path();
482780220f2SAdriana Kobylak     storePriority(flashId, value);
48325773a7eSAdriana Kobylak     helper.setEntry(flashId, value);
484bbcb7be1SAdriana Kobylak }
485bbcb7be1SAdriana Kobylak 
486b9da6634SSaqib Khan void ItemUpdater::freePriority(uint8_t value, const std::string& versionId)
4874c1aec09SSaqib Khan {
488b77551cdSAdriana Kobylak     std::map<std::string, uint8_t> priorityMap;
489b77551cdSAdriana Kobylak 
490b77551cdSAdriana Kobylak     // Insert the requested version and priority, it may not exist yet.
491b77551cdSAdriana Kobylak     priorityMap.insert(std::make_pair(versionId, value));
492b77551cdSAdriana Kobylak 
4934c1aec09SSaqib Khan     for (const auto& intf : activations)
4944c1aec09SSaqib Khan     {
4954c1aec09SSaqib Khan         if (intf.second->redundancyPriority)
4964c1aec09SSaqib Khan         {
497b77551cdSAdriana Kobylak             priorityMap.insert(std::make_pair(
4982285fe0fSAdriana Kobylak                 intf.first, intf.second->redundancyPriority.get()->priority()));
499b77551cdSAdriana Kobylak         }
500b77551cdSAdriana Kobylak     }
501b77551cdSAdriana Kobylak 
502b77551cdSAdriana Kobylak     // Lambda function to compare 2 priority values, use <= to allow duplicates
5032285fe0fSAdriana Kobylak     typedef std::function<bool(std::pair<std::string, uint8_t>,
5042285fe0fSAdriana Kobylak                                std::pair<std::string, uint8_t>)>
5052285fe0fSAdriana Kobylak         cmpPriority;
5062285fe0fSAdriana Kobylak     cmpPriority cmpPriorityFunc =
5072285fe0fSAdriana Kobylak         [](std::pair<std::string, uint8_t> priority1,
5082285fe0fSAdriana Kobylak            std::pair<std::string, uint8_t> priority2) {
509b77551cdSAdriana Kobylak             return priority1.second <= priority2.second;
510b77551cdSAdriana Kobylak         };
511b77551cdSAdriana Kobylak 
512b77551cdSAdriana Kobylak     // Sort versions by ascending priority
513b77551cdSAdriana Kobylak     std::set<std::pair<std::string, uint8_t>, cmpPriority> prioritySet(
514b77551cdSAdriana Kobylak         priorityMap.begin(), priorityMap.end(), cmpPriorityFunc);
515b77551cdSAdriana Kobylak 
516b77551cdSAdriana Kobylak     auto freePriorityValue = value;
517b77551cdSAdriana Kobylak     for (auto& element : prioritySet)
518b77551cdSAdriana Kobylak     {
519b77551cdSAdriana Kobylak         if (element.first == versionId)
520b77551cdSAdriana Kobylak         {
521b77551cdSAdriana Kobylak             continue;
522b77551cdSAdriana Kobylak         }
523b77551cdSAdriana Kobylak         if (element.second == freePriorityValue)
524b77551cdSAdriana Kobylak         {
525b77551cdSAdriana Kobylak             ++freePriorityValue;
526b77551cdSAdriana Kobylak             auto it = activations.find(element.first);
527b77551cdSAdriana Kobylak             it->second->redundancyPriority.get()->sdbusPriority(
528b77551cdSAdriana Kobylak                 freePriorityValue);
5294c1aec09SSaqib Khan         }
5304c1aec09SSaqib Khan     }
531b77551cdSAdriana Kobylak 
532b77551cdSAdriana Kobylak     auto lowestVersion = prioritySet.begin()->first;
533b77551cdSAdriana Kobylak     if (value == prioritySet.begin()->second)
534b77551cdSAdriana Kobylak     {
535b77551cdSAdriana Kobylak         lowestVersion = versionId;
5364c1aec09SSaqib Khan     }
537b77551cdSAdriana Kobylak     updateUbootEnvVars(lowestVersion);
5384c1aec09SSaqib Khan }
5394c1aec09SSaqib Khan 
54037a59043SMichael Tritz void ItemUpdater::reset()
54137a59043SMichael Tritz {
54256aaf454SLei YU     helper.factoryReset();
54337a59043SMichael Tritz 
544c9bb6425SPatrick Williams     info("BMC factory reset will take effect upon reboot.");
54537a59043SMichael Tritz }
54637a59043SMichael Tritz 
5473526ef73SLeonel Gonzalez void ItemUpdater::removeReadOnlyPartition(std::string versionId)
5483526ef73SLeonel Gonzalez {
54925773a7eSAdriana Kobylak     auto flashId = versions.find(versionId)->second->path();
55025773a7eSAdriana Kobylak     helper.removeVersion(flashId);
5513526ef73SLeonel Gonzalez }
5523526ef73SLeonel Gonzalez 
5530129d926SMichael Tritz bool ItemUpdater::fieldModeEnabled(bool value)
5540129d926SMichael Tritz {
5550129d926SMichael Tritz     // enabling field mode is intended to be one way: false -> true
5560129d926SMichael Tritz     if (value && !control::FieldMode::fieldModeEnabled())
5570129d926SMichael Tritz     {
5580129d926SMichael Tritz         control::FieldMode::fieldModeEnabled(value);
5590129d926SMichael Tritz 
56022848eceSAdriana Kobylak         auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
56122848eceSAdriana Kobylak                                           SYSTEMD_INTERFACE, "StartUnit");
56222848eceSAdriana Kobylak         method.append("obmc-flash-bmc-setenv@fieldmode\\x3dtrue.service",
56322848eceSAdriana Kobylak                       "replace");
56422848eceSAdriana Kobylak         bus.call_noreply(method);
56522848eceSAdriana Kobylak 
56622848eceSAdriana Kobylak         method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
56722848eceSAdriana Kobylak                                      SYSTEMD_INTERFACE, "StopUnit");
56822848eceSAdriana Kobylak         method.append("usr-local.mount", "replace");
56922848eceSAdriana Kobylak         bus.call_noreply(method);
57022848eceSAdriana Kobylak 
57122848eceSAdriana Kobylak         std::vector<std::string> usrLocal = {"usr-local.mount"};
57222848eceSAdriana Kobylak 
57322848eceSAdriana Kobylak         method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
57422848eceSAdriana Kobylak                                      SYSTEMD_INTERFACE, "MaskUnitFiles");
57522848eceSAdriana Kobylak         method.append(usrLocal, false, true);
57622848eceSAdriana Kobylak         bus.call_noreply(method);
5770129d926SMichael Tritz     }
578d5b8f75cSAdriana Kobylak     else if (!value && control::FieldMode::fieldModeEnabled())
579d5b8f75cSAdriana Kobylak     {
580d5b8f75cSAdriana Kobylak         elog<NotAllowed>(xyz::openbmc_project::Common::NotAllowed::REASON(
581d5b8f75cSAdriana Kobylak             "FieldMode is not allowed to be cleared"));
582d5b8f75cSAdriana Kobylak     }
5830129d926SMichael Tritz 
5840129d926SMichael Tritz     return control::FieldMode::fieldModeEnabled();
5850129d926SMichael Tritz }
5860129d926SMichael Tritz 
5870129d926SMichael Tritz void ItemUpdater::restoreFieldModeStatus()
5880129d926SMichael Tritz {
589ff0b421dSMichael Tritz     std::ifstream input("/dev/mtd/u-boot-env");
5900129d926SMichael Tritz     std::string envVar;
5910129d926SMichael Tritz     std::getline(input, envVar);
5920129d926SMichael Tritz 
5930129d926SMichael Tritz     if (envVar.find("fieldmode=true") != std::string::npos)
5940129d926SMichael Tritz     {
5950129d926SMichael Tritz         ItemUpdater::fieldModeEnabled(true);
5960129d926SMichael Tritz     }
5970129d926SMichael Tritz }
5980129d926SMichael Tritz 
599b60add1eSGunnar Mills void ItemUpdater::setBMCInventoryPath()
600b60add1eSGunnar Mills {
601b60add1eSGunnar Mills     auto depth = 0;
6022285fe0fSAdriana Kobylak     auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
6032285fe0fSAdriana Kobylak                                           MAPPER_INTERFACE, "GetSubTreePaths");
604b60add1eSGunnar Mills 
6051254c628SAdriana Kobylak     mapperCall.append(INVENTORY_PATH);
606b60add1eSGunnar Mills     mapperCall.append(depth);
6071254c628SAdriana Kobylak     std::vector<std::string> filter = {BMC_INVENTORY_INTERFACE};
608b60add1eSGunnar Mills     mapperCall.append(filter);
609b60add1eSGunnar Mills 
61087c78173SEd Tanous     try
611b60add1eSGunnar Mills     {
61287c78173SEd Tanous         auto response = bus.call(mapperCall);
613b60add1eSGunnar Mills 
614b60add1eSGunnar Mills         using ObjectPaths = std::vector<std::string>;
615b60add1eSGunnar Mills         ObjectPaths result;
616b60add1eSGunnar Mills         response.read(result);
617b60add1eSGunnar Mills 
6181254c628SAdriana Kobylak         if (!result.empty())
619b60add1eSGunnar Mills         {
6201254c628SAdriana Kobylak             bmcInventoryPath = result.front();
621b60add1eSGunnar Mills         }
62287c78173SEd Tanous     }
6234ce901c5SPatrick Williams     catch (const sdbusplus::exception::exception& e)
62487c78173SEd Tanous     {
625c9bb6425SPatrick Williams         error("Error in mapper GetSubTreePath: {ERROR}", "ERROR", e);
62687c78173SEd Tanous         return;
62787c78173SEd Tanous     }
628b60add1eSGunnar Mills 
629b60add1eSGunnar Mills     return;
630b60add1eSGunnar Mills }
631b60add1eSGunnar Mills 
632f10b2326SGunnar Mills void ItemUpdater::createActiveAssociation(const std::string& path)
633ded875dcSGunnar Mills {
6342285fe0fSAdriana Kobylak     assocs.emplace_back(
6352285fe0fSAdriana Kobylak         std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path));
636ded875dcSGunnar Mills     associations(assocs);
637ded875dcSGunnar Mills }
638ded875dcSGunnar Mills 
63988e8a325SGunnar Mills void ItemUpdater::createFunctionalAssociation(const std::string& path)
64088e8a325SGunnar Mills {
64188e8a325SGunnar Mills     assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION,
6422285fe0fSAdriana Kobylak                                         FUNCTIONAL_REV_ASSOCIATION, path));
64388e8a325SGunnar Mills     associations(assocs);
64488e8a325SGunnar Mills }
64588e8a325SGunnar Mills 
646bbebec79SAppaRao Puli void ItemUpdater::createUpdateableAssociation(const std::string& path)
647bbebec79SAppaRao Puli {
648bbebec79SAppaRao Puli     assocs.emplace_back(std::make_tuple(UPDATEABLE_FWD_ASSOCIATION,
649bbebec79SAppaRao Puli                                         UPDATEABLE_REV_ASSOCIATION, path));
650bbebec79SAppaRao Puli     associations(assocs);
651bbebec79SAppaRao Puli }
652bbebec79SAppaRao Puli 
653991af7ecSAdriana Kobylak void ItemUpdater::removeAssociations(const std::string& path)
654ded875dcSGunnar Mills {
655ded875dcSGunnar Mills     for (auto iter = assocs.begin(); iter != assocs.end();)
656ded875dcSGunnar Mills     {
657991af7ecSAdriana Kobylak         if ((std::get<2>(*iter)).compare(path) == 0)
658ded875dcSGunnar Mills         {
659ded875dcSGunnar Mills             iter = assocs.erase(iter);
660ded875dcSGunnar Mills             associations(assocs);
661ded875dcSGunnar Mills         }
662ded875dcSGunnar Mills         else
663ded875dcSGunnar Mills         {
664ded875dcSGunnar Mills             ++iter;
665ded875dcSGunnar Mills         }
666ded875dcSGunnar Mills     }
667ded875dcSGunnar Mills }
668ded875dcSGunnar Mills 
669b9da6634SSaqib Khan bool ItemUpdater::isLowestPriority(uint8_t value)
670b9da6634SSaqib Khan {
671b9da6634SSaqib Khan     for (const auto& intf : activations)
672b9da6634SSaqib Khan     {
673b9da6634SSaqib Khan         if (intf.second->redundancyPriority)
674b9da6634SSaqib Khan         {
675b9da6634SSaqib Khan             if (intf.second->redundancyPriority.get()->priority() < value)
676b9da6634SSaqib Khan             {
677b9da6634SSaqib Khan                 return false;
678b9da6634SSaqib Khan             }
679b9da6634SSaqib Khan         }
680b9da6634SSaqib Khan     }
681b9da6634SSaqib Khan     return true;
682b9da6634SSaqib Khan }
683b9da6634SSaqib Khan 
684b77551cdSAdriana Kobylak void ItemUpdater::updateUbootEnvVars(const std::string& versionId)
685b77551cdSAdriana Kobylak {
6869c76a0acSLei YU     auto it = versions.find(versionId);
6879c76a0acSLei YU     if (it == versions.end())
6889c76a0acSLei YU     {
6899c76a0acSLei YU         return;
6909c76a0acSLei YU     }
6919c76a0acSLei YU     auto flashId = it->second->path();
69225773a7eSAdriana Kobylak     helper.updateUbootVersionId(flashId);
693b77551cdSAdriana Kobylak }
694b77551cdSAdriana Kobylak 
69549446ae9SSaqib Khan void ItemUpdater::resetUbootEnvVars()
69649446ae9SSaqib Khan {
69749446ae9SSaqib Khan     decltype(activations.begin()->second->redundancyPriority.get()->priority())
69849446ae9SSaqib Khan         lowestPriority = std::numeric_limits<uint8_t>::max();
69949446ae9SSaqib Khan     decltype(activations.begin()->second->versionId) lowestPriorityVersion;
70049446ae9SSaqib Khan     for (const auto& intf : activations)
70149446ae9SSaqib Khan     {
70249446ae9SSaqib Khan         if (!intf.second->redundancyPriority.get())
70349446ae9SSaqib Khan         {
70449446ae9SSaqib Khan             // Skip this version if the redundancyPriority is not initialized.
70549446ae9SSaqib Khan             continue;
70649446ae9SSaqib Khan         }
70749446ae9SSaqib Khan 
7082285fe0fSAdriana Kobylak         if (intf.second->redundancyPriority.get()->priority() <= lowestPriority)
70949446ae9SSaqib Khan         {
71049446ae9SSaqib Khan             lowestPriority = intf.second->redundancyPriority.get()->priority();
71149446ae9SSaqib Khan             lowestPriorityVersion = intf.second->versionId;
71249446ae9SSaqib Khan         }
71349446ae9SSaqib Khan     }
71449446ae9SSaqib Khan 
715f0382c35SSaqib Khan     // Update the U-boot environment variable to point to the lowest priority
716b77551cdSAdriana Kobylak     updateUbootEnvVars(lowestPriorityVersion);
71749446ae9SSaqib Khan }
71849446ae9SSaqib Khan 
719*d8c9eea3SLei YU void ItemUpdater::freeSpace([[maybe_unused]] const Activation& caller)
720204e1e74SAdriana Kobylak {
721*d8c9eea3SLei YU #ifdef BMC_STATIC_DUAL_IMAGE
722*d8c9eea3SLei YU     // For the golden image case, always remove the version on the primary side
723*d8c9eea3SLei YU     std::string versionIDtoErase;
724*d8c9eea3SLei YU     for (const auto& iter : activations)
725*d8c9eea3SLei YU     {
726*d8c9eea3SLei YU         if (iter.second->redundancyPriority &&
727*d8c9eea3SLei YU             iter.second->redundancyPriority.get()->priority() == 0)
728*d8c9eea3SLei YU         {
729*d8c9eea3SLei YU             versionIDtoErase = iter.second->versionId;
730*d8c9eea3SLei YU             break;
731*d8c9eea3SLei YU         }
732*d8c9eea3SLei YU     }
733*d8c9eea3SLei YU     if (!versionIDtoErase.empty())
734*d8c9eea3SLei YU     {
735*d8c9eea3SLei YU         erase(versionIDtoErase);
736*d8c9eea3SLei YU     }
737*d8c9eea3SLei YU     else
738*d8c9eea3SLei YU     {
739*d8c9eea3SLei YU         warning("Failed to find version to erase");
740*d8c9eea3SLei YU     }
741*d8c9eea3SLei YU #else
742204e1e74SAdriana Kobylak     //  Versions with the highest priority in front
743204e1e74SAdriana Kobylak     std::priority_queue<std::pair<int, std::string>,
744204e1e74SAdriana Kobylak                         std::vector<std::pair<int, std::string>>,
7452285fe0fSAdriana Kobylak                         std::less<std::pair<int, std::string>>>
7462285fe0fSAdriana Kobylak         versionsPQ;
747204e1e74SAdriana Kobylak 
748204e1e74SAdriana Kobylak     std::size_t count = 0;
749204e1e74SAdriana Kobylak     for (const auto& iter : activations)
750204e1e74SAdriana Kobylak     {
751204e1e74SAdriana Kobylak         if ((iter.second.get()->activation() ==
752204e1e74SAdriana Kobylak              server::Activation::Activations::Active) ||
753204e1e74SAdriana Kobylak             (iter.second.get()->activation() ==
754204e1e74SAdriana Kobylak              server::Activation::Activations::Failed))
755204e1e74SAdriana Kobylak         {
756204e1e74SAdriana Kobylak             count++;
757204e1e74SAdriana Kobylak             // Don't put the functional version on the queue since we can't
758204e1e74SAdriana Kobylak             // remove the "running" BMC version.
7590f88b5afSLei YU             // If ACTIVE_BMC_MAX_ALLOWED <= 1, there is only one active BMC,
7600f88b5afSLei YU             // so remove functional version as well.
761a6963590SAdriana Kobylak             // Don't delete the the Activation object that called this function.
762a6963590SAdriana Kobylak             if ((versions.find(iter.second->versionId)
763a6963590SAdriana Kobylak                      ->second->isFunctional() &&
764a6963590SAdriana Kobylak                  ACTIVE_BMC_MAX_ALLOWED > 1) ||
765a6963590SAdriana Kobylak                 (iter.second->versionId == caller.versionId))
766204e1e74SAdriana Kobylak             {
767204e1e74SAdriana Kobylak                 continue;
768204e1e74SAdriana Kobylak             }
769a6963590SAdriana Kobylak 
770a6963590SAdriana Kobylak             // Failed activations don't have priority, assign them a large value
771a6963590SAdriana Kobylak             // for sorting purposes.
772a6963590SAdriana Kobylak             auto priority = 999;
773a6963590SAdriana Kobylak             if (iter.second.get()->activation() ==
774cfb4b209SLei YU                     server::Activation::Activations::Active &&
775cfb4b209SLei YU                 iter.second->redundancyPriority)
776a6963590SAdriana Kobylak             {
777a6963590SAdriana Kobylak                 priority = iter.second->redundancyPriority.get()->priority();
778a6963590SAdriana Kobylak             }
779a6963590SAdriana Kobylak 
780a6963590SAdriana Kobylak             versionsPQ.push(std::make_pair(priority, iter.second->versionId));
781204e1e74SAdriana Kobylak         }
782204e1e74SAdriana Kobylak     }
783204e1e74SAdriana Kobylak 
784204e1e74SAdriana Kobylak     // If the number of BMC versions is over ACTIVE_BMC_MAX_ALLOWED -1,
785204e1e74SAdriana Kobylak     // remove the highest priority one(s).
786204e1e74SAdriana Kobylak     while ((count >= ACTIVE_BMC_MAX_ALLOWED) && (!versionsPQ.empty()))
787204e1e74SAdriana Kobylak     {
788204e1e74SAdriana Kobylak         erase(versionsPQ.top().second);
789204e1e74SAdriana Kobylak         versionsPQ.pop();
790204e1e74SAdriana Kobylak         count--;
791204e1e74SAdriana Kobylak     }
792*d8c9eea3SLei YU #endif
793204e1e74SAdriana Kobylak }
794204e1e74SAdriana Kobylak 
795eaa1ee05SEddie James void ItemUpdater::mirrorUbootToAlt()
796eaa1ee05SEddie James {
79756aaf454SLei YU     helper.mirrorAlt();
798eaa1ee05SEddie James }
799eaa1ee05SEddie James 
8008e9ccfe7SBright Cheng bool ItemUpdater::checkImage(const std::string& filePath,
8018e9ccfe7SBright Cheng                              const std::vector<std::string>& imageList)
8028e9ccfe7SBright Cheng {
8038e9ccfe7SBright Cheng     bool valid = true;
8048e9ccfe7SBright Cheng 
8058e9ccfe7SBright Cheng     for (auto& bmcImage : imageList)
8068e9ccfe7SBright Cheng     {
8078e9ccfe7SBright Cheng         fs::path file(filePath);
8088e9ccfe7SBright Cheng         file /= bmcImage;
8098e9ccfe7SBright Cheng         std::ifstream efile(file.c_str());
8108e9ccfe7SBright Cheng         if (efile.good() != 1)
8118e9ccfe7SBright Cheng         {
8128e9ccfe7SBright Cheng             valid = false;
8138e9ccfe7SBright Cheng             break;
8148e9ccfe7SBright Cheng         }
8158e9ccfe7SBright Cheng     }
8168e9ccfe7SBright Cheng 
8178e9ccfe7SBright Cheng     return valid;
8188e9ccfe7SBright Cheng }
8198e9ccfe7SBright Cheng 
8206e9fb1d6SLei YU #ifdef HOST_BIOS_UPGRADE
8216e9fb1d6SLei YU void ItemUpdater::createBIOSObject()
8226e9fb1d6SLei YU {
8236e9fb1d6SLei YU     std::string path = BIOS_OBJPATH;
8246e9fb1d6SLei YU     // Get version id from last item in the path
8256e9fb1d6SLei YU     auto pos = path.rfind("/");
8266e9fb1d6SLei YU     if (pos == std::string::npos)
8276e9fb1d6SLei YU     {
828c9bb6425SPatrick Williams         error("No version id found in object path {PATH}", "PATH", path);
8296e9fb1d6SLei YU         return;
8306e9fb1d6SLei YU     }
8316e9fb1d6SLei YU 
8326e9fb1d6SLei YU     createActiveAssociation(path);
8336e9fb1d6SLei YU     createFunctionalAssociation(path);
8346e9fb1d6SLei YU 
8356e9fb1d6SLei YU     auto versionId = path.substr(pos + 1);
8366e9fb1d6SLei YU     auto version = "null";
8376e9fb1d6SLei YU     AssociationList assocs = {};
8386e9fb1d6SLei YU     biosActivation = std::make_unique<Activation>(
8396e9fb1d6SLei YU         bus, path, *this, versionId, server::Activation::Activations::Active,
8406e9fb1d6SLei YU         assocs);
8416e9fb1d6SLei YU     auto dummyErase = [](std::string /*entryId*/) {
8426e9fb1d6SLei YU         // Do nothing;
8436e9fb1d6SLei YU     };
8446e9fb1d6SLei YU     biosVersion = std::make_unique<VersionClass>(
8456e9fb1d6SLei YU         bus, path, version, VersionPurpose::Host, "", "",
84659b640b0SAdriana Kobylak         std::bind(dummyErase, std::placeholders::_1), "");
8476e9fb1d6SLei YU     biosVersion->deleteObject =
8486e9fb1d6SLei YU         std::make_unique<phosphor::software::manager::Delete>(bus, path,
8496e9fb1d6SLei YU                                                               *biosVersion);
8506e9fb1d6SLei YU }
8516e9fb1d6SLei YU #endif
8526e9fb1d6SLei YU 
853531fbc25SLei YU void ItemUpdater::getRunningSlot()
854531fbc25SLei YU {
855531fbc25SLei YU     // Check /run/media/slot to get the slot number
856531fbc25SLei YU     constexpr auto slotFile = "/run/media/slot";
857531fbc25SLei YU     std::fstream f(slotFile, std::ios_base::in);
858531fbc25SLei YU     f >> runningImageSlot;
859531fbc25SLei YU }
860531fbc25SLei YU 
861ec1b41c4SGunnar Mills } // namespace updater
862ec1b41c4SGunnar Mills } // namespace software
863ec1b41c4SGunnar Mills } // namespace phosphor
864