blob: ce8cd077b9290819dec7535bc65aa2787e17d3b3 [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
7#include <experimental/filesystem>
Saqib Khan7f80e0b2017-10-22 11:29:07 -05008#include <phosphor-logging/log.hpp>
Gunnar Mills74b657e2018-07-13 09:27:31 -05009#include <sdbusplus/exception.hpp>
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -050010
Jayanth Othayoth4016e522018-03-20 09:39:06 -050011#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth4016e522018-03-20 09:39:06 -050012#include "image_verify.hpp"
Gunnar Millsf6ed5892018-09-07 17:08:02 -050013
14#include <phosphor-logging/elog-errors.hpp>
15#include <phosphor-logging/elog.hpp>
16#include <sdbusplus/server.hpp>
17#include <xyz/openbmc_project/Common/error.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;
Saqib Khan7f80e0b2017-10-22 11:29:07 -050032
Jayanth Othayoth4016e522018-03-20 09:39:06 -050033#ifdef WANT_SIGNATURE_VERIFY
34using InternalFailure =
35 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Jayanth Othayoth11271fb2018-03-29 10:25:50 -050036
37// Field mode path and interface.
38constexpr auto FIELDMODE_PATH("/xyz/openbmc_project/software");
39constexpr auto FIELDMODE_INTERFACE("xyz.openbmc_project.Control.FieldMode");
Jayanth Othayoth4016e522018-03-20 09:39:06 -050040#endif
41
Adriana Kobylak70dcb632018-02-27 15:46:52 -060042constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
43constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
Michael Tritz9d25b602017-06-14 14:41:43 -050044
45void Activation::subscribeToSystemdSignals()
46{
Adriana Kobylak70dcb632018-02-27 15:46:52 -060047 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
48 SYSTEMD_INTERFACE, "Subscribe");
Gunnar Mills74b657e2018-07-13 09:27:31 -050049 try
50 {
51 this->bus.call_noreply(method);
52 }
53 catch (const SdBusError& e)
54 {
55 if (e.name() != nullptr &&
56 strcmp("org.freedesktop.systemd1.AlreadySubscribed", e.name()) == 0)
57 {
58 // If an Activation attempt fails, the Unsubscribe method is not
59 // called. This may lead to an AlreadySubscribed error if the
60 // Activation is re-attempted.
61 }
62 else
63 {
64 log<level::ERR>("Error subscribing to systemd",
65 entry("ERROR=%s", e.what()));
66 }
67 }
Michael Tritz9d25b602017-06-14 14:41:43 -050068 return;
69}
70
Michael Tritz1cb127f2017-07-26 15:40:38 -050071void Activation::unsubscribeFromSystemdSignals()
72{
Adriana Kobylak70dcb632018-02-27 15:46:52 -060073 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
74 SYSTEMD_INTERFACE, "Unsubscribe");
Michael Tritz1cb127f2017-07-26 15:40:38 -050075 this->bus.call_noreply(method);
76
77 return;
78}
79
Adriana Kobylak70dcb632018-02-27 15:46:52 -060080auto Activation::requestedActivation(RequestedActivations value)
81 -> RequestedActivations
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050082{
83 if ((value == softwareServer::Activation::RequestedActivations::Active) &&
84 (softwareServer::Activation::requestedActivation() !=
Adriana Kobylak70dcb632018-02-27 15:46:52 -060085 softwareServer::Activation::RequestedActivations::Active))
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050086 {
87 if ((softwareServer::Activation::activation() ==
Adriana Kobylak70dcb632018-02-27 15:46:52 -060088 softwareServer::Activation::Activations::Ready) ||
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050089 (softwareServer::Activation::activation() ==
Adriana Kobylak70dcb632018-02-27 15:46:52 -060090 softwareServer::Activation::Activations::Failed))
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050091 {
92 Activation::activation(
Adriana Kobylak70dcb632018-02-27 15:46:52 -060093 softwareServer::Activation::Activations::Activating);
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050094 }
95 }
Adriana Kobylak99c8c0e2017-04-17 13:39:11 -050096 return softwareServer::Activation::requestedActivation(value);
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -050097}
98
Saqib Khan7f80e0b2017-10-22 11:29:07 -050099void Activation::deleteImageManagerObject()
100{
101 // Get the Delete object for <versionID> inside image_manager
Lei YUc9caf862019-01-24 15:40:25 +0800102 constexpr auto versionServiceStr = "xyz.openbmc_project.Software.Version";
103 constexpr auto deleteInterface = "xyz.openbmc_project.Object.Delete";
104 std::string versionService;
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600105 auto method = this->bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
106 MAPPER_INTERFACE, "GetObject");
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500107
108 method.append(path);
Lei YUc9caf862019-01-24 15:40:25 +0800109 method.append(std::vector<std::string>({deleteInterface}));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500110 auto mapperResponseMsg = bus.call(method);
111 if (mapperResponseMsg.is_method_error())
112 {
113 log<level::ERR>("Error in Get Delete Object",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500114 entry("VERSIONPATH=%s", path.c_str()));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500115 return;
116 }
117 std::map<std::string, std::vector<std::string>> mapperResponse;
118 mapperResponseMsg.read(mapperResponse);
119 if (mapperResponse.begin() == mapperResponse.end())
120 {
121 log<level::ERR>("ERROR in reading the mapper response",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500122 entry("VERSIONPATH=%s", path.c_str()));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500123 return;
124 }
125
Lei YUc9caf862019-01-24 15:40:25 +0800126 // We need to find the phosphor-software-manager's version service
127 // to invoke the delete interface
128 for (auto resp : mapperResponse)
129 {
130 if (resp.first.find(versionServiceStr) != std::string::npos)
131 {
132 versionService = resp.first;
133 }
134 }
135
136 if (versionService.empty())
137 {
138 log<level::ERR>("Error finding version service");
139 return;
140 }
141
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500142 // Call the Delete object for <versionID> inside image_manager
Lei YUc9caf862019-01-24 15:40:25 +0800143 method = this->bus.new_method_call(versionService.c_str(), path.c_str(),
144 deleteInterface, "Delete");
Adriana Kobylakab435df2018-07-16 11:37:19 -0500145 try
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500146 {
Adriana Kobylakab435df2018-07-16 11:37:19 -0500147 auto mapperResponseMsg = bus.call(method);
148
149 // Check that the bus call didn't result in an error
150 if (mapperResponseMsg.is_method_error())
151 {
152 log<level::ERR>("Error in Deleting image from image manager",
153 entry("VERSIONPATH=%s", path.c_str()));
154 return;
155 }
156 }
157 catch (const SdBusError& e)
158 {
159 if (e.name() != nullptr && strcmp("System.Error.ELOOP", e.name()) == 0)
160 {
161 // TODO: Error being tracked with openbmc/openbmc#3311
162 }
163 else
164 {
165 log<level::ERR>("Error performing call to Delete object path",
166 entry("ERROR=%s", e.what()),
167 entry("PATH=%s", path.c_str()));
168 }
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500169 return;
170 }
171}
172
Saqib Khan2021b4c2017-06-07 14:37:36 -0500173uint8_t RedundancyPriority::priority(uint8_t value)
174{
Saqib Khanb8e7f312017-08-12 10:24:10 -0500175 parent.parent.freePriority(value, parent.versionId);
Saqib Khan2021b4c2017-06-07 14:37:36 -0500176 return softwareServer::RedundancyPriority::priority(value);
177}
178
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500179#ifdef WANT_SIGNATURE_VERIFY
Lei YU9b21efc2019-02-21 15:52:53 +0800180bool Activation::validateSignature()
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500181{
182 using Signature = openpower::software::image::Signature;
183 fs::path imageDir(IMG_DIR);
184
185 Signature signature(imageDir / versionId, PNOR_SIGNED_IMAGE_CONF_PATH);
186
187 // Validate the signed image.
188 if (signature.verify())
189 {
190 return true;
191 }
192 // Log error and continue activation process, if field mode disabled.
193 log<level::ERR>("Error occurred during image validation");
194 report<InternalFailure>();
195
196 try
197 {
198 if (!fieldModeEnabled())
199 {
200 return true;
201 }
202 }
203 catch (const InternalFailure& e)
204 {
205 report<InternalFailure>();
206 }
207 return false;
208}
209
210bool Activation::fieldModeEnabled()
211{
212 auto fieldModeSvc = getService(bus, FIELDMODE_PATH, FIELDMODE_INTERFACE);
213
214 auto method = bus.new_method_call(fieldModeSvc.c_str(), FIELDMODE_PATH,
215 "org.freedesktop.DBus.Properties", "Get");
216
217 method.append(FIELDMODE_INTERFACE, "FieldModeEnabled");
218 auto reply = bus.call(method);
219 if (reply.is_method_error())
220 {
221 log<level::ERR>("Error in fieldModeEnabled getValue");
222 elog<InternalFailure>();
223 }
224 sdbusplus::message::variant<bool> fieldMode;
225 reply.read(fieldMode);
226
William A. Kennington III17f55a82018-11-27 15:22:05 -0800227 return sdbusplus::message::variant_ns::get<bool>(fieldMode);
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500228}
229
230std::string Activation::getService(sdbusplus::bus::bus& bus,
231 const std::string& path,
232 const std::string& intf)
233{
234 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
235 MAPPER_INTERFACE, "GetObject");
236
237 mapperCall.append(path);
238 mapperCall.append(std::vector<std::string>({intf}));
239
240 auto mapperResponseMsg = bus.call(mapperCall);
241
242 if (mapperResponseMsg.is_method_error())
243 {
244 log<level::ERR>("ERROR in getting service",
245 entry("PATH=%s", path.c_str()),
246 entry("INTERFACE=%s", intf.c_str()));
247
248 elog<InternalFailure>();
249 }
250
251 std::map<std::string, std::vector<std::string>> mapperResponse;
252 mapperResponseMsg.read(mapperResponse);
253
254 if (mapperResponse.begin() == mapperResponse.end())
255 {
256 log<level::ERR>("ERROR reading mapper response",
257 entry("PATH=%s", path.c_str()),
258 entry("INTERFACE=%s", intf.c_str()));
259
260 elog<InternalFailure>();
261 }
262 return mapperResponse.begin()->first;
263}
264#endif
265
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500266} // namespace updater
267} // namespace software
268} // namespace openpower