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