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