blob: 11c7b3254e72977d1c88df9d02f1b85e9189fb03 [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>
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -05007
Jayanth Othayoth4016e522018-03-20 09:39:06 -05008#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth11271fb2018-03-29 10:25:50 -05009#include <sdbusplus/server.hpp>
Jayanth Othayoth4016e522018-03-20 09:39:06 -050010#include <phosphor-logging/elog.hpp>
11#include <phosphor-logging/elog-errors.hpp>
12#include <xyz/openbmc_project/Common/error.hpp>
13#include "image_verify.hpp"
Jayanth Othayoth4016e522018-03-20 09:39:06 -050014#endif
15
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -050016namespace openpower
17{
18namespace software
19{
20namespace updater
21{
22
Adriana Kobylak55f9e832017-05-14 16:13:00 -050023namespace fs = std::experimental::filesystem;
Adriana Kobylak99c8c0e2017-04-17 13:39:11 -050024namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server;
25
Saqib Khan7f80e0b2017-10-22 11:29:07 -050026using namespace phosphor::logging;
27
Jayanth Othayoth4016e522018-03-20 09:39:06 -050028#ifdef WANT_SIGNATURE_VERIFY
29using InternalFailure =
30 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Jayanth Othayoth11271fb2018-03-29 10:25:50 -050031
32// Field mode path and interface.
33constexpr auto FIELDMODE_PATH("/xyz/openbmc_project/software");
34constexpr auto FIELDMODE_INTERFACE("xyz.openbmc_project.Control.FieldMode");
Jayanth Othayoth4016e522018-03-20 09:39:06 -050035#endif
36
Adriana Kobylak70dcb632018-02-27 15:46:52 -060037constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
38constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
Michael Tritz9d25b602017-06-14 14:41:43 -050039
40void Activation::subscribeToSystemdSignals()
41{
Adriana Kobylak70dcb632018-02-27 15:46:52 -060042 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
43 SYSTEMD_INTERFACE, "Subscribe");
Michael Tritz9d25b602017-06-14 14:41:43 -050044 this->bus.call_noreply(method);
45
46 return;
47}
48
Michael Tritz1cb127f2017-07-26 15:40:38 -050049void Activation::unsubscribeFromSystemdSignals()
50{
Adriana Kobylak70dcb632018-02-27 15:46:52 -060051 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
52 SYSTEMD_INTERFACE, "Unsubscribe");
Michael Tritz1cb127f2017-07-26 15:40:38 -050053 this->bus.call_noreply(method);
54
55 return;
56}
57
Michael Tritz1cb127f2017-07-26 15:40:38 -050058void Activation::startActivation()
59{
60 // Since the squashfs image has not yet been loaded to pnor and the
61 // RW volumes have not yet been created, we need to start the
62 // service files for each of those actions.
63
64 if (!activationProgress)
65 {
Adriana Kobylak70dcb632018-02-27 15:46:52 -060066 activationProgress = std::make_unique<ActivationProgress>(bus, path);
Michael Tritz1cb127f2017-07-26 15:40:38 -050067 }
68
69 if (!activationBlocksTransition)
70 {
71 activationBlocksTransition =
Adriana Kobylak70dcb632018-02-27 15:46:52 -060072 std::make_unique<ActivationBlocksTransition>(bus, path);
Michael Tritz1cb127f2017-07-26 15:40:38 -050073 }
74
Michael Tritz1cb127f2017-07-26 15:40:38 -050075 constexpr auto ubimountService = "obmc-flash-bios-ubimount@";
Adriana Kobylak70dcb632018-02-27 15:46:52 -060076 auto ubimountServiceFile =
77 std::string(ubimountService) + versionId + ".service";
78 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
79 SYSTEMD_INTERFACE, "StartUnit");
Michael Tritz1cb127f2017-07-26 15:40:38 -050080 method.append(ubimountServiceFile, "replace");
81 bus.call_noreply(method);
82
83 activationProgress->progress(10);
84}
85
86void Activation::finishActivation()
87{
88 activationProgress->progress(90);
Michael Tritz1cb127f2017-07-26 15:40:38 -050089
90 // Set Redundancy Priority before setting to Active
91 if (!redundancyPriority)
92 {
Adriana Kobylak70dcb632018-02-27 15:46:52 -060093 redundancyPriority =
94 std::make_unique<RedundancyPriority>(bus, path, *this, 0);
Michael Tritz1cb127f2017-07-26 15:40:38 -050095 }
96
97 activationProgress->progress(100);
98
99 activationBlocksTransition.reset(nullptr);
100 activationProgress.reset(nullptr);
101
Saqib Khan1e0aa5c2017-08-31 11:04:17 -0500102 ubiVolumesCreated = false;
Michael Tritz1cb127f2017-07-26 15:40:38 -0500103 Activation::unsubscribeFromSystemdSignals();
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500104 // Remove version object from image manager
105 Activation::deleteImageManagerObject();
Gunnar Mills9741cd12017-08-28 15:09:00 -0500106 // Create active association
107 parent.createActiveAssociation(path);
Michael Tritz1cb127f2017-07-26 15:40:38 -0500108}
109
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600110auto Activation::activation(Activations value) -> Activations
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500111{
Saqib Khan942df8a2017-06-01 14:09:27 -0500112
113 if (value != softwareServer::Activation::Activations::Active)
114 {
115 redundancyPriority.reset(nullptr);
116 }
117
Adriana Kobylak99c8c0e2017-04-17 13:39:11 -0500118 if (value == softwareServer::Activation::Activations::Activating)
119 {
Saqib Khan2cbfa032017-08-17 14:52:37 -0500120 parent.freeSpace();
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500121 softwareServer::Activation::activation(value);
122
Saqib Khan1e0aa5c2017-08-31 11:04:17 -0500123 if (ubiVolumesCreated == false)
Adriana Kobylak99c8c0e2017-04-17 13:39:11 -0500124 {
Jayanth Othayoth4016e522018-03-20 09:39:06 -0500125
126#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth4016e522018-03-20 09:39:06 -0500127 // Validate the signed image.
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500128 if (!validateSignature())
Jayanth Othayoth4016e522018-03-20 09:39:06 -0500129 {
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500130 // Cleanup
131 activationBlocksTransition.reset(nullptr);
132 activationProgress.reset(nullptr);
Jayanth Othayoth4016e522018-03-20 09:39:06 -0500133
134 return softwareServer::Activation::activation(
135 softwareServer::Activation::Activations::Failed);
136 }
137#endif
Michael Tritz1cb127f2017-07-26 15:40:38 -0500138 Activation::startActivation();
Michael Tritz9d25b602017-06-14 14:41:43 -0500139 return softwareServer::Activation::activation(value);
140 }
Saqib Khan1e0aa5c2017-08-31 11:04:17 -0500141 else if (ubiVolumesCreated == true)
Michael Tritz9d25b602017-06-14 14:41:43 -0500142 {
143 // Only when the squashfs image is finished loading AND the RW
Michael Tritz1cb127f2017-07-26 15:40:38 -0500144 // volumes have been created do we proceed with activation. To
145 // verify that this happened, we check for the mount dirs PNOR_PRSV
146 // and PNOR_RW_PREFIX_<versionid>, as well as the image dir R0.
Michael Tritz9d25b602017-06-14 14:41:43 -0500147
Michael Tritz9d25b602017-06-14 14:41:43 -0500148 if ((fs::is_directory(PNOR_PRSV)) &&
149 (fs::is_directory(PNOR_RW_PREFIX + versionId)) &&
150 (fs::is_directory(PNOR_RO_PREFIX + versionId)))
151 {
Michael Tritz1cb127f2017-07-26 15:40:38 -0500152 Activation::finishActivation();
Michael Tritz9d25b602017-06-14 14:41:43 -0500153 return softwareServer::Activation::activation(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600154 softwareServer::Activation::Activations::Active);
Michael Tritz9d25b602017-06-14 14:41:43 -0500155 }
156 else
157 {
Saqib Khancb9df4e2017-06-26 11:06:07 -0500158 activationBlocksTransition.reset(nullptr);
Michael Tritz1793b642017-06-28 18:35:58 -0500159 activationProgress.reset(nullptr);
Michael Tritz9d25b602017-06-14 14:41:43 -0500160 return softwareServer::Activation::activation(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600161 softwareServer::Activation::Activations::Failed);
Michael Tritz9d25b602017-06-14 14:41:43 -0500162 }
Adriana Kobylak55f9e832017-05-14 16:13:00 -0500163 }
Adriana Kobylak692b5552017-04-17 14:02:58 -0500164 }
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500165 else
166 {
167 activationBlocksTransition.reset(nullptr);
Michael Tritz1793b642017-06-28 18:35:58 -0500168 activationProgress.reset(nullptr);
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500169 }
Michael Tritz1cb127f2017-07-26 15:40:38 -0500170
171 return softwareServer::Activation::activation(value);
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500172}
173
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600174auto Activation::requestedActivation(RequestedActivations value)
175 -> RequestedActivations
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500176{
Saqib Khan1e0aa5c2017-08-31 11:04:17 -0500177 ubiVolumesCreated = false;
Michael Tritz9d25b602017-06-14 14:41:43 -0500178
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500179 if ((value == softwareServer::Activation::RequestedActivations::Active) &&
180 (softwareServer::Activation::requestedActivation() !=
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600181 softwareServer::Activation::RequestedActivations::Active))
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500182 {
183 if ((softwareServer::Activation::activation() ==
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600184 softwareServer::Activation::Activations::Ready) ||
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500185 (softwareServer::Activation::activation() ==
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600186 softwareServer::Activation::Activations::Failed))
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500187 {
188 Activation::activation(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600189 softwareServer::Activation::Activations::Activating);
Adriana Kobylak2fdb9312017-05-14 19:08:26 -0500190 }
191 }
Adriana Kobylak99c8c0e2017-04-17 13:39:11 -0500192 return softwareServer::Activation::requestedActivation(value);
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500193}
194
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500195void Activation::deleteImageManagerObject()
196{
197 // Get the Delete object for <versionID> inside image_manager
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600198 auto method = this->bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
199 MAPPER_INTERFACE, "GetObject");
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500200
201 method.append(path);
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600202 method.append(
203 std::vector<std::string>({"xyz.openbmc_project.Object.Delete"}));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500204 auto mapperResponseMsg = bus.call(method);
205 if (mapperResponseMsg.is_method_error())
206 {
207 log<level::ERR>("Error in Get Delete Object",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500208 entry("VERSIONPATH=%s", path.c_str()));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500209 return;
210 }
211 std::map<std::string, std::vector<std::string>> mapperResponse;
212 mapperResponseMsg.read(mapperResponse);
213 if (mapperResponse.begin() == mapperResponse.end())
214 {
215 log<level::ERR>("ERROR in reading the mapper response",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500216 entry("VERSIONPATH=%s", path.c_str()));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500217 return;
218 }
219
220 // Call the Delete object for <versionID> inside image_manager
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600221 method = this->bus.new_method_call(
222 (mapperResponse.begin()->first).c_str(), path.c_str(),
223 "xyz.openbmc_project.Object.Delete", "Delete");
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500224 mapperResponseMsg = bus.call(method);
225
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600226 // Check that the bus call didn't result in an error
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500227 if (mapperResponseMsg.is_method_error())
228 {
229 log<level::ERR>("Error in Deleting image from image manager",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500230 entry("VERSIONPATH=%s", path.c_str()));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500231 return;
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);
Michael Tritz60bc20f2017-07-29 23:32:21 -0500238 storeToFile(parent.versionId, value);
Saqib Khan2021b4c2017-06-07 14:37:36 -0500239 return softwareServer::RedundancyPriority::priority(value);
240}
241
Michael Tritz9d25b602017-06-14 14:41:43 -0500242void Activation::unitStateChange(sdbusplus::message::message& msg)
243{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600244 uint32_t newStateID{};
Michael Tritz9d25b602017-06-14 14:41:43 -0500245 sdbusplus::message::object_path newStateObjPath;
246 std::string newStateUnit{};
247 std::string newStateResult{};
248
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600249 // Read the msg and populate each variable
Michael Tritz9d25b602017-06-14 14:41:43 -0500250 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
251
Michael Tritz9d25b602017-06-14 14:41:43 -0500252 auto ubimountServiceFile =
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600253 "obmc-flash-bios-ubimount@" + versionId + ".service";
Michael Tritz9d25b602017-06-14 14:41:43 -0500254
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600255 if (newStateUnit == ubimountServiceFile && newStateResult == "done")
Michael Tritz9d25b602017-06-14 14:41:43 -0500256 {
Saqib Khan1e0aa5c2017-08-31 11:04:17 -0500257 ubiVolumesCreated = true;
Michael Tritz1793b642017-06-28 18:35:58 -0500258 activationProgress->progress(activationProgress->progress() + 50);
Michael Tritz9d25b602017-06-14 14:41:43 -0500259 }
260
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600261 if (ubiVolumesCreated)
Michael Tritz9d25b602017-06-14 14:41:43 -0500262 {
263 Activation::activation(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600264 softwareServer::Activation::Activations::Activating);
Michael Tritz9d25b602017-06-14 14:41:43 -0500265 }
266
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600267 if ((newStateUnit == ubimountServiceFile) &&
Michael Tritz9d25b602017-06-14 14:41:43 -0500268 (newStateResult == "failed" || newStateResult == "dependency"))
269 {
270 Activation::activation(softwareServer::Activation::Activations::Failed);
271 }
272
273 return;
274}
275
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500276#ifdef WANT_SIGNATURE_VERIFY
277inline bool Activation::validateSignature()
278{
279 using Signature = openpower::software::image::Signature;
280 fs::path imageDir(IMG_DIR);
281
282 Signature signature(imageDir / versionId, PNOR_SIGNED_IMAGE_CONF_PATH);
283
284 // Validate the signed image.
285 if (signature.verify())
286 {
287 return true;
288 }
289 // Log error and continue activation process, if field mode disabled.
290 log<level::ERR>("Error occurred during image validation");
291 report<InternalFailure>();
292
293 try
294 {
295 if (!fieldModeEnabled())
296 {
297 return true;
298 }
299 }
300 catch (const InternalFailure& e)
301 {
302 report<InternalFailure>();
303 }
304 return false;
305}
306
307bool Activation::fieldModeEnabled()
308{
309 auto fieldModeSvc = getService(bus, FIELDMODE_PATH, FIELDMODE_INTERFACE);
310
311 auto method = bus.new_method_call(fieldModeSvc.c_str(), FIELDMODE_PATH,
312 "org.freedesktop.DBus.Properties", "Get");
313
314 method.append(FIELDMODE_INTERFACE, "FieldModeEnabled");
315 auto reply = bus.call(method);
316 if (reply.is_method_error())
317 {
318 log<level::ERR>("Error in fieldModeEnabled getValue");
319 elog<InternalFailure>();
320 }
321 sdbusplus::message::variant<bool> fieldMode;
322 reply.read(fieldMode);
323
324 return (fieldMode.get<bool>());
325}
326
327std::string Activation::getService(sdbusplus::bus::bus& bus,
328 const std::string& path,
329 const std::string& intf)
330{
331 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
332 MAPPER_INTERFACE, "GetObject");
333
334 mapperCall.append(path);
335 mapperCall.append(std::vector<std::string>({intf}));
336
337 auto mapperResponseMsg = bus.call(mapperCall);
338
339 if (mapperResponseMsg.is_method_error())
340 {
341 log<level::ERR>("ERROR in getting service",
342 entry("PATH=%s", path.c_str()),
343 entry("INTERFACE=%s", intf.c_str()));
344
345 elog<InternalFailure>();
346 }
347
348 std::map<std::string, std::vector<std::string>> mapperResponse;
349 mapperResponseMsg.read(mapperResponse);
350
351 if (mapperResponse.begin() == mapperResponse.end())
352 {
353 log<level::ERR>("ERROR reading mapper response",
354 entry("PATH=%s", path.c_str()),
355 entry("INTERFACE=%s", intf.c_str()));
356
357 elog<InternalFailure>();
358 }
359 return mapperResponse.begin()->first;
360}
361#endif
362
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500363} // namespace updater
364} // namespace software
365} // namespace openpower