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      */
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      */
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 
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("Could not open file for writing  {LID_PATH}", "LID_PATH",
133                   lidPath.c_str());
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("writeFileFromMemory failed with rc= {RC}", "RC", rc);
142             return rc;
143         }
144         if (lidType == PLDM_FILE_TYPE_LID_MARKER)
145         {
146             markerLIDremainingSize -= length;
147             if (markerLIDremainingSize == 0)
148             {
149                 pldm::responder::oem_ibm_platform::Handler*
150                     oemIbmPlatformHandler = dynamic_cast<
151                         pldm::responder::oem_ibm_platform::Handler*>(
152                         oemPlatformHandler);
153                 auto sensorId =
154                     oemIbmPlatformHandler->codeUpdate->getMarkerLidSensor();
155                 using namespace pldm::responder::oem_ibm_platform;
156                 oemIbmPlatformHandler->sendStateSensorEvent(
157                     sensorId, PLDM_STATE_SENSOR_STATE, 0, VALID, VALID);
158                 // rc = validate api;
159                 rc = PLDM_SUCCESS;
160             }
161         }
162         else if (codeUpdateInProgress)
163         {
164             rc = processCodeUpdateLid(lidPath);
165         }
166         return rc;
167     }
168 
169     virtual int readIntoMemory(uint32_t offset, uint32_t& length,
170                                uint64_t address,
171                                oem_platform::Handler* oemPlatformHandler)
172     {
173         if (constructLIDPath(oemPlatformHandler))
174         {
175             return transferFileData(lidPath, true, offset, length, address);
176         }
177         return PLDM_ERROR;
178     }
179 
180     virtual int write(const char* buffer, uint32_t offset, uint32_t& length,
181                       oem_platform::Handler* oemPlatformHandler)
182     {
183         int rc = PLDM_SUCCESS;
184         bool codeUpdateInProgress = false;
185         if (oemPlatformHandler != nullptr)
186         {
187             pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler =
188                 dynamic_cast<pldm::responder::oem_ibm_platform::Handler*>(
189                     oemPlatformHandler);
190             codeUpdateInProgress =
191                 oemIbmPlatformHandler->codeUpdate->isCodeUpdateInProgress();
192             if (codeUpdateInProgress || lidType == PLDM_FILE_TYPE_LID_MARKER)
193             {
194                 std::string dir = LID_STAGING_DIR;
195                 std::stringstream stream;
196                 stream << std::hex << fileHandle;
197                 auto lidName = stream.str() + ".lid";
198                 lidPath = std::move(dir) + '/' + lidName;
199             }
200         }
201         bool fileExists = fs::exists(lidPath);
202         int flags{};
203         if (fileExists)
204         {
205             flags = O_RDWR;
206             size_t fileSize = fs::file_size(lidPath);
207             if (offset > fileSize)
208             {
209                 error(
210                     "Offset exceeds file size, OFFSET={OFFSET} FILE_SIZE={FILE_SIZE} FILE_HANDLE{FILE_HANDLE}",
211                     "OFFSET", offset, "FILE_SIZE", fileSize, "FILE_HANDLE",
212                     fileHandle);
213                 return PLDM_DATA_OUT_OF_RANGE;
214             }
215         }
216         else
217         {
218             flags = O_WRONLY | O_CREAT | O_TRUNC | O_SYNC;
219             if (offset > 0)
220             {
221                 error("Offset is non zero in a new file");
222                 return PLDM_DATA_OUT_OF_RANGE;
223             }
224         }
225         auto fd = open(lidPath.c_str(), flags, S_IRUSR);
226         if (fd == -1)
227         {
228             error("could not open file {LID_PATH}", "LID_PATH",
229                   lidPath.c_str());
230             return PLDM_ERROR;
231         }
232         rc = lseek(fd, offset, SEEK_SET);
233         if (rc == -1)
234         {
235             error("lseek failed, ERROR={ERR}, OFFSET={OFFSET}", "ERR", errno,
236                   "OFFSET", offset);
237             return PLDM_ERROR;
238         }
239         rc = ::write(fd, buffer, length);
240         if (rc == -1)
241         {
242             error(
243                 "file write failed, ERROR={ERR}, LENGTH={LEN}, OFFSET={OFFSET}",
244                 "ERR", errno, "LEN", length, "OFFSET", offset);
245             return PLDM_ERROR;
246         }
247         else if (rc == static_cast<int>(length))
248         {
249             rc = PLDM_SUCCESS;
250         }
251         else if (rc < static_cast<int>(length))
252         {
253             rc = PLDM_ERROR;
254         }
255         close(fd);
256 
257         if (lidType == PLDM_FILE_TYPE_LID_MARKER)
258         {
259             markerLIDremainingSize -= length;
260             if (markerLIDremainingSize == 0)
261             {
262                 pldm::responder::oem_ibm_platform::Handler*
263                     oemIbmPlatformHandler = dynamic_cast<
264                         pldm::responder::oem_ibm_platform::Handler*>(
265                         oemPlatformHandler);
266                 auto sensorId =
267                     oemIbmPlatformHandler->codeUpdate->getMarkerLidSensor();
268                 using namespace pldm::responder::oem_ibm_platform;
269                 oemIbmPlatformHandler->sendStateSensorEvent(
270                     sensorId, PLDM_STATE_SENSOR_STATE, 0, VALID, VALID);
271                 // validate api
272                 rc = PLDM_SUCCESS;
273             }
274         }
275         else if (codeUpdateInProgress)
276         {
277             rc = processCodeUpdateLid(lidPath);
278         }
279 
280         return rc;
281     }
282 
283     virtual int read(uint32_t offset, uint32_t& length, Response& response,
284                      oem_platform::Handler* oemPlatformHandler)
285     {
286         if (constructLIDPath(oemPlatformHandler))
287         {
288             return readFile(lidPath, offset, length, response);
289         }
290         return PLDM_ERROR;
291     }
292 
293     virtual int fileAck(uint8_t /*fileStatus*/)
294     {
295         return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
296     }
297 
298     virtual int newFileAvailable(uint64_t length)
299 
300     {
301         if (lidType == PLDM_FILE_TYPE_LID_MARKER)
302         {
303             markerLIDremainingSize = length;
304             return PLDM_SUCCESS;
305         }
306         return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
307     }
308 
309     /** @brief LidHandler destructor
310      */
311     ~LidHandler() {}
312 
313   protected:
314     std::string lidPath;
315     std::string sideToRead;
316     bool isPatchDir;
317     static inline MarkerLIDremainingSize markerLIDremainingSize;
318     uint8_t lidType;
319 };
320 
321 } // namespace responder
322 } // namespace pldm
323