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}",
211                     "OFFSET", offset, "FILE_SIZE", fileSize);
212                 return PLDM_DATA_OUT_OF_RANGE;
213             }
214         }
215         else
216         {
217             flags = O_WRONLY | O_CREAT | O_TRUNC | O_SYNC;
218             if (offset > 0)
219             {
220                 error("Offset is non zero in a new file");
221                 return PLDM_DATA_OUT_OF_RANGE;
222             }
223         }
224         auto fd = open(lidPath.c_str(), flags, S_IRUSR);
225         if (fd == -1)
226         {
227             error("could not open file {LID_PATH}", "LID_PATH",
228                   lidPath.c_str());
229             return PLDM_ERROR;
230         }
231         rc = lseek(fd, offset, SEEK_SET);
232         if (rc == -1)
233         {
234             error("lseek failed, ERROR={ERR}, OFFSET={OFFSET}", "ERR", errno,
235                   "OFFSET", offset);
236             return PLDM_ERROR;
237         }
238         rc = ::write(fd, buffer, length);
239         if (rc == -1)
240         {
241             error(
242                 "file write failed, ERROR={ERR}, LENGTH={LEN}, OFFSET={OFFSET}",
243                 "ERR", errno, "LEN", length, "OFFSET", offset);
244             return PLDM_ERROR;
245         }
246         else if (rc == static_cast<int>(length))
247         {
248             rc = PLDM_SUCCESS;
249         }
250         else if (rc < static_cast<int>(length))
251         {
252             rc = PLDM_ERROR;
253         }
254         close(fd);
255 
256         if (lidType == PLDM_FILE_TYPE_LID_MARKER)
257         {
258             markerLIDremainingSize -= length;
259             if (markerLIDremainingSize == 0)
260             {
261                 pldm::responder::oem_ibm_platform::Handler*
262                     oemIbmPlatformHandler = dynamic_cast<
263                         pldm::responder::oem_ibm_platform::Handler*>(
264                         oemPlatformHandler);
265                 auto sensorId =
266                     oemIbmPlatformHandler->codeUpdate->getMarkerLidSensor();
267                 using namespace pldm::responder::oem_ibm_platform;
268                 oemIbmPlatformHandler->sendStateSensorEvent(
269                     sensorId, PLDM_STATE_SENSOR_STATE, 0, VALID, VALID);
270                 // validate api
271                 rc = PLDM_SUCCESS;
272             }
273         }
274         else if (codeUpdateInProgress)
275         {
276             rc = processCodeUpdateLid(lidPath);
277         }
278 
279         return rc;
280     }
281 
282     virtual int read(uint32_t offset, uint32_t& length, Response& response,
283                      oem_platform::Handler* oemPlatformHandler)
284     {
285         if (constructLIDPath(oemPlatformHandler))
286         {
287             return readFile(lidPath, offset, length, response);
288         }
289         return PLDM_ERROR;
290     }
291 
292     virtual int fileAck(uint8_t /*fileStatus*/)
293     {
294         return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
295     }
296 
297     virtual int newFileAvailable(uint64_t length)
298 
299     {
300         if (lidType == PLDM_FILE_TYPE_LID_MARKER)
301         {
302             markerLIDremainingSize = length;
303             return PLDM_SUCCESS;
304         }
305         return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
306     }
307 
308     /** @brief LidHandler destructor
309      */
310     ~LidHandler() {}
311 
312   protected:
313     std::string lidPath;
314     std::string sideToRead;
315     bool isPatchDir;
316     static inline MarkerLIDremainingSize markerLIDremainingSize;
317     uint8_t lidType;
318 };
319 
320 } // namespace responder
321 } // namespace pldm
322