xref: /openbmc/dbus-sensors/src/NotifyWatch.cpp (revision 0d2f96f1e95a6a37f00a3c458c8562d6af92e4a4)
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