CernVM-FS  2.13.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
file_watcher_inotify.cc
Go to the documentation of this file.
1 
5 #include "file_watcher_inotify.h"
6 
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <linux/limits.h>
10 #include <poll.h>
11 #include <sys/inotify.h>
12 #include <sys/time.h>
13 #include <sys/types.h>
14 #include <unistd.h>
15 
16 #include <cassert>
17 #include <string>
18 #include <vector>
19 
20 #include "util/logging.h"
21 #include "util/posix.h"
22 
23 namespace file_watcher {
24 
26 
28 
30  int read_pipe, int write_pipe) {
31  inotify_fd_ = inotify_init1(IN_NONBLOCK);
32  assert(inotify_fd_ >= 0);
33 
34  for (FileWatcher::HandlerMap::const_iterator it = handlers.begin();
35  it != handlers.end();
36  ++it) {
37  RegisterFilter(it->first, it->second);
38  }
39 
40  // Use the control pipe to signal readiness to the main thread,
41  // before continuing with the event loop.
42  WritePipe(write_pipe, "s", 1);
43 
44  struct pollfd poll_set[2];
45 
46  poll_set[0].fd = read_pipe;
47  poll_set[0].events = POLLHUP | POLLIN;
48  poll_set[0].revents = 0;
49  poll_set[1].fd = inotify_fd_;
50  poll_set[1].events = POLLIN;
51  poll_set[1].revents = 0;
52 
53  bool stop = false;
54  while (!stop) {
55  int ready = poll(poll_set, 2, -1);
56  if (ready == -1) {
57  if (errno == EINTR) {
58  continue;
59  }
61  "FileWatcherInotify - Could not poll events. Errno: %d", errno);
62  return false;
63  }
64  if (ready == 0) {
65  continue;
66  }
67 
68  if (poll_set[0].revents & POLLHUP) {
69  LogCvmfs(kLogCvmfs, kLogDebug, "FileWatcherInotify - Stopping.\n");
70  stop = true;
71  continue;
72  }
73  if (poll_set[0].revents & POLLIN) {
74  char buffer[1];
75  ReadPipe(read_pipe, &buffer, 1);
76  LogCvmfs(kLogCvmfs, kLogDebug, "FileWatcherInotify - Stopping.\n");
77  stop = true;
78  continue;
79  }
80 
81  const size_t event_size = sizeof(struct inotify_event);
82  // We need a large enough buffer for an event with the largest path name
83  const size_t buffer_size = event_size + PATH_MAX + 1;
84  char buffer[buffer_size];
85  if (poll_set[1].revents & POLLIN) {
86  int len = read(inotify_fd_, buffer, buffer_size);
87  assert(len > 0);
88  int i = 0;
89  while (i < len) {
90  struct inotify_event
91  *inotify_event = reinterpret_cast<struct inotify_event *>(
92  &buffer[i]);
93  std::map<int, WatchRecord>::const_iterator it = watch_records_.find(
94  inotify_event->wd);
95  if (it != watch_records_.end()) {
96  WatchRecord current_record = it->second;
98  if (inotify_event->mask & IN_DELETE_SELF) {
99  event = file_watcher::kDeleted;
100  } else if (inotify_event->mask & IN_CLOSE_WRITE) {
101  // Modified
102  event = file_watcher::kModified;
103  } else if (inotify_event->mask & IN_MOVE_SELF) {
104  // Renamed
105  event = file_watcher::kRenamed;
106  } else if (inotify_event->mask & IN_ATTRIB) {
107  // Attributes
109  } else if (inotify_event->mask & IN_IGNORED) {
110  // An IN_IGNORED event is generated after a file is deleted and the
111  // watch is removed
112  event = file_watcher::kIgnored;
113  }
114  bool clear_handler = true;
115  if (event != file_watcher::kInvalid
116  && event != file_watcher::kIgnored) {
117  current_record.handler_->Handle(current_record.file_path_, event,
118  &clear_handler);
119  } else {
121  "FileWatcherInotify - Unknown event 0x%x\n",
122  inotify_event->mask);
123  }
124 
125  // Perform post-handling actions (i.e. remove, reset filter)
126  if (event == file_watcher::kDeleted) {
127  watch_records_.erase(inotify_event->wd);
128  if (!clear_handler) {
129  RegisterFilter(current_record.file_path_,
130  current_record.handler_);
131  }
132  }
133  } else {
135  "FileWatcherInotify - Unknown event ident: %d",
136  inotify_event->wd);
137  }
138 
139  i += event_size + inotify_event->len;
140  }
141  }
142  }
143 
144  watch_records_.clear();
145 
146  close(inotify_fd_);
147 
148  return true;
149 }
150 
151 int FileWatcherInotify::TryRegisterFilter(const std::string &file_path) {
152  return inotify_add_watch(
153  inotify_fd_, file_path.c_str(),
154  IN_ATTRIB | IN_CLOSE_WRITE | IN_DELETE_SELF | IN_MOVE_SELF);
155 }
156 
157 } // namespace file_watcher
void RegisterFilter(const std::string &file_path, EventHandler *handler)
assert((mem||(size==0))&&"Out Of Memory")
std::map< std::string, EventHandler * > HandlerMap
Definition: file_watcher.h:62
file_watcher::EventHandler * handler_
Definition: file_watcher.h:57
virtual int TryRegisterFilter(const std::string &file_path)
virtual bool Handle(const std::string &file_path, Event event, bool *clear_handler)=0
std::map< int, WatchRecord > watch_records_
Definition: file_watcher.h:87
void WritePipe(int fd, const void *buf, size_t nbyte)
Definition: posix.cc:496
void ReadPipe(int fd, void *buf, size_t nbyte)
Definition: posix.cc:508
virtual bool RunEventLoop(const FileWatcher::HandlerMap &handler, int read_pipe, int write_pipe)
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:545