23 #include <utils/system/fam.h>
24 #include <core/exception.h>
27 # include <sys/inotify.h>
28 # include <sys/stat.h>
91 | FAM_CLOSE_NOWRITE | FAM_OPEN | FAM_MOVED_FROM \
92 | FAM_MOVED_TO | FAM_CREATE | FAM_DELETE \
93 | FAM_DELETE_SELF | FAM_MOVE_SELF);
111 if ( (__inotify_fd = inotify_init()) == -1 ) {
112 throw Exception(errno,
"Failed to initialize inotify");
116 __inotify_bufsize = 1024 * (
sizeof(
struct inotify_event) + 16);
117 __inotify_buf = (
char *)malloc(__inotify_bufsize);
120 __interrupted =
false;
121 __interruptible = (pipe(__pipe_fds) == 0);
130 for (__rxit = __regexes.begin(); __rxit != __regexes.end(); ++__rxit) {
136 for (__inotify_wit = __inotify_watches.begin(); __inotify_wit != __inotify_watches.end(); ++__inotify_wit) {
137 inotify_rm_watch(__inotify_fd, __inotify_wit->first);
140 if ( __inotify_buf ) {
142 __inotify_buf = NULL;
156 DIR *d = opendir(dirpath);
158 throw Exception(errno,
"Failed to open dir %s", dirpath);
161 uint32_t mask = IN_MODIFY | IN_MOVE | IN_CREATE | IN_DELETE | IN_DELETE_SELF;
165 if ( (iw = inotify_add_watch(__inotify_fd, dirpath, mask)) >= 0) {
166 __inotify_watches[iw] = dirpath;
169 while ( (readdir_r(d, &de, &res) == 0) && (res != NULL) ) {
170 std::string fp = std::string(dirpath) +
"/" + de.d_name;
172 if ( stat(fp.c_str(), &st) == 0 ) {
173 if ( (de.d_name[0] !=
'.') && S_ISDIR(st.st_mode) ) {
190 throw Exception(errno,
"FileAlterationMonitor: cannot add watch for %s", dirpath);
205 uint32_t mask = IN_MODIFY | IN_MOVE | IN_CREATE | IN_DELETE | IN_DELETE_SELF;
209 if ( (iw = inotify_add_watch(__inotify_fd, filepath, mask)) >= 0) {
210 __inotify_watches[iw] = filepath;
212 throw Exception(
"FileAlterationMonitor: cannot add watch for file %s", filepath);
234 regex_t *rx = (regex_t *)malloc(
sizeof(regex_t));
235 if ( (regerr = regcomp(rx, regex, REG_EXTENDED)) != 0 ) {
237 regerror(regerr, rx, errtmp,
sizeof(errtmp));
239 throw Exception(
"Failed to compile lua file regex: %s", errtmp);
251 __listeners.push_back_locked(listener);
261 __listeners.remove_locked(listener);
275 __interrupted =
false;
277 ipfd[0].fd = __inotify_fd;
278 ipfd[0].events = POLLIN;
280 ipfd[1].fd = __pipe_fds[0];
281 ipfd[1].events = POLLIN;
283 int prv = poll(ipfd, 2, timeout);
285 if ( errno != EINTR ) {
290 __interrupted =
true;
292 }
else while ( !__interrupted && (prv > 0) ) {
294 if ( ipfd[0].revents & POLLERR ) {
296 }
else if (__interrupted) {
301 int bytes = 0, i = 0;
302 if ((bytes = read(__inotify_fd, __inotify_buf, __inotify_bufsize)) != -1) {
303 while (!__interrupted && (i < bytes)) {
304 struct inotify_event *
event = (
struct inotify_event *) &__inotify_buf[i];
307 if (! (event->mask & IN_ISDIR)) {
308 for (__rxit = __regexes.begin(); __rxit != __regexes.end(); ++__rxit) {
309 if (regexec(*__rxit, event->name, 0, NULL, 0) == REG_NOMATCH ) {
333 for (__lit = __listeners.begin(); __lit != __listeners.end(); ++__lit) {
334 (*__lit)->fam_event(event->name, event->mask);
338 if (event->mask & IN_DELETE_SELF) {
340 __inotify_watches.erase(event->wd);
341 inotify_rm_watch(__inotify_fd, event->wd);
344 if (event->mask & IN_CREATE) {
346 std::string fp = __inotify_watches[
event->wd] +
"/" +
event->name;
347 if ( (event->mask & IN_ISDIR) && (event->name[0] !=
'.') ) {
362 i +=
sizeof(
struct inotify_event) + event->len;
369 prv = poll(ipfd, 2, 0);
375 throw Exception(
"FileAlterationMonitor: inotify support not available, "
376 "but process_events() was called.");
388 if (__interruptible) {
389 __interrupted =
true;
391 if (write(__pipe_fds[1], &tmp, 1) != 1) {
392 throw Exception(errno,
"Failed to interrupt file alteration monitor,"
393 " failed to write to pipe");
396 throw Exception(
"Currently not interruptible");
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.