blob: e807d0474beee8fbc191d009fac87192baa970d1 [file] [log] [blame]
Adriana Kobylak55f9e832017-05-14 16:13:00 -05001#include <experimental/filesystem>
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -05002#include "activation.hpp"
Adriana Kobylak692b5552017-04-17 14:02:58 -05003#include "config.h"
Saqib Khan81bac882017-06-08 12:17:01 -05004#include "item_updater.hpp"
Michael Tritz60bc20f2017-07-29 23:32:21 -05005#include "serialize.hpp"
Saqib Khan7f80e0b2017-10-22 11:29:07 -05006#include <phosphor-logging/log.hpp>
Gunnar Mills74b657e2018-07-13 09:27:31 -05007#include <sdbusplus/exception.hpp>
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -05008
Jayanth Othayoth4016e522018-03-20 09:39:06 -05009#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth11271fb2018-03-29 10:25:50 -050010#include <sdbusplus/server.hpp>
Jayanth Othayoth4016e522018-03-20 09:39:06 -050011#include <phosphor-logging/elog.hpp>
12#include <phosphor-logging/elog-errors.hpp>
13#include <xyz/openbmc_project/Common/error.hpp>
14#include "image_verify.hpp"
Jayanth Othayoth4016e522018-03-20 09:39:06 -050015#endif
16
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -050017namespace openpower
18{
19namespace software
20{
21namespace updater
22{
23
Adriana Kobylak55f9e832017-05-14 16:13:00 -050024namespace fs = std::experimental::filesystem;
Adriana Kobylak99c8c0e2017-04-17 13:39:11 -050025namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server;
26
Saqib Khan7f80e0b2017-10-22 11:29:07 -050027using namespace phosphor::logging;
Gunnar Mills74b657e2018-07-13 09:27:31 -050028using sdbusplus::exception::SdBusError;
Saqib Khan7f80e0b2017-10-22 11:29:07 -050029
Jayanth Othayoth4016e522018-03-20 09:39:06 -050030#ifdef WANT_SIGNATURE_VERIFY
31using InternalFailure =
32 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Jayanth Othayoth11271fb2018-03-29 10:25:50 -050033
34// Field mode path and interface.
35constexpr auto FIELDMODE_PATH("/xyz/openbmc_project/software");
36constexpr auto FIELDMODE_INTERFACE("xyz.openbmc_project.Control.FieldMode");
Jayanth Othayoth4016e522018-03-20 09:39:06 -050037#endif
38
Adriana Kobylak70dcb632018-02-27 15:46:52 -060039constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
40constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
Michael Tritz9d25b602017-06-14 14:41:43 -050041
42void Activation::subscribeToSystemdSignals()
43{
Adriana Kobylak70dcb632018-02-27 15:46:52 -060044 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
45 SYSTEMD_INTERFACE, "Subscribe");
Gunnar Mills74b657e2018-07-13 09:27:31 -050046 try
47 {
48 this->bus.call_noreply(method);
49 }
50 catch (const SdBusError& e)
51 {
52 if (e.name() != nullptr &&
53 strcmp("org.freedesktop.systemd1.AlreadySubscribed", e.name()) == 0)
54 {
55 // If an Activation attempt fails, the Unsubscribe method is not
56 // called. This may lead to an AlreadySubscribed error if the
57 // Activation is re-attempted.
58 }
59 else
60 {
61 log<level::ERR>("Error subscribing to systemd",
62 entry("ERROR=%s", e.what()));
63 }
64 }
Michael Tritz9d25b602017-06-14 14:41:43 -050065 return;
66}
67
Michael Tritz1cb127f2017-07-26 15:40:38 -050068void Activation::unsubscribeFromSystemdSignals()
69{
Adriana Kobylak70dcb632018-02-27 15:46:52 -060070 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
71 SYSTEMD_INTERFACE, "Unsubscribe");
Michael Tritz1cb127f2017-07-26 15:40:38 -050072 this->bus.call_noreply(method);
73
74 return;
75}
76
Michael Tritz1cb127f2017-07-26 15:40:38 -050077void Activation::startActivation()
78{
79 // Since the squashfs image has not yet been loaded to pnor and the
80 // RW volumes have not yet been created, we need to start the
81 // service files for each of those actions.
82
83 if (!activationProgress)
84 {
Adriana Kobylak70dcb632018-02-27 15:46:52 -060085 activationProgress = std::make_unique<ActivationProgress>(bus, path);
Michael Tritz1cb127f2017-07-26 15:40:38 -050086 }
87
88 if (!activationBlocksTransition)
89 {
90 activationBlocksTransition =
Adriana Kobylak70dcb632018-02-27 15:46:52 -060091 std::make_unique<ActivationBlocksTransition>(bus, path);
Michael Tritz1cb127f2017-07-26 15:40:38 -050092 }
93
Michael Tritz1cb127f2017-07-26 15:40:38 -050094 constexpr auto ubimountService = "obmc-flash-bios-ubimount@";
Adriana Kobylak70dcb632018-02-27 15:46:52 -060095 auto ubimountServiceFile =
96 std::string(ubimountService) + versionId + ".service";
97 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
98 SYSTEMD_INTERFACE, "StartUnit");
Michael Tritz1cb127f2017-07-26 15:40:38 -050099 method.append(ubimountServiceFile, "replace");
100 bus.call_noreply(method);
101
102 activationProgress->progress(10);
103}
104
105void Activation::finishActivation()
106{
107 activationProgress->progress(90);
Michael Tritz1cb127f2017-07-26 15:40:38 -0500108
109 // Set Redundancy Priority before setting to Active
110 if (!redundancyPriority)
111 {
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600112 redundancyPriority =
113 std::make_unique<RedundancyPriority>(bus, path, *this, 0);
Michael Tritz1cb127f2017-07-26 15:40:38 -0500114 }
115
116 activationProgress->progress(100);
117
118 activationBlocksTransition.reset(nullptr);
119 activationProgress.reset(nullptr);
120
Saqib Khan1e0aa5c2017-08-31 11:04:17 -0500121 ubiVolumesCreated = false;
Michael Tritz1cb127f2017-07-26 15:40:38 -0500122 Activation::unsubscribeFromSystemdSignals();
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500123 // Remove version object from image manager
124 Activation::deleteImageManagerObject();
Gunnar Mills9741cd12017-08-28 15:09:00 -0500125 // Create active association
126 parent.createActiveAssociation(path);
Michael Tritz1cb127f2017-07-26 15:40:38 -0500127}
128
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600129auto Activation::activation(Activations value) -> Activations
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500130{
Saqib Khan942df8a2017-06-01 14:09:27 -0500131
132 if (value != softwareServer::Activation::Activations::Active)
133 {
134 redundancyPriority.reset(nullptr);
135 }
136
Adriana Kobylak99c8c0e2017-04-17 13:39:11 -0500137 if (value == softwareServer::Activation::Activations::Activating)
138 {
Saqib Khan2cbfa032017-08-17 14:52:37 -0500139 parent.freeSpace();
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500140 softwareServer::Activation::activation(value);
141
Saqib Khan1e0aa5c2017-08-31 11:04:17 -0500142 if (ubiVolumesCreated == false)
Adriana Kobylak99c8c0e2017-04-17 13:39:11 -0500143 {
Gunnar Mills74b657e2018-07-13 09:27:31 -0500144 // Enable systemd signals
145 Activation::subscribeToSystemdSignals();
Jayanth Othayoth4016e522018-03-20 09:39:06 -0500146
147#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth4016e522018-03-20 09:39:06 -0500148 // Validate the signed image.
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500149 if (!validateSignature())
Jayanth Othayoth4016e522018-03-20 09:39:06 -0500150 {
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500151 // Cleanup
152 activationBlocksTransition.reset(nullptr);
153 activationProgress.reset(nullptr);
Jayanth Othayoth4016e522018-03-20 09:39:06 -0500154
155 return softwareServer::Activation::activation(
156 softwareServer::Activation::Activations::Failed);
157 }
158#endif
Michael Tritz1cb127f2017-07-26 15:40:38 -0500159 Activation::startActivation();
Michael Tritz9d25b602017-06-14 14:41:43 -0500160 return softwareServer::Activation::activation(value);
161 }
Saqib Khan1e0aa5c2017-08-31 11:04:17 -0500162 else if (ubiVolumesCreated == true)
Michael Tritz9d25b602017-06-14 14:41:43 -0500163 {
164 // Only when the squashfs image is finished loading AND the RW
Michael Tritz1cb127f2017-07-26 15:40:38 -0500165 // volumes have been created do we proceed with activation. To
166 // verify that this happened, we check for the mount dirs PNOR_PRSV
167 // and PNOR_RW_PREFIX_<versionid>, as well as the image dir R0.
Michael Tritz9d25b602017-06-14 14:41:43 -0500168
Michael Tritz9d25b602017-06-14 14:41:43 -0500169 if ((fs::is_directory(PNOR_PRSV)) &&
170 (fs::is_directory(PNOR_RW_PREFIX + versionId)) &&
171 (fs::is_directory(PNOR_RO_PREFIX + versionId)))
172 {
Michael Tritz1cb127f2017-07-26 15:40:38 -0500173 Activation::finishActivation();
Michael Tritz9d25b602017-06-14 14:41:43 -0500174 return softwareServer::Activation::activation(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600175 softwareServer::Activation::Activations::Active);
Michael Tritz9d25b602017-06-14 14:41:43 -0500176 }
177 else
178 {
Saqib Khancb9df4e2017-06-26 11:06:07 -0500179 activationBlocksTransition.reset(nullptr);
Michael Tritz1793b642017-06-28 18:35:58 -0500180 activationProgress.reset(nullptr);
Michael Tritz9d25b602017-06-14 14:41:43 -0500181 return softwareServer::Activation::activation(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600182 softwareServer::Activation::Activations::Failed);
Michael Tritz9d25b602017-06-14 14:41:43 -0500183 }
Adriana Kobylak55f9e832017-05-14 16:13:00 -0500184 }
Adriana Kobylak692b5552017-04-17 14:02:58 -0500185 }
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500186 else
187 {
188 activationBlocksTransition.reset(nullptr);
Michael Tritz1793b642017-06-28 18:35:58 -0500189 activationProgress.reset(nullptr);
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500190 }
Michael Tritz1cb127f2017-07-26 15:40:38 -0500191
192 return softwareServer::Activation::activation(value);
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500193}
194
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600195auto Activation::requestedActivation(RequestedActivations value)
196 -> RequestedActivations
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500197{
Saqib Khan1e0aa5c2017-08-31 11:04:17 -0500198 ubiVolumesCreated = false;
Michael Tritz9d25b602017-06-14 14:41:43 -0500199
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500200 if ((value == softwareServer::Activation::RequestedActivations::Active) &&
201 (softwareServer::Activation::requestedActivation() !=
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600202 softwareServer::Activation::RequestedActivations::Active))
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500203 {
204 if ((softwareServer::Activation::activation() ==
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600205 softwareServer::Activation::Activations::Ready) ||
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500206 (softwareServer::Activation::activation() ==
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600207 softwareServer::Activation::Activations::Failed))
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500208 {
209 Activation::activation(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600210 softwareServer::Activation::Activations::Activating);
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500211 }
212 }
Adriana Kobylak99c8c0e2017-04-17 13:39:11 -0500213 return softwareServer::Activation::requestedActivation(value);
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500214}
215
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500216void Activation::deleteImageManagerObject()
217{
218 // Get the Delete object for <versionID> inside image_manager
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600219 auto method = this->bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
220 MAPPER_INTERFACE, "GetObject");
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500221
222 method.append(path);
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600223 method.append(
224 std::vector<std::string>({"xyz.openbmc_project.Object.Delete"}));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500225 auto mapperResponseMsg = bus.call(method);
226 if (mapperResponseMsg.is_method_error())
227 {
228 log<level::ERR>("Error in Get Delete Object",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500229 entry("VERSIONPATH=%s", path.c_str()));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500230 return;
231 }
232 std::map<std::string, std::vector<std::string>> mapperResponse;
233 mapperResponseMsg.read(mapperResponse);
234 if (mapperResponse.begin() == mapperResponse.end())
235 {
236 log<level::ERR>("ERROR in reading the mapper response",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500237 entry("VERSIONPATH=%s", path.c_str()));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500238 return;
239 }
240
241 // Call the Delete object for <versionID> inside image_manager
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600242 method = this->bus.new_method_call(
243 (mapperResponse.begin()->first).c_str(), path.c_str(),
244 "xyz.openbmc_project.Object.Delete", "Delete");
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500245 mapperResponseMsg = bus.call(method);
246
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600247 // Check that the bus call didn't result in an error
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500248 if (mapperResponseMsg.is_method_error())
249 {
250 log<level::ERR>("Error in Deleting image from image manager",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500251 entry("VERSIONPATH=%s", path.c_str()));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500252 return;
253 }
254}
255
Saqib Khan2021b4c2017-06-07 14:37:36 -0500256uint8_t RedundancyPriority::priority(uint8_t value)
257{
Saqib Khanb8e7f312017-08-12 10:24:10 -0500258 parent.parent.freePriority(value, parent.versionId);
Michael Tritz60bc20f2017-07-29 23:32:21 -0500259 storeToFile(parent.versionId, value);
Saqib Khan2021b4c2017-06-07 14:37:36 -0500260 return softwareServer::RedundancyPriority::priority(value);
261}
262
Michael Tritz9d25b602017-06-14 14:41:43 -0500263void Activation::unitStateChange(sdbusplus::message::message& msg)
264{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600265 uint32_t newStateID{};
Michael Tritz9d25b602017-06-14 14:41:43 -0500266 sdbusplus::message::object_path newStateObjPath;
267 std::string newStateUnit{};
268 std::string newStateResult{};
269
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600270 // Read the msg and populate each variable
Michael Tritz9d25b602017-06-14 14:41:43 -0500271 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
272
Michael Tritz9d25b602017-06-14 14:41:43 -0500273 auto ubimountServiceFile =
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600274 "obmc-flash-bios-ubimount@" + versionId + ".service";
Michael Tritz9d25b602017-06-14 14:41:43 -0500275
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600276 if (newStateUnit == ubimountServiceFile && newStateResult == "done")
Michael Tritz9d25b602017-06-14 14:41:43 -0500277 {
Saqib Khan1e0aa5c2017-08-31 11:04:17 -0500278 ubiVolumesCreated = true;
Michael Tritz1793b642017-06-28 18:35:58 -0500279 activationProgress->progress(activationProgress->progress() + 50);
Michael Tritz9d25b602017-06-14 14:41:43 -0500280 }
281
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600282 if (ubiVolumesCreated)
Michael Tritz9d25b602017-06-14 14:41:43 -0500283 {
284 Activation::activation(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600285 softwareServer::Activation::Activations::Activating);
Michael Tritz9d25b602017-06-14 14:41:43 -0500286 }
287
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600288 if ((newStateUnit == ubimountServiceFile) &&
Michael Tritz9d25b602017-06-14 14:41:43 -0500289 (newStateResult == "failed" || newStateResult == "dependency"))
290 {
291 Activation::activation(softwareServer::Activation::Activations::Failed);
292 }
293
294 return;
295}
296
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500297#ifdef WANT_SIGNATURE_VERIFY
298inline bool Activation::validateSignature()
299{
300 using Signature = openpower::software::image::Signature;
301 fs::path imageDir(IMG_DIR);
302
303 Signature signature(imageDir / versionId, PNOR_SIGNED_IMAGE_CONF_PATH);
304
305 // Validate the signed image.
306 if (signature.verify())
307 {
308 return true;
309 }
310 // Log error and continue activation process, if field mode disabled.
311 log<level::ERR>("Error occurred during image validation");
312 report<InternalFailure>();
313
314 try
315 {
316 if (!fieldModeEnabled())
317 {
318 return true;
319 }
320 }
321 catch (const InternalFailure& e)
322 {
323 report<InternalFailure>();
324 }
325 return false;
326}
327
328bool Activation::fieldModeEnabled()
329{
330 auto fieldModeSvc = getService(bus, FIELDMODE_PATH, FIELDMODE_INTERFACE);
331
332 auto method = bus.new_method_call(fieldModeSvc.c_str(), FIELDMODE_PATH,
333 "org.freedesktop.DBus.Properties", "Get");
334
335 method.append(FIELDMODE_INTERFACE, "FieldModeEnabled");
336 auto reply = bus.call(method);
337 if (reply.is_method_error())
338 {
339 log<level::ERR>("Error in fieldModeEnabled getValue");
340 elog<InternalFailure>();
341 }
342 sdbusplus::message::variant<bool> fieldMode;
343 reply.read(fieldMode);
344
345 return (fieldMode.get<bool>());
346}
347
348std::string Activation::getService(sdbusplus::bus::bus& bus,
349 const std::string& path,
350 const std::string& intf)
351{
352 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
353 MAPPER_INTERFACE, "GetObject");
354
355 mapperCall.append(path);
356 mapperCall.append(std::vector<std::string>({intf}));
357
358 auto mapperResponseMsg = bus.call(mapperCall);
359
360 if (mapperResponseMsg.is_method_error())
361 {
362 log<level::ERR>("ERROR in getting service",
363 entry("PATH=%s", path.c_str()),
364 entry("INTERFACE=%s", intf.c_str()));
365
366 elog<InternalFailure>();
367 }
368
369 std::map<std::string, std::vector<std::string>> mapperResponse;
370 mapperResponseMsg.read(mapperResponse);
371
372 if (mapperResponse.begin() == mapperResponse.end())
373 {
374 log<level::ERR>("ERROR reading mapper response",
375 entry("PATH=%s", path.c_str()),
376 entry("INTERFACE=%s", intf.c_str()));
377
378 elog<InternalFailure>();
379 }
380 return mapperResponse.begin()->first;
381}
382#endif
383
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500384} // namespace updater
385} // namespace software
386} // namespace openpower