1 #include "event_parser.hpp"
2 
3 #include <phosphor-logging/lg2.hpp>
4 #include <xyz/openbmc_project/Common/error.hpp>
5 
6 #include <filesystem>
7 #include <fstream>
8 #include <set>
9 
10 PHOSPHOR_LOG2_USING;
11 
12 namespace pldm::responder::events
13 {
14 namespace fs = std::filesystem;
15 using InternalFailure =
16     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
17 
18 const Json emptyJson{};
19 const std::vector<Json> emptyJsonList{};
20 
21 const std::set<std::string_view> supportedDbusPropertyTypes = {
22     "bool",     "uint8_t", "int16_t",  "uint16_t", "int32_t",
23     "uint32_t", "int64_t", "uint64_t", "double",   "string"};
24 
25 StateSensorHandler::StateSensorHandler(const std::string& dirPath)
26 {
27     fs::path dir(dirPath);
28     if (!fs::exists(dir) || fs::is_empty(dir))
29     {
30         error("Event config directory at '{PATH}' does not exist or empty",
31               "PATH", dirPath.c_str());
32         return;
33     }
34 
35     for (auto& file : fs::directory_iterator(dirPath))
36     {
37         std::ifstream jsonFile(file.path());
38 
39         auto data = Json::parse(jsonFile, nullptr, false);
40         if (data.is_discarded())
41         {
42             error("Failed to parse event state sensor JSON file at '{PATH}'",
43                   "PATH", file.path().c_str());
44             continue;
45         }
46 
47         auto entries = data.value("entries", emptyJsonList);
48         for (const auto& entry : entries)
49         {
50             StateSensorEntry stateSensorEntry{};
51             stateSensorEntry.containerId =
52                 static_cast<uint16_t>(entry.value("containerID", 0));
53             stateSensorEntry.entityType =
54                 static_cast<uint16_t>(entry.value("entityType", 0));
55             stateSensorEntry.entityInstance =
56                 static_cast<uint16_t>(entry.value("entityInstance", 0));
57             stateSensorEntry.sensorOffset =
58                 static_cast<uint8_t>(entry.value("sensorOffset", 0));
59             stateSensorEntry.stateSetid =
60                 static_cast<uint16_t>(entry.value("stateSetId", 0));
61 
62             pldm::utils::DBusMapping dbusInfo{};
63 
64             auto dbus = entry.value("dbus", emptyJson);
65             dbusInfo.objectPath = dbus.value("object_path", "");
66             dbusInfo.interface = dbus.value("interface", "");
67             dbusInfo.propertyName = dbus.value("property_name", "");
68             dbusInfo.propertyType = dbus.value("property_type", "");
69             if (dbusInfo.objectPath.empty() || dbusInfo.interface.empty() ||
70                 dbusInfo.propertyName.empty() ||
71                 !supportedDbusPropertyTypes.contains(dbusInfo.propertyType))
72             {
73                 error(
74                     "Invalid dbus config at '{PATH}', interface '{DBUS_INTERFACE}', property name '{PROPERTY_NAME}' and property type '{PROPERTY_TYPE}'",
75                     "PATH", dbusInfo.objectPath.c_str(), "DBUS_INTERFACE",
76                     dbusInfo.interface, "PROPERTY_NAME", dbusInfo.propertyName,
77                     "PROPERTY_TYPE", dbusInfo.propertyType);
78                 continue;
79             }
80 
81             auto eventStates = entry.value("event_states", emptyJsonList);
82             auto propertyValues = dbus.value("property_values", emptyJsonList);
83             if ((eventStates.size() == 0) || (propertyValues.size() == 0) ||
84                 (eventStates.size() != propertyValues.size()))
85             {
86                 error(
87                     "Invalid event state JSON config size '{EVENT_STATE_SIZE}' and property value size '{PROPERTY_VALUE_SIZE}'",
88                     "EVENT_STATE_SIZE", eventStates.size(),
89                     "PROPERTY_VALUE_SIZE", propertyValues.size());
90                 continue;
91             }
92 
93             auto eventStateMap = mapStateToDBusVal(eventStates, propertyValues,
94                                                    dbusInfo.propertyType);
95             eventMap.emplace(
96                 stateSensorEntry,
97                 std::make_tuple(std::move(dbusInfo), std::move(eventStateMap)));
98         }
99     }
100 }
101 
102 StateToDBusValue StateSensorHandler::mapStateToDBusVal(
103     const Json& eventStates, const Json& propertyValues, std::string_view type)
104 {
105     StateToDBusValue eventStateMap{};
106     auto stateIt = eventStates.begin();
107     auto propIt = propertyValues.begin();
108 
109     for (; stateIt != eventStates.end(); ++stateIt, ++propIt)
110     {
111         auto propValue = utils::jsonEntryToDbusVal(type, propIt.value());
112         eventStateMap.emplace((*stateIt).get<uint8_t>(), std::move(propValue));
113     }
114 
115     return eventStateMap;
116 }
117 
118 int StateSensorHandler::eventAction(const StateSensorEntry& entry,
119                                     pdr::EventState state)
120 {
121     try
122     {
123         const auto& [dbusMapping, eventStateMap] = eventMap.at(entry);
124         utils::PropertyValue propValue{};
125         try
126         {
127             propValue = eventStateMap.at(state);
128         }
129         catch (const std::out_of_range& e)
130         {
131             error("Invalid event state '{EVENT_STATE}', error - {ERROR}",
132                   "EVENT_STATE", state, "ERROR", e);
133             return PLDM_ERROR_INVALID_DATA;
134         }
135 
136         try
137         {
138             pldm::utils::DBusHandler().setDbusProperty(dbusMapping, propValue);
139         }
140         catch (const std::exception& e)
141         {
142             error(
143                 "Failed to  set property '{PROPERTY}' on interface '{INTERFACE}' at path '{PATH}', error - {ERROR}",
144                 "PROPERTY", dbusMapping.propertyName, "INTERFACE",
145                 dbusMapping.interface, "PATH", dbusMapping.objectPath, "ERROR",
146                 e);
147             return PLDM_ERROR;
148         }
149     }
150     catch (const std::out_of_range&)
151     {
152         // There is no BMC action for this PLDM event
153         return PLDM_SUCCESS;
154     }
155     return PLDM_SUCCESS;
156 }
157 
158 } // namespace pldm::responder::events
159