1*ca8c7e98SJagpal Singh Gill #include "NotifyWatch.hpp"
2*ca8c7e98SJagpal Singh Gill
3*ca8c7e98SJagpal Singh Gill #include <sys/inotify.h>
4*ca8c7e98SJagpal Singh Gill #include <unistd.h>
5*ca8c7e98SJagpal Singh Gill
6*ca8c7e98SJagpal Singh Gill #include <sdbusplus/async.hpp>
7*ca8c7e98SJagpal Singh Gill
8*ca8c7e98SJagpal Singh Gill #include <array>
9*ca8c7e98SJagpal Singh Gill #include <cerrno>
10*ca8c7e98SJagpal Singh Gill #include <cstdint>
11*ca8c7e98SJagpal Singh Gill #include <filesystem>
12*ca8c7e98SJagpal Singh Gill #include <memory>
13*ca8c7e98SJagpal Singh Gill #include <span>
14*ca8c7e98SJagpal Singh Gill #include <string>
15*ca8c7e98SJagpal Singh Gill #include <system_error>
16*ca8c7e98SJagpal Singh Gill #include <utility>
17*ca8c7e98SJagpal Singh Gill
18*ca8c7e98SJagpal Singh Gill namespace notify_watch
19*ca8c7e98SJagpal Singh Gill {
20*ca8c7e98SJagpal Singh Gill
21*ca8c7e98SJagpal Singh Gill namespace fs = std::filesystem;
22*ca8c7e98SJagpal Singh Gill
NotifyWatch(sdbusplus::async::context & ctx,const std::string & dir,Callback_t callback)23*ca8c7e98SJagpal Singh Gill NotifyWatch::NotifyWatch(sdbusplus::async::context& ctx, const std::string& dir,
24*ca8c7e98SJagpal Singh Gill Callback_t callback) :
25*ca8c7e98SJagpal Singh Gill ctx(ctx), callback(std::move(callback))
26*ca8c7e98SJagpal Singh Gill {
27*ca8c7e98SJagpal Singh Gill std::error_code ec = {};
28*ca8c7e98SJagpal Singh Gill
29*ca8c7e98SJagpal Singh Gill fs::path dirPath(dir);
30*ca8c7e98SJagpal Singh Gill if (!fs::create_directories(dirPath, ec))
31*ca8c7e98SJagpal Singh Gill {
32*ca8c7e98SJagpal Singh Gill if (ec)
33*ca8c7e98SJagpal Singh Gill {
34*ca8c7e98SJagpal Singh Gill throw std::system_error(ec, "Failed to create directory " + dir);
35*ca8c7e98SJagpal Singh Gill }
36*ca8c7e98SJagpal Singh Gill }
37*ca8c7e98SJagpal Singh Gill
38*ca8c7e98SJagpal Singh Gill fd = inotify_init1(IN_NONBLOCK);
39*ca8c7e98SJagpal Singh Gill if (-1 == fd)
40*ca8c7e98SJagpal Singh Gill {
41*ca8c7e98SJagpal Singh Gill throw std::system_error(errno, std::system_category(),
42*ca8c7e98SJagpal Singh Gill "inotify_init1 failed");
43*ca8c7e98SJagpal Singh Gill }
44*ca8c7e98SJagpal Singh Gill
45*ca8c7e98SJagpal Singh Gill wd = inotify_add_watch(fd, dir.c_str(), IN_CLOSE_WRITE);
46*ca8c7e98SJagpal Singh Gill if (-1 == wd)
47*ca8c7e98SJagpal Singh Gill {
48*ca8c7e98SJagpal Singh Gill close(fd);
49*ca8c7e98SJagpal Singh Gill throw std::system_error(errno, std::system_category(),
50*ca8c7e98SJagpal Singh Gill "inotify_add_watch failed");
51*ca8c7e98SJagpal Singh Gill }
52*ca8c7e98SJagpal Singh Gill
53*ca8c7e98SJagpal Singh Gill fdioInstance = std::make_unique<sdbusplus::async::fdio>(ctx, fd);
54*ca8c7e98SJagpal Singh Gill if (!fdioInstance)
55*ca8c7e98SJagpal Singh Gill {
56*ca8c7e98SJagpal Singh Gill throw std::system_error(errno, std::system_category(),
57*ca8c7e98SJagpal Singh Gill "Failed to create fdio");
58*ca8c7e98SJagpal Singh Gill }
59*ca8c7e98SJagpal Singh Gill }
60*ca8c7e98SJagpal Singh Gill
~NotifyWatch()61*ca8c7e98SJagpal Singh Gill NotifyWatch::~NotifyWatch()
62*ca8c7e98SJagpal Singh Gill {
63*ca8c7e98SJagpal Singh Gill if (-1 != fd)
64*ca8c7e98SJagpal Singh Gill {
65*ca8c7e98SJagpal Singh Gill if (-1 != wd)
66*ca8c7e98SJagpal Singh Gill {
67*ca8c7e98SJagpal Singh Gill inotify_rm_watch(fd, wd);
68*ca8c7e98SJagpal Singh Gill }
69*ca8c7e98SJagpal Singh Gill close(fd);
70*ca8c7e98SJagpal Singh Gill }
71*ca8c7e98SJagpal Singh Gill }
72*ca8c7e98SJagpal Singh Gill
readNotifyAsync()73*ca8c7e98SJagpal Singh Gill auto NotifyWatch::readNotifyAsync() -> sdbusplus::async::task<>
74*ca8c7e98SJagpal Singh Gill {
75*ca8c7e98SJagpal Singh Gill if (!fdioInstance)
76*ca8c7e98SJagpal Singh Gill {
77*ca8c7e98SJagpal Singh Gill co_return;
78*ca8c7e98SJagpal Singh Gill }
79*ca8c7e98SJagpal Singh Gill co_await fdioInstance->next();
80*ca8c7e98SJagpal Singh Gill
81*ca8c7e98SJagpal Singh Gill alignas(inotify_event) std::array<uint8_t, 4096> buffer{};
82*ca8c7e98SJagpal Singh Gill
83*ca8c7e98SJagpal Singh Gill auto bytes = read(fd, buffer.data(), buffer.size());
84*ca8c7e98SJagpal Singh Gill if (bytes < 0)
85*ca8c7e98SJagpal Singh Gill {
86*ca8c7e98SJagpal Singh Gill throw std::system_error(errno, std::system_category(),
87*ca8c7e98SJagpal Singh Gill "Failed to read notify event");
88*ca8c7e98SJagpal Singh Gill }
89*ca8c7e98SJagpal Singh Gill
90*ca8c7e98SJagpal Singh Gill for (auto* iter = buffer.data(); iter < buffer.data() + bytes;)
91*ca8c7e98SJagpal Singh Gill {
92*ca8c7e98SJagpal Singh Gill // Bypassed clang tidy warning about reinterpret_cast as cast is being
93*ca8c7e98SJagpal Singh Gill // performed to avoid copying of buffer data.
94*ca8c7e98SJagpal Singh Gill // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
95*ca8c7e98SJagpal Singh Gill std::span<inotify_event> event{reinterpret_cast<inotify_event*>(iter),
96*ca8c7e98SJagpal Singh Gill 1};
97*ca8c7e98SJagpal Singh Gill if (((event[0].mask & IN_CLOSE_WRITE) != 0U) &&
98*ca8c7e98SJagpal Singh Gill ((event[0].mask & IN_ISDIR) == 0U))
99*ca8c7e98SJagpal Singh Gill {
100*ca8c7e98SJagpal Singh Gill if (callback)
101*ca8c7e98SJagpal Singh Gill {
102*ca8c7e98SJagpal Singh Gill // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
103*ca8c7e98SJagpal Singh Gill std::span<char> name{reinterpret_cast<char*>(event[0].name),
104*ca8c7e98SJagpal Singh Gill event[0].len};
105*ca8c7e98SJagpal Singh Gill co_await callback(std::string(name.begin(), name.end()));
106*ca8c7e98SJagpal Singh Gill }
107*ca8c7e98SJagpal Singh Gill }
108*ca8c7e98SJagpal Singh Gill iter += sizeof(inotify_event) + event[0].len;
109*ca8c7e98SJagpal Singh Gill }
110*ca8c7e98SJagpal Singh Gill
111*ca8c7e98SJagpal Singh Gill if (!ctx.stop_requested())
112*ca8c7e98SJagpal Singh Gill {
113*ca8c7e98SJagpal Singh Gill ctx.spawn(readNotifyAsync());
114*ca8c7e98SJagpal Singh Gill }
115*ca8c7e98SJagpal Singh Gill }
116*ca8c7e98SJagpal Singh Gill
117*ca8c7e98SJagpal Singh Gill } // namespace notify_watch
118