1 ## 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! 4 <% 5 import re 6 from collections import defaultdict 7 objects = list(settingsDict.viewkeys()) 8 sdbusplus_namespaces = [] 9 sdbusplus_includes = [] 10 interfaces = [] 11 props = defaultdict(list) 12 validators = defaultdict(tuple) 13 14 def get_setting_sdbusplus_type(setting_intf): 15 setting = "sdbusplus::" + setting_intf.replace('.', '::') 16 i = setting.rfind('::') 17 setting = setting[:i] + '::server::' + setting[i+2:] 18 return setting 19 20 def get_setting_type(setting_intf): 21 setting = setting_intf.replace('.', '::') 22 return setting 23 %>\ 24 #pragma once 25 26 % for object in objects: 27 <% 28 include = settingsDict[object]['Interface'] 29 include = include.replace('.', '/') 30 include = include + "/server.hpp" 31 sdbusplus_includes.append(include) 32 %>\ 33 % endfor 34 #include <cereal/archives/json.hpp> 35 #include <fstream> 36 #include <utility> 37 #include <experimental/filesystem> 38 #include <regex> 39 #include <phosphor-logging/elog.hpp> 40 #include <phosphor-logging/elog-errors.hpp> 41 #include <phosphor-logging/log.hpp> 42 #include "config.h" 43 #include <xyz/openbmc_project/Common/error.hpp> 44 45 % for i in set(sdbusplus_includes): 46 #include "${i}" 47 % endfor 48 49 % for object in objects: 50 <% 51 ns = get_setting_sdbusplus_type(settingsDict[object]['Interface']) 52 i = ns.rfind('::') 53 ns = ns[:i] 54 sdbusplus_namespaces.append(ns) 55 %>\ 56 % endfor 57 58 namespace phosphor 59 { 60 namespace settings 61 { 62 63 namespace fs = std::experimental::filesystem; 64 65 namespace 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__. 76 constexpr auto fileSuffix = "__"; 77 78 } 79 80 % for n in set(sdbusplus_namespaces): 81 using 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: 89 for property, property_metadata in settingsDict[object]['Properties'].items(): 90 props[intf].append(property) 91 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']) 97 %>\ 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: 105 namespace ${n} 106 { 107 % endfor 108 109 using Base = ${sdbusplus_type}; 110 <% parent = "sdbusplus::server::object::object" + "<" + sdbusplus_type + ">" %>\ 111 using Parent = ${parent}; 112 113 class 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:] %>\ 125 <% fname = "validate"+arg %>\ 126 decltype(std::declval<Base>().${t}()) ${t}(decltype(std::declval<Base>().${t}()) value) override 127 { 128 auto result = Base::${t}(); 129 if (value != result) 130 { 131 % 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 148 fs::path p(SETTINGS_PERSIST_PATH); 149 p /= path; 150 p += persistent::fileSuffix; 151 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 161 % endfor 162 private: 163 fs::path path; 164 % 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 204 }; 205 206 template<class Archive> 207 void 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 217 template<class Archive> 218 void 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 240 /** @class Manager 241 * 242 * @brief Compose settings objects and put them on the bus. 243 */ 244 class 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 { 259 fs::path path{}; 260 settings = 261 std::make_tuple( 262 % for index, object in enumerate(objects): 263 <% type = get_setting_type(settingsDict[object]['Interface']) + "::Impl" %>\ 264 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): 274 % for property, value in settingsDict[object]['Properties'].items(): 275 <% p = property[:1].lower() + property[1:] %>\ 276 <% defaultValue = value['Default'] %>\ 277 path = fs::path(SETTINGS_PERSIST_PATH) / "${object}"; 278 path += persistent::fileSuffix; 279 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)-> 288 ${get_setting_sdbusplus_type(settingsDict[object]['Interface'])}::${p}(${defaultValue}); 289 } 290 % endfor 291 std::get<${index}>(settings)->emit_object_added(); 292 293 % endfor 294 } 295 296 private: 297 /* @brief Composition of settings objects. */ 298 std::tuple< 299 % for index, object in enumerate(objects): 300 <% type = get_setting_type(settingsDict[object]['Interface']) + "::Impl" %>\ 301 % 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 311