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