summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDeepak Kodihalli <dkodihal@in.ibm.com>2017-06-23 23:05:47 -0500
committerDeepak Kodihalli <dkodihal@in.ibm.com>2017-07-03 09:33:52 -0500
commit7a6f2526fd46badb145baa4309f88036af1bee9c (patch)
tree48a5a3a94dfeb040aefdd0396beeb177da978b00
parent9711211cb53df56fb5bdf84e3882672ac7ec8a50 (diff)
downloadphosphor-settingsd-7a6f2526fd46badb145baa4309f88036af1bee9c.tar.gz
phosphor-settingsd-7a6f2526fd46badb145baa4309f88036af1bee9c.zip
Persist changes to settings
Persist changes made to settings, if any, such that those changes can be restored upon a reboot. Use Cereal for serialization of the settings' properties. Since the settings code is generated based on a system specific settings policy, generate the serialization code as well such that only relevant settings are serialized. Resolves openbmc/openbmc#1764. Change-Id: Id8bd84a9455cf4348b22f255d038b050d004eb7c Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
-rwxr-xr-xMakefile.am3
-rw-r--r--configure.ac7
-rw-r--r--settings_main.cpp3
-rw-r--r--settings_manager.mako.hpp156
4 files changed, 146 insertions, 23 deletions
diff --git a/Makefile.am b/Makefile.am
index 65f95cb..55ea2d6 100755
--- a/Makefile.am
+++ b/Makefile.am
@@ -30,4 +30,5 @@ phosphor_settings_manager_CXXFLAGS = \
phosphor_settings_manager_LDADD = \
$(PHOSPHOR_DBUS_INTERFACES_LIBS) \
- $(SDBUSPLUS_LIBS)
+ $(SDBUSPLUS_LIBS) \
+ -lstdc++fs
diff --git a/configure.ac b/configure.ac
index 3ee9c6b..083d623 100644
--- a/configure.ac
+++ b/configure.ac
@@ -32,5 +32,12 @@ AS_IF([test "x$SETTINGS_YAML" == "x"], [SETTINGS_YAML="settings_example.yaml"])
SETTINGSGEN="$PYTHON $srcdir/settings.py -i $SETTINGS_YAML"
AC_SUBST(SETTINGSGEN)
+AC_ARG_VAR(SETTINGS_PERSIST_PATH, \
+ [Path of directory housing persisted settings.])
+AS_IF([test "x$SETTINGS_PERSIST_PATH" == "x"], \
+ [SETTINGS_PERSIST_PATH="/var/lib/phosphor-settings-manager/settings"])
+AC_DEFINE_UNQUOTED([SETTINGS_PERSIST_PATH], ["$SETTINGS_PERSIST_PATH"], \
+ [Path of directory housing persisted settings])
+
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
diff --git a/settings_main.cpp b/settings_main.cpp
index 0d775e2..fbb9a0d 100644
--- a/settings_main.cpp
+++ b/settings_main.cpp
@@ -11,11 +11,10 @@ int main(int argc, char *argv[])
// the object namespace and are not under a (settings) root. Hence register
// "/" as the path.
sdbusplus::server::manager::manager objManager(bus, "/");
+ bus.request_name(SETTINGS_BUSNAME);
phosphor::settings::Manager mgr(bus);
- bus.request_name(SETTINGS_BUSNAME);
-
while(true)
{
bus.process_discard();
diff --git a/settings_manager.mako.hpp b/settings_manager.mako.hpp
index acdf66d..6a4f1bf 100644
--- a/settings_manager.mako.hpp
+++ b/settings_manager.mako.hpp
@@ -1,17 +1,23 @@
## This file is a template. The comment below is emitted
## into the rendered file; feel free to edit this file.
// WARNING: Generated header. Do not edit!
-
<%
+from collections import defaultdict
objects = list(settingsDict.viewkeys())
-ns_list = []
-includes = []
+sdbusplus_namespaces = []
+sdbusplus_includes = []
+interfaces = []
+props = defaultdict(list)
-def get_setting_type(setting_intf):
+def get_setting_sdbusplus_type(setting_intf):
setting = "sdbusplus::" + setting_intf.replace('.', '::')
i = setting.rfind('::')
setting = setting[:i] + '::server::' + setting[i+2:]
return setting
+
+def get_setting_type(setting_intf):
+ setting = setting_intf.replace('.', '::')
+ return setting
%>\
#pragma once
@@ -20,30 +26,130 @@ def get_setting_type(setting_intf):
include = settingsDict[object]['Interface']
include = include.replace('.', '/')
include = include + "/server.hpp"
- includes.append(include)
+ sdbusplus_includes.append(include)
%>\
% endfor
-% for i in set(includes):
+#include <cereal/archives/json.hpp>
+#include <fstream>
+#include <utility>
+#include <experimental/filesystem>
+#include "config.h"
+
+% for i in set(sdbusplus_includes):
#include "${i}"
% endfor
% for object in objects:
<%
- ns = get_setting_type(settingsDict[object]['Interface'])
+ ns = get_setting_sdbusplus_type(settingsDict[object]['Interface'])
i = ns.rfind('::')
ns = ns[:i]
- ns_list.append(ns)
+ sdbusplus_namespaces.append(ns)
%>\
% endfor
-% for n in set(ns_list):
-using namespace ${n};
-% endfor
namespace phosphor
{
namespace settings
{
+namespace fs = std::experimental::filesystem;
+
+% for n in set(sdbusplus_namespaces):
+using namespace ${n};
+% endfor
+
+% for object in objects:
+<%
+ intf = settingsDict[object]['Interface']
+ interfaces.append(intf)
+ if intf not in props:
+ for property, value in settingsDict[object]['Defaults'].items():
+ props[intf].append(property)
+%>\
+% endfor
+% for intf in set(interfaces):
+<%
+ ns = intf.split(".")
+ sdbusplus_type = get_setting_sdbusplus_type(intf)
+%>\
+% for n in ns:
+namespace ${n}
+{
+% endfor
+
+using Base = ${sdbusplus_type};
+<% parent = "sdbusplus::server::object::object" + "<" + sdbusplus_type + ">" %>\
+using Parent = ${parent};
+
+class Impl : public Parent
+{
+ public:
+ Impl(sdbusplus::bus::bus& bus, const char* path):
+ Parent(bus, path, true),
+ path(path)
+ {
+ }
+ virtual ~Impl() = default;
+
+% for arg in props[intf]:
+<% t = arg[:1].lower() + arg[1:] %>\
+ decltype(std::declval<Base>().${t}()) ${t}(decltype(std::declval<Base>().${t}()) value) override
+ {
+ auto result = Base::${t}();
+ if (value != result)
+ {
+ fs::path p(SETTINGS_PERSIST_PATH);
+ p /= path;
+ fs::create_directories(p.parent_path());
+ std::ofstream os(p.c_str(), std::ios::binary);
+ cereal::JSONOutputArchive oarchive(os);
+ result = Base::${t}(value);
+ oarchive(*this);
+ }
+ return result;
+ }
+ using Base::${t};
+
+ private:
+ fs::path path;
+% endfor
+};
+
+template<class Archive>
+void save(Archive& a,
+ const Impl& setting)
+{
+<%
+ args = ["setting." + p[:1].lower() + p[1:] + "()" for p in props[intf]]
+ args = ','.join(args)
+%>\
+ a(${args});
+}
+
+template<class Archive>
+void load(Archive& a,
+ Impl& setting)
+{
+% for arg in props[intf]:
+<% t = "setting." + arg[:1].lower() + arg[1:] + "()" %>\
+ decltype(${t}) ${arg}{};
+% endfor
+<%
+ args = ','.join(props[intf])
+%>\
+ a(${args});
+% for arg in props[intf]:
+<% t = "setting." + arg[:1].lower() + arg[1:] + "(" + arg + ")" %>\
+ ${t};
+% endfor
+}
+
+% for n in reversed(ns):
+} // namespace ${n}
+% endfor
+% endfor
+
/** @class Manager
*
* @brief Compose settings objects and put them on the bus.
@@ -63,10 +169,11 @@ class Manager
*/
Manager(sdbusplus::bus::bus& bus)
{
+ fs::path path{};
settings =
std::make_tuple(
% for index, object in enumerate(objects):
-<% type = get_setting_type(settingsDict[object]['Interface']) %>\
+<% type = get_setting_type(settingsDict[object]['Interface']) + "::Impl" %>\
std::make_unique<${type}>(
bus,
% if index < len(settingsDict) - 1:
@@ -77,13 +184,22 @@ class Manager
% endfor
% for index, object in enumerate(objects):
- % if 'Defaults' in settingsDict[object].viewkeys():
- % for property, value in settingsDict[object]['Defaults'].items():
- std::get<${index}>(settings)->
- setPropertyByName("${property}", ${value});
- % endfor
- % endif
- bus.emit_object_added("${object}");
+ % for property, value in settingsDict[object]['Defaults'].items():
+<% p = property[:1].lower() + property[1:] %>\
+ path = fs::path(SETTINGS_PERSIST_PATH) / "${object}";
+ if (fs::exists(path))
+ {
+ std::ifstream is(path.c_str(), std::ios::in);
+ cereal::JSONInputArchive iarchive(is);
+ iarchive(*std::get<${index}>(settings));
+ }
+ else
+ {
+ std::get<${index}>(settings)->
+ ${get_setting_sdbusplus_type(settingsDict[object]['Interface'])}::${p}(${value});
+ }
+ % endfor
+ std::get<${index}>(settings)->emit_object_added();
% endfor
}
@@ -92,7 +208,7 @@ class Manager
/* @brief Composition of settings objects. */
std::tuple<
% for index, object in enumerate(objects):
-<% type = get_setting_type(settingsDict[object]['Interface']) %>\
+<% type = get_setting_type(settingsDict[object]['Interface']) + "::Impl" %>\
% if index < len(settingsDict) - 1:
std::unique_ptr<${type}>,
% else:
OpenPOWER on IntegriCloud