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