xref: /openbmc/phosphor-debug-collector/watch.cpp (revision fa6a47bf0a4d44b6730e4a50984bd555bdb6b3f8)
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