blob: dbfc536d779baee91f73153dc77598b551b81379 [file] [log] [blame]
Deepak Kodihalli5de09572017-05-16 23:53:40 -05001## This file is a template. The comment below is emitted
2## into the rendered file; feel free to edit this file.
3// WARNING: Generated header. Do not edit!
Deepak Kodihalli5de09572017-05-16 23:53:40 -05004<%
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -05005import re
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -05006from collections import defaultdict
Patrick Williamsbcf95782021-05-05 16:20:32 -05007from sdbusplus.namedelement import NamedElement
Patrick Williams2b7152f2020-04-02 07:18:32 -05008objects = settingsDict.keys()
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -05009sdbusplus_includes = []
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050010props = defaultdict(list)
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -050011validators = defaultdict(tuple)
Deepak Kodihalli5de09572017-05-16 23:53:40 -050012
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050013def get_setting_sdbusplus_type(setting_intf):
Deepak Kodihalli5de09572017-05-16 23:53:40 -050014 setting = "sdbusplus::" + setting_intf.replace('.', '::')
15 i = setting.rfind('::')
16 setting = setting[:i] + '::server::' + setting[i+2:]
17 return setting
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050018
Deepak Kodihallidb838622017-08-27 02:46:47 -050019def get_setting_type(path):
20 path = path[1:]
21 path = path.replace('/', '::')
22 return path
Matt Spinlerffdf8652023-05-24 11:09:54 -050023
24def get_default_value(object, interface, prop):
25 default_value = None
26 for item in settingsDict[object]:
27 if item['Interface'] == interface:
28 default_value = item['Properties'][prop]['Default']
29 break
30
31 if isinstance(default_value, str) and not \
32 default_value.startswith('"') and '::' in default_value:
33 ns = get_setting_sdbusplus_type(interface)
34 i = ns.rfind('::')
35 default_value = "{}::{}".format(ns[:i], default_value)
36
37 return default_value
Deepak Kodihalli5de09572017-05-16 23:53:40 -050038%>\
39#pragma once
40
41% for object in objects:
Deepak Kodihallidb838622017-08-27 02:46:47 -050042 % for item in settingsDict[object]:
Deepak Kodihalli5de09572017-05-16 23:53:40 -050043<%
Deepak Kodihallidb838622017-08-27 02:46:47 -050044 include = item['Interface']
Deepak Kodihalli5de09572017-05-16 23:53:40 -050045 include = include.replace('.', '/')
46 include = include + "/server.hpp"
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050047 sdbusplus_includes.append(include)
Deepak Kodihalli5de09572017-05-16 23:53:40 -050048%>\
Deepak Kodihallidb838622017-08-27 02:46:47 -050049 % endfor
Deepak Kodihalli5de09572017-05-16 23:53:40 -050050% endfor
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050051#include <cereal/archives/json.hpp>
James Feist74e3be72019-02-15 09:59:42 -080052#include <cereal/types/vector.hpp>
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050053#include <fstream>
54#include <utility>
Patrick Williams6306e5e2022-06-16 17:14:54 -050055#include <filesystem>
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -050056#include <regex>
57#include <phosphor-logging/elog.hpp>
58#include <phosphor-logging/elog-errors.hpp>
59#include <phosphor-logging/log.hpp>
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -050060#include <xyz/openbmc_project/Common/error.hpp>
Tom Joseph4636e072017-09-24 20:47:24 +053061using namespace phosphor::logging;
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050062
Jagpal Singh Gill4d28bcd2023-04-23 23:34:05 -070063/* The DBus busname to own */
64#define SETTINGS_BUSNAME "xyz.openbmc_project.Settings"
65/* Path of directory housing persisted settings */
66#define SETTINGS_PERSIST_PATH "/var/lib/phosphor-settings-manager/settings"
67
68/* Class version to register with Cereal */
69static constexpr size_t CLASS_VERSION = 1;
70
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050071% for i in set(sdbusplus_includes):
Deepak Kodihalli5de09572017-05-16 23:53:40 -050072#include "${i}"
73% endfor
74
Deepak Kodihalli5de09572017-05-16 23:53:40 -050075namespace phosphor
76{
77namespace settings
78{
79
Patrick Williams6306e5e2022-06-16 17:14:54 -050080namespace fs = std::filesystem;
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050081
Deepak Kodihalli242bc772017-08-04 02:47:54 -050082namespace persistent
83{
84
85// A setting d-bus object /foo/bar/baz is persisted in the filesystem with the
86// same path. This eases re-construction of settings objects when we restore
87// from the filesystem. This can be a problem though when you have two objects
88// such as - /foo/bar and /foo/bar/baz. This is because 'bar' will be treated as
89// a file in the first case, and a subdir in the second. To solve this, suffix
90// files with a trailing __. The __ is a safe character sequence to use, because
91// we won't have d-bus object paths ending with this.
92// With this the objects would be persisted as - /foo/bar__ and /foo/bar/baz__.
93constexpr auto fileSuffix = "__";
94
95}
96
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050097% for object in objects:
98<%
Deepak Kodihallidb838622017-08-27 02:46:47 -050099 ns = object.split('/')
100 ns.pop(0)
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500101%>\
102% for n in ns:
103namespace ${n}
104{
105% endfor
Deepak Kodihallidb838622017-08-27 02:46:47 -0500106<%
107 interfaces = []
108 aliases = []
109 for item in settingsDict[object]:
110 interfaces.append(item['Interface'])
111 for name, meta in item['Properties'].items():
112 if 'Validation' in meta:
113 dict = meta['Validation']
114 if dict['Type'] == "range":
115 validators[name] = (dict['Type'], dict['Validator'], dict['Unit'])
116 else:
117 validators[name] = (dict['Type'], dict['Validator'])
118%>
119% for index, intf in enumerate(interfaces):
120using Iface${index} = ${get_setting_sdbusplus_type(intf)};
121<% aliases.append("Iface" + str(index)) %>\
122% endfor
123<%
Patrick Williams7c4181c2022-07-22 19:26:52 -0500124 parent = "sdbusplus::server::object_t" + "<" + ", ".join(aliases) + ">"
Deepak Kodihallidb838622017-08-27 02:46:47 -0500125%>\
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500126using Parent = ${parent};
127
128class Impl : public Parent
129{
130 public:
Patrick Williams7c4181c2022-07-22 19:26:52 -0500131 Impl(sdbusplus::bus_t& bus, const char* path):
Patrick Williams74c4f3b2022-04-05 16:16:20 -0500132 Parent(bus, path, Parent::action::defer_emit),
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500133 path(path)
134 {
135 }
136 virtual ~Impl() = default;
137
Deepak Kodihallidb838622017-08-27 02:46:47 -0500138% for index, item in enumerate(settingsDict[object]):
139 % for propName, metaDict in item['Properties'].items():
Patrick Williamsbcf95782021-05-05 16:20:32 -0500140<% t = NamedElement(name=propName).camelCase %>\
Deepak Kodihallidb838622017-08-27 02:46:47 -0500141<% fname = "validate" + propName %>\
142 decltype(std::declval<Iface${index}>().${t}()) ${t}(decltype(std::declval<Iface${index}>().${t}()) value) override
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500143 {
Deepak Kodihallidb838622017-08-27 02:46:47 -0500144 auto result = Iface${index}::${t}();
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500145 if (value != result)
146 {
Deepak Kodihallidb838622017-08-27 02:46:47 -0500147 % if propName in validators:
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500148 if (!${fname}(value))
149 {
150 namespace error =
151 sdbusplus::xyz::openbmc_project::Common::Error;
152 namespace metadata =
153 phosphor::logging::xyz::openbmc_project::Common;
154 phosphor::logging::report<error::InvalidArgument>(
155 metadata::InvalidArgument::ARGUMENT_NAME("${t}"),
Deepak Kodihallidb838622017-08-27 02:46:47 -0500156 % if validators[propName][0] != "regex":
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500157 metadata::InvalidArgument::ARGUMENT_VALUE(std::to_string(value).c_str()));
158 % else:
159 metadata::InvalidArgument::ARGUMENT_VALUE(value.c_str()));
160 % endif
161 return result;
162 }
163 % endif
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500164 fs::path p(SETTINGS_PERSIST_PATH);
Adriana Kobylakf792a6d2022-07-20 15:07:08 -0500165 p /= path.relative_path();
Deepak Kodihalli242bc772017-08-04 02:47:54 -0500166 p += persistent::fileSuffix;
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500167 fs::create_directories(p.parent_path());
168 std::ofstream os(p.c_str(), std::ios::binary);
169 cereal::JSONOutputArchive oarchive(os);
Deepak Kodihallidb838622017-08-27 02:46:47 -0500170 result = Iface${index}::${t}(value);
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500171 oarchive(*this);
172 }
173 return result;
174 }
Deepak Kodihallidb838622017-08-27 02:46:47 -0500175 using Iface${index}::${t};
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500176
Deepak Kodihallidb838622017-08-27 02:46:47 -0500177 % endfor
Andrew Geisslerc15990a2017-07-06 11:36:31 -0500178% endfor
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500179 private:
180 fs::path path;
Deepak Kodihallidb838622017-08-27 02:46:47 -0500181% for index, item in enumerate(settingsDict[object]):
182 % for propName, metaDict in item['Properties'].items():
Patrick Williamsbcf95782021-05-05 16:20:32 -0500183<% t = NamedElement(name=propName).camelCase %>\
Deepak Kodihallidb838622017-08-27 02:46:47 -0500184<% fname = "validate" + propName %>\
185 % if propName in validators:
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500186
Deepak Kodihallidb838622017-08-27 02:46:47 -0500187 bool ${fname}(decltype(std::declval<Iface${index}>().${t}()) value)
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500188 {
189 bool matched = false;
Deepak Kodihallidb838622017-08-27 02:46:47 -0500190 % if (validators[propName][0] == 'regex'):
191 std::regex regexToCheck("${validators[propName][1]}");
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500192 matched = std::regex_search(value, regexToCheck);
193 if (!matched)
194 {
Deepak Kodihallidb838622017-08-27 02:46:47 -0500195 std::string err = "Input parameter for ${propName} is invalid "
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500196 "Input: " + value + " not in the format of this regex: "
Deepak Kodihallidb838622017-08-27 02:46:47 -0500197 "${validators[propName][1]}";
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500198 using namespace phosphor::logging;
199 log<level::ERR>(err.c_str());
200 }
Deepak Kodihallidb838622017-08-27 02:46:47 -0500201 % elif (validators[propName][0] == 'range'):
202<% lowhigh = re.split('\.\.', validators[propName][1]) %>\
Jagpal Singh Gillcfd49eb2023-04-23 23:09:09 -0700203 % if lowhigh[0] == '0':
204 if (value <= ${lowhigh[1]})
205 % else:
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500206 if ((value <= ${lowhigh[1]}) && (value >= ${lowhigh[0]}))
Jagpal Singh Gillcfd49eb2023-04-23 23:09:09 -0700207 % endif
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500208 {
209 matched = true;
210 }
211 else
212 {
Deepak Kodihallidb838622017-08-27 02:46:47 -0500213 std::string err = "Input parameter for ${propName} is invalid "
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500214 "Input: " + std::to_string(value) + "in uint: "
Deepak Kodihallidb838622017-08-27 02:46:47 -0500215 "${validators[propName][2]} is not in range:${validators[propName][1]}";
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500216 using namespace phosphor::logging;
217 log<level::ERR>(err.c_str());
218 }
Deepak Kodihallidb838622017-08-27 02:46:47 -0500219 % else:
220 <% assert("Unknown validation type: propName") %>\
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500221 % endif
222 return matched;
223 }
Deepak Kodihallidb838622017-08-27 02:46:47 -0500224 % endif
225 % endfor
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500226% endfor
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500227};
228
229template<class Archive>
230void save(Archive& a,
Vishwanatha Subbannaa29a3eb2017-09-29 19:18:20 +0530231 const Impl& setting,
Jagpal Singh Gillcfd49eb2023-04-23 23:09:09 -0700232 [[maybe_unused]] const std::uint32_t version)
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500233{
234<%
Deepak Kodihallidb838622017-08-27 02:46:47 -0500235props = []
236for index, item in enumerate(settingsDict[object]):
Patrick Williamsbcf95782021-05-05 16:20:32 -0500237 intfProps = ["setting." + NamedElement(name=propName).camelCase + "()" for \
Deepak Kodihallidb838622017-08-27 02:46:47 -0500238 propName, metaDict in item['Properties'].items()]
239 props.extend(intfProps)
240props = ', '.join(props)
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500241%>\
Lei YUc0ce9922022-03-09 16:01:10 +0800242% if props:
Deepak Kodihallidb838622017-08-27 02:46:47 -0500243 a(${props});
Lei YUc0ce9922022-03-09 16:01:10 +0800244% endif
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500245}
246
247template<class Archive>
248void load(Archive& a,
Vishwanatha Subbannaa29a3eb2017-09-29 19:18:20 +0530249 Impl& setting,
Jagpal Singh Gillcfd49eb2023-04-23 23:09:09 -0700250 [[maybe_unused]] const std::uint32_t version)
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500251{
Deepak Kodihallidb838622017-08-27 02:46:47 -0500252<% props = [] %>\
253% for index, item in enumerate(settingsDict[object]):
254 % for prop, metaDict in item['Properties'].items():
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500255<%
Patrick Williamsbcf95782021-05-05 16:20:32 -0500256 t = "setting." + NamedElement(name=prop).camelCase + "()"
Deepak Kodihallidb838622017-08-27 02:46:47 -0500257 props.append(prop)
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500258%>\
Deepak Kodihallidb838622017-08-27 02:46:47 -0500259 decltype(${t}) ${prop}{};
260 % endfor
261% endfor
262<% props = ', '.join(props) %>
Lei YUc0ce9922022-03-09 16:01:10 +0800263% if props:
Deepak Kodihallidb838622017-08-27 02:46:47 -0500264 a(${props});
Lei YUc0ce9922022-03-09 16:01:10 +0800265% endif
266
Deepak Kodihallidb838622017-08-27 02:46:47 -0500267<% props = [] %>
268% for index, item in enumerate(settingsDict[object]):
269 % for prop, metaDict in item['Properties'].items():
270<%
Patrick Williamsbcf95782021-05-05 16:20:32 -0500271 t = "setting." + NamedElement(name=prop).camelCase + "(" + prop + ")"
Deepak Kodihallidb838622017-08-27 02:46:47 -0500272%>\
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500273 ${t};
Deepak Kodihallidb838622017-08-27 02:46:47 -0500274 % endfor
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500275% endfor
276}
277
278% for n in reversed(ns):
279} // namespace ${n}
280% endfor
Deepak Kodihallidb838622017-08-27 02:46:47 -0500281
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500282% endfor
283
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500284/** @class Manager
285 *
286 * @brief Compose settings objects and put them on the bus.
287 */
288class Manager
289{
290 public:
291 Manager() = delete;
292 Manager(const Manager&) = delete;
293 Manager& operator=(const Manager&) = delete;
294 Manager(Manager&&) = delete;
295 Manager& operator=(Manager&&) = delete;
296 virtual ~Manager() = default;
297
298 /** @brief Constructor to put settings objects on to the bus.
299 * @param[in] bus - Bus to attach to.
300 */
Patrick Williams7c4181c2022-07-22 19:26:52 -0500301 explicit Manager(sdbusplus::bus_t& bus) :
Patrick Williams0f6903d2022-04-15 10:03:58 -0500302 settings(
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500303 std::make_tuple(
Deepak Kodihallidb838622017-08-27 02:46:47 -0500304% for index, path in enumerate(objects):
305<% type = get_setting_type(path) + "::Impl" %>\
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500306 std::make_unique<${type}>(
307 bus,
308 % if index < len(settingsDict) - 1:
Deepak Kodihallidb838622017-08-27 02:46:47 -0500309 "${path}"),
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500310 % else:
Patrick Williams0f6903d2022-04-15 10:03:58 -0500311 "${path}")
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500312 % endif
313% endfor
Patrick Williams0f6903d2022-04-15 10:03:58 -0500314 )
315 )
316 {
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500317
Patrick Williams0f6903d2022-04-15 10:03:58 -0500318 fs::path path{};
Deepak Kodihallidb838622017-08-27 02:46:47 -0500319% for index, path in enumerate(objects):
Adriana Kobylakf792a6d2022-07-20 15:07:08 -0500320<% relativePath = path[1:] %>\
321 path = fs::path(SETTINGS_PERSIST_PATH) / "${relativePath}";
Deepak Kodihalli242bc772017-08-04 02:47:54 -0500322 path += persistent::fileSuffix;
Tom Joseph4636e072017-09-24 20:47:24 +0530323 auto initSetting${index} = [&]()
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500324 {
Deepak Kodihallidb838622017-08-27 02:46:47 -0500325 % for item in settingsDict[path]:
326 % for propName, metaDict in item['Properties'].items():
Patrick Williamsbcf95782021-05-05 16:20:32 -0500327<% p = NamedElement(name=propName).camelCase %>\
Matt Spinlerffdf8652023-05-24 11:09:54 -0500328<% defaultValue = get_default_value(path, item['Interface'], propName) %>\
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500329 std::get<${index}>(settings)->
Tom Joseph4636e072017-09-24 20:47:24 +0530330 ${get_setting_sdbusplus_type(item['Interface'])}::${p}(${defaultValue});
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500331 % endfor
Tom Joseph4636e072017-09-24 20:47:24 +0530332% endfor
333 };
334
335 try
336 {
337 if (fs::exists(path))
338 {
339 std::ifstream is(path.c_str(), std::ios::in);
340 cereal::JSONInputArchive iarchive(is);
341 iarchive(*std::get<${index}>(settings));
342 }
343 else
344 {
345 initSetting${index}();
346 }
347 }
Patrick Williamsb6fa9bb2021-10-06 12:27:57 -0500348 catch (const cereal::Exception& e)
Tom Joseph4636e072017-09-24 20:47:24 +0530349 {
350 log<level::ERR>(e.what());
351 fs::remove(path);
352 initSetting${index}();
Deepak Kodihallidb838622017-08-27 02:46:47 -0500353 }
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500354 std::get<${index}>(settings)->emit_object_added();
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500355
356% endfor
357 }
358
359 private:
360 /* @brief Composition of settings objects. */
361 std::tuple<
Deepak Kodihallidb838622017-08-27 02:46:47 -0500362% for index, path in enumerate(objects):
363<% type = get_setting_type(path) + "::Impl" %>\
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500364 % if index < len(settingsDict) - 1:
365 std::unique_ptr<${type}>,
366 % else:
367 std::unique_ptr<${type}>> settings;
368 % endif
369% endfor
370};
371
372} // namespace settings
373} // namespace phosphor
Vishwanatha Subbannaa29a3eb2017-09-29 19:18:20 +0530374
375// Now register the class version with Cereal
376% for object in objects:
377<%
378 classname = "phosphor::settings"
379 ns = object.split('/')
380 ns.pop(0)
381%>\
382% for n in ns:
383<%
384 classname += "::" + n
385%>\
386% endfor
387CEREAL_CLASS_VERSION(${classname + "::Impl"}, CLASS_VERSION);
388% endfor