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