xref: /openbmc/dbus-sensors/src/Utils.cpp (revision b82c2a78)
1 /*
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 
17 #include "filesystem.hpp"
18 
19 #include <Utils.hpp>
20 #include <boost/algorithm/string/predicate.hpp>
21 #include <fstream>
22 #include <regex>
23 #include <sdbusplus/asio/connection.hpp>
24 #include <sdbusplus/bus/match.hpp>
25 
26 namespace fs = std::filesystem;
27 const static constexpr char* powerInterfaceName =
28     "xyz.openbmc_project.Chassis.Control.Power";
29 const static constexpr char* powerObjectName =
30     "/xyz/openbmc_project/Chassis/Control/Power0";
31 
32 static bool powerStatusOn = false;
33 static std::unique_ptr<sdbusplus::bus::match::match> powerMatch = nullptr;
34 
35 bool getSensorConfiguration(
36     const std::string& type,
37     const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
38     ManagedObjectType& resp, bool useCache)
39 {
40     static ManagedObjectType managedObj;
41 
42     if (!useCache)
43     {
44         managedObj.clear();
45         sdbusplus::message::message getManagedObjects =
46             dbusConnection->new_method_call(
47                 entityManagerName, "/", "org.freedesktop.DBus.ObjectManager",
48                 "GetManagedObjects");
49         bool err = false;
50         try
51         {
52             sdbusplus::message::message reply =
53                 dbusConnection->call(getManagedObjects);
54             reply.read(managedObj);
55         }
56         catch (const sdbusplus::exception::exception&)
57         {
58             err = true;
59         }
60 
61         if (err)
62         {
63             std::cerr << "Error communicating to entity manager\n";
64             return false;
65         }
66     }
67     for (const auto& pathPair : managedObj)
68     {
69         std::vector<boost::container::flat_map<std::string, BasicVariantType>>
70             sensorData;
71         bool correctType = false;
72         for (const auto& entry : pathPair.second)
73         {
74             if (boost::starts_with(entry.first, type))
75             {
76                 correctType = true;
77                 break;
78             }
79         }
80         if (correctType)
81         {
82             resp.emplace(pathPair);
83         }
84     }
85     return true;
86 }
87 
88 bool findFiles(const fs::path dirPath, const std::string& matchString,
89                std::vector<fs::path>& foundPaths, unsigned int symlinkDepth)
90 {
91     if (!fs::exists(dirPath))
92         return false;
93 
94     std::regex search(matchString);
95     std::smatch match;
96     for (auto& p : fs::recursive_directory_iterator(dirPath))
97     {
98         std::string path = p.path().string();
99         if (!is_directory(p))
100         {
101             if (std::regex_search(path, match, search))
102                 foundPaths.emplace_back(p.path());
103         }
104         else if (is_symlink(p) && symlinkDepth)
105         {
106             findFiles(p.path(), matchString, foundPaths, symlinkDepth - 1);
107         }
108     }
109     return true;
110 }
111 
112 bool isPowerOn(void)
113 {
114     if (!powerMatch)
115     {
116         throw std::runtime_error("Power Match Not Created");
117     }
118     return powerStatusOn;
119 }
120 
121 void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn)
122 {
123 
124     // create a match for powergood changes, first time do a method call to
125     // cache the correct value
126     std::function<void(sdbusplus::message::message & message)> eventHandler =
127         [](sdbusplus::message::message& message) {
128             std::string objectName;
129             boost::container::flat_map<std::string,
130                                        sdbusplus::message::variant<int32_t>>
131                 values;
132             message.read(objectName, values);
133             auto findPgood = values.find("pgood");
134             if (findPgood != values.end())
135             {
136                 powerStatusOn = sdbusplus::message::variant_ns::get<int32_t>(
137                     findPgood->second);
138             }
139         };
140 
141     powerMatch = std::make_unique<sdbusplus::bus::match::match>(
142         static_cast<sdbusplus::bus::bus&>(*conn),
143         "type='signal',interface='org.freedesktop.DBus.Properties',path_"
144         "namespace='/xyz/openbmc_project/Chassis/Control/"
145         "power0',arg0='xyz.openbmc_project.Chassis.Control.Power'",
146         eventHandler);
147 
148     conn->async_method_call(
149         [](boost::system::error_code ec,
150            const sdbusplus::message::variant<int32_t>& pgood) {
151             if (ec)
152             {
153                 std::cerr << "Error getting initial power status\n";
154                 return;
155             }
156             powerStatusOn = sdbusplus::message::variant_ns::get<int32_t>(pgood);
157         },
158         powerInterfaceName, powerObjectName, "org.freedesktop.DBus.Properties",
159         "Get", powerInterfaceName, "pgood");
160 }
161 
162 // replaces limits if MinReading and MaxReading are found.
163 void findLimits(std::pair<double, double>& limits,
164                 const SensorBaseConfiguration* data)
165 {
166     if (!data)
167     {
168         return;
169     }
170     auto maxFind = data->second.find("MaxReading");
171     auto minFind = data->second.find("MinReading");
172 
173     if (minFind != data->second.end())
174     {
175         limits.first = sdbusplus::message::variant_ns::visit(
176             VariantToDoubleVisitor(), minFind->second);
177     }
178     if (maxFind != data->second.end())
179     {
180         limits.second = sdbusplus::message::variant_ns::visit(
181             VariantToDoubleVisitor(), maxFind->second);
182     }
183 }