blob: b1c3988571af88b3baab50e43fb75a50f2fc391e [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
Deepak Kodihalli5de09572017-05-16 23:53:40 -05007objects = list(settingsDict.viewkeys())
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -05008sdbusplus_namespaces = []
9sdbusplus_includes = []
10interfaces = []
11props = defaultdict(list)
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -050012validators = defaultdict(tuple)
Deepak Kodihalli5de09572017-05-16 23:53:40 -050013
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050014def get_setting_sdbusplus_type(setting_intf):
Deepak Kodihalli5de09572017-05-16 23:53:40 -050015 setting = "sdbusplus::" + setting_intf.replace('.', '::')
16 i = setting.rfind('::')
17 setting = setting[:i] + '::server::' + setting[i+2:]
18 return setting
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050019
20def get_setting_type(setting_intf):
21 setting = setting_intf.replace('.', '::')
22 return setting
Deepak Kodihalli5de09572017-05-16 23:53:40 -050023%>\
24#pragma once
25
26% for object in objects:
27<%
Deepak Kodihalli5de09572017-05-16 23:53:40 -050028 include = settingsDict[object]['Interface']
29 include = include.replace('.', '/')
30 include = include + "/server.hpp"
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050031 sdbusplus_includes.append(include)
Deepak Kodihalli5de09572017-05-16 23:53:40 -050032%>\
33% endfor
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050034#include <cereal/archives/json.hpp>
35#include <fstream>
36#include <utility>
37#include <experimental/filesystem>
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -050038#include <regex>
39#include <phosphor-logging/elog.hpp>
40#include <phosphor-logging/elog-errors.hpp>
41#include <phosphor-logging/log.hpp>
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050042#include "config.h"
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -050043#include <xyz/openbmc_project/Common/error.hpp>
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050044
45% for i in set(sdbusplus_includes):
Deepak Kodihalli5de09572017-05-16 23:53:40 -050046#include "${i}"
47% endfor
48
49% for object in objects:
50<%
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050051 ns = get_setting_sdbusplus_type(settingsDict[object]['Interface'])
Deepak Kodihalli5de09572017-05-16 23:53:40 -050052 i = ns.rfind('::')
53 ns = ns[:i]
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050054 sdbusplus_namespaces.append(ns)
Deepak Kodihalli5de09572017-05-16 23:53:40 -050055%>\
56% endfor
Deepak Kodihalli5de09572017-05-16 23:53:40 -050057
58namespace phosphor
59{
60namespace settings
61{
62
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050063namespace fs = std::experimental::filesystem;
64
Deepak Kodihalli242bc772017-08-04 02:47:54 -050065namespace persistent
66{
67
68// A setting d-bus object /foo/bar/baz is persisted in the filesystem with the
69// same path. This eases re-construction of settings objects when we restore
70// from the filesystem. This can be a problem though when you have two objects
71// such as - /foo/bar and /foo/bar/baz. This is because 'bar' will be treated as
72// a file in the first case, and a subdir in the second. To solve this, suffix
73// files with a trailing __. The __ is a safe character sequence to use, because
74// we won't have d-bus object paths ending with this.
75// With this the objects would be persisted as - /foo/bar__ and /foo/bar/baz__.
76constexpr auto fileSuffix = "__";
77
78}
79
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050080% for n in set(sdbusplus_namespaces):
81using namespace ${n};
82% endfor
83
84% for object in objects:
85<%
86 intf = settingsDict[object]['Interface']
87 interfaces.append(intf)
88 if intf not in props:
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -050089 for property, property_metadata in settingsDict[object]['Properties'].items():
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050090 props[intf].append(property)
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -050091 for attribute, value in property_metadata.items():
92 if attribute == 'Validation':
93 if value['Type'] == "range":
94 validators[property] = (value['Type'], value['Validator'], value['Unit'])
95 else:
96 validators[property] = (value['Type'], value['Validator'])
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -050097%>\
98% endfor
99% for intf in set(interfaces):
100<%
101 ns = intf.split(".")
102 sdbusplus_type = get_setting_sdbusplus_type(intf)
103%>\
104% for n in ns:
105namespace ${n}
106{
107% endfor
108
109using Base = ${sdbusplus_type};
110<% parent = "sdbusplus::server::object::object" + "<" + sdbusplus_type + ">" %>\
111using Parent = ${parent};
112
113class Impl : public Parent
114{
115 public:
116 Impl(sdbusplus::bus::bus& bus, const char* path):
117 Parent(bus, path, true),
118 path(path)
119 {
120 }
121 virtual ~Impl() = default;
122
123% for arg in props[intf]:
124<% t = arg[:1].lower() + arg[1:] %>\
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500125<% fname = "validate"+arg %>\
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500126 decltype(std::declval<Base>().${t}()) ${t}(decltype(std::declval<Base>().${t}()) value) override
127 {
128 auto result = Base::${t}();
129 if (value != result)
130 {
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500131 % if arg in validators.keys():
132 if (!${fname}(value))
133 {
134 namespace error =
135 sdbusplus::xyz::openbmc_project::Common::Error;
136 namespace metadata =
137 phosphor::logging::xyz::openbmc_project::Common;
138 phosphor::logging::report<error::InvalidArgument>(
139 metadata::InvalidArgument::ARGUMENT_NAME("${t}"),
140 % if validators[arg][0] != "regex":
141 metadata::InvalidArgument::ARGUMENT_VALUE(std::to_string(value).c_str()));
142 % else:
143 metadata::InvalidArgument::ARGUMENT_VALUE(value.c_str()));
144 % endif
145 return result;
146 }
147 % endif
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500148 fs::path p(SETTINGS_PERSIST_PATH);
149 p /= path;
Deepak Kodihalli242bc772017-08-04 02:47:54 -0500150 p += persistent::fileSuffix;
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500151 fs::create_directories(p.parent_path());
152 std::ofstream os(p.c_str(), std::ios::binary);
153 cereal::JSONOutputArchive oarchive(os);
154 result = Base::${t}(value);
155 oarchive(*this);
156 }
157 return result;
158 }
159 using Base::${t};
160
Andrew Geisslerc15990a2017-07-06 11:36:31 -0500161% endfor
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500162 private:
163 fs::path path;
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500164% for arg in props[intf]:
165% if arg in validators.keys():
166<% funcName = "validate"+arg %>\
167<% t = arg[:1].lower() + arg[1:] %>\
168
169 bool ${funcName}(decltype(std::declval<Base>().${t}()) value)
170 {
171 bool matched = false;
172 % if (arg in validators.keys()) and (validators[arg][0] == 'regex'):
173 std::regex regexToCheck("${validators[arg][1]}");
174 matched = std::regex_search(value, regexToCheck);
175 if (!matched)
176 {
177 std::string err = "Input parameter for ${arg} is invalid "
178 "Input: " + value + " not in the format of this regex: "
179 "${validators[arg][1]}";
180 using namespace phosphor::logging;
181 log<level::ERR>(err.c_str());
182 }
183 % elif (arg in validators.keys()) and (validators[arg][0] == 'range'):
184<% lowhigh = re.split('\.\.', validators[arg][1]) %>\
185 if ((value <= ${lowhigh[1]}) && (value >= ${lowhigh[0]}))
186 {
187 matched = true;
188 }
189 else
190 {
191 std::string err = "Input parameter for ${arg} is invalid "
192 "Input: " + std::to_string(value) + "in uint: "
193 "${validators[arg][2]} is not in range:${validators[arg][1]}";
194 using namespace phosphor::logging;
195 log<level::ERR>(err.c_str());
196 }
197 % elif (arg in validators.keys()):
198 <% assert("Unknown validation type: arg") %>\
199 % endif
200 return matched;
201 }
202% endif
203% endfor
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500204};
205
206template<class Archive>
207void save(Archive& a,
208 const Impl& setting)
209{
210<%
211 args = ["setting." + p[:1].lower() + p[1:] + "()" for p in props[intf]]
212 args = ','.join(args)
213%>\
214 a(${args});
215}
216
217template<class Archive>
218void load(Archive& a,
219 Impl& setting)
220{
221% for arg in props[intf]:
222<% t = "setting." + arg[:1].lower() + arg[1:] + "()" %>\
223 decltype(${t}) ${arg}{};
224% endfor
225<%
226 args = ','.join(props[intf])
227%>\
228 a(${args});
229% for arg in props[intf]:
230<% t = "setting." + arg[:1].lower() + arg[1:] + "(" + arg + ")" %>\
231 ${t};
232% endfor
233}
234
235% for n in reversed(ns):
236} // namespace ${n}
237% endfor
238% endfor
239
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500240/** @class Manager
241 *
242 * @brief Compose settings objects and put them on the bus.
243 */
244class Manager
245{
246 public:
247 Manager() = delete;
248 Manager(const Manager&) = delete;
249 Manager& operator=(const Manager&) = delete;
250 Manager(Manager&&) = delete;
251 Manager& operator=(Manager&&) = delete;
252 virtual ~Manager() = default;
253
254 /** @brief Constructor to put settings objects on to the bus.
255 * @param[in] bus - Bus to attach to.
256 */
257 Manager(sdbusplus::bus::bus& bus)
258 {
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500259 fs::path path{};
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500260 settings =
261 std::make_tuple(
262% for index, object in enumerate(objects):
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500263<% type = get_setting_type(settingsDict[object]['Interface']) + "::Impl" %>\
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500264 std::make_unique<${type}>(
265 bus,
266 % if index < len(settingsDict) - 1:
267 "${object}"),
268 % else:
269 "${object}"));
270 % endif
271% endfor
272
273% for index, object in enumerate(objects):
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500274 % for property, value in settingsDict[object]['Properties'].items():
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500275<% p = property[:1].lower() + property[1:] %>\
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500276<% defaultValue = value['Default'] %>\
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500277 path = fs::path(SETTINGS_PERSIST_PATH) / "${object}";
Deepak Kodihalli242bc772017-08-04 02:47:54 -0500278 path += persistent::fileSuffix;
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500279 if (fs::exists(path))
280 {
281 std::ifstream is(path.c_str(), std::ios::in);
282 cereal::JSONInputArchive iarchive(is);
283 iarchive(*std::get<${index}>(settings));
284 }
285 else
286 {
287 std::get<${index}>(settings)->
Dhruvaraj Subhashchandran61d3b6a2017-07-25 09:36:54 -0500288 ${get_setting_sdbusplus_type(settingsDict[object]['Interface'])}::${p}(${defaultValue});
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500289 }
290 % endfor
291 std::get<${index}>(settings)->emit_object_added();
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500292
293% endfor
294 }
295
296 private:
297 /* @brief Composition of settings objects. */
298 std::tuple<
299% for index, object in enumerate(objects):
Deepak Kodihalli7a6f2522017-06-23 23:05:47 -0500300<% type = get_setting_type(settingsDict[object]['Interface']) + "::Impl" %>\
Deepak Kodihalli5de09572017-05-16 23:53:40 -0500301 % if index < len(settingsDict) - 1:
302 std::unique_ptr<${type}>,
303 % else:
304 std::unique_ptr<${type}>> settings;
305 % endif
306% endfor
307};
308
309} // namespace settings
310} // namespace phosphor