1 #pragma once
2 #include <tinyxml2.h>
3 
4 #include <app.hpp>
5 #include <async_resp.hpp>
6 #include <boost/algorithm/string.hpp>
7 #include <boost/container/flat_set.hpp>
8 #include <error_messages.hpp>
9 #include <event_service_manager.hpp>
10 #include <ibm/locks.hpp>
11 #include <nlohmann/json.hpp>
12 #include <resource_messages.hpp>
13 #include <sdbusplus/message/types.hpp>
14 #include <utils/json_utils.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     10000000; // Allow save area dir size to be max 10MB
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;
86         return;
87     }
88     std::uintmax_t saveAreaDirSize = 0;
89     for (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;
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;
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;
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;
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;
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[10MB]";
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         redfish::EventServiceManager::getInstance().sendEvent(
224             redfish::messages::resourceChanged(), origin, "IBMConfigFile");
225     }
226     else
227     {
228         BMCWEB_LOG_DEBUG << "config file is created";
229         asyncResp->res.jsonValue["Description"] = "File Created";
230 
231         redfish::EventServiceManager::getInstance().sendEvent(
232             redfish::messages::resourceCreated(), origin, "IBMConfigFile");
233     }
234 }
235 
236 inline void
237     handleConfigFileList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
238 {
239     std::vector<std::string> pathObjList;
240     std::filesystem::path loc(
241         "/var/lib/bmcweb/ibm-management-console/configfiles");
242     if (std::filesystem::exists(loc) && std::filesystem::is_directory(loc))
243     {
244         for (const auto& file : std::filesystem::directory_iterator(loc))
245         {
246             const std::filesystem::path& pathObj = file.path();
247             pathObjList.push_back("/ibm/v1/Host/ConfigFiles/" +
248                                   pathObj.filename().string());
249         }
250     }
251     asyncResp->res.jsonValue["@odata.type"] =
252         "#IBMConfigFile.v1_0_0.IBMConfigFile";
253     asyncResp->res.jsonValue["@odata.id"] = "/ibm/v1/Host/ConfigFiles/";
254     asyncResp->res.jsonValue["Id"] = "ConfigFiles";
255     asyncResp->res.jsonValue["Name"] = "ConfigFiles";
256 
257     asyncResp->res.jsonValue["Members"] = std::move(pathObjList);
258     asyncResp->res.jsonValue["Actions"]["#IBMConfigFiles.DeleteAll"] = {
259         {"target",
260          "/ibm/v1/Host/ConfigFiles/Actions/IBMConfigFiles.DeleteAll"}};
261     return;
262 }
263 
264 inline void
265     deleteConfigFiles(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
266 {
267     std::vector<std::string> pathObjList;
268     std::error_code ec;
269     std::filesystem::path loc(
270         "/var/lib/bmcweb/ibm-management-console/configfiles");
271     if (std::filesystem::exists(loc) && std::filesystem::is_directory(loc))
272     {
273         std::filesystem::remove_all(loc, ec);
274         if (ec)
275         {
276             asyncResp->res.result(
277                 boost::beast::http::status::internal_server_error);
278             asyncResp->res.jsonValue["Description"] = internalServerError;
279             BMCWEB_LOG_DEBUG << "deleteConfigFiles: Failed to delete the "
280                                 "config files directory. ec : "
281                              << ec;
282         }
283     }
284     return;
285 }
286 
287 inline void
288     getLockServiceData(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
289 {
290     asyncResp->res.jsonValue["@odata.type"] = "#LockService.v1_0_0.LockService";
291     asyncResp->res.jsonValue["@odata.id"] = "/ibm/v1/HMC/LockService/";
292     asyncResp->res.jsonValue["Id"] = "LockService";
293     asyncResp->res.jsonValue["Name"] = "LockService";
294 
295     asyncResp->res.jsonValue["Actions"]["#LockService.AcquireLock"] = {
296         {"target", "/ibm/v1/HMC/LockService/Actions/LockService.AcquireLock"}};
297     asyncResp->res.jsonValue["Actions"]["#LockService.ReleaseLock"] = {
298         {"target", "/ibm/v1/HMC/LockService/Actions/LockService.ReleaseLock"}};
299     asyncResp->res.jsonValue["Actions"]["#LockService.GetLockList"] = {
300         {"target", "/ibm/v1/HMC/LockService/Actions/LockService.GetLockList"}};
301     return;
302 }
303 
304 inline void handleFileGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
305                           const std::string& fileID)
306 {
307     BMCWEB_LOG_DEBUG << "HandleGet on SaveArea files on path: " << fileID;
308     std::filesystem::path loc(
309         "/var/lib/bmcweb/ibm-management-console/configfiles/" + fileID);
310     if (!std::filesystem::exists(loc))
311     {
312         BMCWEB_LOG_ERROR << loc << "Not found";
313         asyncResp->res.result(boost::beast::http::status::not_found);
314         asyncResp->res.jsonValue["Description"] = resourceNotFoundMsg;
315         return;
316     }
317 
318     std::ifstream readfile(loc.string());
319     if (!readfile)
320     {
321         BMCWEB_LOG_ERROR << loc.string() << "Not found";
322         asyncResp->res.result(boost::beast::http::status::not_found);
323         asyncResp->res.jsonValue["Description"] = resourceNotFoundMsg;
324         return;
325     }
326 
327     std::string contentDispositionParam =
328         "attachment; filename=\"" + fileID + "\"";
329     asyncResp->res.addHeader("Content-Disposition", contentDispositionParam);
330     std::string fileData;
331     fileData = {std::istreambuf_iterator<char>(readfile),
332                 std::istreambuf_iterator<char>()};
333     asyncResp->res.jsonValue["Data"] = fileData;
334     return;
335 }
336 
337 inline void
338     handleFileDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
339                      const std::string& fileID)
340 {
341     std::string filePath("/var/lib/bmcweb/ibm-management-console/configfiles/" +
342                          fileID);
343     BMCWEB_LOG_DEBUG << "Removing the file : " << filePath << "\n";
344     std::ifstream fileOpen(filePath.c_str());
345     if (static_cast<bool>(fileOpen))
346     {
347         if (remove(filePath.c_str()) == 0)
348         {
349             BMCWEB_LOG_DEBUG << "File removed!\n";
350             asyncResp->res.jsonValue["Description"] = "File Deleted";
351         }
352         else
353         {
354             BMCWEB_LOG_ERROR << "File not removed!\n";
355             asyncResp->res.result(
356                 boost::beast::http::status::internal_server_error);
357             asyncResp->res.jsonValue["Description"] = internalServerError;
358         }
359     }
360     else
361     {
362         BMCWEB_LOG_ERROR << "File not found!\n";
363         asyncResp->res.result(boost::beast::http::status::not_found);
364         asyncResp->res.jsonValue["Description"] = resourceNotFoundMsg;
365     }
366     return;
367 }
368 
369 inline void
370     handleBroadcastService(const crow::Request& req,
371                            const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
372 {
373     std::string broadcastMsg;
374 
375     if (!redfish::json_util::readJson(req, asyncResp->res, "Message",
376                                       broadcastMsg))
377     {
378         BMCWEB_LOG_DEBUG << "Not a Valid JSON";
379         asyncResp->res.result(boost::beast::http::status::bad_request);
380         return;
381     }
382     if (broadcastMsg.size() > maxBroadcastMsgSize)
383     {
384         BMCWEB_LOG_ERROR << "Message size exceeds maximum allowed size[1KB]";
385         asyncResp->res.result(boost::beast::http::status::bad_request);
386         return;
387     }
388     redfish::EventServiceManager::getInstance().sendBroadcastMsg(broadcastMsg);
389     return;
390 }
391 
392 inline void handleFileUrl(const crow::Request& req,
393                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
394                           const std::string& fileID)
395 {
396     if (req.method() == boost::beast::http::verb::put)
397     {
398         handleFilePut(req, asyncResp, fileID);
399         return;
400     }
401     if (req.method() == boost::beast::http::verb::get)
402     {
403         handleFileGet(asyncResp, fileID);
404         return;
405     }
406     if (req.method() == boost::beast::http::verb::delete_)
407     {
408         handleFileDelete(asyncResp, fileID);
409         return;
410     }
411 }
412 
413 inline void
414     handleAcquireLockAPI(const crow::Request& req,
415                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
416                          std::vector<nlohmann::json> body)
417 {
418     LockRequests lockRequestStructure;
419     for (auto& element : body)
420     {
421         std::string lockType;
422         uint64_t resourceId;
423 
424         SegmentFlags segInfo;
425         std::vector<nlohmann::json> segmentFlags;
426 
427         if (!redfish::json_util::readJson(element, asyncResp->res, "LockType",
428                                           lockType, "ResourceID", resourceId,
429                                           "SegmentFlags", segmentFlags))
430         {
431             BMCWEB_LOG_DEBUG << "Not a Valid JSON";
432             asyncResp->res.result(boost::beast::http::status::bad_request);
433             return;
434         }
435         BMCWEB_LOG_DEBUG << lockType;
436         BMCWEB_LOG_DEBUG << resourceId;
437 
438         BMCWEB_LOG_DEBUG << "Segment Flags are present";
439 
440         for (auto& e : segmentFlags)
441         {
442             std::string lockFlags;
443             uint32_t segmentLength;
444 
445             if (!redfish::json_util::readJson(e, asyncResp->res, "LockFlag",
446                                               lockFlags, "SegmentLength",
447                                               segmentLength))
448             {
449                 asyncResp->res.result(boost::beast::http::status::bad_request);
450                 return;
451             }
452 
453             BMCWEB_LOG_DEBUG << "Lockflag : " << lockFlags;
454             BMCWEB_LOG_DEBUG << "SegmentLength : " << segmentLength;
455 
456             segInfo.push_back(std::make_pair(lockFlags, segmentLength));
457         }
458         lockRequestStructure.push_back(
459             make_tuple(req.session->uniqueId, req.session->clientId, lockType,
460                        resourceId, segInfo));
461     }
462 
463     // print lock request into journal
464 
465     for (auto& i : lockRequestStructure)
466     {
467         BMCWEB_LOG_DEBUG << std::get<0>(i);
468         BMCWEB_LOG_DEBUG << std::get<1>(i);
469         BMCWEB_LOG_DEBUG << std::get<2>(i);
470         BMCWEB_LOG_DEBUG << std::get<3>(i);
471 
472         for (const auto& p : std::get<4>(i))
473         {
474             BMCWEB_LOG_DEBUG << p.first << ", " << p.second;
475         }
476     }
477 
478     const LockRequests& t = lockRequestStructure;
479 
480     auto varAcquireLock = crow::ibm_mc_lock::Lock::getInstance().acquireLock(t);
481 
482     if (varAcquireLock.first)
483     {
484         // Either validity failure of there is a conflict with itself
485 
486         auto validityStatus =
487             std::get<std::pair<bool, int>>(varAcquireLock.second);
488 
489         if ((!validityStatus.first) && (validityStatus.second == 0))
490         {
491             BMCWEB_LOG_DEBUG << "Not a Valid record";
492             BMCWEB_LOG_DEBUG << "Bad json in request";
493             asyncResp->res.result(boost::beast::http::status::bad_request);
494             return;
495         }
496         if (validityStatus.first && (validityStatus.second == 1))
497         {
498             BMCWEB_LOG_DEBUG << "There is a conflict within itself";
499             asyncResp->res.result(boost::beast::http::status::bad_request);
500             return;
501         }
502     }
503     else
504     {
505         auto conflictStatus =
506             std::get<crow::ibm_mc_lock::Rc>(varAcquireLock.second);
507         if (!conflictStatus.first)
508         {
509             BMCWEB_LOG_DEBUG << "There is no conflict with the locktable";
510             asyncResp->res.result(boost::beast::http::status::ok);
511 
512             auto var = std::get<uint32_t>(conflictStatus.second);
513             nlohmann::json returnJson;
514             returnJson["id"] = var;
515             asyncResp->res.jsonValue["TransactionID"] = var;
516             return;
517         }
518         BMCWEB_LOG_DEBUG << "There is a conflict with the lock table";
519         asyncResp->res.result(boost::beast::http::status::conflict);
520         auto var =
521             std::get<std::pair<uint32_t, LockRequest>>(conflictStatus.second);
522         nlohmann::json returnJson, segments;
523         nlohmann::json myarray = nlohmann::json::array();
524         returnJson["TransactionID"] = var.first;
525         returnJson["SessionID"] = std::get<0>(var.second);
526         returnJson["HMCID"] = std::get<1>(var.second);
527         returnJson["LockType"] = std::get<2>(var.second);
528         returnJson["ResourceID"] = std::get<3>(var.second);
529 
530         for (auto& i : std::get<4>(var.second))
531         {
532             segments["LockFlag"] = i.first;
533             segments["SegmentLength"] = i.second;
534             myarray.push_back(segments);
535         }
536 
537         returnJson["SegmentFlags"] = myarray;
538 
539         asyncResp->res.jsonValue["Record"] = returnJson;
540         return;
541     }
542 }
543 inline void
544     handleRelaseAllAPI(const crow::Request& req,
545                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
546 {
547     crow::ibm_mc_lock::Lock::getInstance().releaseLock(req.session->uniqueId);
548     asyncResp->res.result(boost::beast::http::status::ok);
549     return;
550 }
551 
552 inline void
553     handleReleaseLockAPI(const crow::Request& req,
554                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
555                          const std::vector<uint32_t>& listTransactionIds)
556 {
557     BMCWEB_LOG_DEBUG << listTransactionIds.size();
558     BMCWEB_LOG_DEBUG << "Data is present";
559     for (unsigned int listTransactionId : listTransactionIds)
560     {
561         BMCWEB_LOG_DEBUG << listTransactionId;
562     }
563 
564     // validate the request ids
565 
566     auto varReleaselock = crow::ibm_mc_lock::Lock::getInstance().releaseLock(
567         listTransactionIds,
568         std::make_pair(req.session->clientId, req.session->uniqueId));
569 
570     if (!varReleaselock.first)
571     {
572         // validation Failed
573         asyncResp->res.result(boost::beast::http::status::bad_request);
574         return;
575     }
576     auto statusRelease =
577         std::get<crow::ibm_mc_lock::RcRelaseLock>(varReleaselock.second);
578     if (statusRelease.first)
579     {
580         // The current hmc owns all the locks, so we already released
581         // them
582         return;
583     }
584 
585     // valid rid, but the current hmc does not own all the locks
586     BMCWEB_LOG_DEBUG << "Current HMC does not own all the locks";
587     asyncResp->res.result(boost::beast::http::status::unauthorized);
588 
589     auto var = statusRelease.second;
590     nlohmann::json returnJson, segments;
591     nlohmann::json myArray = nlohmann::json::array();
592     returnJson["TransactionID"] = var.first;
593     returnJson["SessionID"] = std::get<0>(var.second);
594     returnJson["HMCID"] = std::get<1>(var.second);
595     returnJson["LockType"] = std::get<2>(var.second);
596     returnJson["ResourceID"] = std::get<3>(var.second);
597 
598     for (auto& i : std::get<4>(var.second))
599     {
600         segments["LockFlag"] = i.first;
601         segments["SegmentLength"] = i.second;
602         myArray.push_back(segments);
603     }
604 
605     returnJson["SegmentFlags"] = myArray;
606     asyncResp->res.jsonValue["Record"] = returnJson;
607     return;
608 }
609 
610 inline void
611     handleGetLockListAPI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
612                          const ListOfSessionIds& listSessionIds)
613 {
614     BMCWEB_LOG_DEBUG << listSessionIds.size();
615 
616     auto status =
617         crow::ibm_mc_lock::Lock::getInstance().getLockList(listSessionIds);
618     auto var = std::get<std::vector<std::pair<uint32_t, LockRequests>>>(status);
619 
620     nlohmann::json lockRecords = nlohmann::json::array();
621 
622     for (const auto& transactionId : var)
623     {
624         for (const auto& lockRecord : transactionId.second)
625         {
626             nlohmann::json returnJson;
627 
628             returnJson["TransactionID"] = transactionId.first;
629             returnJson["SessionID"] = std::get<0>(lockRecord);
630             returnJson["HMCID"] = std::get<1>(lockRecord);
631             returnJson["LockType"] = std::get<2>(lockRecord);
632             returnJson["ResourceID"] = std::get<3>(lockRecord);
633 
634             nlohmann::json segments;
635             nlohmann::json segmentInfoArray = nlohmann::json::array();
636 
637             for (const auto& segment : std::get<4>(lockRecord))
638             {
639                 segments["LockFlag"] = segment.first;
640                 segments["SegmentLength"] = segment.second;
641                 segmentInfoArray.push_back(segments);
642             }
643 
644             returnJson["SegmentFlags"] = segmentInfoArray;
645             lockRecords.push_back(returnJson);
646         }
647     }
648     asyncResp->res.result(boost::beast::http::status::ok);
649     asyncResp->res.jsonValue["Records"] = lockRecords;
650 }
651 
652 inline bool isValidConfigFileName(const std::string& fileName,
653                                   crow::Response& res)
654 {
655     if (fileName.empty())
656     {
657         BMCWEB_LOG_ERROR << "Empty filename";
658         res.jsonValue["Description"] = "Empty file path in the url";
659         return false;
660     }
661 
662     // ConfigFile name is allowed to take upper and lowercase letters,
663     // numbers and hyphen
664     std::size_t found = fileName.find_first_not_of(
665         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-");
666     if (found != std::string::npos)
667     {
668         BMCWEB_LOG_ERROR << "Unsupported character in filename: " << fileName;
669         res.jsonValue["Description"] = "Unsupported character in filename";
670         return false;
671     }
672 
673     // Check the filename length
674     if (fileName.length() > 20)
675     {
676         BMCWEB_LOG_ERROR << "Name must be maximum 20 characters. "
677                             "Input filename length is: "
678                          << fileName.length();
679         res.jsonValue["Description"] = "Filename must be maximum 20 characters";
680         return false;
681     }
682 
683     return true;
684 }
685 
686 inline void requestRoutes(App& app)
687 {
688 
689     // allowed only for admin
690     BMCWEB_ROUTE(app, "/ibm/v1/")
691         .privileges({{"ConfigureComponents", "ConfigureManager"}})
692         .methods(boost::beast::http::verb::get)(
693             [](const crow::Request&,
694                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
695                 asyncResp->res.jsonValue["@odata.type"] =
696                     "#ibmServiceRoot.v1_0_0.ibmServiceRoot";
697                 asyncResp->res.jsonValue["@odata.id"] = "/ibm/v1/";
698                 asyncResp->res.jsonValue["Id"] = "IBM Rest RootService";
699                 asyncResp->res.jsonValue["Name"] = "IBM Service Root";
700                 asyncResp->res.jsonValue["ConfigFiles"] = {
701                     {"@odata.id", "/ibm/v1/Host/ConfigFiles"}};
702                 asyncResp->res.jsonValue["LockService"] = {
703                     {"@odata.id", "/ibm/v1/HMC/LockService"}};
704                 asyncResp->res.jsonValue["BroadcastService"] = {
705                     {"@odata.id", "/ibm/v1/HMC/BroadcastService"}};
706             });
707 
708     BMCWEB_ROUTE(app, "/ibm/v1/Host/ConfigFiles")
709         .privileges({{"ConfigureComponents", "ConfigureManager"}})
710         .methods(boost::beast::http::verb::get)(
711             [](const crow::Request&,
712                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
713                 handleConfigFileList(asyncResp);
714             });
715 
716     BMCWEB_ROUTE(app,
717                  "/ibm/v1/Host/ConfigFiles/Actions/IBMConfigFiles.DeleteAll")
718         .privileges({{"ConfigureComponents", "ConfigureManager"}})
719         .methods(boost::beast::http::verb::post)(
720             [](const crow::Request&,
721                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
722                 deleteConfigFiles(asyncResp);
723             });
724 
725     BMCWEB_ROUTE(app, "/ibm/v1/Host/ConfigFiles/<str>")
726         .privileges({{"ConfigureComponents", "ConfigureManager"}})
727         .methods(boost::beast::http::verb::put, boost::beast::http::verb::get,
728                  boost::beast::http::verb::delete_)(
729             [](const crow::Request& req,
730                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
731                const std::string& fileName) {
732                 BMCWEB_LOG_DEBUG << "ConfigFile : " << fileName;
733                 // Validate the incoming fileName
734                 if (!isValidConfigFileName(fileName, asyncResp->res))
735                 {
736                     asyncResp->res.result(
737                         boost::beast::http::status::bad_request);
738                     return;
739                 }
740                 handleFileUrl(req, asyncResp, fileName);
741             });
742 
743     BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService")
744         .privileges({{"ConfigureComponents", "ConfigureManager"}})
745         .methods(boost::beast::http::verb::get)(
746             [](const crow::Request&,
747                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
748                 getLockServiceData(asyncResp);
749             });
750 
751     BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService/Actions/LockService.AcquireLock")
752         .privileges({{"ConfigureComponents", "ConfigureManager"}})
753         .methods(boost::beast::http::verb::post)(
754             [](const crow::Request& req,
755                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
756                 std::vector<nlohmann::json> body;
757                 if (!redfish::json_util::readJson(req, asyncResp->res,
758                                                   "Request", body))
759                 {
760                     BMCWEB_LOG_DEBUG << "Not a Valid JSON";
761                     asyncResp->res.result(
762                         boost::beast::http::status::bad_request);
763                     return;
764                 }
765                 handleAcquireLockAPI(req, asyncResp, body);
766             });
767     BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService/Actions/LockService.ReleaseLock")
768         .privileges({{"ConfigureComponents", "ConfigureManager"}})
769         .methods(boost::beast::http::verb::post)(
770             [](const crow::Request& req,
771                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
772                 std::string type;
773                 std::vector<uint32_t> listTransactionIds;
774 
775                 if (!redfish::json_util::readJson(req, asyncResp->res, "Type",
776                                                   type, "TransactionIDs",
777                                                   listTransactionIds))
778                 {
779                     asyncResp->res.result(
780                         boost::beast::http::status::bad_request);
781                     return;
782                 }
783                 if (type == "Transaction")
784                 {
785                     handleReleaseLockAPI(req, asyncResp, listTransactionIds);
786                 }
787                 else if (type == "Session")
788                 {
789                     handleRelaseAllAPI(req, asyncResp);
790                 }
791                 else
792                 {
793                     BMCWEB_LOG_DEBUG << " Value of Type : " << type
794                                      << "is Not a Valid key";
795                     redfish::messages::propertyValueNotInList(asyncResp->res,
796                                                               type, "Type");
797                 }
798             });
799     BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService/Actions/LockService.GetLockList")
800         .privileges({{"ConfigureComponents", "ConfigureManager"}})
801         .methods(boost::beast::http::verb::post)(
802             [](const crow::Request& req,
803                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
804                 ListOfSessionIds listSessionIds;
805 
806                 if (!redfish::json_util::readJson(req, asyncResp->res,
807                                                   "SessionIDs", listSessionIds))
808                 {
809                     asyncResp->res.result(
810                         boost::beast::http::status::bad_request);
811                     return;
812                 }
813                 handleGetLockListAPI(asyncResp, listSessionIds);
814             });
815 
816     BMCWEB_ROUTE(app, "/ibm/v1/HMC/BroadcastService")
817         .privileges({{"ConfigureComponents", "ConfigureManager"}})
818         .methods(boost::beast::http::verb::post)(
819             [](const crow::Request& req,
820                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
821                 handleBroadcastService(req, asyncResp);
822             });
823 }
824 
825 } // namespace ibm_mc
826 } // namespace crow
827