1 #include "inventory_backup_handler.hpp"
2
3 #include "error_codes.hpp"
4 #include "utility/common_utility.hpp"
5 #include "utility/dbus_utility.hpp"
6
checkInventoryBackupPath(uint16_t & o_errCode) const7 bool InventoryBackupHandler::checkInventoryBackupPath(
8 uint16_t& o_errCode) const noexcept
9 {
10 bool l_rc{false};
11 o_errCode = 0;
12 try
13 {
14 const auto l_systemInventoryBackupPath{
15 m_inventoryBackupPath /
16 std::filesystem::path(vpd::constants::systemInvPath)
17 .relative_path()};
18
19 if (std::filesystem::is_directory(l_systemInventoryBackupPath) &&
20 !std::filesystem::is_empty(l_systemInventoryBackupPath))
21 {
22 // check number of directories under /system path, as we are only
23 // interested in the FRUs VPD which is populated under respective
24 // /system/chassis* directories
25 auto l_backupDirIt = std::filesystem::directory_iterator{
26 l_systemInventoryBackupPath};
27
28 const auto l_numSubDirectories = std::count_if(
29 std::filesystem::begin(l_backupDirIt),
30 std::filesystem::end(l_backupDirIt),
31 [](const auto& l_entry) { return l_entry.is_directory(); });
32
33 l_rc = (l_numSubDirectories != 0);
34 }
35 }
36 catch (const std::exception& l_ex)
37 {
38 o_errCode = vpd::error_code::STANDARD_EXCEPTION;
39
40 m_logger->logMessage("Failed to check inventory path. Error: " +
41 std::string(l_ex.what()));
42 }
43 return l_rc;
44 }
45
restoreInventoryBackupData(uint16_t & o_errCode) const46 bool InventoryBackupHandler::restoreInventoryBackupData(
47 uint16_t& o_errCode) const noexcept
48 {
49 bool l_rc{false};
50 o_errCode = 0;
51 try
52 {
53 if (!checkInventoryBackupPath(o_errCode))
54 {
55 if (o_errCode)
56 {
57 throw std::runtime_error(
58 "Failed to check if inventory backup path exists. Error: " +
59 vpd::commonUtility::getErrCodeMsg(o_errCode));
60 }
61 return l_rc;
62 }
63
64 const auto l_systemInventoryPrimaryPath{
65 m_inventoryPrimaryPath /
66 std::filesystem::path(vpd::constants::systemVpdInvPath)
67 .relative_path()};
68
69 if (std::filesystem::is_directory(l_systemInventoryPrimaryPath))
70 {
71 const auto l_systemInventoryBackupPath{
72 m_inventoryBackupPath /
73 std::filesystem::path(vpd::constants::systemVpdInvPath)
74 .relative_path()};
75
76 // copy all sub directories under /system from backup path to
77 // primary path
78 auto l_backupDirIt = std::filesystem::directory_iterator{
79 l_systemInventoryBackupPath};
80
81 // vector to hold a list of sub directories under /system for which
82 // restoration failed
83 using FailedPathList = std::vector<std::filesystem::path>;
84 FailedPathList l_failedPaths;
85
86 std::for_each(std::filesystem::begin(l_backupDirIt),
87 std::filesystem::end(l_backupDirIt),
88 [this,
89 l_systemInventoryPrimaryPath =
90 std::as_const(l_systemInventoryPrimaryPath),
91 &l_failedPaths](const auto& l_entry) {
92 if (l_entry.is_directory())
93 {
94 if (!moveFiles(l_entry.path(),
95 l_systemInventoryPrimaryPath /
96 l_entry.path().filename()))
97 {
98 l_failedPaths.emplace_back(
99 l_entry.path().filename());
100 }
101 }
102 });
103
104 // check if there are any paths for which restoration failed, if yes
105 // log a PEL
106 if (!l_failedPaths.empty())
107 {
108 std::string l_formattedFailedPaths{"Failed paths: "};
109
110 // create a string representation of the failed path list
111 for (const auto& l_path : l_failedPaths)
112 {
113 l_formattedFailedPaths +=
114 std::format("[{}],", l_path.string());
115 }
116
117 m_logger->logMessage(
118 "Failed to restore inventory data for some chassis. Check user data for details",
119 vpd::PlaceHolder::PEL,
120 vpd::types::PelInfoTuple{
121 vpd::types::ErrorType::FirmwareError,
122 vpd::types::SeverityType::Warning, 0,
123 l_formattedFailedPaths, std::nullopt, std::nullopt,
124 std::nullopt});
125 }
126 // We have logged a PEL for the paths(chassis) which we have failed
127 // to move. Consider restoration is successful even if have failed
128 // to move some of the paths (chassis) under /system, so that
129 // inventory manager exposes atleast some of the chassis.
130 l_rc = true;
131 }
132 else
133 {
134 o_errCode = vpd::error_code::INVALID_INVENTORY_PATH;
135 }
136 }
137 catch (const std::exception& l_ex)
138 {
139 m_logger->logMessage(
140 "Failed to restore inventory backup data from [" +
141 m_inventoryBackupPath.string() + "] to [" +
142 m_inventoryPrimaryPath.string() +
143 "] Error: " + std::string(l_ex.what()),
144 vpd::PlaceHolder::PEL,
145 vpd::types::PelInfoTuple{vpd::types::ErrorType::FirmwareError,
146 vpd::types::SeverityType::Warning, 0,
147 std::nullopt, std::nullopt, std::nullopt,
148 std::nullopt});
149
150 o_errCode = vpd::error_code::STANDARD_EXCEPTION;
151 }
152 return l_rc;
153 }
154
clearInventoryBackupData(uint16_t & o_errCode) const155 bool InventoryBackupHandler::clearInventoryBackupData(
156 uint16_t& o_errCode) const noexcept
157 {
158 bool l_rc{false};
159 o_errCode = 0;
160 try
161 {
162 const auto l_systemInventoryBackupPath{
163 m_inventoryBackupPath /
164 std::filesystem::path(vpd::constants::systemVpdInvPath)
165 .relative_path()};
166
167 std::filesystem::remove_all(l_systemInventoryBackupPath);
168
169 l_rc = true;
170 }
171 catch (const std::exception& l_ex)
172 {
173 m_logger->logMessage(
174 "Failed to clear inventory backup data from path [" +
175 m_inventoryBackupPath.string() +
176 "]. Error: " + std::string(l_ex.what()),
177 vpd::PlaceHolder::PEL,
178 vpd::types::PelInfoTuple{vpd::types::ErrorType::FirmwareError,
179 vpd::types::SeverityType::Warning, 0,
180 std::nullopt, std::nullopt, std::nullopt,
181 std::nullopt});
182
183 o_errCode = vpd::error_code::STANDARD_EXCEPTION;
184 }
185 return l_rc;
186 }
187
restartInventoryManagerService(uint16_t & o_errCode) const188 bool InventoryBackupHandler::restartInventoryManagerService(
189 uint16_t& o_errCode) const noexcept
190 {
191 bool l_rc{false};
192 o_errCode = 0;
193 try
194 {
195 // Restart inventory manager service, with a re-try limit of 3 attempts
196 constexpr auto l_numRetries{3};
197
198 for (unsigned l_attempt = 0; l_attempt < l_numRetries; ++l_attempt)
199 {
200 if (vpd::commonUtility::restartService(
201 m_inventoryManagerServiceName, o_errCode))
202 {
203 // restarting inventory manager service is successful, return
204 // success
205 return true;
206 }
207 }
208
209 // re-try limit crossed
210 m_logger->logMessage(
211 "Failed to restart [" + m_inventoryManagerServiceName + "] after " +
212 std::to_string(l_numRetries) + " attempts. Error: " +
213 vpd::commonUtility::getErrCodeMsg(o_errCode));
214
215 // check inventory manager service state and set appropriate error code
216 o_errCode =
217 vpd::dbusUtility::isServiceRunning(m_inventoryManagerServiceName)
218 ? vpd::error_code::SERVICE_RUNNING
219 : vpd::error_code::SERVICE_NOT_RUNNING;
220 }
221 catch (const std::exception& l_ex)
222 {
223 m_logger->logMessage("Failed to restart inventory manager service " +
224 m_inventoryManagerServiceName +
225 ". Error: " + std::string(l_ex.what()));
226 o_errCode = vpd::error_code::STANDARD_EXCEPTION;
227 }
228 return l_rc;
229 }
230
moveFiles(const std::filesystem::path & l_src,const std::filesystem::path & l_dest) const231 bool InventoryBackupHandler::moveFiles(
232 const std::filesystem::path& l_src,
233 const std::filesystem::path& l_dest) const noexcept
234 {
235 bool l_rc{false};
236 try
237 {
238 std::error_code l_ec;
239
240 // try to rename first as it is more efficient
241 std::filesystem::rename(l_src, l_dest, l_ec);
242
243 if (l_ec == std::errc::directory_not_empty)
244 {
245 // rename failed, because destination path
246 // already exists and is not empty
247 // let's try to copy the data while overwriting
248
249 std::filesystem::copy(
250 l_src, l_dest,
251 std::filesystem::copy_options::recursive |
252 std::filesystem::copy_options::overwrite_existing);
253
254 // remove the original after successful copy
255 if (static_cast<std::uintmax_t>(-1) ==
256 std::filesystem::remove_all(l_src, l_ec))
257 {
258 m_logger->logMessage(
259 "Failed to remove file [" + l_src.string() +
260 "]. Error: " + l_ec.message(),
261 vpd::PlaceHolder::COLLECTION);
262 }
263 }
264 else if (l_ec)
265 {
266 // for all other errors, we need to throw so
267 // that it fails the operation
268 throw std::runtime_error(l_ec.message());
269 }
270
271 l_rc = true;
272 }
273 catch (const std::exception& l_ex)
274 {
275 m_logger->logMessage(
276 "Failed to move files from [" + l_src.string() + "] to [" +
277 l_dest.string() + "]. Error: " + l_ex.what(),
278 vpd::PlaceHolder::COLLECTION);
279 }
280
281 return l_rc;
282 }
283