15#include "../../config.h"
17#include "inotifytools_p.h"
31#include <sys/select.h>
37#include "inotifytools/inotify.h"
40struct fanotify_event_fid;
42#define FAN_EVENT_INFO_TYPE_FID 1
43#define FAN_EVENT_INFO_TYPE_DFID_NAME 2
44#define FAN_EVENT_INFO_TYPE_DFID 3
52#include "inotifytools/fanotify.h"
54struct fanotify_event_fid {
55 struct fanotify_event_info_fid info;
56 struct file_handle handle;
146#define MAX_EVENTS 4096
147#define INOTIFY_PROCDIR "/proc/sys/fs/inotify/"
148#define WATCHES_SIZE_PATH INOTIFY_PROCDIR "max_user_watches"
149#define QUEUE_SIZE_PATH INOTIFY_PROCDIR "max_queued_watches"
150#define INSTANCES_PATH INOTIFY_PROCDIR "max_user_instances"
152static int inotify_fd = -1;
154int collect_stats = 0;
156struct rbtree *tree_wd = 0;
157struct rbtree* tree_fid = 0;
158struct rbtree *tree_filename = 0;
162int fanotify_mode = 0;
163int fanotify_mark_type = 0;
164static pid_t self_pid = 0;
165static char* timefmt = 0;
166static regex_t* regex = 0;
168static int invert_regexp = 0;
170static int isdir(
char const * path );
171void record_stats(
struct inotify_event
const * event );
172int onestr_to_event(
char const * event);
174#define nasprintf(...) niceassert( -1 != asprintf(__VA_ARGS__), "out of memory")
193void _niceassert(
long cond,
int line,
char const * file,
194 char const * condstr,
char const * mesg ) {
198 fprintf(stderr,
"%s:%d assertion ( %s ) failed: %s\n", file, line,
202 fprintf(stderr,
"%s:%d assertion ( %s ) failed.\n", file, line, condstr);
206static void charcat(
char* s,
const char c) {
207 size_t l = strlen(s);
215static int read_num_from_file(
char* filename,
int* num) {
216 FILE * file = fopen( filename,
"r" );
222 if ( EOF == fscanf( file,
"%d", num ) ) {
224 const int fclose_ret = fclose(file);
225 niceassert(!fclose_ret, 0);
229 const int fclose_ret = fclose(file);
230 niceassert(!fclose_ret, 0);
235static int wd_compare(
const void* d1,
const void* d2,
const void* config) {
236 if (!d1 || !d2)
return d1 - d2;
237 return ((watch*)d1)->wd - ((watch*)d2)->wd;
240static int fid_compare(
const void* d1,
const void* d2,
const void* config) {
244 watch* w1 = (watch*)d1;
245 watch* w2 = (watch*)d2;
247 n1 = w1->fid->info.hdr.len;
248 n2 = w2->fid->info.hdr.len;
251 return memcmp(w1->fid, w2->fid, n1);
257static int filename_compare(
const void* d1,
259 const void* config) {
260 if (!d1 || !d2)
return d1 - d2;
261 return strcmp(((watch*)d1)->filename, ((watch*)d2)->filename);
267watch *watch_from_wd(
int wd ) {
270 return (watch*)rbfind(&w, tree_wd);
276watch* watch_from_fid(
struct fanotify_event_fid* fid) {
279 return (watch*)rbfind(&w, tree_fid);
285watch *watch_from_filename(
char const *filename ) {
287 w.filename = (
char*)filename;
288 return (watch*)rbfind(&w, tree_filename);
313 watch_filesystem ? FAN_MARK_FILESYSTEM : FAN_MARK_INODE;
315 fanotify_init(FAN_REPORT_FID | FAN_REPORT_DFID_NAME, 0);
319 inotify_fd = inotify_init();
321 if (inotify_fd < 0) {
328 tree_wd = rbinit(wd_compare, 0);
329 tree_fid = rbinit(fid_compare, 0);
330 tree_filename = rbinit(filename_compare, 0);
336int inotifytools_initialize() {
343void destroy_watch(watch *w) {
344 if (w->filename) free(w->filename);
355void cleanup_tree(
const void *nodep,
357 const int depth,
void* arg) {
358 if (which != endorder && which != leaf)
return;
359 watch *w = (watch*)nodep;
385 rbwalk(tree_wd, cleanup_tree, 0);
388 rbdestroy(tree_filename);
399struct replace_filename_data {
400 char const *old_name;
401 char const *new_name;
408static void replace_filename(
const void* nodep,
411 const struct replace_filename_data* data) {
412 if (which != endorder && which != leaf)
414 watch *w = (watch*)nodep;
416 if ( 0 == strncmp( data->old_name, w->filename, data->old_len ) ) {
417 nasprintf( &name,
"%s%s", data->new_name, &(w->filename[data->old_len]) );
418 if (!strcmp( w->filename, data->new_name )) {
421 rbdelete(w, tree_filename);
424 rbsearch(w, tree_filename);
432static void get_num(
const void* nodep,
436 if (which != endorder && which != leaf)
469 if ( strchr(
"_" "abcdefghijklmnopqrstuvwxyz"
470 "ABCDEFGHIJKLMNOPQRSTUVWXYZ", sep ) ) {
475 char * event1, * event2;
476 static const size_t eventstr_size = 4096;
477 char eventstr[eventstr_size];
480 if ( !event || !event[0] )
return 0;
482 event1 = (
char *)event;
483 event2 = strchr( event1, sep );
484 while ( event1 && event1[0] ) {
486 len = event2 - event1;
487 niceassert(len < eventstr_size,
488 "malformed event string (very long)");
491 len = strlen(event1);
493 if (len > eventstr_size - 1)
494 len = eventstr_size - 1;
496 strncpy(eventstr, event1, len);
500 int ret1 = onestr_to_event(eventstr);
501 if ( 0 == ret1 || -1 == ret1 ) {
508 if ( event1 && event1[0] ) {
512 if ( !event1[0] )
return 0;
513 event2 = strchr( event1, sep );
558int onestr_to_event(
char const * event)
563 if ( !event || !event[0] )
565 else if ( 0 == strcasecmp(event,
"ACCESS") )
567 else if ( 0 == strcasecmp(event,
"MODIFY") )
569 else if ( 0 == strcasecmp(event,
"ATTRIB") )
571 else if ( 0 == strcasecmp(event,
"CLOSE_WRITE") )
572 ret = IN_CLOSE_WRITE;
573 else if ( 0 == strcasecmp(event,
"CLOSE_NOWRITE") )
574 ret = IN_CLOSE_NOWRITE;
575 else if ( 0 == strcasecmp(event,
"OPEN") )
577 else if ( 0 == strcasecmp(event,
"MOVED_FROM") )
579 else if ( 0 == strcasecmp(event,
"MOVED_TO") )
581 else if ( 0 == strcasecmp(event,
"CREATE") )
583 else if ( 0 == strcasecmp(event,
"DELETE") )
585 else if ( 0 == strcasecmp(event,
"DELETE_SELF") )
586 ret = IN_DELETE_SELF;
587 else if ( 0 == strcasecmp(event,
"UNMOUNT") )
589 else if ( 0 == strcasecmp(event,
"Q_OVERFLOW") )
591 else if ( 0 == strcasecmp(event,
"IGNORED") )
593 else if ( 0 == strcasecmp(event,
"CLOSE") )
595 else if ( 0 == strcasecmp(event,
"MOVE_SELF") )
597 else if ( 0 == strcasecmp(event,
"MOVE") )
599 else if ( 0 == strcasecmp(event,
"ISDIR") )
601 else if ( 0 == strcasecmp(event,
"ONESHOT") )
603 else if ( 0 == strcasecmp(event,
"ALL_EVENTS") )
660 static char ret[1024];
664 if ( IN_ACCESS & events ) {
666 strncat(ret,
"ACCESS", 7);
668 if ( IN_MODIFY & events ) {
670 strncat(ret,
"MODIFY", 7);
672 if ( IN_ATTRIB & events ) {
674 strncat(ret,
"ATTRIB", 7);
676 if ( IN_CLOSE_WRITE & events ) {
678 strncat(ret,
"CLOSE_WRITE", 12);
680 if ( IN_CLOSE_NOWRITE & events ) {
682 strncat(ret,
"CLOSE_NOWRITE", 14);
684 if ( IN_OPEN & events ) {
686 strncat(ret,
"OPEN", 5);
688 if ( IN_MOVED_FROM & events ) {
690 strncat(ret,
"MOVED_FROM", 11);
692 if ( IN_MOVED_TO & events ) {
694 strncat(ret,
"MOVED_TO", 9);
696 if ( IN_CREATE & events ) {
698 strncat(ret,
"CREATE", 7);
700 if ( IN_DELETE & events ) {
702 strncat(ret,
"DELETE", 7);
704 if ( IN_DELETE_SELF & events ) {
706 strncat(ret,
"DELETE_SELF", 12);
708 if ( IN_UNMOUNT & events ) {
710 strncat(ret,
"UNMOUNT", 8);
712 if ( IN_Q_OVERFLOW & events ) {
714 strncat(ret,
"Q_OVERFLOW", 11);
716 if ( IN_IGNORED & events ) {
718 strncat(ret,
"IGNORED", 8);
720 if ( IN_CLOSE & events ) {
722 strncat(ret,
"CLOSE", 6);
724 if ( IN_MOVE_SELF & events ) {
726 strncat(ret,
"MOVE_SELF", 10);
728 if ( IN_ISDIR & events ) {
730 strncat(ret,
"ISDIR", 6);
732 if ( IN_ONESHOT & events ) {
734 strncat(ret,
"ONESHOT", 8);
738 if (ret[0] ==
'\0') {
739 niceassert( -1 != sprintf( ret,
"%c0x%08x", sep, events ), 0 );
751static const char* inotifytools_filename_from_fid(
752 struct fanotify_event_fid* fid) {
754 static char filename[PATH_MAX];
755 struct fanotify_event_fid fsid = {};
756 int dirf = 0, mount_fd = AT_FDCWD;
757 int len = 0, name_len = 0;
760 fsid.info.fsid.val[0] = fid->info.fsid.val[0];
761 fsid.info.fsid.val[1] = fid->info.fsid.val[1];
762 fsid.info.hdr.info_type = FAN_EVENT_INFO_TYPE_FID;
763 fsid.info.hdr.len =
sizeof(fsid);
764 watch* mnt = watch_from_fid(&fsid);
766 mount_fd = mnt->dirf;
768 if (fid->info.hdr.info_type == FAN_EVENT_INFO_TYPE_DFID_NAME) {
769 int fid_len =
sizeof(*fid) + fid->handle.handle_bytes;
771 name_len = fid->info.hdr.len - fid_len;
772 if (name_len && !fid->handle.f_handle[fid->handle.handle_bytes])
777 dirf = open_by_handle_at(mount_fd, &fid->handle, 0);
780 }
else if (fanotify_mark_type == FAN_MARK_FILESYSTEM) {
781 fprintf(stderr,
"Failed to decode directory fid.\n");
783 }
else if (name_len) {
785 fid->info.hdr.info_type = FAN_EVENT_INFO_TYPE_DFID;
786 fid->info.hdr.len -= name_len;
788 watch* w = watch_from_fid(fid);
790 fid->info.hdr.info_type = FAN_EVENT_INFO_TYPE_DFID_NAME;
791 fid->info.hdr.len += name_len;
795 "Failed to lookup path by directory fid.\n");
799 dirf = w->dirf ? dup(w->dirf) : -1;
801 fprintf(stderr,
"Failed to get directory fd.\n");
809 sprintf(sym,
"/proc/self/fd/%d", dirf);
813 len = readlink(sym, filename, PATH_MAX - 2);
816 fprintf(stderr,
"Failed to resolve path from directory fd.\n");
820 filename[len++] =
'/';
824 const char* name = (
const char*)fid->handle.f_handle +
825 fid->handle.handle_bytes;
826 int deleted = faccessat(dirf, name, F_OK, AT_SYMLINK_NOFOLLOW);
827 if (deleted && errno != ENOENT) {
828 fprintf(stderr,
"Failed to access file %s (%s).\n",
829 name, strerror(errno));
833 memcpy(filename + len, name, name_len);
835 strncat(filename,
" (deleted)", 11);
853 if (!w->fid || !fanotify_mark_type)
856 return inotifytools_filename_from_fid(w->fid) ?: w->filename;
880 niceassert(initialized,
"inotifytools_initialize not called yet");
883 watch *w = watch_from_wd(wd);
899 size_t* dirnamelen) {
901 const char* dirsep = NULL;
909 dirsep = strrchr(filename,
'/');
911 *dirnamelen = strlen(filename);
915 *dirnamelen = dirsep - filename + 1;
928 char const** eventname,
929 size_t* dirnamelen) {
931 *eventname =
event->name;
935 const char* filename =
939 if (filename && filename[*dirnamelen])
940 *eventname = filename + *dirnamelen;
956 if (!filename || !*filename || !(event->mask & IN_ISDIR)) {
965 nasprintf(&path,
"%s%s/", filename, fanotify_mode ?
"" :
event->name);
985 niceassert(initialized,
"inotifytools_initialize not called yet");
986 if (!filename || !*filename)
988 watch *w = watch_from_filename(filename);
1008 niceassert(initialized,
"inotifytools_initialize not called yet");
1009 watch *w = watch_from_wd(wd);
1011 if (w->filename) free(w->filename);
1012 w->filename = strdup(filename);
1030 char const * newname ) {
1031 watch *w = watch_from_filename(oldname);
1033 if (w->filename) free(w->filename);
1034 w->filename = strdup(newname);
1060 char const * newname ) {
1061 if (!oldname || !newname)
1063 if (!*oldname || !*newname)
1065 struct replace_filename_data data;
1066 data.old_name = oldname;
1067 data.new_name = newname;
1068 data.old_len = strlen(oldname);
1069 rbwalk(tree_filename, (
void *)replace_filename, (
void *)&data);
1075int remove_inotify_watch(watch *w) {
1080 int status = inotify_rm_watch( inotify_fd, w->wd );
1082 fprintf(stderr,
"Failed to remove watch on %s: %s\n", w->filename,
1093watch* create_watch(
int wd,
1094 struct fanotify_event_fid* fid,
1095 const char* filename,
1097 if (wd < 0 || !filename)
1100 watch *w = (watch*)calloc(1,
sizeof(watch));
1102 fprintf(stderr,
"Failed to allocate watch.\n");
1105 w->wd = wd ?: (
unsigned long)fid;
1108 w->filename = strdup(filename);
1109 rbsearch(w, tree_wd);
1111 rbsearch(w, tree_fid);
1113 rbsearch(w, tree_filename);
1130 niceassert(initialized,
"inotifytools_initialize not called yet");
1131 watch *w = watch_from_wd(wd);
1134 if (!remove_inotify_watch(w))
return 0;
1135 rbdelete(w, tree_wd);
1137 rbdelete(w, tree_fid);
1138 rbdelete(w, tree_filename);
1155 niceassert(initialized,
"inotifytools_initialize not called yet");
1156 watch *w = watch_from_filename(filename);
1159 if (!remove_inotify_watch(w))
return 0;
1160 rbdelete(w, tree_wd);
1162 rbdelete(w, tree_fid);
1163 rbdelete(w, tree_filename);
1180 static char const* filenames[2];
1181 filenames[0] = filename;
1182 filenames[1] = NULL;
1202 niceassert(initialized,
"inotifytools_initialize not called yet");
1206 for ( i = 0; filenames[i]; ++i ) {
1208 if (fanotify_mode) {
1209#ifdef LINUX_FANOTIFY
1210 unsigned int flags = FAN_MARK_ADD | fanotify_mark_type;
1212 if (events & IN_DONT_FOLLOW) {
1213 events &= ~IN_DONT_FOLLOW;
1214 flags |= FAN_MARK_DONT_FOLLOW;
1217 wd = fanotify_mark(inotify_fd, flags,
1218 events | FAN_EVENT_ON_CHILD,
1219 AT_FDCWD, filenames[i]);
1223 inotify_add_watch(inotify_fd, filenames[i], events);
1231 fprintf( stderr,
"Failed to watch %s: returned wd was %d "
1232 "(expected -1 or >0 )", filenames[i], wd );
1238 const char* filename = filenames[i];
1239 size_t filenamelen = strlen(filename);
1243 if (!isdir(filename)) {
1245 }
else if (filename[filenamelen - 1] ==
'/') {
1246 dirname = strdup(filename);
1248 nasprintf(&dirname,
"%s/", filename);
1253 struct fanotify_event_fid* fid = NULL;
1254#ifdef LINUX_FANOTIFY
1256 fid = calloc(1,
sizeof(*fid) + MAX_FID_LEN);
1258 fprintf(stderr,
"Failed to allocate fid");
1264 if (statfs(filenames[i], &buf)) {
1266 fprintf(stderr,
"Statfs failed on %s: %s\n",
1267 filenames[i], strerror(errno));
1271 memcpy(&fid->info.fsid, &buf.f_fsid,
1272 sizeof(__kernel_fsid_t));
1276 watch* mnt = dirname ? watch_from_fid(fid) : NULL;
1277 if (dirname && !mnt) {
1278 struct fanotify_event_fid* fsid;
1280 fsid = calloc(1,
sizeof(*fsid));
1284 "Failed to allocate fsid");
1288 fsid->info.fsid.val[0] = fid->info.fsid.val[0];
1289 fsid->info.fsid.val[1] = fid->info.fsid.val[1];
1290 fsid->info.hdr.info_type =
1291 FAN_EVENT_INFO_TYPE_FID;
1292 fsid->info.hdr.len =
sizeof(*fsid);
1293 mntid = open(dirname, O_RDONLY);
1298 "Failed to open %s: %s\n",
1299 dirname, strerror(errno));
1304 dirname[filenamelen - 1] = 0;
1305 create_watch(0, fsid, dirname, mntid);
1306 dirname[filenamelen - 1] =
'/';
1309 fid->handle.handle_bytes = MAX_FID_LEN;
1310 ret = name_to_handle_at(AT_FDCWD, filenames[i],
1311 (
void*)&fid->handle, &mntid, 0);
1312 if (ret || fid->handle.handle_bytes > MAX_FID_LEN) {
1314 fprintf(stderr,
"Encode fid failed on %s: %s\n",
1315 filenames[i], strerror(errno));
1319 fid->info.hdr.info_type = dirname
1320 ? FAN_EVENT_INFO_TYPE_DFID
1321 : FAN_EVENT_INFO_TYPE_FID;
1323 sizeof(*fid) + fid->handle.handle_bytes;
1325 dirf = open(dirname, O_PATH);
1329 "Failed to open %s: %s\n",
1330 dirname, strerror(errno));
1337 create_watch(wd, fid, filename, dirf);
1428 niceassert(initialized,
"inotifytools_initialize not called yet");
1429 niceassert( num_events <= MAX_EVENTS,
"too many events requested" );
1431 if ( num_events < 1 )
return NULL;
1434 static struct inotify_event event[2 * MAX_EVENTS];
1435 static struct inotify_event * ret;
1436 static int first_byte = 0;
1437 static ssize_t bytes;
1438 static ssize_t this_bytes;
1440 static struct nstring match_name;
1441 static char match_name_string[MAX_STRLEN+1];
1445 pid_t event_pid = 0;
1449 if ( first_byte != 0
1450 && first_byte <= (
int)(bytes -
sizeof(
struct inotify_event)) ) {
1452 ret = (
struct inotify_event *)((
char *)&
event[0] + first_byte);
1453 if (!fanotify_mode &&
1454 first_byte +
sizeof(*ret) + ret->len > bytes) {
1461 niceassert( (
long)((
char *)&event[0] +
1462 sizeof(
struct inotify_event) +
1463 event[0].len) <= (
long)ret,
1464 "extremely unlucky user, death imminent" );
1466 bytes = (
char *)&event[0] + bytes - (
char *)ret;
1467 memcpy( &event[0], ret, bytes );
1475 else if ( first_byte == 0 ) {
1480 static unsigned int bytes_to_read;
1482 static fd_set read_fds;
1484 static struct timeval read_timeout;
1485 read_timeout.tv_sec = timeout;
1486 read_timeout.tv_usec = 0;
1487 static struct timeval * read_timeout_ptr;
1488 read_timeout_ptr = ( timeout < 0 ? NULL : &read_timeout );
1491 FD_SET(inotify_fd, &read_fds);
1492 rc = select(inotify_fd + 1, &read_fds,
1493 NULL, NULL, read_timeout_ptr);
1499 else if ( rc == 0 ) {
1506 rc = ioctl( inotify_fd, FIONREAD, &bytes_to_read );
1508 bytes_to_read <
sizeof(
struct inotify_event)*num_events );
1515 this_bytes = read(inotify_fd, (
char*)&event[0] + bytes,
1516 sizeof(
struct inotify_event) * MAX_EVENTS - bytes);
1517 if ( this_bytes < 0 ) {
1521 if ( this_bytes == 0 ) {
1522 fprintf(stderr,
"Inotify reported end-of-file. Possibly too many "
1523 "events occurred at once.\n");
1527 ret = (
struct inotify_event*)((
char*)&
event[0] + first_byte);
1528#ifdef LINUX_FANOTIFY
1530 if (fanotify_mode) {
1531 struct fanotify_event_metadata* meta = (
void*)ret;
1532 struct fanotify_event_info_fid* info = (
void*)(meta + 1);
1533 struct fanotify_event_fid* fid = NULL;
1534 const char* name =
"";
1538 first_byte += meta->event_len;
1540 if (meta->event_len >
sizeof(*meta)) {
1541 switch (info->hdr.info_type) {
1542 case FAN_EVENT_INFO_TYPE_FID:
1543 case FAN_EVENT_INFO_TYPE_DFID:
1544 case FAN_EVENT_INFO_TYPE_DFID_NAME:
1546 fid_len =
sizeof(*fid) +
1547 fid->handle.handle_bytes;
1548 if (info->hdr.info_type ==
1549 FAN_EVENT_INFO_TYPE_DFID_NAME) {
1551 info->hdr.len - fid_len;
1556 fid->handle.f_handle +
1557 fid->handle.handle_bytes;
1566 (!*name || !strcmp(name,
"."))) {
1567 info->hdr.len -= name_len;
1574 fprintf(stderr,
"No fid in fanotify event.\n");
1577 if (verbosity > 1) {
1579 "fanotify_event: bytes=%zd, first_byte=%d, "
1580 "this_bytes=%zd, event_len=%u, fid_len=%d, "
1581 "name_len=%d, name=%s\n",
1582 bytes, first_byte, this_bytes, meta->event_len,
1583 fid_len, name_len, name);
1586 ret = &
event[MAX_EVENTS];
1587 watch* w = watch_from_fid(fid);
1589 struct fanotify_event_fid* newfid =
1590 calloc(1, info->hdr.len);
1592 fprintf(stderr,
"Failed to allocate fid.\n");
1595 memcpy(newfid, fid, info->hdr.len);
1596 const char* filename =
1597 inotifytools_filename_from_fid(fid);
1599 w = create_watch(0, newfid, filename, 0);
1608 memcpy((
void*)&
id, fid->handle.f_handle,
1610 printf(
"[fid=%x.%x.%lx;name='%s'] %s\n",
1611 fid->info.fsid.val[0],
1612 fid->info.fsid.val[1],
id, name,
1616 ret->wd = w ? w->wd : 0;
1617 ret->mask = (uint32_t)meta->mask;
1618 ret->len = name_len;
1620 memcpy(ret->name, name, name_len);
1621 event_pid = meta->pid;
1623 first_byte +=
sizeof(
struct inotify_event) + ret->len;
1627 bytes += this_bytes;
1628 niceassert( first_byte <= bytes,
"ridiculously long filename, things will "
1629 "almost certainly screw up." );
1630 if ( first_byte == bytes ) {
1635 if (self_pid && self_pid == event_pid) {
1641 memcpy(&match_name_string, &match_name.
buf, match_name.
len);
1642 match_name_string[match_name.
len] =
'\0';
1643 if (0 == regexec(regex, match_name_string, 0, 0, 0)) {
1652 if (collect_stats) {
1722 char const** exclude_list) {
1723 niceassert(initialized,
"inotifytools_initialize not called yet");
1728 dir = opendir( path );
1731 if ( errno == ENOTDIR ) {
1740 if ( path[strlen(path)-1] !=
'/' ) {
1741 nasprintf( &my_path,
"%s/", path );
1744 my_path = (
char *)path;
1747 static struct dirent * ent;
1749 static struct stat64 my_stat;
1750 ent = readdir( dir );
1753 if ( (0 != strcmp( ent->d_name,
"." )) &&
1754 (0 != strcmp( ent->d_name,
".." )) ) {
1755 nasprintf(&next_file,
"%s%s", my_path, ent->d_name);
1756 if ( -1 == lstat64( next_file, &my_stat ) ) {
1759 if ( errno != EACCES ) {
1761 if ( my_path != path ) free( my_path );
1766 else if ( S_ISDIR( my_stat.st_mode ) &&
1767 !S_ISLNK( my_stat.st_mode )) {
1769 nasprintf(&next_file,
"%s%s/", my_path, ent->d_name);
1770 static unsigned int no_watch;
1771 static char const** exclude_entry;
1774 for (exclude_entry = exclude_list;
1775 exclude_entry && *exclude_entry && !no_watch;
1777 static int exclude_length;
1779 exclude_length = strlen(*exclude_entry);
1780 if ((*exclude_entry)[exclude_length-1] ==
'/') {
1783 if ( strlen(next_file) == (
unsigned)(exclude_length + 1) &&
1784 !strncmp(*exclude_entry, next_file, exclude_length)) {
1796 if ( !status && (EACCES != error) && (ENOENT != error) &&
1797 (ELOOP != error) ) {
1799 if ( my_path != path ) free( my_path );
1810 ent = readdir( dir );
1817 if ( my_path != path ) free( my_path );
1838static int isdir(
char const * path ) {
1839 static struct stat64 my_stat;
1841 if ( -1 == lstat64( path, &my_stat ) ) {
1842 if (errno == ENOENT)
return 0;
1843 fprintf(stderr,
"Stat failed on %s: %s\n", path, strerror(errno));
1847 return S_ISDIR( my_stat.st_mode ) && !S_ISLNK( my_stat.st_mode );
1859 rbwalk(tree_filename, get_num, (
void*)&ret);
1960 if ( -1 != ret ) fwrite( out.
buf,
sizeof(
char), out.
len, file );
2072 struct inotify_event* event,
char* fmt ) {
2073 const char* eventstr;
2074 static unsigned int i, ind;
2076 static char timestr[MAX_STRLEN];
2079 size_t dirnamelen = 0;
2080 const char* eventname;
2081 const char* filename =
2084 if ( !fmt || 0 == strlen(fmt) ) {
2088 if ( strlen(fmt) > MAX_STRLEN || size > MAX_STRLEN) {
2094 for ( i = 0; i < strlen(fmt) &&
2095 (int)ind < size - 1; ++i ) {
2096 if ( fmt[i] !=
'%' ) {
2097 out->
buf[ind++] = fmt[i];
2101 if ( i == strlen(fmt) - 1 ) {
2110 out->
buf[ind++] =
'%';
2116 out->
buf[ind++] =
'\0';
2122 out->
buf[ind++] =
'\n';
2128 if (filename && dirnamelen <= size - ind) {
2129 strncpy(&out->
buf[ind], filename, dirnamelen);
2138 strncpy( &out->
buf[ind], eventname, size - ind );
2139 ind += strlen(eventname);
2146 ind += snprintf( &out->
buf[ind], size-ind,
"%x", event->cookie);
2153 strncpy( &out->
buf[ind], eventstr, size - ind );
2154 ind += strlen(eventstr);
2164 if (!strftime(timestr, MAX_STRLEN - 1, timefmt,
2165 localtime_r(&now, &now_tm))) {
2175 strncpy( &out->
buf[ind], timestr, size - ind );
2176 ind += strlen(timestr);
2182 if ( i < strlen(fmt) - 2 && fmt[i+2] ==
'e' ) {
2184 strncpy( &out->
buf[ind], eventstr, size - ind );
2185 ind += strlen(eventstr);
2191 if ( ind < MAX_STRLEN ) out->
buf[ind++] =
'%';
2192 if ( ind < MAX_STRLEN ) out->
buf[ind++] = ch1;
2223 if ( !read_num_from_file( QUEUE_SIZE_PATH, &ret ) )
return -1;
2238 if ( !read_num_from_file( INSTANCES_PATH, &ret ) )
return -1;
2253 if ( !read_num_from_file( WATCHES_SIZE_PATH, &ret ) )
return -1;
2270static int do_ignore_events_by_regex(
char const *pattern,
int flags,
int invert ) {
2280 if (regex) { regfree(regex); }
2281 else { regex = (regex_t *)malloc(
sizeof(regex_t)); }
2283 invert_regexp = invert;
2284 int ret = regcomp(regex, pattern, flags | REG_NOSUB);
2285 if (0 == ret)
return 1;
2306 return do_ignore_events_by_regex(pattern, flags, 0);
2321 return do_ignore_events_by_regex(pattern, flags, 1);
2324int event_compare(
const void *p1,
const void *p2,
const void *config)
2326 if (!p1 || !p2)
return p1 - p2;
2328 long sort_event = (long)config;
2329 if (sort_event == -1) {
2332 }
else if (sort_event < 0) {
2333 sort_event = -sort_event;
2336 unsigned int *i1 = stat_ptr((watch*)p1, sort_event);
2337 unsigned int *i2 = stat_ptr((watch*)p2, sort_event);
2338 if (0 == *i1 - *i2) {
2339 return ((watch*)p1)->wd - ((watch*)p2)->wd;
2347struct rbtree *inotifytools_wd_sorted_by_event(
int sort_event)
2349 struct rbtree *ret = rbinit(event_compare, (
void*)(uintptr_t)sort_event);
2350 RBLIST *all = rbopenlist(tree_wd);
2351 void const *p = rbreadlist(all);
2353 void const *r = rbsearch(p, ret);
2354 niceassert((
int)(r == p),
"Couldn't insert watch into new tree");
2355 p = rbreadlist(all);
This structure holds string that can contain any character including NULL.