15 #include "../../config.h" 
   17 #include "inotifytools_p.h" 
   24 #include <sys/select.h> 
   25 #include <sys/types.h> 
   27 #include <sys/ioctl.h> 
   34 #include "inotifytools/inotify.h" 
  122 #define MAX_EVENTS 4096 
  123 #define MAX_STRLEN 4096 
  124 #define INOTIFY_PROCDIR "/proc/sys/fs/inotify/" 
  125 #define WATCHES_SIZE_PATH INOTIFY_PROCDIR "max_user_watches" 
  126 #define QUEUE_SIZE_PATH   INOTIFY_PROCDIR "max_queued_watches" 
  127 #define INSTANCES_PATH    INOTIFY_PROCDIR "max_user_instances" 
  129 static int inotify_fd;
 
  130 static unsigned  num_access;
 
  131 static unsigned  num_modify;
 
  132 static unsigned  num_attrib;
 
  133 static unsigned  num_close_nowrite;
 
  134 static unsigned  num_close_write;
 
  135 static unsigned  num_open;
 
  136 static unsigned  num_move_self;
 
  137 static unsigned  num_moved_to;
 
  138 static unsigned  num_moved_from;
 
  139 static unsigned  num_create;
 
  140 static unsigned  num_delete;
 
  141 static unsigned  num_delete_self;
 
  142 static unsigned  num_unmount;
 
  143 static unsigned  num_total;
 
  144 static int collect_stats = 0;
 
  146 struct rbtree *tree_wd = 0;
 
  147 struct rbtree *tree_filename = 0;
 
  148 static int error = 0;
 
  150 static char* timefmt = 0;
 
  151 static regex_t* regex = 0;
 
  153 static int invert_regexp = 0;
 
  155 static int isdir( 
char const * path );
 
  156 void record_stats( 
struct inotify_event 
const * event );
 
  157 int onestr_to_event(
char const * event);
 
  176 #define niceassert(cond,mesg) _niceassert((long)cond, __LINE__, __FILE__, \ 
  179 #define nasprintf(...) niceassert( -1 != asprintf(__VA_ARGS__), "out of memory") 
  198 static void _niceassert( 
long cond, 
int line, 
char const * file,
 
  199                   char const * condstr, 
char const * mesg ) {
 
  203                 fprintf(stderr, 
"%s:%d assertion ( %s ) failed: %s\n", file, line,
 
  207                 fprintf(stderr, 
"%s:%d assertion ( %s ) failed.\n", file, line, condstr);
 
  220 char * chrtostr(
char ch) {
 
  221         static char str[2] = { 
'\0', 
'\0' };
 
  229 int read_num_from_file( 
char * filename, 
int * num ) {
 
  230         FILE * file = fopen( filename, 
"r" );
 
  236         if ( EOF == fscanf( file, 
"%d", num ) ) {
 
  241         niceassert( 0 == fclose( file ), 0 );
 
  246 int wd_compare(
const void *d1, 
const void *d2, 
const void *config) {
 
  247         if (!d1 || !d2) 
return d1 - d2;
 
  248         return ((watch*)d1)->wd - ((watch*)d2)->wd;
 
  251 int filename_compare(
const void *d1, 
const void *d2, 
const void *config) {
 
  252         if (!d1 || !d2) 
return d1 - d2;
 
  253         return strcmp(((watch*)d1)->filename, ((watch*)d2)->filename);
 
  259 watch *watch_from_wd( 
int wd ) {
 
  262         return (watch*)rbfind(&w, tree_wd);
 
  268 watch *watch_from_filename( 
char const *filename ) {
 
  270         w.filename = (
char*)filename;
 
  271         return (watch*)rbfind(&w, tree_filename);
 
  288         inotify_fd = inotify_init();
 
  289         if (inotify_fd < 0)     {
 
  296         tree_wd = rbinit(wd_compare, 0);
 
  297         tree_filename = rbinit(filename_compare, 0);
 
  306 void destroy_watch(watch *w) {
 
  307         if (w->filename) free(w->filename);
 
  314 void cleanup_tree(
const void *nodep,
 
  316                  const int depth, 
void* arg) {
 
  317         if (which != endorder && which != leaf) 
return;
 
  318         watch *w = (watch*)nodep;
 
  343         rbwalk(tree_wd, cleanup_tree, 0);
 
  344         rbdestroy(tree_wd); tree_wd = 0;
 
  345         rbdestroy(tree_filename); tree_filename = 0;
 
  351 void empty_stats(
const void *nodep,
 
  353                  const int depth, 
void *arg) {
 
  354     if (which != endorder && which != leaf) 
return;
 
  355         watch *w = (watch*)nodep;
 
  359         w->hit_close_nowrite = 0;
 
  360         w->hit_close_write = 0;
 
  362         w->hit_move_self = 0;
 
  363         w->hit_moved_from = 0;
 
  367         w->hit_delete_self = 0;
 
  375 void replace_filename(
const void *nodep,
 
  377                       const int depth, 
void *arg) {
 
  378     if (which != endorder && which != leaf) 
return;
 
  379         watch *w = (watch*)nodep;
 
  380         char *old_name = ((
char**)arg)[0];
 
  381         char *new_name = ((
char**)arg)[1];
 
  382         int old_len = *((
int*)&((
char**)arg)[2]);
 
  384         if ( 0 == strncmp( old_name, w->filename, old_len ) ) {
 
  385                 nasprintf( &name, 
"%s%s", new_name, &(w->filename[old_len]) );
 
  386                 if (!strcmp( w->filename, new_name )) {
 
  389                         rbdelete(w, tree_filename);
 
  392                         rbsearch(w, tree_filename);
 
  400 void get_num(
const void *nodep,
 
  402              const int depth, 
void *arg) {
 
  403     if (which != endorder && which != leaf) 
return;
 
  421         niceassert( init, 
"inotifytools_initialize not called yet" );
 
  425                 rbwalk(tree_wd, empty_stats, 0);
 
  431         num_close_nowrite = 0;
 
  474         if ( strchr( 
"_" "abcdefghijklmnopqrstuvwxyz" 
  475                          "ABCDEFGHIJKLMNOPQRSTUVWXYZ", sep ) ) {
 
  480         char * event1, * event2;
 
  484         if ( !event || !event[0] ) 
return 0;
 
  486         event1 = (
char *)event;
 
  487         event2 = strchr( event1, sep );
 
  488         while ( event1 && event1[0] ) {
 
  490                         len = event2 - event1;
 
  491                         niceassert( len < 4096, 
"malformed event string (very long)" );
 
  494                         len = strlen(event1);
 
  496                 if ( len > 4095 ) len = 4095;
 
  497                 strncpy( eventstr, event1, len );
 
  500                 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 );
 
  558 int 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 ) {
 
  665                 strcat( ret, chrtostr(sep) );
 
  666                 strcat( ret, 
"ACCESS" );
 
  668         if ( IN_MODIFY & events ) {
 
  669                 strcat( ret, chrtostr(sep) );
 
  670                 strcat( ret, 
"MODIFY" );
 
  672         if ( IN_ATTRIB & events ) {
 
  673                 strcat( ret, chrtostr(sep) );
 
  674                 strcat( ret, 
"ATTRIB" );
 
  676         if ( IN_CLOSE_WRITE & events ) {
 
  677                 strcat( ret, chrtostr(sep) );
 
  678                 strcat( ret, 
"CLOSE_WRITE" );
 
  680         if ( IN_CLOSE_NOWRITE & events ) {
 
  681                 strcat( ret, chrtostr(sep) );
 
  682                 strcat( ret, 
"CLOSE_NOWRITE" );
 
  684         if ( IN_OPEN & events ) {
 
  685                 strcat( ret, chrtostr(sep) );
 
  686                 strcat( ret, 
"OPEN" );
 
  688         if ( IN_MOVED_FROM & events ) {
 
  689                 strcat( ret, chrtostr(sep) );
 
  690                 strcat( ret, 
"MOVED_FROM" );
 
  692         if ( IN_MOVED_TO & events ) {
 
  693                 strcat( ret, chrtostr(sep) );
 
  694                 strcat( ret, 
"MOVED_TO" );
 
  696         if ( IN_CREATE & events ) {
 
  697                 strcat( ret, chrtostr(sep) );
 
  698                 strcat( ret, 
"CREATE" );
 
  700         if ( IN_DELETE & events ) {
 
  701                 strcat( ret, chrtostr(sep) );
 
  702                 strcat( ret, 
"DELETE" );
 
  704         if ( IN_DELETE_SELF & events ) {
 
  705                 strcat( ret, chrtostr(sep) );
 
  706                 strcat( ret, 
"DELETE_SELF" );
 
  708         if ( IN_UNMOUNT & events ) {
 
  709                 strcat( ret, chrtostr(sep) );
 
  710                 strcat( ret, 
"UNMOUNT" );
 
  712         if ( IN_Q_OVERFLOW & events ) {
 
  713                 strcat( ret, chrtostr(sep) );
 
  714                 strcat( ret, 
"Q_OVERFLOW" );
 
  716         if ( IN_IGNORED & events ) {
 
  717                 strcat( ret, chrtostr(sep) );
 
  718                 strcat( ret, 
"IGNORED" );
 
  720         if ( IN_CLOSE & events ) {
 
  721                 strcat( ret, chrtostr(sep) );
 
  722                 strcat( ret, 
"CLOSE" );
 
  724         if ( IN_MOVE_SELF & events ) {
 
  725                 strcat( ret, chrtostr(sep) );
 
  726                 strcat( ret, 
"MOVE_SELF" );
 
  728         if ( IN_ISDIR & events ) {
 
  729                 strcat( ret, chrtostr(sep) );
 
  730                 strcat( ret, 
"ISDIR" );
 
  732         if ( IN_ONESHOT & events ) {
 
  733                 strcat( ret, chrtostr(sep) );
 
  734                 strcat( ret, 
"ONESHOT" );
 
  738         if (ret[0] == 
'\0') {
 
  739                 niceassert( -1 != sprintf( ret, 
"%c0x%08x", sep, events ), 0 );
 
  766         niceassert( init, 
"inotifytools_initialize not called yet" );
 
  767         watch *w = watch_from_wd(wd);
 
  789         niceassert( init, 
"inotifytools_initialize not called yet" );
 
  790         watch *w = watch_from_filename(filename);
 
  810         niceassert( init, 
"inotifytools_initialize not called yet" );
 
  811         watch *w = watch_from_wd(wd);
 
  813         if (w->filename) free(w->filename);
 
  814         w->filename = strdup(filename);
 
  832                                             char const * newname ) {
 
  833         watch *w = watch_from_filename(oldname);
 
  835         if (w->filename) free(w->filename);
 
  836         w->filename = strdup(newname);
 
  862                                     char const * newname ) {
 
  863         if ( !oldname || !newname ) 
return;
 
  864         char *names[2+
sizeof(int)/
sizeof(
char*)];
 
  865         names[0] = (
char*)oldname;
 
  866         names[1] = (
char*)newname;
 
  867         *((
int*)&names[2]) = strlen(oldname);
 
  868         rbwalk(tree_filename, replace_filename, (
void*)names);
 
  874 int remove_inotify_watch(watch *w) {
 
  876         int status = inotify_rm_watch( inotify_fd, w->wd );
 
  878                 fprintf(stderr, 
"Failed to remove watch on %s: %s\n", w->filename,
 
  889 watch *create_watch(
int wd, 
char *filename) {
 
  890         if ( wd <= 0 || !filename) 
return 0;
 
  892         watch *w = (watch*)calloc(1, 
sizeof(watch));
 
  894         w->filename = strdup(filename);
 
  895         rbsearch(w, tree_wd);
 
  896         rbsearch(w, tree_filename);
 
  912         niceassert( init, 
"inotifytools_initialize not called yet" );
 
  913         watch *w = watch_from_wd(wd);
 
  916         if (!remove_inotify_watch(w)) 
return 0;
 
  917         rbdelete(w, tree_wd);
 
  918         rbdelete(w, tree_filename);
 
  935         niceassert( init, 
"inotifytools_initialize not called yet" );
 
  936         watch *w = watch_from_filename(filename);
 
  939         if (!remove_inotify_watch(w)) 
return 0;
 
  940         rbdelete(w, tree_wd);
 
  941         rbdelete(w, tree_filename);
 
  958         static char const * filenames[2];
 
  959         filenames[0] = filename;
 
  980         niceassert( init, 
"inotifytools_initialize not called yet" );
 
  984         for ( i = 0; filenames[i]; ++i ) {
 
  986                 wd = inotify_add_watch( inotify_fd, filenames[i], events );
 
  993                                 fprintf( stderr, 
"Failed to watch %s: returned wd was %d " 
  994                                          "(expected -1 or >0 )", filenames[i], wd );
 
 1002                 if ( !isdir(filenames[i])
 
 1003                      || filenames[i][strlen(filenames[i])-1] == 
'/') {
 
 1004                         filename = strdup(filenames[i]);
 
 1007                         nasprintf( &filename, 
"%s/", filenames[i] );
 
 1009                 create_watch(wd, filename);
 
 1096         niceassert( init, 
"inotifytools_initialize not called yet" );
 
 1097         niceassert( num_events <= MAX_EVENTS, 
"too many events requested" );
 
 1099         if ( num_events < 1 ) 
return NULL;
 
 1101         static struct inotify_event event[MAX_EVENTS];
 
 1102         static struct inotify_event * ret;
 
 1103         static int first_byte = 0;
 
 1104         static ssize_t bytes;
 
 1106         static char match_name[MAX_STRLEN];
 
 1108 #define RETURN(A) {\ 
 1110                 inotifytools_snprintf(match_name, MAX_STRLEN, A, "%w%f");\ 
 1111                 if (0 == regexec(regex, match_name, 0, 0, 0)) {\ 
 1112                         if (!invert_regexp)\ 
 1119         if ( collect_stats ) {\ 
 1130         if ( first_byte != 0
 
 1131           && first_byte <= (
int)(bytes - 
sizeof(
struct inotify_event)) ) {
 
 1133                 ret = (
struct inotify_event *)((
char *)&
event[0] + first_byte);
 
 1134                 first_byte += 
sizeof(
struct inotify_event) + ret->len;
 
 1138                 if ( first_byte == bytes ) {
 
 1141                 else if ( first_byte > bytes ) {
 
 1148                         niceassert( (
long)((
char *)&event[0] +
 
 1149                                     sizeof(
struct inotify_event) +
 
 1150                                     event[0].len) <= (
long)ret,
 
 1151                                     "extremely unlucky user, death imminent" );
 
 1153                         bytes = (
char *)&event[0] + bytes - (
char *)ret;
 
 1154                         memcpy( &event[0], ret, bytes );
 
 1161         else if ( first_byte == 0 ) {
 
 1166         static ssize_t this_bytes;
 
 1167         static unsigned int bytes_to_read;
 
 1169         static fd_set read_fds;
 
 1171         static struct timeval read_timeout;
 
 1172         read_timeout.tv_sec = timeout;
 
 1173         read_timeout.tv_usec = 0;
 
 1174         static struct timeval * read_timeout_ptr;
 
 1175         read_timeout_ptr = ( timeout < 0 ? NULL : &read_timeout );
 
 1178         FD_SET(inotify_fd, &read_fds);
 
 1179         rc = select(inotify_fd + 1, &read_fds,
 
 1180                     NULL, NULL, read_timeout_ptr);
 
 1186         else if ( rc == 0 ) {
 
 1193                 rc = ioctl( inotify_fd, FIONREAD, &bytes_to_read );
 
 1195                   bytes_to_read < 
sizeof(
struct inotify_event)*num_events );
 
 1202         this_bytes = read(inotify_fd, &event[0] + bytes,
 
 1203                           sizeof(
struct inotify_event)*MAX_EVENTS - bytes);
 
 1204         if ( this_bytes < 0 ) {
 
 1208         if ( this_bytes == 0 ) {
 
 1209                 fprintf(stderr, 
"Inotify reported end-of-file.  Possibly too many " 
 1210                                 "events occurred at once.\n");
 
 1213         bytes += this_bytes;
 
 1216         first_byte = 
sizeof(
struct inotify_event) + ret->len;
 
 1217         niceassert( first_byte <= bytes, 
"ridiculously long filename, things will " 
 1218                                          "almost certainly screw up." );
 
 1219         if ( first_byte == bytes ) {
 
 1290                                                  char const ** exclude_list ) {
 
 1291         niceassert( init, 
"inotifytools_initialize not called yet" );
 
 1296         dir = opendir( path );
 
 1299                 if ( errno == ENOTDIR ) {
 
 1308         if ( path[strlen(path)-1] != 
'/' ) {
 
 1309                 nasprintf( &my_path, 
"%s/", path );
 
 1312                 my_path = (
char *)path;
 
 1315         static struct dirent * ent;
 
 1317         static struct stat64 my_stat;
 
 1318         ent = readdir( dir );
 
 1321                 if ( (0 != strcmp( ent->d_name, 
"." )) &&
 
 1322                      (0 != strcmp( ent->d_name, 
".." )) ) {
 
 1323                         nasprintf(&next_file,
"%s%s", my_path, ent->d_name);
 
 1324                         if ( -1 == lstat64( next_file, &my_stat ) ) {
 
 1327                                 if ( errno != EACCES ) {
 
 1329                                         if ( my_path != path ) free( my_path );
 
 1334                         else if ( S_ISDIR( my_stat.st_mode ) &&
 
 1335                                   !S_ISLNK( my_stat.st_mode )) {
 
 1337                                 nasprintf(&next_file,
"%s%s/", my_path, ent->d_name);
 
 1338                                 static unsigned int no_watch;
 
 1339                                 static char const ** exclude_entry;
 
 1342                                 for (exclude_entry = exclude_list;
 
 1343                                          exclude_entry && *exclude_entry && !no_watch;
 
 1345                                         static int exclude_length;
 
 1347                                         exclude_length = strlen(*exclude_entry);
 
 1348                                         if ((*exclude_entry)[exclude_length-1] == 
'/') {
 
 1351                                         if ( strlen(next_file) == (
unsigned)(exclude_length + 1) &&
 
 1352                                             !strncmp(*exclude_entry, next_file, exclude_length)) {
 
 1364                                         if ( !status && (EACCES != error) && (ENOENT != error) &&
 
 1365                                              (ELOOP != error) ) {
 
 1367                                                 if ( my_path != path ) free( my_path );
 
 1378                 ent = readdir( dir );
 
 1385         if ( my_path != path ) free( my_path );
 
 1392 void record_stats( 
struct inotify_event 
const * event ) {
 
 1394         watch *w = watch_from_wd(event->wd);
 
 1396         if ( IN_ACCESS & event->mask ) {
 
 1400         if ( IN_MODIFY & event->mask ) {
 
 1404         if ( IN_ATTRIB & event->mask ) {
 
 1408         if ( IN_CLOSE_WRITE & event->mask ) {
 
 1409                 ++w->hit_close_write;
 
 1412         if ( IN_CLOSE_NOWRITE & event->mask ) {
 
 1413                 ++w->hit_close_nowrite;
 
 1414                 ++num_close_nowrite;
 
 1416         if ( IN_OPEN & event->mask ) {
 
 1420         if ( IN_MOVED_FROM & event->mask ) {
 
 1421                 ++w->hit_moved_from;
 
 1424         if ( IN_MOVED_TO & event->mask ) {
 
 1428         if ( IN_CREATE & event->mask ) {
 
 1432         if ( IN_DELETE & event->mask ) {
 
 1436         if ( IN_DELETE_SELF & event->mask ) {
 
 1437                 ++w->hit_delete_self;
 
 1440         if ( IN_UNMOUNT & event->mask ) {
 
 1444         if ( IN_MOVE_SELF & event->mask ) {
 
 1454 int *stat_ptr(watch *w, 
int event)
 
 1456         if ( IN_ACCESS == event )
 
 1457                 return &w->hit_access;
 
 1458         if ( IN_MODIFY == event )
 
 1459                 return &w->hit_modify;
 
 1460         if ( IN_ATTRIB == event )
 
 1461                 return &w->hit_attrib;
 
 1462         if ( IN_CLOSE_WRITE == event )
 
 1463                 return &w->hit_close_write;
 
 1464         if ( IN_CLOSE_NOWRITE == event )
 
 1465                 return &w->hit_close_nowrite;
 
 1466         if ( IN_OPEN == event )
 
 1467                 return &w->hit_open;
 
 1468         if ( IN_MOVED_FROM == event )
 
 1469                 return &w->hit_moved_from;
 
 1470         if ( IN_MOVED_TO == event )
 
 1471                 return &w->hit_moved_to;
 
 1472         if ( IN_CREATE == event )
 
 1473                 return &w->hit_create;
 
 1474         if ( IN_DELETE == event )
 
 1475                 return &w->hit_delete;
 
 1476         if ( IN_DELETE_SELF == event )
 
 1477                 return &w->hit_delete_self;
 
 1478         if ( IN_UNMOUNT == event )
 
 1479                 return &w->hit_unmount;
 
 1480         if ( IN_MOVE_SELF == event )
 
 1481                 return &w->hit_move_self;
 
 1483                 return &w->hit_total;
 
 1503         if (!collect_stats) 
return -1;
 
 1505         watch *w = watch_from_wd(wd);
 
 1507         int *i = stat_ptr(w, event);
 
 1526         if (!collect_stats) 
return -1;
 
 1527         if ( IN_ACCESS == event )
 
 1529         if ( IN_MODIFY == event )
 
 1531         if ( IN_ATTRIB == event )
 
 1533         if ( IN_CLOSE_WRITE == event )
 
 1534                 return num_close_write;
 
 1535         if ( IN_CLOSE_NOWRITE == event )
 
 1536                 return num_close_nowrite;
 
 1537         if ( IN_OPEN == event )
 
 1539         if ( IN_MOVED_FROM == event )
 
 1540                 return num_moved_from;
 
 1541         if ( IN_MOVED_TO == event )
 
 1542                 return num_moved_to;
 
 1543         if ( IN_CREATE == event )
 
 1545         if ( IN_DELETE == event )
 
 1547         if ( IN_DELETE_SELF == event )
 
 1548                 return num_delete_self;
 
 1549         if ( IN_UNMOUNT == event )
 
 1551         if ( IN_MOVE_SELF == event )
 
 1552                 return num_move_self;
 
 1582                filename ), event );
 
 1602 static int isdir( 
char const * path ) {
 
 1603         static struct stat64 my_stat;
 
 1605         if ( -1 == lstat64( path, &my_stat ) ) {
 
 1606                 if (errno == ENOENT) 
return 0;
 
 1607                 fprintf(stderr, 
"Stat failed on %s: %s\n", path, strerror(errno));
 
 1611         return S_ISDIR( my_stat.st_mode ) && !S_ISLNK( my_stat.st_mode );
 
 1623         rbwalk(tree_filename, get_num, (
void*)&ret);
 
 1713         static char out[MAX_STRLEN+1];
 
 1716         if ( -1 != ret ) fprintf( file, 
"%s", out );
 
 1822                            struct inotify_event* event, 
char* fmt ) {
 
 1823         static char * filename, * eventname, * eventstr;
 
 1824         static unsigned int i, ind;
 
 1826         static char timestr[MAX_STRLEN];
 
 1830         if ( event->len > 0 ) {
 
 1831                 eventname = 
event->name;
 
 1840         if ( !fmt || 0 == strlen(fmt) ) {
 
 1844         if ( strlen(fmt) > MAX_STRLEN || size > MAX_STRLEN) {
 
 1850         for ( i = 0; i < strlen(fmt) &&
 
 1851                      (int)ind < size - 1; ++i ) {
 
 1852                 if ( fmt[i] != 
'%' ) {
 
 1853                         out[ind++] = fmt[i];
 
 1857                 if ( i == strlen(fmt) - 1 ) {
 
 1873                                 strncpy( &out[ind], filename, size - ind );
 
 1874                                 ind += strlen(filename);
 
 1882                                 strncpy( &out[ind], eventname, size - ind );
 
 1883                                 ind += strlen(eventname);
 
 1891                         strncpy( &out[ind], eventstr, size - ind );
 
 1892                         ind += strlen(eventstr);
 
 1902                                 if ( 0 >= strftime( timestr, MAX_STRLEN-1, timefmt,
 
 1903                                                     localtime( &now ) ) ) {
 
 1914                         strncpy( &out[ind], timestr, size - ind );
 
 1915                         ind += strlen(timestr);
 
 1921                 if ( i < strlen(fmt) - 2 && fmt[i+2] == 
'e' ) {
 
 1923                         strncpy( &out[ind], eventstr, size - ind );
 
 1924                         ind += strlen(eventstr);
 
 1930                 if ( ind < MAX_STRLEN ) out[ind++] = 
'%';
 
 1931                 if ( ind < MAX_STRLEN ) out[ind++] = ch1;
 
 1962         if ( !read_num_from_file( QUEUE_SIZE_PATH, &ret ) ) 
return -1;
 
 1977         if ( !read_num_from_file( INSTANCES_PATH, &ret ) ) 
return -1;
 
 1992         if ( !read_num_from_file( WATCHES_SIZE_PATH, &ret ) ) 
return -1;
 
 2009 static int do_ignore_events_by_regex( 
char const *pattern, 
int flags, 
int invert ) {
 
 2019         if (regex) { regfree(regex); }
 
 2020         else       { regex = (regex_t *)malloc(
sizeof(regex_t)); }
 
 2022         invert_regexp = invert;
 
 2023         int ret = regcomp(regex, pattern, flags | REG_NOSUB);
 
 2024         if (0 == ret) 
return 1;
 
 2045         return do_ignore_events_by_regex(pattern, flags, 0);
 
 2060         return do_ignore_events_by_regex(pattern, flags, 1);
 
 2063 int event_compare(
const void *p1, 
const void *p2, 
const void *config)
 
 2065         if (!p1 || !p2) 
return p1 - p2;
 
 2067         int sort_event = (int)config;
 
 2068         if (sort_event == -1) {
 
 2071         } 
else if (sort_event < 0) {
 
 2072                 sort_event = -sort_event;
 
 2075         int *i1 = stat_ptr((watch*)p1, sort_event);
 
 2076         int *i2 = stat_ptr((watch*)p2, sort_event);
 
 2077         if (0 == *i1 - *i2) {
 
 2078                 return ((watch*)p1)->wd - ((watch*)p2)->wd;
 
 2086 struct rbtree *inotifytools_wd_sorted_by_event(
int sort_event)
 
 2088         struct rbtree *ret = rbinit(event_compare, (
void*)sort_event);
 
 2089         RBLIST *all = rbopenlist(tree_wd);
 
 2090         void const *p = rbreadlist(all);
 
 2092                 void const *r = rbsearch(p, ret);
 
 2093                 niceassert((
int)(r == p), 
"Couldn't insert watch into new tree");
 
 2094                 p = rbreadlist(all);