blob: 9b6b6f3b2bd0975a6534e1b5e6efb7da6da97b9b [file] [log] [blame]
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -05001#include "watch.hpp"
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -05002
3#include "xyz/openbmc_project/Common/error.hpp"
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -05004
5#include <phosphor-logging/elog-errors.hpp>
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -05006#include <phosphor-logging/lg2.hpp>
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -05007
Jayanth Othayothceb3e762024-11-25 23:19:37 -06008#include <span>
9
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050010namespace phosphor
11{
12namespace dump
13{
14namespace inotify
15{
16
17using namespace std::string_literals;
18using namespace phosphor::logging;
19using namespace sdbusplus::xyz::openbmc_project::Common::Error;
20
21Watch::~Watch()
22{
23 if ((fd() >= 0) && (wd >= 0))
24 {
25 inotify_rm_watch(fd(), wd);
26 }
27}
28
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050029Watch::Watch(const EventPtr& eventObj, const int flags, const uint32_t mask,
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -050030 const uint32_t events, const std::filesystem::path& path,
31 UserType userFunc) :
Patrick Williams973b2912024-08-16 15:20:50 -040032 flags(flags), mask(mask), events(events), path(path), fd(inotifyInit()),
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050033 userFunc(userFunc)
34{
35 // Check if watch DIR exists.
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -050036 if (!std::filesystem::is_directory(path))
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050037 {
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -050038 lg2::error("Watch directory doesn't exist, DIR: {DIRECTORY}",
39 "DIRECTORY", path);
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050040 elog<InternalFailure>();
41 }
42
43 wd = inotify_add_watch(fd(), path.c_str(), mask);
44 if (-1 == wd)
45 {
46 auto error = errno;
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -050047 lg2::error(
48 "Error occurred during the inotify_add_watch call, errno: {ERRNO}",
49 "ERRNO", error);
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050050 elog<InternalFailure>();
51 }
52
Patrick Williams973b2912024-08-16 15:20:50 -040053 auto rc =
54 sd_event_add_io(eventObj.get(), nullptr, fd(), events, callback, this);
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050055 if (0 > rc)
56 {
57 // Failed to add to event loop
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -050058 lg2::error("Error occurred during the sd_event_add_io call, rc: {RC}",
59 "RC", rc);
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050060 elog<InternalFailure>();
61 }
62}
63
64int Watch::inotifyInit()
65{
66 auto fd = inotify_init1(flags);
67
68 if (-1 == fd)
69 {
70 auto error = errno;
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -050071 lg2::error("Error occurred during the inotify_init1, errno: {ERRNO}",
72 "ERRNO", error);
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050073 elog<InternalFailure>();
74 }
75
76 return fd;
77}
78
Ramesh Iyyarbb410df2020-08-03 03:13:04 -050079int Watch::callback(sd_event_source*, int fd, uint32_t revents, void* userdata)
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050080{
Jayanth Othayoth764d1b22017-07-12 19:14:02 -050081 auto userData = static_cast<Watch*>(userdata);
82
Jayanth Othayothb913e072024-11-26 01:23:20 -060083 if ((revents & userData->events) == 0U)
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050084 {
85 return 0;
86 }
87
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050088 // Maximum inotify events supported in the buffer
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050089 constexpr auto maxBytes = sizeof(struct inotify_event) + NAME_MAX + 1;
90 uint8_t buffer[maxBytes];
91
Jayanth Othayothceb3e762024-11-25 23:19:37 -060092 std::span<char> bufferSpan(reinterpret_cast<char*>(buffer), maxBytes);
93 auto bytes = read(fd, bufferSpan.data(), bufferSpan.size());
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050094 if (0 > bytes)
95 {
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -050096 // Failed to read inotify event
97 // Report error and return
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -050098 auto error = errno;
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -050099 lg2::error("Error occurred during the read, errno: {ERRNO}", "ERRNO",
100 error);
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -0500101 report<InternalFailure>();
102 return 0;
103 }
104
105 auto offset = 0;
106
107 UserMap userMap;
108
109 while (offset < bytes)
110 {
111 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500112 auto mask = event->mask & userData->mask;
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -0500113
Jayanth Othayothb913e072024-11-26 01:23:20 -0600114 if (mask != 0U)
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -0500115 {
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500116 userMap.emplace((userData->path / event->name), mask);
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -0500117 }
118
119 offset += offsetof(inotify_event, name) + event->len;
120 }
121
Jayanth Othayothcb65ffc2018-10-16 08:29:32 -0500122 // Call user call back function in case valid data in the map
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -0500123 if (!userMap.empty())
124 {
Jayanth Othayoth764d1b22017-07-12 19:14:02 -0500125 userData->userFunc(userMap);
Jayanth Othayoth671fc7f2017-06-14 08:01:41 -0500126 }
127
128 return 0;
129}
130
131} // namespace inotify
132} // namespace dump
133} // namespace phosphor