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);
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());
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", 0xFFFF));
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             // container id is not found in the json
63             stateSensorEntry.skipContainerId =
64                 (stateSensorEntry.containerId == 0xFFFF) ? true : false;
65 
66             pldm::utils::DBusMapping dbusInfo{};
67 
68             auto dbus = entry.value("dbus", emptyJson);
69             dbusInfo.objectPath = dbus.value("object_path", "");
70             dbusInfo.interface = dbus.value("interface", "");
71             dbusInfo.propertyName = dbus.value("property_name", "");
72             dbusInfo.propertyType = dbus.value("property_type", "");
73             if (dbusInfo.objectPath.empty() || dbusInfo.interface.empty() ||
74                 dbusInfo.propertyName.empty() ||
75                 !supportedDbusPropertyTypes.contains(dbusInfo.propertyType))
76             {
77                 error(
78                     "Invalid dbus config at '{PATH}', interface '{DBUS_INTERFACE}', property name '{PROPERTY_NAME}' and property type '{PROPERTY_TYPE}'",
79                     "PATH", dbusInfo.objectPath, "DBUS_INTERFACE",
80                     dbusInfo.interface, "PROPERTY_NAME", dbusInfo.propertyName,
81                     "PROPERTY_TYPE", dbusInfo.propertyType);
82                 continue;
83             }
84 
85             auto eventStates = entry.value("event_states", emptyJsonList);
86             auto propertyValues = dbus.value("property_values", emptyJsonList);
87             if ((eventStates.size() == 0) || (propertyValues.size() == 0) ||
88                 (eventStates.size() != propertyValues.size()))
89             {
90                 error(
91                     "Invalid event state JSON config size '{EVENT_STATE_SIZE}' and property value size '{PROPERTY_VALUE_SIZE}'",
92                     "EVENT_STATE_SIZE", eventStates.size(),
93                     "PROPERTY_VALUE_SIZE", propertyValues.size());
94                 continue;
95             }
96 
97             auto eventStateMap = mapStateToDBusVal(eventStates, propertyValues,
98                                                    dbusInfo.propertyType);
99             eventMap.emplace(
100                 stateSensorEntry,
101                 std::make_tuple(std::move(dbusInfo), std::move(eventStateMap)));
102         }
103     }
104 }
105 
106 StateToDBusValue StateSensorHandler::mapStateToDBusVal(
107     const Json& eventStates, const Json& propertyValues, std::string_view type)
108 {
109     StateToDBusValue eventStateMap{};
110     auto stateIt = eventStates.begin();
111     auto propIt = propertyValues.begin();
112 
113     for (; stateIt != eventStates.end(); ++stateIt, ++propIt)
114     {
115         auto propValue = utils::jsonEntryToDbusVal(type, propIt.value());
116         eventStateMap.emplace((*stateIt).get<uint8_t>(), std::move(propValue));
117     }
118 
119     return eventStateMap;
120 }
121 
122 int StateSensorHandler::eventAction(const StateSensorEntry& entry,
123                                     pdr::EventState state)
124 {
125     try
126     {
127         const auto& [dbusMapping, eventStateMap] = eventMap.at(entry);
128         utils::PropertyValue propValue{};
129         try
130         {
131             propValue = eventStateMap.at(state);
132         }
133         catch (const std::out_of_range& e)
134         {
135             error("Invalid event state '{EVENT_STATE}', error - {ERROR}",
136                   "EVENT_STATE", state, "ERROR", e);
137             return PLDM_ERROR_INVALID_DATA;
138         }
139 
140         try
141         {
142             pldm::utils::DBusHandler().setDbusProperty(dbusMapping, propValue);
143         }
144         catch (const std::exception& e)
145         {
146             error(
147                 "Failed to  set property '{PROPERTY}' on interface '{INTERFACE}' at path '{PATH}', error - {ERROR}",
148                 "PROPERTY", dbusMapping.propertyName, "INTERFACE",
149                 dbusMapping.interface, "PATH", dbusMapping.objectPath, "ERROR",
150                 e);
151             return PLDM_ERROR;
152         }
153     }
154     catch (const std::out_of_range&)
155     {
156         // There is no BMC action for this PLDM event
157         return PLDM_SUCCESS;
158     }
159     return PLDM_SUCCESS;
160 }
161 
162 } // namespace pldm::responder::events
163