xref: /openbmc/phosphor-debug-collector/watch.cpp (revision fdc0c3a12d58a0694718fe4616d9d91eab97b460)
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*, int fd, uint32_t revents, void* userdata)
76 {
77     auto userData = static_cast<Watch*>(userdata);
78 
79     if (!(revents & userData->events))
80     {
81         return 0;
82     }
83 
84     // Maximum inotify events supported in the buffer
85     constexpr auto maxBytes = sizeof(struct inotify_event) + NAME_MAX + 1;
86     uint8_t buffer[maxBytes];
87 
88     auto bytes = read(fd, buffer, maxBytes);
89     if (0 > bytes)
90     {
91         // Failed to read inotify event
92         // Report error and return
93         auto error = errno;
94         log<level::ERR>("Error occurred during the read",
95                         entry("ERRNO=%d", error));
96         report<InternalFailure>();
97         return 0;
98     }
99 
100     auto offset = 0;
101 
102     UserMap userMap;
103 
104     while (offset < bytes)
105     {
106         auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
107         auto mask = event->mask & userData->mask;
108 
109         if (mask)
110         {
111             userMap.emplace((userData->path / event->name), mask);
112         }
113 
114         offset += offsetof(inotify_event, name) + event->len;
115     }
116 
117     // Call user call back function in case valid data in the map
118     if (!userMap.empty())
119     {
120         userData->userFunc(userMap);
121     }
122 
123     return 0;
124 }
125 
126 } // namespace inotify
127 } // namespace dump
128 } // namespace phosphor
129