xref: /openbmc/phosphor-bmc-code-mgmt/bmc/item_updater.cpp (revision eae5ec9e28d8e0586eae116802e1f0c173040df7)
1cab87e9cSJagpal Singh Gill #include "config.h"
2cab87e9cSJagpal Singh Gill 
3cab87e9cSJagpal Singh Gill #include "item_updater.hpp"
4cab87e9cSJagpal Singh Gill 
5cab87e9cSJagpal Singh Gill #include "images.hpp"
6cab87e9cSJagpal Singh Gill #include "serialize.hpp"
7cab87e9cSJagpal Singh Gill #include "version.hpp"
8cab87e9cSJagpal Singh Gill #include "xyz/openbmc_project/Software/ExtendedVersion/server.hpp"
9cab87e9cSJagpal Singh Gill #include "xyz/openbmc_project/Software/Version/server.hpp"
10cab87e9cSJagpal Singh Gill 
11cab87e9cSJagpal Singh Gill #include <phosphor-logging/elog-errors.hpp>
12cab87e9cSJagpal Singh Gill #include <phosphor-logging/elog.hpp>
13cab87e9cSJagpal Singh Gill #include <phosphor-logging/lg2.hpp>
14cab87e9cSJagpal Singh Gill #include <xyz/openbmc_project/Common/error.hpp>
15cab87e9cSJagpal Singh Gill #include <xyz/openbmc_project/Software/Image/error.hpp>
16cab87e9cSJagpal Singh Gill 
17cab87e9cSJagpal Singh Gill #include <filesystem>
18cab87e9cSJagpal Singh Gill #include <fstream>
19cab87e9cSJagpal Singh Gill #include <queue>
20cab87e9cSJagpal Singh Gill #include <set>
21cab87e9cSJagpal Singh Gill #include <string>
22cab87e9cSJagpal Singh Gill #include <system_error>
23cab87e9cSJagpal Singh Gill 
24cab87e9cSJagpal Singh Gill namespace phosphor
25cab87e9cSJagpal Singh Gill {
26cab87e9cSJagpal Singh Gill namespace software
27cab87e9cSJagpal Singh Gill {
28cab87e9cSJagpal Singh Gill namespace updater
29cab87e9cSJagpal Singh Gill {
30cab87e9cSJagpal Singh Gill 
31cab87e9cSJagpal Singh Gill // When you see server:: you know we're referencing our base class
32cab87e9cSJagpal Singh Gill namespace server = sdbusplus::server::xyz::openbmc_project::software;
33cab87e9cSJagpal Singh Gill namespace control = sdbusplus::server::xyz::openbmc_project::control;
34cab87e9cSJagpal Singh Gill 
35cab87e9cSJagpal Singh Gill PHOSPHOR_LOG2_USING;
36cab87e9cSJagpal Singh Gill using namespace phosphor::logging;
37cab87e9cSJagpal Singh Gill using namespace sdbusplus::error::xyz::openbmc_project::software::image;
38cab87e9cSJagpal Singh Gill using namespace phosphor::software::image;
39cab87e9cSJagpal Singh Gill namespace fs = std::filesystem;
40cab87e9cSJagpal Singh Gill using NotAllowed = sdbusplus::error::xyz::openbmc_project::common::NotAllowed;
41cab87e9cSJagpal Singh Gill 
createActivation(sdbusplus::message_t & msg)42cab87e9cSJagpal Singh Gill void ItemUpdater::createActivation(sdbusplus::message_t& msg)
43cab87e9cSJagpal Singh Gill {
44cab87e9cSJagpal Singh Gill     using SVersion = server::Version;
45cab87e9cSJagpal Singh Gill     using VersionPurpose = SVersion::VersionPurpose;
46cab87e9cSJagpal Singh Gill 
47cab87e9cSJagpal Singh Gill     sdbusplus::message::object_path objPath;
48cab87e9cSJagpal Singh Gill     auto purpose = VersionPurpose::Unknown;
49cab87e9cSJagpal Singh Gill     std::string extendedVersion;
50cab87e9cSJagpal Singh Gill     std::string version;
51cab87e9cSJagpal Singh Gill     std::map<std::string,
52cab87e9cSJagpal Singh Gill              std::map<std::string,
53cab87e9cSJagpal Singh Gill                       std::variant<std::string, std::vector<std::string>>>>
54cab87e9cSJagpal Singh Gill         interfaces;
55cab87e9cSJagpal Singh Gill     msg.read(objPath, interfaces);
56cab87e9cSJagpal Singh Gill     std::string path(std::move(objPath));
57cab87e9cSJagpal Singh Gill     std::string filePath;
58cab87e9cSJagpal Singh Gill     std::vector<std::string> compatibleNames;
59cab87e9cSJagpal Singh Gill 
60cab87e9cSJagpal Singh Gill     for (const auto& intf : interfaces)
61cab87e9cSJagpal Singh Gill     {
62cab87e9cSJagpal Singh Gill         if (intf.first == VERSION_IFACE)
63cab87e9cSJagpal Singh Gill         {
64cab87e9cSJagpal Singh Gill             for (const auto& property : intf.second)
65cab87e9cSJagpal Singh Gill             {
66cab87e9cSJagpal Singh Gill                 if (property.first == "Purpose")
67cab87e9cSJagpal Singh Gill                 {
68cab87e9cSJagpal Singh Gill                     auto value = SVersion::convertVersionPurposeFromString(
69cab87e9cSJagpal Singh Gill                         std::get<std::string>(property.second));
70cab87e9cSJagpal Singh Gill                     if (value == VersionPurpose::BMC ||
71cab87e9cSJagpal Singh Gill #ifdef HOST_BIOS_UPGRADE
72cab87e9cSJagpal Singh Gill                         value == VersionPurpose::Host ||
73cab87e9cSJagpal Singh Gill #endif
74cab87e9cSJagpal Singh Gill                         value == VersionPurpose::System)
75cab87e9cSJagpal Singh Gill                     {
76cab87e9cSJagpal Singh Gill                         purpose = value;
77cab87e9cSJagpal Singh Gill                     }
78cab87e9cSJagpal Singh Gill                 }
79cab87e9cSJagpal Singh Gill                 else if (property.first == "Version")
80cab87e9cSJagpal Singh Gill                 {
81cab87e9cSJagpal Singh Gill                     version = std::get<std::string>(property.second);
82cab87e9cSJagpal Singh Gill                 }
83cab87e9cSJagpal Singh Gill             }
84cab87e9cSJagpal Singh Gill         }
85cab87e9cSJagpal Singh Gill         else if (intf.first == FILEPATH_IFACE)
86cab87e9cSJagpal Singh Gill         {
87cab87e9cSJagpal Singh Gill             for (const auto& property : intf.second)
88cab87e9cSJagpal Singh Gill             {
89cab87e9cSJagpal Singh Gill                 if (property.first == "Path")
90cab87e9cSJagpal Singh Gill                 {
91cab87e9cSJagpal Singh Gill                     filePath = std::get<std::string>(property.second);
92cab87e9cSJagpal Singh Gill                 }
93cab87e9cSJagpal Singh Gill             }
94cab87e9cSJagpal Singh Gill         }
95cab87e9cSJagpal Singh Gill         else if (intf.first == EXTENDED_VERSION_IFACE)
96cab87e9cSJagpal Singh Gill         {
97cab87e9cSJagpal Singh Gill             for (const auto& property : intf.second)
98cab87e9cSJagpal Singh Gill             {
99cab87e9cSJagpal Singh Gill                 if (property.first == "ExtendedVersion")
100cab87e9cSJagpal Singh Gill                 {
101cab87e9cSJagpal Singh Gill                     extendedVersion = std::get<std::string>(property.second);
102cab87e9cSJagpal Singh Gill                 }
103cab87e9cSJagpal Singh Gill             }
104cab87e9cSJagpal Singh Gill         }
105cab87e9cSJagpal Singh Gill         else if (intf.first == COMPATIBLE_IFACE)
106cab87e9cSJagpal Singh Gill         {
107cab87e9cSJagpal Singh Gill             for (const auto& property : intf.second)
108cab87e9cSJagpal Singh Gill             {
109cab87e9cSJagpal Singh Gill                 if (property.first == "Names")
110cab87e9cSJagpal Singh Gill                 {
111cab87e9cSJagpal Singh Gill                     compatibleNames =
112cab87e9cSJagpal Singh Gill                         std::get<std::vector<std::string>>(property.second);
113cab87e9cSJagpal Singh Gill                 }
114cab87e9cSJagpal Singh Gill             }
115cab87e9cSJagpal Singh Gill         }
116cab87e9cSJagpal Singh Gill     }
117cab87e9cSJagpal Singh Gill     if (version.empty() || filePath.empty() ||
118cab87e9cSJagpal Singh Gill         purpose == VersionPurpose::Unknown)
119cab87e9cSJagpal Singh Gill     {
120cab87e9cSJagpal Singh Gill         return;
121cab87e9cSJagpal Singh Gill     }
122cab87e9cSJagpal Singh Gill 
123cab87e9cSJagpal Singh Gill     // Version id is the last item in the path
124cab87e9cSJagpal Singh Gill     auto pos = path.rfind('/');
125cab87e9cSJagpal Singh Gill     if (pos == std::string::npos)
126cab87e9cSJagpal Singh Gill     {
127cab87e9cSJagpal Singh Gill         error("No version id found in object path: {PATH}", "PATH", path);
128cab87e9cSJagpal Singh Gill         return;
129cab87e9cSJagpal Singh Gill     }
130cab87e9cSJagpal Singh Gill 
131cab87e9cSJagpal Singh Gill     auto versionId = path.substr(pos + 1);
132cab87e9cSJagpal Singh Gill 
133cab87e9cSJagpal Singh Gill     if (activations.find(versionId) == activations.end())
134cab87e9cSJagpal Singh Gill     {
135cab87e9cSJagpal Singh Gill         verifyAndCreateObjects(versionId, path, version, purpose,
136cab87e9cSJagpal Singh Gill                                extendedVersion, filePath, compatibleNames);
137cab87e9cSJagpal Singh Gill     }
138cab87e9cSJagpal Singh Gill     return;
139cab87e9cSJagpal Singh Gill }
140cab87e9cSJagpal Singh Gill 
createActivationWithApplyTime(std::string & id,std::string & path,ApplyTimeIntf::RequestedApplyTimes applyTime)141cab87e9cSJagpal Singh Gill void ItemUpdater::createActivationWithApplyTime(
142cab87e9cSJagpal Singh Gill     std::string& id, std::string& path,
143cab87e9cSJagpal Singh Gill     ApplyTimeIntf::RequestedApplyTimes applyTime)
144cab87e9cSJagpal Singh Gill {
145cab87e9cSJagpal Singh Gill     info("Creating Activation object for id: {ID}", "ID", id);
146cab87e9cSJagpal Singh Gill     AssociationList associations = {};
147cab87e9cSJagpal Singh Gill     // Create an association to the BMC inventory item
148cab87e9cSJagpal Singh Gill     associations.emplace_back(
149cab87e9cSJagpal Singh Gill         std::make_tuple(ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
150cab87e9cSJagpal Singh Gill                         bmcInventoryPath));
151cab87e9cSJagpal Singh Gill     activations.insert(std::make_pair(
152cab87e9cSJagpal Singh Gill         id, std::make_unique<Activation>(
153cab87e9cSJagpal Singh Gill                 bus, path, *this, id, server::Activation::Activations::NotReady,
154cab87e9cSJagpal Singh Gill                 associations)));
155cab87e9cSJagpal Singh Gill     activations[id]->applyTime = applyTime;
156cab87e9cSJagpal Singh Gill }
157cab87e9cSJagpal Singh Gill 
verifyAndCreateObjects(std::string & id,std::string & path,std::string & version,VersionClass::VersionPurpose purpose,std::string & extendedVersion,std::string & filePath,std::vector<std::string> & compatibleNames)158cab87e9cSJagpal Singh Gill ActivationIntf::Activations ItemUpdater::verifyAndCreateObjects(
159cab87e9cSJagpal Singh Gill     std::string& id, std::string& path, std::string& version,
160cab87e9cSJagpal Singh Gill     VersionClass::VersionPurpose purpose, std::string& extendedVersion,
161cab87e9cSJagpal Singh Gill     std ::string& filePath, std::vector<std::string>& compatibleNames)
162cab87e9cSJagpal Singh Gill {
163cab87e9cSJagpal Singh Gill     // Determine the Activation state by processing the given image dir.
164cab87e9cSJagpal Singh Gill     auto activationState = server::Activation::Activations::Invalid;
165cab87e9cSJagpal Singh Gill     ItemUpdater::ActivationStatus result;
166cab87e9cSJagpal Singh Gill     if (purpose == VersionPurpose::BMC || purpose == VersionPurpose::System)
167cab87e9cSJagpal Singh Gill     {
168cab87e9cSJagpal Singh Gill         result = ItemUpdater::validateSquashFSImage(filePath);
169cab87e9cSJagpal Singh Gill     }
170cab87e9cSJagpal Singh Gill     else
171cab87e9cSJagpal Singh Gill     {
172cab87e9cSJagpal Singh Gill         result = ItemUpdater::ActivationStatus::ready;
173cab87e9cSJagpal Singh Gill     }
174cab87e9cSJagpal Singh Gill 
175cab87e9cSJagpal Singh Gill     AssociationList associations = {};
176cab87e9cSJagpal Singh Gill 
177cab87e9cSJagpal Singh Gill     if (result == ItemUpdater::ActivationStatus::ready)
178cab87e9cSJagpal Singh Gill     {
179cab87e9cSJagpal Singh Gill         activationState = server::Activation::Activations::Ready;
180cab87e9cSJagpal Singh Gill         // Create an association to the BMC inventory item
181cab87e9cSJagpal Singh Gill         associations.emplace_back(
182cab87e9cSJagpal Singh Gill             std::make_tuple(ACTIVATION_FWD_ASSOCIATION,
183cab87e9cSJagpal Singh Gill                             ACTIVATION_REV_ASSOCIATION, bmcInventoryPath));
184cab87e9cSJagpal Singh Gill     }
185cab87e9cSJagpal Singh Gill 
186cab87e9cSJagpal Singh Gill     auto versionPtr = std::make_unique<VersionClass>(
187cab87e9cSJagpal Singh Gill         bus, path, version, purpose, extendedVersion, filePath, compatibleNames,
188cab87e9cSJagpal Singh Gill         std::bind(&ItemUpdater::erase, this, std::placeholders::_1), id);
189cab87e9cSJagpal Singh Gill     versionPtr->deleteObject =
190cab87e9cSJagpal Singh Gill         std::make_unique<phosphor::software::manager::Delete>(
191cab87e9cSJagpal Singh Gill             bus, path, *versionPtr);
192cab87e9cSJagpal Singh Gill     versions.insert(std::make_pair(id, std::move(versionPtr)));
193cab87e9cSJagpal Singh Gill 
194cab87e9cSJagpal Singh Gill     auto activation = activations.find(id);
195cab87e9cSJagpal Singh Gill     if (activation == activations.end())
196cab87e9cSJagpal Singh Gill     {
197cab87e9cSJagpal Singh Gill         activations.insert(std::make_pair(
198cab87e9cSJagpal Singh Gill             id, std::make_unique<Activation>(bus, path, *this, id,
199cab87e9cSJagpal Singh Gill                                              activationState, associations)));
200cab87e9cSJagpal Singh Gill     }
201cab87e9cSJagpal Singh Gill     else
202cab87e9cSJagpal Singh Gill     {
203cab87e9cSJagpal Singh Gill         activation->second->activation(activationState);
204cab87e9cSJagpal Singh Gill     }
205cab87e9cSJagpal Singh Gill     return activationState;
206cab87e9cSJagpal Singh Gill }
207cab87e9cSJagpal Singh Gill 
requestActivation(std::string & id)208cab87e9cSJagpal Singh Gill bool ItemUpdater::requestActivation(std::string& id)
209cab87e9cSJagpal Singh Gill {
210cab87e9cSJagpal Singh Gill     auto activation = activations.find(id);
211cab87e9cSJagpal Singh Gill     if (activation == activations.end())
212cab87e9cSJagpal Singh Gill     {
213cab87e9cSJagpal Singh Gill         error("Activation object not found for id: {ID}", "ID", id);
214cab87e9cSJagpal Singh Gill         return false;
215cab87e9cSJagpal Singh Gill     }
216cab87e9cSJagpal Singh Gill     activation->second->requestedActivation(
217cab87e9cSJagpal Singh Gill         server::Activation::RequestedActivations::Active);
218cab87e9cSJagpal Singh Gill     return true;
219cab87e9cSJagpal Singh Gill }
220cab87e9cSJagpal Singh Gill 
updateActivationStatus(std::string & id,ActivationIntf::Activations status)221cab87e9cSJagpal Singh Gill bool ItemUpdater::updateActivationStatus(std::string& id,
222cab87e9cSJagpal Singh Gill                                          ActivationIntf::Activations status)
223cab87e9cSJagpal Singh Gill {
224cab87e9cSJagpal Singh Gill     auto activation = activations.find(id);
225cab87e9cSJagpal Singh Gill     if (activation == activations.end())
226cab87e9cSJagpal Singh Gill     {
227cab87e9cSJagpal Singh Gill         error("Activation object not found for id: {ID}", "ID", id);
228cab87e9cSJagpal Singh Gill         return false;
229cab87e9cSJagpal Singh Gill     }
230cab87e9cSJagpal Singh Gill     activation->second->activation(status);
231cab87e9cSJagpal Singh Gill     return true;
232cab87e9cSJagpal Singh Gill }
233cab87e9cSJagpal Singh Gill 
createUpdateObject(const std::string & id,const std::string & path)234cab87e9cSJagpal Singh Gill void ItemUpdater::createUpdateObject(const std::string& id,
235cab87e9cSJagpal Singh Gill                                      const std::string& path)
236cab87e9cSJagpal Singh Gill {
237cab87e9cSJagpal Singh Gill     if (updateManagers.find(id) != updateManagers.end())
238cab87e9cSJagpal Singh Gill     {
239cab87e9cSJagpal Singh Gill         error("UpdateManager object already exists for id: {ID}", "ID", id);
240cab87e9cSJagpal Singh Gill         return;
241cab87e9cSJagpal Singh Gill     }
242cab87e9cSJagpal Singh Gill     updateManagers.insert(
243cab87e9cSJagpal Singh Gill         std::make_pair(id, std::make_unique<UpdateManager>(ctx, path, *this)));
244cab87e9cSJagpal Singh Gill }
245cab87e9cSJagpal Singh Gill 
processBMCImage()246cab87e9cSJagpal Singh Gill void ItemUpdater::processBMCImage()
247cab87e9cSJagpal Singh Gill {
248cab87e9cSJagpal Singh Gill     using VersionClass = phosphor::software::manager::Version;
249cab87e9cSJagpal Singh Gill 
250cab87e9cSJagpal Singh Gill     // Check MEDIA_DIR and create if it does not exist
251cab87e9cSJagpal Singh Gill     try
252cab87e9cSJagpal Singh Gill     {
253cab87e9cSJagpal Singh Gill         if (!fs::is_directory(MEDIA_DIR))
254cab87e9cSJagpal Singh Gill         {
255cab87e9cSJagpal Singh Gill             fs::create_directory(MEDIA_DIR);
256cab87e9cSJagpal Singh Gill         }
257cab87e9cSJagpal Singh Gill     }
258cab87e9cSJagpal Singh Gill     catch (const fs::filesystem_error& e)
259cab87e9cSJagpal Singh Gill     {
260cab87e9cSJagpal Singh Gill         error("Failed to prepare dir: {ERROR}", "ERROR", e);
261cab87e9cSJagpal Singh Gill         return;
262cab87e9cSJagpal Singh Gill     }
263cab87e9cSJagpal Singh Gill 
264cab87e9cSJagpal Singh Gill     // Functional images are mounted as rofs-<location>-functional
265cab87e9cSJagpal Singh Gill     constexpr auto functionalSuffix = "-functional";
266cab87e9cSJagpal Singh Gill     bool functionalFound = false;
267cab87e9cSJagpal Singh Gill 
268cab87e9cSJagpal Singh Gill     // Read os-release from folders under /media/ to get
269cab87e9cSJagpal Singh Gill     // BMC Software Versions.
270cab87e9cSJagpal Singh Gill     std::error_code ec;
271cab87e9cSJagpal Singh Gill     for (const auto& iter : fs::directory_iterator(MEDIA_DIR, ec))
272cab87e9cSJagpal Singh Gill     {
273cab87e9cSJagpal Singh Gill         auto activationState = server::Activation::Activations::Active;
274cab87e9cSJagpal Singh Gill         static const auto BMC_RO_PREFIX_LEN = strlen(BMC_ROFS_PREFIX);
275cab87e9cSJagpal Singh Gill 
276cab87e9cSJagpal Singh Gill         // Check if the BMC_RO_PREFIXis the prefix of the iter.path
277cab87e9cSJagpal Singh Gill         if (0 ==
278cab87e9cSJagpal Singh Gill             iter.path().native().compare(0, BMC_RO_PREFIX_LEN, BMC_ROFS_PREFIX))
279cab87e9cSJagpal Singh Gill         {
280cab87e9cSJagpal Singh Gill             // Get the version to calculate the id
281cab87e9cSJagpal Singh Gill             fs::path releaseFile(OS_RELEASE_FILE);
282cab87e9cSJagpal Singh Gill             auto osRelease = iter.path() / releaseFile.relative_path();
283cab87e9cSJagpal Singh Gill             if (!fs::is_regular_file(osRelease, ec))
284cab87e9cSJagpal Singh Gill             {
285cab87e9cSJagpal Singh Gill #ifdef BMC_STATIC_DUAL_IMAGE
286cab87e9cSJagpal Singh Gill                 // For dual image, it is possible that the secondary image is
287cab87e9cSJagpal Singh Gill                 // empty or contains invalid data, ignore such case.
288cab87e9cSJagpal Singh Gill                 info("Unable to find osRelease: {PATH}: {ERROR_MSG}", "PATH",
289cab87e9cSJagpal Singh Gill                      osRelease, "ERROR_MSG", ec.message());
290cab87e9cSJagpal Singh Gill #else
291cab87e9cSJagpal Singh Gill                 error("Failed to read osRelease: {PATH}: {ERROR_MSG}", "PATH",
292cab87e9cSJagpal Singh Gill                       osRelease, "ERROR_MSG", ec.message());
293cab87e9cSJagpal Singh Gill 
294cab87e9cSJagpal Singh Gill                 // Try to get the version id from the mount directory name and
295cab87e9cSJagpal Singh Gill                 // call to delete it as this version may be corrupted. Dynamic
296cab87e9cSJagpal Singh Gill                 // volumes created by the UBI layout for example have the id in
297cab87e9cSJagpal Singh Gill                 // the mount directory name. The worst that can happen is that
298cab87e9cSJagpal Singh Gill                 // erase() is called with an non-existent id and returns.
299cab87e9cSJagpal Singh Gill                 auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN);
300cab87e9cSJagpal Singh Gill                 ItemUpdater::erase(id);
301cab87e9cSJagpal Singh Gill #endif
302cab87e9cSJagpal Singh Gill 
303cab87e9cSJagpal Singh Gill                 continue;
304cab87e9cSJagpal Singh Gill             }
305cab87e9cSJagpal Singh Gill             auto version = VersionClass::getBMCVersion(osRelease);
306cab87e9cSJagpal Singh Gill             if (version.empty())
307cab87e9cSJagpal Singh Gill             {
308cab87e9cSJagpal Singh Gill                 error("Failed to read version from osRelease: {PATH}", "PATH",
309cab87e9cSJagpal Singh Gill                       osRelease);
310cab87e9cSJagpal Singh Gill 
311cab87e9cSJagpal Singh Gill                 // Try to delete the version, same as above if the
312cab87e9cSJagpal Singh Gill                 // OS_RELEASE_FILE does not exist.
313cab87e9cSJagpal Singh Gill                 auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN);
314cab87e9cSJagpal Singh Gill                 ItemUpdater::erase(id);
315cab87e9cSJagpal Singh Gill 
316cab87e9cSJagpal Singh Gill                 continue;
317cab87e9cSJagpal Singh Gill             }
318cab87e9cSJagpal Singh Gill 
319cab87e9cSJagpal Singh Gill             // The flash location is part of the mount name: rofs-<location>
320cab87e9cSJagpal Singh Gill             auto flashId = iter.path().native().substr(BMC_RO_PREFIX_LEN);
321cab87e9cSJagpal Singh Gill 
322cab87e9cSJagpal Singh Gill             auto id = VersionClass::getId(version + flashId);
323cab87e9cSJagpal Singh Gill 
324cab87e9cSJagpal Singh Gill             // Check if the id has already been added. This can happen if the
325cab87e9cSJagpal Singh Gill             // BMC partitions / devices were manually flashed with the same
326cab87e9cSJagpal Singh Gill             // image.
327cab87e9cSJagpal Singh Gill             if (versions.find(id) != versions.end())
328cab87e9cSJagpal Singh Gill             {
329cab87e9cSJagpal Singh Gill                 continue;
330cab87e9cSJagpal Singh Gill             }
331cab87e9cSJagpal Singh Gill 
332cab87e9cSJagpal Singh Gill             auto functional = false;
333cab87e9cSJagpal Singh Gill             if (iter.path().native().find(functionalSuffix) !=
334cab87e9cSJagpal Singh Gill                 std::string::npos)
335cab87e9cSJagpal Singh Gill             {
336cab87e9cSJagpal Singh Gill                 // Set functional to true and remove the functional suffix
337cab87e9cSJagpal Singh Gill                 functional = true;
338cab87e9cSJagpal Singh Gill                 flashId.erase(flashId.length() - strlen(functionalSuffix));
339cab87e9cSJagpal Singh Gill                 functionalFound = true;
340cab87e9cSJagpal Singh Gill             }
341cab87e9cSJagpal Singh Gill 
342cab87e9cSJagpal Singh Gill             auto purpose = server::Version::VersionPurpose::BMC;
343cab87e9cSJagpal Singh Gill             restorePurpose(flashId, purpose);
344cab87e9cSJagpal Singh Gill 
345cab87e9cSJagpal Singh Gill             // Read os-release from /etc/ to get the BMC extended version
346cab87e9cSJagpal Singh Gill             std::string extendedVersion =
347cab87e9cSJagpal Singh Gill                 VersionClass::getBMCExtendedVersion(osRelease);
348cab87e9cSJagpal Singh Gill 
349cab87e9cSJagpal Singh Gill             auto path = fs::path(SOFTWARE_OBJPATH) / id;
350cab87e9cSJagpal Singh Gill 
351cab87e9cSJagpal Singh Gill             // Create functional association and minimum ship level instance if
352cab87e9cSJagpal Singh Gill             // this is the functional version
353cab87e9cSJagpal Singh Gill             if (functional)
354cab87e9cSJagpal Singh Gill             {
355cab87e9cSJagpal Singh Gill                 createFunctionalAssociation(path);
356cab87e9cSJagpal Singh Gill 
357cab87e9cSJagpal Singh Gill                 if (minimum_ship_level::enabled())
358cab87e9cSJagpal Singh Gill                 {
359cab87e9cSJagpal Singh Gill                     minimumVersionObject =
360cab87e9cSJagpal Singh Gill                         std::make_unique<MinimumVersion>(bus, path);
361cab87e9cSJagpal Singh Gill                     minimumVersionObject->minimumVersion(
362cab87e9cSJagpal Singh Gill                         minimum_ship_level::getMinimumVersion());
363cab87e9cSJagpal Singh Gill                 }
364cab87e9cSJagpal Singh Gill             }
365cab87e9cSJagpal Singh Gill 
366cab87e9cSJagpal Singh Gill             AssociationList associations;
367cab87e9cSJagpal Singh Gill 
368cab87e9cSJagpal Singh Gill             if (activationState == server::Activation::Activations::Active)
369cab87e9cSJagpal Singh Gill             {
370cab87e9cSJagpal Singh Gill                 // Create an association to the BMC inventory item
371cab87e9cSJagpal Singh Gill                 associations.emplace_back(std::make_tuple(
372cab87e9cSJagpal Singh Gill                     ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
373cab87e9cSJagpal Singh Gill                     bmcInventoryPath));
374cab87e9cSJagpal Singh Gill 
375cab87e9cSJagpal Singh Gill                 // Create an active association since this image is active
376cab87e9cSJagpal Singh Gill                 createActiveAssociation(path);
377cab87e9cSJagpal Singh Gill             }
378cab87e9cSJagpal Singh Gill 
379cab87e9cSJagpal Singh Gill             // Create Version instance for this version.
380cab87e9cSJagpal Singh Gill             auto versionPtr = std::make_unique<VersionClass>(
381cab87e9cSJagpal Singh Gill                 bus, path, version, purpose, extendedVersion, flashId,
382cab87e9cSJagpal Singh Gill                 std::vector<std::string>(),
383cab87e9cSJagpal Singh Gill                 std::bind(&ItemUpdater::erase, this, std::placeholders::_1),
384cab87e9cSJagpal Singh Gill                 id);
385cab87e9cSJagpal Singh Gill             if (functional)
386cab87e9cSJagpal Singh Gill             {
387cab87e9cSJagpal Singh Gill                 versionPtr->setFunctional(true);
388cab87e9cSJagpal Singh Gill             }
389cab87e9cSJagpal Singh Gill             else
390cab87e9cSJagpal Singh Gill             {
391cab87e9cSJagpal Singh Gill                 versionPtr->deleteObject =
392cab87e9cSJagpal Singh Gill                     std::make_unique<phosphor::software::manager::Delete>(
393cab87e9cSJagpal Singh Gill                         bus, path, *versionPtr);
394cab87e9cSJagpal Singh Gill             }
395cab87e9cSJagpal Singh Gill             versions.insert(std::make_pair(id, std::move(versionPtr)));
396cab87e9cSJagpal Singh Gill 
397cab87e9cSJagpal Singh Gill             // Create Activation instance for this version.
398cab87e9cSJagpal Singh Gill             activations.insert(std::make_pair(
399cab87e9cSJagpal Singh Gill                 id, std::make_unique<Activation>(
400cab87e9cSJagpal Singh Gill                         bus, path, *this, id, activationState, associations)));
401cab87e9cSJagpal Singh Gill 
402cab87e9cSJagpal Singh Gill #ifdef BMC_STATIC_DUAL_IMAGE
403cab87e9cSJagpal Singh Gill             uint8_t priority;
404cab87e9cSJagpal Singh Gill             if ((functional && (runningImageSlot == 0)) ||
405cab87e9cSJagpal Singh Gill                 (!functional && (runningImageSlot == 1)))
406cab87e9cSJagpal Singh Gill             {
407cab87e9cSJagpal Singh Gill                 priority = 0;
408cab87e9cSJagpal Singh Gill             }
409cab87e9cSJagpal Singh Gill             else
410cab87e9cSJagpal Singh Gill             {
411cab87e9cSJagpal Singh Gill                 priority = 1;
412cab87e9cSJagpal Singh Gill             }
413cab87e9cSJagpal Singh Gill             activations.find(id)->second->redundancyPriority =
414cab87e9cSJagpal Singh Gill                 std::make_unique<RedundancyPriority>(
415cab87e9cSJagpal Singh Gill                     bus, path, *(activations.find(id)->second), priority,
416cab87e9cSJagpal Singh Gill                     false);
417cab87e9cSJagpal Singh Gill #else
418cab87e9cSJagpal Singh Gill             // If Active, create RedundancyPriority instance for this
419cab87e9cSJagpal Singh Gill             // version.
420cab87e9cSJagpal Singh Gill             if (activationState == server::Activation::Activations::Active)
421cab87e9cSJagpal Singh Gill             {
422cab87e9cSJagpal Singh Gill                 uint8_t priority = std::numeric_limits<uint8_t>::max();
423cab87e9cSJagpal Singh Gill                 if (!restorePriority(flashId, priority))
424cab87e9cSJagpal Singh Gill                 {
425cab87e9cSJagpal Singh Gill                     if (functional)
426cab87e9cSJagpal Singh Gill                     {
427cab87e9cSJagpal Singh Gill                         priority = 0;
428cab87e9cSJagpal Singh Gill                     }
429cab87e9cSJagpal Singh Gill                     else
430cab87e9cSJagpal Singh Gill                     {
431cab87e9cSJagpal Singh Gill                         error(
432cab87e9cSJagpal Singh Gill                             "Unable to restore priority from file for {VERSIONID}",
433cab87e9cSJagpal Singh Gill                             "VERSIONID", id);
434cab87e9cSJagpal Singh Gill                     }
435cab87e9cSJagpal Singh Gill                 }
436cab87e9cSJagpal Singh Gill                 activations.find(id)->second->redundancyPriority =
437cab87e9cSJagpal Singh Gill                     std::make_unique<RedundancyPriority>(
438cab87e9cSJagpal Singh Gill                         bus, path, *(activations.find(id)->second), priority,
439cab87e9cSJagpal Singh Gill                         false);
440cab87e9cSJagpal Singh Gill             }
441cab87e9cSJagpal Singh Gill #endif
442cab87e9cSJagpal Singh Gill         }
443cab87e9cSJagpal Singh Gill     }
444cab87e9cSJagpal Singh Gill 
445cab87e9cSJagpal Singh Gill     for (const auto& version : versions)
446cab87e9cSJagpal Singh Gill     {
447cab87e9cSJagpal Singh Gill         if ((versions.size() == 1) || (!version.second->isFunctional()))
448cab87e9cSJagpal Singh Gill         {
449cab87e9cSJagpal Singh Gill             // This is the only BMC version or the non-functional BMC version
450cab87e9cSJagpal Singh Gill             // (in a system with more than one flash), hence create Update
451cab87e9cSJagpal Singh Gill             // object and Updateable association for this version
452cab87e9cSJagpal Singh Gill             if (useUpdateDBusInterface)
453cab87e9cSJagpal Singh Gill             {
454cab87e9cSJagpal Singh Gill                 createUpdateObject(version.first, version.second->objPath);
455cab87e9cSJagpal Singh Gill             }
456cab87e9cSJagpal Singh Gill             createUpdateableAssociation(version.second->objPath);
457cab87e9cSJagpal Singh Gill         }
458cab87e9cSJagpal Singh Gill     }
459cab87e9cSJagpal Singh Gill 
460cab87e9cSJagpal Singh Gill     if (!functionalFound)
461cab87e9cSJagpal Singh Gill     {
462cab87e9cSJagpal Singh Gill         // If there is no functional version found, read the /etc/os-release and
463cab87e9cSJagpal Singh Gill         // create rofs-<versionId>-functional under MEDIA_DIR, then call again
464cab87e9cSJagpal Singh Gill         // processBMCImage() to create the D-Bus interface for it.
465cab87e9cSJagpal Singh Gill         auto version = VersionClass::getBMCVersion(OS_RELEASE_FILE);
466cab87e9cSJagpal Singh Gill         auto id = phosphor::software::manager::Version::getId(
467cab87e9cSJagpal Singh Gill             version + functionalSuffix);
468cab87e9cSJagpal Singh Gill         auto versionFileDir = BMC_ROFS_PREFIX + id + functionalSuffix + "/etc/";
469cab87e9cSJagpal Singh Gill         try
470cab87e9cSJagpal Singh Gill         {
471cab87e9cSJagpal Singh Gill             if (!fs::is_directory(versionFileDir))
472cab87e9cSJagpal Singh Gill             {
473cab87e9cSJagpal Singh Gill                 fs::create_directories(versionFileDir);
474cab87e9cSJagpal Singh Gill             }
475cab87e9cSJagpal Singh Gill             auto versionFilePath =
476cab87e9cSJagpal Singh Gill                 BMC_ROFS_PREFIX + id + functionalSuffix + OS_RELEASE_FILE;
477cab87e9cSJagpal Singh Gill             fs::create_directory_symlink(OS_RELEASE_FILE, versionFilePath);
478cab87e9cSJagpal Singh Gill             ItemUpdater::processBMCImage();
479cab87e9cSJagpal Singh Gill         }
480cab87e9cSJagpal Singh Gill         catch (const std::exception& e)
481cab87e9cSJagpal Singh Gill         {
482cab87e9cSJagpal Singh Gill             error("Exception during processing: {ERROR}", "ERROR", e);
483cab87e9cSJagpal Singh Gill         }
484cab87e9cSJagpal Singh Gill     }
485cab87e9cSJagpal Singh Gill 
486cab87e9cSJagpal Singh Gill     mirrorUbootToAlt();
487cab87e9cSJagpal Singh Gill     return;
488cab87e9cSJagpal Singh Gill }
489cab87e9cSJagpal Singh Gill 
erase(std::string entryId)490cab87e9cSJagpal Singh Gill void ItemUpdater::erase(std::string entryId)
491cab87e9cSJagpal Singh Gill {
492cab87e9cSJagpal Singh Gill     // Find entry in versions map
493cab87e9cSJagpal Singh Gill     auto it = versions.find(entryId);
494cab87e9cSJagpal Singh Gill     if (it != versions.end())
495cab87e9cSJagpal Singh Gill     {
496cab87e9cSJagpal Singh Gill         if (it->second->isFunctional() && ACTIVE_BMC_MAX_ALLOWED > 1)
497cab87e9cSJagpal Singh Gill         {
498cab87e9cSJagpal Singh Gill             error(
499cab87e9cSJagpal Singh Gill                 "Version ({VERSIONID}) is currently running on the BMC; unable to remove.",
500cab87e9cSJagpal Singh Gill                 "VERSIONID", entryId);
501cab87e9cSJagpal Singh Gill             return;
502cab87e9cSJagpal Singh Gill         }
503cab87e9cSJagpal Singh Gill     }
504cab87e9cSJagpal Singh Gill 
505cab87e9cSJagpal Singh Gill     // First call resetUbootEnvVars() so that the BMC points to a valid image to
506cab87e9cSJagpal Singh Gill     // boot from. If resetUbootEnvVars() is called after the image is actually
507cab87e9cSJagpal Singh Gill     // deleted from the BMC flash, there'd be a time window where the BMC would
508cab87e9cSJagpal Singh Gill     // be pointing to a non-existent image to boot from.
509cab87e9cSJagpal Singh Gill     // Need to remove the entries from the activations map before that call so
510cab87e9cSJagpal Singh Gill     // that resetUbootEnvVars() doesn't use the version to be deleted.
511cab87e9cSJagpal Singh Gill     auto iteratorActivations = activations.find(entryId);
512cab87e9cSJagpal Singh Gill     if (iteratorActivations == activations.end())
513cab87e9cSJagpal Singh Gill     {
514cab87e9cSJagpal Singh Gill         error(
515cab87e9cSJagpal Singh Gill             "Failed to find version ({VERSIONID}) in item updater activations map; unable to remove.",
516cab87e9cSJagpal Singh Gill             "VERSIONID", entryId);
517cab87e9cSJagpal Singh Gill     }
518cab87e9cSJagpal Singh Gill     else
519cab87e9cSJagpal Singh Gill     {
520cab87e9cSJagpal Singh Gill         removeAssociations(iteratorActivations->second->path);
521cab87e9cSJagpal Singh Gill         iteratorActivations->second->deleteImageManagerObject();
522cab87e9cSJagpal Singh Gill         this->activations.erase(entryId);
523cab87e9cSJagpal Singh Gill     }
524cab87e9cSJagpal Singh Gill     ItemUpdater::resetUbootEnvVars();
525cab87e9cSJagpal Singh Gill 
526cab87e9cSJagpal Singh Gill     if (it != versions.end())
527cab87e9cSJagpal Singh Gill     {
528cab87e9cSJagpal Singh Gill         auto flashId = it->second->path();
529cab87e9cSJagpal Singh Gill 
530cab87e9cSJagpal Singh Gill         // Delete version data if it has been installed on flash (path is not
531cab87e9cSJagpal Singh Gill         // the upload directory)
532cab87e9cSJagpal Singh Gill         if (flashId.find(IMG_UPLOAD_DIR) == std::string::npos)
533cab87e9cSJagpal Singh Gill         {
534cab87e9cSJagpal Singh Gill             removeReadOnlyPartition(entryId);
535cab87e9cSJagpal Singh Gill             removePersistDataDirectory(flashId);
536cab87e9cSJagpal Singh Gill             helper.clearEntry(flashId);
537cab87e9cSJagpal Singh Gill         }
538cab87e9cSJagpal Singh Gill 
539cab87e9cSJagpal Singh Gill         // Removing entry in versions map
540cab87e9cSJagpal Singh Gill         this->versions.erase(entryId);
541cab87e9cSJagpal Singh Gill     }
542cab87e9cSJagpal Singh Gill 
543cab87e9cSJagpal Singh Gill     // Removing entry in updateManagers map
544cab87e9cSJagpal Singh Gill     auto updateManagerIt = updateManagers.find(entryId);
545cab87e9cSJagpal Singh Gill     if (updateManagerIt != updateManagers.end())
546cab87e9cSJagpal Singh Gill     {
547cab87e9cSJagpal Singh Gill         updateManagers.erase(entryId);
548cab87e9cSJagpal Singh Gill     }
549cab87e9cSJagpal Singh Gill 
550cab87e9cSJagpal Singh Gill     return;
551cab87e9cSJagpal Singh Gill }
552cab87e9cSJagpal Singh Gill 
deleteAll()553cab87e9cSJagpal Singh Gill void ItemUpdater::deleteAll()
554cab87e9cSJagpal Singh Gill {
555cab87e9cSJagpal Singh Gill     std::vector<std::string> deletableVersions;
556cab87e9cSJagpal Singh Gill 
557cab87e9cSJagpal Singh Gill     for (const auto& versionIt : versions)
558cab87e9cSJagpal Singh Gill     {
559cab87e9cSJagpal Singh Gill         if (!versionIt.second->isFunctional())
560cab87e9cSJagpal Singh Gill         {
561cab87e9cSJagpal Singh Gill             deletableVersions.push_back(versionIt.first);
562cab87e9cSJagpal Singh Gill         }
563cab87e9cSJagpal Singh Gill     }
564cab87e9cSJagpal Singh Gill 
565cab87e9cSJagpal Singh Gill     for (const auto& deletableIt : deletableVersions)
566cab87e9cSJagpal Singh Gill     {
567cab87e9cSJagpal Singh Gill         ItemUpdater::erase(deletableIt);
568cab87e9cSJagpal Singh Gill     }
569cab87e9cSJagpal Singh Gill 
570cab87e9cSJagpal Singh Gill     helper.cleanup();
571cab87e9cSJagpal Singh Gill }
572cab87e9cSJagpal Singh Gill 
validateSquashFSImage(const std::string & filePath)573*eae5ec9eSPatrick Williams ItemUpdater::ActivationStatus ItemUpdater::validateSquashFSImage(
574*eae5ec9eSPatrick Williams     const std::string& filePath)
575cab87e9cSJagpal Singh Gill {
576cab87e9cSJagpal Singh Gill     bool valid = true;
577cab87e9cSJagpal Singh Gill 
578cab87e9cSJagpal Singh Gill     // Record the images which are being updated
579cab87e9cSJagpal Singh Gill     // First check for the fullimage, then check for images with partitions
580cab87e9cSJagpal Singh Gill     imageUpdateList.push_back(bmcFullImages);
581cab87e9cSJagpal Singh Gill     valid = checkImage(filePath, imageUpdateList);
582cab87e9cSJagpal Singh Gill     if (!valid)
583cab87e9cSJagpal Singh Gill     {
584cab87e9cSJagpal Singh Gill         imageUpdateList.clear();
585cab87e9cSJagpal Singh Gill         imageUpdateList.assign(bmcImages.begin(), bmcImages.end());
586cab87e9cSJagpal Singh Gill         valid = checkImage(filePath, imageUpdateList);
587cab87e9cSJagpal Singh Gill         if (!valid)
588cab87e9cSJagpal Singh Gill         {
589cab87e9cSJagpal Singh Gill             error("Failed to find the needed BMC images.");
590cab87e9cSJagpal Singh Gill             return ItemUpdater::ActivationStatus::invalid;
591cab87e9cSJagpal Singh Gill         }
592cab87e9cSJagpal Singh Gill     }
593cab87e9cSJagpal Singh Gill 
594cab87e9cSJagpal Singh Gill     return ItemUpdater::ActivationStatus::ready;
595cab87e9cSJagpal Singh Gill }
596cab87e9cSJagpal Singh Gill 
savePriority(const std::string & versionId,uint8_t value)597cab87e9cSJagpal Singh Gill void ItemUpdater::savePriority(const std::string& versionId, uint8_t value)
598cab87e9cSJagpal Singh Gill {
599cab87e9cSJagpal Singh Gill     auto flashId = versions.find(versionId)->second->path();
600cab87e9cSJagpal Singh Gill     storePriority(flashId, value);
601cab87e9cSJagpal Singh Gill     helper.setEntry(flashId, value);
602cab87e9cSJagpal Singh Gill }
603cab87e9cSJagpal Singh Gill 
freePriority(uint8_t value,const std::string & versionId)604cab87e9cSJagpal Singh Gill void ItemUpdater::freePriority(uint8_t value, const std::string& versionId)
605cab87e9cSJagpal Singh Gill {
606cab87e9cSJagpal Singh Gill     std::map<std::string, uint8_t> priorityMap;
607cab87e9cSJagpal Singh Gill 
608cab87e9cSJagpal Singh Gill     // Insert the requested version and priority, it may not exist yet.
609cab87e9cSJagpal Singh Gill     priorityMap.insert(std::make_pair(versionId, value));
610cab87e9cSJagpal Singh Gill 
611cab87e9cSJagpal Singh Gill     for (const auto& intf : activations)
612cab87e9cSJagpal Singh Gill     {
613cab87e9cSJagpal Singh Gill         if (intf.second->redundancyPriority)
614cab87e9cSJagpal Singh Gill         {
615cab87e9cSJagpal Singh Gill             priorityMap.insert(std::make_pair(
616cab87e9cSJagpal Singh Gill                 intf.first, intf.second->redundancyPriority->priority()));
617cab87e9cSJagpal Singh Gill         }
618cab87e9cSJagpal Singh Gill     }
619cab87e9cSJagpal Singh Gill 
620cab87e9cSJagpal Singh Gill     // Lambda function to compare 2 priority values, use <= to allow duplicates
621cab87e9cSJagpal Singh Gill     typedef std::function<bool(std::pair<std::string, uint8_t>,
622cab87e9cSJagpal Singh Gill                                std::pair<std::string, uint8_t>)>
623cab87e9cSJagpal Singh Gill         cmpPriority;
624cab87e9cSJagpal Singh Gill     cmpPriority cmpPriorityFunc =
625cab87e9cSJagpal Singh Gill         [](const std::pair<std::string, uint8_t>& priority1,
626cab87e9cSJagpal Singh Gill            const std::pair<std::string, uint8_t>& priority2) {
627cab87e9cSJagpal Singh Gill             return priority1.second <= priority2.second;
628cab87e9cSJagpal Singh Gill         };
629cab87e9cSJagpal Singh Gill 
630cab87e9cSJagpal Singh Gill     // Sort versions by ascending priority
631cab87e9cSJagpal Singh Gill     std::set<std::pair<std::string, uint8_t>, cmpPriority> prioritySet(
632cab87e9cSJagpal Singh Gill         priorityMap.begin(), priorityMap.end(), cmpPriorityFunc);
633cab87e9cSJagpal Singh Gill 
634cab87e9cSJagpal Singh Gill     auto freePriorityValue = value;
635cab87e9cSJagpal Singh Gill     for (auto& element : prioritySet)
636cab87e9cSJagpal Singh Gill     {
637cab87e9cSJagpal Singh Gill         if (element.first == versionId)
638cab87e9cSJagpal Singh Gill         {
639cab87e9cSJagpal Singh Gill             continue;
640cab87e9cSJagpal Singh Gill         }
641cab87e9cSJagpal Singh Gill         if (element.second == freePriorityValue)
642cab87e9cSJagpal Singh Gill         {
643cab87e9cSJagpal Singh Gill             ++freePriorityValue;
644cab87e9cSJagpal Singh Gill             auto it = activations.find(element.first);
645cab87e9cSJagpal Singh Gill             it->second->redundancyPriority->sdbusPriority(freePriorityValue);
646cab87e9cSJagpal Singh Gill         }
647cab87e9cSJagpal Singh Gill     }
648cab87e9cSJagpal Singh Gill 
649cab87e9cSJagpal Singh Gill     auto lowestVersion = prioritySet.begin()->first;
650cab87e9cSJagpal Singh Gill     if (value == prioritySet.begin()->second)
651cab87e9cSJagpal Singh Gill     {
652cab87e9cSJagpal Singh Gill         lowestVersion = versionId;
653cab87e9cSJagpal Singh Gill     }
654cab87e9cSJagpal Singh Gill     updateUbootEnvVars(lowestVersion);
655cab87e9cSJagpal Singh Gill }
656cab87e9cSJagpal Singh Gill 
reset()657cab87e9cSJagpal Singh Gill void ItemUpdater::reset()
658cab87e9cSJagpal Singh Gill {
659cab87e9cSJagpal Singh Gill     phosphor::software::updater::Helper::factoryReset();
660cab87e9cSJagpal Singh Gill 
661cab87e9cSJagpal Singh Gill     info("BMC factory reset will take effect upon reboot.");
662cab87e9cSJagpal Singh Gill }
663cab87e9cSJagpal Singh Gill 
removeReadOnlyPartition(const std::string & versionId)664cab87e9cSJagpal Singh Gill void ItemUpdater::removeReadOnlyPartition(const std::string& versionId)
665cab87e9cSJagpal Singh Gill {
666cab87e9cSJagpal Singh Gill     auto flashId = versions.find(versionId)->second->path();
667cab87e9cSJagpal Singh Gill     helper.removeVersion(flashId);
668cab87e9cSJagpal Singh Gill }
669cab87e9cSJagpal Singh Gill 
fieldModeEnabled(bool value)670cab87e9cSJagpal Singh Gill bool ItemUpdater::fieldModeEnabled(bool value)
671cab87e9cSJagpal Singh Gill {
672cab87e9cSJagpal Singh Gill     // enabling field mode is intended to be one way: false -> true
673cab87e9cSJagpal Singh Gill     if (value && !control::FieldMode::fieldModeEnabled())
674cab87e9cSJagpal Singh Gill     {
675cab87e9cSJagpal Singh Gill         control::FieldMode::fieldModeEnabled(value);
676cab87e9cSJagpal Singh Gill 
677cab87e9cSJagpal Singh Gill         auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
678cab87e9cSJagpal Singh Gill                                           SYSTEMD_INTERFACE, "StartUnit");
679cab87e9cSJagpal Singh Gill         method.append("obmc-flash-bmc-setenv@fieldmode\\x3dtrue.service",
680cab87e9cSJagpal Singh Gill                       "replace");
681cab87e9cSJagpal Singh Gill         bus.call_noreply(method);
682cab87e9cSJagpal Singh Gill 
683cab87e9cSJagpal Singh Gill         method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
684cab87e9cSJagpal Singh Gill                                      SYSTEMD_INTERFACE, "StopUnit");
685cab87e9cSJagpal Singh Gill         method.append("usr-local.mount", "replace");
686cab87e9cSJagpal Singh Gill         bus.call_noreply(method);
687cab87e9cSJagpal Singh Gill 
688cab87e9cSJagpal Singh Gill         std::vector<std::string> usrLocal = {"usr-local.mount"};
689cab87e9cSJagpal Singh Gill 
690cab87e9cSJagpal Singh Gill         method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
691cab87e9cSJagpal Singh Gill                                      SYSTEMD_INTERFACE, "MaskUnitFiles");
692cab87e9cSJagpal Singh Gill         method.append(usrLocal, false, true);
693cab87e9cSJagpal Singh Gill         bus.call_noreply(method);
694cab87e9cSJagpal Singh Gill     }
695cab87e9cSJagpal Singh Gill     else if (!value && control::FieldMode::fieldModeEnabled())
696cab87e9cSJagpal Singh Gill     {
697cab87e9cSJagpal Singh Gill         elog<NotAllowed>(xyz::openbmc_project::common::NotAllowed::REASON(
698cab87e9cSJagpal Singh Gill             "FieldMode is not allowed to be cleared"));
699cab87e9cSJagpal Singh Gill     }
700cab87e9cSJagpal Singh Gill 
701cab87e9cSJagpal Singh Gill     return control::FieldMode::fieldModeEnabled();
702cab87e9cSJagpal Singh Gill }
703cab87e9cSJagpal Singh Gill 
restoreFieldModeStatus()704cab87e9cSJagpal Singh Gill void ItemUpdater::restoreFieldModeStatus()
705cab87e9cSJagpal Singh Gill {
706cab87e9cSJagpal Singh Gill     // The fieldmode u-boot environment variable may not exist since it is not
707cab87e9cSJagpal Singh Gill     // part of the default environment, run fw_printenv with 2>&1 to ignore the
708cab87e9cSJagpal Singh Gill     // error message in the journal "Error: "fieldmode" not defined"
709cab87e9cSJagpal Singh Gill     std::pair<int, std::string> ret =
710cab87e9cSJagpal Singh Gill         utils::execute("/sbin/fw_printenv", "-n", "fieldmode", "2>&1");
711cab87e9cSJagpal Singh Gill 
712cab87e9cSJagpal Singh Gill     if (ret.first != 0)
713cab87e9cSJagpal Singh Gill     {
714cab87e9cSJagpal Singh Gill         return;
715cab87e9cSJagpal Singh Gill     }
716cab87e9cSJagpal Singh Gill 
717cab87e9cSJagpal Singh Gill     // truncate any extra characters off the end to compare against a "true" str
718cab87e9cSJagpal Singh Gill     std::string result = ret.second.substr(0, 4);
719cab87e9cSJagpal Singh Gill     if (result == "true")
720cab87e9cSJagpal Singh Gill     {
721cab87e9cSJagpal Singh Gill         ItemUpdater::fieldModeEnabled(true);
722cab87e9cSJagpal Singh Gill     }
723cab87e9cSJagpal Singh Gill }
724cab87e9cSJagpal Singh Gill 
setBMCInventoryPath()725cab87e9cSJagpal Singh Gill void ItemUpdater::setBMCInventoryPath()
726cab87e9cSJagpal Singh Gill {
727cab87e9cSJagpal Singh Gill     auto depth = 0;
728cab87e9cSJagpal Singh Gill     auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
729cab87e9cSJagpal Singh Gill                                           MAPPER_INTERFACE, "GetSubTreePaths");
730cab87e9cSJagpal Singh Gill 
731cab87e9cSJagpal Singh Gill     mapperCall.append(INVENTORY_PATH);
732cab87e9cSJagpal Singh Gill     mapperCall.append(depth);
733cab87e9cSJagpal Singh Gill     std::vector<std::string> filter = {BMC_INVENTORY_INTERFACE};
734cab87e9cSJagpal Singh Gill     mapperCall.append(filter);
735cab87e9cSJagpal Singh Gill 
736cab87e9cSJagpal Singh Gill     try
737cab87e9cSJagpal Singh Gill     {
738cab87e9cSJagpal Singh Gill         auto response = bus.call(mapperCall);
739cab87e9cSJagpal Singh Gill 
740cab87e9cSJagpal Singh Gill         using ObjectPaths = std::vector<std::string>;
741cab87e9cSJagpal Singh Gill         ObjectPaths result;
742cab87e9cSJagpal Singh Gill         response.read(result);
743cab87e9cSJagpal Singh Gill 
744cab87e9cSJagpal Singh Gill         if (!result.empty())
745cab87e9cSJagpal Singh Gill         {
746cab87e9cSJagpal Singh Gill             bmcInventoryPath = result.front();
747cab87e9cSJagpal Singh Gill         }
748cab87e9cSJagpal Singh Gill     }
749cab87e9cSJagpal Singh Gill     catch (const sdbusplus::exception_t& e)
750cab87e9cSJagpal Singh Gill     {
751cab87e9cSJagpal Singh Gill         error("Error in mapper GetSubTreePath: {ERROR}", "ERROR", e);
752cab87e9cSJagpal Singh Gill         return;
753cab87e9cSJagpal Singh Gill     }
754cab87e9cSJagpal Singh Gill 
755cab87e9cSJagpal Singh Gill     return;
756cab87e9cSJagpal Singh Gill }
757cab87e9cSJagpal Singh Gill 
createActiveAssociation(const std::string & path)758cab87e9cSJagpal Singh Gill void ItemUpdater::createActiveAssociation(const std::string& path)
759cab87e9cSJagpal Singh Gill {
760cab87e9cSJagpal Singh Gill     assocs.emplace_back(
761cab87e9cSJagpal Singh Gill         std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path));
762cab87e9cSJagpal Singh Gill     associations(assocs);
763cab87e9cSJagpal Singh Gill }
764cab87e9cSJagpal Singh Gill 
createFunctionalAssociation(const std::string & path)765cab87e9cSJagpal Singh Gill void ItemUpdater::createFunctionalAssociation(const std::string& path)
766cab87e9cSJagpal Singh Gill {
767cab87e9cSJagpal Singh Gill     assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION,
768cab87e9cSJagpal Singh Gill                                         FUNCTIONAL_REV_ASSOCIATION, path));
769cab87e9cSJagpal Singh Gill     associations(assocs);
770cab87e9cSJagpal Singh Gill }
771cab87e9cSJagpal Singh Gill 
createUpdateableAssociation(const std::string & path)772cab87e9cSJagpal Singh Gill void ItemUpdater::createUpdateableAssociation(const std::string& path)
773cab87e9cSJagpal Singh Gill {
774cab87e9cSJagpal Singh Gill     assocs.emplace_back(std::make_tuple(UPDATEABLE_FWD_ASSOCIATION,
775cab87e9cSJagpal Singh Gill                                         UPDATEABLE_REV_ASSOCIATION, path));
776cab87e9cSJagpal Singh Gill     associations(assocs);
777cab87e9cSJagpal Singh Gill }
778cab87e9cSJagpal Singh Gill 
removeAssociations(const std::string & path)779cab87e9cSJagpal Singh Gill void ItemUpdater::removeAssociations(const std::string& path)
780cab87e9cSJagpal Singh Gill {
781cab87e9cSJagpal Singh Gill     for (auto iter = assocs.begin(); iter != assocs.end();)
782cab87e9cSJagpal Singh Gill     {
783cab87e9cSJagpal Singh Gill         if (std::get<2>(*iter) == path)
784cab87e9cSJagpal Singh Gill         {
785cab87e9cSJagpal Singh Gill             iter = assocs.erase(iter);
786cab87e9cSJagpal Singh Gill             associations(assocs);
787cab87e9cSJagpal Singh Gill         }
788cab87e9cSJagpal Singh Gill         else
789cab87e9cSJagpal Singh Gill         {
790cab87e9cSJagpal Singh Gill             ++iter;
791cab87e9cSJagpal Singh Gill         }
792cab87e9cSJagpal Singh Gill     }
793cab87e9cSJagpal Singh Gill }
794cab87e9cSJagpal Singh Gill 
isLowestPriority(uint8_t value)795cab87e9cSJagpal Singh Gill bool ItemUpdater::isLowestPriority(uint8_t value)
796cab87e9cSJagpal Singh Gill {
797cab87e9cSJagpal Singh Gill     for (const auto& intf : activations)
798cab87e9cSJagpal Singh Gill     {
799cab87e9cSJagpal Singh Gill         if (intf.second->redundancyPriority)
800cab87e9cSJagpal Singh Gill         {
801cab87e9cSJagpal Singh Gill             if (intf.second->redundancyPriority->priority() < value)
802cab87e9cSJagpal Singh Gill             {
803cab87e9cSJagpal Singh Gill                 return false;
804cab87e9cSJagpal Singh Gill             }
805cab87e9cSJagpal Singh Gill         }
806cab87e9cSJagpal Singh Gill     }
807cab87e9cSJagpal Singh Gill     return true;
808cab87e9cSJagpal Singh Gill }
809cab87e9cSJagpal Singh Gill 
updateUbootEnvVars(const std::string & versionId)810cab87e9cSJagpal Singh Gill void ItemUpdater::updateUbootEnvVars(const std::string& versionId)
811cab87e9cSJagpal Singh Gill {
812cab87e9cSJagpal Singh Gill     auto it = versions.find(versionId);
813cab87e9cSJagpal Singh Gill     if (it == versions.end())
814cab87e9cSJagpal Singh Gill     {
815cab87e9cSJagpal Singh Gill         return;
816cab87e9cSJagpal Singh Gill     }
817cab87e9cSJagpal Singh Gill     auto flashId = it->second->path();
818cab87e9cSJagpal Singh Gill     helper.updateUbootVersionId(flashId);
819cab87e9cSJagpal Singh Gill }
820cab87e9cSJagpal Singh Gill 
resetUbootEnvVars()821cab87e9cSJagpal Singh Gill void ItemUpdater::resetUbootEnvVars()
822cab87e9cSJagpal Singh Gill {
823cab87e9cSJagpal Singh Gill     decltype(activations.begin()->second->redundancyPriority->priority())
824cab87e9cSJagpal Singh Gill         lowestPriority = std::numeric_limits<uint8_t>::max();
825cab87e9cSJagpal Singh Gill     decltype(activations.begin()->second->versionId) lowestPriorityVersion;
826cab87e9cSJagpal Singh Gill     for (const auto& intf : activations)
827cab87e9cSJagpal Singh Gill     {
828cab87e9cSJagpal Singh Gill         if (!intf.second->redundancyPriority)
829cab87e9cSJagpal Singh Gill         {
830cab87e9cSJagpal Singh Gill             // Skip this version if the redundancyPriority is not initialized.
831cab87e9cSJagpal Singh Gill             continue;
832cab87e9cSJagpal Singh Gill         }
833cab87e9cSJagpal Singh Gill 
834cab87e9cSJagpal Singh Gill         if (intf.second->redundancyPriority->priority() <= lowestPriority)
835cab87e9cSJagpal Singh Gill         {
836cab87e9cSJagpal Singh Gill             lowestPriority = intf.second->redundancyPriority->priority();
837cab87e9cSJagpal Singh Gill             lowestPriorityVersion = intf.second->versionId;
838cab87e9cSJagpal Singh Gill         }
839cab87e9cSJagpal Singh Gill     }
840cab87e9cSJagpal Singh Gill 
841cab87e9cSJagpal Singh Gill     // Update the U-boot environment variable to point to the lowest priority
842cab87e9cSJagpal Singh Gill     updateUbootEnvVars(lowestPriorityVersion);
843cab87e9cSJagpal Singh Gill }
844cab87e9cSJagpal Singh Gill 
freeSpace(const Activation & caller)845cab87e9cSJagpal Singh Gill void ItemUpdater::freeSpace([[maybe_unused]] const Activation& caller)
846cab87e9cSJagpal Singh Gill {
847cab87e9cSJagpal Singh Gill #ifdef BMC_STATIC_DUAL_IMAGE
848cab87e9cSJagpal Singh Gill     // For the golden image case, always remove the version on the primary side
849cab87e9cSJagpal Singh Gill     std::string versionIDtoErase;
850cab87e9cSJagpal Singh Gill     for (const auto& iter : activations)
851cab87e9cSJagpal Singh Gill     {
852cab87e9cSJagpal Singh Gill         if (iter.second->redundancyPriority &&
853cab87e9cSJagpal Singh Gill             iter.second->redundancyPriority->priority() == 0)
854cab87e9cSJagpal Singh Gill         {
855cab87e9cSJagpal Singh Gill             versionIDtoErase = iter.second->versionId;
856cab87e9cSJagpal Singh Gill             break;
857cab87e9cSJagpal Singh Gill         }
858cab87e9cSJagpal Singh Gill     }
859cab87e9cSJagpal Singh Gill     if (!versionIDtoErase.empty())
860cab87e9cSJagpal Singh Gill     {
861cab87e9cSJagpal Singh Gill         erase(versionIDtoErase);
862cab87e9cSJagpal Singh Gill     }
863cab87e9cSJagpal Singh Gill     else
864cab87e9cSJagpal Singh Gill     {
865cab87e9cSJagpal Singh Gill         warning("Failed to find version to erase");
866cab87e9cSJagpal Singh Gill     }
867cab87e9cSJagpal Singh Gill #else
868cab87e9cSJagpal Singh Gill     //  Versions with the highest priority in front
869cab87e9cSJagpal Singh Gill     std::priority_queue<std::pair<int, std::string>,
870cab87e9cSJagpal Singh Gill                         std::vector<std::pair<int, std::string>>,
871cab87e9cSJagpal Singh Gill                         std::less<std::pair<int, std::string>>>
872cab87e9cSJagpal Singh Gill         versionsPQ;
873cab87e9cSJagpal Singh Gill 
874cab87e9cSJagpal Singh Gill     std::size_t count = 0;
875cab87e9cSJagpal Singh Gill     for (const auto& iter : activations)
876cab87e9cSJagpal Singh Gill     {
877cab87e9cSJagpal Singh Gill         if ((iter.second.get()->activation() ==
878cab87e9cSJagpal Singh Gill              server::Activation::Activations::Active) ||
879cab87e9cSJagpal Singh Gill             (iter.second.get()->activation() ==
880cab87e9cSJagpal Singh Gill              server::Activation::Activations::Failed))
881cab87e9cSJagpal Singh Gill         {
882cab87e9cSJagpal Singh Gill             count++;
883cab87e9cSJagpal Singh Gill             // Don't put the functional version on the queue since we can't
884cab87e9cSJagpal Singh Gill             // remove the "running" BMC version.
885cab87e9cSJagpal Singh Gill             // If ACTIVE_BMC_MAX_ALLOWED <= 1, there is only one active BMC,
886cab87e9cSJagpal Singh Gill             // so remove functional version as well.
887cab87e9cSJagpal Singh Gill             // Don't delete the the Activation object that called this function.
888cab87e9cSJagpal Singh Gill             if ((versions.find(iter.second->versionId)
889cab87e9cSJagpal Singh Gill                      ->second->isFunctional() &&
890cab87e9cSJagpal Singh Gill                  ACTIVE_BMC_MAX_ALLOWED > 1) ||
891cab87e9cSJagpal Singh Gill                 (iter.second->versionId == caller.versionId))
892cab87e9cSJagpal Singh Gill             {
893cab87e9cSJagpal Singh Gill                 continue;
894cab87e9cSJagpal Singh Gill             }
895cab87e9cSJagpal Singh Gill 
896cab87e9cSJagpal Singh Gill             // Failed activations don't have priority, assign them a large value
897cab87e9cSJagpal Singh Gill             // for sorting purposes.
898cab87e9cSJagpal Singh Gill             auto priority = 999;
899cab87e9cSJagpal Singh Gill             if (iter.second.get()->activation() ==
900cab87e9cSJagpal Singh Gill                     server::Activation::Activations::Active &&
901cab87e9cSJagpal Singh Gill                 iter.second->redundancyPriority)
902cab87e9cSJagpal Singh Gill             {
903cab87e9cSJagpal Singh Gill                 priority = iter.second->redundancyPriority.get()->priority();
904cab87e9cSJagpal Singh Gill             }
905cab87e9cSJagpal Singh Gill 
906cab87e9cSJagpal Singh Gill             versionsPQ.push(std::make_pair(priority, iter.second->versionId));
907cab87e9cSJagpal Singh Gill         }
908cab87e9cSJagpal Singh Gill     }
909cab87e9cSJagpal Singh Gill 
910cab87e9cSJagpal Singh Gill     // If the number of BMC versions is over ACTIVE_BMC_MAX_ALLOWED -1,
911cab87e9cSJagpal Singh Gill     // remove the highest priority one(s).
912cab87e9cSJagpal Singh Gill     while ((count >= ACTIVE_BMC_MAX_ALLOWED) && (!versionsPQ.empty()))
913cab87e9cSJagpal Singh Gill     {
914cab87e9cSJagpal Singh Gill         erase(versionsPQ.top().second);
915cab87e9cSJagpal Singh Gill         versionsPQ.pop();
916cab87e9cSJagpal Singh Gill         count--;
917cab87e9cSJagpal Singh Gill     }
918cab87e9cSJagpal Singh Gill #endif
919cab87e9cSJagpal Singh Gill }
920cab87e9cSJagpal Singh Gill 
mirrorUbootToAlt()921cab87e9cSJagpal Singh Gill void ItemUpdater::mirrorUbootToAlt()
922cab87e9cSJagpal Singh Gill {
923cab87e9cSJagpal Singh Gill     helper.mirrorAlt();
924cab87e9cSJagpal Singh Gill }
925cab87e9cSJagpal Singh Gill 
checkImage(const std::string & filePath,const std::vector<std::string> & imageList)926cab87e9cSJagpal Singh Gill bool ItemUpdater::checkImage(const std::string& filePath,
927cab87e9cSJagpal Singh Gill                              const std::vector<std::string>& imageList)
928cab87e9cSJagpal Singh Gill {
929cab87e9cSJagpal Singh Gill     bool valid = true;
930cab87e9cSJagpal Singh Gill 
931cab87e9cSJagpal Singh Gill     for (auto& bmcImage : imageList)
932cab87e9cSJagpal Singh Gill     {
933cab87e9cSJagpal Singh Gill         fs::path file(filePath);
934cab87e9cSJagpal Singh Gill         file /= bmcImage;
935cab87e9cSJagpal Singh Gill         std::ifstream efile(file.c_str());
936cab87e9cSJagpal Singh Gill         if (efile.good() != 1)
937cab87e9cSJagpal Singh Gill         {
938cab87e9cSJagpal Singh Gill             valid = false;
939cab87e9cSJagpal Singh Gill             break;
940cab87e9cSJagpal Singh Gill         }
941cab87e9cSJagpal Singh Gill     }
942cab87e9cSJagpal Singh Gill 
943cab87e9cSJagpal Singh Gill     return valid;
944cab87e9cSJagpal Singh Gill }
945cab87e9cSJagpal Singh Gill 
946cab87e9cSJagpal Singh Gill #ifdef HOST_BIOS_UPGRADE
createBIOSObject()947cab87e9cSJagpal Singh Gill void ItemUpdater::createBIOSObject()
948cab87e9cSJagpal Singh Gill {
949cab87e9cSJagpal Singh Gill     std::string path = BIOS_OBJPATH;
950cab87e9cSJagpal Singh Gill     // Get version id from last item in the path
951cab87e9cSJagpal Singh Gill     auto pos = path.rfind('/');
952cab87e9cSJagpal Singh Gill     if (pos == std::string::npos)
953cab87e9cSJagpal Singh Gill     {
954cab87e9cSJagpal Singh Gill         error("No version id found in object path {PATH}", "PATH", path);
955cab87e9cSJagpal Singh Gill         return;
956cab87e9cSJagpal Singh Gill     }
957cab87e9cSJagpal Singh Gill 
958cab87e9cSJagpal Singh Gill     createActiveAssociation(path);
959cab87e9cSJagpal Singh Gill     createFunctionalAssociation(path);
960cab87e9cSJagpal Singh Gill     createUpdateableAssociation(path);
961cab87e9cSJagpal Singh Gill 
962cab87e9cSJagpal Singh Gill     auto versionId = path.substr(pos + 1);
963cab87e9cSJagpal Singh Gill     auto version = "null";
964cab87e9cSJagpal Singh Gill     AssociationList assocs;
965cab87e9cSJagpal Singh Gill     biosActivation = std::make_unique<Activation>(
966cab87e9cSJagpal Singh Gill         bus, path, *this, versionId, server::Activation::Activations::Active,
967cab87e9cSJagpal Singh Gill         assocs);
968cab87e9cSJagpal Singh Gill     auto dummyErase = [](const std::string& /*entryId*/) {
969cab87e9cSJagpal Singh Gill         // Do nothing;
970cab87e9cSJagpal Singh Gill     };
971cab87e9cSJagpal Singh Gill     biosVersion = std::make_unique<VersionClass>(
972cab87e9cSJagpal Singh Gill         bus, path, version, VersionPurpose::Host, "", "",
973cab87e9cSJagpal Singh Gill         std::vector<std::string>(),
974cab87e9cSJagpal Singh Gill         std::bind(dummyErase, std::placeholders::_1), "");
975cab87e9cSJagpal Singh Gill     biosVersion->deleteObject =
976cab87e9cSJagpal Singh Gill         std::make_unique<phosphor::software::manager::Delete>(
977cab87e9cSJagpal Singh Gill             bus, path, *biosVersion);
978cab87e9cSJagpal Singh Gill 
979cab87e9cSJagpal Singh Gill     if (useUpdateDBusInterface)
980cab87e9cSJagpal Singh Gill     {
981cab87e9cSJagpal Singh Gill         createUpdateObject(versionId, path);
982cab87e9cSJagpal Singh Gill     }
983cab87e9cSJagpal Singh Gill }
984cab87e9cSJagpal Singh Gill #endif
985cab87e9cSJagpal Singh Gill 
getRunningSlot()986cab87e9cSJagpal Singh Gill void ItemUpdater::getRunningSlot()
987cab87e9cSJagpal Singh Gill {
988cab87e9cSJagpal Singh Gill     // Check /run/media/slot to get the slot number
989cab87e9cSJagpal Singh Gill     constexpr auto slotFile = "/run/media/slot";
990cab87e9cSJagpal Singh Gill     std::fstream f(slotFile, std::ios_base::in);
991cab87e9cSJagpal Singh Gill     f >> runningImageSlot;
992cab87e9cSJagpal Singh Gill }
993cab87e9cSJagpal Singh Gill 
994cab87e9cSJagpal Singh Gill } // namespace updater
995cab87e9cSJagpal Singh Gill } // namespace software
996cab87e9cSJagpal Singh Gill } // namespace phosphor
997