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