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);
312 watch_filesystem ? FAN_MARK_FILESYSTEM : FAN_MARK_INODE;
314 fanotify_init(FAN_REPORT_FID | FAN_REPORT_DFID_NAME, 0);
318 inotify_fd = inotify_init();
320 if (inotify_fd < 0) {
327 tree_wd = rbinit(wd_compare, 0);
328 tree_fid = rbinit(fid_compare, 0);
329 tree_filename = rbinit(filename_compare, 0);
335int inotifytools_initialize() {
342void destroy_watch(watch *w) {
343 if (w->filename) free(w->filename);
354void cleanup_tree(
const void *nodep,
356 const int depth,
void* arg) {
357 if (which != endorder && which != leaf)
return;
358 watch *w = (watch*)nodep;
383 rbwalk(tree_wd, cleanup_tree, 0);
386 rbdestroy(tree_filename);
397struct replace_filename_data {
398 char const *old_name;
399 char const *new_name;
406static void replace_filename(
const void* nodep,
409 const struct replace_filename_data* data) {
410 if (which != endorder && which != leaf)
412 watch *w = (watch*)nodep;
414 if ( 0 == strncmp( data->old_name, w->filename, data->old_len ) ) {
415 nasprintf( &name,
"%s%s", data->new_name, &(w->filename[data->old_len]) );
416 if (!strcmp( w->filename, data->new_name )) {
419 rbdelete(w, tree_filename);
422 rbsearch(w, tree_filename);
430static void get_num(
const void* nodep,
434 if (which != endorder && which != leaf)
467 if ( strchr(
"_" "abcdefghijklmnopqrstuvwxyz"
468 "ABCDEFGHIJKLMNOPQRSTUVWXYZ", sep ) ) {
473 char * event1, * event2;
474 static const size_t eventstr_size = 4096;
475 char eventstr[eventstr_size];
478 if ( !event || !event[0] )
return 0;
480 event1 = (
char *)event;
481 event2 = strchr( event1, sep );
482 while ( event1 && event1[0] ) {
484 len = event2 - event1;
485 niceassert(len < eventstr_size,
486 "malformed event string (very long)");
489 len = strlen(event1);
491 if (len > eventstr_size - 1)
492 len = eventstr_size - 1;
494 strncpy(eventstr, event1, len);
498 int ret1 = onestr_to_event(eventstr);
499 if ( 0 == ret1 || -1 == ret1 ) {
506 if ( event1 && event1[0] ) {
510 if ( !event1[0] )
return 0;
511 event2 = strchr( event1, sep );
556int onestr_to_event(
char const * event)
561 if ( !event || !event[0] )
563 else if ( 0 == strcasecmp(event,
"ACCESS") )
565 else if ( 0 == strcasecmp(event,
"MODIFY") )
567 else if ( 0 == strcasecmp(event,
"ATTRIB") )
569 else if ( 0 == strcasecmp(event,
"CLOSE_WRITE") )
570 ret = IN_CLOSE_WRITE;
571 else if ( 0 == strcasecmp(event,
"CLOSE_NOWRITE") )
572 ret = IN_CLOSE_NOWRITE;
573 else if ( 0 == strcasecmp(event,
"OPEN") )
575 else if ( 0 == strcasecmp(event,
"MOVED_FROM") )
577 else if ( 0 == strcasecmp(event,
"MOVED_TO") )
579 else if ( 0 == strcasecmp(event,
"CREATE") )
581 else if ( 0 == strcasecmp(event,
"DELETE") )
583 else if ( 0 == strcasecmp(event,
"DELETE_SELF") )
584 ret = IN_DELETE_SELF;
585 else if ( 0 == strcasecmp(event,
"UNMOUNT") )
587 else if ( 0 == strcasecmp(event,
"Q_OVERFLOW") )
589 else if ( 0 == strcasecmp(event,
"IGNORED") )
591 else if ( 0 == strcasecmp(event,
"CLOSE") )
593 else if ( 0 == strcasecmp(event,
"MOVE_SELF") )
595 else if ( 0 == strcasecmp(event,
"MOVE") )
597 else if ( 0 == strcasecmp(event,
"ISDIR") )
599 else if ( 0 == strcasecmp(event,
"ONESHOT") )
601 else if ( 0 == strcasecmp(event,
"ALL_EVENTS") )
658 static char ret[1024];
662 if ( IN_ACCESS & events ) {
664 strncat(ret,
"ACCESS", 7);
666 if ( IN_MODIFY & events ) {
668 strncat(ret,
"MODIFY", 7);
670 if ( IN_ATTRIB & events ) {
672 strncat(ret,
"ATTRIB", 7);
674 if ( IN_CLOSE_WRITE & events ) {
676 strncat(ret,
"CLOSE_WRITE", 12);
678 if ( IN_CLOSE_NOWRITE & events ) {
680 strncat(ret,
"CLOSE_NOWRITE", 14);
682 if ( IN_OPEN & events ) {
684 strncat(ret,
"OPEN", 5);
686 if ( IN_MOVED_FROM & events ) {
688 strncat(ret,
"MOVED_FROM", 11);
690 if ( IN_MOVED_TO & events ) {
692 strncat(ret,
"MOVED_TO", 9);
694 if ( IN_CREATE & events ) {
696 strncat(ret,
"CREATE", 7);
698 if ( IN_DELETE & events ) {
700 strncat(ret,
"DELETE", 7);
702 if ( IN_DELETE_SELF & events ) {
704 strncat(ret,
"DELETE_SELF", 12);
706 if ( IN_UNMOUNT & events ) {
708 strncat(ret,
"UNMOUNT", 8);
710 if ( IN_Q_OVERFLOW & events ) {
712 strncat(ret,
"Q_OVERFLOW", 11);
714 if ( IN_IGNORED & events ) {
716 strncat(ret,
"IGNORED", 8);
718 if ( IN_CLOSE & events ) {
720 strncat(ret,
"CLOSE", 6);
722 if ( IN_MOVE_SELF & events ) {
724 strncat(ret,
"MOVE_SELF", 10);
726 if ( IN_ISDIR & events ) {
728 strncat(ret,
"ISDIR", 6);
730 if ( IN_ONESHOT & events ) {
732 strncat(ret,
"ONESHOT", 8);
736 if (ret[0] ==
'\0') {
737 niceassert( -1 != sprintf( ret,
"%c0x%08x", sep, events ), 0 );
749static const char* inotifytools_filename_from_fid(
750 struct fanotify_event_fid* fid) {
752 static char filename[PATH_MAX];
753 struct fanotify_event_fid fsid = {};
754 int dirf = 0, mount_fd = AT_FDCWD;
755 int len = 0, name_len = 0;
758 fsid.info.fsid.val[0] = fid->info.fsid.val[0];
759 fsid.info.fsid.val[1] = fid->info.fsid.val[1];
760 fsid.info.hdr.info_type = FAN_EVENT_INFO_TYPE_FID;
761 fsid.info.hdr.len =
sizeof(fsid);
762 watch* mnt = watch_from_fid(&fsid);
764 mount_fd = mnt->dirf;
766 if (fid->info.hdr.info_type == FAN_EVENT_INFO_TYPE_DFID_NAME) {
767 int fid_len =
sizeof(*fid) + fid->handle.handle_bytes;
769 name_len = fid->info.hdr.len - fid_len;
770 if (name_len && !fid->handle.f_handle[fid->handle.handle_bytes])
775 dirf = open_by_handle_at(mount_fd, &fid->handle, 0);
778 }
else if (fanotify_mark_type == FAN_MARK_FILESYSTEM) {
779 fprintf(stderr,
"Failed to decode directory fid.\n");
781 }
else if (name_len) {
783 fid->info.hdr.info_type = FAN_EVENT_INFO_TYPE_DFID;
784 fid->info.hdr.len -= name_len;
786 watch* w = watch_from_fid(fid);
788 fid->info.hdr.info_type = FAN_EVENT_INFO_TYPE_DFID_NAME;
789 fid->info.hdr.len += name_len;
793 "Failed to lookup path by directory fid.\n");
797 dirf = w->dirf ? dup(w->dirf) : -1;
799 fprintf(stderr,
"Failed to get directory fd.\n");
807 sprintf(sym,
"/proc/self/fd/%d", dirf);
811 len = readlink(sym, filename, PATH_MAX - 2);
814 fprintf(stderr,
"Failed to resolve path from directory fd.\n");
818 filename[len++] =
'/';
822 const char* name = (
const char*)fid->handle.f_handle +
823 fid->handle.handle_bytes;
824 int deleted = faccessat(dirf, name, F_OK, AT_SYMLINK_NOFOLLOW);
825 if (deleted && errno != ENOENT) {
826 fprintf(stderr,
"Failed to access file %s (%s).\n",
827 name, strerror(errno));
831 memcpy(filename + len, name, name_len);
833 strncat(filename,
" (deleted)", 11);
851 if (!w->fid || !fanotify_mark_type)
854 return inotifytools_filename_from_fid(w->fid) ?: w->filename;
878 niceassert( init,
"inotifytools_initialize not called yet" );
881 watch *w = watch_from_wd(wd);
897 size_t* dirnamelen) {
899 const char* dirsep = NULL;
907 dirsep = strrchr(filename,
'/');
909 *dirnamelen = strlen(filename);
913 *dirnamelen = dirsep - filename + 1;
926 char const** eventname,
927 size_t* dirnamelen) {
929 *eventname =
event->name;
933 const char* filename =
937 if (filename && filename[*dirnamelen])
938 *eventname = filename + *dirnamelen;
954 if (!filename || !*filename || !(event->mask & IN_ISDIR)) {
963 nasprintf(&path,
"%s%s/", filename, fanotify_mode ?
"" : event->name);
983 niceassert( init,
"inotifytools_initialize not called yet" );
984 if (!filename || !*filename)
986 watch *w = watch_from_filename(filename);
1006 niceassert( init,
"inotifytools_initialize not called yet" );
1007 watch *w = watch_from_wd(wd);
1009 if (w->filename) free(w->filename);
1010 w->filename = strdup(filename);
1028 char const * newname ) {
1029 watch *w = watch_from_filename(oldname);
1031 if (w->filename) free(w->filename);
1032 w->filename = strdup(newname);
1058 char const * newname ) {
1059 if (!oldname || !newname)
1061 if (!*oldname || !*newname)
1063 struct replace_filename_data data;
1064 data.old_name = oldname;
1065 data.new_name = newname;
1066 data.old_len = strlen(oldname);
1067 rbwalk(tree_filename, (
void *)replace_filename, (
void *)&data);
1073int remove_inotify_watch(watch *w) {
1078 int status = inotify_rm_watch( inotify_fd, w->wd );
1080 fprintf(stderr,
"Failed to remove watch on %s: %s\n", w->filename,
1091watch* create_watch(
int wd,
1092 struct fanotify_event_fid* fid,
1093 const char* filename,
1095 if (wd < 0 || !filename)
1098 watch *w = (watch*)calloc(1,
sizeof(watch));
1100 fprintf(stderr,
"Failed to allocate watch.\n");
1103 w->wd = wd ?: (
unsigned long)fid;
1106 w->filename = strdup(filename);
1107 rbsearch(w, tree_wd);
1109 rbsearch(w, tree_fid);
1111 rbsearch(w, tree_filename);
1128 niceassert( init,
"inotifytools_initialize not called yet" );
1129 watch *w = watch_from_wd(wd);
1132 if (!remove_inotify_watch(w))
return 0;
1133 rbdelete(w, tree_wd);
1135 rbdelete(w, tree_fid);
1136 rbdelete(w, tree_filename);
1153 niceassert( init,
"inotifytools_initialize not called yet" );
1154 watch *w = watch_from_filename(filename);
1157 if (!remove_inotify_watch(w))
return 0;
1158 rbdelete(w, tree_wd);
1160 rbdelete(w, tree_fid);
1161 rbdelete(w, tree_filename);
1178 static char const* filenames[2];
1179 filenames[0] = filename;
1180 filenames[1] = NULL;
1200 niceassert( init,
"inotifytools_initialize not called yet" );
1204 for ( i = 0; filenames[i]; ++i ) {
1206 if (fanotify_mode) {
1207#ifdef LINUX_FANOTIFY
1208 unsigned int flags = FAN_MARK_ADD | fanotify_mark_type;
1210 if (events & IN_DONT_FOLLOW) {
1211 events &= ~IN_DONT_FOLLOW;
1212 flags |= FAN_MARK_DONT_FOLLOW;
1215 wd = fanotify_mark(inotify_fd, flags,
1216 events | FAN_EVENT_ON_CHILD,
1217 AT_FDCWD, filenames[i]);
1221 inotify_add_watch(inotify_fd, filenames[i], events);
1229 fprintf( stderr,
"Failed to watch %s: returned wd was %d "
1230 "(expected -1 or >0 )", filenames[i], wd );
1236 const char* filename = filenames[i];
1237 size_t filenamelen = strlen(filename);
1241 if (!isdir(filename)) {
1243 }
else if (filename[filenamelen - 1] ==
'/') {
1244 dirname = strdup(filename);
1246 nasprintf(&dirname,
"%s/", filename);
1251 struct fanotify_event_fid* fid = NULL;
1252#ifdef LINUX_FANOTIFY
1254 fid = calloc(1,
sizeof(*fid) + MAX_FID_LEN);
1256 fprintf(stderr,
"Failed to allocate fid");
1262 if (statfs(filenames[i], &buf)) {
1264 fprintf(stderr,
"Statfs failed on %s: %s\n",
1265 filenames[i], strerror(errno));
1269 memcpy(&fid->info.fsid, &buf.f_fsid,
1270 sizeof(__kernel_fsid_t));
1274 watch* mnt = dirname ? watch_from_fid(fid) : NULL;
1275 if (dirname && !mnt) {
1276 struct fanotify_event_fid* fsid;
1278 fsid = calloc(1,
sizeof(*fsid));
1282 "Failed to allocate fsid");
1286 fsid->info.fsid.val[0] = fid->info.fsid.val[0];
1287 fsid->info.fsid.val[1] = fid->info.fsid.val[1];
1288 fsid->info.hdr.info_type =
1289 FAN_EVENT_INFO_TYPE_FID;
1290 fsid->info.hdr.len =
sizeof(*fsid);
1291 mntid = open(dirname, O_RDONLY);
1296 "Failed to open %s: %s\n",
1297 dirname, strerror(errno));
1302 dirname[filenamelen - 1] = 0;
1303 create_watch(0, fsid, dirname, mntid);
1304 dirname[filenamelen - 1] =
'/';
1307 fid->handle.handle_bytes = MAX_FID_LEN;
1308 ret = name_to_handle_at(AT_FDCWD, filenames[i],
1309 (
void*)&fid->handle, &mntid, 0);
1310 if (ret || fid->handle.handle_bytes > MAX_FID_LEN) {
1312 fprintf(stderr,
"Encode fid failed on %s: %s\n",
1313 filenames[i], strerror(errno));
1317 fid->info.hdr.info_type = dirname
1318 ? FAN_EVENT_INFO_TYPE_DFID
1319 : FAN_EVENT_INFO_TYPE_FID;
1321 sizeof(*fid) + fid->handle.handle_bytes;
1323 dirf = open(dirname, O_PATH);
1327 "Failed to open %s: %s\n",
1328 dirname, strerror(errno));
1335 create_watch(wd, fid, filename, dirf);
1426 niceassert( init,
"inotifytools_initialize not called yet" );
1427 niceassert( num_events <= MAX_EVENTS,
"too many events requested" );
1429 if ( num_events < 1 )
return NULL;
1432 static struct inotify_event event[2 * MAX_EVENTS];
1433 static struct inotify_event * ret;
1434 static int first_byte = 0;
1435 static ssize_t bytes;
1436 static ssize_t this_bytes;
1438 static struct nstring match_name;
1439 static char match_name_string[MAX_STRLEN+1];
1443 pid_t event_pid = 0;
1447 if ( first_byte != 0
1448 && first_byte <= (
int)(bytes -
sizeof(
struct inotify_event)) ) {
1450 ret = (
struct inotify_event *)((
char *)&
event[0] + first_byte);
1451 if (!fanotify_mode &&
1452 first_byte +
sizeof(*ret) + ret->len > bytes) {
1459 niceassert( (
long)((
char *)&event[0] +
1460 sizeof(
struct inotify_event) +
1461 event[0].len) <= (
long)ret,
1462 "extremely unlucky user, death imminent" );
1464 bytes = (
char *)&event[0] + bytes - (
char *)ret;
1465 memcpy( &event[0], ret, bytes );
1473 else if ( first_byte == 0 ) {
1478 static unsigned int bytes_to_read;
1480 static fd_set read_fds;
1482 static struct timeval read_timeout;
1483 read_timeout.tv_sec = timeout;
1484 read_timeout.tv_usec = 0;
1485 static struct timeval * read_timeout_ptr;
1486 read_timeout_ptr = ( timeout < 0 ? NULL : &read_timeout );
1489 FD_SET(inotify_fd, &read_fds);
1490 rc = select(inotify_fd + 1, &read_fds,
1491 NULL, NULL, read_timeout_ptr);
1497 else if ( rc == 0 ) {
1504 rc = ioctl( inotify_fd, FIONREAD, &bytes_to_read );
1506 bytes_to_read <
sizeof(
struct inotify_event)*num_events );
1513 this_bytes = read(inotify_fd, (
char*)&event[0] + bytes,
1514 sizeof(
struct inotify_event) * MAX_EVENTS - bytes);
1515 if ( this_bytes < 0 ) {
1519 if ( this_bytes == 0 ) {
1520 fprintf(stderr,
"Inotify reported end-of-file. Possibly too many "
1521 "events occurred at once.\n");
1525 ret = (
struct inotify_event*)((
char*)&
event[0] + first_byte);
1526#ifdef LINUX_FANOTIFY
1528 if (fanotify_mode) {
1529 struct fanotify_event_metadata* meta = (
void*)ret;
1530 struct fanotify_event_info_fid* info = (
void*)(meta + 1);
1531 struct fanotify_event_fid* fid = NULL;
1532 const char* name =
"";
1536 first_byte += meta->event_len;
1538 if (meta->event_len >
sizeof(*meta)) {
1539 switch (info->hdr.info_type) {
1540 case FAN_EVENT_INFO_TYPE_FID:
1541 case FAN_EVENT_INFO_TYPE_DFID:
1542 case FAN_EVENT_INFO_TYPE_DFID_NAME:
1544 fid_len =
sizeof(*fid) +
1545 fid->handle.handle_bytes;
1546 if (info->hdr.info_type ==
1547 FAN_EVENT_INFO_TYPE_DFID_NAME) {
1549 info->hdr.len - fid_len;
1554 fid->handle.f_handle +
1555 fid->handle.handle_bytes;
1564 (!*name || !strcmp(name,
"."))) {
1565 info->hdr.len -= name_len;
1572 fprintf(stderr,
"No fid in fanotify event.\n");
1575 if (verbosity > 1) {
1577 "fanotify_event: bytes=%zd, first_byte=%d, "
1578 "this_bytes=%zd, event_len=%u, fid_len=%d, "
1579 "name_len=%d, name=%s\n",
1580 bytes, first_byte, this_bytes, meta->event_len,
1581 fid_len, name_len, name);
1584 ret = &
event[MAX_EVENTS];
1585 watch* w = watch_from_fid(fid);
1587 struct fanotify_event_fid* newfid =
1588 calloc(1, info->hdr.len);
1590 fprintf(stderr,
"Failed to allocate fid.\n");
1593 memcpy(newfid, fid, info->hdr.len);
1594 const char* filename =
1595 inotifytools_filename_from_fid(fid);
1597 w = create_watch(0, newfid, filename, 0);
1606 memcpy((
void*)&
id, fid->handle.f_handle,
1608 printf(
"[fid=%x.%x.%lx;name='%s'] %s\n",
1609 fid->info.fsid.val[0],
1610 fid->info.fsid.val[1],
id, name,
1614 ret->wd = w ? w->wd : 0;
1615 ret->mask = (uint32_t)meta->mask;
1616 ret->len = name_len;
1618 memcpy(ret->name, name, name_len);
1619 event_pid = meta->pid;
1621 first_byte +=
sizeof(
struct inotify_event) + ret->len;
1625 bytes += this_bytes;
1626 niceassert( first_byte <= bytes,
"ridiculously long filename, things will "
1627 "almost certainly screw up." );
1628 if ( first_byte == bytes ) {
1633 if (self_pid && self_pid == event_pid) {
1639 memcpy(&match_name_string, &match_name.
buf, match_name.
len);
1640 match_name_string[match_name.
len] =
'\0';
1641 if (0 == regexec(regex, match_name_string, 0, 0, 0)) {
1650 if (collect_stats) {
1720 char const** exclude_list) {
1721 niceassert( init,
"inotifytools_initialize not called yet" );
1726 dir = opendir( path );
1729 if ( errno == ENOTDIR ) {
1738 if ( path[strlen(path)-1] !=
'/' ) {
1739 nasprintf( &my_path,
"%s/", path );
1742 my_path = (
char *)path;
1745 static struct dirent * ent;
1747 static struct stat64 my_stat;
1748 ent = readdir( dir );
1751 if ( (0 != strcmp( ent->d_name,
"." )) &&
1752 (0 != strcmp( ent->d_name,
".." )) ) {
1753 nasprintf(&next_file,
"%s%s", my_path, ent->d_name);
1754 if ( -1 == lstat64( next_file, &my_stat ) ) {
1757 if ( errno != EACCES ) {
1759 if ( my_path != path ) free( my_path );
1764 else if ( S_ISDIR( my_stat.st_mode ) &&
1765 !S_ISLNK( my_stat.st_mode )) {
1767 nasprintf(&next_file,
"%s%s/", my_path, ent->d_name);
1768 static unsigned int no_watch;
1769 static char const** exclude_entry;
1772 for (exclude_entry = exclude_list;
1773 exclude_entry && *exclude_entry && !no_watch;
1775 static int exclude_length;
1777 exclude_length = strlen(*exclude_entry);
1778 if ((*exclude_entry)[exclude_length-1] ==
'/') {
1781 if ( strlen(next_file) == (
unsigned)(exclude_length + 1) &&
1782 !strncmp(*exclude_entry, next_file, exclude_length)) {
1794 if ( !status && (EACCES != error) && (ENOENT != error) &&
1795 (ELOOP != error) ) {
1797 if ( my_path != path ) free( my_path );
1808 ent = readdir( dir );
1815 if ( my_path != path ) free( my_path );
1836static int isdir(
char const * path ) {
1837 static struct stat64 my_stat;
1839 if ( -1 == lstat64( path, &my_stat ) ) {
1840 if (errno == ENOENT)
return 0;
1841 fprintf(stderr,
"Stat failed on %s: %s\n", path, strerror(errno));
1845 return S_ISDIR( my_stat.st_mode ) && !S_ISLNK( my_stat.st_mode );
1857 rbwalk(tree_filename, get_num, (
void*)&ret);
1958 if ( -1 != ret ) fwrite( out.
buf,
sizeof(
char), out.
len, file );
2070 struct inotify_event* event,
char* fmt ) {
2071 const char* eventstr;
2072 static unsigned int i, ind;
2074 static char timestr[MAX_STRLEN];
2077 size_t dirnamelen = 0;
2078 const char* eventname;
2079 const char* filename =
2082 if ( !fmt || 0 == strlen(fmt) ) {
2086 if ( strlen(fmt) > MAX_STRLEN || size > MAX_STRLEN) {
2092 for ( i = 0; i < strlen(fmt) &&
2093 (int)ind < size - 1; ++i ) {
2094 if ( fmt[i] !=
'%' ) {
2095 out->
buf[ind++] = fmt[i];
2099 if ( i == strlen(fmt) - 1 ) {
2108 out->
buf[ind++] =
'%';
2114 out->
buf[ind++] =
'\0';
2120 out->
buf[ind++] =
'\n';
2126 if (filename && dirnamelen <= size - ind) {
2127 strncpy(&out->
buf[ind], filename, dirnamelen);
2136 strncpy( &out->
buf[ind], eventname, size - ind );
2137 ind += strlen(eventname);
2144 ind += snprintf( &out->
buf[ind], size-ind,
"%x", event->cookie);
2151 strncpy( &out->
buf[ind], eventstr, size - ind );
2152 ind += strlen(eventstr);
2162 if (!strftime(timestr, MAX_STRLEN - 1, timefmt,
2163 localtime_r(&now, &now_tm))) {
2173 strncpy( &out->
buf[ind], timestr, size - ind );
2174 ind += strlen(timestr);
2180 if ( i < strlen(fmt) - 2 && fmt[i+2] ==
'e' ) {
2182 strncpy( &out->
buf[ind], eventstr, size - ind );
2183 ind += strlen(eventstr);
2189 if ( ind < MAX_STRLEN ) out->
buf[ind++] =
'%';
2190 if ( ind < MAX_STRLEN ) out->
buf[ind++] = ch1;
2221 if ( !read_num_from_file( QUEUE_SIZE_PATH, &ret ) )
return -1;
2236 if ( !read_num_from_file( INSTANCES_PATH, &ret ) )
return -1;
2251 if ( !read_num_from_file( WATCHES_SIZE_PATH, &ret ) )
return -1;
2268static int do_ignore_events_by_regex(
char const *pattern,
int flags,
int invert ) {
2278 if (regex) { regfree(regex); }
2279 else { regex = (regex_t *)malloc(
sizeof(regex_t)); }
2281 invert_regexp = invert;
2282 int ret = regcomp(regex, pattern, flags | REG_NOSUB);
2283 if (0 == ret)
return 1;
2304 return do_ignore_events_by_regex(pattern, flags, 0);
2319 return do_ignore_events_by_regex(pattern, flags, 1);
2322int event_compare(
const void *p1,
const void *p2,
const void *config)
2324 if (!p1 || !p2)
return p1 - p2;
2326 long sort_event = (long)config;
2327 if (sort_event == -1) {
2330 }
else if (sort_event < 0) {
2331 sort_event = -sort_event;
2334 unsigned int *i1 = stat_ptr((watch*)p1, sort_event);
2335 unsigned int *i2 = stat_ptr((watch*)p2, sort_event);
2336 if (0 == *i1 - *i2) {
2337 return ((watch*)p1)->wd - ((watch*)p2)->wd;
2345struct rbtree *inotifytools_wd_sorted_by_event(
int sort_event)
2347 struct rbtree *ret = rbinit(event_compare, (
void*)(uintptr_t)sort_event);
2348 RBLIST *all = rbopenlist(tree_wd);
2349 void const *p = rbreadlist(all);
2351 void const *r = rbsearch(p, ret);
2352 niceassert((
int)(r == p),
"Couldn't insert watch into new tree");
2353 p = rbreadlist(all);
This structure holds string that can contain any character including NULL.