135e83f3eSSaqib Khan #include <fstream> 2ec1b41c4SGunnar Mills #include <string> 32ce7da29SGunnar Mills #include <phosphor-logging/log.hpp> 4ec1b41c4SGunnar Mills #include "config.h" 52ce7da29SGunnar Mills #include "item_updater.hpp" 62ce7da29SGunnar Mills #include "xyz/openbmc_project/Software/Version/server.hpp" 735e83f3eSSaqib Khan #include <experimental/filesystem> 8705f1bfcSSaqib Khan #include "version.hpp" 9*5d532675SSaqib Khan #include "serialize.hpp" 10ec1b41c4SGunnar Mills 11ec1b41c4SGunnar Mills namespace phosphor 12ec1b41c4SGunnar Mills { 13ec1b41c4SGunnar Mills namespace software 14ec1b41c4SGunnar Mills { 15ec1b41c4SGunnar Mills namespace updater 16ec1b41c4SGunnar Mills { 17ec1b41c4SGunnar Mills 182ce7da29SGunnar Mills // When you see server:: you know we're referencing our base class 192ce7da29SGunnar Mills namespace server = sdbusplus::xyz::openbmc_project::Software::server; 202ce7da29SGunnar Mills 212ce7da29SGunnar Mills using namespace phosphor::logging; 2235e83f3eSSaqib Khan namespace fs = std::experimental::filesystem; 2335e83f3eSSaqib Khan 24b1cfdf99SMichael Tritz const std::vector<std::string> bmcImages = {"image-kernel", 25b1cfdf99SMichael Tritz "image-rofs", 26b1cfdf99SMichael Tritz "image-rwfs", 27b1cfdf99SMichael Tritz "image-u-boot"}; 282ce7da29SGunnar Mills 29e75d10f5SPatrick Williams void ItemUpdater::createActivation(sdbusplus::message::message& msg) 30ec1b41c4SGunnar Mills { 3184a0e693SSaqib Khan 3284a0e693SSaqib Khan using SVersion = server::Version; 3384a0e693SSaqib Khan using VersionPurpose = SVersion::VersionPurpose; 3484a0e693SSaqib Khan namespace mesg = sdbusplus::message; 3584a0e693SSaqib Khan namespace variant_ns = mesg::variant_ns; 3684a0e693SSaqib Khan 3784a0e693SSaqib Khan mesg::object_path objPath; 3884a0e693SSaqib Khan auto purpose = VersionPurpose::Unknown; 39705f1bfcSSaqib Khan std::string version; 402ce7da29SGunnar Mills std::map<std::string, 412ce7da29SGunnar Mills std::map<std::string, 4284a0e693SSaqib Khan mesg::variant<std::string>>> interfaces; 43e75d10f5SPatrick Williams msg.read(objPath, interfaces); 442ce7da29SGunnar Mills std::string path(std::move(objPath)); 4519177d3eSSaqib Khan std::string filePath; 462ce7da29SGunnar Mills 472ce7da29SGunnar Mills for (const auto& intf : interfaces) 482ce7da29SGunnar Mills { 49705f1bfcSSaqib Khan if (intf.first == VERSION_IFACE) 502ce7da29SGunnar Mills { 512ce7da29SGunnar Mills for (const auto& property : intf.second) 522ce7da29SGunnar Mills { 53705f1bfcSSaqib Khan if (property.first == "Purpose") 542ce7da29SGunnar Mills { 5584a0e693SSaqib Khan auto value = SVersion::convertVersionPurposeFromString( 5684a0e693SSaqib Khan variant_ns::get<std::string>(property.second)); 5784a0e693SSaqib Khan if (value == VersionPurpose::BMC || 5884a0e693SSaqib Khan value == VersionPurpose::System) 5984a0e693SSaqib Khan { 6084a0e693SSaqib Khan purpose = value; 6184a0e693SSaqib Khan } 62705f1bfcSSaqib Khan } 63705f1bfcSSaqib Khan else if (property.first == "Version") 64705f1bfcSSaqib Khan { 6584a0e693SSaqib Khan version = variant_ns::get<std::string>(property.second); 66705f1bfcSSaqib Khan } 67705f1bfcSSaqib Khan } 68705f1bfcSSaqib Khan } 6919177d3eSSaqib Khan else if (intf.first == FILEPATH_IFACE) 7019177d3eSSaqib Khan { 7119177d3eSSaqib Khan for (const auto& property : intf.second) 7219177d3eSSaqib Khan { 7319177d3eSSaqib Khan if (property.first == "Path") 7419177d3eSSaqib Khan { 7584a0e693SSaqib Khan filePath = variant_ns::get<std::string>(property.second); 7619177d3eSSaqib Khan } 7719177d3eSSaqib Khan } 7819177d3eSSaqib Khan } 79705f1bfcSSaqib Khan } 80705f1bfcSSaqib Khan if (version.empty() || 8119177d3eSSaqib Khan filePath.empty() || 8284a0e693SSaqib Khan purpose == VersionPurpose::Unknown) 832ce7da29SGunnar Mills { 84e75d10f5SPatrick Williams return; 852ce7da29SGunnar Mills } 862ce7da29SGunnar Mills 872ce7da29SGunnar Mills // Version id is the last item in the path 882ce7da29SGunnar Mills auto pos = path.rfind("/"); 892ce7da29SGunnar Mills if (pos == std::string::npos) 902ce7da29SGunnar Mills { 912ce7da29SGunnar Mills log<level::ERR>("No version id found in object path", 922ce7da29SGunnar Mills entry("OBJPATH=%s", path)); 93e75d10f5SPatrick Williams return; 942ce7da29SGunnar Mills } 952ce7da29SGunnar Mills 962ce7da29SGunnar Mills auto versionId = path.substr(pos + 1); 972ce7da29SGunnar Mills 98e75d10f5SPatrick Williams if (activations.find(versionId) == activations.end()) 992ce7da29SGunnar Mills { 10035e83f3eSSaqib Khan // Determine the Activation state by processing the given image dir. 10135e83f3eSSaqib Khan auto activationState = server::Activation::Activations::Invalid; 10235e83f3eSSaqib Khan ItemUpdater::ActivationStatus result = ItemUpdater:: 10319177d3eSSaqib Khan validateSquashFSImage(filePath); 10435e83f3eSSaqib Khan if (result == ItemUpdater::ActivationStatus::ready) 10535e83f3eSSaqib Khan { 10635e83f3eSSaqib Khan activationState = server::Activation::Activations::Ready; 10735e83f3eSSaqib Khan } 10835e83f3eSSaqib Khan activations.insert(std::make_pair( 1092ce7da29SGunnar Mills versionId, 110ec1b41c4SGunnar Mills std::make_unique<Activation>( 11135e83f3eSSaqib Khan bus, 11235e83f3eSSaqib Khan path, 1134c1aec09SSaqib Khan *this, 11435e83f3eSSaqib Khan versionId, 11535e83f3eSSaqib Khan activationState))); 116705f1bfcSSaqib Khan versions.insert(std::make_pair( 117705f1bfcSSaqib Khan versionId, 118705f1bfcSSaqib Khan std::make_unique<phosphor::software:: 119705f1bfcSSaqib Khan manager::Version>( 120705f1bfcSSaqib Khan bus, 121705f1bfcSSaqib Khan path, 122705f1bfcSSaqib Khan version, 123705f1bfcSSaqib Khan purpose, 1243526ef73SLeonel Gonzalez filePath, 1253526ef73SLeonel Gonzalez std::bind(&ItemUpdater::erase, 1263526ef73SLeonel Gonzalez this, 1273526ef73SLeonel Gonzalez std::placeholders::_1)))); 1282ce7da29SGunnar Mills } 1297b5010f2SSaqib Khan else 1307b5010f2SSaqib Khan { 1317b5010f2SSaqib Khan log<level::INFO>("Software Object with the same version already exists", 1327b5010f2SSaqib Khan entry("VERSION_ID=%s", versionId)); 1337b5010f2SSaqib Khan } 134e75d10f5SPatrick Williams return; 135ec1b41c4SGunnar Mills } 136ec1b41c4SGunnar Mills 137ba239881SSaqib Khan void ItemUpdater::processBMCImage() 138ba239881SSaqib Khan { 139ba239881SSaqib Khan auto purpose = server::Version::VersionPurpose::BMC; 140ba239881SSaqib Khan auto version = phosphor::software::manager::Version::getBMCVersion(); 141ba239881SSaqib Khan auto id = phosphor::software::manager::Version::getId(version); 142ba239881SSaqib Khan auto path = std::string{SOFTWARE_OBJPATH} + '/' + id; 143ba239881SSaqib Khan activations.insert(std::make_pair( 144ba239881SSaqib Khan id, 145ba239881SSaqib Khan std::make_unique<Activation>( 146ba239881SSaqib Khan bus, 147ba239881SSaqib Khan path, 1484c1aec09SSaqib Khan *this, 149ba239881SSaqib Khan id, 150ba239881SSaqib Khan server::Activation::Activations::Active))); 151ba239881SSaqib Khan versions.insert(std::make_pair( 152ba239881SSaqib Khan id, 153ba239881SSaqib Khan std::make_unique<phosphor::software:: 154ba239881SSaqib Khan manager::Version>( 155ba239881SSaqib Khan bus, 156ba239881SSaqib Khan path, 157ba239881SSaqib Khan version, 158ba239881SSaqib Khan purpose, 1593526ef73SLeonel Gonzalez "", 1603526ef73SLeonel Gonzalez std::bind(&ItemUpdater::erase, 1613526ef73SLeonel Gonzalez this, 1623526ef73SLeonel Gonzalez std::placeholders::_1)))); 1633526ef73SLeonel Gonzalez 164ba239881SSaqib Khan return; 165ba239881SSaqib Khan } 166ba239881SSaqib Khan 1673526ef73SLeonel Gonzalez void ItemUpdater::erase(std::string entryId) 1683526ef73SLeonel Gonzalez { 1693526ef73SLeonel Gonzalez // Delete ReadWrite and ReadOnly partitions 1703526ef73SLeonel Gonzalez removeReadWritePartition(entryId); 1713526ef73SLeonel Gonzalez removeReadOnlyPartition(entryId); 1723526ef73SLeonel Gonzalez 1733526ef73SLeonel Gonzalez // Removing entry in versions map 1743526ef73SLeonel Gonzalez auto it = versions.find(entryId); 1753526ef73SLeonel Gonzalez if (it == versions.end()) 1763526ef73SLeonel Gonzalez { 1773526ef73SLeonel Gonzalez log<level::ERR>(("Error: Failed to find version " + entryId + \ 1783526ef73SLeonel Gonzalez " in item updater versions map." \ 1793526ef73SLeonel Gonzalez " Unable to remove.").c_str()); 1803526ef73SLeonel Gonzalez return; 1813526ef73SLeonel Gonzalez } 1823526ef73SLeonel Gonzalez this->versions.erase(entryId); 1833526ef73SLeonel Gonzalez 1843526ef73SLeonel Gonzalez // Removing entry in activations map 1853526ef73SLeonel Gonzalez auto ita = activations.find(entryId); 1863526ef73SLeonel Gonzalez if (ita == activations.end()) 1873526ef73SLeonel Gonzalez { 1883526ef73SLeonel Gonzalez log<level::ERR>(("Error: Failed to find version " + entryId + \ 1893526ef73SLeonel Gonzalez " in item updater activations map." \ 1903526ef73SLeonel Gonzalez " Unable to remove.").c_str()); 1913526ef73SLeonel Gonzalez return; 1923526ef73SLeonel Gonzalez } 1933526ef73SLeonel Gonzalez // TODO: openbmc/openbmc#1986 1943526ef73SLeonel Gonzalez // Test if this is the currently running image 1953526ef73SLeonel Gonzalez // If not, don't continue. 1963526ef73SLeonel Gonzalez 1973526ef73SLeonel Gonzalez this->activations.erase(entryId); 198*5d532675SSaqib Khan removeFile(entryId); 1993526ef73SLeonel Gonzalez } 2003526ef73SLeonel Gonzalez 20135e83f3eSSaqib Khan ItemUpdater::ActivationStatus ItemUpdater::validateSquashFSImage( 20219177d3eSSaqib Khan const std::string& filePath) 20335e83f3eSSaqib Khan { 204b1cfdf99SMichael Tritz bool invalid = false; 20535e83f3eSSaqib Khan 206b1cfdf99SMichael Tritz for (auto& bmcImage : bmcImages) 207b1cfdf99SMichael Tritz { 20819177d3eSSaqib Khan fs::path file(filePath); 20935e83f3eSSaqib Khan file /= bmcImage; 21035e83f3eSSaqib Khan std::ifstream efile(file.c_str()); 211b1cfdf99SMichael Tritz if (efile.good() != 1) 21235e83f3eSSaqib Khan { 213b1cfdf99SMichael Tritz log<level::ERR>("Failed to find the BMC image.", 214b1cfdf99SMichael Tritz entry("IMAGE=%s", bmcImage.c_str())); 215b1cfdf99SMichael Tritz invalid = true; 21635e83f3eSSaqib Khan } 217b1cfdf99SMichael Tritz } 218b1cfdf99SMichael Tritz 219b1cfdf99SMichael Tritz if (invalid) 22035e83f3eSSaqib Khan { 22135e83f3eSSaqib Khan return ItemUpdater::ActivationStatus::invalid; 22235e83f3eSSaqib Khan } 223b1cfdf99SMichael Tritz 224b1cfdf99SMichael Tritz return ItemUpdater::ActivationStatus::ready; 22535e83f3eSSaqib Khan } 22635e83f3eSSaqib Khan 2274c1aec09SSaqib Khan void ItemUpdater::freePriority(uint8_t value) 2284c1aec09SSaqib Khan { 2294c1aec09SSaqib Khan //TODO openbmc/openbmc#1896 Improve the performance of this function 2304c1aec09SSaqib Khan for (const auto& intf : activations) 2314c1aec09SSaqib Khan { 2324c1aec09SSaqib Khan if(intf.second->redundancyPriority) 2334c1aec09SSaqib Khan { 2344c1aec09SSaqib Khan if (intf.second->redundancyPriority.get()->priority() == value) 2354c1aec09SSaqib Khan { 2364c1aec09SSaqib Khan intf.second->redundancyPriority.get()->priority(value+1); 2374c1aec09SSaqib Khan } 2384c1aec09SSaqib Khan } 2394c1aec09SSaqib Khan } 2404c1aec09SSaqib Khan } 2414c1aec09SSaqib Khan 24237a59043SMichael Tritz void ItemUpdater::reset() 24337a59043SMichael Tritz { 24437a59043SMichael Tritz // Mark the read-write partition for recreation upon reboot. 24537a59043SMichael Tritz auto method = bus.new_method_call( 24637a59043SMichael Tritz SYSTEMD_BUSNAME, 24737a59043SMichael Tritz SYSTEMD_PATH, 24837a59043SMichael Tritz SYSTEMD_INTERFACE, 24937a59043SMichael Tritz "StartUnit"); 25037a59043SMichael Tritz method.append("obmc-flash-bmc-setenv@rwreset=true.service", "replace"); 25137a59043SMichael Tritz bus.call_noreply(method); 25237a59043SMichael Tritz 25337a59043SMichael Tritz log<level::INFO>("BMC factory reset will take effect upon reboot."); 25437a59043SMichael Tritz 25537a59043SMichael Tritz return; 25637a59043SMichael Tritz } 25737a59043SMichael Tritz 2583526ef73SLeonel Gonzalez void ItemUpdater::removeReadOnlyPartition(std::string versionId) 2593526ef73SLeonel Gonzalez { 2603526ef73SLeonel Gonzalez auto serviceFile = "obmc-flash-bmc-ubiro-remove@" + versionId + 2613526ef73SLeonel Gonzalez ".service"; 2623526ef73SLeonel Gonzalez 2633526ef73SLeonel Gonzalez // Remove the read-only partitions. 2643526ef73SLeonel Gonzalez auto method = bus.new_method_call( 2653526ef73SLeonel Gonzalez SYSTEMD_BUSNAME, 2663526ef73SLeonel Gonzalez SYSTEMD_PATH, 2673526ef73SLeonel Gonzalez SYSTEMD_INTERFACE, 2683526ef73SLeonel Gonzalez "StartUnit"); 2693526ef73SLeonel Gonzalez method.append(serviceFile, "replace"); 2703526ef73SLeonel Gonzalez bus.call_noreply(method); 2713526ef73SLeonel Gonzalez } 2723526ef73SLeonel Gonzalez 2733526ef73SLeonel Gonzalez void ItemUpdater::removeReadWritePartition(std::string versionId) 2743526ef73SLeonel Gonzalez { 2753526ef73SLeonel Gonzalez auto serviceFile = "obmc-flash-bmc-ubirw-remove.service"; 2763526ef73SLeonel Gonzalez 2773526ef73SLeonel Gonzalez // Remove the read-write partitions. 2783526ef73SLeonel Gonzalez auto method = bus.new_method_call( 2793526ef73SLeonel Gonzalez SYSTEMD_BUSNAME, 2803526ef73SLeonel Gonzalez SYSTEMD_PATH, 2813526ef73SLeonel Gonzalez SYSTEMD_INTERFACE, 2823526ef73SLeonel Gonzalez "StartUnit"); 2833526ef73SLeonel Gonzalez method.append(serviceFile, "replace"); 2843526ef73SLeonel Gonzalez bus.call_noreply(method); 2853526ef73SLeonel Gonzalez } 2863526ef73SLeonel Gonzalez 287ec1b41c4SGunnar Mills } // namespace updater 288ec1b41c4SGunnar Mills } // namespace software 289ec1b41c4SGunnar Mills } // namespace phosphor 290