1 /*
2 // Copyright (c) 2019 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 #pragma once
17 #include <fcntl.h>
18 #include <unistd.h>
19 
20 #include <cereal/access.hpp>
21 #include <cereal/archives/json.hpp>
22 #include <cereal/cereal.hpp>
23 #include <cereal/types/vector.hpp>
24 #include <experimental/filesystem>
25 #include <fstream>
26 #include <iostream>
27 #include <phosphor-logging/elog-errors.hpp>
28 #include <xyz/openbmc_project/Common/error.hpp>
29 #include <xyz/openbmc_project/State/Boot/PostCode/server.hpp>
30 #include <xyz/openbmc_project/State/Host/server.hpp>
31 
32 #define MaxPostCodeCycles 100
33 
34 const static constexpr char *PostCodePath =
35     "/xyz/openbmc_project/state/boot/raw";
36 const static constexpr char *PropertiesIntf = "org.freedesktop.DBus.Properties";
37 const static constexpr char *PostCodeListPath =
38     "/var/lib/phosphor-post-code-manager/";
39 const static constexpr char *CurrentBootCycleIndexName =
40     "CurrentBootCycleIndex";
41 const static constexpr char *HostStatePath = "/xyz/openbmc_project/state/host0";
42 
43 struct EventDeleter
44 {
45     void operator()(sd_event *event) const
46     {
47         event = sd_event_unref(event);
48     }
49 };
50 using EventPtr = std::unique_ptr<sd_event, EventDeleter>;
51 namespace fs = std::experimental::filesystem;
52 namespace StateServer = sdbusplus::xyz::openbmc_project::State::server;
53 
54 using post_code =
55     sdbusplus::xyz::openbmc_project::State::Boot::server::PostCode;
56 
57 struct PostCode : sdbusplus::server::object_t<post_code>
58 {
59     PostCode(sdbusplus::bus::bus &bus, const char *path, EventPtr &event) :
60         sdbusplus::server::object_t<post_code>(bus, path), bus(bus),
61         propertiesChangedSignalRaw(
62             bus,
63             sdbusplus::bus::match::rules::type::signal() +
64                 sdbusplus::bus::match::rules::member("PropertiesChanged") +
65                 sdbusplus::bus::match::rules::path(PostCodePath) +
66                 sdbusplus::bus::match::rules::interface(PropertiesIntf),
67             [this](sdbusplus::message::message &msg) {
68                 std::string objectName;
69                 std::map<std::string, sdbusplus::message::variant<uint64_t>>
70                     msgData;
71                 msg.read(objectName, msgData);
72                 // Check if it was the Value property that changed.
73                 auto valPropMap = msgData.find("Value");
74                 {
75                     if (valPropMap != msgData.end())
76                     {
77                         this->savePostCodes(
78                             sdbusplus::message::variant_ns::get<uint64_t>(
79                                 valPropMap->second));
80                     }
81                 }
82             }),
83         propertiesChangedSignalCurrentHostState(
84             bus,
85             sdbusplus::bus::match::rules::type::signal() +
86                 sdbusplus::bus::match::rules::member("PropertiesChanged") +
87                 sdbusplus::bus::match::rules::path(HostStatePath) +
88                 sdbusplus::bus::match::rules::interface(PropertiesIntf),
89             [this](sdbusplus::message::message &msg) {
90                 std::string objectName;
91                 std::map<std::string, sdbusplus::message::variant<std::string>>
92                     msgData;
93                 msg.read(objectName, msgData);
94                 // Check if it was the Value property that changed.
95                 auto valPropMap = msgData.find("CurrentHostState");
96                 {
97                     if (valPropMap != msgData.end())
98                     {
99                         StateServer::Host::HostState currentHostState =
100                             StateServer::Host::convertHostStateFromString(
101                                 sdbusplus::message::variant_ns::get<
102                                     std::string>(valPropMap->second));
103                         if (currentHostState ==
104                             StateServer::Host::HostState::Off)
105                         {
106                             if (this->currentBootCycleIndex() >=
107                                 this->maxBootCycleNum())
108                             {
109                                 this->currentBootCycleIndex(1);
110                             }
111                             else
112                             {
113                                 this->currentBootCycleIndex(
114                                     this->currentBootCycleIndex() + 1);
115                             }
116                             this->postCodes.clear();
117                         }
118                     }
119                 }
120             })
121     {
122         phosphor::logging::log<phosphor::logging::level::INFO>(
123             "PostCode is created");
124         auto dir = fs::path(PostCodeListPath);
125         fs::create_directories(dir);
126         strPostCodeListPath = PostCodeListPath;
127         strCurrentBootCycleIndexName = CurrentBootCycleIndexName;
128         uint16_t index = 0;
129         deserialize(
130             fs::path(strPostCodeListPath + strCurrentBootCycleIndexName),
131             index);
132         currentBootCycleIndex(index);
133         maxBootCycleNum(MaxPostCodeCycles);
134         if (currentBootCycleIndex() >= maxBootCycleNum())
135         {
136             currentBootCycleIndex(1);
137         }
138         else
139         {
140             currentBootCycleIndex(currentBootCycleIndex() + 1);
141         }
142     }
143     ~PostCode()
144     {
145     }
146 
147     std::vector<uint64_t> getPostCodes(uint16_t index) override;
148 
149   private:
150     sdbusplus::bus::bus &bus;
151     std::vector<uint64_t> postCodes;
152     std::string strPostCodeListPath;
153     std::string strCurrentBootCycleIndexName;
154     void savePostCodes(uint64_t code);
155     sdbusplus::bus::match_t propertiesChangedSignalRaw;
156     sdbusplus::bus::match_t propertiesChangedSignalCurrentHostState;
157     fs::path serialize(const std::string &path);
158     bool deserialize(const fs::path &path, uint16_t &index);
159     bool deserializePostCodes(const fs::path &path,
160                               std::vector<uint64_t> &codes);
161 };
162