blob: e8f0db93042fa7220cb9680d5dffef78a552e08f [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");
Adriana Kobylakab435df2018-07-16 11:37:19 -0500245 try
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500246 {
Adriana Kobylakab435df2018-07-16 11:37:19 -0500247 auto mapperResponseMsg = bus.call(method);
248
249 // Check that the bus call didn't result in an error
250 if (mapperResponseMsg.is_method_error())
251 {
252 log<level::ERR>("Error in Deleting image from image manager",
253 entry("VERSIONPATH=%s", path.c_str()));
254 return;
255 }
256 }
257 catch (const SdBusError& e)
258 {
259 if (e.name() != nullptr && strcmp("System.Error.ELOOP", e.name()) == 0)
260 {
261 // TODO: Error being tracked with openbmc/openbmc#3311
262 }
263 else
264 {
265 log<level::ERR>("Error performing call to Delete object path",
266 entry("ERROR=%s", e.what()),
267 entry("PATH=%s", path.c_str()));
268 }
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500269 return;
270 }
271}
272
Saqib Khan2021b4c2017-06-07 14:37:36 -0500273uint8_t RedundancyPriority::priority(uint8_t value)
274{
Saqib Khanb8e7f312017-08-12 10:24:10 -0500275 parent.parent.freePriority(value, parent.versionId);
Michael Tritz60bc20f2017-07-29 23:32:21 -0500276 storeToFile(parent.versionId, value);
Saqib Khan2021b4c2017-06-07 14:37:36 -0500277 return softwareServer::RedundancyPriority::priority(value);
278}
279
Michael Tritz9d25b602017-06-14 14:41:43 -0500280void Activation::unitStateChange(sdbusplus::message::message& msg)
281{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600282 uint32_t newStateID{};
Michael Tritz9d25b602017-06-14 14:41:43 -0500283 sdbusplus::message::object_path newStateObjPath;
284 std::string newStateUnit{};
285 std::string newStateResult{};
286
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600287 // Read the msg and populate each variable
Michael Tritz9d25b602017-06-14 14:41:43 -0500288 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
289
Michael Tritz9d25b602017-06-14 14:41:43 -0500290 auto ubimountServiceFile =
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600291 "obmc-flash-bios-ubimount@" + versionId + ".service";
Michael Tritz9d25b602017-06-14 14:41:43 -0500292
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600293 if (newStateUnit == ubimountServiceFile && newStateResult == "done")
Michael Tritz9d25b602017-06-14 14:41:43 -0500294 {
Saqib Khan1e0aa5c2017-08-31 11:04:17 -0500295 ubiVolumesCreated = true;
Michael Tritz1793b642017-06-28 18:35:58 -0500296 activationProgress->progress(activationProgress->progress() + 50);
Michael Tritz9d25b602017-06-14 14:41:43 -0500297 }
298
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600299 if (ubiVolumesCreated)
Michael Tritz9d25b602017-06-14 14:41:43 -0500300 {
301 Activation::activation(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600302 softwareServer::Activation::Activations::Activating);
Michael Tritz9d25b602017-06-14 14:41:43 -0500303 }
304
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600305 if ((newStateUnit == ubimountServiceFile) &&
Michael Tritz9d25b602017-06-14 14:41:43 -0500306 (newStateResult == "failed" || newStateResult == "dependency"))
307 {
308 Activation::activation(softwareServer::Activation::Activations::Failed);
309 }
310
311 return;
312}
313
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500314#ifdef WANT_SIGNATURE_VERIFY
315inline bool Activation::validateSignature()
316{
317 using Signature = openpower::software::image::Signature;
318 fs::path imageDir(IMG_DIR);
319
320 Signature signature(imageDir / versionId, PNOR_SIGNED_IMAGE_CONF_PATH);
321
322 // Validate the signed image.
323 if (signature.verify())
324 {
325 return true;
326 }
327 // Log error and continue activation process, if field mode disabled.
328 log<level::ERR>("Error occurred during image validation");
329 report<InternalFailure>();
330
331 try
332 {
333 if (!fieldModeEnabled())
334 {
335 return true;
336 }
337 }
338 catch (const InternalFailure& e)
339 {
340 report<InternalFailure>();
341 }
342 return false;
343}
344
345bool Activation::fieldModeEnabled()
346{
347 auto fieldModeSvc = getService(bus, FIELDMODE_PATH, FIELDMODE_INTERFACE);
348
349 auto method = bus.new_method_call(fieldModeSvc.c_str(), FIELDMODE_PATH,
350 "org.freedesktop.DBus.Properties", "Get");
351
352 method.append(FIELDMODE_INTERFACE, "FieldModeEnabled");
353 auto reply = bus.call(method);
354 if (reply.is_method_error())
355 {
356 log<level::ERR>("Error in fieldModeEnabled getValue");
357 elog<InternalFailure>();
358 }
359 sdbusplus::message::variant<bool> fieldMode;
360 reply.read(fieldMode);
361
362 return (fieldMode.get<bool>());
363}
364
365std::string Activation::getService(sdbusplus::bus::bus& bus,
366 const std::string& path,
367 const std::string& intf)
368{
369 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
370 MAPPER_INTERFACE, "GetObject");
371
372 mapperCall.append(path);
373 mapperCall.append(std::vector<std::string>({intf}));
374
375 auto mapperResponseMsg = bus.call(mapperCall);
376
377 if (mapperResponseMsg.is_method_error())
378 {
379 log<level::ERR>("ERROR in getting service",
380 entry("PATH=%s", path.c_str()),
381 entry("INTERFACE=%s", intf.c_str()));
382
383 elog<InternalFailure>();
384 }
385
386 std::map<std::string, std::vector<std::string>> mapperResponse;
387 mapperResponseMsg.read(mapperResponse);
388
389 if (mapperResponse.begin() == mapperResponse.end())
390 {
391 log<level::ERR>("ERROR reading mapper response",
392 entry("PATH=%s", path.c_str()),
393 entry("INTERFACE=%s", intf.c_str()));
394
395 elog<InternalFailure>();
396 }
397 return mapperResponse.begin()->first;
398}
399#endif
400
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500401} // namespace updater
402} // namespace software
403} // namespace openpower