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