1 #include "handler.hpp" 2 3 #include "mdrv2.hpp" 4 #include "smbios_mdrv2.hpp" 5 6 #include <sys/stat.h> 7 #include <unistd.h> 8 9 #include <ipmid/api.hpp> 10 #include <phosphor-logging/log.hpp> 11 #include <sdbusplus/bus.hpp> 12 #include <sdbusplus/exception.hpp> 13 #include <sdbusplus/message.hpp> 14 15 #include <algorithm> 16 #include <cstdint> 17 #include <ctime> 18 #include <fstream> 19 #include <memory> 20 #include <string> 21 #include <vector> 22 23 namespace blobs 24 { 25 26 namespace internal 27 { 28 29 constexpr const char* mdrV2Service = "xyz.openbmc_project.Smbios.MDR_V2"; 30 constexpr const char* mdrV2Interface = "xyz.openbmc_project.Smbios.MDR_V2"; 31 32 bool syncSmbiosData() 33 { 34 bool status = false; 35 sdbusplus::bus::bus bus = 36 sdbusplus::bus::bus(ipmid_get_sd_bus_connection()); 37 sdbusplus::message::message method = 38 bus.new_method_call(mdrV2Service, phosphor::smbios::mdrV2Path, 39 mdrV2Interface, "AgentSynchronizeData"); 40 41 try 42 { 43 sdbusplus::message::message reply = bus.call(method); 44 reply.read(status); 45 } 46 catch (const sdbusplus::exception_t& e) 47 { 48 phosphor::logging::log<phosphor::logging::level::ERR>( 49 "Error Sync data with service", 50 phosphor::logging::entry("ERROR=%s", e.what()), 51 phosphor::logging::entry("SERVICE=%s", mdrV2Service), 52 phosphor::logging::entry("PATH=%s", phosphor::smbios::mdrV2Path)); 53 return false; 54 } 55 56 if (!status) 57 { 58 phosphor::logging::log<phosphor::logging::level::ERR>( 59 "Sync data with service failure"); 60 return false; 61 } 62 63 return true; 64 } 65 66 } // namespace internal 67 68 bool SmbiosBlobHandler::canHandleBlob(const std::string& path) 69 { 70 return path == blobId; 71 } 72 73 std::vector<std::string> SmbiosBlobHandler::getBlobIds() 74 { 75 return std::vector<std::string>(1, blobId); 76 } 77 78 bool SmbiosBlobHandler::deleteBlob(const std::string& path) 79 { 80 return false; 81 } 82 83 bool SmbiosBlobHandler::stat(const std::string& path, struct BlobMeta* meta) 84 { 85 if (!blobPtr || blobPtr->blobId != path) 86 { 87 return false; 88 } 89 90 meta->size = blobPtr->buffer.size(); 91 meta->blobState = blobPtr->state; 92 return true; 93 } 94 95 bool SmbiosBlobHandler::open(uint16_t session, uint16_t flags, 96 const std::string& path) 97 { 98 if (flags & blobs::OpenFlags::read) 99 { 100 /* Disable the read operation. */ 101 return false; 102 } 103 104 /* The handler only allows one session. If an open blob exists, return 105 * false directly. 106 */ 107 if (blobPtr) 108 { 109 return false; 110 } 111 blobPtr = std::make_unique<SmbiosBlob>(session, path, flags); 112 return true; 113 } 114 115 std::vector<uint8_t> SmbiosBlobHandler::read(uint16_t session, uint32_t offset, 116 uint32_t requestedSize) 117 { 118 /* SMBIOS blob handler does not support read. */ 119 return std::vector<uint8_t>(); 120 } 121 122 bool SmbiosBlobHandler::write(uint16_t session, uint32_t offset, 123 const std::vector<uint8_t>& data) 124 { 125 if (!blobPtr || blobPtr->sessionId != session) 126 { 127 return false; 128 } 129 130 if (!(blobPtr->state & blobs::StateFlags::open_write)) 131 { 132 phosphor::logging::log<phosphor::logging::level::ERR>( 133 "No open blob to write"); 134 return false; 135 } 136 137 /* Is the offset beyond the array? */ 138 if (offset >= maxBufferSize) 139 { 140 return false; 141 } 142 143 /* Determine whether all their bytes will fit. */ 144 uint32_t remain = maxBufferSize - offset; 145 if (data.size() > remain) 146 { 147 return false; 148 } 149 150 /* Resize the buffer if what we're writing will go over the size */ 151 uint32_t newBufferSize = data.size() + offset; 152 if (newBufferSize > blobPtr->buffer.size()) 153 { 154 blobPtr->buffer.resize(newBufferSize); 155 } 156 157 std::memcpy(blobPtr->buffer.data() + offset, data.data(), data.size()); 158 return true; 159 } 160 161 bool SmbiosBlobHandler::writeMeta(uint16_t session, uint32_t offset, 162 const std::vector<uint8_t>& data) 163 { 164 return false; 165 } 166 167 bool SmbiosBlobHandler::commit(uint16_t session, 168 const std::vector<uint8_t>& data) 169 { 170 if (!data.empty()) 171 { 172 phosphor::logging::log<phosphor::logging::level::ERR>( 173 "Unexpected data provided to commit call"); 174 return false; 175 } 176 177 if (!blobPtr || blobPtr->sessionId != session) 178 { 179 return false; 180 } 181 182 /* If a blob is committing or commited, return true directly. But if last 183 * commit fails, may try to commit again. 184 */ 185 if (blobPtr->state & 186 (blobs::StateFlags::committing | blobs::StateFlags::committed)) 187 { 188 return true; 189 } 190 191 /* Clear the commit_error bit. */ 192 blobPtr->state &= ~blobs::StateFlags::commit_error; 193 194 MDRSMBIOSHeader mdrHdr; 195 mdrHdr.mdrType = mdrTypeII; 196 mdrHdr.timestamp = std::time(nullptr); 197 mdrHdr.dataSize = blobPtr->buffer.size(); 198 if (access(smbiosPath, F_OK) == -1) 199 { 200 int flag = mkdir(smbiosPath, S_IRWXU); 201 if (flag != 0) 202 { 203 phosphor::logging::log<phosphor::logging::level::ERR>( 204 "create folder failed for writting smbios file"); 205 blobPtr->state |= blobs::StateFlags::commit_error; 206 return false; 207 } 208 } 209 210 std::ofstream smbiosFile(mdrType2File, 211 std::ios_base::binary | std::ios_base::trunc); 212 if (!smbiosFile.good()) 213 { 214 phosphor::logging::log<phosphor::logging::level::ERR>( 215 "Write data from flash error - Open SMBIOS table file failure"); 216 blobPtr->state |= blobs::StateFlags::commit_error; 217 return false; 218 } 219 220 smbiosFile.exceptions(std::ofstream::badbit | std::ofstream::failbit); 221 try 222 { 223 smbiosFile.write(reinterpret_cast<char*>(&mdrHdr), 224 sizeof(MDRSMBIOSHeader)); 225 smbiosFile.write(reinterpret_cast<char*>(blobPtr->buffer.data()), 226 mdrHdr.dataSize); 227 blobPtr->state |= blobs::StateFlags::committing; 228 } 229 catch (const std::ofstream::failure& e) 230 { 231 phosphor::logging::log<phosphor::logging::level::ERR>( 232 "Write data from flash error - write data error", 233 phosphor::logging::entry("ERROR=%s", e.what())); 234 blobPtr->state |= blobs::StateFlags::commit_error; 235 return false; 236 } 237 238 if (!internal::syncSmbiosData()) 239 { 240 blobPtr->state &= ~blobs::StateFlags::committing; 241 blobPtr->state |= blobs::StateFlags::commit_error; 242 return false; 243 } 244 245 // Unset committing state and set committed state 246 blobPtr->state &= ~blobs::StateFlags::committing; 247 blobPtr->state |= blobs::StateFlags::committed; 248 249 return true; 250 } 251 252 bool SmbiosBlobHandler::close(uint16_t session) 253 { 254 if (!blobPtr || blobPtr->sessionId != session) 255 { 256 return false; 257 } 258 259 blobPtr = nullptr; 260 return true; 261 } 262 263 bool SmbiosBlobHandler::stat(uint16_t session, struct BlobMeta* meta) 264 { 265 if (!blobPtr || blobPtr->sessionId != session) 266 { 267 return false; 268 } 269 270 meta->size = blobPtr->buffer.size(); 271 meta->blobState = blobPtr->state; 272 return true; 273 } 274 275 bool SmbiosBlobHandler::expire(uint16_t session) 276 { 277 return close(session); 278 } 279 280 } // namespace blobs 281