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