xref: /openbmc/entity-manager/src/entity_manager/dbus_interface.cpp (revision 91e360ebd7a1d4b87d2156761827c78cbedda557)
1fc9e7fdaSChristopher Meis #include "dbus_interface.hpp"
2fc9e7fdaSChristopher Meis 
3fc9e7fdaSChristopher Meis #include "perform_probe.hpp"
459ef1e72SChristopher Meis #include "utils.hpp"
5fc9e7fdaSChristopher Meis 
6fc9e7fdaSChristopher Meis #include <boost/algorithm/string/case_conv.hpp>
7fc9e7fdaSChristopher Meis #include <boost/container/flat_map.hpp>
8fc9e7fdaSChristopher Meis 
959ef1e72SChristopher Meis #include <fstream>
10fc9e7fdaSChristopher Meis #include <regex>
11fc9e7fdaSChristopher Meis #include <string>
12fc9e7fdaSChristopher Meis #include <vector>
13fc9e7fdaSChristopher Meis 
14fc9e7fdaSChristopher Meis using JsonVariantType =
15fc9e7fdaSChristopher Meis     std::variant<std::vector<std::string>, std::vector<double>, std::string,
16fc9e7fdaSChristopher Meis                  int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
17fc9e7fdaSChristopher Meis                  uint16_t, uint8_t, bool>;
18fc9e7fdaSChristopher Meis 
19fc9e7fdaSChristopher Meis namespace dbus_interface
20fc9e7fdaSChristopher Meis {
21fc9e7fdaSChristopher Meis 
22fc9e7fdaSChristopher Meis const std::regex illegalDbusPathRegex("[^A-Za-z0-9_.]");
23fc9e7fdaSChristopher Meis const std::regex illegalDbusMemberRegex("[^A-Za-z0-9_]");
24fc9e7fdaSChristopher Meis 
25fc9e7fdaSChristopher Meis // NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
26fc9e7fdaSChristopher Meis // store reference to all interfaces so we can destroy them later
27fc9e7fdaSChristopher Meis boost::container::flat_map<
28fc9e7fdaSChristopher Meis     std::string, std::vector<std::weak_ptr<sdbusplus::asio::dbus_interface>>>
29fc9e7fdaSChristopher Meis     inventory;
30fc9e7fdaSChristopher Meis // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
31fc9e7fdaSChristopher Meis 
tryIfaceInitialize(std::shared_ptr<sdbusplus::asio::dbus_interface> & iface)32fc9e7fdaSChristopher Meis void tryIfaceInitialize(std::shared_ptr<sdbusplus::asio::dbus_interface>& iface)
33fc9e7fdaSChristopher Meis {
34fc9e7fdaSChristopher Meis     try
35fc9e7fdaSChristopher Meis     {
36fc9e7fdaSChristopher Meis         iface->initialize();
37fc9e7fdaSChristopher Meis     }
38fc9e7fdaSChristopher Meis     catch (std::exception& e)
39fc9e7fdaSChristopher Meis     {
40fc9e7fdaSChristopher Meis         std::cerr << "Unable to initialize dbus interface : " << e.what()
41fc9e7fdaSChristopher Meis                   << "\n"
42fc9e7fdaSChristopher Meis                   << "object Path : " << iface->get_object_path() << "\n"
43fc9e7fdaSChristopher Meis                   << "interface name : " << iface->get_interface_name() << "\n";
44fc9e7fdaSChristopher Meis     }
45fc9e7fdaSChristopher Meis }
46fc9e7fdaSChristopher Meis 
createInterface(sdbusplus::asio::object_server & objServer,const std::string & path,const std::string & interface,const std::string & parent,bool checkNull)47fc9e7fdaSChristopher Meis std::shared_ptr<sdbusplus::asio::dbus_interface> createInterface(
48fc9e7fdaSChristopher Meis     sdbusplus::asio::object_server& objServer, const std::string& path,
49fc9e7fdaSChristopher Meis     const std::string& interface, const std::string& parent, bool checkNull)
50fc9e7fdaSChristopher Meis {
51fc9e7fdaSChristopher Meis     // on first add we have no reason to check for null before add, as there
52fc9e7fdaSChristopher Meis     // won't be any. For dynamically added interfaces, we check for null so that
53fc9e7fdaSChristopher Meis     // a constant delete/add will not create a memory leak
54fc9e7fdaSChristopher Meis 
55fc9e7fdaSChristopher Meis     auto ptr = objServer.add_interface(path, interface);
56fc9e7fdaSChristopher Meis     auto& dataVector = inventory[parent];
57fc9e7fdaSChristopher Meis     if (checkNull)
58fc9e7fdaSChristopher Meis     {
59fc9e7fdaSChristopher Meis         auto it = std::find_if(dataVector.begin(), dataVector.end(),
60fc9e7fdaSChristopher Meis                                [](const auto& p) { return p.expired(); });
61fc9e7fdaSChristopher Meis         if (it != dataVector.end())
62fc9e7fdaSChristopher Meis         {
63fc9e7fdaSChristopher Meis             *it = ptr;
64fc9e7fdaSChristopher Meis             return ptr;
65fc9e7fdaSChristopher Meis         }
66fc9e7fdaSChristopher Meis     }
67fc9e7fdaSChristopher Meis     dataVector.emplace_back(ptr);
68fc9e7fdaSChristopher Meis     return ptr;
69fc9e7fdaSChristopher Meis }
70fc9e7fdaSChristopher Meis 
createDeleteObjectMethod(const std::string & jsonPointerPath,const std::shared_ptr<sdbusplus::asio::dbus_interface> & iface,sdbusplus::asio::object_server & objServer,nlohmann::json & systemConfiguration)71fc9e7fdaSChristopher Meis void createDeleteObjectMethod(
72fc9e7fdaSChristopher Meis     const std::string& jsonPointerPath,
73fc9e7fdaSChristopher Meis     const std::shared_ptr<sdbusplus::asio::dbus_interface>& iface,
74fc9e7fdaSChristopher Meis     sdbusplus::asio::object_server& objServer,
75fc9e7fdaSChristopher Meis     nlohmann::json& systemConfiguration)
76fc9e7fdaSChristopher Meis {
77fc9e7fdaSChristopher Meis     std::weak_ptr<sdbusplus::asio::dbus_interface> interface = iface;
78fc9e7fdaSChristopher Meis     iface->register_method(
79fc9e7fdaSChristopher Meis         "Delete", [&objServer, &systemConfiguration, interface,
80fc9e7fdaSChristopher Meis                    jsonPointerPath{std::string(jsonPointerPath)}]() {
81fc9e7fdaSChristopher Meis             std::shared_ptr<sdbusplus::asio::dbus_interface> dbusInterface =
82fc9e7fdaSChristopher Meis                 interface.lock();
83fc9e7fdaSChristopher Meis             if (!dbusInterface)
84fc9e7fdaSChristopher Meis             {
85fc9e7fdaSChristopher Meis                 // this technically can't happen as the pointer is pointing to
86fc9e7fdaSChristopher Meis                 // us
87fc9e7fdaSChristopher Meis                 throw DBusInternalError();
88fc9e7fdaSChristopher Meis             }
89fc9e7fdaSChristopher Meis             nlohmann::json::json_pointer ptr(jsonPointerPath);
90fc9e7fdaSChristopher Meis             systemConfiguration[ptr] = nullptr;
91fc9e7fdaSChristopher Meis 
92fc9e7fdaSChristopher Meis             // todo(james): dig through sdbusplus to find out why we can't
93fc9e7fdaSChristopher Meis             // delete it in a method call
94fc9e7fdaSChristopher Meis             boost::asio::post(io, [&objServer, dbusInterface]() mutable {
95fc9e7fdaSChristopher Meis                 objServer.remove_interface(dbusInterface);
96fc9e7fdaSChristopher Meis             });
97fc9e7fdaSChristopher Meis 
98fc9e7fdaSChristopher Meis             if (!configuration::writeJsonFiles(systemConfiguration))
99fc9e7fdaSChristopher Meis             {
100fc9e7fdaSChristopher Meis                 std::cerr << "error setting json file\n";
101fc9e7fdaSChristopher Meis                 throw DBusInternalError();
102fc9e7fdaSChristopher Meis             }
103fc9e7fdaSChristopher Meis         });
104fc9e7fdaSChristopher Meis }
105fc9e7fdaSChristopher Meis 
106d72dc33dSAlexander Hansen static bool checkArrayElementsSameType(nlohmann::json& value)
populateInterfaceFromJson(nlohmann::json & systemConfiguration,const std::string & jsonPointerPath,std::shared_ptr<sdbusplus::asio::dbus_interface> & iface,nlohmann::json & dict,sdbusplus::asio::object_server & objServer,sdbusplus::asio::PropertyPermission permission)107d72dc33dSAlexander Hansen {
108d72dc33dSAlexander Hansen     nlohmann::json::array_t* arr = value.get_ptr<nlohmann::json::array_t*>();
109d72dc33dSAlexander Hansen     if (arr == nullptr)
110d72dc33dSAlexander Hansen     {
111d72dc33dSAlexander Hansen         return false;
112d72dc33dSAlexander Hansen     }
113d72dc33dSAlexander Hansen 
114d72dc33dSAlexander Hansen     if (arr->empty())
115d72dc33dSAlexander Hansen     {
116d72dc33dSAlexander Hansen         return true;
117d72dc33dSAlexander Hansen     }
118d72dc33dSAlexander Hansen 
119d72dc33dSAlexander Hansen     nlohmann::json::value_t firstType = value[0].type();
120d72dc33dSAlexander Hansen     return std::ranges::all_of(value, [firstType](const nlohmann::json& el) {
121d72dc33dSAlexander Hansen         return el.type() == firstType;
122d72dc33dSAlexander Hansen     });
123d72dc33dSAlexander Hansen }
124d72dc33dSAlexander Hansen 
125*91e360ebSAlexander Hansen static nlohmann::json::value_t getDBusType(
126*91e360ebSAlexander Hansen     const nlohmann::json& value, nlohmann::json::value_t type,
127fc9e7fdaSChristopher Meis     sdbusplus::asio::PropertyPermission permission)
128fc9e7fdaSChristopher Meis {
12917f8e6aeSAlexander Hansen     const bool array = value.type() == nlohmann::json::value_t::array;
130fc9e7fdaSChristopher Meis 
131fc9e7fdaSChristopher Meis     if (permission == sdbusplus::asio::PropertyPermission::readWrite)
132fc9e7fdaSChristopher Meis     {
133fc9e7fdaSChristopher Meis         // all setable numbers are doubles as it is difficult to always
134fc9e7fdaSChristopher Meis         // create a configuration file with all whole numbers as decimals
135fc9e7fdaSChristopher Meis         // i.e. 1.0
136fc9e7fdaSChristopher Meis         if (array)
137fc9e7fdaSChristopher Meis         {
138fc9e7fdaSChristopher Meis             if (value[0].is_number())
139fc9e7fdaSChristopher Meis             {
140*91e360ebSAlexander Hansen                 return nlohmann::json::value_t::number_float;
141fc9e7fdaSChristopher Meis             }
142fc9e7fdaSChristopher Meis         }
143fc9e7fdaSChristopher Meis         else if (value.is_number())
144fc9e7fdaSChristopher Meis         {
145*91e360ebSAlexander Hansen             return nlohmann::json::value_t::number_float;
146fc9e7fdaSChristopher Meis         }
147fc9e7fdaSChristopher Meis     }
148fc9e7fdaSChristopher Meis 
149*91e360ebSAlexander Hansen     return type;
150*91e360ebSAlexander Hansen }
151*91e360ebSAlexander Hansen 
152*91e360ebSAlexander Hansen static void populateInterfacePropertyFromJson(
153*91e360ebSAlexander Hansen     nlohmann::json& systemConfiguration, const std::string& path,
154*91e360ebSAlexander Hansen     const nlohmann::json& key, const nlohmann::json& value,
155*91e360ebSAlexander Hansen     nlohmann::json::value_t type,
156*91e360ebSAlexander Hansen     std::shared_ptr<sdbusplus::asio::dbus_interface>& iface,
157*91e360ebSAlexander Hansen     sdbusplus::asio::PropertyPermission permission)
158*91e360ebSAlexander Hansen {
159*91e360ebSAlexander Hansen     const auto modifiedType = getDBusType(value, type, permission);
160*91e360ebSAlexander Hansen 
161*91e360ebSAlexander Hansen     switch (modifiedType)
162fc9e7fdaSChristopher Meis     {
163fc9e7fdaSChristopher Meis         case (nlohmann::json::value_t::boolean):
164fc9e7fdaSChristopher Meis         {
165*91e360ebSAlexander Hansen             if (value.is_array())
166fc9e7fdaSChristopher Meis             {
167fc9e7fdaSChristopher Meis                 // todo: array of bool isn't detected correctly by
168fc9e7fdaSChristopher Meis                 // sdbusplus, change it to numbers
16917f8e6aeSAlexander Hansen                 addArrayToDbus<uint64_t>(key, value, iface.get(), permission,
17017f8e6aeSAlexander Hansen                                          systemConfiguration, path);
171fc9e7fdaSChristopher Meis             }
172fc9e7fdaSChristopher Meis 
173fc9e7fdaSChristopher Meis             else
174fc9e7fdaSChristopher Meis             {
175fc9e7fdaSChristopher Meis                 addProperty(key, value.get<bool>(), iface.get(),
176fc9e7fdaSChristopher Meis                             systemConfiguration, path, permission);
177fc9e7fdaSChristopher Meis             }
178fc9e7fdaSChristopher Meis             break;
179fc9e7fdaSChristopher Meis         }
180fc9e7fdaSChristopher Meis         case (nlohmann::json::value_t::number_integer):
181fc9e7fdaSChristopher Meis         {
182d7908697SAlexander Hansen             addValueToDBus<int64_t>(key, value, *iface, permission,
183fc9e7fdaSChristopher Meis                                     systemConfiguration, path);
184fc9e7fdaSChristopher Meis             break;
185fc9e7fdaSChristopher Meis         }
186fc9e7fdaSChristopher Meis         case (nlohmann::json::value_t::number_unsigned):
187fc9e7fdaSChristopher Meis         {
188d7908697SAlexander Hansen             addValueToDBus<uint64_t>(key, value, *iface, permission,
189d7908697SAlexander Hansen                                      systemConfiguration, path);
190fc9e7fdaSChristopher Meis             break;
191fc9e7fdaSChristopher Meis         }
192fc9e7fdaSChristopher Meis         case (nlohmann::json::value_t::number_float):
193fc9e7fdaSChristopher Meis         {
194d7908697SAlexander Hansen             addValueToDBus<double>(key, value, *iface, permission,
195fc9e7fdaSChristopher Meis                                    systemConfiguration, path);
196fc9e7fdaSChristopher Meis             break;
197fc9e7fdaSChristopher Meis         }
198fc9e7fdaSChristopher Meis         case (nlohmann::json::value_t::string):
199fc9e7fdaSChristopher Meis         {
200d7908697SAlexander Hansen             addValueToDBus<std::string>(key, value, *iface, permission,
201d7908697SAlexander Hansen                                         systemConfiguration, path);
202fc9e7fdaSChristopher Meis             break;
203fc9e7fdaSChristopher Meis         }
204fc9e7fdaSChristopher Meis         default:
205fc9e7fdaSChristopher Meis         {
20617f8e6aeSAlexander Hansen             std::cerr << "Unexpected json type in system configuration " << key
20717f8e6aeSAlexander Hansen                       << ": " << value.type_name() << "\n";
208fc9e7fdaSChristopher Meis             break;
209fc9e7fdaSChristopher Meis         }
210fc9e7fdaSChristopher Meis     }
211fc9e7fdaSChristopher Meis }
21217f8e6aeSAlexander Hansen 
21317f8e6aeSAlexander Hansen // adds simple json types to interface's properties
21417f8e6aeSAlexander Hansen void populateInterfaceFromJson(
21517f8e6aeSAlexander Hansen     nlohmann::json& systemConfiguration, const std::string& jsonPointerPath,
21617f8e6aeSAlexander Hansen     std::shared_ptr<sdbusplus::asio::dbus_interface>& iface,
21717f8e6aeSAlexander Hansen     nlohmann::json& dict, sdbusplus::asio::object_server& objServer,
21817f8e6aeSAlexander Hansen     sdbusplus::asio::PropertyPermission permission)
21917f8e6aeSAlexander Hansen {
22017f8e6aeSAlexander Hansen     for (const auto& [key, value] : dict.items())
22117f8e6aeSAlexander Hansen     {
22217f8e6aeSAlexander Hansen         auto type = value.type();
22317f8e6aeSAlexander Hansen         if (value.type() == nlohmann::json::value_t::array)
22417f8e6aeSAlexander Hansen         {
22517f8e6aeSAlexander Hansen             if (value.empty())
22617f8e6aeSAlexander Hansen             {
22717f8e6aeSAlexander Hansen                 continue;
22817f8e6aeSAlexander Hansen             }
22917f8e6aeSAlexander Hansen             type = value[0].type();
23017f8e6aeSAlexander Hansen             if (!checkArrayElementsSameType(value))
23117f8e6aeSAlexander Hansen             {
23217f8e6aeSAlexander Hansen                 std::cerr << "dbus format error" << value << "\n";
23317f8e6aeSAlexander Hansen                 continue;
23417f8e6aeSAlexander Hansen             }
23517f8e6aeSAlexander Hansen         }
23617f8e6aeSAlexander Hansen         if (type == nlohmann::json::value_t::object)
23717f8e6aeSAlexander Hansen         {
23817f8e6aeSAlexander Hansen             continue; // handled elsewhere
23917f8e6aeSAlexander Hansen         }
24017f8e6aeSAlexander Hansen 
24117f8e6aeSAlexander Hansen         std::string path = jsonPointerPath;
24217f8e6aeSAlexander Hansen         path.append("/").append(key);
24317f8e6aeSAlexander Hansen 
24417f8e6aeSAlexander Hansen         populateInterfacePropertyFromJson(systemConfiguration, path, key, value,
24517f8e6aeSAlexander Hansen                                           type, iface, permission);
24617f8e6aeSAlexander Hansen     }
247fc9e7fdaSChristopher Meis     if (permission == sdbusplus::asio::PropertyPermission::readWrite)
248fc9e7fdaSChristopher Meis     {
249fc9e7fdaSChristopher Meis         createDeleteObjectMethod(jsonPointerPath, iface, objServer,
250fc9e7fdaSChristopher Meis                                  systemConfiguration);
251fc9e7fdaSChristopher Meis     }
252fc9e7fdaSChristopher Meis     tryIfaceInitialize(iface);
253fc9e7fdaSChristopher Meis }
254fc9e7fdaSChristopher Meis 
255fc9e7fdaSChristopher Meis void createAddObjectMethod(
256fc9e7fdaSChristopher Meis     const std::string& jsonPointerPath, const std::string& path,
257fc9e7fdaSChristopher Meis     nlohmann::json& systemConfiguration,
258fc9e7fdaSChristopher Meis     sdbusplus::asio::object_server& objServer, const std::string& board)
259fc9e7fdaSChristopher Meis {
260fc9e7fdaSChristopher Meis     std::shared_ptr<sdbusplus::asio::dbus_interface> iface = createInterface(
261fc9e7fdaSChristopher Meis         objServer, path, "xyz.openbmc_project.AddObject", board);
createAddObjectMethod(const std::string & jsonPointerPath,const std::string & path,nlohmann::json & systemConfiguration,sdbusplus::asio::object_server & objServer,const std::string & board)262fc9e7fdaSChristopher Meis 
263fc9e7fdaSChristopher Meis     iface->register_method(
264fc9e7fdaSChristopher Meis         "AddObject",
265fc9e7fdaSChristopher Meis         [&systemConfiguration, &objServer,
266fc9e7fdaSChristopher Meis          jsonPointerPath{std::string(jsonPointerPath)}, path{std::string(path)},
267fc9e7fdaSChristopher Meis          board](const boost::container::flat_map<std::string, JsonVariantType>&
268fc9e7fdaSChristopher Meis                     data) {
269fc9e7fdaSChristopher Meis             nlohmann::json::json_pointer ptr(jsonPointerPath);
270fc9e7fdaSChristopher Meis             nlohmann::json& base = systemConfiguration[ptr];
271fc9e7fdaSChristopher Meis             auto findExposes = base.find("Exposes");
272fc9e7fdaSChristopher Meis 
273fc9e7fdaSChristopher Meis             if (findExposes == base.end())
274fc9e7fdaSChristopher Meis             {
__anoncc3dd2920402(const boost::container::flat_map<std::string, JsonVariantType>& data) 275fc9e7fdaSChristopher Meis                 throw std::invalid_argument("Entity must have children.");
276fc9e7fdaSChristopher Meis             }
277fc9e7fdaSChristopher Meis 
278fc9e7fdaSChristopher Meis             // this will throw invalid-argument to sdbusplus if invalid json
279fc9e7fdaSChristopher Meis             nlohmann::json newData{};
280fc9e7fdaSChristopher Meis             for (const auto& item : data)
281fc9e7fdaSChristopher Meis             {
282fc9e7fdaSChristopher Meis                 nlohmann::json& newJson = newData[item.first];
283fc9e7fdaSChristopher Meis                 std::visit(
284fc9e7fdaSChristopher Meis                     [&newJson](auto&& val) {
285fc9e7fdaSChristopher Meis                         newJson = std::forward<decltype(val)>(val);
286fc9e7fdaSChristopher Meis                     },
287fc9e7fdaSChristopher Meis                     item.second);
288fc9e7fdaSChristopher Meis             }
289fc9e7fdaSChristopher Meis 
290fc9e7fdaSChristopher Meis             auto findName = newData.find("Name");
__anoncc3dd2920502(auto&& val) 291fc9e7fdaSChristopher Meis             auto findType = newData.find("Type");
292fc9e7fdaSChristopher Meis             if (findName == newData.end() || findType == newData.end())
293fc9e7fdaSChristopher Meis             {
294fc9e7fdaSChristopher Meis                 throw std::invalid_argument("AddObject missing Name or Type");
295fc9e7fdaSChristopher Meis             }
296fc9e7fdaSChristopher Meis             const std::string* type = findType->get_ptr<const std::string*>();
297fc9e7fdaSChristopher Meis             const std::string* name = findName->get_ptr<const std::string*>();
298fc9e7fdaSChristopher Meis             if (type == nullptr || name == nullptr)
299fc9e7fdaSChristopher Meis             {
300fc9e7fdaSChristopher Meis                 throw std::invalid_argument("Type and Name must be a string.");
301fc9e7fdaSChristopher Meis             }
302fc9e7fdaSChristopher Meis 
303fc9e7fdaSChristopher Meis             bool foundNull = false;
304fc9e7fdaSChristopher Meis             size_t lastIndex = 0;
305fc9e7fdaSChristopher Meis             // we add in the "exposes"
306fc9e7fdaSChristopher Meis             for (const auto& expose : *findExposes)
307fc9e7fdaSChristopher Meis             {
308fc9e7fdaSChristopher Meis                 if (expose.is_null())
309fc9e7fdaSChristopher Meis                 {
310fc9e7fdaSChristopher Meis                     foundNull = true;
311fc9e7fdaSChristopher Meis                     continue;
312fc9e7fdaSChristopher Meis                 }
313fc9e7fdaSChristopher Meis 
314fc9e7fdaSChristopher Meis                 if (expose["Name"] == *name && expose["Type"] == *type)
315fc9e7fdaSChristopher Meis                 {
316fc9e7fdaSChristopher Meis                     throw std::invalid_argument(
317fc9e7fdaSChristopher Meis                         "Field already in JSON, not adding");
318fc9e7fdaSChristopher Meis                 }
319fc9e7fdaSChristopher Meis 
320fc9e7fdaSChristopher Meis                 if (foundNull)
321fc9e7fdaSChristopher Meis                 {
322fc9e7fdaSChristopher Meis                     continue;
323fc9e7fdaSChristopher Meis                 }
324fc9e7fdaSChristopher Meis 
325fc9e7fdaSChristopher Meis                 lastIndex++;
326fc9e7fdaSChristopher Meis             }
327fc9e7fdaSChristopher Meis 
328fc9e7fdaSChristopher Meis             std::ifstream schemaFile(
329fc9e7fdaSChristopher Meis                 std::string(configuration::schemaDirectory) + "/" +
330fc9e7fdaSChristopher Meis                 boost::to_lower_copy(*type) + ".json");
331fc9e7fdaSChristopher Meis             // todo(james) we might want to also make a list of 'can add'
332fc9e7fdaSChristopher Meis             // interfaces but for now I think the assumption if there is a
333fc9e7fdaSChristopher Meis             // schema avaliable that it is allowed to update is fine
334fc9e7fdaSChristopher Meis             if (!schemaFile.good())
335fc9e7fdaSChristopher Meis             {
336fc9e7fdaSChristopher Meis                 throw std::invalid_argument(
337fc9e7fdaSChristopher Meis                     "No schema avaliable, cannot validate.");
338fc9e7fdaSChristopher Meis             }
339fc9e7fdaSChristopher Meis             nlohmann::json schema =
340fc9e7fdaSChristopher Meis                 nlohmann::json::parse(schemaFile, nullptr, false, true);
341fc9e7fdaSChristopher Meis             if (schema.is_discarded())
342fc9e7fdaSChristopher Meis             {
343fc9e7fdaSChristopher Meis                 std::cerr << "Schema not legal" << *type << ".json\n";
344fc9e7fdaSChristopher Meis                 throw DBusInternalError();
345fc9e7fdaSChristopher Meis             }
346fc9e7fdaSChristopher Meis             if (!configuration::validateJson(schema, newData))
347fc9e7fdaSChristopher Meis             {
348fc9e7fdaSChristopher Meis                 throw std::invalid_argument("Data does not match schema");
349fc9e7fdaSChristopher Meis             }
350fc9e7fdaSChristopher Meis             if (foundNull)
351fc9e7fdaSChristopher Meis             {
352fc9e7fdaSChristopher Meis                 findExposes->at(lastIndex) = newData;
353fc9e7fdaSChristopher Meis             }
354fc9e7fdaSChristopher Meis             else
355fc9e7fdaSChristopher Meis             {
356fc9e7fdaSChristopher Meis                 findExposes->push_back(newData);
357fc9e7fdaSChristopher Meis             }
358fc9e7fdaSChristopher Meis             if (!configuration::writeJsonFiles(systemConfiguration))
359fc9e7fdaSChristopher Meis             {
360fc9e7fdaSChristopher Meis                 std::cerr << "Error writing json files\n";
361fc9e7fdaSChristopher Meis                 throw DBusInternalError();
362fc9e7fdaSChristopher Meis             }
363fc9e7fdaSChristopher Meis             std::string dbusName = *name;
364fc9e7fdaSChristopher Meis 
365fc9e7fdaSChristopher Meis             std::regex_replace(dbusName.begin(), dbusName.begin(),
366fc9e7fdaSChristopher Meis                                dbusName.end(), illegalDbusMemberRegex, "_");
367fc9e7fdaSChristopher Meis 
368fc9e7fdaSChristopher Meis             std::shared_ptr<sdbusplus::asio::dbus_interface> interface =
369fc9e7fdaSChristopher Meis                 createInterface(objServer, path + "/" + dbusName,
370fc9e7fdaSChristopher Meis                                 "xyz.openbmc_project.Configuration." + *type,
371fc9e7fdaSChristopher Meis                                 board, true);
372fc9e7fdaSChristopher Meis             // permission is read-write, as since we just created it, must be
373fc9e7fdaSChristopher Meis             // runtime modifiable
374fc9e7fdaSChristopher Meis             populateInterfaceFromJson(
375fc9e7fdaSChristopher Meis                 systemConfiguration,
376fc9e7fdaSChristopher Meis                 jsonPointerPath + "/Exposes/" + std::to_string(lastIndex),
377fc9e7fdaSChristopher Meis                 interface, newData, objServer,
378fc9e7fdaSChristopher Meis                 sdbusplus::asio::PropertyPermission::readWrite);
379fc9e7fdaSChristopher Meis         });
380fc9e7fdaSChristopher Meis     tryIfaceInitialize(iface);
381fc9e7fdaSChristopher Meis }
382fc9e7fdaSChristopher Meis 
383fc9e7fdaSChristopher Meis std::vector<std::weak_ptr<sdbusplus::asio::dbus_interface>>&
384fc9e7fdaSChristopher Meis     getDeviceInterfaces(const nlohmann::json& device)
385fc9e7fdaSChristopher Meis {
386fc9e7fdaSChristopher Meis     return inventory[device["Name"].get<std::string>()];
387fc9e7fdaSChristopher Meis }
388fc9e7fdaSChristopher Meis 
389fc9e7fdaSChristopher Meis } // namespace dbus_interface
390