1cb65ffceSJayanth Othayoth #include "watch.hpp"
2671fc7f3SJayanth Othayoth
3671fc7f3SJayanth Othayoth #include "xyz/openbmc_project/Common/error.hpp"
4cb65ffceSJayanth Othayoth
5cb65ffceSJayanth Othayoth #include <phosphor-logging/elog-errors.hpp>
6d1f670feSDhruvaraj Subhashchandran #include <phosphor-logging/lg2.hpp>
7671fc7f3SJayanth Othayoth
8ceb3e762SJayanth Othayoth #include <span>
9ceb3e762SJayanth Othayoth
10671fc7f3SJayanth Othayoth namespace phosphor
11671fc7f3SJayanth Othayoth {
12671fc7f3SJayanth Othayoth namespace dump
13671fc7f3SJayanth Othayoth {
14671fc7f3SJayanth Othayoth namespace inotify
15671fc7f3SJayanth Othayoth {
16671fc7f3SJayanth Othayoth
17671fc7f3SJayanth Othayoth using namespace std::string_literals;
18671fc7f3SJayanth Othayoth using namespace phosphor::logging;
19671fc7f3SJayanth Othayoth using namespace sdbusplus::xyz::openbmc_project::Common::Error;
20671fc7f3SJayanth Othayoth
~Watch()21671fc7f3SJayanth Othayoth Watch::~Watch()
22671fc7f3SJayanth Othayoth {
23671fc7f3SJayanth Othayoth if ((fd() >= 0) && (wd >= 0))
24671fc7f3SJayanth Othayoth {
25*fa6a47bfSJian Zhang sd_event_source_unref(source);
26671fc7f3SJayanth Othayoth inotify_rm_watch(fd(), wd);
27671fc7f3SJayanth Othayoth }
28671fc7f3SJayanth Othayoth }
29671fc7f3SJayanth Othayoth
Watch(const EventPtr & eventObj,const int flags,const uint32_t mask,const uint32_t events,const std::filesystem::path & path,UserType userFunc)30cb65ffceSJayanth Othayoth Watch::Watch(const EventPtr& eventObj, const int flags, const uint32_t mask,
313fc6df48SJayanth Othayoth const uint32_t events, const std::filesystem::path& path,
323fc6df48SJayanth Othayoth UserType userFunc) :
33973b291eSPatrick Williams flags(flags), mask(mask), events(events), path(path), fd(inotifyInit()),
34671fc7f3SJayanth Othayoth userFunc(userFunc)
35671fc7f3SJayanth Othayoth {
36671fc7f3SJayanth Othayoth // Check if watch DIR exists.
373fc6df48SJayanth Othayoth if (!std::filesystem::is_directory(path))
38671fc7f3SJayanth Othayoth {
39d1f670feSDhruvaraj Subhashchandran lg2::error("Watch directory doesn't exist, DIR: {DIRECTORY}",
40d1f670feSDhruvaraj Subhashchandran "DIRECTORY", path);
41671fc7f3SJayanth Othayoth elog<InternalFailure>();
42671fc7f3SJayanth Othayoth }
43671fc7f3SJayanth Othayoth
44671fc7f3SJayanth Othayoth wd = inotify_add_watch(fd(), path.c_str(), mask);
45671fc7f3SJayanth Othayoth if (-1 == wd)
46671fc7f3SJayanth Othayoth {
47671fc7f3SJayanth Othayoth auto error = errno;
48d1f670feSDhruvaraj Subhashchandran lg2::error(
49d1f670feSDhruvaraj Subhashchandran "Error occurred during the inotify_add_watch call, errno: {ERRNO}",
50d1f670feSDhruvaraj Subhashchandran "ERRNO", error);
51671fc7f3SJayanth Othayoth elog<InternalFailure>();
52671fc7f3SJayanth Othayoth }
53671fc7f3SJayanth Othayoth
54973b291eSPatrick Williams auto rc =
55*fa6a47bfSJian Zhang sd_event_add_io(eventObj.get(), &source, fd(), events, callback, this);
56671fc7f3SJayanth Othayoth if (0 > rc)
57671fc7f3SJayanth Othayoth {
58671fc7f3SJayanth Othayoth // Failed to add to event loop
59d1f670feSDhruvaraj Subhashchandran lg2::error("Error occurred during the sd_event_add_io call, rc: {RC}",
60d1f670feSDhruvaraj Subhashchandran "RC", rc);
61671fc7f3SJayanth Othayoth elog<InternalFailure>();
62671fc7f3SJayanth Othayoth }
63671fc7f3SJayanth Othayoth }
64671fc7f3SJayanth Othayoth
inotifyInit()65671fc7f3SJayanth Othayoth int Watch::inotifyInit()
66671fc7f3SJayanth Othayoth {
67671fc7f3SJayanth Othayoth auto fd = inotify_init1(flags);
68671fc7f3SJayanth Othayoth
69671fc7f3SJayanth Othayoth if (-1 == fd)
70671fc7f3SJayanth Othayoth {
71671fc7f3SJayanth Othayoth auto error = errno;
72d1f670feSDhruvaraj Subhashchandran lg2::error("Error occurred during the inotify_init1, errno: {ERRNO}",
73d1f670feSDhruvaraj Subhashchandran "ERRNO", error);
74671fc7f3SJayanth Othayoth elog<InternalFailure>();
75671fc7f3SJayanth Othayoth }
76671fc7f3SJayanth Othayoth
77671fc7f3SJayanth Othayoth return fd;
78671fc7f3SJayanth Othayoth }
79671fc7f3SJayanth Othayoth
callback(sd_event_source *,int fd,uint32_t revents,void * userdata)80bb410df7SRamesh Iyyar int Watch::callback(sd_event_source*, int fd, uint32_t revents, void* userdata)
81671fc7f3SJayanth Othayoth {
82764d1b22SJayanth Othayoth auto userData = static_cast<Watch*>(userdata);
83764d1b22SJayanth Othayoth
84b913e078SJayanth Othayoth if ((revents & userData->events) == 0U)
85671fc7f3SJayanth Othayoth {
86671fc7f3SJayanth Othayoth return 0;
87671fc7f3SJayanth Othayoth }
88671fc7f3SJayanth Othayoth
89671fc7f3SJayanth Othayoth // Maximum inotify events supported in the buffer
90671fc7f3SJayanth Othayoth constexpr auto maxBytes = sizeof(struct inotify_event) + NAME_MAX + 1;
91671fc7f3SJayanth Othayoth uint8_t buffer[maxBytes];
92671fc7f3SJayanth Othayoth
93ceb3e762SJayanth Othayoth std::span<char> bufferSpan(reinterpret_cast<char*>(buffer), maxBytes);
94ceb3e762SJayanth Othayoth auto bytes = read(fd, bufferSpan.data(), bufferSpan.size());
95671fc7f3SJayanth Othayoth if (0 > bytes)
96671fc7f3SJayanth Othayoth {
97671fc7f3SJayanth Othayoth // Failed to read inotify event
98671fc7f3SJayanth Othayoth // Report error and return
99671fc7f3SJayanth Othayoth auto error = errno;
100d1f670feSDhruvaraj Subhashchandran lg2::error("Error occurred during the read, errno: {ERRNO}", "ERRNO",
101d1f670feSDhruvaraj Subhashchandran error);
102671fc7f3SJayanth Othayoth report<InternalFailure>();
103671fc7f3SJayanth Othayoth return 0;
104671fc7f3SJayanth Othayoth }
105671fc7f3SJayanth Othayoth
106671fc7f3SJayanth Othayoth auto offset = 0;
107671fc7f3SJayanth Othayoth
108671fc7f3SJayanth Othayoth UserMap userMap;
109671fc7f3SJayanth Othayoth
110671fc7f3SJayanth Othayoth while (offset < bytes)
111671fc7f3SJayanth Othayoth {
112671fc7f3SJayanth Othayoth auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
113764d1b22SJayanth Othayoth auto mask = event->mask & userData->mask;
114671fc7f3SJayanth Othayoth
115b913e078SJayanth Othayoth if (mask != 0U)
116671fc7f3SJayanth Othayoth {
117cb65ffceSJayanth Othayoth userMap.emplace((userData->path / event->name), mask);
118671fc7f3SJayanth Othayoth }
119671fc7f3SJayanth Othayoth
120671fc7f3SJayanth Othayoth offset += offsetof(inotify_event, name) + event->len;
121671fc7f3SJayanth Othayoth }
122671fc7f3SJayanth Othayoth
123671fc7f3SJayanth Othayoth // Call user call back function in case valid data in the map
124671fc7f3SJayanth Othayoth if (!userMap.empty())
125671fc7f3SJayanth Othayoth {
126764d1b22SJayanth Othayoth userData->userFunc(userMap);
127671fc7f3SJayanth Othayoth }
128671fc7f3SJayanth Othayoth
129671fc7f3SJayanth Othayoth return 0;
130671fc7f3SJayanth Othayoth }
131671fc7f3SJayanth Othayoth
132671fc7f3SJayanth Othayoth } // namespace inotify
133671fc7f3SJayanth Othayoth } // namespace dump
134671fc7f3SJayanth Othayoth } // namespace phosphor
135