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