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