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