xref: /openbmc/phosphor-debug-collector/watch.cpp (revision e57ee7623b4e4a5e6987879548ce4f201eabe685)
1 #include "watch.hpp"
2 
3 #include "xyz/openbmc_project/Common/error.hpp"
4 
5 #include <phosphor-logging/elog-errors.hpp>
6 
7 namespace phosphor
8 {
9 namespace dump
10 {
11 namespace inotify
12 {
13 
14 using namespace std::string_literals;
15 using namespace phosphor::logging;
16 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
17 
18 Watch::~Watch()
19 {
20     if ((fd() >= 0) && (wd >= 0))
21     {
22         inotify_rm_watch(fd(), wd);
23     }
24 }
25 
26 Watch::Watch(const EventPtr& eventObj, const int flags, const uint32_t mask,
27              const uint32_t events, const fs::path& path, UserType userFunc) :
28     flags(flags),
29     mask(mask), events(events), path(path), fd(inotifyInit()),
30     userFunc(userFunc)
31 {
32     // Check if watch DIR exists.
33     if (!fs::is_directory(path))
34     {
35         log<level::ERR>("Watch directory doesn't exist",
36                         entry("DIR=%s", path.c_str()));
37         elog<InternalFailure>();
38     }
39 
40     wd = inotify_add_watch(fd(), path.c_str(), mask);
41     if (-1 == wd)
42     {
43         auto error = errno;
44         log<level::ERR>("Error occurred during the inotify_add_watch call",
45                         entry("ERRNO=%d", error));
46         elog<InternalFailure>();
47     }
48 
49     auto rc =
50         sd_event_add_io(eventObj.get(), nullptr, fd(), events, callback, this);
51     if (0 > rc)
52     {
53         // Failed to add to event loop
54         log<level::ERR>("Error occurred during the sd_event_add_io call",
55                         entry("RC=%d", rc));
56         elog<InternalFailure>();
57     }
58 }
59 
60 int Watch::inotifyInit()
61 {
62     auto fd = inotify_init1(flags);
63 
64     if (-1 == fd)
65     {
66         auto error = errno;
67         log<level::ERR>("Error occurred during the inotify_init1",
68                         entry("ERRNO=%d", error));
69         elog<InternalFailure>();
70     }
71 
72     return fd;
73 }
74 
75 int Watch::callback(sd_event_source* s, int fd, uint32_t revents,
76                     void* userdata)
77 {
78     auto userData = static_cast<Watch*>(userdata);
79 
80     if (!(revents & userData->events))
81     {
82         return 0;
83     }
84 
85     // Maximum inotify events supported in the buffer
86     constexpr auto maxBytes = sizeof(struct inotify_event) + NAME_MAX + 1;
87     uint8_t buffer[maxBytes];
88 
89     auto bytes = read(fd, buffer, maxBytes);
90     if (0 > bytes)
91     {
92         // Failed to read inotify event
93         // Report error and return
94         auto error = errno;
95         log<level::ERR>("Error occurred during the read",
96                         entry("ERRNO=%d", error));
97         report<InternalFailure>();
98         return 0;
99     }
100 
101     auto offset = 0;
102 
103     UserMap userMap;
104 
105     while (offset < bytes)
106     {
107         auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
108         auto mask = event->mask & userData->mask;
109 
110         if (mask)
111         {
112             userMap.emplace((userData->path / event->name), mask);
113         }
114 
115         offset += offsetof(inotify_event, name) + event->len;
116     }
117 
118     // Call user call back function in case valid data in the map
119     if (!userMap.empty())
120     {
121         userData->userFunc(userMap);
122     }
123 
124     return 0;
125 }
126 
127 } // namespace inotify
128 } // namespace dump
129 } // namespace phosphor
130