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