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" 9ec1b41c4SGunnar Mills 10ec1b41c4SGunnar Mills namespace phosphor 11ec1b41c4SGunnar Mills { 12ec1b41c4SGunnar Mills namespace software 13ec1b41c4SGunnar Mills { 14ec1b41c4SGunnar Mills namespace updater 15ec1b41c4SGunnar Mills { 16ec1b41c4SGunnar Mills 172ce7da29SGunnar Mills // When you see server:: you know we're referencing our base class 182ce7da29SGunnar Mills namespace server = sdbusplus::xyz::openbmc_project::Software::server; 192ce7da29SGunnar Mills 202ce7da29SGunnar Mills using namespace phosphor::logging; 2135e83f3eSSaqib Khan namespace fs = std::experimental::filesystem; 2235e83f3eSSaqib Khan 2335e83f3eSSaqib Khan constexpr auto bmcImage = "image-rofs"; 242ce7da29SGunnar Mills 25*37a59043SMichael Tritz constexpr auto SYSTEMD_BUSNAME = "org.freedesktop.systemd1"; 26*37a59043SMichael Tritz constexpr auto SYSTEMD_PATH = "/org/freedesktop/systemd1"; 27*37a59043SMichael Tritz constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager"; 28*37a59043SMichael Tritz 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, 12419177d3eSSaqib Khan filePath))); 1252ce7da29SGunnar Mills } 126e75d10f5SPatrick Williams return; 127ec1b41c4SGunnar Mills } 128ec1b41c4SGunnar Mills 129ba239881SSaqib Khan void ItemUpdater::processBMCImage() 130ba239881SSaqib Khan { 131ba239881SSaqib Khan auto purpose = server::Version::VersionPurpose::BMC; 132ba239881SSaqib Khan auto version = phosphor::software::manager::Version::getBMCVersion(); 133ba239881SSaqib Khan auto id = phosphor::software::manager::Version::getId(version); 134ba239881SSaqib Khan auto path = std::string{SOFTWARE_OBJPATH} + '/' + id; 135ba239881SSaqib Khan activations.insert(std::make_pair( 136ba239881SSaqib Khan id, 137ba239881SSaqib Khan std::make_unique<Activation>( 138ba239881SSaqib Khan bus, 139ba239881SSaqib Khan path, 1404c1aec09SSaqib Khan *this, 141ba239881SSaqib Khan id, 142ba239881SSaqib Khan server::Activation::Activations::Active))); 143ba239881SSaqib Khan versions.insert(std::make_pair( 144ba239881SSaqib Khan id, 145ba239881SSaqib Khan std::make_unique<phosphor::software:: 146ba239881SSaqib Khan manager::Version>( 147ba239881SSaqib Khan bus, 148ba239881SSaqib Khan path, 149ba239881SSaqib Khan version, 150ba239881SSaqib Khan purpose, 151ba239881SSaqib Khan ""))); 152ba239881SSaqib Khan return; 153ba239881SSaqib Khan } 154ba239881SSaqib Khan 15535e83f3eSSaqib Khan ItemUpdater::ActivationStatus ItemUpdater::validateSquashFSImage( 15619177d3eSSaqib Khan const std::string& filePath) 15735e83f3eSSaqib Khan { 15835e83f3eSSaqib Khan 15919177d3eSSaqib Khan fs::path file(filePath); 16035e83f3eSSaqib Khan file /= bmcImage; 16135e83f3eSSaqib Khan std::ifstream efile(file.c_str()); 16235e83f3eSSaqib Khan 16335e83f3eSSaqib Khan if (efile.good() == 1) 16435e83f3eSSaqib Khan { 16535e83f3eSSaqib Khan return ItemUpdater::ActivationStatus::ready; 16635e83f3eSSaqib Khan } 16735e83f3eSSaqib Khan else 16835e83f3eSSaqib Khan { 16919177d3eSSaqib Khan log<level::ERR>("Failed to find the BMC image."); 17035e83f3eSSaqib Khan return ItemUpdater::ActivationStatus::invalid; 17135e83f3eSSaqib Khan } 17235e83f3eSSaqib Khan } 17335e83f3eSSaqib Khan 1744c1aec09SSaqib Khan void ItemUpdater::freePriority(uint8_t value) 1754c1aec09SSaqib Khan { 1764c1aec09SSaqib Khan //TODO openbmc/openbmc#1896 Improve the performance of this function 1774c1aec09SSaqib Khan for (const auto& intf : activations) 1784c1aec09SSaqib Khan { 1794c1aec09SSaqib Khan if(intf.second->redundancyPriority) 1804c1aec09SSaqib Khan { 1814c1aec09SSaqib Khan if (intf.second->redundancyPriority.get()->priority() == value) 1824c1aec09SSaqib Khan { 1834c1aec09SSaqib Khan intf.second->redundancyPriority.get()->priority(value+1); 1844c1aec09SSaqib Khan } 1854c1aec09SSaqib Khan } 1864c1aec09SSaqib Khan } 1874c1aec09SSaqib Khan } 1884c1aec09SSaqib Khan 189*37a59043SMichael Tritz void ItemUpdater::reset() 190*37a59043SMichael Tritz { 191*37a59043SMichael Tritz // Mark the read-write partition for recreation upon reboot. 192*37a59043SMichael Tritz auto method = bus.new_method_call( 193*37a59043SMichael Tritz SYSTEMD_BUSNAME, 194*37a59043SMichael Tritz SYSTEMD_PATH, 195*37a59043SMichael Tritz SYSTEMD_INTERFACE, 196*37a59043SMichael Tritz "StartUnit"); 197*37a59043SMichael Tritz method.append("obmc-flash-bmc-setenv@rwreset=true.service", "replace"); 198*37a59043SMichael Tritz bus.call_noreply(method); 199*37a59043SMichael Tritz 200*37a59043SMichael Tritz log<level::INFO>("BMC factory reset will take effect upon reboot."); 201*37a59043SMichael Tritz 202*37a59043SMichael Tritz return; 203*37a59043SMichael Tritz } 204*37a59043SMichael Tritz 205ec1b41c4SGunnar Mills } // namespace updater 206ec1b41c4SGunnar Mills } // namespace software 207ec1b41c4SGunnar Mills } // namespace phosphor 208