1 /**
2  * Copyright © 2021 IBM 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 #include "config.h"
17 
18 #include "dbus_zone.hpp"
19 
20 #include "dbus_paths.hpp"
21 #include "sdbusplus.hpp"
22 #include "zone.hpp"
23 
24 #include <fmt/format.h>
25 
26 #include <cereal/archives/json.hpp>
27 #include <cereal/cereal.hpp>
28 #include <phosphor-logging/log.hpp>
29 
30 #include <algorithm>
31 #include <filesystem>
32 #include <fstream>
33 
34 namespace phosphor::fan::control::json
35 {
36 
37 using namespace phosphor::logging;
38 namespace fs = std::filesystem;
39 
40 DBusZone::DBusZone(const Zone& zone) :
41     ThermalModeIntf(util::SDBusPlus::getBus(),
42                     (fs::path{CONTROL_OBJPATH} /= zone.getName()).c_str(),
43                     ThermalModeIntf::action::defer_emit),
44     _zone(zone)
45 {}
46 
47 std::string DBusZone::current(std::string value)
48 {
49     auto current = ThermalModeIntf::current();
50     std::transform(value.begin(), value.end(), value.begin(), toupper);
51 
52     auto supported = ThermalModeIntf::supported();
53     auto isSupported =
54         std::any_of(supported.begin(), supported.end(), [&value](auto& s) {
55             std::transform(s.begin(), s.end(), s.begin(), toupper);
56             return value == s;
57         });
58 
59     if (isSupported && value != current)
60     {
61         current = ThermalModeIntf::current(value);
62         if (_zone.isPersisted(thermalModeIntf, currentProp))
63         {
64             saveCurrentMode();
65         }
66     }
67 
68     return current;
69 }
70 
71 void DBusZone::restoreCurrentMode()
72 {
73     auto current = ThermalModeIntf::current();
74     fs::path path{CONTROL_PERSIST_ROOT_PATH};
75     // Append this object's name and property description
76     path /= _zone.getName();
77     path /= "CurrentMode";
78     fs::create_directories(path.parent_path());
79 
80     try
81     {
82         if (fs::exists(path))
83         {
84             std::ifstream ifs(path.c_str(), std::ios::in | std::ios::binary);
85             cereal::JSONInputArchive iArch(ifs);
86             iArch(current);
87         }
88     }
89     catch (const std::exception& e)
90     {
91         // Include possible exception when removing file, otherwise ec = 0
92         std::error_code ec;
93         fs::remove(path, ec);
94         log<level::ERR>(
95             fmt::format("Unable to restore persisted `Current` thermal mode "
96                         "property ({}, ec: {})",
97                         e.what(), ec.value())
98                 .c_str());
99         current = ThermalModeIntf::current();
100     }
101 
102     this->current(current);
103 }
104 
105 void DBusZone::saveCurrentMode()
106 {
107     fs::path path{CONTROL_PERSIST_ROOT_PATH};
108     // Append this object's name and property description
109     path /= _zone.getName();
110     path /= "CurrentMode";
111     std::ofstream ofs(path.c_str(), std::ios::binary);
112     cereal::JSONOutputArchive oArch(ofs);
113     oArch(ThermalModeIntf::current());
114 }
115 
116 } // namespace phosphor::fan::control::json
117