blob: 0efe300082f0898e7a9e3bd8d54197ea30ece82f [file] [log] [blame]
Vishwanatha Subbannaca4ce1b2017-10-16 23:17:18 +05301#include "watch.hpp"
2
Vishwanatha Subbannaca4ce1b2017-10-16 23:17:18 +05303#include <errno.h>
Patrick Venture189d44e2018-07-09 12:30:59 -07004#include <sys/inotify.h>
5
6#include <phosphor-logging/elog-errors.hpp>
7#include <phosphor-logging/log.hpp>
8#include <xyz/openbmc_project/Common/error.hpp>
Vishwanatha Subbannaca4ce1b2017-10-16 23:17:18 +05309
10namespace phosphor
11{
12namespace network
13{
14namespace inotify
15{
16
17using namespace phosphor::logging;
18using namespace sdbusplus::xyz::openbmc_project::Common::Error;
19
Gunnar Mills57d9c502018-09-14 14:42:34 -050020Watch::Watch(phosphor::network::EventPtr& eventPtr, fs::path path,
21 UserCallBack userFunc, int flags, uint32_t mask, uint32_t events) :
Vishwanatha Subbannaca4ce1b2017-10-16 23:17:18 +053022 path(path),
Gunnar Mills57d9c502018-09-14 14:42:34 -050023 userFunc(userFunc), flags(flags), mask(mask), events(events),
Vishwanatha Subbannaca4ce1b2017-10-16 23:17:18 +053024 fd(inotifyInit())
25{
26 // Check if watch file exists
27 // This is supposed to be there always
28 if (!fs::is_regular_file(path))
29 {
30 log<level::ERR>("Watch file doesn't exist",
31 entry("FILE=%s", path.c_str()));
32 elog<InternalFailure>();
33 }
34
35 auto dirPath = path.parent_path();
36 wd = inotify_add_watch(fd(), dirPath.c_str(), mask);
37 if (wd == -1)
38 {
39 log<level::ERR>("Error from inotify_add_watch",
40 entry("ERRNO=%d", errno));
41 elog<InternalFailure>();
42 }
43
44 // Register the fd with sd_event infrastructure and setup a
45 // callback handler to be invoked on events
Gunnar Mills57d9c502018-09-14 14:42:34 -050046 auto rc = sd_event_add_io(eventPtr.get(), nullptr, fd(), events,
47 Watch::processEvents, this);
Vishwanatha Subbannaca4ce1b2017-10-16 23:17:18 +053048 if (rc < 0)
49 {
50 // Failed to add to event loop
51 log<level::ERR>("Error registering with sd_event_add_io",
52 entry("RC=%d", rc));
53 elog<InternalFailure>();
54 }
55}
56
57int Watch::inotifyInit()
58{
59 auto fd = inotify_init1(flags);
60 if (fd < 0)
61 {
Gunnar Mills57d9c502018-09-14 14:42:34 -050062 log<level::ERR>("Error from inotify_init1", entry("ERRNO=%d", errno));
Vishwanatha Subbannaca4ce1b2017-10-16 23:17:18 +053063 elog<InternalFailure>();
64 }
65 return fd;
66}
67
Manojkiran Edaaa57fa52020-06-13 14:59:53 +053068int Watch::processEvents(sd_event_source* /*eventSource*/, int fd,
Gunnar Mills57d9c502018-09-14 14:42:34 -050069 uint32_t retEvents, void* userData)
Vishwanatha Subbannaca4ce1b2017-10-16 23:17:18 +053070{
71 auto watch = static_cast<Watch*>(userData);
72
73 // Not the ones we are interested in
74 if (!(retEvents & watch->events))
75 {
76 return 0;
77 }
78
79 // Buffer size to be used while reading events.
80 // per inotify(7), below number should be fine for reading
81 // at-least one event
82 constexpr auto maxBytes = sizeof(struct inotify_event) + NAME_MAX + 1;
83 uint8_t eventData[maxBytes]{};
84
85 auto bytes = read(fd, eventData, maxBytes);
86 if (bytes <= 0)
87 {
88 // Failed to read inotify event data
89 // Report error and return
90 log<level::ERR>("Error reading inotify event",
91 entry("ERRNO=%d", errno));
92 report<InternalFailure>();
93 return 0;
94 }
95
96 auto offset = 0;
97 auto stateFile = watch->path.filename();
98 while (offset < bytes)
99 {
100 auto event = reinterpret_cast<inotify_event*>(&eventData[offset]);
101
102 // Filter the interesting ones
103 auto mask = event->mask & watch->mask;
104 if (mask)
105 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500106 if ((event->len > 0) &&
107 (strstr(event->name, stateFile.string().c_str())))
Vishwanatha Subbannaca4ce1b2017-10-16 23:17:18 +0530108 {
109 if (watch->userFunc)
110 {
111 watch->userFunc(watch->path);
112 }
113 // Found the event of interest
114 break;
115 }
116 }
117 // Move past this entry
118 offset += offsetof(inotify_event, name) + event->len;
119 }
120 return 0;
121}
122
123} // namespace inotify
124} // namespace network
125} // namespace phosphor