blob: 8bd868b31219a8c66965bc6a213ae0319415f947 [file] [log] [blame]
Saqib Khan35e83f32017-05-22 11:37:32 -05001#include <fstream>
Gunnar Millsec1b41c2017-05-02 12:20:36 -05002#include <string>
Gunnar Mills2ce7da22017-05-04 15:37:56 -05003#include <phosphor-logging/log.hpp>
Gunnar Millsec1b41c2017-05-02 12:20:36 -05004#include "config.h"
Gunnar Mills2ce7da22017-05-04 15:37:56 -05005#include "item_updater.hpp"
6#include "xyz/openbmc_project/Software/Version/server.hpp"
Saqib Khan35e83f32017-05-22 11:37:32 -05007#include <experimental/filesystem>
Saqib Khan705f1bf2017-06-09 23:58:38 -05008#include "version.hpp"
Gunnar Millsec1b41c2017-05-02 12:20:36 -05009
10namespace phosphor
11{
12namespace software
13{
14namespace updater
15{
16
Gunnar Mills2ce7da22017-05-04 15:37:56 -050017// When you see server:: you know we're referencing our base class
18namespace server = sdbusplus::xyz::openbmc_project::Software::server;
19
20using namespace phosphor::logging;
Saqib Khan35e83f32017-05-22 11:37:32 -050021namespace fs = std::experimental::filesystem;
22
Michael Tritzb1cfdf92017-08-14 14:33:30 -050023const std::vector<std::string> bmcImages = {"image-kernel",
24 "image-rofs",
25 "image-rwfs",
26 "image-u-boot"};
Gunnar Mills2ce7da22017-05-04 15:37:56 -050027
Patrick Williamse75d10f2017-05-30 16:56:32 -050028void ItemUpdater::createActivation(sdbusplus::message::message& msg)
Gunnar Millsec1b41c2017-05-02 12:20:36 -050029{
Saqib Khan84a0e692017-06-28 17:27:01 -050030
31 using SVersion = server::Version;
32 using VersionPurpose = SVersion::VersionPurpose;
33 namespace mesg = sdbusplus::message;
34 namespace variant_ns = mesg::variant_ns;
35
36 mesg::object_path objPath;
37 auto purpose = VersionPurpose::Unknown;
Saqib Khan705f1bf2017-06-09 23:58:38 -050038 std::string version;
Gunnar Mills2ce7da22017-05-04 15:37:56 -050039 std::map<std::string,
Patrick Williamse75d10f2017-05-30 16:56:32 -050040 std::map<std::string,
Saqib Khan84a0e692017-06-28 17:27:01 -050041 mesg::variant<std::string>>> interfaces;
Patrick Williamse75d10f2017-05-30 16:56:32 -050042 msg.read(objPath, interfaces);
Gunnar Mills2ce7da22017-05-04 15:37:56 -050043 std::string path(std::move(objPath));
Saqib Khan19177d32017-06-20 08:11:49 -050044 std::string filePath;
Gunnar Mills2ce7da22017-05-04 15:37:56 -050045
46 for (const auto& intf : interfaces)
47 {
Saqib Khan705f1bf2017-06-09 23:58:38 -050048 if (intf.first == VERSION_IFACE)
Gunnar Mills2ce7da22017-05-04 15:37:56 -050049 {
Saqib Khan705f1bf2017-06-09 23:58:38 -050050 for (const auto& property : intf.second)
Gunnar Mills2ce7da22017-05-04 15:37:56 -050051 {
Saqib Khan705f1bf2017-06-09 23:58:38 -050052 if (property.first == "Purpose")
Gunnar Mills2ce7da22017-05-04 15:37:56 -050053 {
Saqib Khan84a0e692017-06-28 17:27:01 -050054 auto value = SVersion::convertVersionPurposeFromString(
55 variant_ns::get<std::string>(property.second));
56 if (value == VersionPurpose::BMC ||
57 value == VersionPurpose::System)
58 {
59 purpose = value;
60 }
Saqib Khan705f1bf2017-06-09 23:58:38 -050061 }
62 else if (property.first == "Version")
63 {
Saqib Khan84a0e692017-06-28 17:27:01 -050064 version = variant_ns::get<std::string>(property.second);
Gunnar Mills2ce7da22017-05-04 15:37:56 -050065 }
66 }
67 }
Saqib Khan19177d32017-06-20 08:11:49 -050068 else if (intf.first == FILEPATH_IFACE)
69 {
70 for (const auto& property : intf.second)
71 {
72 if (property.first == "Path")
73 {
Saqib Khan84a0e692017-06-28 17:27:01 -050074 filePath = variant_ns::get<std::string>(property.second);
Saqib Khan19177d32017-06-20 08:11:49 -050075 }
76 }
77 }
Gunnar Mills2ce7da22017-05-04 15:37:56 -050078 }
Saqib Khan705f1bf2017-06-09 23:58:38 -050079 if (version.empty() ||
Saqib Khan19177d32017-06-20 08:11:49 -050080 filePath.empty() ||
Saqib Khan84a0e692017-06-28 17:27:01 -050081 purpose == VersionPurpose::Unknown)
Saqib Khan705f1bf2017-06-09 23:58:38 -050082 {
83 return;
84 }
Gunnar Mills2ce7da22017-05-04 15:37:56 -050085
86 // Version id is the last item in the path
87 auto pos = path.rfind("/");
88 if (pos == std::string::npos)
89 {
90 log<level::ERR>("No version id found in object path",
91 entry("OBJPATH=%s", path));
Patrick Williamse75d10f2017-05-30 16:56:32 -050092 return;
Gunnar Mills2ce7da22017-05-04 15:37:56 -050093 }
94
95 auto versionId = path.substr(pos + 1);
96
Patrick Williamse75d10f2017-05-30 16:56:32 -050097 if (activations.find(versionId) == activations.end())
Gunnar Mills2ce7da22017-05-04 15:37:56 -050098 {
Saqib Khan35e83f32017-05-22 11:37:32 -050099 // Determine the Activation state by processing the given image dir.
100 auto activationState = server::Activation::Activations::Invalid;
101 ItemUpdater::ActivationStatus result = ItemUpdater::
Saqib Khan19177d32017-06-20 08:11:49 -0500102 validateSquashFSImage(filePath);
Saqib Khan35e83f32017-05-22 11:37:32 -0500103 if (result == ItemUpdater::ActivationStatus::ready)
104 {
105 activationState = server::Activation::Activations::Ready;
106 }
Saqib Khan35e83f32017-05-22 11:37:32 -0500107 activations.insert(std::make_pair(
Saqib Khan705f1bf2017-06-09 23:58:38 -0500108 versionId,
109 std::make_unique<Activation>(
110 bus,
111 path,
Saqib Khan4c1aec02017-07-06 11:46:13 -0500112 *this,
Saqib Khan35e83f32017-05-22 11:37:32 -0500113 versionId,
Saqib Khan705f1bf2017-06-09 23:58:38 -0500114 activationState)));
115 versions.insert(std::make_pair(
116 versionId,
117 std::make_unique<phosphor::software::
118 manager::Version>(
119 bus,
120 path,
121 version,
122 purpose,
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500123 filePath,
124 std::bind(&ItemUpdater::erase,
125 this,
126 std::placeholders::_1))));
Gunnar Mills2ce7da22017-05-04 15:37:56 -0500127 }
Saqib Khan7b5010f2017-08-09 10:03:11 -0500128 else
129 {
130 log<level::INFO>("Software Object with the same version already exists",
131 entry("VERSION_ID=%s", versionId));
132 }
Patrick Williamse75d10f2017-05-30 16:56:32 -0500133 return;
Gunnar Millsec1b41c2017-05-02 12:20:36 -0500134}
135
Saqib Khanba239882017-05-26 08:41:54 -0500136void ItemUpdater::processBMCImage()
137{
138 auto purpose = server::Version::VersionPurpose::BMC;
139 auto version = phosphor::software::manager::Version::getBMCVersion();
140 auto id = phosphor::software::manager::Version::getId(version);
141 auto path = std::string{SOFTWARE_OBJPATH} + '/' + id;
142 activations.insert(std::make_pair(
143 id,
144 std::make_unique<Activation>(
145 bus,
146 path,
Saqib Khan4c1aec02017-07-06 11:46:13 -0500147 *this,
Saqib Khanba239882017-05-26 08:41:54 -0500148 id,
149 server::Activation::Activations::Active)));
150 versions.insert(std::make_pair(
151 id,
152 std::make_unique<phosphor::software::
153 manager::Version>(
154 bus,
155 path,
156 version,
157 purpose,
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500158 "",
159 std::bind(&ItemUpdater::erase,
160 this,
161 std::placeholders::_1))));
162
Saqib Khanba239882017-05-26 08:41:54 -0500163 return;
164}
165
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500166void ItemUpdater::erase(std::string entryId)
167{
168 // Delete ReadWrite and ReadOnly partitions
169 removeReadWritePartition(entryId);
170 removeReadOnlyPartition(entryId);
171
172 // Removing entry in versions map
173 auto it = versions.find(entryId);
174 if (it == versions.end())
175 {
176 log<level::ERR>(("Error: Failed to find version " + entryId + \
177 " in item updater versions map." \
178 " Unable to remove.").c_str());
179 return;
180 }
181 this->versions.erase(entryId);
182
183 // Removing entry in activations map
184 auto ita = activations.find(entryId);
185 if (ita == activations.end())
186 {
187 log<level::ERR>(("Error: Failed to find version " + entryId + \
188 " in item updater activations map." \
189 " Unable to remove.").c_str());
190 return;
191 }
192 // TODO: openbmc/openbmc#1986
193 // Test if this is the currently running image
194 // If not, don't continue.
195
196 this->activations.erase(entryId);
197}
198
Saqib Khan35e83f32017-05-22 11:37:32 -0500199ItemUpdater::ActivationStatus ItemUpdater::validateSquashFSImage(
Saqib Khan19177d32017-06-20 08:11:49 -0500200 const std::string& filePath)
Saqib Khan35e83f32017-05-22 11:37:32 -0500201{
Michael Tritzb1cfdf92017-08-14 14:33:30 -0500202 bool invalid = false;
Saqib Khan35e83f32017-05-22 11:37:32 -0500203
Michael Tritzb1cfdf92017-08-14 14:33:30 -0500204 for (auto& bmcImage : bmcImages)
Saqib Khan35e83f32017-05-22 11:37:32 -0500205 {
Michael Tritzb1cfdf92017-08-14 14:33:30 -0500206 fs::path file(filePath);
207 file /= bmcImage;
208 std::ifstream efile(file.c_str());
209 if (efile.good() != 1)
210 {
211 log<level::ERR>("Failed to find the BMC image.",
212 entry("IMAGE=%s", bmcImage.c_str()));
213 invalid = true;
214 }
Saqib Khan35e83f32017-05-22 11:37:32 -0500215 }
Michael Tritzb1cfdf92017-08-14 14:33:30 -0500216
217 if (invalid)
Saqib Khan35e83f32017-05-22 11:37:32 -0500218 {
Saqib Khan35e83f32017-05-22 11:37:32 -0500219 return ItemUpdater::ActivationStatus::invalid;
220 }
Michael Tritzb1cfdf92017-08-14 14:33:30 -0500221
222 return ItemUpdater::ActivationStatus::ready;
Saqib Khan35e83f32017-05-22 11:37:32 -0500223}
224
Saqib Khan4c1aec02017-07-06 11:46:13 -0500225void ItemUpdater::freePriority(uint8_t value)
226{
227 //TODO openbmc/openbmc#1896 Improve the performance of this function
228 for (const auto& intf : activations)
229 {
230 if(intf.second->redundancyPriority)
231 {
232 if (intf.second->redundancyPriority.get()->priority() == value)
233 {
234 intf.second->redundancyPriority.get()->priority(value+1);
235 }
236 }
237 }
238}
239
Michael Tritz37a59042017-07-12 13:44:53 -0500240void ItemUpdater::reset()
241{
242 // Mark the read-write partition for recreation upon reboot.
243 auto method = bus.new_method_call(
244 SYSTEMD_BUSNAME,
245 SYSTEMD_PATH,
246 SYSTEMD_INTERFACE,
247 "StartUnit");
248 method.append("obmc-flash-bmc-setenv@rwreset=true.service", "replace");
249 bus.call_noreply(method);
250
251 log<level::INFO>("BMC factory reset will take effect upon reboot.");
252
253 return;
254}
255
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500256void ItemUpdater::removeReadOnlyPartition(std::string versionId)
257{
258 auto serviceFile = "obmc-flash-bmc-ubiro-remove@" + versionId +
259 ".service";
260
261 // Remove the read-only partitions.
262 auto method = bus.new_method_call(
263 SYSTEMD_BUSNAME,
264 SYSTEMD_PATH,
265 SYSTEMD_INTERFACE,
266 "StartUnit");
267 method.append(serviceFile, "replace");
268 bus.call_noreply(method);
269}
270
271void ItemUpdater::removeReadWritePartition(std::string versionId)
272{
273 auto serviceFile = "obmc-flash-bmc-ubirw-remove.service";
274
275 // Remove the read-write partitions.
276 auto method = bus.new_method_call(
277 SYSTEMD_BUSNAME,
278 SYSTEMD_PATH,
279 SYSTEMD_INTERFACE,
280 "StartUnit");
281 method.append(serviceFile, "replace");
282 bus.call_noreply(method);
283}
284
Gunnar Millsec1b41c2017-05-02 12:20:36 -0500285} // namespace updater
286} // namespace software
287} // namespace phosphor