xref: /openbmc/dbus-sensors/src/Utils.cpp (revision 6714a25a)
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 <Utils.hpp>
18 #include <boost/algorithm/string/predicate.hpp>
19 #include <experimental/filesystem>
20 #include <fstream>
21 #include <regex>
22 #include <sdbusplus/asio/connection.hpp>
23 #include <sdbusplus/bus/match.hpp>
24 
25 namespace fs = std::experimental::filesystem;
26 const static constexpr char* POWER_INTERFACE_NAME =
27     "xyz.openbmc_project.Chassis.Control.Power";
28 const static constexpr char* POWER_OBJECT_NAME =
29     "/xyz/openbmc_project/Chassis/Control/Power0";
30 
31 bool getSensorConfiguration(
32     const std::string& type,
33     const std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
34     ManagedObjectType& resp, bool useCache)
35 {
36     static ManagedObjectType managedObj;
37 
38     if (!useCache)
39     {
40         managedObj.clear();
41         sdbusplus::message::message getManagedObjects =
42             dbusConnection->new_method_call(
43                 ENTITY_MANAGER_NAME, "/", "org.freedesktop.DBus.ObjectManager",
44                 "GetManagedObjects");
45         bool err = false;
46         try
47         {
48             sdbusplus::message::message reply =
49                 dbusConnection->call(getManagedObjects);
50             err = reply.is_method_error();
51             if (!err)
52             {
53                 reply.read(managedObj);
54             }
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 find_files(const fs::path dir_path, const std::string& match_string,
89                 std::vector<fs::path>& found_paths, unsigned int symlink_depth)
90 {
91     if (!fs::exists(dir_path))
92         return false;
93 
94     fs::directory_iterator end_itr;
95     std::regex search(match_string);
96     std::smatch match;
97     for (auto& p : fs::recursive_directory_iterator(dir_path))
98     {
99         std::string path = p.path().string();
100         if (!is_directory(p))
101         {
102             if (std::regex_search(path, match, search))
103                 found_paths.emplace_back(p.path());
104         }
105         // since we're using a recursive iterator, these should only be symlink
106         // dirs
107         else if (symlink_depth)
108         {
109             find_files(p.path(), match_string, found_paths, symlink_depth - 1);
110         }
111     }
112     return true;
113 }
114 
115 // initially returns false, then sets up matches and returns status
116 // should be called once first to initialize
117 bool isPowerOn(const std::shared_ptr<sdbusplus::asio::connection>& conn)
118 {
119     static std::unique_ptr<sdbusplus::bus::match::match> powerMatch = nullptr;
120     static bool powerStatusOn = false;
121 
122     if (powerMatch != nullptr)
123     {
124         return powerStatusOn;
125     }
126 
127     // create a match for powergood changes, first time do a method call to
128     // return the correct value
129     std::function<void(sdbusplus::message::message & message)> eventHandler =
130         [&powerStatusOn](sdbusplus::message::message& message) {
131             std::string objectName;
132             boost::container::flat_map<std::string,
133                                        sdbusplus::message::variant<int32_t>>
134                 values;
135             message.read(objectName, values);
136             auto findPgood = values.find("pgood");
137             if (findPgood != values.end())
138             {
139                 powerStatusOn = sdbusplus::message::variant_ns::get<int32_t>(
140                     findPgood->second);
141             }
142         };
143 
144     powerMatch = std::make_unique<sdbusplus::bus::match::match>(
145         static_cast<sdbusplus::bus::bus&>(*conn),
146         "type='signal',interface='org.freedesktop.DBus.Properties',path_"
147         "namespace='/xyz/openbmc_project/Chassis/Control/"
148         "power0',arg0='xyz.openbmc_project.Chassis.Control.Power'",
149         eventHandler);
150 
151     conn->async_method_call(
152         [&powerStatusOn](boost::system::error_code ec,
153                          const sdbusplus::message::variant<int32_t>& pgood) {
154             if (ec)
155             {
156                 std::cerr << "Error getting initial power status\n";
157                 return;
158             }
159             powerStatusOn = sdbusplus::message::variant_ns::get<int32_t>(pgood);
160         },
161         POWER_INTERFACE_NAME, POWER_OBJECT_NAME,
162         "org.freedesktop.DBus.Properties", "Get", "pgood");
163 
164     return powerStatusOn;
165 }