23 #include <utils/system/fam.h> 24 #include <core/exception.h> 25 #include <logging/liblogger.h> 28 # include <sys/inotify.h> 29 # include <sys/stat.h> 92 | FAM_CLOSE_NOWRITE | FAM_OPEN | FAM_MOVED_FROM \
93 | FAM_MOVED_TO | FAM_CREATE | FAM_DELETE \
94 | FAM_DELETE_SELF | FAM_MOVE_SELF);
112 __inotify_buf = NULL;
113 __inotify_bufsize = 0;
116 if ( (__inotify_fd = inotify_init()) == -1 ) {
117 throw Exception(errno,
"Failed to initialize inotify");
121 __inotify_bufsize = 1024 * (
sizeof(
struct inotify_event) + 16);
122 __inotify_buf = (
char *)malloc(__inotify_bufsize);
125 __interrupted =
false;
126 __interruptible = (pipe(__pipe_fds) == 0);
135 for (__rxit = __regexes.begin(); __rxit != __regexes.end(); ++__rxit) {
141 for (__inotify_wit = __inotify_watches.begin(); __inotify_wit != __inotify_watches.end(); ++__inotify_wit) {
142 inotify_rm_watch(__inotify_fd, __inotify_wit->first);
145 if ( __inotify_buf ) {
147 __inotify_buf = NULL;
161 DIR *d = opendir(dirpath);
163 throw Exception(errno,
"Failed to open dir %s", dirpath);
166 uint32_t mask = IN_MODIFY | IN_MOVE | IN_CREATE | IN_DELETE | IN_DELETE_SELF;
170 if ( (iw = inotify_add_watch(__inotify_fd, dirpath, mask)) >= 0) {
171 __inotify_watches[iw] = dirpath;
174 while ( (de = readdir(d)) ) {
175 std::string fp = std::string(dirpath) +
"/" + de->d_name;
177 if ( stat(fp.c_str(), &st) == 0 ) {
178 if ( (de->d_name[0] !=
'.') && S_ISDIR(st.st_mode) ) {
195 throw Exception(errno,
"FileAlterationMonitor: cannot add watch for %s", dirpath);
210 uint32_t mask = IN_MODIFY | IN_MOVE | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF;
213 if ( (iw = inotify_add_watch(__inotify_fd, filepath, mask)) >= 0) {
215 __inotify_watches[iw] = filepath;
217 throw Exception(
"FileAlterationMonitor: cannot add watch for file %s", filepath);
228 std::map<int, std::string>::iterator wit;
229 for (wit = __inotify_watches.begin(); wit != __inotify_watches.end(); ++wit) {
230 inotify_rm_watch(__inotify_fd, wit->first);
232 __inotify_watches.clear();
252 regex_t *rx = (regex_t *)malloc(
sizeof(regex_t));
253 if ( (regerr = regcomp(rx, regex, REG_EXTENDED)) != 0 ) {
255 regerror(regerr, rx, errtmp,
sizeof(errtmp));
257 throw Exception(
"Failed to compile lua file regex: %s", errtmp);
269 __listeners.push_back_locked(listener);
279 __listeners.remove_locked(listener);
293 __interrupted =
false;
294 std::map<std::string, unsigned int> events;
297 ipfd[0].fd = __inotify_fd;
298 ipfd[0].events = POLLIN;
300 ipfd[1].fd = __pipe_fds[0];
301 ipfd[1].events = POLLIN;
303 int prv = poll(ipfd, 2, timeout);
305 if ( errno != EINTR ) {
310 __interrupted =
true;
312 }
else while ( !__interrupted && (prv > 0) ) {
314 if ( ipfd[0].revents & POLLERR ) {
316 }
else if (__interrupted) {
321 int bytes = 0, i = 0;
323 if ((bytes = read(__inotify_fd, __inotify_buf, __inotify_bufsize)) != -1) {
324 while (!__interrupted && (i < bytes)) {
325 struct inotify_event *
event = (
struct inotify_event *) &__inotify_buf[i];
327 if (event->mask & IN_IGNORED) {
328 i +=
sizeof(
struct inotify_event) + event->len;
333 if (! (event->mask & IN_ISDIR)) {
334 for (__rxit = __regexes.begin(); __rxit != __regexes.end(); ++__rxit) {
335 if (event->len > 0 &&
336 (regexec(*__rxit, event->name, 0, NULL, 0) == REG_NOMATCH))
345 if (event->len == 0) {
346 if (__inotify_watches.find(event->wd) != __inotify_watches.end()) {
347 if (events.find(__inotify_watches[event->wd]) != events.end()) {
348 events[__inotify_watches[
event->wd]] |=
event->mask;
350 events[__inotify_watches[
event->wd]] =
event->mask;
354 if (events.find(event->name) != events.end()) {
355 events[
event->name] |=
event->mask;
357 events[
event->name] =
event->mask;
362 if (event->mask & IN_DELETE_SELF) {
364 __inotify_watches.erase(event->wd);
365 inotify_rm_watch(__inotify_fd, event->wd);
368 if (event->mask & IN_CREATE) {
370 std::string fp = __inotify_watches[
event->wd] +
"/" +
event->name;
371 if ( (event->mask & IN_ISDIR) && (event->name[0] !=
'.') ) {
386 i +=
sizeof(
struct inotify_event) + event->len;
395 prv = poll(ipfd, 2, 0);
398 std::map<std::string, unsigned int>::const_iterator e;
399 for (e = events.begin(); e != events.end(); ++e) {
402 for (__lit = __listeners.begin(); __lit != __listeners.end(); ++__lit) {
403 (*__lit)->fam_event(e->first.c_str(), e->second);
411 throw Exception(
"FileAlterationMonitor: inotify support not available, " 412 "but process_events() was called.");
424 if (__interruptible) {
425 __interrupted =
true;
427 if (write(__pipe_fds[1], &tmp, 1) != 1) {
428 throw Exception(errno,
"Failed to interrupt file alteration monitor," 429 " failed to write to pipe");
432 throw Exception(
"Currently not interruptible");
Fawkes library namespace.
void reset()
Remove all currently active watches.
static const unsigned int FAM_UNMOUNT
Backing fs was unmounted.
static const unsigned int FAM_ONESHOT
Only send event once.
void add_filter(const char *regex)
Add a filter.
static const unsigned int FAM_CREATE
Subfile was created.
void interrupt()
Interrupt a running process_events().
void push_back_locked(const Type &x)
Push element to list at back with lock protection.
static const unsigned int FAM_ISDIR
Event occurred against dir.
static const unsigned int FAM_MOVE
Moves.
static const unsigned int FAM_OPEN
File was opened.
static const unsigned int FAM_ACCESS
File was accessed.
~FileAlterationMonitor()
Destructor.
static const unsigned int FAM_IGNORED
File was ignored.
Base class for exceptions in Fawkes.
static const unsigned int FAM_Q_OVERFLOW
Event queued overflowed.
static const unsigned int FAM_ONLYDIR
Only watch the path if it is a directory.
static const unsigned int FAM_MASK_ADD
Add to the mask of an already existing watch.
File Alteration Monitor Listener.
static const unsigned int FAM_MOVE_SELF
Self was moved.
static const unsigned int FAM_MOVED_FROM
File was moved from X.
FileAlterationMonitor()
Constructor.
static const unsigned int FAM_MOVED_TO
File was moved to Y.
static const unsigned int FAM_DELETE_SELF
Self was deleted.
void remove_listener(FamListener *listener)
Remove a listener.
static const unsigned int FAM_ALL_EVENTS
All events which a program can wait on.
void add_listener(FamListener *listener)
Add a listener.
static const unsigned int FAM_CLOSE_NOWRITE
Unwrittable file closed.
static const unsigned int FAM_DELETE
Subfile was deleted.
static const unsigned int FAM_MODIFY
File was modified.
void watch_dir(const char *dirpath)
Watch a directory.
void process_events(int timeout=0)
Process events.
static const unsigned int FAM_DONT_FOLLOW
Do not follow a sym link.
void watch_file(const char *filepath)
Watch a file.
static const unsigned int FAM_ATTRIB
Metadata changed.
virtual ~FamListener()
Virtual empty destructor.
static const unsigned int FAM_CLOSE_WRITE
Writtable file was closed.
static const unsigned int FAM_CLOSE
Close.