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