blob: d33ac6d55665c83608d1fb4c1434fc035a0366a5 [file] [log] [blame]
Saqib Khan7254f0e2017-04-10 21:45:37 -05001#include <string>
2#include <fstream>
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -05003#include <phosphor-logging/log.hpp>
Adriana Kobylak2d8fa222017-03-15 12:34:32 -05004#include "config.h"
5#include "item_updater.hpp"
Saqib Khana8ade7e2017-04-12 10:27:56 -05006#include "activation.hpp"
Adriana Kobylak2d8fa222017-03-15 12:34:32 -05007
8namespace openpower
9{
10namespace software
11{
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -050012namespace updater
Adriana Kobylak2d8fa222017-03-15 12:34:32 -050013{
14
Saqib Khana8ade7e2017-04-12 10:27:56 -050015// When you see server:: you know we're referencing our base class
16namespace server = sdbusplus::xyz::openbmc_project::Software::server;
17
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050018using namespace phosphor::logging;
19
Saqib Khana8ade7e2017-04-12 10:27:56 -050020constexpr auto squashFSImage = "pnor.xz.squashfs";
21
Patrick Williams3accb322017-05-30 16:29:52 -050022void ItemUpdater::createActivation(sdbusplus::message::message&)
Adriana Kobylak2d8fa222017-03-15 12:34:32 -050023{
Patrick Williams3accb322017-05-30 16:29:52 -050024 auto mapper = busItem.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
25 MAPPER_INTERFACE, "GetSubTreePaths");
26 mapper.append(SOFTWARE_OBJPATH, /* Depth */ 1,
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050027 std::vector<std::string>({VERSION_IFACE}));
28
Patrick Williams3accb322017-05-30 16:29:52 -050029 auto mapperResponseMsg = busItem.call(mapper);
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050030 if (mapperResponseMsg.is_method_error())
31 {
32 log<level::ERR>("Error in mapper call",
33 entry("PATH=%s", SOFTWARE_OBJPATH),
34 entry("INTERFACE=%s", VERSION_IFACE));
Patrick Williams3accb322017-05-30 16:29:52 -050035 return;
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050036 }
37
38 std::vector<std::string> mapperResponse;
39 mapperResponseMsg.read(mapperResponse);
40 if (mapperResponse.empty())
41 {
42 log<level::ERR>("Error reading mapper response",
43 entry("PATH=%s", SOFTWARE_OBJPATH),
44 entry("INTERFACE=%s", VERSION_IFACE));
Patrick Williams3accb322017-05-30 16:29:52 -050045 return;
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050046 }
47
Saqib Khan7254f0e2017-04-10 21:45:37 -050048 auto extendedVersion = ItemUpdater::getExtendedVersion(MANIFEST_FILE);
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050049 for (const auto& resp : mapperResponse)
50 {
51 // Version id is the last item in the path
52 auto pos = resp.rfind("/");
53 if (pos == std::string::npos)
54 {
55 log<level::ERR>("No version id found in object path",
56 entry("OBJPATH=%s", resp));
Patrick Williams3accb322017-05-30 16:29:52 -050057 return;
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050058 }
59
Adriana Kobylak268616b2017-04-05 15:23:30 -050060 auto versionId = resp.substr(pos + 1);
Saqib Khana8ade7e2017-04-12 10:27:56 -050061
Patrick Williams3accb322017-05-30 16:29:52 -050062 if (activations.find(versionId) == activations.end())
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050063 {
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050064 // Determine the Activation state by processing the given image dir.
65 auto activationState = server::Activation::Activations::Invalid;
66 if (ItemUpdater::validateSquashFSImage(versionId) == 0)
67 {
68 activationState = server::Activation::Activations::Ready;
69
70 // Load the squashfs image to pnor so that it is available to be
71 // activated when requested.
72 // This is done since the image on the BMC can be removed.
73 constexpr auto squashfsMountService =
Patrick Williams3accb322017-05-30 16:29:52 -050074 "obmc-flash-bios-squashfsmount@";
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050075 auto squashfsMountServiceFile =
Patrick Williams3accb322017-05-30 16:29:52 -050076 std::string(squashfsMountService) +
77 versionId + ".service";
78 auto method = busItem.new_method_call(SYSTEMD_BUSNAME,
79 SYSTEMD_PATH,
80 SYSTEMD_INTERFACE,
81 "StartUnit");
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050082 method.append(squashfsMountServiceFile, "replace");
Patrick Williams3accb322017-05-30 16:29:52 -050083 busItem.call_noreply(method);
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050084 }
85
Patrick Williams3accb322017-05-30 16:29:52 -050086 activations.insert(std::make_pair(
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050087 versionId,
88 std::make_unique<Activation>(
Patrick Williams3accb322017-05-30 16:29:52 -050089 busItem,
Adriana Kobylakbc37a4c2017-04-10 09:45:36 -050090 resp,
Saqib Khan7254f0e2017-04-10 21:45:37 -050091 versionId,
Saqib Khana8ade7e2017-04-12 10:27:56 -050092 extendedVersion,
93 activationState)));
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050094 }
95 }
Patrick Williams3accb322017-05-30 16:29:52 -050096 return;
Adriana Kobylak2d8fa222017-03-15 12:34:32 -050097}
98
Saqib Khan7254f0e2017-04-10 21:45:37 -050099std::string ItemUpdater::getExtendedVersion(const std::string& manifestFilePath)
100{
101 constexpr auto extendedVersionKey = "extended_version=";
102 constexpr auto extendedVersionKeySize = strlen(extendedVersionKey);
103
104 if (manifestFilePath.empty())
105 {
106 log<level::ERR>("Error MANIFESTFilePath is empty");
107 throw std::runtime_error("MANIFESTFilePath is empty");
108 }
109
110 std::string extendedVersion{};
111 std::ifstream efile;
112 std::string line;
113 efile.exceptions(std::ifstream::failbit
114 | std::ifstream::badbit
115 | std::ifstream::eofbit);
116
117 try
118 {
119 efile.open(manifestFilePath);
120 while (getline(efile, line))
121 {
122 if (line.compare(0, extendedVersionKeySize,
123 extendedVersionKey) == 0)
124 {
125 extendedVersion = line.substr(extendedVersionKeySize);
126 break;
127 }
128 }
129 efile.close();
130 }
131 catch (const std::exception& e)
132 {
133 log<level::ERR>("Error in reading Host MANIFEST file");
134 }
Saqib Khan7254f0e2017-04-10 21:45:37 -0500135 return extendedVersion;
136}
137
Saqib Khana8ade7e2017-04-12 10:27:56 -0500138int ItemUpdater::validateSquashFSImage(const std::string& versionId)
139{
140 auto file = IMAGE_DIR + versionId + "/" +
141 std::string(squashFSImage);
142 std::ifstream efile(file.c_str());
143
144 if (efile.good() == 1)
145 {
146 return 0;
147 }
148 else
149 {
150 log<level::ERR>("Failed to find the SquashFS image.");
151 return -1;
152 }
153}
154
Michael Tritzdd961b62017-05-17 14:07:03 -0500155void ItemUpdater::reset()
156{
157 for(const auto& it : activations)
158 {
159 auto serviceFile = "obmc-flash-bios-ubiumount-rw@" + it.first +
160 ".service";
161
162 // Remove the read-write partitions.
163 auto method = busItem.new_method_call(
164 SYSTEMD_BUSNAME,
165 SYSTEMD_PATH,
166 SYSTEMD_INTERFACE,
167 "StartUnit");
168 method.append(serviceFile, "replace");
169 busItem.call_noreply(method);
170 }
171
172 // Remove the preserved partition.
173 auto method = busItem.new_method_call(
174 SYSTEMD_BUSNAME,
175 SYSTEMD_PATH,
176 SYSTEMD_INTERFACE,
177 "StartUnit");
178 method.append("obmc-flash-bios-ubiumount-prsv.service", "replace");
179 busItem.call_noreply(method);
180
181 return;
182}
183
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500184} // namespace updater
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500185} // namespace software
186} // namespace openpower