1 #pragma once
2 
3 #include "app.hpp"
4 #include "async_resp.hpp"
5 #include "error_messages.hpp"
6 #include "event_service_manager.hpp"
7 #include "ibm/locks.hpp"
8 #include "resource_messages.hpp"
9 #include "utils/json_utils.hpp"
10 
11 #include <boost/algorithm/string/predicate.hpp>
12 #include <boost/container/flat_set.hpp>
13 #include <nlohmann/json.hpp>
14 #include <sdbusplus/message/types.hpp>
15 
16 #include <filesystem>
17 #include <fstream>
18 
19 using SType = std::string;
20 using SegmentFlags = std::vector<std::pair<std::string, uint32_t>>;
21 using LockRequest = std::tuple<SType, SType, SType, uint64_t, SegmentFlags>;
22 using LockRequests = std::vector<LockRequest>;
23 using Rc = std::pair<bool, std::variant<uint32_t, LockRequest>>;
24 using RcGetLockList =
25     std::variant<std::string, std::vector<std::pair<uint32_t, LockRequests>>>;
26 using ListOfSessionIds = std::vector<std::string>;
27 namespace crow
28 {
29 namespace ibm_mc
30 {
31 constexpr const char* methodNotAllowedMsg = "Method Not Allowed";
32 constexpr const char* resourceNotFoundMsg = "Resource Not Found";
33 constexpr const char* contentNotAcceptableMsg = "Content Not Acceptable";
34 constexpr const char* internalServerError = "Internal Server Error";
35 
36 constexpr size_t maxSaveareaDirSize =
37     25000000; // Allow save area dir size to be max 25MB
38 constexpr size_t minSaveareaFileSize =
39     100;      // Allow save area file size of minimum 100B
40 constexpr size_t maxSaveareaFileSize =
41     500000;   // Allow save area file size upto 500KB
42 constexpr size_t maxBroadcastMsgSize =
43     1000;     // Allow Broadcast message size upto 1KB
44 
45 inline void handleFilePut(const crow::Request& req,
46                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
47                           const std::string& fileID)
48 {
49     std::error_code ec;
50     // Check the content-type of the request
51     boost::beast::string_view contentType = req.getHeaderValue("content-type");
52     if (!boost::iequals(contentType, "application/octet-stream"))
53     {
54         asyncResp->res.result(boost::beast::http::status::not_acceptable);
55         asyncResp->res.jsonValue["Description"] = contentNotAcceptableMsg;
56         return;
57     }
58     BMCWEB_LOG_DEBUG(
59         "File upload in application/octet-stream format. Continue..");
60 
61     BMCWEB_LOG_DEBUG(
62         "handleIbmPut: Request to create/update the save-area file");
63     std::string_view path =
64         "/var/lib/bmcweb/ibm-management-console/configfiles";
65     if (!crow::ibm_utils::createDirectory(path))
66     {
67         asyncResp->res.result(boost::beast::http::status::not_found);
68         asyncResp->res.jsonValue["Description"] = resourceNotFoundMsg;
69         return;
70     }
71 
72     std::ofstream file;
73     std::filesystem::path loc(
74         "/var/lib/bmcweb/ibm-management-console/configfiles");
75 
76     // Get the current size of the savearea directory
77     std::filesystem::recursive_directory_iterator iter(loc, ec);
78     if (ec)
79     {
80         asyncResp->res.result(
81             boost::beast::http::status::internal_server_error);
82         asyncResp->res.jsonValue["Description"] = internalServerError;
83         BMCWEB_LOG_DEBUG("handleIbmPut: Failed to prepare save-area "
84                          "directory iterator. ec : {}",
85                          ec.message());
86         return;
87     }
88     std::uintmax_t saveAreaDirSize = 0;
89     for (const auto& it : iter)
90     {
91         if (!std::filesystem::is_directory(it, ec))
92         {
93             if (ec)
94             {
95                 asyncResp->res.result(
96                     boost::beast::http::status::internal_server_error);
97                 asyncResp->res.jsonValue["Description"] = internalServerError;
98                 BMCWEB_LOG_DEBUG("handleIbmPut: Failed to find save-area "
99                                  "directory . ec : {}",
100                                  ec.message());
101                 return;
102             }
103             std::uintmax_t fileSize = std::filesystem::file_size(it, ec);
104             if (ec)
105             {
106                 asyncResp->res.result(
107                     boost::beast::http::status::internal_server_error);
108                 asyncResp->res.jsonValue["Description"] = internalServerError;
109                 BMCWEB_LOG_DEBUG("handleIbmPut: Failed to find save-area "
110                                  "file size inside the directory . ec : {}",
111                                  ec.message());
112                 return;
113             }
114             saveAreaDirSize += fileSize;
115         }
116     }
117     BMCWEB_LOG_DEBUG("saveAreaDirSize: {}", saveAreaDirSize);
118 
119     // Get the file size getting uploaded
120     const std::string& data = req.body();
121     BMCWEB_LOG_DEBUG("data length: {}", data.length());
122 
123     if (data.length() < minSaveareaFileSize)
124     {
125         asyncResp->res.result(boost::beast::http::status::bad_request);
126         asyncResp->res.jsonValue["Description"] =
127             "File size is less than minimum allowed size[100B]";
128         return;
129     }
130     if (data.length() > maxSaveareaFileSize)
131     {
132         asyncResp->res.result(boost::beast::http::status::bad_request);
133         asyncResp->res.jsonValue["Description"] =
134             "File size exceeds maximum allowed size[500KB]";
135         return;
136     }
137 
138     // Form the file path
139     loc /= fileID;
140     BMCWEB_LOG_DEBUG("Writing to the file: {}", loc.string());
141 
142     // Check if the same file exists in the directory
143     bool fileExists = std::filesystem::exists(loc, ec);
144     if (ec)
145     {
146         asyncResp->res.result(
147             boost::beast::http::status::internal_server_error);
148         asyncResp->res.jsonValue["Description"] = internalServerError;
149         BMCWEB_LOG_DEBUG("handleIbmPut: Failed to find if file exists. ec : {}",
150                          ec.message());
151         return;
152     }
153 
154     std::uintmax_t newSizeToWrite = 0;
155     if (fileExists)
156     {
157         // File exists. Get the current file size
158         std::uintmax_t currentFileSize = std::filesystem::file_size(loc, ec);
159         if (ec)
160         {
161             asyncResp->res.result(
162                 boost::beast::http::status::internal_server_error);
163             asyncResp->res.jsonValue["Description"] = internalServerError;
164             BMCWEB_LOG_DEBUG("handleIbmPut: Failed to find file size. ec : {}",
165                              ec.message());
166             return;
167         }
168         // Calculate the difference in the file size.
169         // If the data.length is greater than the existing file size, then
170         // calculate the difference. Else consider the delta size as zero -
171         // because there is no increase in the total directory size.
172         // We need to add the diff only if the incoming data is larger than the
173         // existing filesize
174         if (data.length() > currentFileSize)
175         {
176             newSizeToWrite = data.length() - currentFileSize;
177         }
178         BMCWEB_LOG_DEBUG("newSizeToWrite: {}", newSizeToWrite);
179     }
180     else
181     {
182         // This is a new file upload
183         newSizeToWrite = data.length();
184     }
185 
186     // Calculate the total dir size before writing the new file
187     BMCWEB_LOG_DEBUG("total new size: {}", saveAreaDirSize + newSizeToWrite);
188 
189     if ((saveAreaDirSize + newSizeToWrite) > maxSaveareaDirSize)
190     {
191         asyncResp->res.result(boost::beast::http::status::bad_request);
192         asyncResp->res.jsonValue["Description"] =
193             "File size does not fit in the savearea "
194             "directory maximum allowed size[25MB]";
195         return;
196     }
197 
198     file.open(loc, std::ofstream::out);
199 
200     // set the permission of the file to 600
201     std::filesystem::perms permission = std::filesystem::perms::owner_write |
202                                         std::filesystem::perms::owner_read;
203     std::filesystem::permissions(loc, permission);
204 
205     if (file.fail())
206     {
207         BMCWEB_LOG_DEBUG("Error while opening the file for writing");
208         asyncResp->res.result(
209             boost::beast::http::status::internal_server_error);
210         asyncResp->res.jsonValue["Description"] =
211             "Error while creating the file";
212         return;
213     }
214     file << data;
215 
216     std::string origin = "/ibm/v1/Host/ConfigFiles/" + fileID;
217     // Push an event
218     if (fileExists)
219     {
220         BMCWEB_LOG_DEBUG("config file is updated");
221         asyncResp->res.jsonValue["Description"] = "File Updated";
222     }
223     else
224     {
225         BMCWEB_LOG_DEBUG("config file is created");
226         asyncResp->res.jsonValue["Description"] = "File Created";
227     }
228 }
229 
230 inline void
231     handleConfigFileList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
232 {
233     std::vector<std::string> pathObjList;
234     std::filesystem::path loc(
235         "/var/lib/bmcweb/ibm-management-console/configfiles");
236     if (std::filesystem::exists(loc) && std::filesystem::is_directory(loc))
237     {
238         for (const auto& file : std::filesystem::directory_iterator(loc))
239         {
240             const std::filesystem::path& pathObj = file.path();
241             if (std::filesystem::is_regular_file(pathObj))
242             {
243                 pathObjList.emplace_back("/ibm/v1/Host/ConfigFiles/" +
244                                          pathObj.filename().string());
245             }
246         }
247     }
248     asyncResp->res.jsonValue["@odata.type"] =
249         "#IBMConfigFile.v1_0_0.IBMConfigFile";
250     asyncResp->res.jsonValue["@odata.id"] = "/ibm/v1/Host/ConfigFiles/";
251     asyncResp->res.jsonValue["Id"] = "ConfigFiles";
252     asyncResp->res.jsonValue["Name"] = "ConfigFiles";
253 
254     asyncResp->res.jsonValue["Members"] = std::move(pathObjList);
255     asyncResp->res.jsonValue["Actions"]["#IBMConfigFiles.DeleteAll"] = {
256         {"target",
257          "/ibm/v1/Host/ConfigFiles/Actions/IBMConfigFiles.DeleteAll"}};
258 }
259 
260 inline void
261     deleteConfigFiles(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
262 {
263     std::error_code ec;
264     std::filesystem::path loc(
265         "/var/lib/bmcweb/ibm-management-console/configfiles");
266     if (std::filesystem::exists(loc) && std::filesystem::is_directory(loc))
267     {
268         std::filesystem::remove_all(loc, ec);
269         if (ec)
270         {
271             asyncResp->res.result(
272                 boost::beast::http::status::internal_server_error);
273             asyncResp->res.jsonValue["Description"] = internalServerError;
274             BMCWEB_LOG_DEBUG("deleteConfigFiles: Failed to delete the "
275                              "config files directory. ec : {}",
276                              ec.message());
277         }
278     }
279 }
280 
281 inline void
282     getLockServiceData(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
283 {
284     asyncResp->res.jsonValue["@odata.type"] = "#LockService.v1_0_0.LockService";
285     asyncResp->res.jsonValue["@odata.id"] = "/ibm/v1/HMC/LockService/";
286     asyncResp->res.jsonValue["Id"] = "LockService";
287     asyncResp->res.jsonValue["Name"] = "LockService";
288 
289     asyncResp->res.jsonValue["Actions"]["#LockService.AcquireLock"] = {
290         {"target", "/ibm/v1/HMC/LockService/Actions/LockService.AcquireLock"}};
291     asyncResp->res.jsonValue["Actions"]["#LockService.ReleaseLock"] = {
292         {"target", "/ibm/v1/HMC/LockService/Actions/LockService.ReleaseLock"}};
293     asyncResp->res.jsonValue["Actions"]["#LockService.GetLockList"] = {
294         {"target", "/ibm/v1/HMC/LockService/Actions/LockService.GetLockList"}};
295 }
296 
297 inline void handleFileGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
298                           const std::string& fileID)
299 {
300     BMCWEB_LOG_DEBUG("HandleGet on SaveArea files on path: {}", fileID);
301     std::filesystem::path loc(
302         "/var/lib/bmcweb/ibm-management-console/configfiles/" + fileID);
303     if (!std::filesystem::exists(loc) || !std::filesystem::is_regular_file(loc))
304     {
305         BMCWEB_LOG_WARNING("{} Not found", loc.string());
306         asyncResp->res.result(boost::beast::http::status::not_found);
307         asyncResp->res.jsonValue["Description"] = resourceNotFoundMsg;
308         return;
309     }
310 
311     std::ifstream readfile(loc.string());
312     if (!readfile)
313     {
314         BMCWEB_LOG_WARNING("{} Not found", loc.string());
315         asyncResp->res.result(boost::beast::http::status::not_found);
316         asyncResp->res.jsonValue["Description"] = resourceNotFoundMsg;
317         return;
318     }
319 
320     std::string contentDispositionParam = "attachment; filename=\"" + fileID +
321                                           "\"";
322     asyncResp->res.addHeader(boost::beast::http::field::content_disposition,
323                              contentDispositionParam);
324     std::string fileData;
325     fileData = {std::istreambuf_iterator<char>(readfile),
326                 std::istreambuf_iterator<char>()};
327     asyncResp->res.jsonValue["Data"] = fileData;
328 }
329 
330 inline void
331     handleFileDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
332                      const std::string& fileID)
333 {
334     std::string filePath("/var/lib/bmcweb/ibm-management-console/configfiles/" +
335                          fileID);
336     BMCWEB_LOG_DEBUG("Removing the file : {}", filePath);
337     std::ifstream fileOpen(filePath.c_str());
338     if (static_cast<bool>(fileOpen))
339     {
340         if (remove(filePath.c_str()) == 0)
341         {
342             BMCWEB_LOG_DEBUG("File removed!");
343             asyncResp->res.jsonValue["Description"] = "File Deleted";
344         }
345         else
346         {
347             BMCWEB_LOG_ERROR("File not removed!");
348             asyncResp->res.result(
349                 boost::beast::http::status::internal_server_error);
350             asyncResp->res.jsonValue["Description"] = internalServerError;
351         }
352     }
353     else
354     {
355         BMCWEB_LOG_WARNING("File not found!");
356         asyncResp->res.result(boost::beast::http::status::not_found);
357         asyncResp->res.jsonValue["Description"] = resourceNotFoundMsg;
358     }
359 }
360 
361 inline void
362     handleBroadcastService(const crow::Request& req,
363                            const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
364 {
365     std::string broadcastMsg;
366 
367     if (!redfish::json_util::readJsonPatch(req, asyncResp->res, "Message",
368                                            broadcastMsg))
369     {
370         BMCWEB_LOG_DEBUG("Not a Valid JSON");
371         asyncResp->res.result(boost::beast::http::status::bad_request);
372         return;
373     }
374     if (broadcastMsg.size() > maxBroadcastMsgSize)
375     {
376         BMCWEB_LOG_ERROR("Message size exceeds maximum allowed size[1KB]");
377         asyncResp->res.result(boost::beast::http::status::bad_request);
378         return;
379     }
380 }
381 
382 inline void handleFileUrl(const crow::Request& req,
383                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
384                           const std::string& fileID)
385 {
386     if (req.method() == boost::beast::http::verb::put)
387     {
388         handleFilePut(req, asyncResp, fileID);
389         return;
390     }
391     if (req.method() == boost::beast::http::verb::get)
392     {
393         handleFileGet(asyncResp, fileID);
394         return;
395     }
396     if (req.method() == boost::beast::http::verb::delete_)
397     {
398         handleFileDelete(asyncResp, fileID);
399         return;
400     }
401 }
402 
403 inline void
404     handleAcquireLockAPI(const crow::Request& req,
405                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
406                          std::vector<nlohmann::json> body)
407 {
408     LockRequests lockRequestStructure;
409     for (auto& element : body)
410     {
411         std::string lockType;
412         uint64_t resourceId = 0;
413 
414         SegmentFlags segInfo;
415         std::vector<nlohmann::json> segmentFlags;
416 
417         if (!redfish::json_util::readJson(element, asyncResp->res, "LockType",
418                                           lockType, "ResourceID", resourceId,
419                                           "SegmentFlags", segmentFlags))
420         {
421             BMCWEB_LOG_DEBUG("Not a Valid JSON");
422             asyncResp->res.result(boost::beast::http::status::bad_request);
423             return;
424         }
425         BMCWEB_LOG_DEBUG("{}", lockType);
426         BMCWEB_LOG_DEBUG("{}", resourceId);
427 
428         BMCWEB_LOG_DEBUG("Segment Flags are present");
429 
430         for (auto& e : segmentFlags)
431         {
432             std::string lockFlags;
433             uint32_t segmentLength = 0;
434 
435             if (!redfish::json_util::readJson(e, asyncResp->res, "LockFlag",
436                                               lockFlags, "SegmentLength",
437                                               segmentLength))
438             {
439                 asyncResp->res.result(boost::beast::http::status::bad_request);
440                 return;
441             }
442 
443             BMCWEB_LOG_DEBUG("Lockflag : {}", lockFlags);
444             BMCWEB_LOG_DEBUG("SegmentLength : {}", segmentLength);
445 
446             segInfo.emplace_back(std::make_pair(lockFlags, segmentLength));
447         }
448 
449         lockRequestStructure.emplace_back(make_tuple(
450             req.session->uniqueId, req.session->clientId.value_or(""), lockType,
451             resourceId, segInfo));
452     }
453 
454     // print lock request into journal
455 
456     for (auto& i : lockRequestStructure)
457     {
458         BMCWEB_LOG_DEBUG("{}", std::get<0>(i));
459         BMCWEB_LOG_DEBUG("{}", std::get<1>(i));
460         BMCWEB_LOG_DEBUG("{}", std::get<2>(i));
461         BMCWEB_LOG_DEBUG("{}", std::get<3>(i));
462 
463         for (const auto& p : std::get<4>(i))
464         {
465             BMCWEB_LOG_DEBUG("{}, {}", p.first, p.second);
466         }
467     }
468 
469     const LockRequests& t = lockRequestStructure;
470 
471     auto varAcquireLock = crow::ibm_mc_lock::Lock::getInstance().acquireLock(t);
472 
473     if (varAcquireLock.first)
474     {
475         // Either validity failure of there is a conflict with itself
476 
477         auto validityStatus =
478             std::get<std::pair<bool, int>>(varAcquireLock.second);
479 
480         if ((!validityStatus.first) && (validityStatus.second == 0))
481         {
482             BMCWEB_LOG_DEBUG("Not a Valid record");
483             BMCWEB_LOG_DEBUG("Bad json in request");
484             asyncResp->res.result(boost::beast::http::status::bad_request);
485             return;
486         }
487         if (validityStatus.first && (validityStatus.second == 1))
488         {
489             BMCWEB_LOG_ERROR("There is a conflict within itself");
490             asyncResp->res.result(boost::beast::http::status::conflict);
491             return;
492         }
493     }
494     else
495     {
496         auto conflictStatus =
497             std::get<crow::ibm_mc_lock::Rc>(varAcquireLock.second);
498         if (!conflictStatus.first)
499         {
500             BMCWEB_LOG_DEBUG("There is no conflict with the locktable");
501             asyncResp->res.result(boost::beast::http::status::ok);
502 
503             auto var = std::get<uint32_t>(conflictStatus.second);
504             nlohmann::json returnJson;
505             returnJson["id"] = var;
506             asyncResp->res.jsonValue["TransactionID"] = var;
507             return;
508         }
509         BMCWEB_LOG_DEBUG("There is a conflict with the lock table");
510         asyncResp->res.result(boost::beast::http::status::conflict);
511         auto var =
512             std::get<std::pair<uint32_t, LockRequest>>(conflictStatus.second);
513         nlohmann::json returnJson;
514         nlohmann::json segments;
515         nlohmann::json myarray = nlohmann::json::array();
516         returnJson["TransactionID"] = var.first;
517         returnJson["SessionID"] = std::get<0>(var.second);
518         returnJson["HMCID"] = std::get<1>(var.second);
519         returnJson["LockType"] = std::get<2>(var.second);
520         returnJson["ResourceID"] = std::get<3>(var.second);
521 
522         for (const auto& i : std::get<4>(var.second))
523         {
524             segments["LockFlag"] = i.first;
525             segments["SegmentLength"] = i.second;
526             myarray.push_back(segments);
527         }
528 
529         returnJson["SegmentFlags"] = myarray;
530         BMCWEB_LOG_ERROR("Conflicting lock record: {}", returnJson);
531         asyncResp->res.jsonValue["Record"] = returnJson;
532         return;
533     }
534 }
535 inline void
536     handleRelaseAllAPI(const crow::Request& req,
537                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
538 {
539     crow::ibm_mc_lock::Lock::getInstance().releaseLock(req.session->uniqueId);
540     asyncResp->res.result(boost::beast::http::status::ok);
541 }
542 
543 inline void
544     handleReleaseLockAPI(const crow::Request& req,
545                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
546                          const std::vector<uint32_t>& listTransactionIds)
547 {
548     BMCWEB_LOG_DEBUG("{}", listTransactionIds.size());
549     BMCWEB_LOG_DEBUG("Data is present");
550     for (unsigned int listTransactionId : listTransactionIds)
551     {
552         BMCWEB_LOG_DEBUG("{}", listTransactionId);
553     }
554 
555     // validate the request ids
556 
557     auto varReleaselock = crow::ibm_mc_lock::Lock::getInstance().releaseLock(
558         listTransactionIds, std::make_pair(req.session->clientId.value_or(""),
559                                            req.session->uniqueId));
560 
561     if (!varReleaselock.first)
562     {
563         // validation Failed
564         BMCWEB_LOG_ERROR("handleReleaseLockAPI: validation failed");
565         asyncResp->res.result(boost::beast::http::status::bad_request);
566         return;
567     }
568     auto statusRelease =
569         std::get<crow::ibm_mc_lock::RcRelaseLock>(varReleaselock.second);
570     if (statusRelease.first)
571     {
572         // The current hmc owns all the locks, so we already released
573         // them
574         return;
575     }
576 
577     // valid rid, but the current hmc does not own all the locks
578     BMCWEB_LOG_DEBUG("Current HMC does not own all the locks");
579     asyncResp->res.result(boost::beast::http::status::unauthorized);
580 
581     auto var = statusRelease.second;
582     nlohmann::json returnJson;
583     nlohmann::json segments;
584     nlohmann::json myArray = nlohmann::json::array();
585     returnJson["TransactionID"] = var.first;
586     returnJson["SessionID"] = std::get<0>(var.second);
587     returnJson["HMCID"] = std::get<1>(var.second);
588     returnJson["LockType"] = std::get<2>(var.second);
589     returnJson["ResourceID"] = std::get<3>(var.second);
590 
591     for (const auto& i : std::get<4>(var.second))
592     {
593         segments["LockFlag"] = i.first;
594         segments["SegmentLength"] = i.second;
595         myArray.push_back(segments);
596     }
597 
598     returnJson["SegmentFlags"] = myArray;
599     BMCWEB_LOG_DEBUG("handleReleaseLockAPI: lockrecord: {}", returnJson);
600     asyncResp->res.jsonValue["Record"] = returnJson;
601 }
602 
603 inline void
604     handleGetLockListAPI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
605                          const ListOfSessionIds& listSessionIds)
606 {
607     BMCWEB_LOG_DEBUG("{}", listSessionIds.size());
608 
609     auto status =
610         crow::ibm_mc_lock::Lock::getInstance().getLockList(listSessionIds);
611     auto var = std::get<std::vector<std::pair<uint32_t, LockRequests>>>(status);
612 
613     nlohmann::json lockRecords = nlohmann::json::array();
614 
615     for (const auto& transactionId : var)
616     {
617         for (const auto& lockRecord : transactionId.second)
618         {
619             nlohmann::json returnJson;
620 
621             returnJson["TransactionID"] = transactionId.first;
622             returnJson["SessionID"] = std::get<0>(lockRecord);
623             returnJson["HMCID"] = std::get<1>(lockRecord);
624             returnJson["LockType"] = std::get<2>(lockRecord);
625             returnJson["ResourceID"] = std::get<3>(lockRecord);
626 
627             nlohmann::json segments;
628             nlohmann::json segmentInfoArray = nlohmann::json::array();
629 
630             for (const auto& segment : std::get<4>(lockRecord))
631             {
632                 segments["LockFlag"] = segment.first;
633                 segments["SegmentLength"] = segment.second;
634                 segmentInfoArray.push_back(segments);
635             }
636 
637             returnJson["SegmentFlags"] = segmentInfoArray;
638             lockRecords.push_back(returnJson);
639         }
640     }
641     asyncResp->res.result(boost::beast::http::status::ok);
642     asyncResp->res.jsonValue["Records"] = lockRecords;
643 }
644 
645 inline bool isValidConfigFileName(const std::string& fileName,
646                                   crow::Response& res)
647 {
648     if (fileName.empty())
649     {
650         BMCWEB_LOG_ERROR("Empty filename");
651         res.jsonValue["Description"] = "Empty file path in the url";
652         return false;
653     }
654 
655     // ConfigFile name is allowed to take upper and lowercase letters,
656     // numbers and hyphen
657     std::size_t found = fileName.find_first_not_of(
658         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-");
659     if (found != std::string::npos)
660     {
661         BMCWEB_LOG_ERROR("Unsupported character in filename: {}", fileName);
662         res.jsonValue["Description"] = "Unsupported character in filename";
663         return false;
664     }
665 
666     // Check the filename length
667     if (fileName.length() > 20)
668     {
669         BMCWEB_LOG_ERROR("Name must be maximum 20 characters. "
670                          "Input filename length is: {}",
671                          fileName.length());
672         res.jsonValue["Description"] = "Filename must be maximum 20 characters";
673         return false;
674     }
675 
676     return true;
677 }
678 
679 inline void requestRoutes(App& app)
680 {
681     // allowed only for admin
682     BMCWEB_ROUTE(app, "/ibm/v1/")
683         .privileges({{"ConfigureComponents", "ConfigureManager"}})
684         .methods(boost::beast::http::verb::get)(
685             [](const crow::Request&,
686                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
687         asyncResp->res.jsonValue["@odata.type"] =
688             "#ibmServiceRoot.v1_0_0.ibmServiceRoot";
689         asyncResp->res.jsonValue["@odata.id"] = "/ibm/v1/";
690         asyncResp->res.jsonValue["Id"] = "IBM Rest RootService";
691         asyncResp->res.jsonValue["Name"] = "IBM Service Root";
692         asyncResp->res.jsonValue["ConfigFiles"]["@odata.id"] =
693             "/ibm/v1/Host/ConfigFiles";
694         asyncResp->res.jsonValue["LockService"]["@odata.id"] =
695             "/ibm/v1/HMC/LockService";
696         asyncResp->res.jsonValue["BroadcastService"]["@odata.id"] =
697             "/ibm/v1/HMC/BroadcastService";
698         });
699 
700     BMCWEB_ROUTE(app, "/ibm/v1/Host/ConfigFiles")
701         .privileges({{"ConfigureComponents", "ConfigureManager"}})
702         .methods(boost::beast::http::verb::get)(
703             [](const crow::Request&,
704                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
705         handleConfigFileList(asyncResp);
706         });
707 
708     BMCWEB_ROUTE(app,
709                  "/ibm/v1/Host/ConfigFiles/Actions/IBMConfigFiles.DeleteAll")
710         .privileges({{"ConfigureComponents", "ConfigureManager"}})
711         .methods(boost::beast::http::verb::post)(
712             [](const crow::Request&,
713                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
714         deleteConfigFiles(asyncResp);
715         });
716 
717     BMCWEB_ROUTE(app, "/ibm/v1/Host/ConfigFiles/<str>")
718         .privileges({{"ConfigureComponents", "ConfigureManager"}})
719         .methods(boost::beast::http::verb::put, boost::beast::http::verb::get,
720                  boost::beast::http::verb::delete_)(
721             [](const crow::Request& req,
722                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
723                const std::string& fileName) {
724         BMCWEB_LOG_DEBUG("ConfigFile : {}", fileName);
725         // Validate the incoming fileName
726         if (!isValidConfigFileName(fileName, asyncResp->res))
727         {
728             asyncResp->res.result(boost::beast::http::status::bad_request);
729             return;
730         }
731         handleFileUrl(req, asyncResp, fileName);
732         });
733 
734     BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService")
735         .privileges({{"ConfigureComponents", "ConfigureManager"}})
736         .methods(boost::beast::http::verb::get)(
737             [](const crow::Request&,
738                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
739         getLockServiceData(asyncResp);
740         });
741 
742     BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService/Actions/LockService.AcquireLock")
743         .privileges({{"ConfigureComponents", "ConfigureManager"}})
744         .methods(boost::beast::http::verb::post)(
745             [](const crow::Request& req,
746                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
747         std::vector<nlohmann::json> body;
748         if (!redfish::json_util::readJsonAction(req, asyncResp->res, "Request",
749                                                 body))
750         {
751             BMCWEB_LOG_DEBUG("Not a Valid JSON");
752             asyncResp->res.result(boost::beast::http::status::bad_request);
753             return;
754         }
755         handleAcquireLockAPI(req, asyncResp, body);
756         });
757     BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService/Actions/LockService.ReleaseLock")
758         .privileges({{"ConfigureComponents", "ConfigureManager"}})
759         .methods(boost::beast::http::verb::post)(
760             [](const crow::Request& req,
761                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
762         std::string type;
763         std::vector<uint32_t> listTransactionIds;
764 
765         if (!redfish::json_util::readJsonPatch(req, asyncResp->res, "Type",
766                                                type, "TransactionIDs",
767                                                listTransactionIds))
768         {
769             asyncResp->res.result(boost::beast::http::status::bad_request);
770             return;
771         }
772         if (type == "Transaction")
773         {
774             handleReleaseLockAPI(req, asyncResp, listTransactionIds);
775         }
776         else if (type == "Session")
777         {
778             handleRelaseAllAPI(req, asyncResp);
779         }
780         else
781         {
782             BMCWEB_LOG_DEBUG(" Value of Type : {}is Not a Valid key", type);
783             redfish::messages::propertyValueNotInList(asyncResp->res, type,
784                                                       "Type");
785         }
786         });
787     BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService/Actions/LockService.GetLockList")
788         .privileges({{"ConfigureComponents", "ConfigureManager"}})
789         .methods(boost::beast::http::verb::post)(
790             [](const crow::Request& req,
791                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
792         ListOfSessionIds listSessionIds;
793 
794         if (!redfish::json_util::readJsonPatch(req, asyncResp->res,
795                                                "SessionIDs", listSessionIds))
796         {
797             asyncResp->res.result(boost::beast::http::status::bad_request);
798             return;
799         }
800         handleGetLockListAPI(asyncResp, listSessionIds);
801         });
802 
803     BMCWEB_ROUTE(app, "/ibm/v1/HMC/BroadcastService")
804         .privileges({{"ConfigureComponents", "ConfigureManager"}})
805         .methods(boost::beast::http::verb::post)(
806             [](const crow::Request& req,
807                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
808         handleBroadcastService(req, asyncResp);
809         });
810 }
811 
812 } // namespace ibm_mc
813 } // namespace crow
814