1 #pragma once
2 
3 #include "config.h"
4 
5 #include "file_io_by_type.hpp"
6 
7 #include <filesystem>
8 #include <sstream>
9 #include <string>
10 
11 namespace pldm
12 {
13 namespace responder
14 {
15 
16 namespace fs = std::filesystem;
17 
18 using MarkerLIDremainingSize = uint64_t;
19 
20 /** @class LidHandler
21  *
22  *  @brief Inherits and implements FileHandler. This class is used
23  *  to read/write LIDs.
24  */
25 class LidHandler : public FileHandler
26 {
27   public:
28     /** @brief LidHandler constructor
29      */
30     LidHandler(uint32_t fileHandle, bool permSide, uint8_t lidType = 0) :
31         FileHandler(fileHandle), lidType(lidType)
32     {
33         sideToRead = permSide ? Pside : Tside;
34         isPatchDir = false;
35         std::string dir = permSide ? LID_ALTERNATE_DIR : LID_RUNNING_DIR;
36         std::stringstream stream;
37         stream << std::hex << fileHandle;
38         auto lidName = stream.str() + ".lid";
39         std::string patchDir =
40             permSide ? LID_ALTERNATE_PATCH_DIR : LID_RUNNING_PATCH_DIR;
41         auto patch = fs::path(patchDir) / lidName;
42         if (fs::is_regular_file(patch))
43         {
44             lidPath = patch;
45             isPatchDir = true;
46         }
47         else
48         {
49             lidPath = std::move(dir) + '/' + lidName;
50         }
51     }
52 
53     /** @brief Method to construct the LID path based on current boot side
54      *  @param[in] oemPlatformHandler - OEM platform handler
55      *  @return bool - true if a new path is constructed
56      */
57     bool constructLIDPath(oem_platform::Handler* oemPlatformHandler)
58     {
59         if (oemPlatformHandler != nullptr)
60         {
61             pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler =
62                 dynamic_cast<pldm::responder::oem_ibm_platform::Handler*>(
63                     oemPlatformHandler);
64             std::string dir = LID_ALTERNATE_DIR;
65             if (isPatchDir)
66             {
67                 dir = LID_ALTERNATE_PATCH_DIR;
68             }
69             if (oemIbmPlatformHandler->codeUpdate->fetchCurrentBootSide() ==
70                 sideToRead)
71             {
72                 if (isPatchDir)
73                 {
74                     dir = LID_RUNNING_PATCH_DIR;
75                 }
76                 else
77                 {
78                     dir = LID_RUNNING_DIR;
79                 }
80             }
81             else if (oemIbmPlatformHandler->codeUpdate
82                          ->isCodeUpdateInProgress())
83             {
84                 return false;
85             }
86 
87             std::stringstream stream;
88             stream << std::hex << fileHandle;
89             auto lidName = stream.str() + ".lid";
90             lidPath = std::move(dir) + '/' + lidName;
91         }
92         return true;
93     }
94 
95     virtual int writeFromMemory(uint32_t offset, uint32_t length,
96                                 uint64_t address,
97                                 oem_platform::Handler* oemPlatformHandler)
98     {
99         int rc = PLDM_SUCCESS;
100         bool codeUpdateInProgress = false;
101         if (oemPlatformHandler != nullptr)
102         {
103             pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler =
104                 dynamic_cast<pldm::responder::oem_ibm_platform::Handler*>(
105                     oemPlatformHandler);
106             codeUpdateInProgress =
107                 oemIbmPlatformHandler->codeUpdate->isCodeUpdateInProgress();
108             if (codeUpdateInProgress || lidType == PLDM_FILE_TYPE_LID_MARKER)
109             {
110                 std::string dir = LID_STAGING_DIR;
111                 std::stringstream stream;
112                 stream << std::hex << fileHandle;
113                 auto lidName = stream.str() + ".lid";
114                 lidPath = std::move(dir) + '/' + lidName;
115             }
116         }
117         bool fileExists = fs::exists(lidPath);
118         int flags{};
119         if (fileExists)
120         {
121             flags = O_RDWR;
122         }
123         else
124         {
125             flags = O_WRONLY | O_CREAT | O_TRUNC | O_SYNC;
126         }
127         auto fd = open(lidPath.c_str(), flags, S_IRUSR);
128         if (fd == -1)
129         {
130             std::cerr << "Could not open file for writing  " << lidPath.c_str()
131                       << "\n";
132             return PLDM_ERROR;
133         }
134         close(fd);
135 
136         rc = transferFileData(lidPath, false, offset, length, address);
137         if (rc != PLDM_SUCCESS)
138         {
139             std::cerr << "writeFileFromMemory failed with rc= " << rc << " \n";
140             return rc;
141         }
142         if (lidType == PLDM_FILE_TYPE_LID_MARKER)
143         {
144             markerLIDremainingSize -= length;
145             if (markerLIDremainingSize == 0)
146             {
147                 pldm::responder::oem_ibm_platform::Handler*
148                     oemIbmPlatformHandler = dynamic_cast<
149                         pldm::responder::oem_ibm_platform::Handler*>(
150                         oemPlatformHandler);
151                 auto sensorId =
152                     oemIbmPlatformHandler->codeUpdate->getMarkerLidSensor();
153                 using namespace pldm::responder::oem_ibm_platform;
154                 oemIbmPlatformHandler->sendStateSensorEvent(
155                     sensorId, PLDM_STATE_SENSOR_STATE, 0, VALID, VALID);
156                 // rc = validate api;
157                 rc = PLDM_SUCCESS;
158             }
159         }
160         else if (codeUpdateInProgress)
161         {
162             rc = processCodeUpdateLid(lidPath);
163         }
164         return rc;
165     }
166 
167     virtual int readIntoMemory(uint32_t offset, uint32_t& length,
168                                uint64_t address,
169                                oem_platform::Handler* oemPlatformHandler)
170     {
171         if (constructLIDPath(oemPlatformHandler))
172         {
173             return transferFileData(lidPath, true, offset, length, address);
174         }
175         return PLDM_ERROR;
176     }
177 
178     virtual int write(const char* buffer, uint32_t offset, uint32_t& length,
179                       oem_platform::Handler* oemPlatformHandler)
180     {
181         int rc = PLDM_SUCCESS;
182         bool codeUpdateInProgress = false;
183         if (oemPlatformHandler != nullptr)
184         {
185             pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler =
186                 dynamic_cast<pldm::responder::oem_ibm_platform::Handler*>(
187                     oemPlatformHandler);
188             codeUpdateInProgress =
189                 oemIbmPlatformHandler->codeUpdate->isCodeUpdateInProgress();
190             if (codeUpdateInProgress || lidType == PLDM_FILE_TYPE_LID_MARKER)
191             {
192                 std::string dir = LID_STAGING_DIR;
193                 std::stringstream stream;
194                 stream << std::hex << fileHandle;
195                 auto lidName = stream.str() + ".lid";
196                 lidPath = std::move(dir) + '/' + lidName;
197             }
198         }
199         bool fileExists = fs::exists(lidPath);
200         int flags{};
201         if (fileExists)
202         {
203             flags = O_RDWR;
204             size_t fileSize = fs::file_size(lidPath);
205             if (offset > fileSize)
206             {
207                 std::cerr << "Offset exceeds file size, OFFSET=" << offset
208                           << " FILE_SIZE=" << fileSize << "\n";
209                 return PLDM_DATA_OUT_OF_RANGE;
210             }
211         }
212         else
213         {
214             flags = O_WRONLY | O_CREAT | O_TRUNC | O_SYNC;
215             if (offset > 0)
216             {
217                 std::cerr << "Offset is non zero in a new file \n";
218                 return PLDM_DATA_OUT_OF_RANGE;
219             }
220         }
221         auto fd = open(lidPath.c_str(), flags, S_IRUSR);
222         if (fd == -1)
223         {
224             std::cerr << "could not open file " << lidPath.c_str() << "\n";
225             return PLDM_ERROR;
226         }
227         rc = lseek(fd, offset, SEEK_SET);
228         if (rc == -1)
229         {
230             std::cerr << "lseek failed, ERROR=" << errno
231                       << ", OFFSET=" << offset << "\n";
232             return PLDM_ERROR;
233         }
234         rc = ::write(fd, buffer, length);
235         if (rc == -1)
236         {
237             std::cerr << "file write failed, ERROR=" << errno
238                       << ", LENGTH=" << length << ", OFFSET=" << offset << "\n";
239             return PLDM_ERROR;
240         }
241         else if (rc == static_cast<int>(length))
242         {
243             rc = PLDM_SUCCESS;
244         }
245         else if (rc < static_cast<int>(length))
246         {
247             rc = PLDM_ERROR;
248         }
249         close(fd);
250 
251         if (lidType == PLDM_FILE_TYPE_LID_MARKER)
252         {
253             markerLIDremainingSize -= length;
254             if (markerLIDremainingSize == 0)
255             {
256                 pldm::responder::oem_ibm_platform::Handler*
257                     oemIbmPlatformHandler = dynamic_cast<
258                         pldm::responder::oem_ibm_platform::Handler*>(
259                         oemPlatformHandler);
260                 auto sensorId =
261                     oemIbmPlatformHandler->codeUpdate->getMarkerLidSensor();
262                 using namespace pldm::responder::oem_ibm_platform;
263                 oemIbmPlatformHandler->sendStateSensorEvent(
264                     sensorId, PLDM_STATE_SENSOR_STATE, 0, VALID, VALID);
265                 // validate api
266                 rc = PLDM_SUCCESS;
267             }
268         }
269         else if (codeUpdateInProgress)
270         {
271             rc = processCodeUpdateLid(lidPath);
272         }
273 
274         return rc;
275     }
276 
277     virtual int read(uint32_t offset, uint32_t& length, Response& response,
278                      oem_platform::Handler* oemPlatformHandler)
279     {
280         if (constructLIDPath(oemPlatformHandler))
281         {
282             return readFile(lidPath, offset, length, response);
283         }
284         return PLDM_ERROR;
285     }
286 
287     virtual int fileAck(uint8_t /*fileStatus*/)
288     {
289         return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
290     }
291 
292     virtual int newFileAvailable(uint64_t length)
293 
294     {
295         if (lidType == PLDM_FILE_TYPE_LID_MARKER)
296         {
297             markerLIDremainingSize = length;
298             return PLDM_SUCCESS;
299         }
300         return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
301     }
302 
303     /** @brief LidHandler destructor
304      */
305     ~LidHandler()
306     {}
307 
308   protected:
309     std::string lidPath;
310     std::string sideToRead;
311     bool isPatchDir;
312     static inline MarkerLIDremainingSize markerLIDremainingSize;
313     uint8_t lidType;
314 };
315 
316 } // namespace responder
317 } // namespace pldm
318