blob: 2caacfe292daaa7c33a7827d89d0ad1d11ffe060 [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{
Patrick Williamse4290942017-06-16 05:43:08 -050027 using SVersion = server::Version;
28 using VersionPurpose = SVersion::VersionPurpose;
29 namespace msg = sdbusplus::message;
30 namespace variant_ns = msg::variant_ns;
31
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050032 sdbusplus::message::object_path objPath;
33 std::map<std::string,
Patrick Williamse4290942017-06-16 05:43:08 -050034 std::map<std::string, msg::variant<std::string>>> interfaces;
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050035 m.read(objPath, interfaces);
Patrick Williamse4290942017-06-16 05:43:08 -050036
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050037 std::string path(std::move(objPath));
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050038 std::string filePath;
Patrick Williamse4290942017-06-16 05:43:08 -050039 auto purpose = VersionPurpose::Unknown;
Saqib Khance148702017-06-11 12:01:58 -050040 std::string version;
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050041
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050042 for (const auto& intf : interfaces)
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050043 {
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050044 if (intf.first == VERSION_IFACE)
45 {
46 for (const auto& property : intf.second)
47 {
48 if (property.first == "Purpose")
49 {
50 // Only process the Host and System images
Patrick Williamse4290942017-06-16 05:43:08 -050051 auto value = SVersion::convertVersionPurposeFromString(
52 variant_ns::get<std::string>(property.second));
53
54 if (value == VersionPurpose::Host ||
55 value == VersionPurpose::System)
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050056 {
Saqib Khance148702017-06-11 12:01:58 -050057 purpose = value;
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050058 }
59 }
Saqib Khance148702017-06-11 12:01:58 -050060 else if (property.first == "Version")
61 {
Patrick Williamse4290942017-06-16 05:43:08 -050062 version = variant_ns::get<std::string>(property.second);
Saqib Khance148702017-06-11 12:01:58 -050063 }
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050064 }
65 }
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050066 else if (intf.first == FILEPATH_IFACE)
67 {
68 for (const auto& property : intf.second)
69 {
70 if (property.first == "Path")
71 {
Patrick Williamse4290942017-06-16 05:43:08 -050072 filePath = variant_ns::get<std::string>(property.second);
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050073 }
74 }
75 }
76 }
Patrick Williamse4290942017-06-16 05:43:08 -050077 if ((filePath.empty()) || (purpose == VersionPurpose::Unknown))
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050078 {
79 return;
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050080 }
81
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050082 // Version id is the last item in the path
83 auto pos = path.rfind("/");
84 if (pos == std::string::npos)
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050085 {
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050086 log<level::ERR>("No version id found in object path",
87 entry("OBJPATH=%s", path));
88 return;
89 }
90
91 auto versionId = path.substr(pos + 1);
92
93 if (activations.find(versionId) == activations.end())
94 {
95 // Determine the Activation state by processing the given image dir.
96 auto activationState = server::Activation::Activations::Invalid;
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050097 if (ItemUpdater::validateSquashFSImage(filePath) == 0)
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050098 {
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050099 activationState = server::Activation::Activations::Ready;
100
101 // Load the squashfs image to pnor so that it is available to be
102 // activated when requested.
103 // This is done since the image on the BMC can be removed.
104 constexpr auto squashfsMountService =
105 "obmc-flash-bios-squashfsmount@";
106 auto squashfsMountServiceFile =
107 std::string(squashfsMountService) +
108 versionId +
109 ".service";
110 auto method = bus.new_method_call(
111 SYSTEMD_BUSNAME,
112 SYSTEMD_PATH,
113 SYSTEMD_INTERFACE,
114 "StartUnit");
115 method.append(squashfsMountServiceFile, "replace");
116 bus.call_noreply(method);
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -0500117 }
118
Adriana Kobylak5ba6b102017-05-19 09:41:27 -0500119 fs::path manifestPath(filePath);
120 manifestPath /= MANIFEST_FILE;
121 auto extendedVersion = ItemUpdater::getExtendedVersion(manifestPath);
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500122 activations.insert(std::make_pair(
123 versionId,
124 std::make_unique<Activation>(
125 bus,
126 path,
127 versionId,
128 extendedVersion,
129 activationState)));
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -0500130 }
Saqib Khance148702017-06-11 12:01:58 -0500131 versions.insert(std::make_pair(
132 versionId,
133 std::make_unique<Version>(
134 bus,
135 path,
136 version,
137 purpose,
138 filePath)));
Patrick Williams3accb322017-05-30 16:29:52 -0500139 return;
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500140}
141
Saqib Khan7254f0e2017-04-10 21:45:37 -0500142std::string ItemUpdater::getExtendedVersion(const std::string& manifestFilePath)
143{
144 constexpr auto extendedVersionKey = "extended_version=";
145 constexpr auto extendedVersionKeySize = strlen(extendedVersionKey);
146
147 if (manifestFilePath.empty())
148 {
149 log<level::ERR>("Error MANIFESTFilePath is empty");
150 throw std::runtime_error("MANIFESTFilePath is empty");
151 }
152
153 std::string extendedVersion{};
154 std::ifstream efile;
155 std::string line;
156 efile.exceptions(std::ifstream::failbit
157 | std::ifstream::badbit
158 | std::ifstream::eofbit);
159
160 try
161 {
162 efile.open(manifestFilePath);
163 while (getline(efile, line))
164 {
165 if (line.compare(0, extendedVersionKeySize,
166 extendedVersionKey) == 0)
167 {
168 extendedVersion = line.substr(extendedVersionKeySize);
169 break;
170 }
171 }
172 efile.close();
173 }
174 catch (const std::exception& e)
175 {
176 log<level::ERR>("Error in reading Host MANIFEST file");
177 }
Saqib Khan7254f0e2017-04-10 21:45:37 -0500178 return extendedVersion;
179}
180
Adriana Kobylak5ba6b102017-05-19 09:41:27 -0500181int ItemUpdater::validateSquashFSImage(const std::string& filePath)
Saqib Khana8ade7e2017-04-12 10:27:56 -0500182{
Adriana Kobylak5ba6b102017-05-19 09:41:27 -0500183 fs::path file(filePath);
184 file /= squashFSImage;
Saqib Khana8ade7e2017-04-12 10:27:56 -0500185 std::ifstream efile(file.c_str());
186
187 if (efile.good() == 1)
188 {
189 return 0;
190 }
191 else
192 {
193 log<level::ERR>("Failed to find the SquashFS image.");
194 return -1;
195 }
196}
197
Michael Tritzdd961b62017-05-17 14:07:03 -0500198void ItemUpdater::reset()
199{
200 for(const auto& it : activations)
201 {
202 auto serviceFile = "obmc-flash-bios-ubiumount-rw@" + it.first +
203 ".service";
204
205 // Remove the read-write partitions.
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500206 auto method = bus.new_method_call(
Michael Tritzdd961b62017-05-17 14:07:03 -0500207 SYSTEMD_BUSNAME,
208 SYSTEMD_PATH,
209 SYSTEMD_INTERFACE,
210 "StartUnit");
211 method.append(serviceFile, "replace");
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500212 bus.call_noreply(method);
Michael Tritzdd961b62017-05-17 14:07:03 -0500213 }
214
215 // Remove the preserved partition.
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500216 auto method = bus.new_method_call(
Michael Tritzdd961b62017-05-17 14:07:03 -0500217 SYSTEMD_BUSNAME,
218 SYSTEMD_PATH,
219 SYSTEMD_INTERFACE,
220 "StartUnit");
221 method.append("obmc-flash-bios-ubiumount-prsv.service", "replace");
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500222 bus.call_noreply(method);
Michael Tritzdd961b62017-05-17 14:07:03 -0500223
224 return;
225}
226
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500227} // namespace updater
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500228} // namespace software
229} // namespace openpower