15 #include "../../config.h"
17 #include "inotifytools_p.h"
26 #include <sys/select.h>
27 #include <sys/types.h>
29 #include <sys/ioctl.h>
36 #include "inotifytools/inotify.h"
39 struct fanotify_event_fid;
41 #define FAN_EVENT_INFO_TYPE_FID 1
42 #define FAN_EVENT_INFO_TYPE_DFID_NAME 2
43 #define FAN_EVENT_INFO_TYPE_DFID 3
47 #define LINUX_FANOTIFY
51 #include "inotifytools/fanotify.h"
53 struct fanotify_event_fid {
54 struct fanotify_event_info_fid info;
55 struct file_handle handle;
145 #define MAX_EVENTS 4096
146 #define INOTIFY_PROCDIR "/proc/sys/fs/inotify/"
147 #define WATCHES_SIZE_PATH INOTIFY_PROCDIR "max_user_watches"
148 #define QUEUE_SIZE_PATH INOTIFY_PROCDIR "max_queued_watches"
149 #define INSTANCES_PATH INOTIFY_PROCDIR "max_user_instances"
151 static int inotify_fd = -1;
153 int collect_stats = 0;
155 struct rbtree *tree_wd = 0;
156 struct rbtree* tree_fid = 0;
157 struct rbtree *tree_filename = 0;
158 static int error = 0;
161 int fanotify_mode = 0;
162 int fanotify_mark_type = 0;
163 static char* timefmt = 0;
164 static regex_t* regex = 0;
166 static int invert_regexp = 0;
168 static int isdir(
char const * path );
169 void record_stats(
struct inotify_event
const * event );
170 int onestr_to_event(
char const * event);
172 #define nasprintf(...) niceassert( -1 != asprintf(__VA_ARGS__), "out of memory")
191 void _niceassert(
long cond,
int line,
char const * file,
192 char const * condstr,
char const * mesg ) {
196 fprintf(stderr,
"%s:%d assertion ( %s ) failed: %s\n", file, line,
200 fprintf(stderr,
"%s:%d assertion ( %s ) failed.\n", file, line, condstr);
204 static void charcat(
char* s,
const char c) {
205 size_t l = strlen(s);
213 static int read_num_from_file(
char* filename,
int* num) {
214 FILE * file = fopen( filename,
"r" );
220 if ( EOF == fscanf( file,
"%d", num ) ) {
222 const int fclose_ret = fclose(file);
223 niceassert(!fclose_ret, 0);
227 const int fclose_ret = fclose(file);
228 niceassert(!fclose_ret, 0);
233 static int wd_compare(
const void* d1,
const void* d2,
const void* config) {
234 if (!d1 || !d2)
return d1 - d2;
235 return ((watch*)d1)->wd - ((watch*)d2)->wd;
238 static int fid_compare(
const void* d1,
const void* d2,
const void* config) {
239 #ifdef LINUX_FANOTIFY
242 watch* w1 = (watch*)d1;
243 watch* w2 = (watch*)d2;
245 n1 = w1->fid->info.hdr.len;
246 n2 = w2->fid->info.hdr.len;
249 return memcmp(w1->fid, w2->fid, n1);
255 static int filename_compare(
const void* d1,
257 const void* config) {
258 if (!d1 || !d2)
return d1 - d2;
259 return strcmp(((watch*)d1)->filename, ((watch*)d2)->filename);
265 watch *watch_from_wd(
int wd ) {
268 return (watch*)rbfind(&w, tree_wd);
274 watch* watch_from_fid(
struct fanotify_event_fid* fid) {
277 return (watch*)rbfind(&w, tree_fid);
283 watch *watch_from_filename(
char const *filename ) {
285 w.filename = (
char*)filename;
286 return (watch*)rbfind(&w, tree_filename);
306 #ifdef LINUX_FANOTIFY
309 watch_filesystem ? FAN_MARK_FILESYSTEM : FAN_MARK_INODE;
311 fanotify_init(FAN_REPORT_FID | FAN_REPORT_DFID_NAME, 0);
315 inotify_fd = inotify_init();
317 if (inotify_fd < 0) {
324 tree_wd = rbinit(wd_compare, 0);
325 tree_fid = rbinit(fid_compare, 0);
326 tree_filename = rbinit(filename_compare, 0);
332 int inotifytools_initialize() {
339 void destroy_watch(watch *w) {
340 if (w->filename) free(w->filename);
351 void cleanup_tree(
const void *nodep,
353 const int depth,
void* arg) {
354 if (which != endorder && which != leaf)
return;
355 watch *w = (watch*)nodep;
380 rbwalk(tree_wd, cleanup_tree, 0);
383 rbdestroy(tree_filename);
394 struct replace_filename_data {
395 char const *old_name;
396 char const *new_name;
403 static void replace_filename(
const void* nodep,
406 const struct replace_filename_data* data) {
407 if (which != endorder && which != leaf)
409 watch *w = (watch*)nodep;
411 if ( 0 == strncmp( data->old_name, w->filename, data->old_len ) ) {
412 nasprintf( &name,
"%s%s", data->new_name, &(w->filename[data->old_len]) );
413 if (!strcmp( w->filename, data->new_name )) {
416 rbdelete(w, tree_filename);
419 rbsearch(w, tree_filename);
427 static void get_num(
const void* nodep,
431 if (which != endorder && which != leaf)
464 if ( strchr(
"_" "abcdefghijklmnopqrstuvwxyz"
465 "ABCDEFGHIJKLMNOPQRSTUVWXYZ", sep ) ) {
470 char * event1, * event2;
471 static const size_t eventstr_size = 4096;
472 char eventstr[eventstr_size];
475 if ( !event || !event[0] )
return 0;
477 event1 = (
char *)event;
478 event2 = strchr( event1, sep );
479 while ( event1 && event1[0] ) {
481 len = event2 - event1;
482 niceassert(len < eventstr_size,
483 "malformed event string (very long)");
486 len = strlen(event1);
488 if (len > eventstr_size - 1)
489 len = eventstr_size - 1;
491 strncpy(eventstr, event1, len);
495 int ret1 = onestr_to_event(eventstr);
496 if ( 0 == ret1 || -1 == ret1 ) {
503 if ( event1 && event1[0] ) {
507 if ( !event1[0] )
return 0;
508 event2 = strchr( event1, sep );
553 int onestr_to_event(
char const * event)
558 if ( !event || !event[0] )
560 else if ( 0 == strcasecmp(event,
"ACCESS") )
562 else if ( 0 == strcasecmp(event,
"MODIFY") )
564 else if ( 0 == strcasecmp(event,
"ATTRIB") )
566 else if ( 0 == strcasecmp(event,
"CLOSE_WRITE") )
567 ret = IN_CLOSE_WRITE;
568 else if ( 0 == strcasecmp(event,
"CLOSE_NOWRITE") )
569 ret = IN_CLOSE_NOWRITE;
570 else if ( 0 == strcasecmp(event,
"OPEN") )
572 else if ( 0 == strcasecmp(event,
"MOVED_FROM") )
574 else if ( 0 == strcasecmp(event,
"MOVED_TO") )
576 else if ( 0 == strcasecmp(event,
"CREATE") )
578 else if ( 0 == strcasecmp(event,
"DELETE") )
580 else if ( 0 == strcasecmp(event,
"DELETE_SELF") )
581 ret = IN_DELETE_SELF;
582 else if ( 0 == strcasecmp(event,
"UNMOUNT") )
584 else if ( 0 == strcasecmp(event,
"Q_OVERFLOW") )
586 else if ( 0 == strcasecmp(event,
"IGNORED") )
588 else if ( 0 == strcasecmp(event,
"CLOSE") )
590 else if ( 0 == strcasecmp(event,
"MOVE_SELF") )
592 else if ( 0 == strcasecmp(event,
"MOVE") )
594 else if ( 0 == strcasecmp(event,
"ISDIR") )
596 else if ( 0 == strcasecmp(event,
"ONESHOT") )
598 else if ( 0 == strcasecmp(event,
"ALL_EVENTS") )
655 static char ret[1024];
659 if ( IN_ACCESS & events ) {
661 strncat(ret,
"ACCESS", 7);
663 if ( IN_MODIFY & events ) {
665 strncat(ret,
"MODIFY", 7);
667 if ( IN_ATTRIB & events ) {
669 strncat(ret,
"ATTRIB", 7);
671 if ( IN_CLOSE_WRITE & events ) {
673 strncat(ret,
"CLOSE_WRITE", 12);
675 if ( IN_CLOSE_NOWRITE & events ) {
677 strncat(ret,
"CLOSE_NOWRITE", 14);
679 if ( IN_OPEN & events ) {
681 strncat(ret,
"OPEN", 5);
683 if ( IN_MOVED_FROM & events ) {
685 strncat(ret,
"MOVED_FROM", 11);
687 if ( IN_MOVED_TO & events ) {
689 strncat(ret,
"MOVED_TO", 9);
691 if ( IN_CREATE & events ) {
693 strncat(ret,
"CREATE", 7);
695 if ( IN_DELETE & events ) {
697 strncat(ret,
"DELETE", 7);
699 if ( IN_DELETE_SELF & events ) {
701 strncat(ret,
"DELETE_SELF", 12);
703 if ( IN_UNMOUNT & events ) {
705 strncat(ret,
"UNMOUNT", 8);
707 if ( IN_Q_OVERFLOW & events ) {
709 strncat(ret,
"Q_OVERFLOW", 11);
711 if ( IN_IGNORED & events ) {
713 strncat(ret,
"IGNORED", 8);
715 if ( IN_CLOSE & events ) {
717 strncat(ret,
"CLOSE", 6);
719 if ( IN_MOVE_SELF & events ) {
721 strncat(ret,
"MOVE_SELF", 10);
723 if ( IN_ISDIR & events ) {
725 strncat(ret,
"ISDIR", 6);
727 if ( IN_ONESHOT & events ) {
729 strncat(ret,
"ONESHOT", 8);
733 if (ret[0] ==
'\0') {
734 niceassert( -1 != sprintf( ret,
"%c0x%08x", sep, events ), 0 );
746 static const char* inotifytools_filename_from_fid(
747 struct fanotify_event_fid* fid) {
748 #ifdef LINUX_FANOTIFY
749 static char filename[PATH_MAX];
750 struct fanotify_event_fid fsid = {};
751 int dirf = 0, mount_fd = AT_FDCWD;
752 int len = 0, name_len = 0;
755 fsid.info.fsid.val[0] = fid->info.fsid.val[0];
756 fsid.info.fsid.val[1] = fid->info.fsid.val[1];
757 fsid.info.hdr.info_type = FAN_EVENT_INFO_TYPE_FID;
758 fsid.info.hdr.len =
sizeof(fsid);
759 watch* mnt = watch_from_fid(&fsid);
761 mount_fd = mnt->dirf;
763 if (fid->info.hdr.info_type == FAN_EVENT_INFO_TYPE_DFID_NAME) {
764 int fid_len =
sizeof(*fid) + fid->handle.handle_bytes;
766 name_len = fid->info.hdr.len - fid_len;
767 if (name_len && !fid->handle.f_handle[fid->handle.handle_bytes])
772 dirf = open_by_handle_at(mount_fd, &fid->handle, 0);
775 }
else if (fanotify_mark_type == FAN_MARK_FILESYSTEM) {
776 fprintf(stderr,
"Failed to decode directory fid.\n");
778 }
else if (name_len) {
780 fid->info.hdr.info_type = FAN_EVENT_INFO_TYPE_DFID;
781 fid->info.hdr.len -= name_len;
783 watch* w = watch_from_fid(fid);
785 fid->info.hdr.info_type = FAN_EVENT_INFO_TYPE_DFID_NAME;
786 fid->info.hdr.len += name_len;
790 "Failed to lookup path by directory fid.\n");
794 dirf = w->dirf ? dup(w->dirf) : -1;
796 fprintf(stderr,
"Failed to get directory fd.\n");
804 sprintf(sym,
"/proc/self/fd/%d", dirf);
808 len = readlink(sym, filename, PATH_MAX - 2);
811 fprintf(stderr,
"Failed to resolve path from directory fd.\n");
815 filename[len++] =
'/';
819 const char* name = (
const char*)fid->handle.f_handle +
820 fid->handle.handle_bytes;
821 int deleted = faccessat(dirf, name, F_OK, AT_SYMLINK_NOFOLLOW);
822 if (deleted && errno != ENOENT) {
823 fprintf(stderr,
"Failed to access file %s (%s).\n",
824 name, strerror(errno));
828 memcpy(filename + len, name, name_len);
830 strncat(filename,
" (deleted)", 11);
848 if (!w->fid || !fanotify_mark_type)
851 return inotifytools_filename_from_fid(w->fid) ?: w->filename;
875 niceassert( init,
"inotifytools_initialize not called yet" );
878 watch *w = watch_from_wd(wd);
894 size_t* dirnamelen) {
902 dirsep = strrchr(filename,
'/');
907 *dirnamelen = dirsep - filename + 1;
922 if (!filename || !*filename || !(event->mask & IN_ISDIR)) {
931 nasprintf(&path,
"%s%s/", filename, fanotify_mode ?
"" : event->name);
951 niceassert( init,
"inotifytools_initialize not called yet" );
952 if (!filename || !*filename)
954 watch *w = watch_from_filename(filename);
974 niceassert( init,
"inotifytools_initialize not called yet" );
975 watch *w = watch_from_wd(wd);
977 if (w->filename) free(w->filename);
978 w->filename = strdup(filename);
996 char const * newname ) {
997 watch *w = watch_from_filename(oldname);
999 if (w->filename) free(w->filename);
1000 w->filename = strdup(newname);
1026 char const * newname ) {
1027 if (!oldname || !newname)
1029 if (!*oldname || !*newname)
1031 struct replace_filename_data data;
1032 data.old_name = oldname;
1033 data.new_name = newname;
1034 data.old_len = strlen(oldname);
1035 rbwalk(tree_filename, (
void *)replace_filename, (
void *)&data);
1041 int remove_inotify_watch(watch *w) {
1046 int status = inotify_rm_watch( inotify_fd, w->wd );
1048 fprintf(stderr,
"Failed to remove watch on %s: %s\n", w->filename,
1059 watch* create_watch(
int wd,
1060 struct fanotify_event_fid* fid,
1061 const char* filename,
1063 if (wd < 0 || !filename)
1066 watch *w = (watch*)calloc(1,
sizeof(watch));
1068 fprintf(stderr,
"Failed to allocate watch.\n");
1071 w->wd = wd ?: (
unsigned long)fid;
1074 w->filename = strdup(filename);
1075 rbsearch(w, tree_wd);
1077 rbsearch(w, tree_fid);
1079 rbsearch(w, tree_filename);
1096 niceassert( init,
"inotifytools_initialize not called yet" );
1097 watch *w = watch_from_wd(wd);
1100 if (!remove_inotify_watch(w))
return 0;
1101 rbdelete(w, tree_wd);
1103 rbdelete(w, tree_fid);
1104 rbdelete(w, tree_filename);
1121 niceassert( init,
"inotifytools_initialize not called yet" );
1122 watch *w = watch_from_filename(filename);
1125 if (!remove_inotify_watch(w))
return 0;
1126 rbdelete(w, tree_wd);
1128 rbdelete(w, tree_fid);
1129 rbdelete(w, tree_filename);
1146 static char const* filenames[2];
1147 filenames[0] = filename;
1148 filenames[1] = NULL;
1168 niceassert( init,
"inotifytools_initialize not called yet" );
1172 for ( i = 0; filenames[i]; ++i ) {
1174 if (fanotify_mode) {
1175 #ifdef LINUX_FANOTIFY
1176 unsigned int flags = FAN_MARK_ADD | fanotify_mark_type;
1178 if (events & IN_DONT_FOLLOW) {
1179 events &= ~IN_DONT_FOLLOW;
1180 flags |= FAN_MARK_DONT_FOLLOW;
1183 wd = fanotify_mark(inotify_fd, flags,
1184 events | FAN_EVENT_ON_CHILD,
1185 AT_FDCWD, filenames[i]);
1189 inotify_add_watch(inotify_fd, filenames[i], events);
1197 fprintf( stderr,
"Failed to watch %s: returned wd was %d "
1198 "(expected -1 or >0 )", filenames[i], wd );
1204 const char* filename = filenames[i];
1205 size_t filenamelen = strlen(filename);
1209 if (!isdir(filename)) {
1211 }
else if (filename[filenamelen - 1] ==
'/') {
1212 dirname = strdup(filename);
1214 nasprintf(&dirname,
"%s/", filename);
1219 struct fanotify_event_fid* fid = NULL;
1220 #ifdef LINUX_FANOTIFY
1222 fid = calloc(1,
sizeof(*fid) + MAX_FID_LEN);
1224 fprintf(stderr,
"Failed to allocate fid");
1230 if (statfs(filenames[i], &buf)) {
1232 fprintf(stderr,
"Statfs failed on %s: %s\n",
1233 filenames[i], strerror(errno));
1237 memcpy(&fid->info.fsid, &buf.f_fsid,
1238 sizeof(__kernel_fsid_t));
1242 watch* mnt = dirname ? watch_from_fid(fid) : NULL;
1243 if (dirname && !mnt) {
1244 struct fanotify_event_fid* fsid;
1246 fsid = calloc(1,
sizeof(*fsid));
1250 "Failed to allocate fsid");
1254 fsid->info.fsid.val[0] = fid->info.fsid.val[0];
1255 fsid->info.fsid.val[1] = fid->info.fsid.val[1];
1256 fsid->info.hdr.info_type =
1257 FAN_EVENT_INFO_TYPE_FID;
1258 fsid->info.hdr.len =
sizeof(*fsid);
1259 mntid = open(dirname, O_RDONLY);
1264 "Failed to open %s: %s\n",
1265 dirname, strerror(errno));
1270 dirname[filenamelen - 1] = 0;
1271 create_watch(0, fsid, dirname, mntid);
1272 dirname[filenamelen - 1] =
'/';
1275 fid->handle.handle_bytes = MAX_FID_LEN;
1276 ret = name_to_handle_at(AT_FDCWD, filenames[i],
1277 (
void*)&fid->handle, &mntid, 0);
1278 if (ret || fid->handle.handle_bytes > MAX_FID_LEN) {
1280 fprintf(stderr,
"Encode fid failed on %s: %s\n",
1281 filenames[i], strerror(errno));
1285 fid->info.hdr.info_type = dirname
1286 ? FAN_EVENT_INFO_TYPE_DFID
1287 : FAN_EVENT_INFO_TYPE_FID;
1289 sizeof(*fid) + fid->handle.handle_bytes;
1291 dirf = open(dirname, O_PATH);
1295 "Failed to open %s: %s\n",
1296 dirname, strerror(errno));
1303 create_watch(wd, fid, filename, dirf);
1394 niceassert( init,
"inotifytools_initialize not called yet" );
1395 niceassert( num_events <= MAX_EVENTS,
"too many events requested" );
1397 if ( num_events < 1 )
return NULL;
1400 static struct inotify_event event[2 * MAX_EVENTS];
1401 static struct inotify_event * ret;
1402 static int first_byte = 0;
1403 static ssize_t bytes;
1404 static ssize_t this_bytes;
1406 static struct nstring match_name;
1407 static char match_name_string[MAX_STRLEN+1];
1414 if ( first_byte != 0
1415 && first_byte <= (
int)(bytes -
sizeof(
struct inotify_event)) ) {
1417 ret = (
struct inotify_event *)((
char *)&
event[0] + first_byte);
1418 if (!fanotify_mode &&
1419 first_byte +
sizeof(*ret) + ret->len > bytes) {
1426 niceassert( (
long)((
char *)&event[0] +
1427 sizeof(
struct inotify_event) +
1428 event[0].len) <= (
long)ret,
1429 "extremely unlucky user, death imminent" );
1431 bytes = (
char *)&event[0] + bytes - (
char *)ret;
1432 memcpy( &event[0], ret, bytes );
1440 else if ( first_byte == 0 ) {
1445 static unsigned int bytes_to_read;
1447 static fd_set read_fds;
1449 static struct timeval read_timeout;
1450 read_timeout.tv_sec = timeout;
1451 read_timeout.tv_usec = 0;
1452 static struct timeval * read_timeout_ptr;
1453 read_timeout_ptr = ( timeout < 0 ? NULL : &read_timeout );
1456 FD_SET(inotify_fd, &read_fds);
1457 rc = select(inotify_fd + 1, &read_fds,
1458 NULL, NULL, read_timeout_ptr);
1464 else if ( rc == 0 ) {
1471 rc = ioctl( inotify_fd, FIONREAD, &bytes_to_read );
1473 bytes_to_read <
sizeof(
struct inotify_event)*num_events );
1480 this_bytes = read(inotify_fd, &event[0] + bytes,
1481 sizeof(
struct inotify_event)*MAX_EVENTS - bytes);
1482 if ( this_bytes < 0 ) {
1486 if ( this_bytes == 0 ) {
1487 fprintf(stderr,
"Inotify reported end-of-file. Possibly too many "
1488 "events occurred at once.\n");
1492 ret = (
struct inotify_event*)((
char*)&
event[0] + first_byte);
1493 #ifdef LINUX_FANOTIFY
1495 if (fanotify_mode) {
1496 struct fanotify_event_metadata* meta = (
void*)ret;
1497 struct fanotify_event_info_fid* info = (
void*)(meta + 1);
1498 struct fanotify_event_fid* fid = NULL;
1499 const char* name =
"";
1503 first_byte += meta->event_len;
1505 if (meta->event_len >
sizeof(*meta)) {
1506 switch (info->hdr.info_type) {
1507 case FAN_EVENT_INFO_TYPE_FID:
1508 case FAN_EVENT_INFO_TYPE_DFID:
1509 case FAN_EVENT_INFO_TYPE_DFID_NAME:
1511 fid_len =
sizeof(*fid) +
1512 fid->handle.handle_bytes;
1513 if (info->hdr.info_type ==
1514 FAN_EVENT_INFO_TYPE_DFID_NAME) {
1516 info->hdr.len - fid_len;
1521 fid->handle.f_handle +
1522 fid->handle.handle_bytes;
1531 (!*name || !strcmp(name,
"."))) {
1532 info->hdr.len -= name_len;
1539 fprintf(stderr,
"No fid in fanotify event.\n");
1542 if (verbosity > 1) {
1544 "fanotify_event: bytes=%zd, first_byte=%d, "
1545 "this_bytes=%zd, event_len=%u, fid_len=%d, "
1546 "name_len=%d, name=%s\n",
1547 bytes, first_byte, this_bytes, meta->event_len,
1548 fid_len, name_len, name);
1551 ret = &
event[MAX_EVENTS];
1552 watch* w = watch_from_fid(fid);
1554 struct fanotify_event_fid* newfid =
1555 calloc(1, info->hdr.len);
1557 fprintf(stderr,
"Failed to allocate fid.\n");
1560 memcpy(newfid, fid, info->hdr.len);
1561 const char* filename =
1562 inotifytools_filename_from_fid(fid);
1564 w = create_watch(0, newfid, filename, 0);
1573 memcpy((
void*)&
id, fid->handle.f_handle,
1575 printf(
"[fid=%x.%x.%lx;name='%s'] %s\n",
1576 fid->info.fsid.val[0],
1577 fid->info.fsid.val[1],
id, name,
1581 ret->wd = w ? w->wd : 0;
1582 ret->mask = (uint32_t)meta->mask;
1583 ret->len = name_len;
1585 memcpy(ret->name, name, name_len);
1587 first_byte +=
sizeof(
struct inotify_event) + ret->len;
1591 bytes += this_bytes;
1592 niceassert( first_byte <= bytes,
"ridiculously long filename, things will "
1593 "almost certainly screw up." );
1594 if ( first_byte == bytes ) {
1600 memcpy(&match_name_string, &match_name.
buf, match_name.
len);
1601 match_name_string[match_name.
len] =
'\0';
1602 if (0 == regexec(regex, match_name_string, 0, 0, 0)) {
1611 if (collect_stats) {
1681 char const** exclude_list) {
1682 niceassert( init,
"inotifytools_initialize not called yet" );
1687 dir = opendir( path );
1690 if ( errno == ENOTDIR ) {
1699 if ( path[strlen(path)-1] !=
'/' ) {
1700 nasprintf( &my_path,
"%s/", path );
1703 my_path = (
char *)path;
1706 static struct dirent * ent;
1708 static struct stat64 my_stat;
1709 ent = readdir( dir );
1712 if ( (0 != strcmp( ent->d_name,
"." )) &&
1713 (0 != strcmp( ent->d_name,
".." )) ) {
1714 nasprintf(&next_file,
"%s%s", my_path, ent->d_name);
1715 if ( -1 == lstat64( next_file, &my_stat ) ) {
1718 if ( errno != EACCES ) {
1720 if ( my_path != path ) free( my_path );
1725 else if ( S_ISDIR( my_stat.st_mode ) &&
1726 !S_ISLNK( my_stat.st_mode )) {
1728 nasprintf(&next_file,
"%s%s/", my_path, ent->d_name);
1729 static unsigned int no_watch;
1730 static char const** exclude_entry;
1733 for (exclude_entry = exclude_list;
1734 exclude_entry && *exclude_entry && !no_watch;
1736 static int exclude_length;
1738 exclude_length = strlen(*exclude_entry);
1739 if ((*exclude_entry)[exclude_length-1] ==
'/') {
1742 if ( strlen(next_file) == (
unsigned)(exclude_length + 1) &&
1743 !strncmp(*exclude_entry, next_file, exclude_length)) {
1755 if ( !status && (EACCES != error) && (ENOENT != error) &&
1756 (ELOOP != error) ) {
1758 if ( my_path != path ) free( my_path );
1769 ent = readdir( dir );
1776 if ( my_path != path ) free( my_path );
1797 static int isdir(
char const * path ) {
1798 static struct stat64 my_stat;
1800 if ( -1 == lstat64( path, &my_stat ) ) {
1801 if (errno == ENOENT)
return 0;
1802 fprintf(stderr,
"Stat failed on %s: %s\n", path, strerror(errno));
1806 return S_ISDIR( my_stat.st_mode ) && !S_ISLNK( my_stat.st_mode );
1818 rbwalk(tree_filename, get_num, (
void*)&ret);
1919 if ( -1 != ret ) fwrite( out.
buf,
sizeof(
char), out.
len, file );
2031 struct inotify_event* event,
char* fmt ) {
2032 static const char* filename;
2033 static char *eventname, *eventstr;
2034 static unsigned int i, ind;
2036 static char timestr[MAX_STRLEN];
2039 if ( event->len > 0 ) {
2040 eventname =
event->name;
2046 size_t dirnamelen = 0;
2049 if ( !fmt || 0 == strlen(fmt) ) {
2053 if ( strlen(fmt) > MAX_STRLEN || size > MAX_STRLEN) {
2059 for ( i = 0; i < strlen(fmt) &&
2060 (int)ind < size - 1; ++i ) {
2061 if ( fmt[i] !=
'%' ) {
2062 out->
buf[ind++] = fmt[i];
2066 if ( i == strlen(fmt) - 1 ) {
2075 out->
buf[ind++] =
'%';
2081 out->
buf[ind++] =
'\0';
2087 out->
buf[ind++] =
'\n';
2093 if (filename && dirnamelen <= size - ind) {
2094 strncpy(&out->
buf[ind], filename, dirnamelen);
2103 strncpy( &out->
buf[ind], eventname, size - ind );
2104 ind += strlen(eventname);
2111 ind += snprintf( &out->
buf[ind], size-ind,
"%x", event->cookie);
2118 strncpy( &out->
buf[ind], eventstr, size - ind );
2119 ind += strlen(eventstr);
2129 if (!strftime(timestr, MAX_STRLEN - 1, timefmt,
2130 localtime_r(&now, &now_tm))) {
2140 strncpy( &out->
buf[ind], timestr, size - ind );
2141 ind += strlen(timestr);
2147 if ( i < strlen(fmt) - 2 && fmt[i+2] ==
'e' ) {
2149 strncpy( &out->
buf[ind], eventstr, size - ind );
2150 ind += strlen(eventstr);
2156 if ( ind < MAX_STRLEN ) out->
buf[ind++] =
'%';
2157 if ( ind < MAX_STRLEN ) out->
buf[ind++] = ch1;
2188 if ( !read_num_from_file( QUEUE_SIZE_PATH, &ret ) )
return -1;
2203 if ( !read_num_from_file( INSTANCES_PATH, &ret ) )
return -1;
2218 if ( !read_num_from_file( WATCHES_SIZE_PATH, &ret ) )
return -1;
2235 static int do_ignore_events_by_regex(
char const *pattern,
int flags,
int invert ) {
2245 if (regex) { regfree(regex); }
2246 else { regex = (regex_t *)malloc(
sizeof(regex_t)); }
2248 invert_regexp = invert;
2249 int ret = regcomp(regex, pattern, flags | REG_NOSUB);
2250 if (0 == ret)
return 1;
2271 return do_ignore_events_by_regex(pattern, flags, 0);
2286 return do_ignore_events_by_regex(pattern, flags, 1);
2289 int event_compare(
const void *p1,
const void *p2,
const void *config)
2291 if (!p1 || !p2)
return p1 - p2;
2293 long sort_event = (long)config;
2294 if (sort_event == -1) {
2297 }
else if (sort_event < 0) {
2298 sort_event = -sort_event;
2301 unsigned int *i1 = stat_ptr((watch*)p1, sort_event);
2302 unsigned int *i2 = stat_ptr((watch*)p2, sort_event);
2303 if (0 == *i1 - *i2) {
2304 return ((watch*)p1)->wd - ((watch*)p2)->wd;
2312 struct rbtree *inotifytools_wd_sorted_by_event(
int sort_event)
2314 struct rbtree *ret = rbinit(event_compare, (
void*)(uintptr_t)sort_event);
2315 RBLIST *all = rbopenlist(tree_wd);
2316 void const *p = rbreadlist(all);
2318 void const *r = rbsearch(p, ret);
2319 niceassert((
int)(r == p),
"Couldn't insert watch into new tree");
2320 p = rbreadlist(all);
This structure holds string that can contain any character including NULL.