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