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>
2244b9fef9SGeorge Liu #include <system_error>
23ec1b41c4SGunnar Mills 
24ec1b41c4SGunnar Mills namespace phosphor
25ec1b41c4SGunnar Mills {
26ec1b41c4SGunnar Mills namespace software
27ec1b41c4SGunnar Mills {
28ec1b41c4SGunnar Mills namespace updater
29ec1b41c4SGunnar Mills {
30ec1b41c4SGunnar Mills 
312ce7da29SGunnar Mills // When you see server:: you know we're referencing our base class
321e9a5f1aSPatrick Williams namespace server = sdbusplus::server::xyz::openbmc_project::software;
331e9a5f1aSPatrick Williams namespace control = sdbusplus::server::xyz::openbmc_project::control;
342ce7da29SGunnar Mills 
35c9bb6425SPatrick Williams PHOSPHOR_LOG2_USING;
362ce7da29SGunnar Mills using namespace phosphor::logging;
37ce82de51SAdriana Kobylak using namespace sdbusplus::error::xyz::openbmc_project::software::image;
382ab9b109SJayanth Othayoth using namespace phosphor::software::image;
39c98d912eSAdriana Kobylak namespace fs = std::filesystem;
40ce82de51SAdriana Kobylak using NotAllowed = sdbusplus::error::xyz::openbmc_project::common::NotAllowed;
4135e83f3eSSaqib Khan 
createActivation(sdbusplus::message_t & msg)42bf2bb2b1SPatrick Williams void ItemUpdater::createActivation(sdbusplus::message_t& msg)
43ec1b41c4SGunnar Mills {
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;
52054bb0b8SJustin Ledford     std::map<std::string,
53054bb0b8SJustin Ledford              std::map<std::string,
54054bb0b8SJustin Ledford                       std::variant<std::string, std::vector<std::string>>>>
552285fe0fSAdriana Kobylak         interfaces;
56e75d10f5SPatrick Williams     msg.read(objPath, interfaces);
572ce7da29SGunnar Mills     std::string path(std::move(objPath));
5819177d3eSSaqib Khan     std::string filePath;
59054bb0b8SJustin Ledford     std::vector<std::string> compatibleNames;
602ce7da29SGunnar Mills 
612ce7da29SGunnar Mills     for (const auto& intf : interfaces)
622ce7da29SGunnar Mills     {
63705f1bfcSSaqib Khan         if (intf.first == VERSION_IFACE)
642ce7da29SGunnar Mills         {
652ce7da29SGunnar Mills             for (const auto& property : intf.second)
662ce7da29SGunnar Mills             {
67705f1bfcSSaqib Khan                 if (property.first == "Purpose")
682ce7da29SGunnar Mills                 {
6984a0e693SSaqib Khan                     auto value = SVersion::convertVersionPurposeFromString(
70e883fb8bSPatrick Williams                         std::get<std::string>(property.second));
7184a0e693SSaqib Khan                     if (value == VersionPurpose::BMC ||
72e9f6c845SVijay Khemka #ifdef HOST_BIOS_UPGRADE
73e9f6c845SVijay Khemka                         value == VersionPurpose::Host ||
74e9f6c845SVijay Khemka #endif
7584a0e693SSaqib Khan                         value == VersionPurpose::System)
7684a0e693SSaqib Khan                     {
7784a0e693SSaqib Khan                         purpose = value;
7884a0e693SSaqib Khan                     }
79705f1bfcSSaqib Khan                 }
80705f1bfcSSaqib Khan                 else if (property.first == "Version")
81705f1bfcSSaqib Khan                 {
82e883fb8bSPatrick Williams                     version = std::get<std::string>(property.second);
83705f1bfcSSaqib Khan                 }
84705f1bfcSSaqib Khan             }
85705f1bfcSSaqib Khan         }
8619177d3eSSaqib Khan         else if (intf.first == FILEPATH_IFACE)
8719177d3eSSaqib Khan         {
8819177d3eSSaqib Khan             for (const auto& property : intf.second)
8919177d3eSSaqib Khan             {
9019177d3eSSaqib Khan                 if (property.first == "Path")
9119177d3eSSaqib Khan                 {
92e883fb8bSPatrick Williams                     filePath = std::get<std::string>(property.second);
9319177d3eSSaqib Khan                 }
9419177d3eSSaqib Khan             }
9519177d3eSSaqib Khan         }
961fd6dddfSChanh Nguyen         else if (intf.first == EXTENDED_VERSION_IFACE)
971fd6dddfSChanh Nguyen         {
981fd6dddfSChanh Nguyen             for (const auto& property : intf.second)
991fd6dddfSChanh Nguyen             {
1001fd6dddfSChanh Nguyen                 if (property.first == "ExtendedVersion")
1011fd6dddfSChanh Nguyen                 {
1021fd6dddfSChanh Nguyen                     extendedVersion = std::get<std::string>(property.second);
1031fd6dddfSChanh Nguyen                 }
1041fd6dddfSChanh Nguyen             }
1051fd6dddfSChanh Nguyen         }
106054bb0b8SJustin Ledford         else if (intf.first == COMPATIBLE_IFACE)
107054bb0b8SJustin Ledford         {
108054bb0b8SJustin Ledford             for (const auto& property : intf.second)
109054bb0b8SJustin Ledford             {
110054bb0b8SJustin Ledford                 if (property.first == "Names")
111054bb0b8SJustin Ledford                 {
112054bb0b8SJustin Ledford                     compatibleNames =
113054bb0b8SJustin Ledford                         std::get<std::vector<std::string>>(property.second);
114054bb0b8SJustin Ledford                 }
115054bb0b8SJustin Ledford             }
116054bb0b8SJustin Ledford         }
117705f1bfcSSaqib Khan     }
1182285fe0fSAdriana Kobylak     if (version.empty() || filePath.empty() ||
11984a0e693SSaqib Khan         purpose == VersionPurpose::Unknown)
1202ce7da29SGunnar Mills     {
121e75d10f5SPatrick Williams         return;
1222ce7da29SGunnar Mills     }
1232ce7da29SGunnar Mills 
1242ce7da29SGunnar Mills     // Version id is the last item in the path
1252ce7da29SGunnar Mills     auto pos = path.rfind("/");
1262ce7da29SGunnar Mills     if (pos == std::string::npos)
1272ce7da29SGunnar Mills     {
128c9bb6425SPatrick Williams         error("No version id found in object path: {PATH}", "PATH", path);
129e75d10f5SPatrick Williams         return;
1302ce7da29SGunnar Mills     }
1312ce7da29SGunnar Mills 
1322ce7da29SGunnar Mills     auto versionId = path.substr(pos + 1);
1332ce7da29SGunnar Mills 
134e75d10f5SPatrick Williams     if (activations.find(versionId) == activations.end())
1352ce7da29SGunnar Mills     {
13635e83f3eSSaqib Khan         // Determine the Activation state by processing the given image dir.
13735e83f3eSSaqib Khan         auto activationState = server::Activation::Activations::Invalid;
138e9f6c845SVijay Khemka         ItemUpdater::ActivationStatus result;
139e9f6c845SVijay Khemka         if (purpose == VersionPurpose::BMC || purpose == VersionPurpose::System)
140e9f6c845SVijay Khemka             result = ItemUpdater::validateSquashFSImage(filePath);
141e9f6c845SVijay Khemka         else
142e9f6c845SVijay Khemka             result = ItemUpdater::ActivationStatus::ready;
143e9f6c845SVijay Khemka 
14443b25cdeSGunnar Mills         AssociationList associations = {};
14543b25cdeSGunnar Mills 
14635e83f3eSSaqib Khan         if (result == ItemUpdater::ActivationStatus::ready)
14735e83f3eSSaqib Khan         {
14835e83f3eSSaqib Khan             activationState = server::Activation::Activations::Ready;
149b60add1eSGunnar Mills             // Create an association to the BMC inventory item
1502285fe0fSAdriana Kobylak             associations.emplace_back(
1512285fe0fSAdriana Kobylak                 std::make_tuple(ACTIVATION_FWD_ASSOCIATION,
1522285fe0fSAdriana Kobylak                                 ACTIVATION_REV_ASSOCIATION, bmcInventoryPath));
15343b25cdeSGunnar Mills         }
154b60add1eSGunnar Mills 
155ee13e831SSaqib Khan         auto versionPtr = std::make_unique<VersionClass>(
1561fd6dddfSChanh Nguyen             bus, path, version, purpose, extendedVersion, filePath,
157054bb0b8SJustin Ledford             compatibleNames,
15859b640b0SAdriana Kobylak             std::bind(&ItemUpdater::erase, this, std::placeholders::_1),
15959b640b0SAdriana Kobylak             versionId);
160ee13e831SSaqib Khan         versionPtr->deleteObject =
1612285fe0fSAdriana Kobylak             std::make_unique<phosphor::software::manager::Delete>(bus, path,
1622285fe0fSAdriana Kobylak                                                                   *versionPtr);
163ee13e831SSaqib Khan         versions.insert(std::make_pair(versionId, std::move(versionPtr)));
16488ba1f9eSAdriana Kobylak 
16588ba1f9eSAdriana Kobylak         activations.insert(std::make_pair(
16688ba1f9eSAdriana Kobylak             versionId,
16788ba1f9eSAdriana Kobylak             std::make_unique<Activation>(bus, path, *this, versionId,
16888ba1f9eSAdriana Kobylak                                          activationState, associations)));
1692ce7da29SGunnar Mills     }
170e75d10f5SPatrick Williams     return;
171ec1b41c4SGunnar Mills }
172ec1b41c4SGunnar Mills 
processBMCImage()173ba239881SSaqib Khan void ItemUpdater::processBMCImage()
174ba239881SSaqib Khan {
17588e8a325SGunnar Mills     using VersionClass = phosphor::software::manager::Version;
176269bff30SLei YU 
177269bff30SLei YU     // Check MEDIA_DIR and create if it does not exist
178269bff30SLei YU     try
179269bff30SLei YU     {
180269bff30SLei YU         if (!fs::is_directory(MEDIA_DIR))
181269bff30SLei YU         {
182269bff30SLei YU             fs::create_directory(MEDIA_DIR);
183269bff30SLei YU         }
184269bff30SLei YU     }
185269bff30SLei YU     catch (const fs::filesystem_error& e)
186269bff30SLei YU     {
187c9bb6425SPatrick Williams         error("Failed to prepare dir: {ERROR}", "ERROR", e);
188269bff30SLei YU         return;
189269bff30SLei YU     }
190269bff30SLei YU 
1911e81f23cSAdriana Kobylak     // Functional images are mounted as rofs-<location>-functional
1921e81f23cSAdriana Kobylak     constexpr auto functionalSuffix = "-functional";
193d474d9cdSLei YU     bool functionalFound = false;
19488e8a325SGunnar Mills 
1951eef62deSSaqib Khan     // Read os-release from folders under /media/ to get
1961eef62deSSaqib Khan     // BMC Software Versions.
19744b9fef9SGeorge Liu     std::error_code ec;
19844b9fef9SGeorge Liu     for (const auto& iter : fs::directory_iterator(MEDIA_DIR, ec))
1991eef62deSSaqib Khan     {
2001eef62deSSaqib Khan         auto activationState = server::Activation::Activations::Active;
2016fab70daSSaqib Khan         static const auto BMC_RO_PREFIX_LEN = strlen(BMC_ROFS_PREFIX);
2021eef62deSSaqib Khan 
2031eef62deSSaqib Khan         // Check if the BMC_RO_PREFIXis the prefix of the iter.path
2042285fe0fSAdriana Kobylak         if (0 ==
2052285fe0fSAdriana Kobylak             iter.path().native().compare(0, BMC_RO_PREFIX_LEN, BMC_ROFS_PREFIX))
2061eef62deSSaqib Khan         {
207716cd78dSAdriana Kobylak             // Get the version to calculate the id
20824a8d83dSAdriana Kobylak             fs::path releaseFile(OS_RELEASE_FILE);
20924a8d83dSAdriana Kobylak             auto osRelease = iter.path() / releaseFile.relative_path();
21044b9fef9SGeorge Liu             if (!fs::is_regular_file(osRelease, ec))
2111eef62deSSaqib Khan             {
212e56bf878SLei YU #ifdef BMC_STATIC_DUAL_IMAGE
213e56bf878SLei YU                 // For dual image, it is possible that the secondary image is
214e56bf878SLei YU                 // empty or contains invalid data, ignore such case.
21544b9fef9SGeorge Liu                 info("Unable to find osRelease: {PATH}: {ERROR_MSG}", "PATH",
21644b9fef9SGeorge Liu                      osRelease, "ERROR_MSG", ec.message());
217e56bf878SLei YU #else
21844b9fef9SGeorge Liu                 error("Failed to read osRelease: {PATH}: {ERROR_MSG}", "PATH",
21944b9fef9SGeorge Liu                       osRelease, "ERROR_MSG", ec.message());
220716cd78dSAdriana Kobylak 
221716cd78dSAdriana Kobylak                 // Try to get the version id from the mount directory name and
222716cd78dSAdriana Kobylak                 // call to delete it as this version may be corrupted. Dynamic
223716cd78dSAdriana Kobylak                 // volumes created by the UBI layout for example have the id in
224716cd78dSAdriana Kobylak                 // the mount directory name. The worst that can happen is that
225716cd78dSAdriana Kobylak                 // erase() is called with an non-existent id and returns.
226716cd78dSAdriana Kobylak                 auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN);
227021c365bSSaqib Khan                 ItemUpdater::erase(id);
228e56bf878SLei YU #endif
229716cd78dSAdriana Kobylak 
230021c365bSSaqib Khan                 continue;
2311eef62deSSaqib Khan             }
23288e8a325SGunnar Mills             auto version = VersionClass::getBMCVersion(osRelease);
2331eef62deSSaqib Khan             if (version.empty())
2341eef62deSSaqib Khan             {
235c9bb6425SPatrick Williams                 error("Failed to read version from osRelease: {PATH}", "PATH",
236c9bb6425SPatrick Williams                       osRelease);
237716cd78dSAdriana Kobylak 
238716cd78dSAdriana Kobylak                 // Try to delete the version, same as above if the
239716cd78dSAdriana Kobylak                 // OS_RELEASE_FILE does not exist.
240716cd78dSAdriana Kobylak                 auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN);
241716cd78dSAdriana Kobylak                 ItemUpdater::erase(id);
242716cd78dSAdriana Kobylak 
243716cd78dSAdriana Kobylak                 continue;
2441eef62deSSaqib Khan             }
245021c365bSSaqib Khan 
24659b640b0SAdriana Kobylak             // The flash location is part of the mount name: rofs-<location>
24759b640b0SAdriana Kobylak             auto flashId = iter.path().native().substr(BMC_RO_PREFIX_LEN);
24859b640b0SAdriana Kobylak 
24959b640b0SAdriana Kobylak             auto id = VersionClass::getId(version + flashId);
250716cd78dSAdriana Kobylak 
251f383d27aSAdriana Kobylak             // Check if the id has already been added. This can happen if the
252f383d27aSAdriana Kobylak             // BMC partitions / devices were manually flashed with the same
253f383d27aSAdriana Kobylak             // image.
254f383d27aSAdriana Kobylak             if (versions.find(id) != versions.end())
255f383d27aSAdriana Kobylak             {
256f383d27aSAdriana Kobylak                 continue;
257f383d27aSAdriana Kobylak             }
258f383d27aSAdriana Kobylak 
2591e81f23cSAdriana Kobylak             auto functional = false;
2601e81f23cSAdriana Kobylak             if (iter.path().native().find(functionalSuffix) !=
2611e81f23cSAdriana Kobylak                 std::string::npos)
2621e81f23cSAdriana Kobylak             {
2631e81f23cSAdriana Kobylak                 // Set functional to true and remove the functional suffix
2641e81f23cSAdriana Kobylak                 functional = true;
2651e81f23cSAdriana Kobylak                 flashId.erase(flashId.length() - strlen(functionalSuffix));
266d474d9cdSLei YU                 functionalFound = true;
2671e81f23cSAdriana Kobylak             }
268780220f2SAdriana Kobylak 
2691eef62deSSaqib Khan             auto purpose = server::Version::VersionPurpose::BMC;
270780220f2SAdriana Kobylak             restorePurpose(flashId, purpose);
271ec4eec34SAdriana Kobylak 
2721fd6dddfSChanh Nguyen             // Read os-release from /etc/ to get the BMC extended version
2731fd6dddfSChanh Nguyen             std::string extendedVersion =
2741fd6dddfSChanh Nguyen                 VersionClass::getBMCExtendedVersion(osRelease);
2751fd6dddfSChanh Nguyen 
2761eef62deSSaqib Khan             auto path = fs::path(SOFTWARE_OBJPATH) / id;
2771eef62deSSaqib Khan 
278269bff30SLei YU             // Create functional association if this is the functional
279269bff30SLei YU             // version
2801e81f23cSAdriana Kobylak             if (functional)
28188e8a325SGunnar Mills             {
28288e8a325SGunnar Mills                 createFunctionalAssociation(path);
28388e8a325SGunnar Mills             }
28488e8a325SGunnar Mills 
28543b25cdeSGunnar Mills             AssociationList associations = {};
28643b25cdeSGunnar Mills 
28743b25cdeSGunnar Mills             if (activationState == server::Activation::Activations::Active)
28843b25cdeSGunnar Mills             {
28943b25cdeSGunnar Mills                 // Create an association to the BMC inventory item
29043b25cdeSGunnar Mills                 associations.emplace_back(std::make_tuple(
2912285fe0fSAdriana Kobylak                     ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
29243b25cdeSGunnar Mills                     bmcInventoryPath));
29343b25cdeSGunnar Mills 
29443b25cdeSGunnar Mills                 // Create an active association since this image is active
29543b25cdeSGunnar Mills                 createActiveAssociation(path);
29643b25cdeSGunnar Mills             }
29743b25cdeSGunnar Mills 
298bbebec79SAppaRao Puli             // All updateable firmware components must expose the updateable
299bbebec79SAppaRao Puli             // association.
300bbebec79SAppaRao Puli             createUpdateableAssociation(path);
301bbebec79SAppaRao Puli 
302ee590c74SAdriana Kobylak             // Create Version instance for this version.
303ee590c74SAdriana Kobylak             auto versionPtr = std::make_unique<VersionClass>(
304a84f06d2SAdriana Kobylak                 bus, path, version, purpose, extendedVersion, flashId,
305054bb0b8SJustin Ledford                 std::vector<std::string>(),
30659b640b0SAdriana Kobylak                 std::bind(&ItemUpdater::erase, this, std::placeholders::_1),
30759b640b0SAdriana Kobylak                 id);
3081e81f23cSAdriana Kobylak             if (functional)
3091e81f23cSAdriana Kobylak             {
3101e81f23cSAdriana Kobylak                 versionPtr->setFunctional(true);
3111e81f23cSAdriana Kobylak             }
3121e81f23cSAdriana Kobylak             else
313ee13e831SSaqib Khan             {
314ee13e831SSaqib Khan                 versionPtr->deleteObject =
315ee13e831SSaqib Khan                     std::make_unique<phosphor::software::manager::Delete>(
316ee13e831SSaqib Khan                         bus, path, *versionPtr);
317ee13e831SSaqib Khan             }
3182285fe0fSAdriana Kobylak             versions.insert(std::make_pair(id, std::move(versionPtr)));
319ee590c74SAdriana Kobylak 
3201eef62deSSaqib Khan             // Create Activation instance for this version.
321ee13e831SSaqib Khan             activations.insert(std::make_pair(
3222285fe0fSAdriana Kobylak                 id, std::make_unique<Activation>(
3232285fe0fSAdriana Kobylak                         bus, path, *this, id, activationState, associations)));
3241eef62deSSaqib Khan 
325bdf2d6ceSLei YU #ifdef BMC_STATIC_DUAL_IMAGE
326bdf2d6ceSLei YU             uint8_t priority;
327bdf2d6ceSLei YU             if ((functional && (runningImageSlot == 0)) ||
328bdf2d6ceSLei YU                 (!functional && (runningImageSlot == 1)))
329bdf2d6ceSLei YU             {
330bdf2d6ceSLei YU                 priority = 0;
331bdf2d6ceSLei YU             }
332bdf2d6ceSLei YU             else
333bdf2d6ceSLei YU             {
334bdf2d6ceSLei YU                 priority = 1;
335bdf2d6ceSLei YU             }
336bdf2d6ceSLei YU             activations.find(id)->second->redundancyPriority =
337bdf2d6ceSLei YU                 std::make_unique<RedundancyPriority>(
338bdf2d6ceSLei YU                     bus, path, *(activations.find(id)->second), priority,
339bdf2d6ceSLei YU                     false);
340bdf2d6ceSLei YU #else
341269bff30SLei YU             // If Active, create RedundancyPriority instance for this
342269bff30SLei YU             // version.
3431eef62deSSaqib Khan             if (activationState == server::Activation::Activations::Active)
3441eef62deSSaqib Khan             {
3451eef62deSSaqib Khan                 uint8_t priority = std::numeric_limits<uint8_t>::max();
346780220f2SAdriana Kobylak                 if (!restorePriority(flashId, priority))
3471eef62deSSaqib Khan                 {
3481e81f23cSAdriana Kobylak                     if (functional)
349ee590c74SAdriana Kobylak                     {
350ee590c74SAdriana Kobylak                         priority = 0;
351ee590c74SAdriana Kobylak                     }
352ee590c74SAdriana Kobylak                     else
353ee590c74SAdriana Kobylak                     {
354c9bb6425SPatrick Williams                         error(
355c9bb6425SPatrick Williams                             "Unable to restore priority from file for {VERSIONID}",
356c9bb6425SPatrick Williams                             "VERSIONID", id);
3571eef62deSSaqib Khan                     }
358ee590c74SAdriana Kobylak                 }
3591eef62deSSaqib Khan                 activations.find(id)->second->redundancyPriority =
3601eef62deSSaqib Khan                     std::make_unique<RedundancyPriority>(
3612285fe0fSAdriana Kobylak                         bus, path, *(activations.find(id)->second), priority,
362b77551cdSAdriana Kobylak                         false);
3631eef62deSSaqib Khan             }
364bdf2d6ceSLei YU #endif
3651eef62deSSaqib Khan         }
3661eef62deSSaqib Khan     }
367dcbfa04aSSaqib Khan 
368d474d9cdSLei YU     if (!functionalFound)
369dcbfa04aSSaqib Khan     {
370d474d9cdSLei YU         // If there is no functional version found, read the /etc/os-release and
371d474d9cdSLei YU         // create rofs-<versionId>-functional under MEDIA_DIR, then call again
372d474d9cdSLei YU         // processBMCImage() to create the D-Bus interface for it.
373d16bcbd5SGunnar Mills         auto version = VersionClass::getBMCVersion(OS_RELEASE_FILE);
37459b640b0SAdriana Kobylak         auto id = phosphor::software::manager::Version::getId(version +
37559b640b0SAdriana Kobylak                                                               functionalSuffix);
3761e81f23cSAdriana Kobylak         auto versionFileDir = BMC_ROFS_PREFIX + id + functionalSuffix + "/etc/";
377dcbfa04aSSaqib Khan         try
378dcbfa04aSSaqib Khan         {
379dcbfa04aSSaqib Khan             if (!fs::is_directory(versionFileDir))
380dcbfa04aSSaqib Khan             {
381dcbfa04aSSaqib Khan                 fs::create_directories(versionFileDir);
382dcbfa04aSSaqib Khan             }
383d5e8e73bSPatrick Williams             auto versionFilePath = BMC_ROFS_PREFIX + id + functionalSuffix +
384d5e8e73bSPatrick Williams                                    OS_RELEASE_FILE;
385dcbfa04aSSaqib Khan             fs::create_directory_symlink(OS_RELEASE_FILE, versionFilePath);
386dcbfa04aSSaqib Khan             ItemUpdater::processBMCImage();
387dcbfa04aSSaqib Khan         }
388dcbfa04aSSaqib Khan         catch (const std::exception& e)
389dcbfa04aSSaqib Khan         {
390c9bb6425SPatrick Williams             error("Exception during processing: {ERROR}", "ERROR", e);
391dcbfa04aSSaqib Khan         }
392dcbfa04aSSaqib Khan     }
393eaa1ee05SEddie James 
394eaa1ee05SEddie James     mirrorUbootToAlt();
395ba239881SSaqib Khan     return;
396ba239881SSaqib Khan }
397ba239881SSaqib Khan 
erase(std::string entryId)3983526ef73SLeonel Gonzalez void ItemUpdater::erase(std::string entryId)
3993526ef73SLeonel Gonzalez {
4006d873715SEddie James     // Find entry in versions map
4016d873715SEddie James     auto it = versions.find(entryId);
4026d873715SEddie James     if (it != versions.end())
4036d873715SEddie James     {
4040f88b5afSLei YU         if (it->second->isFunctional() && ACTIVE_BMC_MAX_ALLOWED > 1)
4056d873715SEddie James         {
406c9bb6425SPatrick Williams             error(
407c9bb6425SPatrick Williams                 "Version ({VERSIONID}) is currently running on the BMC; unable to remove.",
408c9bb6425SPatrick Williams                 "VERSIONID", entryId);
4096d873715SEddie James             return;
4106d873715SEddie James         }
411d1a55adcSAdriana Kobylak     }
4126d873715SEddie James 
413d1a55adcSAdriana Kobylak     // First call resetUbootEnvVars() so that the BMC points to a valid image to
414d1a55adcSAdriana Kobylak     // boot from. If resetUbootEnvVars() is called after the image is actually
415d1a55adcSAdriana Kobylak     // deleted from the BMC flash, there'd be a time window where the BMC would
416d1a55adcSAdriana Kobylak     // be pointing to a non-existent image to boot from.
417d1a55adcSAdriana Kobylak     // Need to remove the entries from the activations map before that call so
418d1a55adcSAdriana Kobylak     // that resetUbootEnvVars() doesn't use the version to be deleted.
419d1a55adcSAdriana Kobylak     auto iteratorActivations = activations.find(entryId);
420d1a55adcSAdriana Kobylak     if (iteratorActivations == activations.end())
421d1a55adcSAdriana Kobylak     {
422c9bb6425SPatrick Williams         error(
423c9bb6425SPatrick Williams             "Failed to find version ({VERSIONID}) in item updater activations map; unable to remove.",
424c9bb6425SPatrick Williams             "VERSIONID", entryId);
425d1a55adcSAdriana Kobylak     }
426d1a55adcSAdriana Kobylak     else
427d1a55adcSAdriana Kobylak     {
428d1a55adcSAdriana Kobylak         removeAssociations(iteratorActivations->second->path);
429ae06d76aSZami Seck         iteratorActivations->second->deleteImageManagerObject();
430d1a55adcSAdriana Kobylak         this->activations.erase(entryId);
431d1a55adcSAdriana Kobylak     }
432d1a55adcSAdriana Kobylak     ItemUpdater::resetUbootEnvVars();
433d1a55adcSAdriana Kobylak 
434d1a55adcSAdriana Kobylak     if (it != versions.end())
435d1a55adcSAdriana Kobylak     {
436780220f2SAdriana Kobylak         auto flashId = it->second->path();
437780220f2SAdriana Kobylak 
43825773a7eSAdriana Kobylak         // Delete version data if it has been installed on flash (path is not
43925773a7eSAdriana Kobylak         // the upload directory)
44025773a7eSAdriana Kobylak         if (flashId.find(IMG_UPLOAD_DIR) == std::string::npos)
44125773a7eSAdriana Kobylak         {
4423526ef73SLeonel Gonzalez             removeReadOnlyPartition(entryId);
443780220f2SAdriana Kobylak             removePersistDataDirectory(flashId);
44425773a7eSAdriana Kobylak             helper.clearEntry(flashId);
44525773a7eSAdriana Kobylak         }
446ee13e831SSaqib Khan 
447ee13e831SSaqib Khan         // Removing entry in versions map
448ee13e831SSaqib Khan         this->versions.erase(entryId);
4496d873715SEddie James     }
4503526ef73SLeonel Gonzalez 
451ee13e831SSaqib Khan     return;
4523526ef73SLeonel Gonzalez }
4533526ef73SLeonel Gonzalez 
deleteAll()454bc1bf3afSMichael Tritz void ItemUpdater::deleteAll()
455bc1bf3afSMichael Tritz {
45683cd21fbSAdriana Kobylak     std::vector<std::string> deletableVersions;
45783cd21fbSAdriana Kobylak 
458bc1bf3afSMichael Tritz     for (const auto& versionIt : versions)
459bc1bf3afSMichael Tritz     {
460bc1bf3afSMichael Tritz         if (!versionIt.second->isFunctional())
461bc1bf3afSMichael Tritz         {
46283cd21fbSAdriana Kobylak             deletableVersions.push_back(versionIt.first);
463bc1bf3afSMichael Tritz         }
464bc1bf3afSMichael Tritz     }
465bc1bf3afSMichael Tritz 
46683cd21fbSAdriana Kobylak     for (const auto& deletableIt : deletableVersions)
46783cd21fbSAdriana Kobylak     {
46883cd21fbSAdriana Kobylak         ItemUpdater::erase(deletableIt);
46983cd21fbSAdriana Kobylak     }
47083cd21fbSAdriana Kobylak 
47156aaf454SLei YU     helper.cleanup();
472bc1bf3afSMichael Tritz }
473bc1bf3afSMichael Tritz 
4742285fe0fSAdriana Kobylak ItemUpdater::ActivationStatus
validateSquashFSImage(const std::string & filePath)4752285fe0fSAdriana Kobylak     ItemUpdater::validateSquashFSImage(const std::string& filePath)
47635e83f3eSSaqib Khan {
4778e9ccfe7SBright Cheng     bool valid = true;
47835e83f3eSSaqib Khan 
4798e9ccfe7SBright Cheng     // Record the images which are being updated
4808e9ccfe7SBright Cheng     // First check for the fullimage, then check for images with partitions
4818e9ccfe7SBright Cheng     imageUpdateList.push_back(bmcFullImages);
4828e9ccfe7SBright Cheng     valid = checkImage(filePath, imageUpdateList);
4838e9ccfe7SBright Cheng     if (!valid)
484b1cfdf99SMichael Tritz     {
4858e9ccfe7SBright Cheng         imageUpdateList.clear();
4868e9ccfe7SBright Cheng         imageUpdateList.assign(bmcImages.begin(), bmcImages.end());
4878e9ccfe7SBright Cheng         valid = checkImage(filePath, imageUpdateList);
4888e9ccfe7SBright Cheng         if (!valid)
48935e83f3eSSaqib Khan         {
490c9bb6425SPatrick Williams             error("Failed to find the needed BMC images.");
49135e83f3eSSaqib Khan             return ItemUpdater::ActivationStatus::invalid;
49235e83f3eSSaqib Khan         }
4938e9ccfe7SBright Cheng     }
494b1cfdf99SMichael Tritz 
495b1cfdf99SMichael Tritz     return ItemUpdater::ActivationStatus::ready;
49635e83f3eSSaqib Khan }
49735e83f3eSSaqib Khan 
savePriority(const std::string & versionId,uint8_t value)498bbcb7be1SAdriana Kobylak void ItemUpdater::savePriority(const std::string& versionId, uint8_t value)
499bbcb7be1SAdriana Kobylak {
500780220f2SAdriana Kobylak     auto flashId = versions.find(versionId)->second->path();
501780220f2SAdriana Kobylak     storePriority(flashId, value);
50225773a7eSAdriana Kobylak     helper.setEntry(flashId, value);
503bbcb7be1SAdriana Kobylak }
504bbcb7be1SAdriana Kobylak 
freePriority(uint8_t value,const std::string & versionId)505b9da6634SSaqib Khan void ItemUpdater::freePriority(uint8_t value, const std::string& versionId)
5064c1aec09SSaqib Khan {
507b77551cdSAdriana Kobylak     std::map<std::string, uint8_t> priorityMap;
508b77551cdSAdriana Kobylak 
509b77551cdSAdriana Kobylak     // Insert the requested version and priority, it may not exist yet.
510b77551cdSAdriana Kobylak     priorityMap.insert(std::make_pair(versionId, value));
511b77551cdSAdriana Kobylak 
5124c1aec09SSaqib Khan     for (const auto& intf : activations)
5134c1aec09SSaqib Khan     {
5144c1aec09SSaqib Khan         if (intf.second->redundancyPriority)
5154c1aec09SSaqib Khan         {
516b77551cdSAdriana Kobylak             priorityMap.insert(std::make_pair(
5172285fe0fSAdriana Kobylak                 intf.first, intf.second->redundancyPriority.get()->priority()));
518b77551cdSAdriana Kobylak         }
519b77551cdSAdriana Kobylak     }
520b77551cdSAdriana Kobylak 
521b77551cdSAdriana Kobylak     // Lambda function to compare 2 priority values, use <= to allow duplicates
5222285fe0fSAdriana Kobylak     typedef std::function<bool(std::pair<std::string, uint8_t>,
5232285fe0fSAdriana Kobylak                                std::pair<std::string, uint8_t>)>
5242285fe0fSAdriana Kobylak         cmpPriority;
5252285fe0fSAdriana Kobylak     cmpPriority cmpPriorityFunc =
5262285fe0fSAdriana Kobylak         [](std::pair<std::string, uint8_t> priority1,
5272285fe0fSAdriana Kobylak            std::pair<std::string, uint8_t> priority2) {
528b77551cdSAdriana Kobylak         return priority1.second <= priority2.second;
529b77551cdSAdriana Kobylak     };
530b77551cdSAdriana Kobylak 
531b77551cdSAdriana Kobylak     // Sort versions by ascending priority
532b77551cdSAdriana Kobylak     std::set<std::pair<std::string, uint8_t>, cmpPriority> prioritySet(
533b77551cdSAdriana Kobylak         priorityMap.begin(), priorityMap.end(), cmpPriorityFunc);
534b77551cdSAdriana Kobylak 
535b77551cdSAdriana Kobylak     auto freePriorityValue = value;
536b77551cdSAdriana Kobylak     for (auto& element : prioritySet)
537b77551cdSAdriana Kobylak     {
538b77551cdSAdriana Kobylak         if (element.first == versionId)
539b77551cdSAdriana Kobylak         {
540b77551cdSAdriana Kobylak             continue;
541b77551cdSAdriana Kobylak         }
542b77551cdSAdriana Kobylak         if (element.second == freePriorityValue)
543b77551cdSAdriana Kobylak         {
544b77551cdSAdriana Kobylak             ++freePriorityValue;
545b77551cdSAdriana Kobylak             auto it = activations.find(element.first);
546b77551cdSAdriana Kobylak             it->second->redundancyPriority.get()->sdbusPriority(
547b77551cdSAdriana Kobylak                 freePriorityValue);
5484c1aec09SSaqib Khan         }
5494c1aec09SSaqib Khan     }
550b77551cdSAdriana Kobylak 
551b77551cdSAdriana Kobylak     auto lowestVersion = prioritySet.begin()->first;
552b77551cdSAdriana Kobylak     if (value == prioritySet.begin()->second)
553b77551cdSAdriana Kobylak     {
554b77551cdSAdriana Kobylak         lowestVersion = versionId;
5554c1aec09SSaqib Khan     }
556b77551cdSAdriana Kobylak     updateUbootEnvVars(lowestVersion);
5574c1aec09SSaqib Khan }
5584c1aec09SSaqib Khan 
reset()55937a59043SMichael Tritz void ItemUpdater::reset()
56037a59043SMichael Tritz {
56156aaf454SLei YU     helper.factoryReset();
56237a59043SMichael Tritz 
563c9bb6425SPatrick Williams     info("BMC factory reset will take effect upon reboot.");
56437a59043SMichael Tritz }
56537a59043SMichael Tritz 
removeReadOnlyPartition(std::string versionId)5663526ef73SLeonel Gonzalez void ItemUpdater::removeReadOnlyPartition(std::string versionId)
5673526ef73SLeonel Gonzalez {
56825773a7eSAdriana Kobylak     auto flashId = versions.find(versionId)->second->path();
56925773a7eSAdriana Kobylak     helper.removeVersion(flashId);
5703526ef73SLeonel Gonzalez }
5713526ef73SLeonel Gonzalez 
fieldModeEnabled(bool value)5720129d926SMichael Tritz bool ItemUpdater::fieldModeEnabled(bool value)
5730129d926SMichael Tritz {
5740129d926SMichael Tritz     // enabling field mode is intended to be one way: false -> true
5750129d926SMichael Tritz     if (value && !control::FieldMode::fieldModeEnabled())
5760129d926SMichael Tritz     {
5770129d926SMichael Tritz         control::FieldMode::fieldModeEnabled(value);
5780129d926SMichael Tritz 
57922848eceSAdriana Kobylak         auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
58022848eceSAdriana Kobylak                                           SYSTEMD_INTERFACE, "StartUnit");
58122848eceSAdriana Kobylak         method.append("obmc-flash-bmc-setenv@fieldmode\\x3dtrue.service",
58222848eceSAdriana Kobylak                       "replace");
58322848eceSAdriana Kobylak         bus.call_noreply(method);
58422848eceSAdriana Kobylak 
58522848eceSAdriana Kobylak         method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
58622848eceSAdriana Kobylak                                      SYSTEMD_INTERFACE, "StopUnit");
58722848eceSAdriana Kobylak         method.append("usr-local.mount", "replace");
58822848eceSAdriana Kobylak         bus.call_noreply(method);
58922848eceSAdriana Kobylak 
59022848eceSAdriana Kobylak         std::vector<std::string> usrLocal = {"usr-local.mount"};
59122848eceSAdriana Kobylak 
59222848eceSAdriana Kobylak         method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
59322848eceSAdriana Kobylak                                      SYSTEMD_INTERFACE, "MaskUnitFiles");
59422848eceSAdriana Kobylak         method.append(usrLocal, false, true);
59522848eceSAdriana Kobylak         bus.call_noreply(method);
5960129d926SMichael Tritz     }
597d5b8f75cSAdriana Kobylak     else if (!value && control::FieldMode::fieldModeEnabled())
598d5b8f75cSAdriana Kobylak     {
599ce82de51SAdriana Kobylak         elog<NotAllowed>(xyz::openbmc_project::common::NotAllowed::REASON(
600d5b8f75cSAdriana Kobylak             "FieldMode is not allowed to be cleared"));
601d5b8f75cSAdriana Kobylak     }
6020129d926SMichael Tritz 
6030129d926SMichael Tritz     return control::FieldMode::fieldModeEnabled();
6040129d926SMichael Tritz }
6050129d926SMichael Tritz 
restoreFieldModeStatus()6060129d926SMichael Tritz void ItemUpdater::restoreFieldModeStatus()
6070129d926SMichael Tritz {
608deb86b4aSIsaac Kurth     // The fieldmode u-boot environment variable may not exist since it is not
609deb86b4aSIsaac Kurth     // part of the default environment, run fw_printenv with 2>&1 to ignore the
610deb86b4aSIsaac Kurth     // error message in the journal "Error: "fieldmode" not defined"
611d5e8e73bSPatrick Williams     std::pair<int, std::string> ret = utils::execute("/sbin/fw_printenv", "-n",
612d5e8e73bSPatrick Williams                                                      "fieldmode", "2>&1");
6130129d926SMichael Tritz 
614deb86b4aSIsaac Kurth     if (ret.first != 0)
615deb86b4aSIsaac Kurth     {
616deb86b4aSIsaac Kurth         return;
617deb86b4aSIsaac Kurth     }
618deb86b4aSIsaac Kurth 
619deb86b4aSIsaac Kurth     // truncate any extra characters off the end to compare against a "true" str
620deb86b4aSIsaac Kurth     std::string result = ret.second.substr(0, 4);
621deb86b4aSIsaac Kurth     if (result == "true")
6220129d926SMichael Tritz     {
6230129d926SMichael Tritz         ItemUpdater::fieldModeEnabled(true);
6240129d926SMichael Tritz     }
6250129d926SMichael Tritz }
6260129d926SMichael Tritz 
setBMCInventoryPath()627b60add1eSGunnar Mills void ItemUpdater::setBMCInventoryPath()
628b60add1eSGunnar Mills {
629b60add1eSGunnar Mills     auto depth = 0;
6302285fe0fSAdriana Kobylak     auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
6312285fe0fSAdriana Kobylak                                           MAPPER_INTERFACE, "GetSubTreePaths");
632b60add1eSGunnar Mills 
6331254c628SAdriana Kobylak     mapperCall.append(INVENTORY_PATH);
634b60add1eSGunnar Mills     mapperCall.append(depth);
6351254c628SAdriana Kobylak     std::vector<std::string> filter = {BMC_INVENTORY_INTERFACE};
636b60add1eSGunnar Mills     mapperCall.append(filter);
637b60add1eSGunnar Mills 
63887c78173SEd Tanous     try
639b60add1eSGunnar Mills     {
64087c78173SEd Tanous         auto response = bus.call(mapperCall);
641b60add1eSGunnar Mills 
642b60add1eSGunnar Mills         using ObjectPaths = std::vector<std::string>;
643b60add1eSGunnar Mills         ObjectPaths result;
644b60add1eSGunnar Mills         response.read(result);
645b60add1eSGunnar Mills 
6461254c628SAdriana Kobylak         if (!result.empty())
647b60add1eSGunnar Mills         {
6481254c628SAdriana Kobylak             bmcInventoryPath = result.front();
649b60add1eSGunnar Mills         }
65087c78173SEd Tanous     }
651bf2bb2b1SPatrick Williams     catch (const sdbusplus::exception_t& e)
65287c78173SEd Tanous     {
653c9bb6425SPatrick Williams         error("Error in mapper GetSubTreePath: {ERROR}", "ERROR", e);
65487c78173SEd Tanous         return;
65587c78173SEd Tanous     }
656b60add1eSGunnar Mills 
657b60add1eSGunnar Mills     return;
658b60add1eSGunnar Mills }
659b60add1eSGunnar Mills 
createActiveAssociation(const std::string & path)660f10b2326SGunnar Mills void ItemUpdater::createActiveAssociation(const std::string& path)
661ded875dcSGunnar Mills {
6622285fe0fSAdriana Kobylak     assocs.emplace_back(
6632285fe0fSAdriana Kobylak         std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path));
664ded875dcSGunnar Mills     associations(assocs);
665ded875dcSGunnar Mills }
666ded875dcSGunnar Mills 
createFunctionalAssociation(const std::string & path)66788e8a325SGunnar Mills void ItemUpdater::createFunctionalAssociation(const std::string& path)
66888e8a325SGunnar Mills {
66988e8a325SGunnar Mills     assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION,
6702285fe0fSAdriana Kobylak                                         FUNCTIONAL_REV_ASSOCIATION, path));
67188e8a325SGunnar Mills     associations(assocs);
67288e8a325SGunnar Mills }
67388e8a325SGunnar Mills 
createUpdateableAssociation(const std::string & path)674bbebec79SAppaRao Puli void ItemUpdater::createUpdateableAssociation(const std::string& path)
675bbebec79SAppaRao Puli {
676bbebec79SAppaRao Puli     assocs.emplace_back(std::make_tuple(UPDATEABLE_FWD_ASSOCIATION,
677bbebec79SAppaRao Puli                                         UPDATEABLE_REV_ASSOCIATION, path));
678bbebec79SAppaRao Puli     associations(assocs);
679bbebec79SAppaRao Puli }
680bbebec79SAppaRao Puli 
removeAssociations(const std::string & path)681991af7ecSAdriana Kobylak void ItemUpdater::removeAssociations(const std::string& path)
682ded875dcSGunnar Mills {
683ded875dcSGunnar Mills     for (auto iter = assocs.begin(); iter != assocs.end();)
684ded875dcSGunnar Mills     {
685991af7ecSAdriana Kobylak         if ((std::get<2>(*iter)).compare(path) == 0)
686ded875dcSGunnar Mills         {
687ded875dcSGunnar Mills             iter = assocs.erase(iter);
688ded875dcSGunnar Mills             associations(assocs);
689ded875dcSGunnar Mills         }
690ded875dcSGunnar Mills         else
691ded875dcSGunnar Mills         {
692ded875dcSGunnar Mills             ++iter;
693ded875dcSGunnar Mills         }
694ded875dcSGunnar Mills     }
695ded875dcSGunnar Mills }
696ded875dcSGunnar Mills 
isLowestPriority(uint8_t value)697b9da6634SSaqib Khan bool ItemUpdater::isLowestPriority(uint8_t value)
698b9da6634SSaqib Khan {
699b9da6634SSaqib Khan     for (const auto& intf : activations)
700b9da6634SSaqib Khan     {
701b9da6634SSaqib Khan         if (intf.second->redundancyPriority)
702b9da6634SSaqib Khan         {
703b9da6634SSaqib Khan             if (intf.second->redundancyPriority.get()->priority() < value)
704b9da6634SSaqib Khan             {
705b9da6634SSaqib Khan                 return false;
706b9da6634SSaqib Khan             }
707b9da6634SSaqib Khan         }
708b9da6634SSaqib Khan     }
709b9da6634SSaqib Khan     return true;
710b9da6634SSaqib Khan }
711b9da6634SSaqib Khan 
updateUbootEnvVars(const std::string & versionId)712b77551cdSAdriana Kobylak void ItemUpdater::updateUbootEnvVars(const std::string& versionId)
713b77551cdSAdriana Kobylak {
7149c76a0acSLei YU     auto it = versions.find(versionId);
7159c76a0acSLei YU     if (it == versions.end())
7169c76a0acSLei YU     {
7179c76a0acSLei YU         return;
7189c76a0acSLei YU     }
7199c76a0acSLei YU     auto flashId = it->second->path();
72025773a7eSAdriana Kobylak     helper.updateUbootVersionId(flashId);
721b77551cdSAdriana Kobylak }
722b77551cdSAdriana Kobylak 
resetUbootEnvVars()72349446ae9SSaqib Khan void ItemUpdater::resetUbootEnvVars()
72449446ae9SSaqib Khan {
72549446ae9SSaqib Khan     decltype(activations.begin()->second->redundancyPriority.get()->priority())
72649446ae9SSaqib Khan         lowestPriority = std::numeric_limits<uint8_t>::max();
72749446ae9SSaqib Khan     decltype(activations.begin()->second->versionId) lowestPriorityVersion;
72849446ae9SSaqib Khan     for (const auto& intf : activations)
72949446ae9SSaqib Khan     {
73049446ae9SSaqib Khan         if (!intf.second->redundancyPriority.get())
73149446ae9SSaqib Khan         {
73249446ae9SSaqib Khan             // Skip this version if the redundancyPriority is not initialized.
73349446ae9SSaqib Khan             continue;
73449446ae9SSaqib Khan         }
73549446ae9SSaqib Khan 
7362285fe0fSAdriana Kobylak         if (intf.second->redundancyPriority.get()->priority() <= lowestPriority)
73749446ae9SSaqib Khan         {
73849446ae9SSaqib Khan             lowestPriority = intf.second->redundancyPriority.get()->priority();
73949446ae9SSaqib Khan             lowestPriorityVersion = intf.second->versionId;
74049446ae9SSaqib Khan         }
74149446ae9SSaqib Khan     }
74249446ae9SSaqib Khan 
743f0382c35SSaqib Khan     // Update the U-boot environment variable to point to the lowest priority
744b77551cdSAdriana Kobylak     updateUbootEnvVars(lowestPriorityVersion);
74549446ae9SSaqib Khan }
74649446ae9SSaqib Khan 
freeSpace(const Activation & caller)747d8c9eea3SLei YU void ItemUpdater::freeSpace([[maybe_unused]] const Activation& caller)
748204e1e74SAdriana Kobylak {
749d8c9eea3SLei YU #ifdef BMC_STATIC_DUAL_IMAGE
750d8c9eea3SLei YU     // For the golden image case, always remove the version on the primary side
751d8c9eea3SLei YU     std::string versionIDtoErase;
752d8c9eea3SLei YU     for (const auto& iter : activations)
753d8c9eea3SLei YU     {
754d8c9eea3SLei YU         if (iter.second->redundancyPriority &&
755d8c9eea3SLei YU             iter.second->redundancyPriority.get()->priority() == 0)
756d8c9eea3SLei YU         {
757d8c9eea3SLei YU             versionIDtoErase = iter.second->versionId;
758d8c9eea3SLei YU             break;
759d8c9eea3SLei YU         }
760d8c9eea3SLei YU     }
761d8c9eea3SLei YU     if (!versionIDtoErase.empty())
762d8c9eea3SLei YU     {
763d8c9eea3SLei YU         erase(versionIDtoErase);
764d8c9eea3SLei YU     }
765d8c9eea3SLei YU     else
766d8c9eea3SLei YU     {
767d8c9eea3SLei YU         warning("Failed to find version to erase");
768d8c9eea3SLei YU     }
769d8c9eea3SLei YU #else
770204e1e74SAdriana Kobylak     //  Versions with the highest priority in front
771204e1e74SAdriana Kobylak     std::priority_queue<std::pair<int, std::string>,
772204e1e74SAdriana Kobylak                         std::vector<std::pair<int, std::string>>,
7732285fe0fSAdriana Kobylak                         std::less<std::pair<int, std::string>>>
7742285fe0fSAdriana Kobylak         versionsPQ;
775204e1e74SAdriana Kobylak 
776204e1e74SAdriana Kobylak     std::size_t count = 0;
777204e1e74SAdriana Kobylak     for (const auto& iter : activations)
778204e1e74SAdriana Kobylak     {
779204e1e74SAdriana Kobylak         if ((iter.second.get()->activation() ==
780204e1e74SAdriana Kobylak              server::Activation::Activations::Active) ||
781204e1e74SAdriana Kobylak             (iter.second.get()->activation() ==
782204e1e74SAdriana Kobylak              server::Activation::Activations::Failed))
783204e1e74SAdriana Kobylak         {
784204e1e74SAdriana Kobylak             count++;
785204e1e74SAdriana Kobylak             // Don't put the functional version on the queue since we can't
786204e1e74SAdriana Kobylak             // remove the "running" BMC version.
7870f88b5afSLei YU             // If ACTIVE_BMC_MAX_ALLOWED <= 1, there is only one active BMC,
7880f88b5afSLei YU             // so remove functional version as well.
789a6963590SAdriana Kobylak             // Don't delete the the Activation object that called this function.
790a6963590SAdriana Kobylak             if ((versions.find(iter.second->versionId)
791a6963590SAdriana Kobylak                      ->second->isFunctional() &&
792a6963590SAdriana Kobylak                  ACTIVE_BMC_MAX_ALLOWED > 1) ||
793a6963590SAdriana Kobylak                 (iter.second->versionId == caller.versionId))
794204e1e74SAdriana Kobylak             {
795204e1e74SAdriana Kobylak                 continue;
796204e1e74SAdriana Kobylak             }
797a6963590SAdriana Kobylak 
798a6963590SAdriana Kobylak             // Failed activations don't have priority, assign them a large value
799a6963590SAdriana Kobylak             // for sorting purposes.
800a6963590SAdriana Kobylak             auto priority = 999;
801a6963590SAdriana Kobylak             if (iter.second.get()->activation() ==
802cfb4b209SLei YU                     server::Activation::Activations::Active &&
803cfb4b209SLei YU                 iter.second->redundancyPriority)
804a6963590SAdriana Kobylak             {
805a6963590SAdriana Kobylak                 priority = iter.second->redundancyPriority.get()->priority();
806a6963590SAdriana Kobylak             }
807a6963590SAdriana Kobylak 
808a6963590SAdriana Kobylak             versionsPQ.push(std::make_pair(priority, iter.second->versionId));
809204e1e74SAdriana Kobylak         }
810204e1e74SAdriana Kobylak     }
811204e1e74SAdriana Kobylak 
812204e1e74SAdriana Kobylak     // If the number of BMC versions is over ACTIVE_BMC_MAX_ALLOWED -1,
813204e1e74SAdriana Kobylak     // remove the highest priority one(s).
814204e1e74SAdriana Kobylak     while ((count >= ACTIVE_BMC_MAX_ALLOWED) && (!versionsPQ.empty()))
815204e1e74SAdriana Kobylak     {
816204e1e74SAdriana Kobylak         erase(versionsPQ.top().second);
817204e1e74SAdriana Kobylak         versionsPQ.pop();
818204e1e74SAdriana Kobylak         count--;
819204e1e74SAdriana Kobylak     }
820d8c9eea3SLei YU #endif
821204e1e74SAdriana Kobylak }
822204e1e74SAdriana Kobylak 
mirrorUbootToAlt()823eaa1ee05SEddie James void ItemUpdater::mirrorUbootToAlt()
824eaa1ee05SEddie James {
82556aaf454SLei YU     helper.mirrorAlt();
826eaa1ee05SEddie James }
827eaa1ee05SEddie James 
checkImage(const std::string & filePath,const std::vector<std::string> & imageList)8288e9ccfe7SBright Cheng bool ItemUpdater::checkImage(const std::string& filePath,
8298e9ccfe7SBright Cheng                              const std::vector<std::string>& imageList)
8308e9ccfe7SBright Cheng {
8318e9ccfe7SBright Cheng     bool valid = true;
8328e9ccfe7SBright Cheng 
8338e9ccfe7SBright Cheng     for (auto& bmcImage : imageList)
8348e9ccfe7SBright Cheng     {
8358e9ccfe7SBright Cheng         fs::path file(filePath);
8368e9ccfe7SBright Cheng         file /= bmcImage;
8378e9ccfe7SBright Cheng         std::ifstream efile(file.c_str());
8388e9ccfe7SBright Cheng         if (efile.good() != 1)
8398e9ccfe7SBright Cheng         {
8408e9ccfe7SBright Cheng             valid = false;
8418e9ccfe7SBright Cheng             break;
8428e9ccfe7SBright Cheng         }
8438e9ccfe7SBright Cheng     }
8448e9ccfe7SBright Cheng 
8458e9ccfe7SBright Cheng     return valid;
8468e9ccfe7SBright Cheng }
8478e9ccfe7SBright Cheng 
8486e9fb1d6SLei YU #ifdef HOST_BIOS_UPGRADE
createBIOSObject()8496e9fb1d6SLei YU void ItemUpdater::createBIOSObject()
8506e9fb1d6SLei YU {
8516e9fb1d6SLei YU     std::string path = BIOS_OBJPATH;
8526e9fb1d6SLei YU     // Get version id from last item in the path
8536e9fb1d6SLei YU     auto pos = path.rfind("/");
8546e9fb1d6SLei YU     if (pos == std::string::npos)
8556e9fb1d6SLei YU     {
856c9bb6425SPatrick Williams         error("No version id found in object path {PATH}", "PATH", path);
8576e9fb1d6SLei YU         return;
8586e9fb1d6SLei YU     }
8596e9fb1d6SLei YU 
8606e9fb1d6SLei YU     createActiveAssociation(path);
8616e9fb1d6SLei YU     createFunctionalAssociation(path);
862*27d734f0SDaniel Hsu     createUpdateableAssociation(path);
8636e9fb1d6SLei YU 
8646e9fb1d6SLei YU     auto versionId = path.substr(pos + 1);
8656e9fb1d6SLei YU     auto version = "null";
8666e9fb1d6SLei YU     AssociationList assocs = {};
8676e9fb1d6SLei YU     biosActivation = std::make_unique<Activation>(
8686e9fb1d6SLei YU         bus, path, *this, versionId, server::Activation::Activations::Active,
8696e9fb1d6SLei YU         assocs);
8706e9fb1d6SLei YU     auto dummyErase = [](std::string /*entryId*/) {
8716e9fb1d6SLei YU         // Do nothing;
8726e9fb1d6SLei YU     };
8736e9fb1d6SLei YU     biosVersion = std::make_unique<VersionClass>(
8746e9fb1d6SLei YU         bus, path, version, VersionPurpose::Host, "", "",
875054bb0b8SJustin Ledford         std::vector<std::string>(),
87659b640b0SAdriana Kobylak         std::bind(dummyErase, std::placeholders::_1), "");
8776e9fb1d6SLei YU     biosVersion->deleteObject =
8786e9fb1d6SLei YU         std::make_unique<phosphor::software::manager::Delete>(bus, path,
8796e9fb1d6SLei YU                                                               *biosVersion);
8806e9fb1d6SLei YU }
8816e9fb1d6SLei YU #endif
8826e9fb1d6SLei YU 
getRunningSlot()883531fbc25SLei YU void ItemUpdater::getRunningSlot()
884531fbc25SLei YU {
885531fbc25SLei YU     // Check /run/media/slot to get the slot number
886531fbc25SLei YU     constexpr auto slotFile = "/run/media/slot";
887531fbc25SLei YU     std::fstream f(slotFile, std::ios_base::in);
888531fbc25SLei YU     f >> runningImageSlot;
889531fbc25SLei YU }
890531fbc25SLei YU 
891ec1b41c4SGunnar Mills } // namespace updater
892ec1b41c4SGunnar Mills } // namespace software
893ec1b41c4SGunnar Mills } // namespace phosphor
894