blob: 88ccd89939fcd4f0dbca30b96afef689cf84efae [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
Adriana Kobylak3a19e622018-11-09 11:39:46 -060022void SyncWatch::addInotifyWatch(const fs::path& path)
23{
24 auto fd = inotify_init1(IN_NONBLOCK);
25 if (-1 == fd)
26 {
27 log<level::ERR>("inotify_init1 failed", entry("ERRNO=%d", errno),
28 entry("FILENAME=%s", path.c_str()));
29 return;
30 }
31
32 auto wd = inotify_add_watch(fd, path.c_str(), IN_CLOSE_WRITE | IN_DELETE);
33 if (-1 == wd)
34 {
35 log<level::ERR>("inotify_add_watch failed", entry("ERRNO=%d", errno),
36 entry("FILENAME=%s", path.c_str()));
37 close(fd);
38 return;
39 }
40
41 auto rc = sd_event_add_io(&loop, nullptr, fd, EPOLLIN, callback, this);
42 if (0 > rc)
43 {
44 log<level::ERR>("failed to add to event loop", entry("RC=%d", rc),
45 entry("FILENAME=%s", path.c_str()));
46 inotify_rm_watch(fd, wd);
47 close(fd);
48 return;
49 }
50
51 fileMap[fd].insert(std::make_pair(wd, fs::path(path)));
52}
53
Adriana Kobylakb072d1b2018-04-24 11:37:21 -050054SyncWatch::SyncWatch(sd_event& loop,
Adriana Kobylaka9074342018-05-08 11:52:44 -050055 std::function<int(int, fs::path&)> syncCallback) :
Adriana Kobylak3a19e622018-11-09 11:39:46 -060056 syncCallback(syncCallback),
57 loop(loop)
Adriana Kobylakb072d1b2018-04-24 11:37:21 -050058{
59 auto syncfile = fs::path(SYNC_LIST_DIR_PATH) / SYNC_LIST_FILE_NAME;
60 if (fs::exists(syncfile))
61 {
62 std::string line;
63 std::ifstream file(syncfile.c_str());
64 while (std::getline(file, line))
65 {
Adriana Kobylak3a19e622018-11-09 11:39:46 -060066 addInotifyWatch(line);
Adriana Kobylakb072d1b2018-04-24 11:37:21 -050067 }
68 }
69}
70
71SyncWatch::~SyncWatch()
72{
73 for (const auto& fd : fileMap)
74 {
75 for (const auto& wd : fd.second)
76 {
77 inotify_rm_watch(fd.first, wd.first);
78 }
79 close(fd.first);
80 }
81}
82
83int SyncWatch::callback(sd_event_source* s, int fd, uint32_t revents,
84 void* userdata)
85{
Adriana Kobylaka9074342018-05-08 11:52:44 -050086 if (!(revents & EPOLLIN))
87 {
88 return 0;
89 }
90
91 constexpr auto maxBytes = 1024;
92 uint8_t buffer[maxBytes];
93 auto bytes = read(fd, buffer, maxBytes);
94 if (0 > bytes)
95 {
96 return 0;
97 }
98
99 auto syncWatch = static_cast<SyncWatch*>(userdata);
100 auto offset = 0;
101 while (offset < bytes)
102 {
103 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
104
105 // fileMap<fd, std::map<wd, path>>
106 auto it1 = syncWatch->fileMap.find(fd);
107 if (it1 != syncWatch->fileMap.end())
108 {
109 auto it2 = it1->second.begin();
Adriana Kobylak3a19e622018-11-09 11:39:46 -0600110
111 // Watch was removed, re-add it if file still exists.
112 if (event->mask & IN_IGNORED)
113 {
114 if (fs::exists(it2->second))
115 {
116 syncWatch->addInotifyWatch(it2->second);
117 }
118 else
119 {
120 log<level::INFO>("The inotify watch was removed",
121 entry("FILENAME=%s", it2->second.c_str()));
122 }
123 return 0;
124 }
125
Adriana Kobylaka9074342018-05-08 11:52:44 -0500126 auto rc = syncWatch->syncCallback(event->mask, it2->second);
127 if (rc)
128 {
129 return rc;
130 }
131 }
132
133 offset += offsetof(inotify_event, name) + event->len;
134 }
135
Adriana Kobylakb072d1b2018-04-24 11:37:21 -0500136 return 0;
137}
138
139} // namespace manager
140} // namespace software
141} // namespace phosphor