xref: /openbmc/dbus-sensors/src/Utils.cpp (revision 0e022058)
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             reply.read(managedObj);
51         }
52         catch (const sdbusplus::exception::exception&)
53         {
54             err = true;
55         }
56 
57         if (err)
58         {
59             std::cerr << "Error communicating to entity manager\n";
60             return false;
61         }
62     }
63     for (const auto& pathPair : managedObj)
64     {
65         std::vector<boost::container::flat_map<std::string, BasicVariantType>>
66             sensorData;
67         bool correctType = false;
68         for (const auto& entry : pathPair.second)
69         {
70             if (boost::starts_with(entry.first, type))
71             {
72                 correctType = true;
73                 break;
74             }
75         }
76         if (correctType)
77         {
78             resp.emplace(pathPair);
79         }
80     }
81     return true;
82 }
83 
84 bool find_files(const fs::path dir_path, const std::string& match_string,
85                 std::vector<fs::path>& found_paths, unsigned int symlink_depth)
86 {
87     if (!fs::exists(dir_path))
88         return false;
89 
90     fs::directory_iterator end_itr;
91     std::regex search(match_string);
92     std::smatch match;
93     for (auto& p : fs::recursive_directory_iterator(dir_path))
94     {
95         std::string path = p.path().string();
96         if (!is_directory(p))
97         {
98             if (std::regex_search(path, match, search))
99                 found_paths.emplace_back(p.path());
100         }
101         // since we're using a recursive iterator, these should only be symlink
102         // dirs
103         else if (symlink_depth)
104         {
105             find_files(p.path(), match_string, found_paths, symlink_depth - 1);
106         }
107     }
108     return true;
109 }
110 
111 // initially returns false, then sets up matches and returns status
112 // should be called once first to initialize
113 bool isPowerOn(const std::shared_ptr<sdbusplus::asio::connection>& conn)
114 {
115     static std::unique_ptr<sdbusplus::bus::match::match> powerMatch = nullptr;
116     static bool powerStatusOn = false;
117 
118     if (powerMatch != nullptr)
119     {
120         return powerStatusOn;
121     }
122 
123     // create a match for powergood changes, first time do a method call to
124     // return the correct value
125     std::function<void(sdbusplus::message::message & message)> eventHandler =
126         [&powerStatusOn](sdbusplus::message::message& message) {
127             std::string objectName;
128             boost::container::flat_map<std::string,
129                                        sdbusplus::message::variant<int32_t>>
130                 values;
131             message.read(objectName, values);
132             auto findPgood = values.find("pgood");
133             if (findPgood != values.end())
134             {
135                 powerStatusOn = sdbusplus::message::variant_ns::get<int32_t>(
136                     findPgood->second);
137             }
138         };
139 
140     powerMatch = std::make_unique<sdbusplus::bus::match::match>(
141         static_cast<sdbusplus::bus::bus&>(*conn),
142         "type='signal',interface='org.freedesktop.DBus.Properties',path_"
143         "namespace='/xyz/openbmc_project/Chassis/Control/"
144         "power0',arg0='xyz.openbmc_project.Chassis.Control.Power'",
145         eventHandler);
146 
147     conn->async_method_call(
148         [&powerStatusOn](boost::system::error_code ec,
149                          const sdbusplus::message::variant<int32_t>& pgood) {
150             if (ec)
151             {
152                 std::cerr << "Error getting initial power status\n";
153                 return;
154             }
155             powerStatusOn = sdbusplus::message::variant_ns::get<int32_t>(pgood);
156         },
157         POWER_INTERFACE_NAME, POWER_OBJECT_NAME,
158         "org.freedesktop.DBus.Properties", "Get", "pgood");
159 
160     return powerStatusOn;
161 }