blob: c017716aa924c493073c5bcf9211db9ce9571c96 [file] [log] [blame]
Gunnar Millsb0ce9962018-09-07 13:39:10 -05001#include "config.h"
2
3#include "sync_watch.hpp"
4
5#include <sys/inotify.h>
6#include <unistd.h>
7
Adriana Kobylakb072d1b2018-04-24 11:37:21 -05008#include <experimental/filesystem>
9#include <fstream>
10#include <phosphor-logging/log.hpp>
Adriana Kobylakb072d1b2018-04-24 11:37:21 -050011
12namespace phosphor
13{
14namespace software
15{
16namespace manager
17{
18
19using namespace phosphor::logging;
20namespace fs = std::experimental::filesystem;
21
22SyncWatch::SyncWatch(sd_event& loop,
Adriana Kobylaka9074342018-05-08 11:52:44 -050023 std::function<int(int, fs::path&)> syncCallback) :
Adriana Kobylakb072d1b2018-04-24 11:37:21 -050024 syncCallback(syncCallback)
25{
26 auto syncfile = fs::path(SYNC_LIST_DIR_PATH) / SYNC_LIST_FILE_NAME;
27 if (fs::exists(syncfile))
28 {
29 std::string line;
30 std::ifstream file(syncfile.c_str());
31 while (std::getline(file, line))
32 {
33 auto fd = inotify_init1(IN_NONBLOCK);
34 if (-1 == fd)
35 {
36 log<level::ERR>("inotify_init1 failed",
37 entry("ERRNO=%d", errno),
38 entry("FILENAME=%s", line.c_str()),
39 entry("SYNCFILE=%s", syncfile.c_str()));
40 continue;
41 }
42
Adriana Kobylaka9074342018-05-08 11:52:44 -050043 auto wd =
44 inotify_add_watch(fd, line.c_str(), IN_CLOSE_WRITE | IN_DELETE);
Adriana Kobylakb072d1b2018-04-24 11:37:21 -050045 if (-1 == wd)
46 {
47 log<level::ERR>("inotify_add_watch failed",
48 entry("ERRNO=%d", errno),
49 entry("FILENAME=%s", line.c_str()),
50 entry("SYNCFILE=%s", syncfile.c_str()));
51 close(fd);
52 continue;
53 }
54
55 auto rc =
56 sd_event_add_io(&loop, nullptr, fd, EPOLLIN, callback, this);
57 if (0 > rc)
58 {
59 log<level::ERR>("failed to add to event loop",
60 entry("RC=%d", rc),
61 entry("FILENAME=%s", line.c_str()),
62 entry("SYNCFILE=%s", syncfile.c_str()));
63 inotify_rm_watch(fd, wd);
64 close(fd);
65 continue;
66 }
67
68 fileMap[fd].insert(std::make_pair(wd, fs::path(line)));
69 }
70 }
71}
72
73SyncWatch::~SyncWatch()
74{
75 for (const auto& fd : fileMap)
76 {
77 for (const auto& wd : fd.second)
78 {
79 inotify_rm_watch(fd.first, wd.first);
80 }
81 close(fd.first);
82 }
83}
84
85int SyncWatch::callback(sd_event_source* s, int fd, uint32_t revents,
86 void* userdata)
87{
Adriana Kobylaka9074342018-05-08 11:52:44 -050088 if (!(revents & EPOLLIN))
89 {
90 return 0;
91 }
92
93 constexpr auto maxBytes = 1024;
94 uint8_t buffer[maxBytes];
95 auto bytes = read(fd, buffer, maxBytes);
96 if (0 > bytes)
97 {
98 return 0;
99 }
100
101 auto syncWatch = static_cast<SyncWatch*>(userdata);
102 auto offset = 0;
103 while (offset < bytes)
104 {
105 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
106
107 // fileMap<fd, std::map<wd, path>>
108 auto it1 = syncWatch->fileMap.find(fd);
109 if (it1 != syncWatch->fileMap.end())
110 {
111 auto it2 = it1->second.begin();
112 auto rc = syncWatch->syncCallback(event->mask, it2->second);
113 if (rc)
114 {
115 return rc;
116 }
117 }
118
119 offset += offsetof(inotify_event, name) + event->len;
120 }
121
Adriana Kobylakb072d1b2018-04-24 11:37:21 -0500122 return 0;
123}
124
125} // namespace manager
126} // namespace software
127} // namespace phosphor