12185ddeaSEd Tanous #include "filesystem_log_watcher.hpp" 22185ddeaSEd Tanous 32185ddeaSEd Tanous #include "event_service_manager.hpp" 42185ddeaSEd Tanous #include "logging.hpp" 52185ddeaSEd Tanous 62185ddeaSEd Tanous #include <sys/inotify.h> 72185ddeaSEd Tanous 82185ddeaSEd Tanous #include <boost/asio/buffer.hpp> 92185ddeaSEd Tanous #include <boost/asio/error.hpp> 102185ddeaSEd Tanous #include <boost/asio/io_context.hpp> 112185ddeaSEd Tanous #include <boost/asio/posix/stream_descriptor.hpp> 122185ddeaSEd Tanous 132185ddeaSEd Tanous #include <array> 142185ddeaSEd Tanous #include <cstddef> 152185ddeaSEd Tanous #include <cstring> 162185ddeaSEd Tanous #include <optional> 172185ddeaSEd Tanous #include <string> 182185ddeaSEd Tanous 192185ddeaSEd Tanous namespace redfish 202185ddeaSEd Tanous { 212185ddeaSEd Tanous 222185ddeaSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 232185ddeaSEd Tanous static std::optional<boost::asio::posix::stream_descriptor> inotifyConn; 242185ddeaSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 252185ddeaSEd Tanous static int inotifyFd = -1; 262185ddeaSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 272185ddeaSEd Tanous static int dirWatchDesc = -1; 282185ddeaSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 292185ddeaSEd Tanous static int fileWatchDesc = -1; 302185ddeaSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) 312185ddeaSEd Tanous static std::array<char, 1024> readBuffer{}; 322185ddeaSEd Tanous 332185ddeaSEd Tanous static constexpr const char* redfishEventLogDir = "/var/log"; 342185ddeaSEd Tanous static constexpr const size_t iEventSize = sizeof(inotify_event); 352185ddeaSEd Tanous 36*ea20bc66SEd Tanous static void watchRedfishEventLogFile(); 372185ddeaSEd Tanous 38*ea20bc66SEd Tanous static void onINotify(const boost::system::error_code& ec, 39*ea20bc66SEd Tanous std::size_t bytesTransferred) 40*ea20bc66SEd Tanous { 412185ddeaSEd Tanous if (ec == boost::asio::error::operation_aborted) 422185ddeaSEd Tanous { 432185ddeaSEd Tanous BMCWEB_LOG_DEBUG("Inotify was canceled (shutdown?)"); 442185ddeaSEd Tanous return; 452185ddeaSEd Tanous } 462185ddeaSEd Tanous if (ec) 472185ddeaSEd Tanous { 482185ddeaSEd Tanous BMCWEB_LOG_ERROR("Callback Error: {}", ec.message()); 492185ddeaSEd Tanous return; 502185ddeaSEd Tanous } 512185ddeaSEd Tanous 522185ddeaSEd Tanous BMCWEB_LOG_DEBUG("reading {} via inotify", bytesTransferred); 532185ddeaSEd Tanous 542185ddeaSEd Tanous std::size_t index = 0; 552185ddeaSEd Tanous while ((index + iEventSize) <= bytesTransferred) 562185ddeaSEd Tanous { 572185ddeaSEd Tanous struct inotify_event event 582185ddeaSEd Tanous {}; 592185ddeaSEd Tanous std::memcpy(&event, &readBuffer[index], iEventSize); 602185ddeaSEd Tanous if (event.wd == dirWatchDesc) 612185ddeaSEd Tanous { 622185ddeaSEd Tanous if ((event.len == 0) || 632185ddeaSEd Tanous (index + iEventSize + event.len > bytesTransferred)) 642185ddeaSEd Tanous { 652185ddeaSEd Tanous index += (iEventSize + event.len); 662185ddeaSEd Tanous continue; 672185ddeaSEd Tanous } 682185ddeaSEd Tanous 692185ddeaSEd Tanous std::string fileName(&readBuffer[index + iEventSize]); 702185ddeaSEd Tanous if (fileName != "redfish") 712185ddeaSEd Tanous { 722185ddeaSEd Tanous index += (iEventSize + event.len); 732185ddeaSEd Tanous continue; 742185ddeaSEd Tanous } 752185ddeaSEd Tanous 76*ea20bc66SEd Tanous BMCWEB_LOG_DEBUG("Redfish log file created/deleted. event.name: {}", 772185ddeaSEd Tanous fileName); 782185ddeaSEd Tanous if (event.mask == IN_CREATE) 792185ddeaSEd Tanous { 802185ddeaSEd Tanous if (fileWatchDesc != -1) 812185ddeaSEd Tanous { 82*ea20bc66SEd Tanous BMCWEB_LOG_DEBUG("Remove and Add inotify watcher on " 832185ddeaSEd Tanous "redfish event log file"); 842185ddeaSEd Tanous // Remove existing inotify watcher and add 852185ddeaSEd Tanous // with new redfish event log file. 862185ddeaSEd Tanous inotify_rm_watch(inotifyFd, fileWatchDesc); 872185ddeaSEd Tanous fileWatchDesc = -1; 882185ddeaSEd Tanous } 892185ddeaSEd Tanous 902185ddeaSEd Tanous fileWatchDesc = inotify_add_watch( 912185ddeaSEd Tanous inotifyFd, redfishEventLogFile, IN_MODIFY); 922185ddeaSEd Tanous if (fileWatchDesc == -1) 932185ddeaSEd Tanous { 942185ddeaSEd Tanous BMCWEB_LOG_ERROR("inotify_add_watch failed for " 952185ddeaSEd Tanous "redfish log file."); 962185ddeaSEd Tanous return; 972185ddeaSEd Tanous } 982185ddeaSEd Tanous 99*ea20bc66SEd Tanous EventServiceManager::getInstance().resetRedfishFilePosition(); 100*ea20bc66SEd Tanous EventServiceManager::getInstance().readEventLogsFromFile(); 1012185ddeaSEd Tanous } 102*ea20bc66SEd Tanous else if ((event.mask == IN_DELETE) || (event.mask == IN_MOVED_TO)) 1032185ddeaSEd Tanous { 1042185ddeaSEd Tanous if (fileWatchDesc != -1) 1052185ddeaSEd Tanous { 1062185ddeaSEd Tanous inotify_rm_watch(inotifyFd, fileWatchDesc); 1072185ddeaSEd Tanous fileWatchDesc = -1; 1082185ddeaSEd Tanous } 1092185ddeaSEd Tanous } 1102185ddeaSEd Tanous } 1112185ddeaSEd Tanous else if (event.wd == fileWatchDesc) 1122185ddeaSEd Tanous { 1132185ddeaSEd Tanous if (event.mask == IN_MODIFY) 1142185ddeaSEd Tanous { 115*ea20bc66SEd Tanous EventServiceManager::getInstance().readEventLogsFromFile(); 1162185ddeaSEd Tanous } 1172185ddeaSEd Tanous } 1182185ddeaSEd Tanous index += (iEventSize + event.len); 1192185ddeaSEd Tanous } 1202185ddeaSEd Tanous 1212185ddeaSEd Tanous watchRedfishEventLogFile(); 122*ea20bc66SEd Tanous } 123*ea20bc66SEd Tanous 124*ea20bc66SEd Tanous static void watchRedfishEventLogFile() 125*ea20bc66SEd Tanous { 126*ea20bc66SEd Tanous if (!inotifyConn) 127*ea20bc66SEd Tanous { 128*ea20bc66SEd Tanous BMCWEB_LOG_ERROR("inotify Connection is not present"); 129*ea20bc66SEd Tanous return; 130*ea20bc66SEd Tanous } 131*ea20bc66SEd Tanous 132*ea20bc66SEd Tanous inotifyConn->async_read_some(boost::asio::buffer(readBuffer), onINotify); 1332185ddeaSEd Tanous } 1342185ddeaSEd Tanous 1352185ddeaSEd Tanous int startEventLogMonitor(boost::asio::io_context& ioc) 1362185ddeaSEd Tanous { 1372185ddeaSEd Tanous BMCWEB_LOG_DEBUG("starting Event Log Monitor"); 1382185ddeaSEd Tanous 1392185ddeaSEd Tanous inotifyConn.emplace(ioc); 1402185ddeaSEd Tanous inotifyFd = inotify_init1(IN_NONBLOCK); 1412185ddeaSEd Tanous if (inotifyFd == -1) 1422185ddeaSEd Tanous { 1432185ddeaSEd Tanous BMCWEB_LOG_ERROR("inotify_init1 failed."); 1442185ddeaSEd Tanous return -1; 1452185ddeaSEd Tanous } 1462185ddeaSEd Tanous 1472185ddeaSEd Tanous // Add watch on directory to handle redfish event log file 1482185ddeaSEd Tanous // create/delete. 1492185ddeaSEd Tanous dirWatchDesc = inotify_add_watch(inotifyFd, redfishEventLogDir, 1502185ddeaSEd Tanous IN_CREATE | IN_MOVED_TO | IN_DELETE); 1512185ddeaSEd Tanous if (dirWatchDesc == -1) 1522185ddeaSEd Tanous { 1532185ddeaSEd Tanous BMCWEB_LOG_ERROR("inotify_add_watch failed for event log directory."); 1542185ddeaSEd Tanous return -1; 1552185ddeaSEd Tanous } 1562185ddeaSEd Tanous 1572185ddeaSEd Tanous // Watch redfish event log file for modifications. 1582185ddeaSEd Tanous fileWatchDesc = 1592185ddeaSEd Tanous inotify_add_watch(inotifyFd, redfishEventLogFile, IN_MODIFY); 1602185ddeaSEd Tanous if (fileWatchDesc == -1) 1612185ddeaSEd Tanous { 1622185ddeaSEd Tanous BMCWEB_LOG_ERROR("inotify_add_watch failed for redfish log file."); 1632185ddeaSEd Tanous // Don't return error if file not exist. 1642185ddeaSEd Tanous // Watch on directory will handle create/delete of file. 1652185ddeaSEd Tanous } 1662185ddeaSEd Tanous 1672185ddeaSEd Tanous // monitor redfish event log file 1682185ddeaSEd Tanous inotifyConn->assign(inotifyFd); 1692185ddeaSEd Tanous watchRedfishEventLogFile(); 1702185ddeaSEd Tanous 1712185ddeaSEd Tanous return 0; 1722185ddeaSEd Tanous } 1732185ddeaSEd Tanous 1742185ddeaSEd Tanous void stopEventLogMonitor() 1752185ddeaSEd Tanous { 1762185ddeaSEd Tanous inotifyConn.reset(); 1772185ddeaSEd Tanous } 1782185ddeaSEd Tanous } // namespace redfish 179