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 =
26 inotify_add_watch(inotifyFd, path.c_str(), 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), syncCallback(std::move(syncCallback))
40 {
41 auto fd = inotify_init1(IN_NONBLOCK);
42 if (-1 == fd)
43 {
44 error("inotify_init1 failed: {ERRNO}", "ERRNO", errno);
45 return;
46 }
47 inotifyFd = fd;
48
49 auto rc = sd_event_add_io(&loop, nullptr, fd, EPOLLIN, callback, this);
50 if (0 > rc)
51 {
52 error("failed to add to event loop: {RC}", "RC", rc);
53 return;
54 }
55
56 std::error_code ec;
57 auto syncfile = fs::path(SYNC_LIST_DIR_PATH) / SYNC_LIST_FILE_NAME;
58 if (fs::exists(syncfile, ec))
59 {
60 std::string line;
61 std::ifstream file(syncfile.c_str());
62 while (std::getline(file, line))
63 {
64 addInotifyWatch(line);
65 }
66 }
67 }
68
~SyncWatch()69 SyncWatch::~SyncWatch()
70 {
71 if (inotifyFd != -1)
72 {
73 close(inotifyFd);
74 }
75 }
76
callback(sd_event_source *,int fd,uint32_t revents,void * userdata)77 int SyncWatch::callback(sd_event_source* /* s */, int fd, uint32_t revents,
78 void* userdata)
79 {
80 if (!(revents & EPOLLIN))
81 {
82 return 0;
83 }
84
85 constexpr auto maxBytes = 1024;
86 uint8_t buffer[maxBytes];
87 auto bytes = read(fd, buffer, maxBytes);
88 if (0 > bytes)
89 {
90 return 0;
91 }
92
93 auto syncWatch = static_cast<SyncWatch*>(userdata);
94 auto offset = 0;
95 while (offset < bytes)
96 {
97 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
98
99 // Watch was removed, re-add it if file still exists.
100 if (event->mask & IN_IGNORED)
101 {
102 std::error_code ec;
103 if (fs::exists(syncWatch->fileMap[event->wd], ec))
104 {
105 syncWatch->addInotifyWatch(syncWatch->fileMap[event->wd]);
106 }
107 else
108 {
109 info("The inotify watch on {PATH} was removed", "PATH",
110 syncWatch->fileMap[event->wd]);
111 }
112 return 0;
113 }
114
115 // fileMap<wd, path>
116 auto rc = syncWatch->syncCallback(static_cast<int>(event->mask),
117 syncWatch->fileMap[event->wd]);
118 if (rc)
119 {
120 return rc;
121 }
122
123 offset += offsetof(inotify_event, name) + event->len;
124 }
125
126 return 0;
127 }
128
129 } // namespace manager
130 } // namespace software
131 } // namespace phosphor
132