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