blob: b8e4506d328262595af38110b3de02df996a715f [file] [log] [blame]
James Feist6714a252018-09-10 15:26:18 -07001/*
2// Copyright (c) 2017 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Patrick Ventureca44b2f2019-10-31 11:02:26 -070017#include "Utils.hpp"
18
James Feist6714a252018-09-10 15:26:18 -070019#include <boost/algorithm/string/predicate.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070020#include <boost/container/flat_map.hpp>
James Feist38fb5982020-05-28 10:09:54 -070021#include <sdbusplus/asio/connection.hpp>
22#include <sdbusplus/asio/object_server.hpp>
23#include <sdbusplus/bus/match.hpp>
24
James Feist24f02f22019-04-15 11:05:39 -070025#include <filesystem>
James Feist6714a252018-09-10 15:26:18 -070026#include <fstream>
Patrick Venture96e97db2019-10-31 13:44:38 -070027#include <memory>
James Feist6714a252018-09-10 15:26:18 -070028#include <regex>
Patrick Venture96e97db2019-10-31 13:44:38 -070029#include <stdexcept>
30#include <string>
31#include <utility>
32#include <variant>
33#include <vector>
James Feist6714a252018-09-10 15:26:18 -070034
James Feistcf3bce62019-01-08 10:07:19 -080035namespace fs = std::filesystem;
James Feist6714a252018-09-10 15:26:18 -070036
James Feist6ef20402019-01-07 16:45:08 -080037static bool powerStatusOn = false;
James Feistfc94b212019-02-06 16:14:51 -080038static bool biosHasPost = false;
James Feist58295ad2019-05-30 15:01:41 -070039
James Feist6ef20402019-01-07 16:45:08 -080040static std::unique_ptr<sdbusplus::bus::match::match> powerMatch = nullptr;
James Feist52497fd2019-06-07 13:01:33 -070041static std::unique_ptr<sdbusplus::bus::match::match> postMatch = nullptr;
James Feist71d31b22019-01-02 16:57:54 -080042
James Feist6714a252018-09-10 15:26:18 -070043bool getSensorConfiguration(
44 const std::string& type,
45 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
46 ManagedObjectType& resp, bool useCache)
47{
48 static ManagedObjectType managedObj;
49
50 if (!useCache)
51 {
52 managedObj.clear();
53 sdbusplus::message::message getManagedObjects =
54 dbusConnection->new_method_call(
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070055 entityManagerName, "/", "org.freedesktop.DBus.ObjectManager",
James Feist6714a252018-09-10 15:26:18 -070056 "GetManagedObjects");
57 bool err = false;
58 try
59 {
60 sdbusplus::message::message reply =
61 dbusConnection->call(getManagedObjects);
Yoo, Jae Hyun0e022052018-10-15 14:05:37 -070062 reply.read(managedObj);
James Feist6714a252018-09-10 15:26:18 -070063 }
Jason Ling5747fab2019-10-02 16:46:23 -070064 catch (const sdbusplus::exception::exception& e)
James Feist6714a252018-09-10 15:26:18 -070065 {
Jason Ling5747fab2019-10-02 16:46:23 -070066 std::cerr << "While calling GetManagedObjects on service:"
67 << entityManagerName << " exception name:" << e.name()
68 << "and description:" << e.description()
69 << " was thrown\n";
James Feist6714a252018-09-10 15:26:18 -070070 err = true;
71 }
72
73 if (err)
74 {
75 std::cerr << "Error communicating to entity manager\n";
76 return false;
77 }
78 }
79 for (const auto& pathPair : managedObj)
80 {
James Feist6714a252018-09-10 15:26:18 -070081 bool correctType = false;
82 for (const auto& entry : pathPair.second)
83 {
84 if (boost::starts_with(entry.first, type))
85 {
86 correctType = true;
87 break;
88 }
89 }
90 if (correctType)
91 {
92 resp.emplace(pathPair);
93 }
94 }
95 return true;
96}
97
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070098bool findFiles(const fs::path dirPath, const std::string& matchString,
99 std::vector<fs::path>& foundPaths, unsigned int symlinkDepth)
James Feist6714a252018-09-10 15:26:18 -0700100{
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700101 if (!fs::exists(dirPath))
James Feist6714a252018-09-10 15:26:18 -0700102 return false;
103
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700104 std::regex search(matchString);
James Feist6714a252018-09-10 15:26:18 -0700105 std::smatch match;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700106 for (auto& p : fs::recursive_directory_iterator(dirPath))
James Feist6714a252018-09-10 15:26:18 -0700107 {
108 std::string path = p.path().string();
109 if (!is_directory(p))
110 {
111 if (std::regex_search(path, match, search))
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700112 foundPaths.emplace_back(p.path());
James Feist6714a252018-09-10 15:26:18 -0700113 }
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700114 else if (is_symlink(p) && symlinkDepth)
James Feist6714a252018-09-10 15:26:18 -0700115 {
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700116 findFiles(p.path(), matchString, foundPaths, symlinkDepth - 1);
James Feist6714a252018-09-10 15:26:18 -0700117 }
118 }
119 return true;
120}
121
James Feist71d31b22019-01-02 16:57:54 -0800122bool isPowerOn(void)
James Feist6714a252018-09-10 15:26:18 -0700123{
James Feist71d31b22019-01-02 16:57:54 -0800124 if (!powerMatch)
James Feist6714a252018-09-10 15:26:18 -0700125 {
James Feist71d31b22019-01-02 16:57:54 -0800126 throw std::runtime_error("Power Match Not Created");
James Feist6714a252018-09-10 15:26:18 -0700127 }
James Feist71d31b22019-01-02 16:57:54 -0800128 return powerStatusOn;
129}
130
James Feistfc94b212019-02-06 16:14:51 -0800131bool hasBiosPost(void)
132{
James Feist52497fd2019-06-07 13:01:33 -0700133 if (!postMatch)
James Feistfc94b212019-02-06 16:14:51 -0800134 {
James Feist52497fd2019-06-07 13:01:33 -0700135 throw std::runtime_error("Post Match Not Created");
James Feistfc94b212019-02-06 16:14:51 -0800136 }
137 return biosHasPost;
138}
139
James Feist8aeffd92020-09-14 12:08:28 -0700140static void
141 getPowerStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn,
142 size_t retries = 2)
143{
144 conn->async_method_call(
145 [conn, retries](boost::system::error_code ec,
146 const std::variant<std::string>& state) {
147 if (ec)
148 {
149 if (retries)
150 {
151 auto timer = std::make_shared<boost::asio::steady_timer>(
152 conn->get_io_context());
153 timer->expires_after(std::chrono::seconds(15));
154 timer->async_wait(
155 [timer, conn, retries](boost::system::error_code) {
156 getPowerStatus(conn, retries - 1);
157 });
158 return;
159 }
160
161 // we commonly come up before power control, we'll capture the
162 // property change later
163 std::cerr << "error getting power status " << ec.message()
164 << "\n";
165 return;
166 }
167 powerStatusOn =
168 boost::ends_with(std::get<std::string>(state), "Running");
169 },
170 power::busname, power::path, properties::interface, properties::get,
171 power::interface, power::property);
172}
173
174static void
175 getPostStatus(const std::shared_ptr<sdbusplus::asio::connection>& conn,
176 size_t retries = 2)
177{
178 conn->async_method_call(
179 [conn, retries](boost::system::error_code ec,
180 const std::variant<std::string>& state) {
181 if (ec)
182 {
183 if (retries)
184 {
185 auto timer = std::make_shared<boost::asio::steady_timer>(
186 conn->get_io_context());
187 timer->expires_after(std::chrono::seconds(15));
188 timer->async_wait(
189 [timer, conn, retries](boost::system::error_code) {
190 getPostStatus(conn, retries - 1);
191 });
192 return;
193 }
194 // we commonly come up before power control, we'll capture the
195 // property change later
196 std::cerr << "error getting post status " << ec.message()
197 << "\n";
198 return;
199 }
200 biosHasPost = std::get<std::string>(state) != "Inactive";
201 },
202 post::busname, post::path, properties::interface, properties::get,
203 post::interface, post::property);
204}
205
James Feist71d31b22019-01-02 16:57:54 -0800206void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn)
207{
James Feist43d32fe2019-09-04 10:35:20 -0700208 static boost::asio::steady_timer timer(conn->get_io_context());
James Feist6714a252018-09-10 15:26:18 -0700209 // create a match for powergood changes, first time do a method call to
James Feist71d31b22019-01-02 16:57:54 -0800210 // cache the correct value
James Feist52497fd2019-06-07 13:01:33 -0700211 if (powerMatch)
212 {
213 return;
214 }
James Feist6714a252018-09-10 15:26:18 -0700215
216 powerMatch = std::make_unique<sdbusplus::bus::match::match>(
217 static_cast<sdbusplus::bus::bus&>(*conn),
James Feist52497fd2019-06-07 13:01:33 -0700218 "type='signal',interface='" + std::string(properties::interface) +
219 "',path='" + std::string(power::path) + "',arg0='" +
220 std::string(power::interface) + "'",
221 [](sdbusplus::message::message& message) {
222 std::string objectName;
223 boost::container::flat_map<std::string, std::variant<std::string>>
224 values;
225 message.read(objectName, values);
226 auto findState = values.find(power::property);
227 if (findState != values.end())
James Feist6714a252018-09-10 15:26:18 -0700228 {
James Feist43d32fe2019-09-04 10:35:20 -0700229 bool on = boost::ends_with(
James Feist52497fd2019-06-07 13:01:33 -0700230 std::get<std::string>(findState->second), "Running");
James Feist43d32fe2019-09-04 10:35:20 -0700231 if (!on)
232 {
233 timer.cancel();
234 powerStatusOn = false;
235 return;
236 }
237 // on comes too quickly
238 timer.expires_after(std::chrono::seconds(10));
239 timer.async_wait([](boost::system::error_code ec) {
240 if (ec == boost::asio::error::operation_aborted)
241 {
242 return;
243 }
244 else if (ec)
245 {
246 std::cerr << "Timer error " << ec.message() << "\n";
247 return;
248 }
249 powerStatusOn = true;
250 });
James Feist6714a252018-09-10 15:26:18 -0700251 }
James Feist52497fd2019-06-07 13:01:33 -0700252 });
253
254 postMatch = std::make_unique<sdbusplus::bus::match::match>(
255 static_cast<sdbusplus::bus::bus&>(*conn),
256 "type='signal',interface='" + std::string(properties::interface) +
257 "',path='" + std::string(post::path) + "',arg0='" +
258 std::string(post::interface) + "'",
259 [](sdbusplus::message::message& message) {
260 std::string objectName;
261 boost::container::flat_map<std::string, std::variant<std::string>>
262 values;
263 message.read(objectName, values);
264 auto findState = values.find(post::property);
265 if (findState != values.end())
266 {
267 biosHasPost =
268 std::get<std::string>(findState->second) != "Inactive";
269 }
270 });
James Feistfc94b212019-02-06 16:14:51 -0800271
James Feist8aeffd92020-09-14 12:08:28 -0700272 getPowerStatus(conn);
273 getPostStatus(conn);
James Feist3f0e8762018-11-27 11:30:42 -0800274}
James Feist87d713a2018-12-06 16:06:24 -0800275
276// replaces limits if MinReading and MaxReading are found.
277void findLimits(std::pair<double, double>& limits,
278 const SensorBaseConfiguration* data)
279{
280 if (!data)
281 {
282 return;
283 }
284 auto maxFind = data->second.find("MaxReading");
285 auto minFind = data->second.find("MinReading");
286
287 if (minFind != data->second.end())
288 {
James Feist3eb82622019-02-08 13:10:22 -0800289 limits.first = std::visit(VariantToDoubleVisitor(), minFind->second);
James Feist87d713a2018-12-06 16:06:24 -0800290 }
291 if (maxFind != data->second.end())
292 {
James Feist3eb82622019-02-08 13:10:22 -0800293 limits.second = std::visit(VariantToDoubleVisitor(), maxFind->second);
James Feist87d713a2018-12-06 16:06:24 -0800294 }
James Feistfc94b212019-02-06 16:14:51 -0800295}
James Feist82bac4c2019-03-11 11:16:53 -0700296
297void createAssociation(
298 std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
299 const std::string& path)
300{
301 if (association)
302 {
James Feistd2543f82019-04-09 11:10:06 -0700303 std::filesystem::path p(path);
304
James Feist82bac4c2019-03-11 11:16:53 -0700305 std::vector<Association> associations;
James Feistd2543f82019-04-09 11:10:06 -0700306 associations.push_back(
James Feistd8bd5622019-06-26 12:09:05 -0700307 Association("chassis", "all_sensors", p.parent_path().string()));
James Feist2adc95c2019-09-30 14:55:28 -0700308 association->register_property("Associations", associations);
James Feist82bac4c2019-03-11 11:16:53 -0700309 association->initialize();
310 }
James Feist43d32fe2019-09-04 10:35:20 -0700311}
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800312
313void setInventoryAssociation(
314 std::shared_ptr<sdbusplus::asio::dbus_interface> association,
AppaRao Pulic82213c2020-02-27 01:24:58 +0530315 const std::string& path,
316 const std::vector<std::string>& chassisPaths = std::vector<std::string>())
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800317{
318 if (association)
319 {
320 std::filesystem::path p(path);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800321 std::vector<Association> associations;
AppaRao Pulic82213c2020-02-27 01:24:58 +0530322 std::string objPath(p.parent_path().string());
323
324 associations.push_back(Association("inventory", "sensors", objPath));
325 associations.push_back(Association("chassis", "all_sensors", objPath));
326
327 for (const std::string& chassisPath : chassisPaths)
328 {
329 associations.push_back(
330 Association("chassis", "all_sensors", chassisPath));
331 }
332
James Feist2adc95c2019-09-30 14:55:28 -0700333 association->register_property("Associations", associations);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800334 association->initialize();
335 }
336}
337
338void createInventoryAssoc(
339 std::shared_ptr<sdbusplus::asio::connection> conn,
340 std::shared_ptr<sdbusplus::asio::dbus_interface> association,
341 const std::string& path)
342{
343 if (!association)
344 {
345 return;
346 }
AppaRao Pulic82213c2020-02-27 01:24:58 +0530347
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800348 conn->async_method_call(
349 [association, path](const boost::system::error_code ec,
AppaRao Pulic82213c2020-02-27 01:24:58 +0530350 const std::vector<std::string>& invSysObjPaths) {
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800351 if (ec)
352 {
AppaRao Pulic82213c2020-02-27 01:24:58 +0530353 // In case of error, set the default associations and
354 // initialize the association Interface.
355 setInventoryAssociation(association, path);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800356 return;
357 }
AppaRao Pulic82213c2020-02-27 01:24:58 +0530358 setInventoryAssociation(association, path, invSysObjPaths);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800359 },
360 mapper::busName, mapper::path, mapper::interface, "GetSubTreePaths",
361 "/xyz/openbmc_project/inventory/system", 2,
362 std::array<std::string, 1>{
363 "xyz.openbmc_project.Inventory.Item.System"});
364}
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200365
366std::optional<double> readFile(const std::string& thresholdFile,
367 const double& scaleFactor)
368{
369 std::string line;
370 std::ifstream labelFile(thresholdFile);
371 if (labelFile.good())
372 {
373 std::getline(labelFile, line);
374 labelFile.close();
375
376 try
377 {
378 return std::stod(line) / scaleFactor;
379 }
380 catch (const std::invalid_argument&)
381 {
382 return std::nullopt;
383 }
384 }
385 return std::nullopt;
386}
387
388std::optional<std::tuple<std::string, std::string, std::string>>
389 splitFileName(const std::filesystem::path& filePath)
390{
391 if (filePath.has_filename())
392 {
393 const auto fileName = filePath.filename().string();
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200394
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200395 size_t numberPos = std::strcspn(fileName.c_str(), "1234567890");
396 size_t itemPos = std::strcspn(fileName.c_str(), "_");
397
398 if (numberPos > 0 && itemPos > numberPos && fileName.size() > itemPos)
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200399 {
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200400 return std::make_optional(
401 std::make_tuple(fileName.substr(0, numberPos),
402 fileName.substr(numberPos, itemPos - numberPos),
403 fileName.substr(itemPos + 1, fileName.size())));
Zbigniew Kurzynski63f38662020-06-09 13:02:11 +0200404 }
405 }
406 return std::nullopt;
Zbigniew Kurzynskidd648002020-07-10 16:44:16 +0200407}