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 does not exist or empty, DIR={DIR_PATH}",
31               "DIR_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(
43                 "Parsing Event state sensor JSON file failed, FILE={FILE_PATH}",
44                 "FILE_PATH", file.path().c_str());
45             continue;
46         }
47 
48         auto entries = data.value("entries", emptyJsonList);
49         for (const auto& entry : entries)
50         {
51             StateSensorEntry stateSensorEntry{};
52             stateSensorEntry.containerId =
53                 static_cast<uint16_t>(entry.value("containerID", 0));
54             stateSensorEntry.entityType =
55                 static_cast<uint16_t>(entry.value("entityType", 0));
56             stateSensorEntry.entityInstance =
57                 static_cast<uint16_t>(entry.value("entityInstance", 0));
58             stateSensorEntry.sensorOffset =
59                 static_cast<uint8_t>(entry.value("sensorOffset", 0));
60             stateSensorEntry.stateSetid =
61                 static_cast<uint16_t>(entry.value("stateSetId", 0));
62 
63             pldm::utils::DBusMapping dbusInfo{};
64 
65             auto dbus = entry.value("dbus", emptyJson);
66             dbusInfo.objectPath = dbus.value("object_path", "");
67             dbusInfo.interface = dbus.value("interface", "");
68             dbusInfo.propertyName = dbus.value("property_name", "");
69             dbusInfo.propertyType = dbus.value("property_type", "");
70             if (dbusInfo.objectPath.empty() || dbusInfo.interface.empty() ||
71                 dbusInfo.propertyName.empty() ||
72                 !supportedDbusPropertyTypes.contains(dbusInfo.propertyType))
73             {
74                 error(
75                     "Invalid dbus config, OBJPATH= {DBUS_OBJ_PATH} INTERFACE={DBUS_INTF} PROPERTY_NAME={DBUS_PROP} PROPERTY_TYPE={DBUS_PROP_TYPE}",
76                     "DBUS_OBJ_PATH", dbusInfo.objectPath.c_str(), "DBUS_INTF",
77                     dbusInfo.interface, "DBUS_PROP", dbusInfo.propertyName,
78                     "DBUS_PROP_TYPE", dbusInfo.propertyType);
79                 continue;
80             }
81 
82             auto eventStates = entry.value("event_states", emptyJsonList);
83             auto propertyValues = dbus.value("property_values", emptyJsonList);
84             if ((eventStates.size() == 0) || (propertyValues.size() == 0) ||
85                 (eventStates.size() != propertyValues.size()))
86             {
87                 error(
88                     "Invalid event state JSON config, EVENT_STATE_SIZE={EVENT_STATE_SIZE} PROPERTY_VALUE_SIZE={PROP_VAL_SIZE}",
89                     "EVENT_STATE_SIZE", eventStates.size(), "PROP_VAL_SIZE",
90                     propertyValues.size());
91                 continue;
92             }
93 
94             auto eventStateMap = mapStateToDBusVal(eventStates, propertyValues,
95                                                    dbusInfo.propertyType);
96             eventMap.emplace(
97                 stateSensorEntry,
98                 std::make_tuple(std::move(dbusInfo), std::move(eventStateMap)));
99         }
100     }
101 }
102 
103 StateToDBusValue StateSensorHandler::mapStateToDBusVal(
104     const Json& eventStates, const Json& propertyValues, std::string_view type)
105 {
106     StateToDBusValue eventStateMap{};
107     auto stateIt = eventStates.begin();
108     auto propIt = propertyValues.begin();
109 
110     for (; stateIt != eventStates.end(); ++stateIt, ++propIt)
111     {
112         auto propValue = utils::jsonEntryToDbusVal(type, propIt.value());
113         eventStateMap.emplace((*stateIt).get<uint8_t>(), std::move(propValue));
114     }
115 
116     return eventStateMap;
117 }
118 
119 int StateSensorHandler::eventAction(const StateSensorEntry& entry,
120                                     pdr::EventState state)
121 {
122     try
123     {
124         const auto& [dbusMapping, eventStateMap] = eventMap.at(entry);
125         utils::PropertyValue propValue{};
126         try
127         {
128             propValue = eventStateMap.at(state);
129         }
130         catch (const std::out_of_range& e)
131         {
132             error("Invalid event state '{EVENT_STATE}': {ERROR}", "EVENT_STATE",
133                   state, "ERROR", e);
134             return PLDM_ERROR_INVALID_DATA;
135         }
136 
137         try
138         {
139             pldm::utils::DBusHandler().setDbusProperty(dbusMapping, propValue);
140         }
141         catch (const std::exception& e)
142         {
143             error(
144                 "Error setting property value '{PROPERTY}' on interface '{INTERFACE}' at '{PATH}': {ERROR}",
145                 "PROPERTY", dbusMapping.propertyName, "INTERFACE",
146                 dbusMapping.interface, "PATH", dbusMapping.objectPath, "ERROR",
147                 e);
148             return PLDM_ERROR;
149         }
150     }
151     catch (const std::out_of_range&)
152     {
153         // There is no BMC action for this PLDM event
154         return PLDM_SUCCESS;
155     }
156     return PLDM_SUCCESS;
157 }
158 
159 } // namespace pldm::responder::events
160