00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <utils/system/fam.h>
00024 #include <utils/logging/liblogger.h>
00025
00026 #ifdef HAVE_INOTIFY
00027 # include <sys/inotify.h>
00028 # include <sys/stat.h>
00029 # include <poll.h>
00030 # include <dirent.h>
00031 # include <unistd.h>
00032 # include <cerrno>
00033 # include <cstring>
00034 #endif
00035 #include <cstdlib>
00036
00037 namespace fawkes {
00038
00039
00040
00041 const unsigned int FamListener::FAM_ACCESS = 0x00000001;
00042
00043 const unsigned int FamListener::FAM_MODIFY = 0x00000002;
00044
00045 const unsigned int FamListener::FAM_ATTRIB = 0x00000004;
00046
00047 const unsigned int FamListener::FAM_CLOSE_WRITE = 0x00000008;
00048
00049 const unsigned int FamListener::FAM_CLOSE_NOWRITE = 0x00000010;
00050
00051 const unsigned int FamListener::FAM_CLOSE = (FAM_CLOSE_WRITE | FAM_CLOSE_NOWRITE);
00052
00053 const unsigned int FamListener::FAM_OPEN = 0x00000020;
00054
00055 const unsigned int FamListener::FAM_MOVED_FROM = 0x00000040;
00056
00057 const unsigned int FamListener::FAM_MOVED_TO = 0x00000080;
00058
00059 const unsigned int FamListener::FAM_MOVE = (FAM_MOVED_FROM | FAM_MOVED_TO);
00060
00061 const unsigned int FamListener::FAM_CREATE = 0x00000100;
00062
00063 const unsigned int FamListener::FAM_DELETE = 0x00000200;
00064
00065 const unsigned int FamListener::FAM_DELETE_SELF = 0x00000400;
00066
00067 const unsigned int FamListener::FAM_MOVE_SELF = 0x00000800;
00068
00069
00070
00071 const unsigned int FamListener::FAM_UNMOUNT = 0x00002000;
00072
00073 const unsigned int FamListener::FAM_Q_OVERFLOW = 0x00004000;
00074
00075 const unsigned int FamListener::FAM_IGNORED = 0x00008000;
00076
00077
00078
00079 const unsigned int FamListener::FAM_ONLYDIR = 0x01000000;
00080
00081 const unsigned int FamListener::FAM_DONT_FOLLOW = 0x02000000;
00082
00083 const unsigned int FamListener::FAM_MASK_ADD = 0x20000000;
00084
00085 const unsigned int FamListener::FAM_ISDIR = 0x40000000;
00086
00087 const unsigned int FamListener::FAM_ONESHOT = 0x80000000;
00088
00089
00090 const unsigned int FamListener::FAM_ALL_EVENTS = (FAM_ACCESS | FAM_MODIFY | FAM_ATTRIB | FAM_CLOSE_WRITE \
00091 | FAM_CLOSE_NOWRITE | FAM_OPEN | FAM_MOVED_FROM \
00092 | FAM_MOVED_TO | FAM_CREATE | FAM_DELETE \
00093 | FAM_DELETE_SELF | FAM_MOVE_SELF);
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108 FileAlterationMonitor::FileAlterationMonitor()
00109 {
00110 #ifdef HAVE_INOTIFY
00111 if ( (__inotify_fd = inotify_init()) == -1 ) {
00112 throw Exception(errno, "Failed to initialize inotify");
00113 }
00114
00115
00116 __inotify_bufsize = 1024 * (sizeof(struct inotify_event) + 16);
00117 __inotify_buf = (char *)malloc(__inotify_bufsize);
00118 #endif
00119
00120 __regexes.clear();
00121 }
00122
00123
00124
00125 FileAlterationMonitor::~FileAlterationMonitor()
00126 {
00127 for (__rxit = __regexes.begin(); __rxit != __regexes.end(); ++__rxit) {
00128 regfree(*__rxit);
00129 free(*__rxit);
00130 }
00131
00132 #ifdef HAVE_INOTIFY
00133 for (__inotify_wit = __inotify_watches.begin(); __inotify_wit != __inotify_watches.end(); ++__inotify_wit) {
00134 inotify_rm_watch(__inotify_fd, __inotify_wit->first);
00135 }
00136 close(__inotify_fd);
00137 if ( __inotify_buf ) {
00138 free(__inotify_buf);
00139 __inotify_buf = NULL;
00140 }
00141 #endif
00142 }
00143
00144
00145
00146
00147
00148
00149 void
00150 FileAlterationMonitor::watch_dir(const char *dirpath)
00151 {
00152 #ifdef HAVE_INOTIFY
00153 DIR *d = opendir(dirpath);
00154 if ( d == NULL ) {
00155 throw Exception(errno, "Failed to open dir %s", dirpath);
00156 }
00157
00158 uint32_t mask = IN_MODIFY | IN_MOVE | IN_CREATE | IN_DELETE | IN_DELETE_SELF;
00159 int iw;
00160
00161
00162 if ( (iw = inotify_add_watch(__inotify_fd, dirpath, mask)) >= 0) {
00163 __inotify_watches[iw] = dirpath;
00164
00165 dirent de, *res;
00166 while ( (readdir_r(d, &de, &res) == 0) && (res != NULL) ) {
00167 std::string fp = std::string(dirpath) + "/" + de.d_name;
00168 struct stat st;
00169 if ( stat(fp.c_str(), &st) == 0 ) {
00170 if ( (de.d_name[0] != '.') && S_ISDIR(st.st_mode) ) {
00171 try {
00172 watch_dir(fp.c_str());
00173 } catch (Exception &e) {
00174 closedir(d);
00175 throw;
00176 }
00177
00178
00179 }
00180 } else {
00181 LibLogger::log_debug("FileAlterationMonitor",
00182 "Skipping watch on %s, cannot stat (%s)",
00183 fp.c_str(), strerror(errno));
00184 }
00185 }
00186 } else {
00187 throw Exception("FileAlterationMonitor",
00188 "Cannot add watch for %s", dirpath);
00189 }
00190
00191 closedir(d);
00192 #endif
00193 }
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 void
00209 FileAlterationMonitor::add_filter(const char *regex)
00210 {
00211 int regerr = 0;
00212 regex_t *rx = (regex_t *)malloc(sizeof(regex_t));
00213 if ( (regerr = regcomp(rx, regex, REG_EXTENDED)) != 0 ) {
00214 char errtmp[1024];
00215 regerror(regerr, rx, errtmp, sizeof(errtmp));
00216 free(rx);
00217 throw Exception("Failed to compile lua file regex: %s", errtmp);
00218 }
00219 __regexes.push_back_locked(rx);
00220 }
00221
00222
00223
00224
00225
00226 void
00227 FileAlterationMonitor::add_listener(FamListener *listener)
00228 {
00229 __listeners.push_back_locked(listener);
00230 }
00231
00232
00233
00234
00235
00236 void
00237 FileAlterationMonitor::remove_listener(FamListener *listener)
00238 {
00239 __listeners.remove_locked(listener);
00240 }
00241
00242
00243
00244
00245
00246
00247
00248 void
00249 FileAlterationMonitor::process_events(int timeout)
00250 {
00251 #ifdef HAVE_INOTIFY
00252
00253 pollfd ipfd;
00254 ipfd.fd = __inotify_fd;
00255 ipfd.events = POLLIN;
00256 ipfd.revents = 0;
00257 int prv = poll(&ipfd, 1, timeout);
00258 if ( prv == -1 ) {
00259 LibLogger::log_error("FileAlterationMonitor",
00260 "inotify poll failed: %s (%i)",
00261 strerror(errno), errno);
00262 } else while ( prv > 0 ) {
00263
00264 if ( ipfd.revents & POLLERR ) {
00265 LibLogger::log_error("FileAlterationMonitor", "inotify poll error");
00266 } else {
00267
00268 int bytes = 0, i = 0;
00269 if ((bytes = read(__inotify_fd, __inotify_buf, __inotify_bufsize)) != -1) {
00270 while (i < bytes) {
00271 struct inotify_event *event = (struct inotify_event *) &__inotify_buf[i];
00272
00273 bool valid = true;
00274 if (! (event->mask & IN_ISDIR)) {
00275 for (__rxit = __regexes.begin(); __rxit != __regexes.end(); ++__rxit) {
00276 if (regexec(*__rxit, event->name, 0, NULL, 0) == REG_NOMATCH ) {
00277
00278 valid = false;
00279 break;
00280 }
00281 }
00282 }
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299 if ( valid ) {
00300 for (__lit = __listeners.begin(); __lit != __listeners.end(); ++__lit) {
00301 (*__lit)->fam_event(event->name, event->mask);
00302 }
00303 }
00304
00305 if (event->mask & IN_DELETE_SELF) {
00306
00307 __inotify_watches.erase(event->wd);
00308 inotify_rm_watch(__inotify_fd, event->wd);
00309 }
00310
00311 if (event->mask & IN_CREATE) {
00312
00313 std::string fp = __inotify_watches[event->wd] + "/" + event->name;
00314 if ( (event->mask & IN_ISDIR) && (event->name[0] != '.') ) {
00315
00316
00317
00318
00319
00320 try {
00321 watch_dir(fp.c_str());
00322 } catch (Exception &e) {
00323 LibLogger::log_warn("FileAlterationMonitor", "Adding watch for %s failed, ignoring.", fp.c_str());
00324 LibLogger::log_warn("FileAlterationMonitor", e);
00325 }
00326 }
00327 }
00328
00329 i += sizeof(struct inotify_event) + event->len;
00330 }
00331 } else {
00332 LibLogger::log_error("FileAlterationMonitor", "inotify failed to read any bytes");
00333 }
00334 }
00335
00336 prv = poll(&ipfd, 1, 0);
00337 }
00338 #else
00339 LibLogger::log_error("FileAlterationMonitor",
00340 "inotify support not available, but "
00341 "process_events() was called. Ignoring.");
00342 #endif
00343 }
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 FamListener::~FamListener()
00361 {
00362 }
00363
00364 }