1 #include "filesystem_log_watcher.hpp" 2 3 #include "event_service_manager.hpp" 4 #include "logging.hpp" 5 6 #include <sys/inotify.h> 7 8 #include <boost/asio/buffer.hpp> 9 #include <boost/asio/error.hpp> 10 #include <boost/asio/io_context.hpp> 11 #include <boost/asio/posix/stream_descriptor.hpp> 12 13 #include <array> 14 #include <cstddef> 15 #include <cstring> 16 #include <optional> 17 #include <string> 18 19 namespace redfish 20 { 21 22 // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 23 static std::optional<boost::asio::posix::stream_descriptor> inotifyConn; 24 // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 25 static int inotifyFd = -1; 26 // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 27 static int dirWatchDesc = -1; 28 // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 29 static int fileWatchDesc = -1; 30 // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 31 static std::array<char, 1024> readBuffer{}; 32 33 static constexpr const char* redfishEventLogDir = "/var/log"; 34 static constexpr const size_t iEventSize = sizeof(inotify_event); 35 36 static void watchRedfishEventLogFile() 37 { 38 if (!inotifyConn) 39 { 40 BMCWEB_LOG_ERROR("inotify Connection is not present"); 41 return; 42 } 43 44 inotifyConn->async_read_some( 45 boost::asio::buffer(readBuffer), 46 [&](const boost::system::error_code& ec, 47 const std::size_t& bytesTransferred) { 48 if (ec == boost::asio::error::operation_aborted) 49 { 50 BMCWEB_LOG_DEBUG("Inotify was canceled (shutdown?)"); 51 return; 52 } 53 if (ec) 54 { 55 BMCWEB_LOG_ERROR("Callback Error: {}", ec.message()); 56 return; 57 } 58 59 BMCWEB_LOG_DEBUG("reading {} via inotify", bytesTransferred); 60 61 std::size_t index = 0; 62 while ((index + iEventSize) <= bytesTransferred) 63 { 64 struct inotify_event event 65 {}; 66 std::memcpy(&event, &readBuffer[index], iEventSize); 67 if (event.wd == dirWatchDesc) 68 { 69 if ((event.len == 0) || 70 (index + iEventSize + event.len > bytesTransferred)) 71 { 72 index += (iEventSize + event.len); 73 continue; 74 } 75 76 std::string fileName(&readBuffer[index + iEventSize]); 77 if (fileName != "redfish") 78 { 79 index += (iEventSize + event.len); 80 continue; 81 } 82 83 BMCWEB_LOG_DEBUG( 84 "Redfish log file created/deleted. event.name: {}", 85 fileName); 86 if (event.mask == IN_CREATE) 87 { 88 if (fileWatchDesc != -1) 89 { 90 BMCWEB_LOG_DEBUG( 91 "Remove and Add inotify watcher on " 92 "redfish event log file"); 93 // Remove existing inotify watcher and add 94 // with new redfish event log file. 95 inotify_rm_watch(inotifyFd, fileWatchDesc); 96 fileWatchDesc = -1; 97 } 98 99 fileWatchDesc = inotify_add_watch( 100 inotifyFd, redfishEventLogFile, IN_MODIFY); 101 if (fileWatchDesc == -1) 102 { 103 BMCWEB_LOG_ERROR("inotify_add_watch failed for " 104 "redfish log file."); 105 return; 106 } 107 108 EventServiceManager::getInstance() 109 .resetRedfishFilePosition(); 110 EventServiceManager::getInstance() 111 .readEventLogsFromFile(); 112 } 113 else if ((event.mask == IN_DELETE) || 114 (event.mask == IN_MOVED_TO)) 115 { 116 if (fileWatchDesc != -1) 117 { 118 inotify_rm_watch(inotifyFd, fileWatchDesc); 119 fileWatchDesc = -1; 120 } 121 } 122 } 123 else if (event.wd == fileWatchDesc) 124 { 125 if (event.mask == IN_MODIFY) 126 { 127 EventServiceManager::getInstance() 128 .readEventLogsFromFile(); 129 } 130 } 131 index += (iEventSize + event.len); 132 } 133 134 watchRedfishEventLogFile(); 135 }); 136 } 137 138 int startEventLogMonitor(boost::asio::io_context& ioc) 139 { 140 BMCWEB_LOG_DEBUG("starting Event Log Monitor"); 141 142 inotifyConn.emplace(ioc); 143 inotifyFd = inotify_init1(IN_NONBLOCK); 144 if (inotifyFd == -1) 145 { 146 BMCWEB_LOG_ERROR("inotify_init1 failed."); 147 return -1; 148 } 149 150 // Add watch on directory to handle redfish event log file 151 // create/delete. 152 dirWatchDesc = inotify_add_watch(inotifyFd, redfishEventLogDir, 153 IN_CREATE | IN_MOVED_TO | IN_DELETE); 154 if (dirWatchDesc == -1) 155 { 156 BMCWEB_LOG_ERROR("inotify_add_watch failed for event log directory."); 157 return -1; 158 } 159 160 // Watch redfish event log file for modifications. 161 fileWatchDesc = 162 inotify_add_watch(inotifyFd, redfishEventLogFile, IN_MODIFY); 163 if (fileWatchDesc == -1) 164 { 165 BMCWEB_LOG_ERROR("inotify_add_watch failed for redfish log file."); 166 // Don't return error if file not exist. 167 // Watch on directory will handle create/delete of file. 168 } 169 170 // monitor redfish event log file 171 inotifyConn->assign(inotifyFd); 172 watchRedfishEventLogFile(); 173 174 return 0; 175 } 176 177 void stopEventLogMonitor() 178 { 179 inotifyConn.reset(); 180 } 181 } // namespace redfish 182