Implement post code manager
This depends on interfaces definition:
https://gerrit.openbmc-project.xyz/c/openbmc/phosphor-dbus-interfaces/+/20474
Implement method and properties defined in PostCode.interface.yaml
under phosphor-dbus-interfaces/xyz/openbmc_project/State/Boot
1. Method: std::vector<uint64_t> PostCode::getPostCodes(uint16_t index)
2. Properties: CurrentBootCycleIndex/MaxBootCycleNum
Test-By:
Every cycle post codes is saved in "/var/lib/phosphor-post-code-manager"
"1" file is saved all post codes for cycle 1
"2" file is saved all post codes for cycle 2
"CurrentBootCycleIndex" file is saved the current boot cycle number.
root@wolfpass:/var/lib/phosphor-post-code-manager# ls
1 2 CurrentBootCycleIndex
Change-Id: Ia89b9121983261fef5573092d890beb84626ceeb
Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
diff --git a/inc/post_code.hpp b/inc/post_code.hpp
new file mode 100644
index 0000000..3c4ac4a
--- /dev/null
+++ b/inc/post_code.hpp
@@ -0,0 +1,161 @@
+/*
+// Copyright (c) 2019 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#pragma once
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <cereal/access.hpp>
+#include <cereal/archives/json.hpp>
+#include <cereal/cereal.hpp>
+#include <cereal/types/vector.hpp>
+#include <experimental/filesystem>
+#include <fstream>
+#include <iostream>
+#include <phosphor-logging/elog-errors.hpp>
+#include <xyz/openbmc_project/Common/error.hpp>
+#include <xyz/openbmc_project/State/Boot/PostCode/server.hpp>
+#include <xyz/openbmc_project/State/Host/server.hpp>
+
+#define MaxPostCodeCycles 100
+
+const static constexpr char *PostCodePath =
+ "/xyz/openbmc_project/state/boot/raw";
+const static constexpr char *PropertiesIntf = "org.freedesktop.DBus.Properties";
+const static constexpr char *PostCodeListPath =
+ "/var/lib/phosphor-post-code-manager/";
+const static constexpr char *CurrentBootCycleIndexName =
+ "CurrentBootCycleIndex";
+const static constexpr char *HostStatePath = "/xyz/openbmc_project/state/host0";
+
+struct EventDeleter
+{
+ void operator()(sd_event *event) const
+ {
+ event = sd_event_unref(event);
+ }
+};
+using EventPtr = std::unique_ptr<sd_event, EventDeleter>;
+namespace fs = std::experimental::filesystem;
+namespace StateServer = sdbusplus::xyz::openbmc_project::State::server;
+
+using post_code =
+ sdbusplus::xyz::openbmc_project::State::Boot::server::PostCode;
+
+struct PostCode : sdbusplus::server::object_t<post_code>
+{
+ PostCode(sdbusplus::bus::bus &bus, const char *path, EventPtr &event) :
+ sdbusplus::server::object_t<post_code>(bus, path), bus(bus),
+ propertiesChangedSignalRaw(
+ bus,
+ sdbusplus::bus::match::rules::type::signal() +
+ sdbusplus::bus::match::rules::member("PropertiesChanged") +
+ sdbusplus::bus::match::rules::path(PostCodePath) +
+ sdbusplus::bus::match::rules::interface(PropertiesIntf),
+ [this](sdbusplus::message::message &msg) {
+ std::string objectName;
+ std::map<std::string, sdbusplus::message::variant<uint64_t>>
+ msgData;
+ msg.read(objectName, msgData);
+ // Check if it was the Value property that changed.
+ auto valPropMap = msgData.find("Value");
+ {
+ if (valPropMap != msgData.end())
+ {
+ this->savePostCodes(
+ sdbusplus::message::variant_ns::get<uint64_t>(
+ valPropMap->second));
+ }
+ }
+ }),
+ propertiesChangedSignalCurrentHostState(
+ bus,
+ sdbusplus::bus::match::rules::type::signal() +
+ sdbusplus::bus::match::rules::member("PropertiesChanged") +
+ sdbusplus::bus::match::rules::path(HostStatePath) +
+ sdbusplus::bus::match::rules::interface(PropertiesIntf),
+ [this](sdbusplus::message::message &msg) {
+ std::string objectName;
+ std::map<std::string, sdbusplus::message::variant<std::string>>
+ msgData;
+ msg.read(objectName, msgData);
+ // Check if it was the Value property that changed.
+ auto valPropMap = msgData.find("CurrentHostState");
+ {
+ if (valPropMap != msgData.end())
+ {
+ StateServer::Host::HostState currentHostState =
+ StateServer::Host::convertHostStateFromString(
+ sdbusplus::message::variant_ns::get<
+ std::string>(valPropMap->second));
+ if (currentHostState ==
+ StateServer::Host::HostState::Off)
+ {
+ if (this->currentBootCycleIndex() >=
+ this->maxBootCycleNum())
+ {
+ this->currentBootCycleIndex(1);
+ }
+ else
+ {
+ this->currentBootCycleIndex(
+ this->currentBootCycleIndex() + 1);
+ }
+ this->postCodes.clear();
+ }
+ }
+ }
+ })
+ {
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "PostCode is created");
+ auto dir = fs::path(PostCodeListPath);
+ fs::create_directories(dir);
+ strPostCodeListPath = PostCodeListPath;
+ strCurrentBootCycleIndexName = CurrentBootCycleIndexName;
+ uint16_t index = 0;
+ deserialize(
+ fs::path(strPostCodeListPath + strCurrentBootCycleIndexName),
+ index);
+ currentBootCycleIndex(index);
+ maxBootCycleNum(MaxPostCodeCycles);
+ if (currentBootCycleIndex() >= maxBootCycleNum())
+ {
+ currentBootCycleIndex(1);
+ }
+ else
+ {
+ currentBootCycleIndex(currentBootCycleIndex() + 1);
+ }
+ }
+ ~PostCode()
+ {
+ }
+
+ std::vector<uint64_t> getPostCodes(uint16_t index) override;
+
+ private:
+ sdbusplus::bus::bus &bus;
+ std::vector<uint64_t> postCodes;
+ std::string strPostCodeListPath;
+ std::string strCurrentBootCycleIndexName;
+ void savePostCodes(uint64_t code);
+ sdbusplus::bus::match_t propertiesChangedSignalRaw;
+ sdbusplus::bus::match_t propertiesChangedSignalCurrentHostState;
+ fs::path serialize(const std::string &path);
+ bool deserialize(const fs::path &path, uint16_t &index);
+ bool deserializePostCodes(const fs::path &path,
+ std::vector<uint64_t> &codes);
+};