1 #include <ipmid/entity_map_json.hpp>
2 #include <ipmid/types.hpp>
3 #include <nlohmann/json.hpp>
4
5 #include <exception>
6 #include <fstream>
7 #include <memory>
8 #include <string>
9 #include <utility>
10
11 namespace ipmi
12 {
13 namespace sensor
14 {
15
getContainer()16 EntityInfoMapContainer* EntityInfoMapContainer::getContainer()
17 {
18 static std::unique_ptr<EntityInfoMapContainer> instance;
19
20 if (!instance)
21 {
22 /* TODO: With multi-threading this would all need to be locked so
23 * the first thread to hit it would set it up.
24 */
25 EntityInfoMap builtEntityMap = buildEntityMapFromFile();
26 instance = std::unique_ptr<EntityInfoMapContainer>(
27 new EntityInfoMapContainer(builtEntityMap));
28 }
29
30 return instance.get();
31 }
32
getIpmiEntityRecords()33 const EntityInfoMap& EntityInfoMapContainer::getIpmiEntityRecords()
34 {
35 return entityRecords;
36 }
37
buildEntityMapFromFile()38 EntityInfoMap buildEntityMapFromFile()
39 {
40 const char* entityMapJsonFilename =
41 "/usr/share/ipmi-providers/entity-map.json";
42 EntityInfoMap builtMap;
43
44 std::ifstream mapFile(entityMapJsonFilename);
45 if (!mapFile.is_open())
46 {
47 return builtMap;
48 }
49
50 auto data = nlohmann::json::parse(mapFile, nullptr, false);
51 if (data.is_discarded())
52 {
53 return builtMap;
54 }
55
56 return buildJsonEntityMap(data);
57 }
58
buildJsonEntityMap(const nlohmann::json & data)59 EntityInfoMap buildJsonEntityMap(const nlohmann::json& data)
60 {
61 EntityInfoMap builtMap;
62
63 if (data.type() != nlohmann::json::value_t::array)
64 {
65 return builtMap;
66 }
67
68 try
69 {
70 for (const auto& entry : data)
71 {
72 /* It's an array entry with the following fields: id,
73 * containerEntityId, containerEntityInstance, isList, isLinked,
74 * entities[4]
75 */
76 EntityInfo obj;
77 Id recordId = entry.at("id").get<Id>();
78 obj.containerEntityId =
79 entry.at("containerEntityId").get<uint8_t>();
80 obj.containerEntityInstance =
81 entry.at("containerEntityInstance").get<uint8_t>();
82 obj.isList = entry.at("isList").get<bool>();
83 obj.isLinked = entry.at("isLinked").get<bool>();
84
85 auto jsonEntities = entry.at("entities");
86
87 if (jsonEntities.type() != nlohmann::json::value_t::array)
88 {
89 throw std::runtime_error(
90 "Invalid type for entities entry, must be array");
91 }
92 if (jsonEntities.size() != obj.containedEntities.size())
93 {
94 throw std::runtime_error(
95 "Entities must be in pairs of " +
96 std::to_string(obj.containedEntities.size()));
97 }
98
99 for (std::size_t i = 0; i < obj.containedEntities.size(); i++)
100 {
101 obj.containedEntities[i] = std::make_pair(
102 jsonEntities[i].at("id").get<uint8_t>(),
103 jsonEntities[i].at("instance").get<uint8_t>());
104 }
105
106 builtMap.insert({recordId, obj});
107 }
108 }
109 catch (const std::exception& e)
110 {
111 /* If any entry is invalid, the entire file cannot be trusted. */
112 builtMap.clear();
113 }
114
115 return builtMap;
116 }
117
118 } // namespace sensor
119 } // namespace ipmi
120