Validate changes to default settings.
Resolves openbmc/openbmc#1771
Change-Id: I763e811e88710425131ec504ff933e3c41c458e6
Signed-off-by: Dhruvaraj Subhashchandran <dhruvaraj@in.ibm.com>
diff --git a/settings_manager.mako.hpp b/settings_manager.mako.hpp
index cc2ab5b..9fca3da 100644
--- a/settings_manager.mako.hpp
+++ b/settings_manager.mako.hpp
@@ -2,12 +2,14 @@
## into the rendered file; feel free to edit this file.
// WARNING: Generated header. Do not edit!
<%
+import re
from collections import defaultdict
objects = list(settingsDict.viewkeys())
sdbusplus_namespaces = []
sdbusplus_includes = []
interfaces = []
props = defaultdict(list)
+validators = defaultdict(tuple)
def get_setting_sdbusplus_type(setting_intf):
setting = "sdbusplus::" + setting_intf.replace('.', '::')
@@ -33,7 +35,12 @@
#include <fstream>
#include <utility>
#include <experimental/filesystem>
+#include <regex>
+#include <phosphor-logging/elog.hpp>
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/log.hpp>
#include "config.h"
+#include <xyz/openbmc_project/Common/error.hpp>
% for i in set(sdbusplus_includes):
#include "${i}"
@@ -64,8 +71,14 @@
intf = settingsDict[object]['Interface']
interfaces.append(intf)
if intf not in props:
- for property, value in settingsDict[object]['Defaults'].items():
+ for property, property_metadata in settingsDict[object]['Properties'].items():
props[intf].append(property)
+ for attribute, value in property_metadata.items():
+ if attribute == 'Validation':
+ if value['Type'] == "range":
+ validators[property] = (value['Type'], value['Validator'], value['Unit'])
+ else:
+ validators[property] = (value['Type'], value['Validator'])
%>\
% endfor
% for intf in set(interfaces):
@@ -94,11 +107,29 @@
% for arg in props[intf]:
<% t = arg[:1].lower() + arg[1:] %>\
+<% fname = "validate"+arg %>\
decltype(std::declval<Base>().${t}()) ${t}(decltype(std::declval<Base>().${t}()) value) override
{
auto result = Base::${t}();
if (value != result)
{
+ % if arg in validators.keys():
+ if (!${fname}(value))
+ {
+ namespace error =
+ sdbusplus::xyz::openbmc_project::Common::Error;
+ namespace metadata =
+ phosphor::logging::xyz::openbmc_project::Common;
+ phosphor::logging::report<error::InvalidArgument>(
+ metadata::InvalidArgument::ARGUMENT_NAME("${t}"),
+ % if validators[arg][0] != "regex":
+ metadata::InvalidArgument::ARGUMENT_VALUE(std::to_string(value).c_str()));
+ % else:
+ metadata::InvalidArgument::ARGUMENT_VALUE(value.c_str()));
+ % endif
+ return result;
+ }
+ % endif
fs::path p(SETTINGS_PERSIST_PATH);
p /= path;
fs::create_directories(p.parent_path());
@@ -114,6 +145,46 @@
% endfor
private:
fs::path path;
+% for arg in props[intf]:
+% if arg in validators.keys():
+<% funcName = "validate"+arg %>\
+<% t = arg[:1].lower() + arg[1:] %>\
+
+ bool ${funcName}(decltype(std::declval<Base>().${t}()) value)
+ {
+ bool matched = false;
+ % if (arg in validators.keys()) and (validators[arg][0] == 'regex'):
+ std::regex regexToCheck("${validators[arg][1]}");
+ matched = std::regex_search(value, regexToCheck);
+ if (!matched)
+ {
+ std::string err = "Input parameter for ${arg} is invalid "
+ "Input: " + value + " not in the format of this regex: "
+ "${validators[arg][1]}";
+ using namespace phosphor::logging;
+ log<level::ERR>(err.c_str());
+ }
+ % elif (arg in validators.keys()) and (validators[arg][0] == 'range'):
+<% lowhigh = re.split('\.\.', validators[arg][1]) %>\
+ if ((value <= ${lowhigh[1]}) && (value >= ${lowhigh[0]}))
+ {
+ matched = true;
+ }
+ else
+ {
+ std::string err = "Input parameter for ${arg} is invalid "
+ "Input: " + std::to_string(value) + "in uint: "
+ "${validators[arg][2]} is not in range:${validators[arg][1]}";
+ using namespace phosphor::logging;
+ log<level::ERR>(err.c_str());
+ }
+ % elif (arg in validators.keys()):
+ <% assert("Unknown validation type: arg") %>\
+ % endif
+ return matched;
+ }
+% endif
+% endfor
};
template<class Archive>
@@ -184,8 +255,9 @@
% endfor
% for index, object in enumerate(objects):
- % for property, value in settingsDict[object]['Defaults'].items():
+ % for property, value in settingsDict[object]['Properties'].items():
<% p = property[:1].lower() + property[1:] %>\
+<% defaultValue = value['Default'] %>\
path = fs::path(SETTINGS_PERSIST_PATH) / "${object}";
if (fs::exists(path))
{
@@ -196,7 +268,7 @@
else
{
std::get<${index}>(settings)->
- ${get_setting_sdbusplus_type(settingsDict[object]['Interface'])}::${p}(${value});
+ ${get_setting_sdbusplus_type(settingsDict[object]['Interface'])}::${p}(${defaultValue});
}
% endfor
std::get<${index}>(settings)->emit_object_added();