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