1 #include "config.h"
2
3 #include "sync_watch.hpp"
4
5 #include <sys/inotify.h>
6 #include <unistd.h>
7
8 #include <phosphor-logging/lg2.hpp>
9
10 #include <filesystem>
11 #include <fstream>
12 #include <system_error>
13
14 namespace phosphor
15 {
16 namespace software
17 {
18 namespace manager
19 {
20
21 PHOSPHOR_LOG2_USING;
22
addInotifyWatch(const fs::path & path)23 void SyncWatch::addInotifyWatch(const fs::path& path)
24 {
25 auto wd = inotify_add_watch(inotifyFd, path.c_str(),
26 IN_CLOSE_WRITE | IN_DELETE);
27 if (-1 == wd)
28 {
29 error("inotify_add_watch on {PATH} failed: {ERRNO}", "ERRNO", errno,
30 "PATH", path);
31 return;
32 }
33
34 fileMap[wd] = fs::path(path);
35 }
36
SyncWatch(sd_event & loop,std::function<int (int,fs::path &)> syncCallback)37 SyncWatch::SyncWatch(sd_event& loop,
38 std::function<int(int, fs::path&)> syncCallback) :
39 inotifyFd(-1),
40 syncCallback(syncCallback), loop(loop)
41 {
42 auto fd = inotify_init1(IN_NONBLOCK);
43 if (-1 == fd)
44 {
45 error("inotify_init1 failed: {ERRNO}", "ERRNO", errno);
46 return;
47 }
48 inotifyFd = fd;
49
50 auto rc = sd_event_add_io(&loop, nullptr, fd, EPOLLIN, callback, this);
51 if (0 > rc)
52 {
53 error("failed to add to event loop: {RC}", "RC", rc);
54 return;
55 }
56
57 std::error_code ec;
58 auto syncfile = fs::path(SYNC_LIST_DIR_PATH) / SYNC_LIST_FILE_NAME;
59 if (fs::exists(syncfile, ec))
60 {
61 std::string line;
62 std::ifstream file(syncfile.c_str());
63 while (std::getline(file, line))
64 {
65 addInotifyWatch(line);
66 }
67 }
68 }
69
~SyncWatch()70 SyncWatch::~SyncWatch()
71 {
72 if (inotifyFd != -1)
73 {
74 close(inotifyFd);
75 }
76 }
77
callback(sd_event_source *,int fd,uint32_t revents,void * userdata)78 int SyncWatch::callback(sd_event_source* /* s */, int fd, uint32_t revents,
79 void* userdata)
80 {
81 if (!(revents & EPOLLIN))
82 {
83 return 0;
84 }
85
86 constexpr auto maxBytes = 1024;
87 uint8_t buffer[maxBytes];
88 auto bytes = read(fd, buffer, maxBytes);
89 if (0 > bytes)
90 {
91 return 0;
92 }
93
94 auto syncWatch = static_cast<SyncWatch*>(userdata);
95 auto offset = 0;
96 while (offset < bytes)
97 {
98 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
99
100 // Watch was removed, re-add it if file still exists.
101 if (event->mask & IN_IGNORED)
102 {
103 std::error_code ec;
104 if (fs::exists(syncWatch->fileMap[event->wd], ec))
105 {
106 syncWatch->addInotifyWatch(syncWatch->fileMap[event->wd]);
107 }
108 else
109 {
110 info("The inotify watch on {PATH} was removed", "PATH",
111 syncWatch->fileMap[event->wd]);
112 }
113 return 0;
114 }
115
116 // fileMap<wd, path>
117 auto rc = syncWatch->syncCallback(event->mask,
118 syncWatch->fileMap[event->wd]);
119 if (rc)
120 {
121 return rc;
122 }
123
124 offset += offsetof(inotify_event, name) + event->len;
125 }
126
127 return 0;
128 }
129
130 } // namespace manager
131 } // namespace software
132 } // namespace phosphor
133