blob: fa1c38dcce39138a3a76f5a66315a8e17609f86e [file] [log] [blame]
Saqib Khan7254f0e2017-04-10 21:45:37 -05001#include <string>
Adriana Kobylak5ba6b102017-05-19 09:41:27 -05002#include <experimental/filesystem>
Saqib Khan7254f0e2017-04-10 21:45:37 -05003#include <fstream>
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -05004#include <phosphor-logging/log.hpp>
Adriana Kobylakd6a549e2017-05-10 16:23:01 -05005#include <xyz/openbmc_project/Software/Version/server.hpp>
Adriana Kobylak2d8fa222017-03-15 12:34:32 -05006#include "config.h"
7#include "item_updater.hpp"
Saqib Khana8ade7e2017-04-12 10:27:56 -05008#include "activation.hpp"
Adriana Kobylak2d8fa222017-03-15 12:34:32 -05009
10namespace openpower
11{
12namespace software
13{
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -050014namespace updater
Adriana Kobylak2d8fa222017-03-15 12:34:32 -050015{
16
Saqib Khana8ade7e2017-04-12 10:27:56 -050017// When you see server:: you know we're referencing our base class
18namespace server = sdbusplus::xyz::openbmc_project::Software::server;
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050019namespace fs = std::experimental::filesystem;
Saqib Khana8ade7e2017-04-12 10:27:56 -050020
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050021using namespace phosphor::logging;
22
Saqib Khana8ade7e2017-04-12 10:27:56 -050023constexpr auto squashFSImage = "pnor.xz.squashfs";
24
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050025void ItemUpdater::createActivation(sdbusplus::message::message& m)
Adriana Kobylak2d8fa222017-03-15 12:34:32 -050026{
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050027 sdbusplus::message::object_path objPath;
28 std::map<std::string,
29 std::map<std::string,
30 sdbusplus::message::variant<std::string>>> interfaces;
31 m.read(objPath, interfaces);
32 std::string path(std::move(objPath));
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050033
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050034 std::string filePath;
35
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050036 for (const auto& intf : interfaces)
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050037 {
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050038 if (intf.first == VERSION_IFACE)
39 {
40 for (const auto& property : intf.second)
41 {
42 if (property.first == "Purpose")
43 {
44 // Only process the Host and System images
45 std::string value = sdbusplus::message::variant_ns::get<
46 std::string>(property.second);
47 if ((value != convertForMessage(
48 server::Version::VersionPurpose::Host)) &&
49 (value != convertForMessage(
50 server::Version::VersionPurpose::System)))
51 {
52 return;
53 }
54 }
55 }
56 }
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050057 else if (intf.first == FILEPATH_IFACE)
58 {
59 for (const auto& property : intf.second)
60 {
61 if (property.first == "Path")
62 {
63 filePath = sdbusplus::message::variant_ns::get<
64 std::string>(property.second);
65 }
66 }
67 }
68 }
69 if (filePath.empty())
70 {
71 return;
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050072 }
73
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050074 // Version id is the last item in the path
75 auto pos = path.rfind("/");
76 if (pos == std::string::npos)
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050077 {
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050078 log<level::ERR>("No version id found in object path",
79 entry("OBJPATH=%s", path));
80 return;
81 }
82
83 auto versionId = path.substr(pos + 1);
84
85 if (activations.find(versionId) == activations.end())
86 {
87 // Determine the Activation state by processing the given image dir.
88 auto activationState = server::Activation::Activations::Invalid;
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050089 if (ItemUpdater::validateSquashFSImage(filePath) == 0)
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050090 {
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050091 activationState = server::Activation::Activations::Ready;
92
93 // Load the squashfs image to pnor so that it is available to be
94 // activated when requested.
95 // This is done since the image on the BMC can be removed.
96 constexpr auto squashfsMountService =
97 "obmc-flash-bios-squashfsmount@";
98 auto squashfsMountServiceFile =
99 std::string(squashfsMountService) +
100 versionId +
101 ".service";
102 auto method = bus.new_method_call(
103 SYSTEMD_BUSNAME,
104 SYSTEMD_PATH,
105 SYSTEMD_INTERFACE,
106 "StartUnit");
107 method.append(squashfsMountServiceFile, "replace");
108 bus.call_noreply(method);
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -0500109 }
110
Adriana Kobylak5ba6b102017-05-19 09:41:27 -0500111 fs::path manifestPath(filePath);
112 manifestPath /= MANIFEST_FILE;
113 auto extendedVersion = ItemUpdater::getExtendedVersion(manifestPath);
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500114 activations.insert(std::make_pair(
115 versionId,
116 std::make_unique<Activation>(
117 bus,
118 path,
119 versionId,
120 extendedVersion,
121 activationState)));
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -0500122 }
Patrick Williams3accb322017-05-30 16:29:52 -0500123 return;
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500124}
125
Saqib Khan7254f0e2017-04-10 21:45:37 -0500126std::string ItemUpdater::getExtendedVersion(const std::string& manifestFilePath)
127{
128 constexpr auto extendedVersionKey = "extended_version=";
129 constexpr auto extendedVersionKeySize = strlen(extendedVersionKey);
130
131 if (manifestFilePath.empty())
132 {
133 log<level::ERR>("Error MANIFESTFilePath is empty");
134 throw std::runtime_error("MANIFESTFilePath is empty");
135 }
136
137 std::string extendedVersion{};
138 std::ifstream efile;
139 std::string line;
140 efile.exceptions(std::ifstream::failbit
141 | std::ifstream::badbit
142 | std::ifstream::eofbit);
143
144 try
145 {
146 efile.open(manifestFilePath);
147 while (getline(efile, line))
148 {
149 if (line.compare(0, extendedVersionKeySize,
150 extendedVersionKey) == 0)
151 {
152 extendedVersion = line.substr(extendedVersionKeySize);
153 break;
154 }
155 }
156 efile.close();
157 }
158 catch (const std::exception& e)
159 {
160 log<level::ERR>("Error in reading Host MANIFEST file");
161 }
Saqib Khan7254f0e2017-04-10 21:45:37 -0500162 return extendedVersion;
163}
164
Adriana Kobylak5ba6b102017-05-19 09:41:27 -0500165int ItemUpdater::validateSquashFSImage(const std::string& filePath)
Saqib Khana8ade7e2017-04-12 10:27:56 -0500166{
Adriana Kobylak5ba6b102017-05-19 09:41:27 -0500167 fs::path file(filePath);
168 file /= squashFSImage;
Saqib Khana8ade7e2017-04-12 10:27:56 -0500169 std::ifstream efile(file.c_str());
170
171 if (efile.good() == 1)
172 {
173 return 0;
174 }
175 else
176 {
177 log<level::ERR>("Failed to find the SquashFS image.");
178 return -1;
179 }
180}
181
Michael Tritzdd961b62017-05-17 14:07:03 -0500182void ItemUpdater::reset()
183{
184 for(const auto& it : activations)
185 {
186 auto serviceFile = "obmc-flash-bios-ubiumount-rw@" + it.first +
187 ".service";
188
189 // Remove the read-write partitions.
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500190 auto method = bus.new_method_call(
Michael Tritzdd961b62017-05-17 14:07:03 -0500191 SYSTEMD_BUSNAME,
192 SYSTEMD_PATH,
193 SYSTEMD_INTERFACE,
194 "StartUnit");
195 method.append(serviceFile, "replace");
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500196 bus.call_noreply(method);
Michael Tritzdd961b62017-05-17 14:07:03 -0500197 }
198
199 // Remove the preserved partition.
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500200 auto method = bus.new_method_call(
Michael Tritzdd961b62017-05-17 14:07:03 -0500201 SYSTEMD_BUSNAME,
202 SYSTEMD_PATH,
203 SYSTEMD_INTERFACE,
204 "StartUnit");
205 method.append("obmc-flash-bios-ubiumount-prsv.service", "replace");
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500206 bus.call_noreply(method);
Michael Tritzdd961b62017-05-17 14:07:03 -0500207
208 return;
209}
210
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500211} // namespace updater
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500212} // namespace software
213} // namespace openpower