15#include "../../config.h" 
   17#include "inotifytools_p.h" 
   26#include <sys/select.h> 
   36#include "inotifytools/inotify.h" 
   39struct 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 
   51#include "inotifytools/fanotify.h" 
   53struct 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" 
  151static int inotify_fd = -1;
 
  153int collect_stats = 0;
 
  155struct rbtree *tree_wd = 0;
 
  156struct rbtree* tree_fid = 0;
 
  157struct rbtree *tree_filename = 0;
 
  161int fanotify_mode = 0;
 
  162int fanotify_mark_type = 0;
 
  163static char* timefmt = 0;
 
  164static regex_t* regex = 0;
 
  166static int invert_regexp = 0;
 
  168static int isdir( 
char const * path );
 
  169void record_stats( 
struct inotify_event 
const * event );
 
  170int onestr_to_event(
char const * event);
 
  172#define nasprintf(...) niceassert( -1 != asprintf(__VA_ARGS__), "out of memory")
 
  191void _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);
 
  204static void charcat(
char* s, 
const char c) {
 
  205        size_t l = strlen(s);
 
  213static 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);
 
  233static 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;
 
  238static int fid_compare(
const void* d1, 
const void* d2, 
const void* config) {
 
  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);
 
  255static 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);
 
  265watch *watch_from_wd( 
int wd ) {
 
  268        return (watch*)rbfind(&w, tree_wd);
 
  274watch* watch_from_fid(
struct fanotify_event_fid* fid) {
 
  277        return (watch*)rbfind(&w, tree_fid);
 
  283watch *watch_from_filename( 
char const *filename ) {
 
  285        w.filename = (
char*)filename;
 
  286        return (watch*)rbfind(&w, tree_filename);
 
  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);
 
  332int inotifytools_initialize() {
 
  339void destroy_watch(watch *w) {
 
  340        if (w->filename) free(w->filename);
 
  351void 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);
 
  394struct replace_filename_data {
 
  395    char const *old_name;
 
  396    char const *new_name;
 
  403static 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);
 
  427static 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 );
 
  553int 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 );
 
  746static const char* inotifytools_filename_from_fid(
 
  747    struct fanotify_event_fid* fid) {
 
  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);
 
 1041int 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,
 
 1059watch* 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 );
 
 1797static 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;
 
 2235static 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);
 
 2289int 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;
 
 2312struct 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.