"Fossies" - the Fresh Open Source Software Archive

Member "inotify-tools-3.20.11.0/libinotifytools/src/inotifytools.c" (13 Nov 2020, 66626 Bytes) of package /linux/privat/inotify-tools-3.20.11.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "inotifytools.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.20.2.2_vs_3.20.11.0.

    1 // kate: replace-tabs off; space-indent off;
    2 
    3 /**
    4  * @mainpage libinotifytools
    5  *
    6  * libinotifytools is a small C library to simplify the use of Linux's inotify
    7  * interface.
    8  *
    9  * @link inotifytools/inotifytools.h Documentation for the library's public
   10  * interface.@endlink
   11  *
   12  * @link todo.html TODO list.@endlink
   13  */
   14 
   15 #include "../../config.h"
   16 #include "inotifytools/inotifytools.h"
   17 #include "inotifytools_p.h"
   18 
   19 #include <string.h>
   20 #include <strings.h>
   21 #include <stdlib.h>
   22 #include <stdint.h>
   23 #include <stdio.h>
   24 #include <errno.h>
   25 #include <sys/select.h>
   26 #include <sys/types.h>
   27 #include <sys/stat.h>
   28 #include <sys/ioctl.h>
   29 #include <unistd.h>
   30 #include <dirent.h>
   31 #include <time.h>
   32 #include <regex.h>
   33 #include <setjmp.h>
   34 
   35 #include "inotifytools/inotify.h"
   36 
   37 /**
   38  * @file inotifytools/inotifytools.h
   39  * @brief inotifytools library public interface.
   40  * @author Rohan McGovern, \<rohan@mcgovern.id.au\>
   41  *
   42  * This library provides a thin layer on top of the basic inotify interface.
   43  * The primary use is to easily set up watches on files, potentially many files
   44  * at once, and read events without having to deal with low-level I/O.  There
   45  * are also several utility functions for inotify-related string formatting.
   46  *
   47  * To use this library, you must \c \#include the following headers accordingly:
   48  * \li \c \<inotifytools/inotifytools.h\> - to use any functions declared in
   49  *     this file.
   50  * \li \c \<inotifytools/inotify.h\> - to have the \c inotify_event type defined
   51  *     and the numeric IN_* event constants defined.   If \c \<sys/inotify.h\>
   52  *     was present on your system at compile time, this header simply includes
   53  *     that.  Otherwise it includes \c \<inotifytools/inotify-nosys.h\>.
   54  *
   55  * @section example Example
   56  * This very simple program recursively watches the entire directory tree
   57  * under its working directory for events, then prints them out with a
   58  * timestamp.
   59  * @include example.c
   60  *
   61  * @section events Events
   62  *
   63  * @note This section comes almost verbatim from the inotify(7) man page.
   64  *
   65  * @warning The information here applies to inotify in Linux 2.6.17.  Older
   66  *          versions of Linux may not support all the events described here.
   67  *
   68  * The following numeric events can be specified to functions in inotifytools,
   69  * and may be present in events returned through inotifytools:
   70  *
   71  * \li \c IN_ACCESS     -     File was accessed (read) \a *
   72  * \li \c IN_ATTRIB     -     Metadata changed (permissions, timestamps,
   73  *                            extended attributes, etc.) \a *
   74  * \li \c IN_CLOSE_WRITE -    File opened for writing was closed \a *
   75  * \li \c IN_CLOSE_NOWRITE -   File not opened for writing was closed \a *
   76  * \li \c IN_CREATE       -   File/directory created in watched directory \a *
   77  * \li \c IN_DELETE       -   File/directory deleted from watched directory \a *
   78  * \li \c IN_DELETE_SELF  -   Watched file/directory was itself deleted
   79  * \li \c IN_MODIFY       -   File was modified \a *
   80  * \li \c IN_MOVE_SELF    -   Watched file/directory was itself moved
   81  * \li \c IN_MOVED_FROM   -   File moved out of watched directory \a *
   82  * \li \c IN_MOVED_TO     -   File moved into watched directory \a *
   83  * \li \c IN_OPEN         -   File was opened \a *
   84  *
   85  * When monitoring a directory, the events marked with an asterisk \a * above
   86  * can  occur  for files  in the directory, in which case the name field in the
   87  * returned inotify_event structure identifies the name of the file within the
   88  * directory.
   89  *
   90  * The IN_ALL_EVENTS macro is defined as a bit mask of all of the above events.
   91  *
   92  * Two additional convenience macros are IN_MOVE, which equates to
   93  * IN_MOVED_FROM|IN_MOVED_TO, and IN_CLOSE which equates to
   94  * IN_CLOSE_WRITE|IN_CLOSE_NOWRITE.
   95  *
   96  * The following bitmasks can also be provided when creating a new watch:
   97  *
   98  * \li \c IN_DONT_FOLLOW  - Don't dereference pathname if it is a symbolic link
   99  * \li \c IN_MASK_ADD    -  Add (OR) events to watch mask for this pathname if
  100  *                          it already exists (instead of replacing mask)
  101  * \li \c IN_ONESHOT    -   Monitor pathname for one event, then remove from
  102  *                          watch list
  103  * \li \c IN_ONLYDIR    -   Only watch pathname if it is a directory
  104  *
  105  * The following bitmasks may occur in events generated by a watch:
  106  *
  107  * \li \c IN_IGNORED   -   Watch was removed explicitly
  108  *                        (inotifytools_remove_watch_*) or automatically (file
  109  *                        was deleted, or file system was unmounted)
  110  * \li \c IN_ISDIR   -     Subject of this event is a directory
  111  * \li \c IN_Q_OVERFLOW  - Event queue overflowed (wd is -1 for this event)
  112  * \li \c IN_UNMOUNT    -  File system containing watched object was unmounted
  113  *
  114  * @section TODO TODO list
  115  *
  116  * @todo Improve wd/filename mapping.  Currently there is no explicit code for
  117  *       handling different filenames mapping to the same inode (and hence, wd).
  118  *       gamin's approach sounds good: let the user watch an inode using several
  119  *       different filenames, and when an event occurs on the inode, generate an
  120  *       event for each filename.
  121  */
  122 
  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"
  128 
  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;
  145 
  146 struct rbtree *tree_wd = 0;
  147 struct rbtree *tree_filename = 0;
  148 static int error = 0;
  149 static int init = 0;
  150 static char* timefmt = 0;
  151 static regex_t* regex = 0;
  152 /* 0: --exclude[i], 1: --include[i] */
  153 static int invert_regexp = 0;
  154 
  155 static int isdir( char const * path );
  156 void record_stats( struct inotify_event const * event );
  157 int onestr_to_event(char const * event);
  158 
  159 /**
  160  * @internal
  161  * Assert that a condition evaluates to true, and optionally output a message
  162  * if the assertion fails.
  163  *
  164  * @param  cond  Integer; if 0, assertion fails, otherwise assertion succeeds.
  165  *
  166  * @param  mesg  A human-readable error message shown if assertion fails.
  167  *
  168  * @section example Example
  169  * @code
  170  * int upper = 100, lower = 50;
  171  * int input = get_user_input();
  172  * niceassert( input <= upper && input >= lower,
  173  *             "input not in required range!");
  174  * @endcode
  175  */
  176 #define niceassert(cond,mesg) _niceassert((long)cond, __LINE__, __FILE__, \
  177                                           #cond, mesg)
  178 
  179 #define nasprintf(...) niceassert( -1 != asprintf(__VA_ARGS__), "out of memory")
  180 
  181 /**
  182  * @internal
  183  * Assert that a condition evaluates to true, and optionally output a message
  184  * if the assertion fails.
  185  *
  186  * You should use the niceassert() preprocessor macro instead.
  187  *
  188  * @param  cond  If 0, assertion fails, otherwise assertion succeeds.
  189  *
  190  * @param  line  Line number of source code where assertion is made.
  191  *
  192  * @param  file  Name of source file where assertion is made.
  193  *
  194  * @param  condstr  Stringified assertion expression.
  195  *
  196  * @param  mesg  A human-readable error message shown if assertion fails.
  197  */
  198 static void _niceassert( long cond, int line, char const * file,
  199                   char const * condstr, char const * mesg ) {
  200     if ( cond ) return;
  201 
  202     if ( mesg ) {
  203         fprintf(stderr, "%s:%d assertion ( %s ) failed: %s\n", file, line,
  204                 condstr, mesg );
  205     }
  206     else {
  207         fprintf(stderr, "%s:%d assertion ( %s ) failed.\n", file, line, condstr);
  208     }
  209 }
  210 
  211 /**
  212  * @internal
  213  * Construct a string from a character.
  214  *
  215  * @param ch A character.
  216  *
  217  * @return A string of length 1 consisting of the character @a ch.  The string
  218  *         will be overwritten in subsequent calls.
  219  */
  220 char * chrtostr(char ch) {
  221     static char str[2] = { '\0', '\0' };
  222     str[0] = ch;
  223     return str;
  224 }
  225 
  226 /**
  227  * @internal
  228  */
  229 int read_num_from_file( char * filename, int * num ) {
  230     FILE * file = fopen( filename, "r" );
  231     if ( !file ) {
  232         error = errno;
  233         return 0;
  234     }
  235 
  236     if ( EOF == fscanf( file, "%d", num ) ) {
  237         error = errno;
  238         return 0;
  239     }
  240 
  241     niceassert( 0 == fclose( file ), 0 );
  242 
  243     return 1;
  244 }
  245 
  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;
  249 }
  250 
  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);
  254 }
  255 
  256 /**
  257  * @internal
  258  */
  259 watch *watch_from_wd( int wd ) {
  260     watch w;
  261     w.wd = wd;
  262     return (watch*)rbfind(&w, tree_wd);
  263 }
  264 
  265 /**
  266  * @internal
  267  */
  268 watch *watch_from_filename( char const *filename ) {
  269     watch w;
  270     w.filename = (char*)filename;
  271     return (watch*)rbfind(&w, tree_filename);
  272 }
  273 
  274 /**
  275  * Initialise inotify.
  276  *
  277  * You must call this function before using any function which adds or removes
  278  * watches or attempts to access any information about watches.
  279  *
  280  * @return 1 on success, 0 on failure.  On failure, the error can be
  281  *         obtained from inotifytools_error().
  282  */
  283 int inotifytools_initialize() {
  284     if (init) return 1;
  285 
  286     error = 0;
  287     // Try to initialise inotify
  288     inotify_fd = inotify_init();
  289     if (inotify_fd < 0) {
  290         error = errno;
  291         return 0;
  292     }
  293 
  294     collect_stats = 0;
  295     init = 1;
  296     tree_wd = rbinit(wd_compare, 0);
  297     tree_filename = rbinit(filename_compare, 0);
  298     timefmt = 0;
  299 
  300     return 1;
  301 }
  302 
  303 /**
  304  * @internal
  305  */
  306 void destroy_watch(watch *w) {
  307     if (w->filename) free(w->filename);
  308     free(w);
  309 }
  310 
  311 /**
  312  * @internal
  313  */
  314 void cleanup_tree(const void *nodep,
  315                  const VISIT which,
  316                  const int depth, void* arg) {
  317     if (which != endorder && which != leaf) return;
  318     watch *w = (watch*)nodep;
  319     destroy_watch(w);
  320 }
  321 
  322 /**
  323  * Close inotify and free the memory used by inotifytools.
  324  *
  325  * If you call this function, you must call inotifytools_initialize()
  326  * again before any other functions can be used.
  327  */
  328 void inotifytools_cleanup() {
  329     if (!init) return;
  330 
  331     init = 0;
  332     close(inotify_fd);
  333     collect_stats = 0;
  334     error = 0;
  335     timefmt = 0;
  336 
  337     if (regex) {
  338         regfree(regex);
  339         free(regex);
  340         regex = 0;
  341     }
  342 
  343     rbwalk(tree_wd, cleanup_tree, 0);
  344     rbdestroy(tree_wd); tree_wd = 0;
  345     rbdestroy(tree_filename); tree_filename = 0;
  346 }
  347 
  348 /**
  349  * @internal
  350  */
  351 void empty_stats(const void *nodep,
  352                  const VISIT which,
  353                  const int depth, void *arg) {
  354     if (which != endorder && which != leaf) return;
  355     watch *w = (watch*)nodep;
  356     w->hit_access = 0;
  357     w->hit_modify = 0;
  358     w->hit_attrib = 0;
  359     w->hit_close_nowrite = 0;
  360     w->hit_close_write = 0;
  361     w->hit_open = 0;
  362     w->hit_move_self = 0;
  363     w->hit_moved_from = 0;
  364     w->hit_moved_to = 0;
  365     w->hit_create = 0;
  366     w->hit_delete = 0;
  367     w->hit_delete_self = 0;
  368     w->hit_unmount = 0;
  369     w->hit_total = 0;
  370 }
  371 
  372 /**
  373  * @internal
  374  */
  375 struct replace_filename_data {
  376     char const *old_name;
  377     char const *new_name;
  378     size_t old_len;
  379 };
  380 
  381 /**
  382  * @internal
  383  */
  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;
  388     char *name;
  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 )) {
  392             free(name);
  393         } else {
  394             rbdelete(w, tree_filename);
  395             free( w->filename );
  396             w->filename = name;
  397             rbsearch(w, tree_filename);
  398         }
  399     }
  400 }
  401 
  402 /**
  403  * @internal
  404  */
  405 void get_num(const void *nodep,
  406              const VISIT which,
  407              const int depth, void *arg) {
  408     if (which != endorder && which != leaf) return;
  409     ++(*((int*)arg));
  410 }
  411 
  412 
  413 /**
  414  * Initialize or reset statistics.
  415  *
  416  * inotifytools_initialize() must be called before this function can
  417  * be used.
  418  *
  419  * When this function is called, all subsequent events will be tallied.
  420  * Statistics can then be obtained via the @a inotifytools_get_stat_* functions.
  421  *
  422  * After the first call, subsequent calls to this function will reset the
  423  * event tallies to 0.
  424  */
  425 void inotifytools_initialize_stats() {
  426     niceassert( init, "inotifytools_initialize not called yet" );
  427 
  428     // if already collecting stats, reset stats
  429     if (collect_stats) {
  430         rbwalk(tree_wd, empty_stats, 0);
  431     }
  432 
  433     num_access = 0;
  434     num_modify = 0;
  435     num_attrib = 0;
  436     num_close_nowrite = 0;
  437     num_close_write = 0;
  438     num_open = 0;
  439     num_move_self = 0;
  440     num_moved_from = 0;
  441     num_moved_to = 0;
  442     num_create = 0;
  443     num_delete = 0;
  444     num_delete_self = 0;
  445     num_unmount = 0;
  446     num_total = 0;
  447 
  448     collect_stats = 1;
  449 }
  450 
  451 /**
  452  * Convert character separated events from string form to integer form
  453  * (as in inotify.h).
  454  *
  455  * @param    event    a sequence of events in string form as defined in
  456  *                    inotify.h without leading IN_ prefix (e.g., MODIFY,
  457  *                    ATTRIB), separated by the @a sep character.  Case
  458  *                    insensitive.  Can be a single event.
  459  *                    Can be empty or NULL.  See section \ref events.
  460  *
  461  * @param    sep      Character used to separate events.  @a sep must not be
  462  *                    a character in a-z, A-Z, or _.
  463  *
  464  * @return            integer representing the mask specified by @a event, or 0
  465  *                    if any string in @a event is empty or NULL, or -1 if
  466  *                    any string in @a event does not match any event or
  467  *                    @a sep is invalid.
  468  *
  469  * @section example Example
  470  * @code
  471  * char * eventstr = "MODIFY:CLOSE:CREATE";
  472  * int eventnum = inotifytools_str_to_event_sep( eventstr, ':' );
  473  * if ( eventnum == IN_MODIFY | IN_CLOSE | IN_CREATE ) {
  474  *    printf( "This code always gets executed!\n" );
  475  * }
  476  * @endcode
  477  */
  478 int inotifytools_str_to_event_sep(char const * event, char sep) {
  479     if ( strchr( "_" "abcdefghijklmnopqrstuvwxyz"
  480                      "ABCDEFGHIJKLMNOPQRSTUVWXYZ", sep ) ) {
  481         return -1;
  482     }
  483 
  484     int ret, ret1, len;
  485     char * event1, * event2;
  486         static const size_t eventstr_size = 4096;
  487         char eventstr[eventstr_size];
  488         ret = 0;
  489 
  490     if ( !event || !event[0] ) return 0;
  491 
  492     event1 = (char *)event;
  493     event2 = strchr( event1, sep );
  494     while ( event1 && event1[0] ) {
  495         if ( event2 ) {
  496             len = event2 - event1;
  497                         niceassert(len < eventstr_size,
  498                                    "malformed event string (very long)");
  499                 }
  500         else {
  501             len = strlen(event1);
  502         }
  503                 if (len > eventstr_size - 1)
  504                     len = eventstr_size - 1;
  505 
  506                 if (event2 || len == eventstr_size - 1) {
  507                     strncpy(eventstr, event1, len);
  508                 } else {
  509                     strcpy(eventstr, event1);
  510                 }
  511 
  512                 eventstr[len] = 0;
  513 
  514         ret1 = onestr_to_event( eventstr );
  515         if ( 0 == ret1 || -1 == ret1 ) {
  516             ret = ret1;
  517             break;
  518         }
  519         ret |= ret1;
  520 
  521         event1 = event2;
  522         if ( event1 && event1[0] ) {
  523             // jump over 'sep' character
  524             ++event1;
  525             // if last character was 'sep'...
  526             if ( !event1[0] ) return 0;
  527             event2 = strchr( event1, sep );
  528         }
  529     }
  530 
  531     return ret;
  532 }
  533 
  534 /**
  535  * Convert comma-separated events from string form to integer form
  536  * (as in inotify.h).
  537  *
  538  * @param    event    a sequence of events in string form as defined in
  539  *                    inotify.h without leading IN_ prefix (e.g., MODIFY,
  540  *                    ATTRIB), comma-separated.  Case
  541  *                    insensitive.  Can be a single event.
  542  *                    Can be empty or NULL.  See section \ref events.
  543  *
  544  * @return            integer representing the mask specified by @a event, or 0
  545  *                    if any string in @a event is empty or NULL, or -1 if
  546  *                    any string in @a event does not match any event.
  547  *
  548  * @section example Example
  549  * @code
  550  * char * eventstr = "MODIFY,CLOSE,CREATE";
  551  * int eventnum = inotifytools_str_to_event( eventstr );
  552  * if ( eventnum == IN_MODIFY | IN_CLOSE | IN_CREATE ) {
  553  *    printf( "This code always gets executed!\n" );
  554  * }
  555  * @endcode
  556  */
  557 int inotifytools_str_to_event(char const * event) {
  558     return inotifytools_str_to_event_sep( event, ',' );
  559 }
  560 
  561 /**
  562  * @internal
  563  * Convert a single event from string form to integer form (as in inotify.h).
  564  *
  565  * @param    event    event in string form as defined in inotify.h without
  566  *                    leading IN_ prefix (e.g., MODIFY, ATTRIB).  Case
  567  *                    insensitive.  Can be empty or NULL.
  568  * @return            integer representing the mask specified by 'event', or 0
  569  *                    if @a event is empty or NULL, or -1 if string does not
  570  *                    match any event.
  571  */
  572 int onestr_to_event(char const * event)
  573 {
  574     static int ret;
  575     ret = -1;
  576 
  577     if ( !event || !event[0] )
  578         ret = 0;
  579     else if ( 0 == strcasecmp(event, "ACCESS") )
  580         ret = IN_ACCESS;
  581     else if ( 0 == strcasecmp(event, "MODIFY") )
  582         ret = IN_MODIFY;
  583     else if ( 0 == strcasecmp(event, "ATTRIB") )
  584         ret = IN_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") )
  590         ret = IN_OPEN;
  591     else if ( 0 == strcasecmp(event, "MOVED_FROM") )
  592         ret = IN_MOVED_FROM;
  593     else if ( 0 == strcasecmp(event, "MOVED_TO") )
  594         ret = IN_MOVED_TO;
  595     else if ( 0 == strcasecmp(event, "CREATE") )
  596         ret = IN_CREATE;
  597     else if ( 0 == strcasecmp(event, "DELETE") )
  598         ret = IN_DELETE;
  599     else if ( 0 == strcasecmp(event, "DELETE_SELF") )
  600         ret = IN_DELETE_SELF;
  601     else if ( 0 == strcasecmp(event, "UNMOUNT") )
  602         ret = IN_UNMOUNT;
  603     else if ( 0 == strcasecmp(event, "Q_OVERFLOW") )
  604         ret = IN_Q_OVERFLOW;
  605     else if ( 0 == strcasecmp(event, "IGNORED") )
  606         ret = IN_IGNORED;
  607     else if ( 0 == strcasecmp(event, "CLOSE") )
  608         ret = IN_CLOSE;
  609     else if ( 0 == strcasecmp(event, "MOVE_SELF") )
  610         ret = IN_MOVE_SELF;
  611     else if ( 0 == strcasecmp(event, "MOVE") )
  612         ret = IN_MOVE;
  613     else if ( 0 == strcasecmp(event, "ISDIR") )
  614         ret = IN_ISDIR;
  615     else if ( 0 == strcasecmp(event, "ONESHOT") )
  616         ret = IN_ONESHOT;
  617     else if ( 0 == strcasecmp(event, "ALL_EVENTS") )
  618         ret = IN_ALL_EVENTS;
  619 
  620     return ret;
  621 }
  622 
  623 /**
  624  * Convert event from integer form to string form (as in inotify.h).
  625  *
  626  * The returned string is from static storage; subsequent calls to this function
  627  * or inotifytools_event_to_str_sep() will overwrite it.  Don't free() it and
  628  * make a copy if you want to keep it.
  629  *
  630  * @param    events   OR'd event(s) in integer form as defined in inotify.h.
  631  *                    See section \ref events.
  632  *
  633  * @return            comma-separated string representing the event(s), in no
  634  *                    particular order
  635  *
  636  * @section example Example
  637  * @code
  638  * int eventnum == IN_MODIFY | IN_CLOSE | IN_CREATE;
  639  * char * eventstr = inotifytools_event_to_str( eventnum );
  640  * printf( "%s\n", eventstr );
  641  * // outputs something like MODIFY,CLOSE,CREATE but order not guaranteed.
  642  * @endcode
  643  */
  644 char * inotifytools_event_to_str(int events) {
  645     return inotifytools_event_to_str_sep(events, ',');
  646 }
  647 
  648 /**
  649  * Convert event from integer form to string form (as in inotify.h).
  650  *
  651  * The returned string is from static storage; subsequent calls to this function
  652  * or inotifytools_event_to_str() will overwrite it.  Don't free() it and
  653  * make a copy if you want to keep it.
  654  *
  655  * @param    events   OR'd event(s) in integer form as defined in inotify.h
  656  *
  657  * @param    sep      character used to separate events
  658  *
  659  * @return            @a sep separated string representing the event(s), in no
  660  *                    particular order.  If the integer is not made of OR'ed
  661  *                    inotify events, the string returned will be a hexadecimal
  662  *                    representation of the integer.
  663  *
  664  * @section example Example
  665  * @code
  666  * int eventnum == IN_MODIFY | IN_CLOSE | IN_CREATE;
  667  * char * eventstr = inotifytools_event_to_str_sep( eventnum, '-' );
  668  * printf( "%s\n", eventstr );
  669  * // outputs something like MODIFY-CLOSE-CREATE but order not guaranteed.
  670  * @endcode
  671  */
  672 char * inotifytools_event_to_str_sep(int events, char sep)
  673 {
  674     static char ret[1024];
  675     ret[0] = '\0';
  676     ret[1] = '\0';
  677 
  678     if ( IN_ACCESS & events ) {
  679         strcat( ret, chrtostr(sep) );
  680         strcat( ret, "ACCESS" );
  681     }
  682     if ( IN_MODIFY & events ) {
  683         strcat( ret, chrtostr(sep) );
  684         strcat( ret, "MODIFY" );
  685     }
  686     if ( IN_ATTRIB & events ) {
  687         strcat( ret, chrtostr(sep) );
  688         strcat( ret, "ATTRIB" );
  689     }
  690     if ( IN_CLOSE_WRITE & events ) {
  691         strcat( ret, chrtostr(sep) );
  692         strcat( ret, "CLOSE_WRITE" );
  693     }
  694     if ( IN_CLOSE_NOWRITE & events ) {
  695         strcat( ret, chrtostr(sep) );
  696         strcat( ret, "CLOSE_NOWRITE" );
  697     }
  698     if ( IN_OPEN & events ) {
  699         strcat( ret, chrtostr(sep) );
  700         strcat( ret, "OPEN" );
  701     }
  702     if ( IN_MOVED_FROM & events ) {
  703         strcat( ret, chrtostr(sep) );
  704         strcat( ret, "MOVED_FROM" );
  705     }
  706     if ( IN_MOVED_TO & events ) {
  707         strcat( ret, chrtostr(sep) );
  708         strcat( ret, "MOVED_TO" );
  709     }
  710     if ( IN_CREATE & events ) {
  711         strcat( ret, chrtostr(sep) );
  712         strcat( ret, "CREATE" );
  713     }
  714     if ( IN_DELETE & events ) {
  715         strcat( ret, chrtostr(sep) );
  716         strcat( ret, "DELETE" );
  717     }
  718     if ( IN_DELETE_SELF & events ) {
  719         strcat( ret, chrtostr(sep) );
  720         strcat( ret, "DELETE_SELF" );
  721     }
  722     if ( IN_UNMOUNT & events ) {
  723         strcat( ret, chrtostr(sep) );
  724         strcat( ret, "UNMOUNT" );
  725     }
  726     if ( IN_Q_OVERFLOW & events ) {
  727         strcat( ret, chrtostr(sep) );
  728         strcat( ret, "Q_OVERFLOW" );
  729     }
  730     if ( IN_IGNORED & events ) {
  731         strcat( ret, chrtostr(sep) );
  732         strcat( ret, "IGNORED" );
  733     }
  734     if ( IN_CLOSE & events ) {
  735         strcat( ret, chrtostr(sep) );
  736         strcat( ret, "CLOSE" );
  737     }
  738     if ( IN_MOVE_SELF & events ) {
  739         strcat( ret, chrtostr(sep) );
  740         strcat( ret, "MOVE_SELF" );
  741     }
  742     if ( IN_ISDIR & events ) {
  743         strcat( ret, chrtostr(sep) );
  744         strcat( ret, "ISDIR" );
  745     }
  746     if ( IN_ONESHOT & events ) {
  747         strcat( ret, chrtostr(sep) );
  748         strcat( ret, "ONESHOT" );
  749     }
  750 
  751     // Maybe we didn't match any... ?
  752     if (ret[0] == '\0') {
  753         niceassert( -1 != sprintf( ret, "%c0x%08x", sep, events ), 0 );
  754     }
  755 
  756     return &ret[1];
  757 }
  758 
  759 /**
  760  * Get the filename used to establish a watch.
  761  *
  762  * inotifytools_initialize() must be called before this function can
  763  * be used.
  764  *
  765  * @param wd watch descriptor.
  766  *
  767  * @return filename associated with watch descriptor @a wd, or NULL if @a wd
  768  *         is not associated with any filename.
  769  *
  770  * @note This always returns the filename which was used to establish a watch.
  771  *       This means the filename may be a relative path.  If this isn't desired,
  772  *       then always use absolute paths when watching files.
  773  *       Also, this is not necessarily the filename which might have been used
  774  *       to cause an event on the file, since inotify is inode based and there
  775  *       can be many filenames mapping to a single inode.
  776  *       Finally, if a file is moved or renamed while being watched, the
  777  *       filename returned will still be the original name.
  778  */
  779 char * inotifytools_filename_from_wd( int wd ) {
  780     niceassert( init, "inotifytools_initialize not called yet" );
  781     watch *w = watch_from_wd(wd);
  782     if (!w)
  783         return NULL;
  784 
  785     return w->filename;
  786 }
  787 
  788 /**
  789  * Get the watch descriptor for a particular filename.
  790  *
  791  * inotifytools_initialize() must be called before this function can
  792  * be used.
  793  *
  794  * @param filename file name to find watch descriptor for.
  795  *
  796  * @return watch descriptor associated with filename, or -1 if @a filename is
  797  *         not associated with any watch descriptor.
  798  *
  799  * @note The filename specified must always be the original name used to
  800  *       establish the watch.
  801  */
  802 int inotifytools_wd_from_filename( char const * filename ) {
  803     niceassert( init, "inotifytools_initialize not called yet" );
  804     watch *w = watch_from_filename(filename);
  805     if (!w) return -1;
  806     return w->wd;
  807 }
  808 
  809 /**
  810  * Set the filename for a particular watch descriptor.
  811  *
  812  * This function should be used to update a filename when a file is known to
  813  * have been moved or renamed.  At the moment, libinotifytools does not
  814  * automatically handle this situation.
  815  *
  816  * inotifytools_initialize() must be called before this function can
  817  * be used.
  818  *
  819  * @param wd Watch descriptor.
  820  *
  821  * @param filename New filename.
  822  */
  823 void inotifytools_set_filename_by_wd( int wd, char const * filename ) {
  824     niceassert( init, "inotifytools_initialize not called yet" );
  825     watch *w = watch_from_wd(wd);
  826     if (!w) return;
  827     if (w->filename) free(w->filename);
  828     w->filename = strdup(filename);
  829 }
  830 
  831 /**
  832  * Set the filename for one or more watches with a particular existing filename.
  833  *
  834  * This function should be used to update a filename when a file is known to
  835  * have been moved or renamed.  At the moment, libinotifytools does not
  836  * automatically handle this situation.
  837  *
  838  * inotifytools_initialize() must be called before this function can
  839  * be used.
  840  *
  841  * @param oldname Current filename.
  842  *
  843  * @param newname New filename.
  844  */
  845 void inotifytools_set_filename_by_filename( char const * oldname,
  846                                             char const * newname ) {
  847     watch *w = watch_from_filename(oldname);
  848     if (!w) return;
  849     if (w->filename) free(w->filename);
  850     w->filename = strdup(newname);
  851 }
  852 
  853 /**
  854  * Replace a certain filename prefix on all watches.
  855  *
  856  * This function should be used to update filenames for an entire directory tree
  857  * when a directory is known to have been moved or renamed.  At the moment,
  858  * libinotifytools does not automatically handle this situation.
  859  *
  860  * inotifytools_initialize() must be called before this function can
  861  * be used.
  862  *
  863  * @param oldname Current filename prefix.
  864  *
  865  * @param newname New filename prefix.
  866  *
  867  * @section example Example
  868  * @code
  869  * // if /home/user1/original_dir is moved to /home/user2/new_dir, then to
  870  * // update all watches:
  871  * inotifytools_replace_filename( "/home/user1/original_dir",
  872  *                                "/home/user2/new_dir" );
  873  * @endcode
  874  */
  875 void inotifytools_replace_filename( char const * oldname,
  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);
  883 }
  884 
  885 /**
  886  * @internal
  887  */
  888 int remove_inotify_watch(watch *w) {
  889     error = 0;
  890     int status = inotify_rm_watch( inotify_fd, w->wd );
  891     if ( status < 0 ) {
  892         fprintf(stderr, "Failed to remove watch on %s: %s\n", w->filename,
  893                 strerror(status) );
  894         error = status;
  895         return 0;
  896     }
  897     return 1;
  898 }
  899 
  900 /**
  901  * @internal
  902  */
  903 watch *create_watch(int wd, char *filename) {
  904     if ( wd <= 0 || !filename) return 0;
  905 
  906     watch *w = (watch*)calloc(1, sizeof(watch));
  907     w->wd = wd;
  908     w->filename = strdup(filename);
  909     rbsearch(w, tree_wd);
  910     rbsearch(w, tree_filename);
  911     return NULL;
  912 }
  913 
  914 /**
  915  * Remove a watch on a file specified by watch descriptor.
  916  *
  917  * inotifytools_initialize() must be called before this function can
  918  * be used.
  919  *
  920  * @param wd Watch descriptor of watch to be removed.
  921  *
  922  * @return 1 on success, 0 on failure.  If the given watch doesn't exist,
  923  *         returns 1.  On failure, the error can be
  924  *         obtained from inotifytools_error().
  925  */
  926 int inotifytools_remove_watch_by_wd( int wd ) {
  927     niceassert( init, "inotifytools_initialize not called yet" );
  928     watch *w = watch_from_wd(wd);
  929     if (!w) return 1;
  930 
  931     if (!remove_inotify_watch(w)) return 0;
  932     rbdelete(w, tree_wd);
  933     rbdelete(w, tree_filename);
  934     destroy_watch(w);
  935     return 1;
  936 }
  937 
  938 /**
  939  * Remove a watch on a file specified by filename.
  940  *
  941  * @param filename Name of file on which watch should be removed.
  942  *
  943  * @return 1 on success, 0 on failure.  On failure, the error can be
  944  *         obtained from inotifytools_error().
  945  *
  946  * @note The filename specified must always be the original name used to
  947  *       establish the watch.
  948  */
  949 int inotifytools_remove_watch_by_filename( char const * filename ) {
  950     niceassert( init, "inotifytools_initialize not called yet" );
  951     watch *w = watch_from_filename(filename);
  952     if (!w) return 1;
  953 
  954     if (!remove_inotify_watch(w)) return 0;
  955     rbdelete(w, tree_wd);
  956     rbdelete(w, tree_filename);
  957     destroy_watch(w);
  958     return 1;
  959 }
  960 
  961 /**
  962  * Set up a watch on a file.
  963  *
  964  * @param filename Absolute or relative path of file to watch.
  965  *
  966  * @param events bitwise ORed inotify events to watch for.  See section
  967  *               \ref events.
  968  *
  969  * @return 1 on success, 0 on failure.  On failure, the error can be
  970  *         obtained from inotifytools_error().
  971  */
  972 int inotifytools_watch_file( char const * filename, int events ) {
  973     static char const * filenames[2];
  974     filenames[0] = filename;
  975     filenames[1] = NULL;
  976     return inotifytools_watch_files( filenames, events );
  977 }
  978 
  979 /**
  980  * Set up a watch on a list of files.
  981  *
  982  * inotifytools_initialize() must be called before this function can
  983  * be used.
  984  *
  985  * @param filenames null-terminated array of absolute or relative paths of
  986  *                  files to watch.
  987  *
  988  * @param events bitwise OR'ed inotify events to watch for.  See section
  989  *               \ref events.
  990  *
  991  * @return 1 on success, 0 on failure.  On failure, the error can be
  992  *         obtained from inotifytools_error().
  993  */
  994 int inotifytools_watch_files( char const * filenames[], int events ) {
  995     niceassert( init, "inotifytools_initialize not called yet" );
  996     error = 0;
  997 
  998     static int i;
  999     for ( i = 0; filenames[i]; ++i ) {
 1000         static int wd;
 1001         wd = inotify_add_watch( inotify_fd, filenames[i], events );
 1002         if ( wd < 0 ) {
 1003             if ( wd == -1 ) {
 1004                 error = errno;
 1005                 return 0;
 1006             } // if ( wd == -1 )
 1007             else {
 1008                 fprintf( stderr, "Failed to watch %s: returned wd was %d "
 1009                          "(expected -1 or >0 )", filenames[i], wd );
 1010                 // no appropriate value for error
 1011                 return 0;
 1012             } // else
 1013         } // if ( wd < 0 )
 1014 
 1015         char *filename;
 1016         // Always end filename with / if it is a directory
 1017         if ( !isdir(filenames[i])
 1018              || filenames[i][strlen(filenames[i])-1] == '/') {
 1019             filename = strdup(filenames[i]);
 1020         }
 1021         else {
 1022             nasprintf( &filename, "%s/", filenames[i] );
 1023         }
 1024         create_watch(wd, filename);
 1025         free(filename);
 1026     } // for
 1027 
 1028     return 1;
 1029 }
 1030 
 1031 /**
 1032  * Get the next inotify event to occur.
 1033  *
 1034  * inotifytools_initialize() must be called before this function can
 1035  * be used.
 1036  *
 1037  * @param timeout maximum amount of time, in seconds, to wait for an event.
 1038  *                If @a timeout is non-negative, the function is non-blocking.
 1039  *                If @a timeout is negative, the function will block until an
 1040  *                event occurs.
 1041  *
 1042  * @return pointer to an inotify event, or NULL if function timed out before
 1043  *         an event occurred.  The event is located in static storage and it
 1044  *         may be overwritten in subsequent calls; do not call free() on it,
 1045  *         and make a copy if you want to keep it.
 1046  *
 1047  * @note Your program should call this function or
 1048  *       inotifytools_next_events() frequently; between calls to this function,
 1049  *       inotify events will be queued in the kernel, and eventually the queue
 1050  *       will overflow and you will miss some events.
 1051  *
 1052  * @note If the function inotifytools_ignore_events_by_regex() has been called
 1053  *       with a non-NULL parameter, this function will not return on events
 1054  *       which match the regular expression passed to that function.  However,
 1055  *       the @a timeout period begins again each time a matching event occurs.
 1056  */
 1057 struct inotify_event * inotifytools_next_event( long int timeout ) {
 1058     return inotifytools_next_events( timeout, 1 );
 1059 }
 1060 
 1061 
 1062 /**
 1063  * Get the next inotify events to occur.
 1064  *
 1065  * inotifytools_initialize() must be called before this function can
 1066  * be used.
 1067  *
 1068  * @param timeout maximum amount of time, in seconds, to wait for an event.
 1069  *                If @a timeout is non-negative, the function is non-blocking.
 1070  *                If @a timeout is negative, the function will block until an
 1071  *                event occurs.
 1072  *
 1073  * @param num_events approximate number of inotify events to wait for until
 1074  *                   this function returns.  Use this for buffering reads to
 1075  *                   inotify if you expect to receive large amounts of events.
 1076  *                   You are NOT guaranteed that this number of events will
 1077  *                   actually be read; instead, you are guaranteed that the
 1078  *                   number of bytes read from inotify is
 1079  *                   @a num_events * sizeof(struct inotify_event).  Obviously
 1080  *                   the larger this number is, the greater the latency between
 1081  *                   when an event occurs and when you'll know about it.
 1082  *                   May not be larger than 4096.
 1083  *
 1084  * @return pointer to an inotify event, or NULL if function timed out before
 1085  *         an event occurred or @a num_events < 1.  The event is located in
 1086  *         static storage and it may be overwritten in subsequent calls; do not
 1087  *         call free() on it, and make a copy if you want to keep it.
 1088  *         When @a num_events is greater than 1, this will return a pointer to
 1089  *         the first event only, and you MUST call this function again to
 1090  *         get pointers to subsequent events; don't try to add to the pointer
 1091  *         to find the next events or you will run into trouble.
 1092  *
 1093  * @note You may actually get different events with different values of
 1094  *       @a num_events.  This is because inotify does some in-kernel filtering
 1095  *       of duplicate events, meaning some duplicate events will not be
 1096  *       reported if @a num_events > 1.  For some purposes this is fine, but
 1097  *       for others (such as gathering accurate statistics on numbers of event
 1098  *       occurrences) you must call this function with @a num_events = 1, or
 1099  *       simply use inotifytools_next_event().
 1100  *
 1101  * @note Your program should call this function frequently; between calls to this
 1102  *       function, inotify events will be queued in the kernel, and eventually
 1103  *       the queue will overflow and you will miss some events.
 1104  *
 1105  * @note If the function inotifytools_ignore_events_by_regex() has been called
 1106  *       with a non-NULL parameter, this function will not return on events
 1107  *       which match the regular expression passed to that function.  However,
 1108  *       the @a timeout period begins again each time a matching event occurs.
 1109  */
 1110 struct inotify_event * inotifytools_next_events( long int timeout, int num_events ) {
 1111     niceassert( init, "inotifytools_initialize not called yet" );
 1112     niceassert( num_events <= MAX_EVENTS, "too many events requested" );
 1113 
 1114     if ( num_events < 1 ) return NULL;
 1115 
 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;
 1120     static jmp_buf jmp;
 1121     static struct nstring match_name;
 1122     static char match_name_string[MAX_STRLEN+1];
 1123 
 1124 #define RETURN(A) {\
 1125     if (regex) {\
 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)\
 1131                 longjmp(jmp,0);\
 1132         } else {\
 1133             if (invert_regexp)\
 1134                 longjmp(jmp,0);\
 1135         }\
 1136     }\
 1137     if ( collect_stats ) {\
 1138         record_stats( A );\
 1139     }\
 1140     return A;\
 1141 }
 1142 
 1143     setjmp(jmp);
 1144 
 1145     error = 0;
 1146 
 1147     // first_byte is index into event buffer
 1148     if ( first_byte != 0
 1149       && first_byte <= (int)(bytes - sizeof(struct inotify_event)) ) {
 1150 
 1151         ret = (struct inotify_event *)((char *)&event[0] + first_byte);
 1152         first_byte += sizeof(struct inotify_event) + ret->len;
 1153 
 1154         // if the pointer to the next event exactly hits end of bytes read,
 1155         // that's good.  next time we're called, we'll read.
 1156         if ( first_byte == bytes ) {
 1157             first_byte = 0;
 1158         }
 1159         else if ( first_byte > bytes ) {
 1160             // oh... no.  this can't be happening.  An incomplete event.
 1161             // Copy what we currently have into first element, call self to
 1162             // read remainder.
 1163             // oh, and they BETTER NOT overlap.
 1164             // Boy I hope this code works.
 1165             // But I think this can never happen due to how inotify is written.
 1166             niceassert( (long)((char *)&event[0] +
 1167                         sizeof(struct inotify_event) +
 1168                         event[0].len) <= (long)ret,
 1169                         "extremely unlucky user, death imminent" );
 1170             // how much of the event do we have?
 1171             bytes = (char *)&event[0] + bytes - (char *)ret;
 1172             memcpy( &event[0], ret, bytes );
 1173             return inotifytools_next_events( timeout, num_events );
 1174         }
 1175         RETURN(ret);
 1176 
 1177     }
 1178 
 1179     else if ( first_byte == 0 ) {
 1180         bytes = 0;
 1181     }
 1182 
 1183 
 1184     static ssize_t this_bytes;
 1185     static unsigned int bytes_to_read;
 1186     static int rc;
 1187     static fd_set read_fds;
 1188 
 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 );
 1194 
 1195     FD_ZERO(&read_fds);
 1196     FD_SET(inotify_fd, &read_fds);
 1197     rc = select(inotify_fd + 1, &read_fds,
 1198                 NULL, NULL, read_timeout_ptr);
 1199     if ( rc < 0 ) {
 1200         // error
 1201         error = errno;
 1202         return NULL;
 1203     }
 1204     else if ( rc == 0 ) {
 1205         // timeout
 1206         return NULL;
 1207     }
 1208 
 1209     // wait until we have enough bytes to read
 1210     do {
 1211         rc = ioctl( inotify_fd, FIONREAD, &bytes_to_read );
 1212     } while ( !rc &&
 1213               bytes_to_read < sizeof(struct inotify_event)*num_events );
 1214 
 1215     if ( rc == -1 ) {
 1216         error = errno;
 1217         return NULL;
 1218     }
 1219 
 1220     this_bytes = read(inotify_fd, &event[0] + bytes,
 1221                       sizeof(struct inotify_event)*MAX_EVENTS - bytes);
 1222     if ( this_bytes < 0 ) {
 1223         error = errno;
 1224         return NULL;
 1225     }
 1226     if ( this_bytes == 0 ) {
 1227         fprintf(stderr, "Inotify reported end-of-file.  Possibly too many "
 1228                         "events occurred at once.\n");
 1229         return NULL;
 1230     }
 1231     bytes += this_bytes;
 1232 
 1233     ret = &event[0];
 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 ) {
 1238         first_byte = 0;
 1239     }
 1240 
 1241     RETURN(ret);
 1242 
 1243 #undef RETURN
 1244 }
 1245 
 1246 /**
 1247  * Set up recursive watches on an entire directory tree.
 1248  *
 1249  * inotifytools_initialize() must be called before this function can
 1250  * be used.
 1251  *
 1252  * @param path path of directory or file to watch.  If the path is a directory,
 1253  *             every subdirectory will also be watched for the same events up
 1254  *             to the maximum readable depth.  If the path is a file, the file
 1255  *             is watched exactly as if inotifytools_watch_file() were used.
 1256  *
 1257  * @param events Inotify events to watch for.  See section \ref events.
 1258  *
 1259  * @return 1 on success, 0 on failure.  On failure, the error can be
 1260  *         obtained from inotifytools_error().  Note that some errors on
 1261  *         subdirectories will be ignored; for example, if you watch a directory
 1262  *         tree which contains some directories which you do not have access to,
 1263  *         those directories will not be watched, but this function will still
 1264  *         return 1 if no other errors occur.
 1265  *
 1266  * @note This function does not attempt to work atomically.  If you use this
 1267  *       function to watch a directory tree and files or directories are being
 1268  *       created or removed within that directory tree, there are no guarantees
 1269  *       as to whether or not those files will be watched.
 1270  */
 1271 int inotifytools_watch_recursively( char const * path, int events ) {
 1272     return inotifytools_watch_recursively_with_exclude( path, events, 0 );
 1273 }
 1274 
 1275 /**
 1276  * Set up recursive watches on an entire directory tree, optionally excluding
 1277  * some directories.
 1278  *
 1279  * inotifytools_initialize() must be called before this function can
 1280  * be used.
 1281  *
 1282  * @author UH
 1283  *
 1284  * @param path path of directory or file to watch.  If the path is a directory,
 1285  *             every subdirectory will also be watched for the same events up
 1286  *             to the maximum readable depth.  If the path is a file, the file
 1287  *             is watched exactly as if inotifytools_watch_file() were used.
 1288  *
 1289  * @param exclude_list NULL terminated path list of directories not to watch.
 1290  *                     Can be NULL if no paths are to be excluded.
 1291  *                     Directories may or may not include a trailing '/'.
 1292  *
 1293  * @param events Inotify events to watch for.  See section \ref events.
 1294  *
 1295  * @return 1 on success, 0 on failure.  On failure, the error can be
 1296  *         obtained from inotifytools_error().  Note that some errors on
 1297  *         subdirectories will be ignored; for example, if you watch a directory
 1298  *         tree which contains some directories which you do not have access to,
 1299  *         those directories will not be watched, but this function will still
 1300  *         return 1 if no other errors occur.
 1301  *
 1302  * @note This function does not attempt to work atomically.  If you use this
 1303  *       function to watch a directory tree and files or directories are being
 1304  *       created or removed within that directory tree, there are no guarantees
 1305  *       as to whether or not those files will be watched.
 1306  */
 1307 int inotifytools_watch_recursively_with_exclude( char const * path, int events,
 1308                                                  char const ** exclude_list ) {
 1309     niceassert( init, "inotifytools_initialize not called yet" );
 1310 
 1311     DIR * dir;
 1312     char * my_path;
 1313     error = 0;
 1314     dir = opendir( path );
 1315     if ( !dir ) {
 1316         // If not a directory, don't need to do anything special
 1317         if ( errno == ENOTDIR ) {
 1318             return inotifytools_watch_file( path, events );
 1319         }
 1320         else {
 1321             error = errno;
 1322             return 0;
 1323         }
 1324     }
 1325 
 1326     if ( path[strlen(path)-1] != '/' ) {
 1327         nasprintf( &my_path, "%s/", path );
 1328     }
 1329     else {
 1330         my_path = (char *)path;
 1331     }
 1332 
 1333     static struct dirent * ent;
 1334     char * next_file;
 1335     static struct stat64 my_stat;
 1336     ent = readdir( dir );
 1337     // Watch each directory within this directory
 1338     while ( ent ) {
 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 ) ) {
 1343                 error = errno;
 1344                 free( next_file );
 1345                 if ( errno != EACCES ) {
 1346                     error = errno;
 1347                     if ( my_path != path ) free( my_path );
 1348                     closedir( dir );
 1349                     return 0;
 1350                 }
 1351             }
 1352             else if ( S_ISDIR( my_stat.st_mode ) &&
 1353                       !S_ISLNK( my_stat.st_mode )) {
 1354                 free( next_file );
 1355                 nasprintf(&next_file,"%s%s/", my_path, ent->d_name);
 1356                 static unsigned int no_watch;
 1357                 static char const ** exclude_entry;
 1358 
 1359                 no_watch = 0;
 1360                 for (exclude_entry = exclude_list;
 1361                      exclude_entry && *exclude_entry && !no_watch;
 1362                      ++exclude_entry) {
 1363                     static int exclude_length;
 1364 
 1365                     exclude_length = strlen(*exclude_entry);
 1366                     if ((*exclude_entry)[exclude_length-1] == '/') {
 1367                         --exclude_length;
 1368                     }
 1369                     if ( strlen(next_file) == (unsigned)(exclude_length + 1) &&
 1370                         !strncmp(*exclude_entry, next_file, exclude_length)) {
 1371                         // directory found in exclude list
 1372                         no_watch = 1;
 1373                     }
 1374                 }
 1375                 if (!no_watch) {
 1376                     static int status;
 1377                     status = inotifytools_watch_recursively_with_exclude(
 1378                                   next_file,
 1379                                   events,
 1380                                   exclude_list );
 1381                     // For some errors, we will continue.
 1382                     if ( !status && (EACCES != error) && (ENOENT != error) &&
 1383                          (ELOOP != error) ) {
 1384                         free( next_file );
 1385                         if ( my_path != path ) free( my_path );
 1386                         closedir( dir );
 1387                         return 0;
 1388                     }
 1389                 } // if !no_watch
 1390                 free( next_file );
 1391             } // if isdir and not islnk
 1392             else {
 1393                 free( next_file );
 1394             }
 1395         }
 1396         ent = readdir( dir );
 1397         error = 0;
 1398     }
 1399 
 1400     closedir( dir );
 1401 
 1402     int ret = inotifytools_watch_file( my_path, events );
 1403     if ( my_path != path ) free( my_path );
 1404         return ret;
 1405 }
 1406 
 1407 /**
 1408  * @internal
 1409  */
 1410 void record_stats( struct inotify_event const * event ) {
 1411     if (!event) return;
 1412     watch *w = watch_from_wd(event->wd);
 1413     if (!w) return;
 1414     if ( IN_ACCESS & event->mask ) {
 1415         ++w->hit_access;
 1416         ++num_access;
 1417     }
 1418     if ( IN_MODIFY & event->mask ) {
 1419         ++w->hit_modify;
 1420         ++num_modify;
 1421     }
 1422     if ( IN_ATTRIB & event->mask ) {
 1423         ++w->hit_attrib;
 1424         ++num_attrib;
 1425     }
 1426     if ( IN_CLOSE_WRITE & event->mask ) {
 1427         ++w->hit_close_write;
 1428         ++num_close_write;
 1429     }
 1430     if ( IN_CLOSE_NOWRITE & event->mask ) {
 1431         ++w->hit_close_nowrite;
 1432         ++num_close_nowrite;
 1433     }
 1434     if ( IN_OPEN & event->mask ) {
 1435         ++w->hit_open;
 1436         ++num_open;
 1437     }
 1438     if ( IN_MOVED_FROM & event->mask ) {
 1439         ++w->hit_moved_from;
 1440         ++num_moved_from;
 1441     }
 1442     if ( IN_MOVED_TO & event->mask ) {
 1443         ++w->hit_moved_to;
 1444         ++num_moved_to;
 1445     }
 1446     if ( IN_CREATE & event->mask ) {
 1447         ++w->hit_create;
 1448         ++num_create;
 1449     }
 1450     if ( IN_DELETE & event->mask ) {
 1451         ++w->hit_delete;
 1452         ++num_delete;
 1453     }
 1454     if ( IN_DELETE_SELF & event->mask ) {
 1455         ++w->hit_delete_self;
 1456         ++num_delete_self;
 1457     }
 1458     if ( IN_UNMOUNT & event->mask ) {
 1459         ++w->hit_unmount;
 1460         ++num_unmount;
 1461     }
 1462     if ( IN_MOVE_SELF & event->mask ) {
 1463         ++w->hit_move_self;
 1464         ++num_move_self;
 1465     }
 1466 
 1467     ++w->hit_total;
 1468     ++num_total;
 1469 
 1470 }
 1471 
 1472 unsigned int *stat_ptr(watch *w, int event)
 1473 {
 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;
 1500     if ( 0 == event )
 1501         return &w->hit_total;
 1502     return 0;
 1503 }
 1504 
 1505 /**
 1506  * Get statistics by a particular watch descriptor.
 1507  *
 1508  * inotifytools_initialize_stats() must be called before this function can
 1509  * be used.
 1510  *
 1511  * @param wd watch descriptor to get stats for.
 1512  *
 1513  * @param event a single inotify event to get statistics for, or 0 for event
 1514  *              total.  See section \ref events.
 1515  *
 1516  * @return the number of times the event specified by @a event has occurred on
 1517  *         the watch descriptor specified by @a wd since stats collection was
 1518  *         enabled, or -1 if @a event or @a wd are invalid.
 1519  */
 1520 int inotifytools_get_stat_by_wd( int wd, int event ) {
 1521     if (!collect_stats) return -1;
 1522 
 1523     watch *w = watch_from_wd(wd);
 1524     if (!w) return -1;
 1525     unsigned int *i = stat_ptr(w, event);
 1526     if (!i) return -1;
 1527     return *i;
 1528 }
 1529 
 1530 /**
 1531  * Get statistics aggregated across all watches.
 1532  *
 1533  * inotifytools_initialize_stats() must be called before this function can
 1534  * be used.
 1535  *
 1536  * @param event a single inotify event to get statistics for, or 0 for event
 1537  *              total.  See section \ref events.
 1538  *
 1539  * @return the number of times the event specified by @a event has occurred over
 1540  *         all watches since stats collection was enabled, or -1 if @a event
 1541  *         is not a valid event.
 1542  */
 1543 int inotifytools_get_stat_total( int event ) {
 1544     if (!collect_stats) return -1;
 1545     if ( IN_ACCESS == event )
 1546         return num_access;
 1547     if ( IN_MODIFY == event )
 1548         return num_modify;
 1549     if ( IN_ATTRIB == event )
 1550         return num_attrib;
 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 )
 1556         return num_open;
 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 )
 1562         return num_create;
 1563     if ( IN_DELETE == event )
 1564         return num_delete;
 1565     if ( IN_DELETE_SELF == event )
 1566         return num_delete_self;
 1567     if ( IN_UNMOUNT == event )
 1568         return num_unmount;
 1569     if ( IN_MOVE_SELF == event )
 1570         return num_move_self;
 1571 
 1572     if ( 0 == event )
 1573         return num_total;
 1574 
 1575     return -1;
 1576 }
 1577 
 1578 /**
 1579  * Get statistics by a particular filename.
 1580  *
 1581  * inotifytools_initialize_stats() must be called before this function can
 1582  * be used.
 1583  *
 1584  * @param filename name of file to get stats for.
 1585  *
 1586  * @param event a single inotify event to get statistics for, or 0 for event
 1587  *              total.  See section \ref events.
 1588  *
 1589  * @return the number of times the event specified by @a event has occurred on
 1590  *         the file specified by @a filename since stats collection was
 1591  *         enabled, or -1 if the file is not being watched or @a event is
 1592  *         invalid.
 1593  *
 1594  * @note The filename specified must always be the original name used to
 1595  *       establish the watch.
 1596  */
 1597 int inotifytools_get_stat_by_filename( char const * filename,
 1598                                                 int event ) {
 1599     return inotifytools_get_stat_by_wd( inotifytools_wd_from_filename(
 1600            filename ), event );
 1601 }
 1602 
 1603 /**
 1604  * Get the last error which occurred.
 1605  *
 1606  * When a function fails, call this to find out why.  The returned value is
 1607  * a typical @a errno value, the meaning of which depends on context.  For
 1608  * example, if inotifytools_watch_file() fails because you attempt to watch
 1609  * a file which doesn't exist, this function will return @a ENOENT.
 1610  *
 1611  * @return an error code.
 1612  */
 1613 int inotifytools_error() {
 1614     return error;
 1615 }
 1616 
 1617 /**
 1618  * @internal
 1619  */
 1620 static int isdir( char const * path ) {
 1621     static struct stat64 my_stat;
 1622 
 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));
 1626         return 0;
 1627     }
 1628 
 1629     return S_ISDIR( my_stat.st_mode ) && !S_ISLNK( my_stat.st_mode );
 1630 }
 1631 
 1632 
 1633 /**
 1634  * Get the number of watches set up through libinotifytools.
 1635  *
 1636  * @return number of watches set up by inotifytools_watch_file(),
 1637  *         inotifytools_watch_files() and inotifytools_watch_recursively().
 1638  */
 1639 int inotifytools_get_num_watches() {
 1640     int ret = 0;
 1641     rbwalk(tree_filename, get_num, (void*)&ret);
 1642     return ret;
 1643 }
 1644 
 1645 /**
 1646  * Print a string to standard out using an inotify_event and a printf-like
 1647  * syntax.
 1648  * The string written will only ever be up to 4096 characters in length.
 1649  *
 1650  * @param event the event to use to construct a string.
 1651  *
 1652  * @param fmt the format string used to construct a string.
 1653  *
 1654  * @return number of characters written, or -1 if an error occurs.
 1655  *
 1656  * @section syntax Format string syntax
 1657  * The following tokens will be replaced with the specified string:
 1658  *  \li \c \%w - This will be replaced with the name of the Watched file on
 1659  *               which an event occurred.
 1660  *  \li \c \%c - This will be replaced with the cookie of the Watched file on
 1661  *               which an event occurred.
 1662  *  \li \c \%f - When an event occurs within a directory, this will be replaced
 1663  *               with the name of the File which caused the event to occur.
 1664  *               Otherwise, this will be replaced with an empty string.
 1665  *  \li \c \%e - Replaced with the Event(s) which occurred, comma-separated.
 1666  *  \li \c \%Xe - Replaced with the Event(s) which occurred, separated by
 1667  *                whichever character is in the place of `X'.
 1668  *  \li \c \%T - Replaced by the current Time in the format specified by the
 1669  *               string previously passed to inotifytools_set_printf_timefmt(),
 1670  *               or replaced with an empty string if that function has never
 1671  *               been called.
 1672  *  \li \c \%0 - Replaced with the 'NUL' character
 1673  *  \li \c \%n - Replaced with the 'Line Feed' character
 1674  *
 1675  * @section example Example
 1676  * @code
 1677  * // suppose this is the only file watched.
 1678  * inotifytools_watch_file( "mydir/", IN_CLOSE );
 1679  *
 1680  * // wait until an event occurs
 1681  * struct inotify_event * event = inotifytools_next_event( -1 );
 1682  *
 1683  * inotifytools_printf(stderr, event, "in %w, file %f had event(s): %.e\n");
 1684  * // suppose the file 'myfile' in mydir was read from and closed.  Then,
 1685  * // this prints to standard out something like:
 1686  * // "in mydir/, file myfile had event(s): CLOSE_NOWRITE.CLOSE.ISDIR\n"
 1687  * @endcode
 1688  */
 1689 int inotifytools_printf( struct inotify_event* event, char* fmt ) {
 1690     return inotifytools_fprintf( stdout, event, fmt );
 1691 }
 1692 
 1693 /**
 1694  * Print a string to a file using an inotify_event and a printf-like syntax.
 1695  * The string written will only ever be up to 4096 characters in length.
 1696  *
 1697  * @param file file to print to
 1698  *
 1699  * @param event the event to use to construct a string.
 1700  *
 1701  * @param fmt the format string used to construct a string.
 1702  *
 1703  * @return number of characters written, or -1 if an error occurs.
 1704  *
 1705  * @section syntax Format string syntax
 1706  * The following tokens will be replaced with the specified string:
 1707  *  \li \c \%w - This will be replaced with the name of the Watched file on
 1708  *               which an event occurred.
 1709  *  \li \c \%c - This will be replaced with the cookie of the Watched file on
 1710  *               which an event occurred.
 1711  *  \li \c \%f - When an event occurs within a directory, this will be replaced
 1712  *               with the name of the File which caused the event to occur.
 1713  *               Otherwise, this will be replaced with an empty string.
 1714  *  \li \c \%e - Replaced with the Event(s) which occurred, comma-separated.
 1715  *  \li \c \%Xe - Replaced with the Event(s) which occurred, separated by
 1716  *                whichever character is in the place of `X'.
 1717  *  \li \c \%T - Replaced by the current Time in the format specified by the
 1718  *               string previously passed to inotifytools_set_printf_timefmt(),
 1719  *               or replaced with an empty string if that function has never
 1720  *               been called.
 1721  *  \li \c \%0 - Replaced with the 'NUL' character
 1722  *  \li \c \%n - Replaced with the 'Line Feed' character
 1723  *
 1724  * @section example Example
 1725  * @code
 1726  * // suppose this is the only file watched.
 1727  * inotifytools_watch_file( "mydir/", IN_CLOSE );
 1728  *
 1729  * // wait until an event occurs
 1730  * struct inotify_event * event = inotifytools_next_event( -1 );
 1731  *
 1732  * inotifytools_fprintf(stderr, event, "in %w, file %f had event(s): %.e\n");
 1733  * // suppose the file 'myfile' in mydir was read from and closed.  Then,
 1734  * // this prints to standard error something like:
 1735  * // "in mydir/, file myfile had event(s): CLOSE_NOWRITE.CLOSE.ISDIR\n"
 1736  * @endcode
 1737  */
 1738 int inotifytools_fprintf( FILE* file, struct inotify_event* event, char* fmt ) {
 1739     static struct nstring out;
 1740     static int ret;
 1741     ret = inotifytools_sprintf( &out, event, fmt );
 1742     if ( -1 != ret ) fwrite( out.buf, sizeof(char), out.len, file );
 1743     return ret;
 1744 }
 1745 
 1746 /**
 1747  * Construct a string using an inotify_event and a printf-like syntax.
 1748  * The string can only ever be up to 4096 characters in length.
 1749  *
 1750  * This function will keep writing until it reaches 4096 characters.  If your
 1751  * allocated array is not large enough to hold the entire string, your program
 1752  * may crash.
 1753  * inotifytools_snprintf() is safer and you should use it where possible.
 1754  *
 1755  * @param out location in which to store nstring.
 1756  *
 1757  * @param event the event to use to construct a nstring.
 1758  *
 1759  * @param fmt the format string used to construct a nstring.
 1760  *
 1761  * @return number of characters written, or -1 if an error occurs.
 1762  *
 1763  * @section syntax Format string syntax
 1764  * The following tokens will be replaced with the specified string:
 1765  *  \li \c \%w - This will be replaced with the name of the Watched file on
 1766  *               which an event occurred.
 1767  *  \li \c \%c - This will be replaced with the cookie of the Watched file on
 1768  *               which an event occurred.
 1769  *  \li \c \%f - When an event occurs within a directory, this will be replaced
 1770  *               with the name of the File which caused the event to occur.
 1771  *               Otherwise, this will be replaced with an empty string.
 1772  *  \li \c \%e - Replaced with the Event(s) which occurred, comma-separated.
 1773  *  \li \c \%Xe - Replaced with the Event(s) which occurred, separated by
 1774  *                whichever character is in the place of `X'.
 1775  *  \li \c \%T - Replaced by the current Time in the format specified by the
 1776  *               string previously passed to inotifytools_set_printf_timefmt(),
 1777  *               or replaced with an empty string if that function has never
 1778  *               been called.
 1779  *  \li \c \%0 - Replaced with the 'NUL' character
 1780  *  \li \c \%n - Replaced with the 'Line Feed' character
 1781  *
 1782  * @section example Example
 1783  * @code
 1784  * // suppose this is the only file watched.
 1785  * inotifytools_watch_file( "mydir/", IN_CLOSE );
 1786  *
 1787  * // wait until an event occurs
 1788  * struct inotify_event * event = inotifytools_next_event( -1 );
 1789  *
 1790  * nstring mynstring;
 1791  * inotifytools_sprintf(mynstring, event, "in %w, file %f had event(s): %.e\n");
 1792  * fwrite( mynstring.buf, sizeof(char), mynstring.len, stdout );
 1793  * // suppose the file 'myfile' in mydir was written to and closed.  Then,
 1794  * // this prints something like:
 1795  * // "in mydir/, file myfile had event(s): CLOSE_WRITE.CLOSE.ISDIR\n"
 1796  * @endcode
 1797  */
 1798 int inotifytools_sprintf( struct nstring * out, struct inotify_event* event, char* fmt ) {
 1799     return inotifytools_snprintf( out, MAX_STRLEN, event, fmt );
 1800 }
 1801 
 1802 
 1803 /**
 1804  * Construct a string using an inotify_event and a printf-like syntax.
 1805  * The string can only ever be up to 4096 characters in length.
 1806  *
 1807  * @param out location in which to store nstring.
 1808  *
 1809  * @param size maximum amount of characters to write.
 1810  *
 1811  * @param event the event to use to construct a nstring.
 1812  *
 1813  * @param fmt the format string used to construct a nstring.
 1814  *
 1815  * @return number of characters written, or -1 if an error occurs.
 1816  *
 1817  * @section syntax Format string syntax
 1818  * The following tokens will be replaced with the specified string:
 1819  *  \li \c \%w - This will be replaced with the name of the Watched file on
 1820  *               which an event occurred.
 1821  *  \li \c \%c - This will be replaced with cookie of the Watched file on
 1822  *               which an event occurred.
 1823  *  \li \c \%f - When an event occurs within a directory, this will be replaced
 1824  *               with the name of the File which caused the event to occur.
 1825  *               Otherwise, this will be replaced with an empty string.
 1826  *  \li \c \%e - Replaced with the Event(s) which occurred, comma-separated.
 1827  *  \li \c \%Xe - Replaced with the Event(s) which occurred, separated by
 1828  *                whichever character is in the place of `X'.
 1829  *  \li \c \%T - Replaced by the current Time in the format specified by the
 1830  *               string previously passed to inotifytools_set_printf_timefmt(),
 1831  *               or replaced with an empty string if that function has never
 1832  *               been called.
 1833  *  \li \c \%0 - Replaced with the 'NUL' character
 1834  *  \li \c \%n - Replaced with the 'Line Feed' character
 1835  *
 1836  * @section example Example
 1837  * @code
 1838  * // suppose this is the only file watched.
 1839  * inotifytools_watch_file( "mydir/", IN_CLOSE );
 1840  *
 1841  * // wait until an event occurs
 1842  * struct inotify_event * event = inotifytools_next_event( -1 );
 1843  *
 1844  * struct nstring mynstring;
 1845  * inotifytools_snprintf( mynstring, MAX_STRLEN, event,
 1846  *                        "in %w, file %f had event(s): %.e\n" );
 1847  * fwrite( mynstring.buf, sizeof(char), mynstring.len, stdout );
 1848  * // suppose the file 'myfile' in mydir was written to and closed.  Then,
 1849  * // this prints something like:
 1850  * // "in mydir/, file myfile had event(s): CLOSE_WRITE.CLOSE.ISDIR\n"
 1851  * @endcode
 1852  */
 1853 int inotifytools_snprintf( struct nstring * out, int size,
 1854                            struct inotify_event* event, char* fmt ) {
 1855     static char * filename, * eventname, * eventstr;
 1856     static unsigned int i, ind;
 1857     static char ch1;
 1858     static char timestr[MAX_STRLEN];
 1859         static time_t now;
 1860 
 1861         if ( event->len > 0 ) {
 1862         eventname = event->name;
 1863     }
 1864     else {
 1865         eventname = NULL;
 1866     }
 1867 
 1868 
 1869     filename = inotifytools_filename_from_wd( event->wd );
 1870 
 1871     if ( !fmt || 0 == strlen(fmt) ) {
 1872         error = EINVAL;
 1873         return -1;
 1874     }
 1875     if ( strlen(fmt) > MAX_STRLEN || size > MAX_STRLEN) {
 1876         error = EMSGSIZE;
 1877         return -1;
 1878     }
 1879 
 1880     ind = 0;
 1881     for ( i = 0; i < strlen(fmt) &&
 1882                  (int)ind < size - 1; ++i ) {
 1883         if ( fmt[i] != '%' ) {
 1884             out->buf[ind++] = fmt[i];
 1885             continue;
 1886         }
 1887 
 1888         if ( i == strlen(fmt) - 1 ) {
 1889             // last character is %, invalid
 1890             error = EINVAL;
 1891             return ind;
 1892         }
 1893 
 1894         ch1 = fmt[i+1];
 1895 
 1896         if ( ch1 == '%' ) {
 1897             out->buf[ind++] = '%';
 1898             ++i;
 1899             continue;
 1900         }
 1901 
 1902         if ( ch1 == '0' ) {
 1903             out->buf[ind++] = '\0';
 1904             ++i;
 1905             continue;
 1906         }
 1907 
 1908         if ( ch1 == 'n' ) {
 1909             out->buf[ind++] = '\n';
 1910             ++i;
 1911             continue;
 1912         }
 1913 
 1914         if ( ch1 == 'w' ) {
 1915             if ( filename ) {
 1916                 strncpy( &out->buf[ind], filename, size - ind );
 1917                 ind += strlen(filename);
 1918             }
 1919             ++i;
 1920             continue;
 1921         }
 1922 
 1923         if ( ch1 == 'f' ) {
 1924             if ( eventname ) {
 1925                 strncpy( &out->buf[ind], eventname, size - ind );
 1926                 ind += strlen(eventname);
 1927             }
 1928             ++i;
 1929             continue;
 1930         }
 1931 
 1932         if ( ch1 == 'c' ) {
 1933             ind += snprintf( &out->buf[ind], size-ind, "%x", event->cookie);
 1934             ++i;
 1935             continue;
 1936         }
 1937 
 1938         if ( ch1 == 'e' ) {
 1939             eventstr = inotifytools_event_to_str( event->mask );
 1940             strncpy( &out->buf[ind], eventstr, size - ind );
 1941             ind += strlen(eventstr);
 1942             ++i;
 1943             continue;
 1944         }
 1945 
 1946         if ( ch1 == 'T' ) {
 1947 
 1948             if ( timefmt ) {
 1949                 now = time(0);
 1950                                 struct tm now_tm;
 1951                                 if (0 >= strftime(timestr, MAX_STRLEN - 1,
 1952                                                   timefmt,
 1953                                                   localtime_r(&now, &now_tm))) {
 1954                                     // time format probably invalid
 1955                                     error = EINVAL;
 1956                                     return ind;
 1957                 }
 1958             }
 1959             else {
 1960                 timestr[0] = 0;
 1961             }
 1962 
 1963             strncpy( &out->buf[ind], timestr, size - ind );
 1964             ind += strlen(timestr);
 1965             ++i;
 1966             continue;
 1967         }
 1968 
 1969         // Check if next char in fmt is e
 1970         if ( i < strlen(fmt) - 2 && fmt[i+2] == 'e' ) {
 1971             eventstr = inotifytools_event_to_str_sep( event->mask, ch1 );
 1972             strncpy( &out->buf[ind], eventstr, size - ind );
 1973             ind += strlen(eventstr);
 1974             i += 2;
 1975             continue;
 1976         }
 1977 
 1978         // OK, this wasn't a special format character, just output it as normal
 1979         if ( ind < MAX_STRLEN ) out->buf[ind++] = '%';
 1980         if ( ind < MAX_STRLEN ) out->buf[ind++] = ch1;
 1981         ++i;
 1982     }
 1983     out->len = ind;
 1984 
 1985     return ind - 1;
 1986 }
 1987 
 1988 /**
 1989  * Set time format for printf functions.
 1990  *
 1991  * @param fmt A format string valid for use with strftime, or NULL.  If NULL,
 1992  *            time substitutions will no longer be made in printf functions.
 1993  *            Note that this format string is not validated at all; using an
 1994  *            incorrect format string will cause the printf functions to give
 1995  *            incorrect results.
 1996  */
 1997 void inotifytools_set_printf_timefmt( char * fmt ) {
 1998     timefmt = fmt;
 1999 }
 2000 
 2001 /**
 2002  * Get the event queue size.
 2003  *
 2004  * This setting can also be read or modified by accessing the file
 2005  * \a /proc/sys/fs/inotify/max_queued_events.
 2006  *
 2007  * @return the maximum number of events which will be queued in the kernel.
 2008  */
 2009 int inotifytools_get_max_queued_events() {
 2010     int ret;
 2011     if ( !read_num_from_file( QUEUE_SIZE_PATH, &ret ) ) return -1;
 2012     return ret;
 2013 }
 2014 
 2015 /**
 2016  * Get the maximum number of user instances of inotify.
 2017  *
 2018  * This setting can also be read or modified by accessing the file
 2019  * \a /proc/sys/fs/inotify/max_user_instances.
 2020  *
 2021  * @return the maximum number of inotify file descriptors a single user can
 2022  *         obtain.
 2023  */
 2024 int inotifytools_get_max_user_instances() {
 2025     int ret;
 2026     if ( !read_num_from_file( INSTANCES_PATH, &ret ) ) return -1;
 2027     return ret;
 2028 }
 2029 
 2030 /**
 2031  * Get the maximum number of user watches.
 2032  *
 2033  * This setting can also be read or modified by accessing the file
 2034  * \a /proc/sys/fs/inotify/max_user_watches.
 2035  *
 2036  * @return the maximum number of inotify watches a single user can obtain per
 2037  *         inotify instance.
 2038  */
 2039 int inotifytools_get_max_user_watches() {
 2040     int ret;
 2041     if ( !read_num_from_file( WATCHES_SIZE_PATH, &ret ) ) return -1;
 2042     return ret;
 2043 }
 2044 
 2045 /**
 2046  * Ignore inotify events matching a particular regular expression.
 2047  *
 2048  * @a pattern is a regular expression and @a flags is a bitwise combination of
 2049  * POSIX regular expression flags. @a invert determines the type of filtering:
 2050  * 0 (--exclude[i]): exclude all files matching @a pattern
 2051  * 1 (--include[i]): exclude all files except those matching @a pattern
 2052  *
 2053  * On future calls to inotifytools_next_events() or inotifytools_next_event(),
 2054  * the regular expression is executed on the filename of files on which
 2055  * events occur.  If the regular expression matches, the matched event will be
 2056  * ignored.
 2057  */
 2058 static int do_ignore_events_by_regex( char const *pattern, int flags, int invert ) {
 2059     if (!pattern) {
 2060         if (regex) {
 2061             regfree(regex);
 2062             free(regex);
 2063             regex = 0;
 2064         }
 2065         return 1;
 2066     }
 2067 
 2068     if (regex) { regfree(regex); }
 2069     else       { regex = (regex_t *)malloc(sizeof(regex_t)); }
 2070 
 2071     invert_regexp = invert;
 2072     int ret = regcomp(regex, pattern, flags | REG_NOSUB);
 2073     if (0 == ret) return 1;
 2074 
 2075     regfree(regex);
 2076     free(regex);
 2077     regex = 0;
 2078     error = EINVAL;
 2079     return 0;
 2080 }
 2081 
 2082 /**
 2083  * Ignore inotify events matching a particular regular expression.
 2084  *
 2085  * @a pattern is a regular expression and @a flags is a bitwise combination of
 2086  * POSIX regular expression flags.
 2087  *
 2088  * On future calls to inotifytools_next_events() or inotifytools_next_event(),
 2089  * the regular expression is executed on the filename of files on which
 2090  * events occur.  If the regular expression matches, the matched event will be
 2091  * ignored.
 2092  */
 2093 int inotifytools_ignore_events_by_regex( char const *pattern, int flags ) {
 2094     return do_ignore_events_by_regex(pattern, flags, 0);
 2095 }
 2096 
 2097 /**
 2098  * Ignore inotify events NOT matching a particular regular expression.
 2099  *
 2100  * @a pattern is a regular expression and @a flags is a bitwise combination of
 2101  * POSIX regular expression flags.
 2102  *
 2103  * On future calls to inotifytools_next_events() or inotifytools_next_event(),
 2104  * the regular expression is executed on the filename of files on which
 2105  * events occur.  If the regular expression matches, the matched event will be
 2106  * ignored.
 2107  */
 2108 int inotifytools_ignore_events_by_inverted_regex( char const *pattern, int flags ) {
 2109     return do_ignore_events_by_regex(pattern, flags, 1);
 2110 }
 2111 
 2112 int event_compare(const void *p1, const void *p2, const void *config)
 2113 {
 2114     if (!p1 || !p2) return p1 - p2;
 2115     char asc = 1;
 2116     long sort_event = (long)config;
 2117     if (sort_event == -1) {
 2118         sort_event = 0;
 2119         asc = 0;
 2120     } else if (sort_event < 0) {
 2121         sort_event = -sort_event;
 2122         asc = 0;
 2123     }
 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;
 2128     }
 2129     if (asc)
 2130         return *i1 - *i2;
 2131     else
 2132         return *i2 - *i1;
 2133 }
 2134 
 2135 struct rbtree *inotifytools_wd_sorted_by_event(int sort_event)
 2136 {
 2137     struct rbtree *ret = rbinit(event_compare, (void*)(uintptr_t)sort_event);
 2138     RBLIST *all = rbopenlist(tree_wd);
 2139     void const *p = rbreadlist(all);
 2140     while (p) {
 2141         void const *r = rbsearch(p, ret);
 2142         niceassert((int)(r == p), "Couldn't insert watch into new tree");
 2143         p = rbreadlist(all);
 2144     }
 2145     rbcloselist(all);
 2146     return ret;
 2147 }