blob: e7a67140fb2cc57ae60528d8c3d730869cd089b2 [file] [log] [blame]
Adriana Kobylak692b5552017-04-17 14:02:58 -05001#include "config.h"
Gunnar Millsf6ed5892018-09-07 17:08:02 -05002
3#include "activation.hpp"
4
Saqib Khan81bac882017-06-08 12:17:01 -05005#include "item_updater.hpp"
Gunnar Millsf6ed5892018-09-07 17:08:02 -05006
Jayashankar Padath4d3d9122019-07-24 16:46:22 +05307#include <phosphor-logging/elog-errors.hpp>
8#include <phosphor-logging/elog.hpp>
Saqib Khan7f80e0b2017-10-22 11:29:07 -05009#include <phosphor-logging/log.hpp>
Gunnar Mills74b657e2018-07-13 09:27:31 -050010#include <sdbusplus/exception.hpp>
Jayashankar Padath4d3d9122019-07-24 16:46:22 +053011#include <sdbusplus/server.hpp>
12#include <xyz/openbmc_project/Common/error.hpp>
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -050013
Brad Bishop8facccf2020-11-04 09:44:58 -050014#include <experimental/filesystem>
15
Jayanth Othayoth4016e522018-03-20 09:39:06 -050016#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth4016e522018-03-20 09:39:06 -050017#include "image_verify.hpp"
Jayanth Othayoth4016e522018-03-20 09:39:06 -050018#endif
19
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -050020namespace openpower
21{
22namespace software
23{
24namespace updater
25{
26
Adriana Kobylak55f9e832017-05-14 16:13:00 -050027namespace fs = std::experimental::filesystem;
Adriana Kobylak99c8c0e2017-04-17 13:39:11 -050028namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server;
29
Saqib Khan7f80e0b2017-10-22 11:29:07 -050030using namespace phosphor::logging;
Gunnar Mills74b657e2018-07-13 09:27:31 -050031using sdbusplus::exception::SdBusError;
Jayanth Othayoth4016e522018-03-20 09:39:06 -050032using InternalFailure =
33 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Jayanth Othayoth11271fb2018-03-29 10:25:50 -050034
Jayashankar Padath4d3d9122019-07-24 16:46:22 +053035#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth11271fb2018-03-29 10:25:50 -050036// Field mode path and interface.
37constexpr auto FIELDMODE_PATH("/xyz/openbmc_project/software");
38constexpr auto FIELDMODE_INTERFACE("xyz.openbmc_project.Control.FieldMode");
Jayanth Othayoth4016e522018-03-20 09:39:06 -050039#endif
40
Adriana Kobylak70dcb632018-02-27 15:46:52 -060041constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
42constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
Michael Tritz9d25b602017-06-14 14:41:43 -050043
44void Activation::subscribeToSystemdSignals()
45{
Adriana Kobylak70dcb632018-02-27 15:46:52 -060046 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
47 SYSTEMD_INTERFACE, "Subscribe");
Gunnar Mills74b657e2018-07-13 09:27:31 -050048 try
49 {
50 this->bus.call_noreply(method);
51 }
52 catch (const SdBusError& e)
53 {
54 if (e.name() != nullptr &&
55 strcmp("org.freedesktop.systemd1.AlreadySubscribed", e.name()) == 0)
56 {
57 // If an Activation attempt fails, the Unsubscribe method is not
58 // called. This may lead to an AlreadySubscribed error if the
59 // Activation is re-attempted.
60 }
61 else
62 {
63 log<level::ERR>("Error subscribing to systemd",
64 entry("ERROR=%s", e.what()));
65 }
66 }
Michael Tritz9d25b602017-06-14 14:41:43 -050067 return;
68}
69
Michael Tritz1cb127f2017-07-26 15:40:38 -050070void Activation::unsubscribeFromSystemdSignals()
71{
Adriana Kobylak70dcb632018-02-27 15:46:52 -060072 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
73 SYSTEMD_INTERFACE, "Unsubscribe");
Michael Tritz1cb127f2017-07-26 15:40:38 -050074 this->bus.call_noreply(method);
75
76 return;
77}
78
Adriana Kobylak70dcb632018-02-27 15:46:52 -060079auto Activation::requestedActivation(RequestedActivations value)
80 -> RequestedActivations
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050081{
82 if ((value == softwareServer::Activation::RequestedActivations::Active) &&
83 (softwareServer::Activation::requestedActivation() !=
Adriana Kobylak70dcb632018-02-27 15:46:52 -060084 softwareServer::Activation::RequestedActivations::Active))
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050085 {
86 if ((softwareServer::Activation::activation() ==
Adriana Kobylak70dcb632018-02-27 15:46:52 -060087 softwareServer::Activation::Activations::Ready) ||
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050088 (softwareServer::Activation::activation() ==
Adriana Kobylak70dcb632018-02-27 15:46:52 -060089 softwareServer::Activation::Activations::Failed))
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050090 {
Lei YUa2e67162019-02-22 17:35:24 +080091 activation(softwareServer::Activation::Activations::Activating);
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050092 }
93 }
Adriana Kobylak99c8c0e2017-04-17 13:39:11 -050094 return softwareServer::Activation::requestedActivation(value);
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -050095}
96
Saqib Khan7f80e0b2017-10-22 11:29:07 -050097void Activation::deleteImageManagerObject()
98{
99 // Get the Delete object for <versionID> inside image_manager
Lei YUc9caf862019-01-24 15:40:25 +0800100 constexpr auto versionServiceStr = "xyz.openbmc_project.Software.Version";
101 constexpr auto deleteInterface = "xyz.openbmc_project.Object.Delete";
102 std::string versionService;
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600103 auto method = this->bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
104 MAPPER_INTERFACE, "GetObject");
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500105
106 method.append(path);
Lei YUc9caf862019-01-24 15:40:25 +0800107 method.append(std::vector<std::string>({deleteInterface}));
Adriana Kobylakb8cb0cc2019-05-31 09:58:04 -0500108
109 std::map<std::string, std::vector<std::string>> mapperResponse;
110
111 try
112 {
113 auto mapperResponseMsg = bus.call(method);
114 mapperResponseMsg.read(mapperResponse);
115 if (mapperResponse.begin() == mapperResponse.end())
116 {
117 log<level::ERR>("ERROR in reading the mapper response",
118 entry("VERSIONPATH=%s", path.c_str()));
119 return;
120 }
121 }
122 catch (const SdBusError& e)
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500123 {
124 log<level::ERR>("Error in Get Delete Object",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500125 entry("VERSIONPATH=%s", path.c_str()));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500126 return;
127 }
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500128
Lei YUc9caf862019-01-24 15:40:25 +0800129 // We need to find the phosphor-software-manager's version service
130 // to invoke the delete interface
131 for (auto resp : mapperResponse)
132 {
133 if (resp.first.find(versionServiceStr) != std::string::npos)
134 {
135 versionService = resp.first;
136 }
137 }
138
139 if (versionService.empty())
140 {
141 log<level::ERR>("Error finding version service");
142 return;
143 }
144
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500145 // Call the Delete object for <versionID> inside image_manager
Lei YUc9caf862019-01-24 15:40:25 +0800146 method = this->bus.new_method_call(versionService.c_str(), path.c_str(),
147 deleteInterface, "Delete");
Adriana Kobylakab435df2018-07-16 11:37:19 -0500148 try
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500149 {
Adriana Kobylakb8cb0cc2019-05-31 09:58:04 -0500150 bus.call(method);
Adriana Kobylakab435df2018-07-16 11:37:19 -0500151 }
152 catch (const SdBusError& e)
153 {
154 if (e.name() != nullptr && strcmp("System.Error.ELOOP", e.name()) == 0)
155 {
156 // TODO: Error being tracked with openbmc/openbmc#3311
157 }
158 else
159 {
160 log<level::ERR>("Error performing call to Delete object path",
161 entry("ERROR=%s", e.what()),
162 entry("PATH=%s", path.c_str()));
163 }
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500164 return;
165 }
166}
167
Jayashankar Padath4d3d9122019-07-24 16:46:22 +0530168bool Activation::checkApplyTimeImmediate()
169{
170 auto service = utils::getService(bus, applyTimeObjPath, applyTimeIntf);
171 if (service.empty())
172 {
173 log<level::INFO>("Error getting the service name for Host image "
174 "ApplyTime. The Host needs to be manually rebooted to "
175 "complete the image activation if needed "
176 "immediately.");
177 }
178 else
179 {
180
181 auto method = bus.new_method_call(service.c_str(), applyTimeObjPath,
182 dbusPropIntf, "Get");
183 method.append(applyTimeIntf, applyTimeProp);
184
185 try
186 {
187 auto reply = bus.call(method);
188
Patrick Williams212102e2020-05-13 17:50:50 -0500189 std::variant<std::string> result;
Jayashankar Padath4d3d9122019-07-24 16:46:22 +0530190 reply.read(result);
Patrick Williams550f31b2020-05-13 11:15:24 -0500191 auto applyTime = std::get<std::string>(result);
Jayashankar Padath4d3d9122019-07-24 16:46:22 +0530192 if (applyTime == applyTimeImmediate)
193 {
194 return true;
195 }
196 }
197 catch (const SdBusError& e)
198 {
199 log<level::ERR>("Error in getting ApplyTime",
200 entry("ERROR=%s", e.what()));
201 }
202 }
203 return false;
204}
205
206void Activation::rebootHost()
207{
208 auto service = utils::getService(bus, hostStateObjPath, hostStateIntf);
209 if (service.empty())
210 {
211 log<level::ALERT>("Error in getting the service name to reboot the "
212 "Host. The Host needs to be manually rebooted to "
213 "complete the image activation.");
214 }
215
216 auto method = bus.new_method_call(service.c_str(), hostStateObjPath,
217 dbusPropIntf, "Set");
Patrick Williams212102e2020-05-13 17:50:50 -0500218 std::variant<std::string> hostReboot = hostStateRebootVal;
Jayashankar Padath4d3d9122019-07-24 16:46:22 +0530219 method.append(hostStateIntf, hostStateRebootProp, hostReboot);
220
221 try
222 {
223 auto reply = bus.call(method);
224 }
225 catch (const SdBusError& e)
226 {
227 log<level::ALERT>("Error in trying to reboot the Host. "
228 "The Host needs to be manually rebooted to complete "
229 "the image activation.",
230 entry("ERROR=%s", e.what()));
231 report<InternalFailure>();
232 }
233}
234
Saqib Khan2021b4c2017-06-07 14:37:36 -0500235uint8_t RedundancyPriority::priority(uint8_t value)
236{
Saqib Khanb8e7f312017-08-12 10:24:10 -0500237 parent.parent.freePriority(value, parent.versionId);
Saqib Khan2021b4c2017-06-07 14:37:36 -0500238 return softwareServer::RedundancyPriority::priority(value);
239}
240
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500241#ifdef WANT_SIGNATURE_VERIFY
Lei YU2b2d2292019-03-18 15:22:56 +0800242bool Activation::validateSignature(const std::string& pnorFileName)
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500243{
244 using Signature = openpower::software::image::Signature;
245 fs::path imageDir(IMG_DIR);
246
Lei YU2b2d2292019-03-18 15:22:56 +0800247 Signature signature(imageDir / versionId, pnorFileName,
248 PNOR_SIGNED_IMAGE_CONF_PATH);
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500249
250 // Validate the signed image.
251 if (signature.verify())
252 {
253 return true;
254 }
255 // Log error and continue activation process, if field mode disabled.
256 log<level::ERR>("Error occurred during image validation");
257 report<InternalFailure>();
258
259 try
260 {
261 if (!fieldModeEnabled())
262 {
263 return true;
264 }
265 }
266 catch (const InternalFailure& e)
267 {
268 report<InternalFailure>();
269 }
270 return false;
271}
272
273bool Activation::fieldModeEnabled()
274{
Lei YUe4994462019-03-14 14:41:53 +0800275 auto fieldModeSvc =
276 utils::getService(bus, FIELDMODE_PATH, FIELDMODE_INTERFACE);
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500277
278 auto method = bus.new_method_call(fieldModeSvc.c_str(), FIELDMODE_PATH,
279 "org.freedesktop.DBus.Properties", "Get");
280
281 method.append(FIELDMODE_INTERFACE, "FieldModeEnabled");
Adriana Kobylakb8cb0cc2019-05-31 09:58:04 -0500282
Patrick Williams212102e2020-05-13 17:50:50 -0500283 std::variant<bool> fieldMode;
Adriana Kobylakb8cb0cc2019-05-31 09:58:04 -0500284
285 try
286 {
287 auto reply = bus.call(method);
288 reply.read(fieldMode);
Patrick Williams550f31b2020-05-13 11:15:24 -0500289 return std::get<bool>(fieldMode);
Adriana Kobylakb8cb0cc2019-05-31 09:58:04 -0500290 }
291 catch (const SdBusError& e)
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500292 {
293 log<level::ERR>("Error in fieldModeEnabled getValue");
294 elog<InternalFailure>();
295 }
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500296}
297
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500298#endif
299
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500300} // namespace updater
301} // namespace software
302} // namespace openpower