xref: /openbmc/phosphor-bmc-code-mgmt/bmc/sync_watch.cpp (revision cab87e9cdeeb3e166d6d577511f6be4dc7721aca)
1*cab87e9cSJagpal Singh Gill #include "config.h"
2*cab87e9cSJagpal Singh Gill 
3*cab87e9cSJagpal Singh Gill #include "sync_watch.hpp"
4*cab87e9cSJagpal Singh Gill 
5*cab87e9cSJagpal Singh Gill #include <sys/inotify.h>
6*cab87e9cSJagpal Singh Gill #include <unistd.h>
7*cab87e9cSJagpal Singh Gill 
8*cab87e9cSJagpal Singh Gill #include <phosphor-logging/lg2.hpp>
9*cab87e9cSJagpal Singh Gill 
10*cab87e9cSJagpal Singh Gill #include <filesystem>
11*cab87e9cSJagpal Singh Gill #include <fstream>
12*cab87e9cSJagpal Singh Gill #include <system_error>
13*cab87e9cSJagpal Singh Gill 
14*cab87e9cSJagpal Singh Gill namespace phosphor
15*cab87e9cSJagpal Singh Gill {
16*cab87e9cSJagpal Singh Gill namespace software
17*cab87e9cSJagpal Singh Gill {
18*cab87e9cSJagpal Singh Gill namespace manager
19*cab87e9cSJagpal Singh Gill {
20*cab87e9cSJagpal Singh Gill 
21*cab87e9cSJagpal Singh Gill PHOSPHOR_LOG2_USING;
22*cab87e9cSJagpal Singh Gill 
addInotifyWatch(const fs::path & path)23*cab87e9cSJagpal Singh Gill void SyncWatch::addInotifyWatch(const fs::path& path)
24*cab87e9cSJagpal Singh Gill {
25*cab87e9cSJagpal Singh Gill     auto wd =
26*cab87e9cSJagpal Singh Gill         inotify_add_watch(inotifyFd, path.c_str(), IN_CLOSE_WRITE | IN_DELETE);
27*cab87e9cSJagpal Singh Gill     if (-1 == wd)
28*cab87e9cSJagpal Singh Gill     {
29*cab87e9cSJagpal Singh Gill         error("inotify_add_watch on {PATH} failed: {ERRNO}", "ERRNO", errno,
30*cab87e9cSJagpal Singh Gill               "PATH", path);
31*cab87e9cSJagpal Singh Gill         return;
32*cab87e9cSJagpal Singh Gill     }
33*cab87e9cSJagpal Singh Gill 
34*cab87e9cSJagpal Singh Gill     fileMap[wd] = fs::path(path);
35*cab87e9cSJagpal Singh Gill }
36*cab87e9cSJagpal Singh Gill 
SyncWatch(sd_event & loop,std::function<int (int,fs::path &)> syncCallback)37*cab87e9cSJagpal Singh Gill SyncWatch::SyncWatch(sd_event& loop,
38*cab87e9cSJagpal Singh Gill                      std::function<int(int, fs::path&)> syncCallback) :
39*cab87e9cSJagpal Singh Gill     inotifyFd(-1), syncCallback(std::move(syncCallback))
40*cab87e9cSJagpal Singh Gill {
41*cab87e9cSJagpal Singh Gill     auto fd = inotify_init1(IN_NONBLOCK);
42*cab87e9cSJagpal Singh Gill     if (-1 == fd)
43*cab87e9cSJagpal Singh Gill     {
44*cab87e9cSJagpal Singh Gill         error("inotify_init1 failed: {ERRNO}", "ERRNO", errno);
45*cab87e9cSJagpal Singh Gill         return;
46*cab87e9cSJagpal Singh Gill     }
47*cab87e9cSJagpal Singh Gill     inotifyFd = fd;
48*cab87e9cSJagpal Singh Gill 
49*cab87e9cSJagpal Singh Gill     auto rc = sd_event_add_io(&loop, nullptr, fd, EPOLLIN, callback, this);
50*cab87e9cSJagpal Singh Gill     if (0 > rc)
51*cab87e9cSJagpal Singh Gill     {
52*cab87e9cSJagpal Singh Gill         error("failed to add to event loop: {RC}", "RC", rc);
53*cab87e9cSJagpal Singh Gill         return;
54*cab87e9cSJagpal Singh Gill     }
55*cab87e9cSJagpal Singh Gill 
56*cab87e9cSJagpal Singh Gill     std::error_code ec;
57*cab87e9cSJagpal Singh Gill     auto syncfile = fs::path(SYNC_LIST_DIR_PATH) / SYNC_LIST_FILE_NAME;
58*cab87e9cSJagpal Singh Gill     if (fs::exists(syncfile, ec))
59*cab87e9cSJagpal Singh Gill     {
60*cab87e9cSJagpal Singh Gill         std::string line;
61*cab87e9cSJagpal Singh Gill         std::ifstream file(syncfile.c_str());
62*cab87e9cSJagpal Singh Gill         while (std::getline(file, line))
63*cab87e9cSJagpal Singh Gill         {
64*cab87e9cSJagpal Singh Gill             addInotifyWatch(line);
65*cab87e9cSJagpal Singh Gill         }
66*cab87e9cSJagpal Singh Gill     }
67*cab87e9cSJagpal Singh Gill }
68*cab87e9cSJagpal Singh Gill 
~SyncWatch()69*cab87e9cSJagpal Singh Gill SyncWatch::~SyncWatch()
70*cab87e9cSJagpal Singh Gill {
71*cab87e9cSJagpal Singh Gill     if (inotifyFd != -1)
72*cab87e9cSJagpal Singh Gill     {
73*cab87e9cSJagpal Singh Gill         close(inotifyFd);
74*cab87e9cSJagpal Singh Gill     }
75*cab87e9cSJagpal Singh Gill }
76*cab87e9cSJagpal Singh Gill 
callback(sd_event_source *,int fd,uint32_t revents,void * userdata)77*cab87e9cSJagpal Singh Gill int SyncWatch::callback(sd_event_source* /* s */, int fd, uint32_t revents,
78*cab87e9cSJagpal Singh Gill                         void* userdata)
79*cab87e9cSJagpal Singh Gill {
80*cab87e9cSJagpal Singh Gill     if (!(revents & EPOLLIN))
81*cab87e9cSJagpal Singh Gill     {
82*cab87e9cSJagpal Singh Gill         return 0;
83*cab87e9cSJagpal Singh Gill     }
84*cab87e9cSJagpal Singh Gill 
85*cab87e9cSJagpal Singh Gill     constexpr auto maxBytes = 1024;
86*cab87e9cSJagpal Singh Gill     uint8_t buffer[maxBytes];
87*cab87e9cSJagpal Singh Gill     auto bytes = read(fd, buffer, maxBytes);
88*cab87e9cSJagpal Singh Gill     if (0 > bytes)
89*cab87e9cSJagpal Singh Gill     {
90*cab87e9cSJagpal Singh Gill         return 0;
91*cab87e9cSJagpal Singh Gill     }
92*cab87e9cSJagpal Singh Gill 
93*cab87e9cSJagpal Singh Gill     auto syncWatch = static_cast<SyncWatch*>(userdata);
94*cab87e9cSJagpal Singh Gill     auto offset = 0;
95*cab87e9cSJagpal Singh Gill     while (offset < bytes)
96*cab87e9cSJagpal Singh Gill     {
97*cab87e9cSJagpal Singh Gill         auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
98*cab87e9cSJagpal Singh Gill 
99*cab87e9cSJagpal Singh Gill         // Watch was removed, re-add it if file still exists.
100*cab87e9cSJagpal Singh Gill         if (event->mask & IN_IGNORED)
101*cab87e9cSJagpal Singh Gill         {
102*cab87e9cSJagpal Singh Gill             std::error_code ec;
103*cab87e9cSJagpal Singh Gill             if (fs::exists(syncWatch->fileMap[event->wd], ec))
104*cab87e9cSJagpal Singh Gill             {
105*cab87e9cSJagpal Singh Gill                 syncWatch->addInotifyWatch(syncWatch->fileMap[event->wd]);
106*cab87e9cSJagpal Singh Gill             }
107*cab87e9cSJagpal Singh Gill             else
108*cab87e9cSJagpal Singh Gill             {
109*cab87e9cSJagpal Singh Gill                 info("The inotify watch on {PATH} was removed", "PATH",
110*cab87e9cSJagpal Singh Gill                      syncWatch->fileMap[event->wd]);
111*cab87e9cSJagpal Singh Gill             }
112*cab87e9cSJagpal Singh Gill             return 0;
113*cab87e9cSJagpal Singh Gill         }
114*cab87e9cSJagpal Singh Gill 
115*cab87e9cSJagpal Singh Gill         // fileMap<wd, path>
116*cab87e9cSJagpal Singh Gill         auto rc = syncWatch->syncCallback(static_cast<int>(event->mask),
117*cab87e9cSJagpal Singh Gill                                           syncWatch->fileMap[event->wd]);
118*cab87e9cSJagpal Singh Gill         if (rc)
119*cab87e9cSJagpal Singh Gill         {
120*cab87e9cSJagpal Singh Gill             return rc;
121*cab87e9cSJagpal Singh Gill         }
122*cab87e9cSJagpal Singh Gill 
123*cab87e9cSJagpal Singh Gill         offset += offsetof(inotify_event, name) + event->len;
124*cab87e9cSJagpal Singh Gill     }
125*cab87e9cSJagpal Singh Gill 
126*cab87e9cSJagpal Singh Gill     return 0;
127*cab87e9cSJagpal Singh Gill }
128*cab87e9cSJagpal Singh Gill 
129*cab87e9cSJagpal Singh Gill } // namespace manager
130*cab87e9cSJagpal Singh Gill } // namespace software
131*cab87e9cSJagpal Singh Gill } // namespace phosphor
132