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