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