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