1692b555eSAdriana Kobylak #include "config.h"
2f6ed5897SGunnar Mills 
3f6ed5897SGunnar Mills #include "activation.hpp"
4f6ed5897SGunnar Mills 
581bac88cSSaqib Khan #include "item_updater.hpp"
6f6ed5897SGunnar Mills 
74d3d9126SJayashankar Padath #include <phosphor-logging/elog-errors.hpp>
84d3d9126SJayashankar Padath #include <phosphor-logging/elog.hpp>
97f80e0b5SSaqib Khan #include <phosphor-logging/log.hpp>
1074b657e8SGunnar Mills #include <sdbusplus/exception.hpp>
114d3d9126SJayashankar Padath #include <sdbusplus/server.hpp>
124d3d9126SJayashankar Padath #include <xyz/openbmc_project/Common/error.hpp>
13befe5ce4SAdriana Kobylak 
149f44c99aSBrad Bishop #include <filesystem>
158facccfaSBrad Bishop 
164016e526SJayanth Othayoth #ifdef WANT_SIGNATURE_VERIFY
174016e526SJayanth Othayoth #include "image_verify.hpp"
184016e526SJayanth Othayoth #endif
194016e526SJayanth Othayoth 
20befe5ce4SAdriana Kobylak namespace openpower
21befe5ce4SAdriana Kobylak {
22befe5ce4SAdriana Kobylak namespace software
23befe5ce4SAdriana Kobylak {
24befe5ce4SAdriana Kobylak namespace updater
25befe5ce4SAdriana Kobylak {
26befe5ce4SAdriana Kobylak 
2799c8c0e9SAdriana Kobylak namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server;
2899c8c0e9SAdriana Kobylak 
297f80e0b5SSaqib Khan using namespace phosphor::logging;
304016e526SJayanth Othayoth using InternalFailure =
314016e526SJayanth Othayoth     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
3211271fb7SJayanth Othayoth 
334d3d9126SJayashankar Padath #ifdef WANT_SIGNATURE_VERIFY
3411271fb7SJayanth Othayoth // Field mode path and interface.
3511271fb7SJayanth Othayoth constexpr auto FIELDMODE_PATH("/xyz/openbmc_project/software");
3611271fb7SJayanth Othayoth constexpr auto FIELDMODE_INTERFACE("xyz.openbmc_project.Control.FieldMode");
374016e526SJayanth Othayoth #endif
384016e526SJayanth Othayoth 
399d25b606SMichael Tritz constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
409d25b606SMichael Tritz constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
419d25b606SMichael Tritz 
subscribeToSystemdSignals()429d25b606SMichael Tritz void Activation::subscribeToSystemdSignals()
439d25b606SMichael Tritz {
4470dcb63aSAdriana Kobylak     auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
4570dcb63aSAdriana Kobylak                                             SYSTEMD_INTERFACE, "Subscribe");
4674b657e8SGunnar Mills     try
4774b657e8SGunnar Mills     {
489d25b606SMichael Tritz         this->bus.call_noreply(method);
4974b657e8SGunnar Mills     }
500dea1992SPatrick Williams     catch (const sdbusplus::exception_t& e)
5174b657e8SGunnar Mills     {
5274b657e8SGunnar Mills         if (e.name() != nullptr &&
5374b657e8SGunnar Mills             strcmp("org.freedesktop.systemd1.AlreadySubscribed", e.name()) == 0)
5474b657e8SGunnar Mills         {
5574b657e8SGunnar Mills             // If an Activation attempt fails, the Unsubscribe method is not
5674b657e8SGunnar Mills             // called. This may lead to an AlreadySubscribed error if the
5774b657e8SGunnar Mills             // Activation is re-attempted.
5874b657e8SGunnar Mills         }
5974b657e8SGunnar Mills         else
6074b657e8SGunnar Mills         {
6174b657e8SGunnar Mills             log<level::ERR>("Error subscribing to systemd",
6274b657e8SGunnar Mills                             entry("ERROR=%s", e.what()));
6374b657e8SGunnar Mills         }
6474b657e8SGunnar Mills     }
659d25b606SMichael Tritz     return;
669d25b606SMichael Tritz }
679d25b606SMichael Tritz 
unsubscribeFromSystemdSignals()681cb127fbSMichael Tritz void Activation::unsubscribeFromSystemdSignals()
691cb127fbSMichael Tritz {
7070dcb63aSAdriana Kobylak     auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
7170dcb63aSAdriana Kobylak                                             SYSTEMD_INTERFACE, "Unsubscribe");
721cb127fbSMichael Tritz     this->bus.call_noreply(method);
731cb127fbSMichael Tritz 
741cb127fbSMichael Tritz     return;
751cb127fbSMichael Tritz }
761cb127fbSMichael Tritz 
requestedActivation(RequestedActivations value)7770dcb63aSAdriana Kobylak auto Activation::requestedActivation(RequestedActivations value)
7870dcb63aSAdriana Kobylak     -> RequestedActivations
792fdb9310SAdriana Kobylak {
802fdb9310SAdriana Kobylak     if ((value == softwareServer::Activation::RequestedActivations::Active) &&
812fdb9310SAdriana Kobylak         (softwareServer::Activation::requestedActivation() !=
822fdb9310SAdriana Kobylak          softwareServer::Activation::RequestedActivations::Active))
832fdb9310SAdriana Kobylak     {
842fdb9310SAdriana Kobylak         if ((softwareServer::Activation::activation() ==
852fdb9310SAdriana Kobylak              softwareServer::Activation::Activations::Ready) ||
862fdb9310SAdriana Kobylak             (softwareServer::Activation::activation() ==
872fdb9310SAdriana Kobylak              softwareServer::Activation::Activations::Failed))
882fdb9310SAdriana Kobylak         {
89a2e67163SLei YU             activation(softwareServer::Activation::Activations::Activating);
902fdb9310SAdriana Kobylak         }
912fdb9310SAdriana Kobylak     }
9299c8c0e9SAdriana Kobylak     return softwareServer::Activation::requestedActivation(value);
93befe5ce4SAdriana Kobylak }
94befe5ce4SAdriana Kobylak 
deleteImageManagerObject()957f80e0b5SSaqib Khan void Activation::deleteImageManagerObject()
967f80e0b5SSaqib Khan {
977f80e0b5SSaqib Khan     // Get the Delete object for <versionID> inside image_manager
98c9caf869SLei YU     constexpr auto versionServiceStr = "xyz.openbmc_project.Software.Version";
99c9caf869SLei YU     constexpr auto deleteInterface = "xyz.openbmc_project.Object.Delete";
100c9caf869SLei YU     std::string versionService;
10170dcb63aSAdriana Kobylak     auto method = this->bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
10270dcb63aSAdriana Kobylak                                             MAPPER_INTERFACE, "GetObject");
1037f80e0b5SSaqib Khan 
1047f80e0b5SSaqib Khan     method.append(path);
105c9caf869SLei YU     method.append(std::vector<std::string>({deleteInterface}));
106b8cb0cc9SAdriana Kobylak 
1077f80e0b5SSaqib Khan     std::map<std::string, std::vector<std::string>> mapperResponse;
108b8cb0cc9SAdriana Kobylak 
109b8cb0cc9SAdriana Kobylak     try
110b8cb0cc9SAdriana Kobylak     {
111b8cb0cc9SAdriana Kobylak         auto mapperResponseMsg = bus.call(method);
1127f80e0b5SSaqib Khan         mapperResponseMsg.read(mapperResponse);
1137f80e0b5SSaqib Khan         if (mapperResponse.begin() == mapperResponse.end())
1147f80e0b5SSaqib Khan         {
1157f80e0b5SSaqib Khan             log<level::ERR>("ERROR in reading the mapper response",
116afd0a45cSJoseph Reynolds                             entry("VERSIONPATH=%s", path.c_str()));
1177f80e0b5SSaqib Khan             return;
1187f80e0b5SSaqib Khan         }
119b8cb0cc9SAdriana Kobylak     }
1200dea1992SPatrick Williams     catch (const sdbusplus::exception_t& e)
121b8cb0cc9SAdriana Kobylak     {
122b8cb0cc9SAdriana Kobylak         log<level::ERR>("Error in Get Delete Object",
123b8cb0cc9SAdriana Kobylak                         entry("VERSIONPATH=%s", path.c_str()));
124b8cb0cc9SAdriana Kobylak         return;
125b8cb0cc9SAdriana Kobylak     }
1267f80e0b5SSaqib Khan 
127c9caf869SLei YU     // We need to find the phosphor-software-manager's version service
128c9caf869SLei YU     // to invoke the delete interface
129c9caf869SLei YU     for (auto resp : mapperResponse)
130c9caf869SLei YU     {
131c9caf869SLei YU         if (resp.first.find(versionServiceStr) != std::string::npos)
132c9caf869SLei YU         {
133c9caf869SLei YU             versionService = resp.first;
134c9caf869SLei YU         }
135c9caf869SLei YU     }
136c9caf869SLei YU 
137c9caf869SLei YU     if (versionService.empty())
138c9caf869SLei YU     {
139c9caf869SLei YU         log<level::ERR>("Error finding version service");
140c9caf869SLei YU         return;
141c9caf869SLei YU     }
142c9caf869SLei YU 
1437f80e0b5SSaqib Khan     // Call the Delete object for <versionID> inside image_manager
144c9caf869SLei YU     method = this->bus.new_method_call(versionService.c_str(), path.c_str(),
145c9caf869SLei YU                                        deleteInterface, "Delete");
146ab435df0SAdriana Kobylak     try
147ab435df0SAdriana Kobylak     {
148b8cb0cc9SAdriana Kobylak         bus.call(method);
1497f80e0b5SSaqib Khan     }
1500dea1992SPatrick Williams     catch (const sdbusplus::exception_t& e)
151ab435df0SAdriana Kobylak     {
152ab435df0SAdriana Kobylak         if (e.name() != nullptr && strcmp("System.Error.ELOOP", e.name()) == 0)
153ab435df0SAdriana Kobylak         {
154ab435df0SAdriana Kobylak             // TODO: Error being tracked with openbmc/openbmc#3311
155ab435df0SAdriana Kobylak         }
156ab435df0SAdriana Kobylak         else
157ab435df0SAdriana Kobylak         {
158ab435df0SAdriana Kobylak             log<level::ERR>("Error performing call to Delete object path",
159ab435df0SAdriana Kobylak                             entry("ERROR=%s", e.what()),
160ab435df0SAdriana Kobylak                             entry("PATH=%s", path.c_str()));
161ab435df0SAdriana Kobylak         }
162ab435df0SAdriana Kobylak         return;
163ab435df0SAdriana Kobylak     }
164ab435df0SAdriana Kobylak }
1657f80e0b5SSaqib Khan 
checkApplyTimeImmediate()1664d3d9126SJayashankar Padath bool Activation::checkApplyTimeImmediate()
1674d3d9126SJayashankar Padath {
1684d3d9126SJayashankar Padath     auto service = utils::getService(bus, applyTimeObjPath, applyTimeIntf);
1694d3d9126SJayashankar Padath     if (service.empty())
1704d3d9126SJayashankar Padath     {
1714d3d9126SJayashankar Padath         log<level::INFO>("Error getting the service name for Host image "
1724d3d9126SJayashankar Padath                          "ApplyTime. The Host needs to be manually rebooted to "
1734d3d9126SJayashankar Padath                          "complete the image activation if needed "
1744d3d9126SJayashankar Padath                          "immediately.");
1754d3d9126SJayashankar Padath     }
1764d3d9126SJayashankar Padath     else
1774d3d9126SJayashankar Padath     {
1784d3d9126SJayashankar Padath         auto method = bus.new_method_call(service.c_str(), applyTimeObjPath,
1794d3d9126SJayashankar Padath                                           dbusPropIntf, "Get");
1804d3d9126SJayashankar Padath         method.append(applyTimeIntf, applyTimeProp);
1814d3d9126SJayashankar Padath 
1824d3d9126SJayashankar Padath         try
1834d3d9126SJayashankar Padath         {
1844d3d9126SJayashankar Padath             auto reply = bus.call(method);
1854d3d9126SJayashankar Padath 
186212102e6SPatrick Williams             std::variant<std::string> result;
1874d3d9126SJayashankar Padath             reply.read(result);
188550f31b3SPatrick Williams             auto applyTime = std::get<std::string>(result);
1894d3d9126SJayashankar Padath             if (applyTime == applyTimeImmediate)
1904d3d9126SJayashankar Padath             {
1914d3d9126SJayashankar Padath                 return true;
1924d3d9126SJayashankar Padath             }
1934d3d9126SJayashankar Padath         }
1940dea1992SPatrick Williams         catch (const sdbusplus::exception_t& e)
1954d3d9126SJayashankar Padath         {
1964d3d9126SJayashankar Padath             log<level::ERR>("Error in getting ApplyTime",
1974d3d9126SJayashankar Padath                             entry("ERROR=%s", e.what()));
1984d3d9126SJayashankar Padath         }
1994d3d9126SJayashankar Padath     }
2004d3d9126SJayashankar Padath     return false;
2014d3d9126SJayashankar Padath }
2024d3d9126SJayashankar Padath 
rebootHost()2034d3d9126SJayashankar Padath void Activation::rebootHost()
2044d3d9126SJayashankar Padath {
2054d3d9126SJayashankar Padath     auto service = utils::getService(bus, hostStateObjPath, hostStateIntf);
2064d3d9126SJayashankar Padath     if (service.empty())
2074d3d9126SJayashankar Padath     {
2084d3d9126SJayashankar Padath         log<level::ALERT>("Error in getting the service name to reboot the "
2094d3d9126SJayashankar Padath                           "Host. The Host needs to be manually rebooted to "
2104d3d9126SJayashankar Padath                           "complete the image activation.");
2114d3d9126SJayashankar Padath     }
2124d3d9126SJayashankar Padath 
2134d3d9126SJayashankar Padath     auto method = bus.new_method_call(service.c_str(), hostStateObjPath,
2144d3d9126SJayashankar Padath                                       dbusPropIntf, "Set");
215212102e6SPatrick Williams     std::variant<std::string> hostReboot = hostStateRebootVal;
2164d3d9126SJayashankar Padath     method.append(hostStateIntf, hostStateRebootProp, hostReboot);
2174d3d9126SJayashankar Padath 
2184d3d9126SJayashankar Padath     try
2194d3d9126SJayashankar Padath     {
2204d3d9126SJayashankar Padath         auto reply = bus.call(method);
2214d3d9126SJayashankar Padath     }
2220dea1992SPatrick Williams     catch (const sdbusplus::exception_t& e)
2234d3d9126SJayashankar Padath     {
2244d3d9126SJayashankar Padath         log<level::ALERT>("Error in trying to reboot the Host. "
2254d3d9126SJayashankar Padath                           "The Host needs to be manually rebooted to complete "
2264d3d9126SJayashankar Padath                           "the image activation.",
2274d3d9126SJayashankar Padath                           entry("ERROR=%s", e.what()));
2284d3d9126SJayashankar Padath         report<InternalFailure>();
2294d3d9126SJayashankar Padath     }
2304d3d9126SJayashankar Padath }
2314d3d9126SJayashankar Padath 
priority(uint8_t value)2322021b4ceSSaqib Khan uint8_t RedundancyPriority::priority(uint8_t value)
2332021b4ceSSaqib Khan {
234b8e7f313SSaqib Khan     parent.parent.freePriority(value, parent.versionId);
2352021b4ceSSaqib Khan     return softwareServer::RedundancyPriority::priority(value);
2362021b4ceSSaqib Khan }
2372021b4ceSSaqib Khan 
23811271fb7SJayanth Othayoth #ifdef WANT_SIGNATURE_VERIFY
validateSignature(const std::string & pnorFileName)2392b2d2298SLei YU bool Activation::validateSignature(const std::string& pnorFileName)
24011271fb7SJayanth Othayoth {
24111271fb7SJayanth Othayoth     using Signature = openpower::software::image::Signature;
2429f44c99aSBrad Bishop     std::filesystem::path imageDir(IMG_DIR);
24311271fb7SJayanth Othayoth 
2442b2d2298SLei YU     Signature signature(imageDir / versionId, pnorFileName,
2452b2d2298SLei YU                         PNOR_SIGNED_IMAGE_CONF_PATH);
24611271fb7SJayanth Othayoth 
24711271fb7SJayanth Othayoth     // Validate the signed image.
24811271fb7SJayanth Othayoth     if (signature.verify())
24911271fb7SJayanth Othayoth     {
25011271fb7SJayanth Othayoth         return true;
25111271fb7SJayanth Othayoth     }
25211271fb7SJayanth Othayoth     // Log error and continue activation process, if field mode disabled.
25311271fb7SJayanth Othayoth     log<level::ERR>("Error occurred during image validation");
25411271fb7SJayanth Othayoth     report<InternalFailure>();
25511271fb7SJayanth Othayoth 
25611271fb7SJayanth Othayoth     try
25711271fb7SJayanth Othayoth     {
25811271fb7SJayanth Othayoth         if (!fieldModeEnabled())
25911271fb7SJayanth Othayoth         {
26011271fb7SJayanth Othayoth             return true;
26111271fb7SJayanth Othayoth         }
26211271fb7SJayanth Othayoth     }
26311271fb7SJayanth Othayoth     catch (const InternalFailure& e)
26411271fb7SJayanth Othayoth     {
26511271fb7SJayanth Othayoth         report<InternalFailure>();
26611271fb7SJayanth Othayoth     }
26711271fb7SJayanth Othayoth     return false;
26811271fb7SJayanth Othayoth }
26911271fb7SJayanth Othayoth 
fieldModeEnabled()27011271fb7SJayanth Othayoth bool Activation::fieldModeEnabled()
27111271fb7SJayanth Othayoth {
272*f8e02429SPatrick Williams     auto fieldModeSvc =
273*f8e02429SPatrick Williams         utils::getService(bus, FIELDMODE_PATH, FIELDMODE_INTERFACE);
27411271fb7SJayanth Othayoth 
27511271fb7SJayanth Othayoth     auto method = bus.new_method_call(fieldModeSvc.c_str(), FIELDMODE_PATH,
27611271fb7SJayanth Othayoth                                       "org.freedesktop.DBus.Properties", "Get");
27711271fb7SJayanth Othayoth 
27811271fb7SJayanth Othayoth     method.append(FIELDMODE_INTERFACE, "FieldModeEnabled");
279b8cb0cc9SAdriana Kobylak 
280212102e6SPatrick Williams     std::variant<bool> fieldMode;
281b8cb0cc9SAdriana Kobylak 
282b8cb0cc9SAdriana Kobylak     try
283b8cb0cc9SAdriana Kobylak     {
28411271fb7SJayanth Othayoth         auto reply = bus.call(method);
285b8cb0cc9SAdriana Kobylak         reply.read(fieldMode);
286550f31b3SPatrick Williams         return std::get<bool>(fieldMode);
287b8cb0cc9SAdriana Kobylak     }
2880dea1992SPatrick Williams     catch (const sdbusplus::exception_t& e)
28911271fb7SJayanth Othayoth     {
29011271fb7SJayanth Othayoth         log<level::ERR>("Error in fieldModeEnabled getValue");
29111271fb7SJayanth Othayoth         elog<InternalFailure>();
29211271fb7SJayanth Othayoth     }
29311271fb7SJayanth Othayoth }
29411271fb7SJayanth Othayoth 
29511271fb7SJayanth Othayoth #endif
29611271fb7SJayanth Othayoth 
297befe5ce4SAdriana Kobylak } // namespace updater
298befe5ce4SAdriana Kobylak } // namespace software
299befe5ce4SAdriana Kobylak } // namespace openpower
300