135e83f3eSSaqib Khan #include <fstream>
2ec1b41c4SGunnar Mills #include <string>
32ce7da29SGunnar Mills #include <phosphor-logging/log.hpp>
4dcbfa04aSSaqib Khan #include <phosphor-logging/elog.hpp>
5dcbfa04aSSaqib Khan #include <elog-errors.hpp>
6dcbfa04aSSaqib Khan #include <xyz/openbmc_project/Software/Version/error.hpp>
7ec1b41c4SGunnar Mills #include "config.h"
82ce7da29SGunnar Mills #include "item_updater.hpp"
92ce7da29SGunnar Mills #include "xyz/openbmc_project/Software/Version/server.hpp"
1035e83f3eSSaqib Khan #include <experimental/filesystem>
11705f1bfcSSaqib Khan #include "version.hpp"
125d532675SSaqib Khan #include "serialize.hpp"
13ec1b41c4SGunnar Mills 
14ec1b41c4SGunnar Mills namespace phosphor
15ec1b41c4SGunnar Mills {
16ec1b41c4SGunnar Mills namespace software
17ec1b41c4SGunnar Mills {
18ec1b41c4SGunnar Mills namespace updater
19ec1b41c4SGunnar Mills {
20ec1b41c4SGunnar Mills 
212ce7da29SGunnar Mills // When you see server:: you know we're referencing our base class
222ce7da29SGunnar Mills namespace server = sdbusplus::xyz::openbmc_project::Software::server;
230129d926SMichael Tritz namespace control = sdbusplus::xyz::openbmc_project::Control::server;
242ce7da29SGunnar Mills 
252ce7da29SGunnar Mills using namespace phosphor::logging;
26dcbfa04aSSaqib Khan using namespace sdbusplus::xyz::openbmc_project::Software::Version::Error;
2735e83f3eSSaqib Khan namespace fs = std::experimental::filesystem;
2835e83f3eSSaqib Khan 
29b1cfdf99SMichael Tritz const std::vector<std::string> bmcImages = { "image-kernel",
30b1cfdf99SMichael Tritz                                              "image-rofs",
31b1cfdf99SMichael Tritz                                              "image-rwfs",
32b1cfdf99SMichael Tritz                                              "image-u-boot" };
332ce7da29SGunnar Mills 
34e75d10f5SPatrick Williams void ItemUpdater::createActivation(sdbusplus::message::message& msg)
35ec1b41c4SGunnar Mills {
3684a0e693SSaqib Khan 
3784a0e693SSaqib Khan     using SVersion = server::Version;
3884a0e693SSaqib Khan     using VersionPurpose = SVersion::VersionPurpose;
399a782243SGunnar Mills     using VersionClass = phosphor::software::manager::Version;
4084a0e693SSaqib Khan     namespace mesg = sdbusplus::message;
4184a0e693SSaqib Khan     namespace variant_ns = mesg::variant_ns;
4284a0e693SSaqib Khan 
4384a0e693SSaqib Khan     mesg::object_path objPath;
4484a0e693SSaqib Khan     auto purpose = VersionPurpose::Unknown;
45705f1bfcSSaqib Khan     std::string version;
462ce7da29SGunnar Mills     std::map<std::string,
472ce7da29SGunnar Mills              std::map<std::string,
4884a0e693SSaqib Khan                       mesg::variant<std::string>>> interfaces;
49e75d10f5SPatrick Williams     msg.read(objPath, interfaces);
502ce7da29SGunnar Mills     std::string path(std::move(objPath));
5119177d3eSSaqib Khan     std::string filePath;
522ce7da29SGunnar Mills 
532ce7da29SGunnar Mills     for (const auto& intf : interfaces)
542ce7da29SGunnar Mills     {
55705f1bfcSSaqib Khan         if (intf.first == VERSION_IFACE)
562ce7da29SGunnar Mills         {
572ce7da29SGunnar Mills             for (const auto& property : intf.second)
582ce7da29SGunnar Mills             {
59705f1bfcSSaqib Khan                 if (property.first == "Purpose")
602ce7da29SGunnar Mills                 {
6184a0e693SSaqib Khan                     auto value = SVersion::convertVersionPurposeFromString(
6284a0e693SSaqib Khan                             variant_ns::get<std::string>(property.second));
6384a0e693SSaqib Khan                     if (value == VersionPurpose::BMC ||
6484a0e693SSaqib Khan                         value == VersionPurpose::System)
6584a0e693SSaqib Khan                     {
6684a0e693SSaqib Khan                         purpose = value;
6784a0e693SSaqib Khan                     }
68705f1bfcSSaqib Khan                 }
69705f1bfcSSaqib Khan                 else if (property.first == "Version")
70705f1bfcSSaqib Khan                 {
7184a0e693SSaqib Khan                     version = variant_ns::get<std::string>(property.second);
72705f1bfcSSaqib Khan                 }
73705f1bfcSSaqib Khan             }
74705f1bfcSSaqib Khan         }
7519177d3eSSaqib Khan         else if (intf.first == FILEPATH_IFACE)
7619177d3eSSaqib Khan         {
7719177d3eSSaqib Khan             for (const auto& property : intf.second)
7819177d3eSSaqib Khan             {
7919177d3eSSaqib Khan                 if (property.first == "Path")
8019177d3eSSaqib Khan                 {
8184a0e693SSaqib Khan                     filePath = variant_ns::get<std::string>(property.second);
8219177d3eSSaqib Khan                 }
8319177d3eSSaqib Khan             }
8419177d3eSSaqib Khan         }
85705f1bfcSSaqib Khan     }
86705f1bfcSSaqib Khan     if (version.empty() ||
8719177d3eSSaqib Khan         filePath.empty() ||
8884a0e693SSaqib Khan         purpose == VersionPurpose::Unknown)
892ce7da29SGunnar Mills     {
90e75d10f5SPatrick Williams         return;
912ce7da29SGunnar Mills     }
922ce7da29SGunnar Mills 
932ce7da29SGunnar Mills     // Version id is the last item in the path
942ce7da29SGunnar Mills     auto pos = path.rfind("/");
952ce7da29SGunnar Mills     if (pos == std::string::npos)
962ce7da29SGunnar Mills     {
972ce7da29SGunnar Mills         log<level::ERR>("No version id found in object path",
982ce7da29SGunnar Mills                         entry("OBJPATH=%s", path));
99e75d10f5SPatrick Williams         return;
1002ce7da29SGunnar Mills     }
1012ce7da29SGunnar Mills 
1022ce7da29SGunnar Mills     auto versionId = path.substr(pos + 1);
1032ce7da29SGunnar Mills 
104e75d10f5SPatrick Williams     if (activations.find(versionId) == activations.end())
1052ce7da29SGunnar Mills     {
10635e83f3eSSaqib Khan         // Determine the Activation state by processing the given image dir.
10735e83f3eSSaqib Khan         auto activationState = server::Activation::Activations::Invalid;
1089a782243SGunnar Mills         ItemUpdater::ActivationStatus result =
1099a782243SGunnar Mills                 ItemUpdater::validateSquashFSImage(filePath);
11043b25cdeSGunnar Mills         AssociationList associations = {};
11143b25cdeSGunnar Mills 
11235e83f3eSSaqib Khan         if (result == ItemUpdater::ActivationStatus::ready)
11335e83f3eSSaqib Khan         {
11435e83f3eSSaqib Khan             activationState = server::Activation::Activations::Ready;
115b60add1eSGunnar Mills             // Create an association to the BMC inventory item
11643b25cdeSGunnar Mills             associations.emplace_back(std::make_tuple(
117b60add1eSGunnar Mills                                               ACTIVATION_FWD_ASSOCIATION,
118b60add1eSGunnar Mills                                               ACTIVATION_REV_ASSOCIATION,
11943b25cdeSGunnar Mills                                               bmcInventoryPath));
12043b25cdeSGunnar Mills         }
121b60add1eSGunnar Mills 
12235e83f3eSSaqib Khan         activations.insert(std::make_pair(
1232ce7da29SGunnar Mills                                versionId,
124ec1b41c4SGunnar Mills                                std::make_unique<Activation>(
12535e83f3eSSaqib Khan                                         bus,
12635e83f3eSSaqib Khan                                         path,
1274c1aec09SSaqib Khan                                         *this,
12835e83f3eSSaqib Khan                                         versionId,
129b60add1eSGunnar Mills                                         activationState,
130b60add1eSGunnar Mills                                         associations)));
131705f1bfcSSaqib Khan         versions.insert(std::make_pair(
132705f1bfcSSaqib Khan                             versionId,
1339a782243SGunnar Mills                             std::make_unique<VersionClass>(
134705f1bfcSSaqib Khan                                 bus,
135705f1bfcSSaqib Khan                                 path,
136705f1bfcSSaqib Khan                                 version,
137705f1bfcSSaqib Khan                                 purpose,
1389440f491SEddie James                                 filePath)));
1392ce7da29SGunnar Mills     }
1407b5010f2SSaqib Khan     else
1417b5010f2SSaqib Khan     {
1427b5010f2SSaqib Khan         log<level::INFO>("Software Object with the same version already exists",
1437b5010f2SSaqib Khan                          entry("VERSION_ID=%s", versionId));
1447b5010f2SSaqib Khan     }
145e75d10f5SPatrick Williams     return;
146ec1b41c4SGunnar Mills }
147ec1b41c4SGunnar Mills 
148ba239881SSaqib Khan void ItemUpdater::processBMCImage()
149ba239881SSaqib Khan {
15088e8a325SGunnar Mills     using VersionClass = phosphor::software::manager::Version;
15188e8a325SGunnar Mills     // Read os-release from /etc/ to get the functional BMC version
15288e8a325SGunnar Mills     auto functionalVersion = VersionClass::getBMCVersion(OS_RELEASE_FILE);
15388e8a325SGunnar Mills 
1541eef62deSSaqib Khan     // Read os-release from folders under /media/ to get
1551eef62deSSaqib Khan     // BMC Software Versions.
1561eef62deSSaqib Khan     for (const auto& iter : fs::directory_iterator(MEDIA_DIR))
1571eef62deSSaqib Khan     {
1581eef62deSSaqib Khan         auto activationState = server::Activation::Activations::Active;
1596fab70daSSaqib Khan         static const auto BMC_RO_PREFIX_LEN = strlen(BMC_ROFS_PREFIX);
1601eef62deSSaqib Khan 
1611eef62deSSaqib Khan         // Check if the BMC_RO_PREFIXis the prefix of the iter.path
1621eef62deSSaqib Khan         if (0 == iter.path().native().compare(0, BMC_RO_PREFIX_LEN,
1636fab70daSSaqib Khan                                               BMC_ROFS_PREFIX))
1641eef62deSSaqib Khan         {
165021c365bSSaqib Khan             // The versionId is extracted from the path
166021c365bSSaqib Khan             // for example /media/ro-2a1022fe.
167021c365bSSaqib Khan             auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN);
1681eef62deSSaqib Khan             auto osRelease = iter.path() / OS_RELEASE_FILE;
1691eef62deSSaqib Khan             if (!fs::is_regular_file(osRelease))
1701eef62deSSaqib Khan             {
1711eef62deSSaqib Khan                 log<level::ERR>("Failed to read osRelease\n",
1721eef62deSSaqib Khan                                 entry("FileName=%s", osRelease.string()));
173021c365bSSaqib Khan                 ItemUpdater::erase(id);
174021c365bSSaqib Khan                 continue;
1751eef62deSSaqib Khan             }
17688e8a325SGunnar Mills             auto version = VersionClass::getBMCVersion(osRelease);
1771eef62deSSaqib Khan             if (version.empty())
1781eef62deSSaqib Khan             {
1791eef62deSSaqib Khan                 log<level::ERR>("Failed to read version from osRelease",
1801eef62deSSaqib Khan                                 entry("FILENAME=%s", osRelease.string()));
1811eef62deSSaqib Khan                 activationState = server::Activation::Activations::Invalid;
1821eef62deSSaqib Khan             }
183021c365bSSaqib Khan 
1841eef62deSSaqib Khan             auto purpose = server::Version::VersionPurpose::BMC;
1851eef62deSSaqib Khan             auto path = fs::path(SOFTWARE_OBJPATH) / id;
1861eef62deSSaqib Khan 
18788e8a325SGunnar Mills             // Create functional association if this is the functional version
18888e8a325SGunnar Mills             if (version.compare(functionalVersion) == 0)
18988e8a325SGunnar Mills             {
19088e8a325SGunnar Mills                 createFunctionalAssociation(path);
19188e8a325SGunnar Mills             }
19288e8a325SGunnar Mills 
19343b25cdeSGunnar Mills             AssociationList associations = {};
19443b25cdeSGunnar Mills 
19543b25cdeSGunnar Mills             if (activationState == server::Activation::Activations::Active)
19643b25cdeSGunnar Mills             {
19743b25cdeSGunnar Mills                 // Create an association to the BMC inventory item
19843b25cdeSGunnar Mills                 associations.emplace_back(std::make_tuple(
19943b25cdeSGunnar Mills                                                   ACTIVATION_FWD_ASSOCIATION,
20043b25cdeSGunnar Mills                                                   ACTIVATION_REV_ASSOCIATION,
20143b25cdeSGunnar Mills                                                   bmcInventoryPath));
20243b25cdeSGunnar Mills 
20343b25cdeSGunnar Mills                 // Create an active association since this image is active
20443b25cdeSGunnar Mills                 createActiveAssociation(path);
20543b25cdeSGunnar Mills             }
20643b25cdeSGunnar Mills 
207ee590c74SAdriana Kobylak             // Create Version instance for this version.
208ee590c74SAdriana Kobylak             auto versionPtr = std::make_unique<VersionClass>(
209ee590c74SAdriana Kobylak                             bus,
210ee590c74SAdriana Kobylak                             path,
211ee590c74SAdriana Kobylak                             version,
212ee590c74SAdriana Kobylak                             purpose,
213ee590c74SAdriana Kobylak                             "");
214ee590c74SAdriana Kobylak             auto isVersionFunctional = versionPtr->isFunctional();
215ee590c74SAdriana Kobylak             versions.insert(std::make_pair(
216ee590c74SAdriana Kobylak                                 id,
217ee590c74SAdriana Kobylak                                 std::move(versionPtr)));
218ee590c74SAdriana Kobylak 
2191eef62deSSaqib Khan             // Create Activation instance for this version.
220ba239881SSaqib Khan             activations.insert(std::make_pair(
221ba239881SSaqib Khan                                    id,
222ba239881SSaqib Khan                                    std::make_unique<Activation>(
223ba239881SSaqib Khan                                        bus,
224ba239881SSaqib Khan                                        path,
2254c1aec09SSaqib Khan                                        *this,
226ba239881SSaqib Khan                                        id,
227b60add1eSGunnar Mills                                        server::Activation::Activations::Active,
228b60add1eSGunnar Mills                                        associations)));
2291eef62deSSaqib Khan 
2301eef62deSSaqib Khan             // If Active, create RedundancyPriority instance for this version.
2311eef62deSSaqib Khan             if (activationState == server::Activation::Activations::Active)
2321eef62deSSaqib Khan             {
2331eef62deSSaqib Khan                 uint8_t priority = std::numeric_limits<uint8_t>::max();
2341eef62deSSaqib Khan                 if (!restoreFromFile(id, priority))
2351eef62deSSaqib Khan                 {
236ee590c74SAdriana Kobylak                     if (isVersionFunctional)
237ee590c74SAdriana Kobylak                     {
238ee590c74SAdriana Kobylak                         priority = 0;
239ee590c74SAdriana Kobylak                     }
240ee590c74SAdriana Kobylak                     else
241ee590c74SAdriana Kobylak                     {
2421eef62deSSaqib Khan                         log<level::ERR>("Unable to restore priority from file.",
2431eef62deSSaqib Khan                                 entry("VERSIONID=%s", id));
2441eef62deSSaqib Khan                     }
245ee590c74SAdriana Kobylak                 }
2461eef62deSSaqib Khan                 activations.find(id)->second->redundancyPriority =
2471eef62deSSaqib Khan                         std::make_unique<RedundancyPriority>(
2481eef62deSSaqib Khan                              bus,
2491eef62deSSaqib Khan                              path,
2501eef62deSSaqib Khan                              *(activations.find(id)->second),
2511eef62deSSaqib Khan                              priority);
2521eef62deSSaqib Khan             }
2531eef62deSSaqib Khan         }
2541eef62deSSaqib Khan     }
255dcbfa04aSSaqib Khan 
256dcbfa04aSSaqib Khan     // If there is no ubi volume for bmc version then read the /etc/os-release
257dcbfa04aSSaqib Khan     // and create rofs-<versionId> under /media
258dcbfa04aSSaqib Khan     if (activations.size() == 0)
259dcbfa04aSSaqib Khan     {
260*d16bcbd5SGunnar Mills         auto version = VersionClass::getBMCVersion(OS_RELEASE_FILE);
261dcbfa04aSSaqib Khan         auto id = phosphor::software::manager::Version::getId(version);
262dcbfa04aSSaqib Khan         auto versionFileDir = BMC_ROFS_PREFIX + id + "/etc/";
263dcbfa04aSSaqib Khan         try
264dcbfa04aSSaqib Khan         {
265dcbfa04aSSaqib Khan             if (!fs::is_directory(versionFileDir))
266dcbfa04aSSaqib Khan             {
267dcbfa04aSSaqib Khan                 fs::create_directories(versionFileDir);
268dcbfa04aSSaqib Khan             }
269dcbfa04aSSaqib Khan             auto versionFilePath = BMC_ROFS_PREFIX + id + OS_RELEASE_FILE;
270dcbfa04aSSaqib Khan             fs::create_directory_symlink(OS_RELEASE_FILE, versionFilePath);
271dcbfa04aSSaqib Khan             ItemUpdater::processBMCImage();
272dcbfa04aSSaqib Khan         }
273dcbfa04aSSaqib Khan         catch (const std::exception& e)
274dcbfa04aSSaqib Khan         {
275dcbfa04aSSaqib Khan             log<level::ERR>(e.what());
276dcbfa04aSSaqib Khan         }
277dcbfa04aSSaqib Khan     }
278ba239881SSaqib Khan     return;
279ba239881SSaqib Khan }
280ba239881SSaqib Khan 
2813526ef73SLeonel Gonzalez void ItemUpdater::erase(std::string entryId)
2823526ef73SLeonel Gonzalez {
2836d873715SEddie James     // Find entry in versions map
2846d873715SEddie James     auto it = versions.find(entryId);
2856d873715SEddie James     if (it != versions.end())
2866d873715SEddie James     {
2876d873715SEddie James         if (it->second->isFunctional())
2886d873715SEddie James         {
2896d873715SEddie James             log<level::ERR>(("Error: Version " + entryId + \
2906d873715SEddie James                              " is currently running on the BMC." \
2916d873715SEddie James                              " Unable to remove.").c_str());
2926d873715SEddie James             return;
2936d873715SEddie James         }
2946d873715SEddie James 
2956d873715SEddie James         // Delete ReadOnly partitions if it's not active
2963526ef73SLeonel Gonzalez         removeReadOnlyPartition(entryId);
2971eef62deSSaqib Khan         removeFile(entryId);
2986d873715SEddie James     }
2996d873715SEddie James     else
3006d873715SEddie James     {
3016d873715SEddie James         // Delete ReadOnly partitions even if we can't find the version
3026d873715SEddie James         removeReadOnlyPartition(entryId);
3036d873715SEddie James         removeFile(entryId);
3046d873715SEddie James 
3056d873715SEddie James         log<level::ERR>(("Error: Failed to find version " + entryId + \
3066d873715SEddie James                          " in item updater versions map." \
3076d873715SEddie James                          " Unable to remove.").c_str());
3086d873715SEddie James         return;
3096d873715SEddie James     }
3101eef62deSSaqib Khan 
3111eef62deSSaqib Khan     // Remove the priority environment variable.
3121eef62deSSaqib Khan     auto serviceFile = "obmc-flash-bmc-setenv@" + entryId + ".service";
3131eef62deSSaqib Khan     auto method = bus.new_method_call(
3141eef62deSSaqib Khan             SYSTEMD_BUSNAME,
3151eef62deSSaqib Khan             SYSTEMD_PATH,
3161eef62deSSaqib Khan             SYSTEMD_INTERFACE,
3171eef62deSSaqib Khan             "StartUnit");
3181eef62deSSaqib Khan     method.append(serviceFile, "replace");
3191eef62deSSaqib Khan     bus.call_noreply(method);
3203526ef73SLeonel Gonzalez 
3213526ef73SLeonel Gonzalez     // Removing entry in versions map
3223526ef73SLeonel Gonzalez     this->versions.erase(entryId);
3233526ef73SLeonel Gonzalez 
3243526ef73SLeonel Gonzalez     // Removing entry in activations map
3253526ef73SLeonel Gonzalez     auto ita = activations.find(entryId);
3263526ef73SLeonel Gonzalez     if (ita == activations.end())
3273526ef73SLeonel Gonzalez     {
3283526ef73SLeonel Gonzalez         log<level::ERR>(("Error: Failed to find version " + entryId + \
3293526ef73SLeonel Gonzalez                          " in item updater activations map." \
3303526ef73SLeonel Gonzalez                          " Unable to remove.").c_str());
3313526ef73SLeonel Gonzalez         return;
3323526ef73SLeonel Gonzalez     }
3333526ef73SLeonel Gonzalez 
3343526ef73SLeonel Gonzalez     this->activations.erase(entryId);
3353526ef73SLeonel Gonzalez }
3363526ef73SLeonel Gonzalez 
337bc1bf3afSMichael Tritz void ItemUpdater::deleteAll()
338bc1bf3afSMichael Tritz {
339bc1bf3afSMichael Tritz     std::vector<std::string> deletableVersions;
340bc1bf3afSMichael Tritz 
341bc1bf3afSMichael Tritz     for (const auto& versionIt : versions)
342bc1bf3afSMichael Tritz     {
343bc1bf3afSMichael Tritz         if (!versionIt.second->isFunctional())
344bc1bf3afSMichael Tritz         {
345bc1bf3afSMichael Tritz             deletableVersions.push_back(versionIt.first);
346bc1bf3afSMichael Tritz         }
347bc1bf3afSMichael Tritz     }
348bc1bf3afSMichael Tritz 
349bc1bf3afSMichael Tritz     for (const auto& deletableIt : deletableVersions)
350bc1bf3afSMichael Tritz     {
351bc1bf3afSMichael Tritz         ItemUpdater::erase(deletableIt);
352bc1bf3afSMichael Tritz     }
353bc1bf3afSMichael Tritz 
354bc1bf3afSMichael Tritz     // Remove any volumes that do not match current versions.
355bc1bf3afSMichael Tritz     auto method = bus.new_method_call(
356bc1bf3afSMichael Tritz             SYSTEMD_BUSNAME,
357bc1bf3afSMichael Tritz             SYSTEMD_PATH,
358bc1bf3afSMichael Tritz             SYSTEMD_INTERFACE,
359bc1bf3afSMichael Tritz             "StartUnit");
360bc1bf3afSMichael Tritz     method.append("obmc-flash-bmc-cleanup.service", "replace");
361bc1bf3afSMichael Tritz     bus.call_noreply(method);
362bc1bf3afSMichael Tritz }
363bc1bf3afSMichael Tritz 
36435e83f3eSSaqib Khan ItemUpdater::ActivationStatus ItemUpdater::validateSquashFSImage(
36519177d3eSSaqib Khan         const std::string& filePath)
36635e83f3eSSaqib Khan {
367b1cfdf99SMichael Tritz     bool invalid = false;
36835e83f3eSSaqib Khan 
369b1cfdf99SMichael Tritz     for (auto& bmcImage : bmcImages)
370b1cfdf99SMichael Tritz     {
37119177d3eSSaqib Khan         fs::path file(filePath);
37235e83f3eSSaqib Khan         file /= bmcImage;
37335e83f3eSSaqib Khan         std::ifstream efile(file.c_str());
374b1cfdf99SMichael Tritz         if (efile.good() != 1)
37535e83f3eSSaqib Khan         {
376b1cfdf99SMichael Tritz             log<level::ERR>("Failed to find the BMC image.",
377b1cfdf99SMichael Tritz                             entry("IMAGE=%s", bmcImage.c_str()));
378b1cfdf99SMichael Tritz             invalid = true;
37935e83f3eSSaqib Khan         }
380b1cfdf99SMichael Tritz     }
381b1cfdf99SMichael Tritz 
382b1cfdf99SMichael Tritz     if (invalid)
38335e83f3eSSaqib Khan     {
38435e83f3eSSaqib Khan         return ItemUpdater::ActivationStatus::invalid;
38535e83f3eSSaqib Khan     }
386b1cfdf99SMichael Tritz 
387b1cfdf99SMichael Tritz     return ItemUpdater::ActivationStatus::ready;
38835e83f3eSSaqib Khan }
38935e83f3eSSaqib Khan 
390b9da6634SSaqib Khan void ItemUpdater::freePriority(uint8_t value, const std::string& versionId)
3914c1aec09SSaqib Khan {
3924c1aec09SSaqib Khan     //TODO openbmc/openbmc#1896 Improve the performance of this function
3934c1aec09SSaqib Khan     for (const auto& intf : activations)
3944c1aec09SSaqib Khan     {
3954c1aec09SSaqib Khan         if (intf.second->redundancyPriority)
3964c1aec09SSaqib Khan         {
397b9da6634SSaqib Khan             if (intf.second->redundancyPriority.get()->priority() == value &&
398b9da6634SSaqib Khan                 intf.second->versionId != versionId)
3994c1aec09SSaqib Khan             {
4004c1aec09SSaqib Khan                 intf.second->redundancyPriority.get()->priority(value + 1);
4014c1aec09SSaqib Khan             }
4024c1aec09SSaqib Khan         }
4034c1aec09SSaqib Khan     }
4044c1aec09SSaqib Khan }
4054c1aec09SSaqib Khan 
40637a59043SMichael Tritz void ItemUpdater::reset()
40737a59043SMichael Tritz {
40837a59043SMichael Tritz     // Mark the read-write partition for recreation upon reboot.
40937a59043SMichael Tritz     auto method = bus.new_method_call(
41037a59043SMichael Tritz             SYSTEMD_BUSNAME,
41137a59043SMichael Tritz             SYSTEMD_PATH,
41237a59043SMichael Tritz             SYSTEMD_INTERFACE,
41337a59043SMichael Tritz             "StartUnit");
4140129d926SMichael Tritz     method.append("obmc-flash-bmc-setenv@rwreset\\x3dtrue.service", "replace");
41537a59043SMichael Tritz     bus.call_noreply(method);
41637a59043SMichael Tritz 
41737a59043SMichael Tritz     log<level::INFO>("BMC factory reset will take effect upon reboot.");
41837a59043SMichael Tritz 
41937a59043SMichael Tritz     return;
42037a59043SMichael Tritz }
42137a59043SMichael Tritz 
4223526ef73SLeonel Gonzalez void ItemUpdater::removeReadOnlyPartition(std::string versionId)
4233526ef73SLeonel Gonzalez {
4243526ef73SLeonel Gonzalez     auto serviceFile = "obmc-flash-bmc-ubiro-remove@" + versionId +
4253526ef73SLeonel Gonzalez             ".service";
4263526ef73SLeonel Gonzalez 
4273526ef73SLeonel Gonzalez     // Remove the read-only partitions.
4283526ef73SLeonel Gonzalez     auto method = bus.new_method_call(
4293526ef73SLeonel Gonzalez             SYSTEMD_BUSNAME,
4303526ef73SLeonel Gonzalez             SYSTEMD_PATH,
4313526ef73SLeonel Gonzalez             SYSTEMD_INTERFACE,
4323526ef73SLeonel Gonzalez             "StartUnit");
4333526ef73SLeonel Gonzalez     method.append(serviceFile, "replace");
4343526ef73SLeonel Gonzalez     bus.call_noreply(method);
4353526ef73SLeonel Gonzalez }
4363526ef73SLeonel Gonzalez 
4370129d926SMichael Tritz bool ItemUpdater::fieldModeEnabled(bool value)
4380129d926SMichael Tritz {
4390129d926SMichael Tritz     // enabling field mode is intended to be one way: false -> true
4400129d926SMichael Tritz     if (value && !control::FieldMode::fieldModeEnabled())
4410129d926SMichael Tritz     {
4420129d926SMichael Tritz         control::FieldMode::fieldModeEnabled(value);
4430129d926SMichael Tritz 
4440129d926SMichael Tritz         auto method = bus.new_method_call(
4450129d926SMichael Tritz                 SYSTEMD_BUSNAME,
4460129d926SMichael Tritz                 SYSTEMD_PATH,
4470129d926SMichael Tritz                 SYSTEMD_INTERFACE,
4480129d926SMichael Tritz                 "StartUnit");
4490129d926SMichael Tritz         method.append("obmc-flash-bmc-setenv@fieldmode\\x3dtrue.service",
4500129d926SMichael Tritz                       "replace");
4510129d926SMichael Tritz         bus.call_noreply(method);
4520129d926SMichael Tritz 
4530129d926SMichael Tritz         method = bus.new_method_call(
4540129d926SMichael Tritz                 SYSTEMD_BUSNAME,
4550129d926SMichael Tritz                 SYSTEMD_PATH,
4560129d926SMichael Tritz                 SYSTEMD_INTERFACE,
4570129d926SMichael Tritz                 "StopUnit");
4580129d926SMichael Tritz         method.append("usr-local.mount", "replace");
4590129d926SMichael Tritz         bus.call_noreply(method);
4600129d926SMichael Tritz 
4610129d926SMichael Tritz         std::vector<std::string> usrLocal = {"usr-local.mount"};
4620129d926SMichael Tritz 
4630129d926SMichael Tritz         method = bus.new_method_call(
4640129d926SMichael Tritz                 SYSTEMD_BUSNAME,
4650129d926SMichael Tritz                 SYSTEMD_PATH,
4660129d926SMichael Tritz                 SYSTEMD_INTERFACE,
4670129d926SMichael Tritz                 "MaskUnitFiles");
4680129d926SMichael Tritz         method.append(usrLocal, false, true);
4690129d926SMichael Tritz         bus.call_noreply(method);
4700129d926SMichael Tritz     }
4710129d926SMichael Tritz 
4720129d926SMichael Tritz     return control::FieldMode::fieldModeEnabled();
4730129d926SMichael Tritz }
4740129d926SMichael Tritz 
4750129d926SMichael Tritz void ItemUpdater::restoreFieldModeStatus()
4760129d926SMichael Tritz {
4770129d926SMichael Tritz     std::ifstream input("/run/fw_env");
4780129d926SMichael Tritz     std::string envVar;
4790129d926SMichael Tritz     std::getline(input, envVar);
4800129d926SMichael Tritz 
4810129d926SMichael Tritz     if (envVar.find("fieldmode=true") != std::string::npos)
4820129d926SMichael Tritz     {
4830129d926SMichael Tritz         ItemUpdater::fieldModeEnabled(true);
4840129d926SMichael Tritz     }
4850129d926SMichael Tritz }
4860129d926SMichael Tritz 
487b60add1eSGunnar Mills void ItemUpdater::setBMCInventoryPath()
488b60add1eSGunnar Mills {
489b60add1eSGunnar Mills     //TODO: openbmc/openbmc#1786 - Get the BMC path by looking for objects
490b60add1eSGunnar Mills     //      that implement the BMC inventory interface
491b60add1eSGunnar Mills     auto depth = 0;
492b60add1eSGunnar Mills     auto mapperCall = bus.new_method_call(MAPPER_BUSNAME,
493b60add1eSGunnar Mills                                           MAPPER_PATH,
494b60add1eSGunnar Mills                                           MAPPER_INTERFACE,
495b60add1eSGunnar Mills                                           "GetSubTreePaths");
496b60add1eSGunnar Mills 
497b60add1eSGunnar Mills     mapperCall.append(CHASSIS_INVENTORY_PATH);
498b60add1eSGunnar Mills     mapperCall.append(depth);
499b60add1eSGunnar Mills 
500b60add1eSGunnar Mills     // TODO: openbmc/openbmc#2226 - Add Inventory Item filter when
501b60add1eSGunnar Mills     //       mapper is fixed.
502b60add1eSGunnar Mills     std::vector<std::string> filter = {};
503b60add1eSGunnar Mills     mapperCall.append(filter);
504b60add1eSGunnar Mills 
505b60add1eSGunnar Mills     auto response = bus.call(mapperCall);
506b60add1eSGunnar Mills     if (response.is_method_error())
507b60add1eSGunnar Mills     {
508b60add1eSGunnar Mills         log<level::ERR>("Error in mapper GetSubTreePath");
509b60add1eSGunnar Mills         return;
510b60add1eSGunnar Mills     }
511b60add1eSGunnar Mills 
512b60add1eSGunnar Mills     using ObjectPaths = std::vector<std::string>;
513b60add1eSGunnar Mills     ObjectPaths result;
514b60add1eSGunnar Mills     response.read(result);
515b60add1eSGunnar Mills 
516b60add1eSGunnar Mills     if (result.empty())
517b60add1eSGunnar Mills     {
518b60add1eSGunnar Mills         log<level::ERR>("Invalid response from mapper");
519b60add1eSGunnar Mills         return;
520b60add1eSGunnar Mills     }
521b60add1eSGunnar Mills 
522b60add1eSGunnar Mills     for (auto& iter : result)
523b60add1eSGunnar Mills     {
524b60add1eSGunnar Mills         const auto& path = iter;
525b60add1eSGunnar Mills         if (path.substr(path.find_last_of('/') + 1).compare("bmc") == 0)
526b60add1eSGunnar Mills         {
527b60add1eSGunnar Mills             bmcInventoryPath = path;
528b60add1eSGunnar Mills             return;
529b60add1eSGunnar Mills         }
530b60add1eSGunnar Mills     }
531b60add1eSGunnar Mills }
532b60add1eSGunnar Mills 
533f10b2326SGunnar Mills void ItemUpdater::createActiveAssociation(const std::string& path)
534ded875dcSGunnar Mills {
535ded875dcSGunnar Mills     assocs.emplace_back(std::make_tuple(ACTIVE_FWD_ASSOCIATION,
536ded875dcSGunnar Mills                                         ACTIVE_REV_ASSOCIATION,
537ded875dcSGunnar Mills                                         path));
538ded875dcSGunnar Mills     associations(assocs);
539ded875dcSGunnar Mills }
540ded875dcSGunnar Mills 
54188e8a325SGunnar Mills void ItemUpdater::createFunctionalAssociation(const std::string& path)
54288e8a325SGunnar Mills {
54388e8a325SGunnar Mills     assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION,
54488e8a325SGunnar Mills                                         FUNCTIONAL_REV_ASSOCIATION,
54588e8a325SGunnar Mills                                         path));
54688e8a325SGunnar Mills     associations(assocs);
54788e8a325SGunnar Mills }
54888e8a325SGunnar Mills 
549f10b2326SGunnar Mills void ItemUpdater::removeActiveAssociation(const std::string& path)
550ded875dcSGunnar Mills {
551ded875dcSGunnar Mills     for (auto iter = assocs.begin(); iter != assocs.end();)
552ded875dcSGunnar Mills     {
55388e8a325SGunnar Mills         // Since there could be multiple associations to the same path,
55488e8a325SGunnar Mills         // only remove ones that have an active forward association.
55588e8a325SGunnar Mills         if ((std::get<0>(*iter)).compare(ACTIVE_FWD_ASSOCIATION) == 0 &&
55688e8a325SGunnar Mills             (std::get<2>(*iter)).compare(path) == 0)
557ded875dcSGunnar Mills         {
558ded875dcSGunnar Mills             iter = assocs.erase(iter);
559ded875dcSGunnar Mills             associations(assocs);
560ded875dcSGunnar Mills         }
561ded875dcSGunnar Mills         else
562ded875dcSGunnar Mills         {
563ded875dcSGunnar Mills             ++iter;
564ded875dcSGunnar Mills         }
565ded875dcSGunnar Mills     }
566ded875dcSGunnar Mills }
567ded875dcSGunnar Mills 
568b9da6634SSaqib Khan bool ItemUpdater::isLowestPriority(uint8_t value)
569b9da6634SSaqib Khan {
570b9da6634SSaqib Khan     for (const auto& intf : activations)
571b9da6634SSaqib Khan     {
572b9da6634SSaqib Khan         if (intf.second->redundancyPriority)
573b9da6634SSaqib Khan         {
574b9da6634SSaqib Khan             if (intf.second->redundancyPriority.get()->priority() < value)
575b9da6634SSaqib Khan             {
576b9da6634SSaqib Khan                 return false;
577b9da6634SSaqib Khan             }
578b9da6634SSaqib Khan         }
579b9da6634SSaqib Khan     }
580b9da6634SSaqib Khan     return true;
581b9da6634SSaqib Khan }
582b9da6634SSaqib Khan 
583ec1b41c4SGunnar Mills } // namespace updater
584ec1b41c4SGunnar Mills } // namespace software
585ec1b41c4SGunnar Mills } // namespace phosphor
586