xref: /openbmc/bmcweb/features/redfish/src/filesystem_log_watcher.cpp (revision 2185ddeac3ed0c49da6399af635f31544e382373)
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