blob: 3b4dc34ddcfeda5c9c73362582fd0de9352fe199 [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>
Matt Spinlerc2f84c72023-05-24 13:51:03 -050060#include <phosphor-logging/lg2.hpp>
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -050061#include <xyz/openbmc_project/Common/error.hpp>
Tom Joseph4636e072017-09-24 20:47:24 +053062using namespace phosphor::logging;
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050063
Jagpal Singh Gill4d28bcd2023-04-23 23:34:05 -070064/* The DBus busname to own */
65#define SETTINGS_BUSNAME "xyz.openbmc_project.Settings"
66/* Path of directory housing persisted settings */
67#define SETTINGS_PERSIST_PATH "/var/lib/phosphor-settings-manager/settings"
68
69/* Class version to register with Cereal */
Matt Spinlerc2f84c72023-05-24 13:51:03 -050070static constexpr size_t CLASS_VERSION = 2;
71static constexpr size_t CLASS_VERSION_WITH_NVP = 2;
Jagpal Singh Gill4d28bcd2023-04-23 23:34:05 -070072
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050073% for i in set(sdbusplus_includes):
Deepak Kodihalli5de09572017-05-16 23:53:40 -050074#include "${i}"
75% endfor
76
Deepak Kodihalli5de09572017-05-16 23:53:40 -050077namespace phosphor
78{
79namespace settings
80{
81
Patrick Williams6306e5e2022-06-16 17:14:54 -050082namespace fs = std::filesystem;
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050083
Deepak Kodihalli242bc772017-08-04 02:47:54 -050084namespace persistent
85{
86
87// A setting d-bus object /foo/bar/baz is persisted in the filesystem with the
88// same path. This eases re-construction of settings objects when we restore
89// from the filesystem. This can be a problem though when you have two objects
90// such as - /foo/bar and /foo/bar/baz. This is because 'bar' will be treated as
91// a file in the first case, and a subdir in the second. To solve this, suffix
92// files with a trailing __. The __ is a safe character sequence to use, because
93// we won't have d-bus object paths ending with this.
94// With this the objects would be persisted as - /foo/bar__ and /foo/bar/baz__.
95constexpr auto fileSuffix = "__";
96
97}
98
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050099% for object in objects:
100<%
Deepak Kodihallidb838622017-08-27 02:46:47 -0500101 ns = object.split('/')
102 ns.pop(0)
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500103%>\
104% for n in ns:
105namespace ${n}
106{
107% endfor
Deepak Kodihallidb838622017-08-27 02:46:47 -0500108<%
109 interfaces = []
110 aliases = []
111 for item in settingsDict[object]:
112 interfaces.append(item['Interface'])
113 for name, meta in item['Properties'].items():
114 if 'Validation' in meta:
115 dict = meta['Validation']
116 if dict['Type'] == "range":
117 validators[name] = (dict['Type'], dict['Validator'], dict['Unit'])
118 else:
119 validators[name] = (dict['Type'], dict['Validator'])
120%>
121% for index, intf in enumerate(interfaces):
122using Iface${index} = ${get_setting_sdbusplus_type(intf)};
123<% aliases.append("Iface" + str(index)) %>\
124% endfor
125<%
Patrick Williams7c4181c2022-07-22 19:26:52 -0500126 parent = "sdbusplus::server::object_t" + "<" + ", ".join(aliases) + ">"
Deepak Kodihallidb838622017-08-27 02:46:47 -0500127%>\
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500128using Parent = ${parent};
129
130class Impl : public Parent
131{
132 public:
Patrick Williams7c4181c2022-07-22 19:26:52 -0500133 Impl(sdbusplus::bus_t& bus, const char* path):
Patrick Williams74c4f3b2022-04-05 16:16:20 -0500134 Parent(bus, path, Parent::action::defer_emit),
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500135 path(path)
136 {
137 }
138 virtual ~Impl() = default;
139
Deepak Kodihallidb838622017-08-27 02:46:47 -0500140% for index, item in enumerate(settingsDict[object]):
141 % for propName, metaDict in item['Properties'].items():
Patrick Williamsbcf95782021-05-05 16:20:32 -0500142<% t = NamedElement(name=propName).camelCase %>\
Deepak Kodihallidb838622017-08-27 02:46:47 -0500143<% fname = "validate" + propName %>\
144 decltype(std::declval<Iface${index}>().${t}()) ${t}(decltype(std::declval<Iface${index}>().${t}()) value) override
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500145 {
Deepak Kodihallidb838622017-08-27 02:46:47 -0500146 auto result = Iface${index}::${t}();
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500147 if (value != result)
148 {
Deepak Kodihallidb838622017-08-27 02:46:47 -0500149 % if propName in validators:
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500150 if (!${fname}(value))
151 {
152 namespace error =
153 sdbusplus::xyz::openbmc_project::Common::Error;
154 namespace metadata =
155 phosphor::logging::xyz::openbmc_project::Common;
156 phosphor::logging::report<error::InvalidArgument>(
157 metadata::InvalidArgument::ARGUMENT_NAME("${t}"),
Deepak Kodihallidb838622017-08-27 02:46:47 -0500158 % if validators[propName][0] != "regex":
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500159 metadata::InvalidArgument::ARGUMENT_VALUE(std::to_string(value).c_str()));
160 % else:
161 metadata::InvalidArgument::ARGUMENT_VALUE(value.c_str()));
162 % endif
163 return result;
164 }
165 % endif
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500166 fs::path p(SETTINGS_PERSIST_PATH);
Adriana Kobylakf792a6d2022-07-20 15:07:08 -0500167 p /= path.relative_path();
Deepak Kodihalli242bc772017-08-04 02:47:54 -0500168 p += persistent::fileSuffix;
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500169 fs::create_directories(p.parent_path());
170 std::ofstream os(p.c_str(), std::ios::binary);
171 cereal::JSONOutputArchive oarchive(os);
Deepak Kodihallidb838622017-08-27 02:46:47 -0500172 result = Iface${index}::${t}(value);
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500173 oarchive(*this);
174 }
175 return result;
176 }
Deepak Kodihallidb838622017-08-27 02:46:47 -0500177 using Iface${index}::${t};
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500178
Deepak Kodihallidb838622017-08-27 02:46:47 -0500179 % endfor
Andrew Geisslerc15990a2017-07-06 11:36:31 -0500180% endfor
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500181 private:
182 fs::path path;
Deepak Kodihallidb838622017-08-27 02:46:47 -0500183% for index, item in enumerate(settingsDict[object]):
184 % for propName, metaDict in item['Properties'].items():
Patrick Williamsbcf95782021-05-05 16:20:32 -0500185<% t = NamedElement(name=propName).camelCase %>\
Deepak Kodihallidb838622017-08-27 02:46:47 -0500186<% fname = "validate" + propName %>\
187 % if propName in validators:
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500188
Deepak Kodihallidb838622017-08-27 02:46:47 -0500189 bool ${fname}(decltype(std::declval<Iface${index}>().${t}()) value)
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500190 {
191 bool matched = false;
Deepak Kodihallidb838622017-08-27 02:46:47 -0500192 % if (validators[propName][0] == 'regex'):
193 std::regex regexToCheck("${validators[propName][1]}");
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500194 matched = std::regex_search(value, regexToCheck);
195 if (!matched)
196 {
Deepak Kodihallidb838622017-08-27 02:46:47 -0500197 std::string err = "Input parameter for ${propName} is invalid "
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500198 "Input: " + value + " not in the format of this regex: "
Deepak Kodihallidb838622017-08-27 02:46:47 -0500199 "${validators[propName][1]}";
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500200 using namespace phosphor::logging;
201 log<level::ERR>(err.c_str());
202 }
Deepak Kodihallidb838622017-08-27 02:46:47 -0500203 % elif (validators[propName][0] == 'range'):
204<% lowhigh = re.split('\.\.', validators[propName][1]) %>\
Jagpal Singh Gillcfd49eb2023-04-23 23:09:09 -0700205 % if lowhigh[0] == '0':
206 if (value <= ${lowhigh[1]})
207 % else:
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500208 if ((value <= ${lowhigh[1]}) && (value >= ${lowhigh[0]}))
Jagpal Singh Gillcfd49eb2023-04-23 23:09:09 -0700209 % endif
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500210 {
211 matched = true;
212 }
213 else
214 {
Deepak Kodihallidb838622017-08-27 02:46:47 -0500215 std::string err = "Input parameter for ${propName} is invalid "
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500216 "Input: " + std::to_string(value) + "in uint: "
Deepak Kodihallidb838622017-08-27 02:46:47 -0500217 "${validators[propName][2]} is not in range:${validators[propName][1]}";
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500218 using namespace phosphor::logging;
219 log<level::ERR>(err.c_str());
220 }
Deepak Kodihallidb838622017-08-27 02:46:47 -0500221 % else:
222 <% assert("Unknown validation type: propName") %>\
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500223 % endif
224 return matched;
225 }
Deepak Kodihallidb838622017-08-27 02:46:47 -0500226 % endif
227 % endfor
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500228% endfor
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500229};
230
231template<class Archive>
232void save(Archive& a,
Vishwanatha Subbannaa29a3eb2017-09-29 19:18:20 +0530233 const Impl& setting,
Jagpal Singh Gillcfd49eb2023-04-23 23:09:09 -0700234 [[maybe_unused]] const std::uint32_t version)
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500235{
236<%
Deepak Kodihallidb838622017-08-27 02:46:47 -0500237props = []
238for index, item in enumerate(settingsDict[object]):
Matt Spinlerc2f84c72023-05-24 13:51:03 -0500239 props.extend(item['Properties'].keys())
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500240%>\
Matt Spinlerc2f84c72023-05-24 13:51:03 -0500241## Since the iface isn't saved, property names need to be unique on
242## the object path. This could be supported by providing unique
243## field names to make_nvp() if ever necessary.
244% if len(set(props)) != len(props):
245#error Duplicate property names on object path ${object}
246%endif
247<%
248args = []
249for prop in props:
250 t = "setting." + NamedElement(name=prop).camelCase + "()"
251 args.append(f"cereal::make_nvp(\"{prop}\", {t})")
252args = ", ".join(args)
253%>\
254 a(${args});
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500255}
256
257template<class Archive>
258void load(Archive& a,
Vishwanatha Subbannaa29a3eb2017-09-29 19:18:20 +0530259 Impl& setting,
Matt Spinlerc2f84c72023-05-24 13:51:03 -0500260 const std::uint32_t version)
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500261{
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500262<%
Matt Spinlerc2f84c72023-05-24 13:51:03 -0500263props = []
264for index, item in enumerate(settingsDict[object]):
265 for prop in item['Properties'].keys():
266 t = "setting." + NamedElement(name=prop).camelCase + "()"
267 props.append({'prop' : prop, 'iface': item['Interface'], 'func': t})
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500268%>\
Matt Spinlerc2f84c72023-05-24 13:51:03 -0500269% for p in props:
270 decltype(${p['func']}) ${p['prop']}{};
Deepak Kodihallidb838622017-08-27 02:46:47 -0500271% endfor
Matt Spinlerc2f84c72023-05-24 13:51:03 -0500272<% propList = ', '.join([p['prop'] for p in props]) %>
273% if propList:
274 if (version < CLASS_VERSION_WITH_NVP)
275 {
276 a(${propList});
277 }
278 else
279 {
280 % for p in props:
281 try
282 {
283 a(CEREAL_NVP(${p['prop']}));
284 }
285 catch (const cereal::Exception& e)
286 {
287 lg2::info("Could not restore property ${p['prop']} on ${object}, setting to default value");
288 ${p['prop']} = ${get_default_value(object, p['iface'], p['prop'])};
289 }
290 % endfor
291 }
Lei YUc0ce9922022-03-09 16:01:10 +0800292% endif
Deepak Kodihallidb838622017-08-27 02:46:47 -0500293<% props = [] %>
294% for index, item in enumerate(settingsDict[object]):
295 % for prop, metaDict in item['Properties'].items():
296<%
Patrick Williamsbcf95782021-05-05 16:20:32 -0500297 t = "setting." + NamedElement(name=prop).camelCase + "(" + prop + ")"
Deepak Kodihallidb838622017-08-27 02:46:47 -0500298%>\
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500299 ${t};
Deepak Kodihallidb838622017-08-27 02:46:47 -0500300 % endfor
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500301% endfor
302}
303
304% for n in reversed(ns):
305} // namespace ${n}
306% endfor
Deepak Kodihallidb838622017-08-27 02:46:47 -0500307
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500308% endfor
309
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500310/** @class Manager
311 *
312 * @brief Compose settings objects and put them on the bus.
313 */
314class Manager
315{
316 public:
317 Manager() = delete;
318 Manager(const Manager&) = delete;
319 Manager& operator=(const Manager&) = delete;
320 Manager(Manager&&) = delete;
321 Manager& operator=(Manager&&) = delete;
322 virtual ~Manager() = default;
323
324 /** @brief Constructor to put settings objects on to the bus.
325 * @param[in] bus - Bus to attach to.
326 */
Patrick Williams7c4181c2022-07-22 19:26:52 -0500327 explicit Manager(sdbusplus::bus_t& bus) :
Patrick Williams0f6903d2022-04-15 10:03:58 -0500328 settings(
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500329 std::make_tuple(
Deepak Kodihallidb838622017-08-27 02:46:47 -0500330% for index, path in enumerate(objects):
331<% type = get_setting_type(path) + "::Impl" %>\
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500332 std::make_unique<${type}>(
333 bus,
334 % if index < len(settingsDict) - 1:
Deepak Kodihallidb838622017-08-27 02:46:47 -0500335 "${path}"),
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500336 % else:
Patrick Williams0f6903d2022-04-15 10:03:58 -0500337 "${path}")
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500338 % endif
339% endfor
Patrick Williams0f6903d2022-04-15 10:03:58 -0500340 )
341 )
342 {
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500343
Patrick Williams0f6903d2022-04-15 10:03:58 -0500344 fs::path path{};
Deepak Kodihallidb838622017-08-27 02:46:47 -0500345% for index, path in enumerate(objects):
Adriana Kobylakf792a6d2022-07-20 15:07:08 -0500346<% relativePath = path[1:] %>\
347 path = fs::path(SETTINGS_PERSIST_PATH) / "${relativePath}";
Deepak Kodihalli242bc772017-08-04 02:47:54 -0500348 path += persistent::fileSuffix;
Tom Joseph4636e072017-09-24 20:47:24 +0530349 auto initSetting${index} = [&]()
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500350 {
Deepak Kodihallidb838622017-08-27 02:46:47 -0500351 % for item in settingsDict[path]:
352 % for propName, metaDict in item['Properties'].items():
Patrick Williamsbcf95782021-05-05 16:20:32 -0500353<% p = NamedElement(name=propName).camelCase %>\
Matt Spinlerffdf8652023-05-24 11:09:54 -0500354<% defaultValue = get_default_value(path, item['Interface'], propName) %>\
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500355 std::get<${index}>(settings)->
Tom Joseph4636e072017-09-24 20:47:24 +0530356 ${get_setting_sdbusplus_type(item['Interface'])}::${p}(${defaultValue});
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500357 % endfor
Tom Joseph4636e072017-09-24 20:47:24 +0530358% endfor
359 };
360
361 try
362 {
363 if (fs::exists(path))
364 {
365 std::ifstream is(path.c_str(), std::ios::in);
366 cereal::JSONInputArchive iarchive(is);
367 iarchive(*std::get<${index}>(settings));
368 }
369 else
370 {
371 initSetting${index}();
372 }
373 }
Patrick Williamsb6fa9bb2021-10-06 12:27:57 -0500374 catch (const cereal::Exception& e)
Tom Joseph4636e072017-09-24 20:47:24 +0530375 {
376 log<level::ERR>(e.what());
377 fs::remove(path);
378 initSetting${index}();
Deepak Kodihallidb838622017-08-27 02:46:47 -0500379 }
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500380 std::get<${index}>(settings)->emit_object_added();
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500381
382% endfor
383 }
384
385 private:
386 /* @brief Composition of settings objects. */
387 std::tuple<
Deepak Kodihallidb838622017-08-27 02:46:47 -0500388% for index, path in enumerate(objects):
389<% type = get_setting_type(path) + "::Impl" %>\
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500390 % if index < len(settingsDict) - 1:
391 std::unique_ptr<${type}>,
392 % else:
393 std::unique_ptr<${type}>> settings;
394 % endif
395% endfor
396};
397
398} // namespace settings
399} // namespace phosphor
Vishwanatha Subbannaa29a3eb2017-09-29 19:18:20 +0530400
401// Now register the class version with Cereal
402% for object in objects:
403<%
404 classname = "phosphor::settings"
405 ns = object.split('/')
406 ns.pop(0)
407%>\
408% for n in ns:
409<%
410 classname += "::" + n
411%>\
412% endfor
413CEREAL_CLASS_VERSION(${classname + "::Impl"}, CLASS_VERSION);
414% endfor