15 #include "../../config.h" 
   17 #include "inotifytools_p.h" 
   25 #include <sys/select.h> 
   26 #include <sys/types.h> 
   28 #include <sys/ioctl.h> 
   35 #include "inotifytools/inotify.h" 
  123 #define MAX_EVENTS 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 struct replace_filename_data {
 
  376     char const *old_name;
 
  377     char const *new_name;
 
  384 void replace_filename(
const void *nodep, 
const VISIT which, 
const int depth,
 
  385                       const struct replace_filename_data *data) {
 
  386     if (which != endorder && which != leaf) 
return;
 
  387         watch *w = (watch*)nodep;
 
  389         if ( 0 == strncmp( data->old_name, w->filename, data->old_len ) ) {
 
  390                 nasprintf( &name, 
"%s%s", data->new_name, &(w->filename[data->old_len]) );
 
  391                 if (!strcmp( w->filename, data->new_name )) {
 
  394                         rbdelete(w, tree_filename);
 
  397                         rbsearch(w, tree_filename);
 
  405 void get_num(
const void *nodep,
 
  407              const int depth, 
void *arg) {
 
  408     if (which != endorder && which != leaf) 
return;
 
  426         niceassert( init, 
"inotifytools_initialize not called yet" );
 
  430                 rbwalk(tree_wd, empty_stats, 0);
 
  436         num_close_nowrite = 0;
 
  479         if ( strchr( 
"_" "abcdefghijklmnopqrstuvwxyz" 
  480                          "ABCDEFGHIJKLMNOPQRSTUVWXYZ", sep ) ) {
 
  485         char * event1, * event2;
 
  486         static const size_t eventstr_size = 4096;
 
  487         char eventstr[eventstr_size];
 
  490         if ( !event || !event[0] ) 
return 0;
 
  492         event1 = (
char *)event;
 
  493         event2 = strchr( event1, sep );
 
  494         while ( event1 && event1[0] ) {
 
  496                         len = event2 - event1;
 
  497                         niceassert(len < eventstr_size,
 
  498                                    "malformed event string (very long)");
 
  501                         len = strlen(event1);
 
  503                 if (len > eventstr_size - 1)
 
  504                     len = eventstr_size - 1;
 
  506                 if (event2 || len == eventstr_size - 1) {
 
  507                     strncpy(eventstr, event1, len);
 
  509                     strcpy(eventstr, event1);
 
  514                 ret1 = onestr_to_event( eventstr );
 
  515                 if ( 0 == ret1 || -1 == ret1 ) {
 
  522                 if ( event1 && event1[0] ) {
 
  526                         if ( !event1[0] ) 
return 0;
 
  527                         event2 = strchr( event1, sep );
 
  572 int onestr_to_event(
char const * event)
 
  577         if ( !event || !event[0] )
 
  579         else if ( 0 == strcasecmp(event, 
"ACCESS") )
 
  581         else if ( 0 == strcasecmp(event, 
"MODIFY") )
 
  583         else if ( 0 == strcasecmp(event, 
"ATTRIB") )
 
  585         else if ( 0 == strcasecmp(event, 
"CLOSE_WRITE") )
 
  586                 ret = IN_CLOSE_WRITE;
 
  587         else if ( 0 == strcasecmp(event, 
"CLOSE_NOWRITE") )
 
  588                 ret = IN_CLOSE_NOWRITE;
 
  589         else if ( 0 == strcasecmp(event, 
"OPEN") )
 
  591         else if ( 0 == strcasecmp(event, 
"MOVED_FROM") )
 
  593         else if ( 0 == strcasecmp(event, 
"MOVED_TO") )
 
  595         else if ( 0 == strcasecmp(event, 
"CREATE") )
 
  597         else if ( 0 == strcasecmp(event, 
"DELETE") )
 
  599         else if ( 0 == strcasecmp(event, 
"DELETE_SELF") )
 
  600                 ret = IN_DELETE_SELF;
 
  601         else if ( 0 == strcasecmp(event, 
"UNMOUNT") )
 
  603         else if ( 0 == strcasecmp(event, 
"Q_OVERFLOW") )
 
  605         else if ( 0 == strcasecmp(event, 
"IGNORED") )
 
  607         else if ( 0 == strcasecmp(event, 
"CLOSE") )
 
  609         else if ( 0 == strcasecmp(event, 
"MOVE_SELF") )
 
  611         else if ( 0 == strcasecmp(event, 
"MOVE") )
 
  613         else if ( 0 == strcasecmp(event, 
"ISDIR") )
 
  615         else if ( 0 == strcasecmp(event, 
"ONESHOT") )
 
  617         else if ( 0 == strcasecmp(event, 
"ALL_EVENTS") )
 
  674         static char ret[1024];
 
  678         if ( IN_ACCESS & events ) {
 
  679                 strcat( ret, chrtostr(sep) );
 
  680                 strcat( ret, 
"ACCESS" );
 
  682         if ( IN_MODIFY & events ) {
 
  683                 strcat( ret, chrtostr(sep) );
 
  684                 strcat( ret, 
"MODIFY" );
 
  686         if ( IN_ATTRIB & events ) {
 
  687                 strcat( ret, chrtostr(sep) );
 
  688                 strcat( ret, 
"ATTRIB" );
 
  690         if ( IN_CLOSE_WRITE & events ) {
 
  691                 strcat( ret, chrtostr(sep) );
 
  692                 strcat( ret, 
"CLOSE_WRITE" );
 
  694         if ( IN_CLOSE_NOWRITE & events ) {
 
  695                 strcat( ret, chrtostr(sep) );
 
  696                 strcat( ret, 
"CLOSE_NOWRITE" );
 
  698         if ( IN_OPEN & events ) {
 
  699                 strcat( ret, chrtostr(sep) );
 
  700                 strcat( ret, 
"OPEN" );
 
  702         if ( IN_MOVED_FROM & events ) {
 
  703                 strcat( ret, chrtostr(sep) );
 
  704                 strcat( ret, 
"MOVED_FROM" );
 
  706         if ( IN_MOVED_TO & events ) {
 
  707                 strcat( ret, chrtostr(sep) );
 
  708                 strcat( ret, 
"MOVED_TO" );
 
  710         if ( IN_CREATE & events ) {
 
  711                 strcat( ret, chrtostr(sep) );
 
  712                 strcat( ret, 
"CREATE" );
 
  714         if ( IN_DELETE & events ) {
 
  715                 strcat( ret, chrtostr(sep) );
 
  716                 strcat( ret, 
"DELETE" );
 
  718         if ( IN_DELETE_SELF & events ) {
 
  719                 strcat( ret, chrtostr(sep) );
 
  720                 strcat( ret, 
"DELETE_SELF" );
 
  722         if ( IN_UNMOUNT & events ) {
 
  723                 strcat( ret, chrtostr(sep) );
 
  724                 strcat( ret, 
"UNMOUNT" );
 
  726         if ( IN_Q_OVERFLOW & events ) {
 
  727                 strcat( ret, chrtostr(sep) );
 
  728                 strcat( ret, 
"Q_OVERFLOW" );
 
  730         if ( IN_IGNORED & events ) {
 
  731                 strcat( ret, chrtostr(sep) );
 
  732                 strcat( ret, 
"IGNORED" );
 
  734         if ( IN_CLOSE & events ) {
 
  735                 strcat( ret, chrtostr(sep) );
 
  736                 strcat( ret, 
"CLOSE" );
 
  738         if ( IN_MOVE_SELF & events ) {
 
  739                 strcat( ret, chrtostr(sep) );
 
  740                 strcat( ret, 
"MOVE_SELF" );
 
  742         if ( IN_ISDIR & events ) {
 
  743                 strcat( ret, chrtostr(sep) );
 
  744                 strcat( ret, 
"ISDIR" );
 
  746         if ( IN_ONESHOT & events ) {
 
  747                 strcat( ret, chrtostr(sep) );
 
  748                 strcat( ret, 
"ONESHOT" );
 
  752         if (ret[0] == 
'\0') {
 
  753                 niceassert( -1 != sprintf( ret, 
"%c0x%08x", sep, events ), 0 );
 
  780         niceassert( init, 
"inotifytools_initialize not called yet" );
 
  781         watch *w = watch_from_wd(wd);
 
  803         niceassert( init, 
"inotifytools_initialize not called yet" );
 
  804         watch *w = watch_from_filename(filename);
 
  824         niceassert( init, 
"inotifytools_initialize not called yet" );
 
  825         watch *w = watch_from_wd(wd);
 
  827         if (w->filename) free(w->filename);
 
  828         w->filename = strdup(filename);
 
  846                                             char const * newname ) {
 
  847         watch *w = watch_from_filename(oldname);
 
  849         if (w->filename) free(w->filename);
 
  850         w->filename = strdup(newname);
 
  876                                     char const * newname ) {
 
  877         if ( !oldname || !newname ) 
return;
 
  878         struct replace_filename_data data;
 
  879         data.old_name = oldname;
 
  880         data.new_name = newname;
 
  881         data.old_len = strlen(oldname);
 
  882         rbwalk(tree_filename, (
void *)replace_filename, (
void *)&data);
 
  888 int remove_inotify_watch(watch *w) {
 
  890         int status = inotify_rm_watch( inotify_fd, w->wd );
 
  892                 fprintf(stderr, 
"Failed to remove watch on %s: %s\n", w->filename,
 
  903 watch *create_watch(
int wd, 
char *filename) {
 
  904         if ( wd <= 0 || !filename) 
return 0;
 
  906         watch *w = (watch*)calloc(1, 
sizeof(watch));
 
  908         w->filename = strdup(filename);
 
  909         rbsearch(w, tree_wd);
 
  910         rbsearch(w, tree_filename);
 
  927         niceassert( init, 
"inotifytools_initialize not called yet" );
 
  928         watch *w = watch_from_wd(wd);
 
  931         if (!remove_inotify_watch(w)) 
return 0;
 
  932         rbdelete(w, tree_wd);
 
  933         rbdelete(w, tree_filename);
 
  950         niceassert( init, 
"inotifytools_initialize not called yet" );
 
  951         watch *w = watch_from_filename(filename);
 
  954         if (!remove_inotify_watch(w)) 
return 0;
 
  955         rbdelete(w, tree_wd);
 
  956         rbdelete(w, tree_filename);
 
  973         static char const * filenames[2];
 
  974         filenames[0] = filename;
 
  995         niceassert( init, 
"inotifytools_initialize not called yet" );
 
  999         for ( i = 0; filenames[i]; ++i ) {
 
 1001                 wd = inotify_add_watch( inotify_fd, filenames[i], events );
 
 1008                                 fprintf( stderr, 
"Failed to watch %s: returned wd was %d " 
 1009                                          "(expected -1 or >0 )", filenames[i], wd );
 
 1017                 if ( !isdir(filenames[i])
 
 1018                      || filenames[i][strlen(filenames[i])-1] == 
'/') {
 
 1019                         filename = strdup(filenames[i]);
 
 1022                         nasprintf( &filename, 
"%s/", filenames[i] );
 
 1024                 create_watch(wd, filename);
 
 1111         niceassert( init, 
"inotifytools_initialize not called yet" );
 
 1112         niceassert( num_events <= MAX_EVENTS, 
"too many events requested" );
 
 1114         if ( num_events < 1 ) 
return NULL;
 
 1116         static struct inotify_event event[MAX_EVENTS];
 
 1117         static struct inotify_event * ret;
 
 1118         static int first_byte = 0;
 
 1119         static ssize_t bytes;
 
 1121         static struct nstring match_name;
 
 1122         static char match_name_string[MAX_STRLEN+1];
 
 1124 #define RETURN(A) {\ 
 1126                 inotifytools_snprintf(&match_name, MAX_STRLEN, A, "%w%f");\ 
 1127                 memcpy(&match_name_string, &match_name.buf, match_name.len);\ 
 1128                 match_name_string[match_name.len] = '\0';\ 
 1129                 if (0 == regexec(regex, match_name_string, 0, 0, 0)) {\ 
 1130                         if (!invert_regexp)\ 
 1137         if ( collect_stats ) {\ 
 1148         if ( first_byte != 0
 
 1149           && first_byte <= (
int)(bytes - 
sizeof(
struct inotify_event)) ) {
 
 1151                 ret = (
struct inotify_event *)((
char *)&
event[0] + first_byte);
 
 1152                 first_byte += 
sizeof(
struct inotify_event) + ret->len;
 
 1156                 if ( first_byte == bytes ) {
 
 1159                 else if ( first_byte > bytes ) {
 
 1166                         niceassert( (
long)((
char *)&event[0] +
 
 1167                                     sizeof(
struct inotify_event) +
 
 1168                                     event[0].len) <= (
long)ret,
 
 1169                                     "extremely unlucky user, death imminent" );
 
 1171                         bytes = (
char *)&event[0] + bytes - (
char *)ret;
 
 1172                         memcpy( &event[0], ret, bytes );
 
 1179         else if ( first_byte == 0 ) {
 
 1184         static ssize_t this_bytes;
 
 1185         static unsigned int bytes_to_read;
 
 1187         static fd_set read_fds;
 
 1189         static struct timeval read_timeout;
 
 1190         read_timeout.tv_sec = timeout;
 
 1191         read_timeout.tv_usec = 0;
 
 1192         static struct timeval * read_timeout_ptr;
 
 1193         read_timeout_ptr = ( timeout < 0 ? NULL : &read_timeout );
 
 1196         FD_SET(inotify_fd, &read_fds);
 
 1197         rc = select(inotify_fd + 1, &read_fds,
 
 1198                     NULL, NULL, read_timeout_ptr);
 
 1204         else if ( rc == 0 ) {
 
 1211                 rc = ioctl( inotify_fd, FIONREAD, &bytes_to_read );
 
 1213                   bytes_to_read < 
sizeof(
struct inotify_event)*num_events );
 
 1220         this_bytes = read(inotify_fd, &event[0] + bytes,
 
 1221                           sizeof(
struct inotify_event)*MAX_EVENTS - bytes);
 
 1222         if ( this_bytes < 0 ) {
 
 1226         if ( this_bytes == 0 ) {
 
 1227                 fprintf(stderr, 
"Inotify reported end-of-file.  Possibly too many " 
 1228                                 "events occurred at once.\n");
 
 1231         bytes += this_bytes;
 
 1234         first_byte = 
sizeof(
struct inotify_event) + ret->len;
 
 1235         niceassert( first_byte <= bytes, 
"ridiculously long filename, things will " 
 1236                                          "almost certainly screw up." );
 
 1237         if ( first_byte == bytes ) {
 
 1308                                                  char const ** exclude_list ) {
 
 1309         niceassert( init, 
"inotifytools_initialize not called yet" );
 
 1314         dir = opendir( path );
 
 1317                 if ( errno == ENOTDIR ) {
 
 1326         if ( path[strlen(path)-1] != 
'/' ) {
 
 1327                 nasprintf( &my_path, 
"%s/", path );
 
 1330                 my_path = (
char *)path;
 
 1333         static struct dirent * ent;
 
 1335         static struct stat64 my_stat;
 
 1336         ent = readdir( dir );
 
 1339                 if ( (0 != strcmp( ent->d_name, 
"." )) &&
 
 1340                      (0 != strcmp( ent->d_name, 
".." )) ) {
 
 1341                         nasprintf(&next_file,
"%s%s", my_path, ent->d_name);
 
 1342                         if ( -1 == lstat64( next_file, &my_stat ) ) {
 
 1345                                 if ( errno != EACCES ) {
 
 1347                                         if ( my_path != path ) free( my_path );
 
 1352                         else if ( S_ISDIR( my_stat.st_mode ) &&
 
 1353                                   !S_ISLNK( my_stat.st_mode )) {
 
 1355                                 nasprintf(&next_file,
"%s%s/", my_path, ent->d_name);
 
 1356                                 static unsigned int no_watch;
 
 1357                                 static char const ** exclude_entry;
 
 1360                                 for (exclude_entry = exclude_list;
 
 1361                                          exclude_entry && *exclude_entry && !no_watch;
 
 1363                                         static int exclude_length;
 
 1365                                         exclude_length = strlen(*exclude_entry);
 
 1366                                         if ((*exclude_entry)[exclude_length-1] == 
'/') {
 
 1369                                         if ( strlen(next_file) == (
unsigned)(exclude_length + 1) &&
 
 1370                                             !strncmp(*exclude_entry, next_file, exclude_length)) {
 
 1382                                         if ( !status && (EACCES != error) && (ENOENT != error) &&
 
 1383                                              (ELOOP != error) ) {
 
 1385                                                 if ( my_path != path ) free( my_path );
 
 1396                 ent = readdir( dir );
 
 1403         if ( my_path != path ) free( my_path );
 
 1410 void record_stats( 
struct inotify_event 
const * event ) {
 
 1412         watch *w = watch_from_wd(event->wd);
 
 1414         if ( IN_ACCESS & event->mask ) {
 
 1418         if ( IN_MODIFY & event->mask ) {
 
 1422         if ( IN_ATTRIB & event->mask ) {
 
 1426         if ( IN_CLOSE_WRITE & event->mask ) {
 
 1427                 ++w->hit_close_write;
 
 1430         if ( IN_CLOSE_NOWRITE & event->mask ) {
 
 1431                 ++w->hit_close_nowrite;
 
 1432                 ++num_close_nowrite;
 
 1434         if ( IN_OPEN & event->mask ) {
 
 1438         if ( IN_MOVED_FROM & event->mask ) {
 
 1439                 ++w->hit_moved_from;
 
 1442         if ( IN_MOVED_TO & event->mask ) {
 
 1446         if ( IN_CREATE & event->mask ) {
 
 1450         if ( IN_DELETE & event->mask ) {
 
 1454         if ( IN_DELETE_SELF & event->mask ) {
 
 1455                 ++w->hit_delete_self;
 
 1458         if ( IN_UNMOUNT & event->mask ) {
 
 1462         if ( IN_MOVE_SELF & event->mask ) {
 
 1472 unsigned int *stat_ptr(watch *w, 
int event)
 
 1474         if ( IN_ACCESS == event )
 
 1475                 return &w->hit_access;
 
 1476         if ( IN_MODIFY == event )
 
 1477                 return &w->hit_modify;
 
 1478         if ( IN_ATTRIB == event )
 
 1479                 return &w->hit_attrib;
 
 1480         if ( IN_CLOSE_WRITE == event )
 
 1481                 return &w->hit_close_write;
 
 1482         if ( IN_CLOSE_NOWRITE == event )
 
 1483                 return &w->hit_close_nowrite;
 
 1484         if ( IN_OPEN == event )
 
 1485                 return &w->hit_open;
 
 1486         if ( IN_MOVED_FROM == event )
 
 1487                 return &w->hit_moved_from;
 
 1488         if ( IN_MOVED_TO == event )
 
 1489                 return &w->hit_moved_to;
 
 1490         if ( IN_CREATE == event )
 
 1491                 return &w->hit_create;
 
 1492         if ( IN_DELETE == event )
 
 1493                 return &w->hit_delete;
 
 1494         if ( IN_DELETE_SELF == event )
 
 1495                 return &w->hit_delete_self;
 
 1496         if ( IN_UNMOUNT == event )
 
 1497                 return &w->hit_unmount;
 
 1498         if ( IN_MOVE_SELF == event )
 
 1499                 return &w->hit_move_self;
 
 1501                 return &w->hit_total;
 
 1521         if (!collect_stats) 
return -1;
 
 1523         watch *w = watch_from_wd(wd);
 
 1525         unsigned int *i = stat_ptr(w, event);
 
 1544         if (!collect_stats) 
return -1;
 
 1545         if ( IN_ACCESS == event )
 
 1547         if ( IN_MODIFY == event )
 
 1549         if ( IN_ATTRIB == event )
 
 1551         if ( IN_CLOSE_WRITE == event )
 
 1552                 return num_close_write;
 
 1553         if ( IN_CLOSE_NOWRITE == event )
 
 1554                 return num_close_nowrite;
 
 1555         if ( IN_OPEN == event )
 
 1557         if ( IN_MOVED_FROM == event )
 
 1558                 return num_moved_from;
 
 1559         if ( IN_MOVED_TO == event )
 
 1560                 return num_moved_to;
 
 1561         if ( IN_CREATE == event )
 
 1563         if ( IN_DELETE == event )
 
 1565         if ( IN_DELETE_SELF == event )
 
 1566                 return num_delete_self;
 
 1567         if ( IN_UNMOUNT == event )
 
 1569         if ( IN_MOVE_SELF == event )
 
 1570                 return num_move_self;
 
 1600                filename ), event );
 
 1620 static int isdir( 
char const * path ) {
 
 1621         static struct stat64 my_stat;
 
 1623         if ( -1 == lstat64( path, &my_stat ) ) {
 
 1624                 if (errno == ENOENT) 
return 0;
 
 1625                 fprintf(stderr, 
"Stat failed on %s: %s\n", path, strerror(errno));
 
 1629         return S_ISDIR( my_stat.st_mode ) && !S_ISLNK( my_stat.st_mode );
 
 1641         rbwalk(tree_filename, get_num, (
void*)&ret);
 
 1742         if ( -1 != ret ) fwrite( out.
buf, 
sizeof(
char), out.
len, file );
 
 1854                            struct inotify_event* event, 
char* fmt ) {
 
 1855         static char * filename, * eventname, * eventstr;
 
 1856         static unsigned int i, ind;
 
 1858         static char timestr[MAX_STRLEN];
 
 1861         if ( event->len > 0 ) {
 
 1862                 eventname = 
event->name;
 
 1871         if ( !fmt || 0 == strlen(fmt) ) {
 
 1875         if ( strlen(fmt) > MAX_STRLEN || size > MAX_STRLEN) {
 
 1881         for ( i = 0; i < strlen(fmt) &&
 
 1882                      (int)ind < size - 1; ++i ) {
 
 1883                 if ( fmt[i] != 
'%' ) {
 
 1884                         out->
buf[ind++] = fmt[i];
 
 1888                 if ( i == strlen(fmt) - 1 ) {
 
 1897                         out->
buf[ind++] = 
'%';
 
 1903                         out->
buf[ind++] = 
'\0';
 
 1909                         out->
buf[ind++] = 
'\n';
 
 1916                                 strncpy( &out->
buf[ind], filename, size - ind );
 
 1917                                 ind += strlen(filename);
 
 1925                                 strncpy( &out->
buf[ind], eventname, size - ind );
 
 1926                                 ind += strlen(eventname);
 
 1933                         ind += snprintf( &out->
buf[ind], size-ind, 
"%x", event->cookie);
 
 1940                         strncpy( &out->
buf[ind], eventstr, size - ind );
 
 1941                         ind += strlen(eventstr);
 
 1951                                 if (0 >= strftime(timestr, MAX_STRLEN - 1,
 
 1953                                                   localtime_r(&now, &now_tm))) {
 
 1963                         strncpy( &out->
buf[ind], timestr, size - ind );
 
 1964                         ind += strlen(timestr);
 
 1970                 if ( i < strlen(fmt) - 2 && fmt[i+2] == 
'e' ) {
 
 1972                         strncpy( &out->
buf[ind], eventstr, size - ind );
 
 1973                         ind += strlen(eventstr);
 
 1979                 if ( ind < MAX_STRLEN ) out->
buf[ind++] = 
'%';
 
 1980                 if ( ind < MAX_STRLEN ) out->
buf[ind++] = ch1;
 
 2011         if ( !read_num_from_file( QUEUE_SIZE_PATH, &ret ) ) 
return -1;
 
 2026         if ( !read_num_from_file( INSTANCES_PATH, &ret ) ) 
return -1;
 
 2041         if ( !read_num_from_file( WATCHES_SIZE_PATH, &ret ) ) 
return -1;
 
 2058 static int do_ignore_events_by_regex( 
char const *pattern, 
int flags, 
int invert ) {
 
 2068         if (regex) { regfree(regex); }
 
 2069         else       { regex = (regex_t *)malloc(
sizeof(regex_t)); }
 
 2071         invert_regexp = invert;
 
 2072         int ret = regcomp(regex, pattern, flags | REG_NOSUB);
 
 2073         if (0 == ret) 
return 1;
 
 2094         return do_ignore_events_by_regex(pattern, flags, 0);
 
 2109         return do_ignore_events_by_regex(pattern, flags, 1);
 
 2112 int event_compare(
const void *p1, 
const void *p2, 
const void *config)
 
 2114         if (!p1 || !p2) 
return p1 - p2;
 
 2116         long sort_event = (long)config;
 
 2117         if (sort_event == -1) {
 
 2120         } 
else if (sort_event < 0) {
 
 2121                 sort_event = -sort_event;
 
 2124         unsigned int *i1 = stat_ptr((watch*)p1, sort_event);
 
 2125         unsigned int *i2 = stat_ptr((watch*)p2, sort_event);
 
 2126         if (0 == *i1 - *i2) {
 
 2127                 return ((watch*)p1)->wd - ((watch*)p2)->wd;
 
 2135 struct rbtree *inotifytools_wd_sorted_by_event(
int sort_event)
 
 2137         struct rbtree *ret = rbinit(event_compare, (
void*)(uintptr_t)sort_event);
 
 2138         RBLIST *all = rbopenlist(tree_wd);
 
 2139         void const *p = rbreadlist(all);
 
 2141                 void const *r = rbsearch(p, ret);
 
 2142                 niceassert((
int)(r == p), 
"Couldn't insert watch into new tree");
 
 2143                 p = rbreadlist(all);