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