1 2 #include "estoraged.hpp" 3 #include "getConfig.hpp" 4 #include "util.hpp" 5 6 #include <boost/asio/deadline_timer.hpp> 7 #include <boost/asio/io_context.hpp> 8 #include <boost/asio/post.hpp> 9 #include <boost/container/flat_map.hpp> 10 #include <boost/container/throw_exception.hpp> 11 #include <phosphor-logging/lg2.hpp> 12 #include <sdbusplus/asio/connection.hpp> 13 #include <sdbusplus/asio/object_server.hpp> 14 #include <sdbusplus/bus.hpp> 15 #include <sdbusplus/bus/match.hpp> 16 #include <util.hpp> 17 18 #include <cstdlib> 19 #include <filesystem> 20 #include <iostream> 21 #include <memory> 22 #include <string> 23 24 /* 25 * Get the configuration objects from Entity Manager and create new D-Bus 26 * objects for each one. This function can be called multiple times, in case 27 * new configuration objects show up later. 28 * 29 * Note: Currently, eStoraged can only support 1 eMMC device. 30 * Additional changes will be needed to support more than 1 eMMC, or to support 31 * more types of storage devices. 32 */ 33 void createStorageObjects( 34 sdbusplus::asio::object_server& objectServer, 35 boost::container::flat_map< 36 std::string, std::unique_ptr<estoraged::EStoraged>>& storageObjects, 37 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection) 38 { 39 auto getter = std::make_shared<estoraged::GetStorageConfiguration>( 40 dbusConnection, 41 [&objectServer, &storageObjects]( 42 const estoraged::ManagedStorageType& storageConfigurations) { 43 size_t numConfigObj = storageConfigurations.size(); 44 if (numConfigObj > 1) 45 { 46 lg2::error("eStoraged can only manage 1 eMMC device; found {NUM}", 47 "NUM", numConfigObj, "REDFISH_MESSAGE_ID", 48 std::string("OpenBMC.0.1.CreateStorageObjectsFail")); 49 return; 50 } 51 52 for (const std::pair<sdbusplus::message::object_path, 53 estoraged::StorageData>& storage : 54 storageConfigurations) 55 { 56 const std::string& path = storage.first.str; 57 58 if (storageObjects.find(path) != storageObjects.end()) 59 { 60 /* 61 * We've already created this object, or at least 62 * attempted to. 63 */ 64 continue; 65 } 66 67 /* Get the properties from the config object. */ 68 const estoraged::StorageData& data = storage.second; 69 70 /* Look for the device file. */ 71 const std::filesystem::path blockDevDir{"/sys/block"}; 72 std::filesystem::path deviceFile, sysfsDir; 73 std::string luksName, locationCode; 74 bool found = estoraged::util::findDevice(data, blockDevDir, 75 deviceFile, sysfsDir, 76 luksName, locationCode); 77 if (!found) 78 { 79 lg2::error("Device not found for path {PATH}", "PATH", path, 80 "REDFISH_MESSAGE_ID", 81 std::string("OpenBMC.0.1.CreateStorageObjectsFail")); 82 /* 83 * Set a NULL pointer as a placeholder, so that we don't 84 * try and fail again later. 85 */ 86 storageObjects[path] = nullptr; 87 continue; 88 } 89 90 uint64_t size = estoraged::util::findSizeOfBlockDevice(deviceFile); 91 92 uint8_t lifeleft = 93 estoraged::util::findPredictedMediaLifeLeftPercent(sysfsDir); 94 std::string partNumber = estoraged::util::getPartNumber(sysfsDir); 95 std::string serialNumber = 96 estoraged::util::getSerialNumber(sysfsDir); 97 /* Create the storage object. */ 98 storageObjects[path] = std::make_unique<estoraged::EStoraged>( 99 objectServer, path, deviceFile, luksName, size, lifeleft, 100 partNumber, serialNumber, locationCode); 101 lg2::info("Created eStoraged object for path {PATH}", "PATH", path, 102 "REDFISH_MESSAGE_ID", 103 std::string("OpenBMC.0.1.CreateStorageObjects")); 104 } 105 }); 106 getter->getConfiguration(); 107 } 108 109 int main(void) 110 { 111 try 112 { 113 // setup connection to dbus 114 boost::asio::io_context io; 115 auto conn = std::make_shared<sdbusplus::asio::connection>(io); 116 // request D-Bus server name. 117 conn->request_name("xyz.openbmc_project.eStoraged"); 118 sdbusplus::asio::object_server server(conn); 119 boost::container::flat_map<std::string, 120 std::unique_ptr<estoraged::EStoraged>> 121 storageObjects; 122 123 boost::asio::post( 124 io, [&]() { createStorageObjects(server, storageObjects, conn); }); 125 126 /* 127 * Set up an event handler to process any new configuration objects 128 * that show up later. 129 */ 130 boost::asio::deadline_timer filterTimer(io); 131 std::function<void(sdbusplus::message_t&)> eventHandler = 132 [&](sdbusplus::message_t& message) { 133 if (message.is_method_error()) 134 { 135 lg2::error("eventHandler callback method error"); 136 return; 137 } 138 /* 139 * This implicitly cancels the timer, if it's already pending. 140 * If there's a burst of events within a short period, we want 141 * to handle them all at once. So, we will wait this long for no 142 * more events to occur, before processing them. 143 */ 144 filterTimer.expires_from_now(boost::posix_time::seconds(1)); 145 146 filterTimer.async_wait([&](const boost::system::error_code& ec) { 147 if (ec == boost::asio::error::operation_aborted) 148 { 149 /* we were canceled */ 150 return; 151 } 152 if (ec) 153 { 154 lg2::error("timer error"); 155 return; 156 } 157 createStorageObjects(server, storageObjects, conn); 158 }); 159 }; 160 161 auto match = std::make_unique<sdbusplus::bus::match_t>( 162 static_cast<sdbusplus::bus_t&>(*conn), 163 "type='signal',member='PropertiesChanged',path_namespace='" + 164 std::string("/xyz/openbmc_project/inventory") + 165 "',arg0namespace='" + estoraged::emmcConfigInterface + "'", 166 eventHandler); 167 168 lg2::info("Storage management service is running", "REDFISH_MESSAGE_ID", 169 std::string("OpenBMC.1.0.ServiceStarted")); 170 171 io.run(); 172 return 0; 173 } 174 catch (const std::exception& e) 175 { 176 lg2::error(e.what(), "REDFISH_MESSAGE_ID", 177 std::string("OpenBMC.1.0.ServiceException")); 178 179 return 2; 180 } 181 return 1; 182 } 183