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