blob: 92dba87fb8dbdb1c76d8fca3b0b375c34460794e [file] [log] [blame]
Christopher Meis59ef1e72025-04-16 08:53:25 +02001#include "utils.hpp"
2
3#include "../variant_visitors.hpp"
4#include "expression.hpp"
Alexander Hansen0ab32b32025-06-27 14:50:33 +02005#include "power_status_monitor.hpp"
Christopher Meis59ef1e72025-04-16 08:53:25 +02006
7#include <boost/algorithm/string/classification.hpp>
8#include <boost/algorithm/string/find.hpp>
9#include <boost/algorithm/string/predicate.hpp>
10#include <boost/algorithm/string/replace.hpp>
11#include <boost/algorithm/string/split.hpp>
12#include <sdbusplus/bus/match.hpp>
13
14#include <fstream>
15#include <iostream>
16
Alexander Hansen0ab32b32025-06-27 14:50:33 +020017bool power::PowerStatusMonitor::isPowerOn()
Christopher Meis59ef1e72025-04-16 08:53:25 +020018{
19 if (!powerMatch)
20 {
21 throw std::runtime_error("Power Match Not Created");
22 }
23 return powerStatusOn;
24}
25
Alexander Hansen0ab32b32025-06-27 14:50:33 +020026void power::PowerStatusMonitor::setupPowerMatch(
27 const std::shared_ptr<sdbusplus::asio::connection>& conn)
Christopher Meis59ef1e72025-04-16 08:53:25 +020028{
29 powerMatch = std::make_unique<sdbusplus::bus::match_t>(
30 static_cast<sdbusplus::bus_t&>(*conn),
Alexander Hansen0ab32b32025-06-27 14:50:33 +020031 "type='signal',interface='" +
32 std::string(em_utils::properties::interface) + "',path='" +
33 std::string(power::path) + "',arg0='" +
Christopher Meis59ef1e72025-04-16 08:53:25 +020034 std::string(power::interface) + "'",
Alexander Hansen0ab32b32025-06-27 14:50:33 +020035 [this](sdbusplus::message_t& message) {
Christopher Meis59ef1e72025-04-16 08:53:25 +020036 std::string objectName;
37 boost::container::flat_map<std::string, std::variant<std::string>>
38 values;
39 message.read(objectName, values);
40 auto findState = values.find(power::property);
41 if (findState != values.end())
42 {
43 powerStatusOn = boost::ends_with(
44 std::get<std::string>(findState->second), "Running");
45 }
46 });
47
48 conn->async_method_call(
Alexander Hansen0ab32b32025-06-27 14:50:33 +020049 [this](boost::system::error_code ec,
50 const std::variant<std::string>& state) {
Christopher Meis59ef1e72025-04-16 08:53:25 +020051 if (ec)
52 {
53 return;
54 }
55 powerStatusOn =
56 boost::ends_with(std::get<std::string>(state), "Running");
57 },
Alexander Hansen0ab32b32025-06-27 14:50:33 +020058 power::busname, power::path, em_utils::properties::interface,
59 em_utils::properties::get, power::interface, power::property);
Christopher Meis59ef1e72025-04-16 08:53:25 +020060}
61
Alexander Hansen0ab32b32025-06-27 14:50:33 +020062namespace em_utils
63{
64
65constexpr const char* templateChar = "$";
66
Christopher Meis59ef1e72025-04-16 08:53:25 +020067bool fwVersionIsSame()
68{
69 std::ifstream version(versionFile);
70 if (!version.good())
71 {
72 std::cerr << "Can't read " << versionFile << "\n";
73 return false;
74 }
75
76 std::string versionData;
77 std::string line;
78 while (std::getline(version, line))
79 {
80 versionData += line;
81 }
82
83 std::string expectedHash =
84 std::to_string(std::hash<std::string>{}(versionData));
85
86 std::filesystem::create_directory(configurationOutDir);
87 std::ifstream hashFile(versionHashFile);
88 if (hashFile.good())
89 {
90 std::string hashString;
91 hashFile >> hashString;
92
93 if (expectedHash == hashString)
94 {
95 return true;
96 }
97 hashFile.close();
98 }
99
100 std::ofstream output(versionHashFile);
101 output << expectedHash;
102 return false;
103}
104
105// Replaces the template character like the other version of this function,
106// but checks all properties on all interfaces provided to do the substitution
107// with.
108std::optional<std::string> templateCharReplace(
109 nlohmann::json::iterator& keyPair, const DBusObject& object,
110 const size_t index, const std::optional<std::string>& replaceStr)
111{
112 for (const auto& [_, interface] : object)
113 {
114 auto ret = templateCharReplace(keyPair, interface, index, replaceStr);
115 if (ret)
116 {
117 return ret;
118 }
119 }
120 return std::nullopt;
121}
122
123// finds the template character (currently set to $) and replaces the value with
124// the field found in a dbus object i.e. $ADDRESS would get populated with the
125// ADDRESS field from a object on dbus
126std::optional<std::string> templateCharReplace(
127 nlohmann::json::iterator& keyPair, const DBusInterface& interface,
128 const size_t index, const std::optional<std::string>& replaceStr)
129{
130 std::optional<std::string> ret = std::nullopt;
131
132 if (keyPair.value().type() == nlohmann::json::value_t::object ||
133 keyPair.value().type() == nlohmann::json::value_t::array)
134 {
135 for (auto nextLayer = keyPair.value().begin();
136 nextLayer != keyPair.value().end(); nextLayer++)
137 {
138 templateCharReplace(nextLayer, interface, index, replaceStr);
139 }
140 return ret;
141 }
142
143 std::string* strPtr = keyPair.value().get_ptr<std::string*>();
144 if (strPtr == nullptr)
145 {
146 return ret;
147 }
148
149 boost::replace_all(*strPtr, std::string(templateChar) + "index",
150 std::to_string(index));
151 if (replaceStr)
152 {
153 boost::replace_all(*strPtr, *replaceStr, std::to_string(index));
154 }
155
156 for (const auto& [propName, propValue] : interface)
157 {
158 std::string templateName = templateChar + propName;
159 boost::iterator_range<std::string::const_iterator> find =
160 boost::ifind_first(*strPtr, templateName);
161 if (!find)
162 {
163 continue;
164 }
165
166 size_t start = find.begin() - strPtr->begin();
167
168 // check for additional operations
169 if ((start == 0U) && find.end() == strPtr->end())
170 {
171 std::visit([&](auto&& val) { keyPair.value() = val; }, propValue);
172 return ret;
173 }
174
175 constexpr const std::array<char, 5> mathChars = {'+', '-', '%', '*',
176 '/'};
177 size_t nextItemIdx = start + templateName.size() + 1;
178
179 if (nextItemIdx > strPtr->size() ||
180 std::find(mathChars.begin(), mathChars.end(),
181 strPtr->at(nextItemIdx)) == mathChars.end())
182 {
183 std::string val = std::visit(VariantToStringVisitor(), propValue);
184 boost::ireplace_all(*strPtr, templateName, val);
185 continue;
186 }
187
188 // save the prefix
189 std::string prefix = strPtr->substr(0, start);
190
191 // operate on the rest
192 std::string end = strPtr->substr(nextItemIdx);
193
194 std::vector<std::string> split;
195 boost::split(split, end, boost::is_any_of(" "));
196
197 // need at least 1 operation and number
198 if (split.size() < 2)
199 {
200 std::cerr << "Syntax error on template replacement of " << *strPtr
201 << "\n";
202 for (const std::string& data : split)
203 {
204 std::cerr << data << " ";
205 }
206 std::cerr << "\n";
207 continue;
208 }
209
210 // we assume that the replacement is a number, because we can
211 // only do math on numbers.. we might concatenate strings in the
212 // future, but thats later
213 int number = std::visit(VariantToIntVisitor(), propValue);
214 auto exprBegin = split.begin();
215 auto exprEnd = split.end();
216
217 number = expression::evaluate(number, exprBegin, exprEnd);
218
219 std::string replaced(find.begin(), find.end());
220 while (exprBegin != exprEnd)
221 {
222 replaced.append(" ").append(*exprBegin++);
223 }
224 ret = replaced;
225
226 std::string result = prefix + std::to_string(number);
227 while (exprEnd != split.end())
228 {
229 result.append(" ").append(*exprEnd++);
230 }
231 keyPair.value() = result;
232
233 // We probably just invalidated the pointer abovei,
234 // reset and continue to handle multiple templates
235 strPtr = keyPair.value().get_ptr<std::string*>();
236 if (strPtr == nullptr)
237 {
238 break;
239 }
240 }
241
242 strPtr = keyPair.value().get_ptr<std::string*>();
243 if (strPtr == nullptr)
244 {
245 return ret;
246 }
247
248 std::string_view strView = *strPtr;
249 int base = 10;
250 if (boost::starts_with(strView, "0x"))
251 {
252 strView.remove_prefix(2);
253 base = 16;
254 }
255
256 uint64_t temp = 0;
257 const char* strDataEndPtr = strView.data() + strView.size();
258 const std::from_chars_result res =
259 std::from_chars(strView.data(), strDataEndPtr, temp, base);
260 if (res.ec == std::errc{} && res.ptr == strDataEndPtr)
261 {
262 keyPair.value() = temp;
263 }
264
265 return ret;
266}
267
268} // namespace em_utils