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