blob: 44a6bae44ad12517e13c162fa6e707c8a52d71b8 [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 Feist24f02f22019-04-15 11:05:39 -070021#include <filesystem>
James Feist6714a252018-09-10 15:26:18 -070022#include <fstream>
Patrick Venture96e97db2019-10-31 13:44:38 -070023#include <memory>
James Feist6714a252018-09-10 15:26:18 -070024#include <regex>
25#include <sdbusplus/asio/connection.hpp>
James Feist82bac4c2019-03-11 11:16:53 -070026#include <sdbusplus/asio/object_server.hpp>
James Feist6714a252018-09-10 15:26:18 -070027#include <sdbusplus/bus/match.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070028#include <stdexcept>
29#include <string>
30#include <utility>
31#include <variant>
32#include <vector>
James Feist6714a252018-09-10 15:26:18 -070033
James Feistcf3bce62019-01-08 10:07:19 -080034namespace fs = std::filesystem;
James Feist6714a252018-09-10 15:26:18 -070035
James Feist6ef20402019-01-07 16:45:08 -080036static bool powerStatusOn = false;
James Feistfc94b212019-02-06 16:14:51 -080037static bool biosHasPost = false;
James Feist58295ad2019-05-30 15:01:41 -070038
James Feist6ef20402019-01-07 16:45:08 -080039static std::unique_ptr<sdbusplus::bus::match::match> powerMatch = nullptr;
James Feist52497fd2019-06-07 13:01:33 -070040static std::unique_ptr<sdbusplus::bus::match::match> postMatch = nullptr;
James Feist71d31b22019-01-02 16:57:54 -080041
James Feist6714a252018-09-10 15:26:18 -070042bool getSensorConfiguration(
43 const std::string& type,
44 const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
45 ManagedObjectType& resp, bool useCache)
46{
47 static ManagedObjectType managedObj;
48
49 if (!useCache)
50 {
51 managedObj.clear();
52 sdbusplus::message::message getManagedObjects =
53 dbusConnection->new_method_call(
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070054 entityManagerName, "/", "org.freedesktop.DBus.ObjectManager",
James Feist6714a252018-09-10 15:26:18 -070055 "GetManagedObjects");
56 bool err = false;
57 try
58 {
59 sdbusplus::message::message reply =
60 dbusConnection->call(getManagedObjects);
Yoo, Jae Hyun0e022052018-10-15 14:05:37 -070061 reply.read(managedObj);
James Feist6714a252018-09-10 15:26:18 -070062 }
Jason Ling5747fab2019-10-02 16:46:23 -070063 catch (const sdbusplus::exception::exception& e)
James Feist6714a252018-09-10 15:26:18 -070064 {
Jason Ling5747fab2019-10-02 16:46:23 -070065 std::cerr << "While calling GetManagedObjects on service:"
66 << entityManagerName << " exception name:" << e.name()
67 << "and description:" << e.description()
68 << " was thrown\n";
James Feist6714a252018-09-10 15:26:18 -070069 err = true;
70 }
71
72 if (err)
73 {
74 std::cerr << "Error communicating to entity manager\n";
75 return false;
76 }
77 }
78 for (const auto& pathPair : managedObj)
79 {
James Feist6714a252018-09-10 15:26:18 -070080 bool correctType = false;
81 for (const auto& entry : pathPair.second)
82 {
83 if (boost::starts_with(entry.first, type))
84 {
85 correctType = true;
86 break;
87 }
88 }
89 if (correctType)
90 {
91 resp.emplace(pathPair);
92 }
93 }
94 return true;
95}
96
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070097bool findFiles(const fs::path dirPath, const std::string& matchString,
98 std::vector<fs::path>& foundPaths, unsigned int symlinkDepth)
James Feist6714a252018-09-10 15:26:18 -070099{
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700100 if (!fs::exists(dirPath))
James Feist6714a252018-09-10 15:26:18 -0700101 return false;
102
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700103 std::regex search(matchString);
James Feist6714a252018-09-10 15:26:18 -0700104 std::smatch match;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700105 for (auto& p : fs::recursive_directory_iterator(dirPath))
James Feist6714a252018-09-10 15:26:18 -0700106 {
107 std::string path = p.path().string();
108 if (!is_directory(p))
109 {
110 if (std::regex_search(path, match, search))
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700111 foundPaths.emplace_back(p.path());
James Feist6714a252018-09-10 15:26:18 -0700112 }
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700113 else if (is_symlink(p) && symlinkDepth)
James Feist6714a252018-09-10 15:26:18 -0700114 {
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700115 findFiles(p.path(), matchString, foundPaths, symlinkDepth - 1);
James Feist6714a252018-09-10 15:26:18 -0700116 }
117 }
118 return true;
119}
120
James Feist71d31b22019-01-02 16:57:54 -0800121bool isPowerOn(void)
James Feist6714a252018-09-10 15:26:18 -0700122{
James Feist71d31b22019-01-02 16:57:54 -0800123 if (!powerMatch)
James Feist6714a252018-09-10 15:26:18 -0700124 {
James Feist71d31b22019-01-02 16:57:54 -0800125 throw std::runtime_error("Power Match Not Created");
James Feist6714a252018-09-10 15:26:18 -0700126 }
James Feist71d31b22019-01-02 16:57:54 -0800127 return powerStatusOn;
128}
129
James Feistfc94b212019-02-06 16:14:51 -0800130bool hasBiosPost(void)
131{
James Feist52497fd2019-06-07 13:01:33 -0700132 if (!postMatch)
James Feistfc94b212019-02-06 16:14:51 -0800133 {
James Feist52497fd2019-06-07 13:01:33 -0700134 throw std::runtime_error("Post Match Not Created");
James Feistfc94b212019-02-06 16:14:51 -0800135 }
136 return biosHasPost;
137}
138
James Feist71d31b22019-01-02 16:57:54 -0800139void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn)
140{
James Feist43d32fe2019-09-04 10:35:20 -0700141 static boost::asio::steady_timer timer(conn->get_io_context());
James Feist6714a252018-09-10 15:26:18 -0700142 // create a match for powergood changes, first time do a method call to
James Feist71d31b22019-01-02 16:57:54 -0800143 // cache the correct value
James Feist52497fd2019-06-07 13:01:33 -0700144 if (powerMatch)
145 {
146 return;
147 }
James Feist6714a252018-09-10 15:26:18 -0700148
149 powerMatch = std::make_unique<sdbusplus::bus::match::match>(
150 static_cast<sdbusplus::bus::bus&>(*conn),
James Feist52497fd2019-06-07 13:01:33 -0700151 "type='signal',interface='" + std::string(properties::interface) +
152 "',path='" + std::string(power::path) + "',arg0='" +
153 std::string(power::interface) + "'",
154 [](sdbusplus::message::message& message) {
155 std::string objectName;
156 boost::container::flat_map<std::string, std::variant<std::string>>
157 values;
158 message.read(objectName, values);
159 auto findState = values.find(power::property);
160 if (findState != values.end())
James Feist6714a252018-09-10 15:26:18 -0700161 {
James Feist43d32fe2019-09-04 10:35:20 -0700162 bool on = boost::ends_with(
James Feist52497fd2019-06-07 13:01:33 -0700163 std::get<std::string>(findState->second), "Running");
James Feist43d32fe2019-09-04 10:35:20 -0700164 if (!on)
165 {
166 timer.cancel();
167 powerStatusOn = false;
168 return;
169 }
170 // on comes too quickly
171 timer.expires_after(std::chrono::seconds(10));
172 timer.async_wait([](boost::system::error_code ec) {
173 if (ec == boost::asio::error::operation_aborted)
174 {
175 return;
176 }
177 else if (ec)
178 {
179 std::cerr << "Timer error " << ec.message() << "\n";
180 return;
181 }
182 powerStatusOn = true;
183 });
James Feist6714a252018-09-10 15:26:18 -0700184 }
James Feist52497fd2019-06-07 13:01:33 -0700185 });
186
187 postMatch = std::make_unique<sdbusplus::bus::match::match>(
188 static_cast<sdbusplus::bus::bus&>(*conn),
189 "type='signal',interface='" + std::string(properties::interface) +
190 "',path='" + std::string(post::path) + "',arg0='" +
191 std::string(post::interface) + "'",
192 [](sdbusplus::message::message& message) {
193 std::string objectName;
194 boost::container::flat_map<std::string, std::variant<std::string>>
195 values;
196 message.read(objectName, values);
197 auto findState = values.find(post::property);
198 if (findState != values.end())
199 {
200 biosHasPost =
201 std::get<std::string>(findState->second) != "Inactive";
202 }
203 });
James Feistfc94b212019-02-06 16:14:51 -0800204
205 conn->async_method_call(
206 [](boost::system::error_code ec,
James Feist52497fd2019-06-07 13:01:33 -0700207 const std::variant<std::string>& state) {
James Feistfc94b212019-02-06 16:14:51 -0800208 if (ec)
209 {
James Feistcee4ef22019-04-04 11:04:08 -0700210 // we commonly come up before power control, we'll capture the
211 // property change later
James Feistfc94b212019-02-06 16:14:51 -0800212 return;
213 }
James Feist52497fd2019-06-07 13:01:33 -0700214 powerStatusOn =
215 boost::ends_with(std::get<std::string>(state), "Running");
James Feistfc94b212019-02-06 16:14:51 -0800216 },
James Feist52497fd2019-06-07 13:01:33 -0700217 power::busname, power::path, properties::interface, properties::get,
218 power::interface, power::property);
219
220 conn->async_method_call(
221 [](boost::system::error_code ec,
222 const std::variant<std::string>& state) {
223 if (ec)
224 {
225 // we commonly come up before power control, we'll capture the
226 // property change later
227 return;
228 }
229 biosHasPost = std::get<std::string>(state) != "Inactive";
230 },
231 post::busname, post::path, properties::interface, properties::get,
232 post::interface, post::property);
James Feist3f0e8762018-11-27 11:30:42 -0800233}
James Feist87d713a2018-12-06 16:06:24 -0800234
235// replaces limits if MinReading and MaxReading are found.
236void findLimits(std::pair<double, double>& limits,
237 const SensorBaseConfiguration* data)
238{
239 if (!data)
240 {
241 return;
242 }
243 auto maxFind = data->second.find("MaxReading");
244 auto minFind = data->second.find("MinReading");
245
246 if (minFind != data->second.end())
247 {
James Feist3eb82622019-02-08 13:10:22 -0800248 limits.first = std::visit(VariantToDoubleVisitor(), minFind->second);
James Feist87d713a2018-12-06 16:06:24 -0800249 }
250 if (maxFind != data->second.end())
251 {
James Feist3eb82622019-02-08 13:10:22 -0800252 limits.second = std::visit(VariantToDoubleVisitor(), maxFind->second);
James Feist87d713a2018-12-06 16:06:24 -0800253 }
James Feistfc94b212019-02-06 16:14:51 -0800254}
James Feist82bac4c2019-03-11 11:16:53 -0700255
256void createAssociation(
257 std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
258 const std::string& path)
259{
260 if (association)
261 {
James Feistd2543f82019-04-09 11:10:06 -0700262 std::filesystem::path p(path);
263
James Feist82bac4c2019-03-11 11:16:53 -0700264 std::vector<Association> associations;
James Feistd2543f82019-04-09 11:10:06 -0700265 associations.push_back(
James Feistd8bd5622019-06-26 12:09:05 -0700266 Association("chassis", "all_sensors", p.parent_path().string()));
James Feist2adc95c2019-09-30 14:55:28 -0700267 association->register_property("Associations", associations);
James Feist82bac4c2019-03-11 11:16:53 -0700268 association->initialize();
269 }
James Feist43d32fe2019-09-04 10:35:20 -0700270}
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800271
272void setInventoryAssociation(
273 std::shared_ptr<sdbusplus::asio::dbus_interface> association,
274 const std::string& path, const std::string& chassisPath)
275{
276 if (association)
277 {
278 std::filesystem::path p(path);
279
280 std::vector<Association> associations;
281 associations.push_back(
282 Association("inventory", "sensors", p.parent_path().string()));
283 associations.push_back(
284 Association("chassis", "all_sensors", chassisPath));
James Feist2adc95c2019-09-30 14:55:28 -0700285 association->register_property("Associations", associations);
Cheng C Yang5580f2f2019-09-19 09:01:47 +0800286 association->initialize();
287 }
288}
289
290void createInventoryAssoc(
291 std::shared_ptr<sdbusplus::asio::connection> conn,
292 std::shared_ptr<sdbusplus::asio::dbus_interface> association,
293 const std::string& path)
294{
295 if (!association)
296 {
297 return;
298 }
299 conn->async_method_call(
300 [association, path](const boost::system::error_code ec,
301 const std::vector<std::string>& ret) {
302 if (ec)
303 {
304 std::cerr << "Error calling mapper\n";
305 return;
306 }
307 for (const auto& object : ret)
308 {
309 setInventoryAssociation(association, path, object);
310 }
311 },
312 mapper::busName, mapper::path, mapper::interface, "GetSubTreePaths",
313 "/xyz/openbmc_project/inventory/system", 2,
314 std::array<std::string, 1>{
315 "xyz.openbmc_project.Inventory.Item.System"});
316}