"Fossies" - the Fresh Open Source Software Archive

Member "inotify-tools-3.20.11.0/src/inotifywait.c" (13 Nov 2020, 24363 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 "inotifywait.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 #include "../config.h"
    2 #include "common.h"
    3 
    4 #include <sys/select.h>
    5 #include <sys/stat.h>
    6 #include <sys/time.h>
    7 #include <sys/types.h>
    8 
    9 #include <assert.h>
   10 #include <errno.h>
   11 #include <fcntl.h>
   12 #include <getopt.h>
   13 #include <limits.h>
   14 #include <regex.h>
   15 #include <signal.h>
   16 #include <stdarg.h>
   17 #include <stdbool.h>
   18 #include <stdio.h>
   19 #include <stdlib.h>
   20 #include <string.h>
   21 #include <syslog.h>
   22 #include <unistd.h>
   23 
   24 #include <inotifytools/inotify.h>
   25 #include <inotifytools/inotifytools.h>
   26 
   27 extern char *optarg;
   28 extern int optind, opterr, optopt;
   29 
   30 #define MAX_STRLEN 4096
   31 
   32 #define nasprintf(...) niceassert(-1 != asprintf(__VA_ARGS__), "out of memory")
   33 
   34 // METHODS
   35 bool parse_opts(int *argc, char ***argv, int *events, bool *monitor, int *quiet,
   36                 long int *timeout, int *recursive, bool *csv, bool *daemon,
   37                 bool *syslog, bool *no_dereference, char **format,
   38                 char **timefmt, char **fromfile, char **outfile,
   39                 char **exc_regex, char **exc_iregex, char **inc_regex,
   40                 char **inc_iregex, bool *no_newline);
   41 
   42 void print_help();
   43 
   44 char *csv_escape(char *string) {
   45     static char csv[MAX_STRLEN + 1];
   46     static unsigned int i, ind;
   47 
   48     if (string == NULL) {
   49         return NULL;
   50     }
   51 
   52     if (strlen(string) > MAX_STRLEN) {
   53         return NULL;
   54     }
   55 
   56     if (strlen(string) == 0) {
   57         return NULL;
   58     }
   59 
   60     // May not need escaping
   61     if (!strchr(string, '"') && !strchr(string, ',') && !strchr(string, '\n') &&
   62         string[0] != ' ' && string[strlen(string) - 1] != ' ') {
   63         strcpy(csv, string);
   64         return csv;
   65     }
   66 
   67     // OK, so now we _do_ need escaping.
   68     csv[0] = '"';
   69     ind = 1;
   70     for (i = 0; i < strlen(string); ++i) {
   71         if (string[i] == '"') {
   72             csv[ind++] = '"';
   73         }
   74         csv[ind++] = string[i];
   75     }
   76     csv[ind++] = '"';
   77     csv[ind] = '\0';
   78 
   79     return csv;
   80 }
   81 
   82 void validate_format(char *fmt) {
   83     // Make a fake event
   84     struct inotify_event *event =
   85         (struct inotify_event *)malloc(sizeof(struct inotify_event) + 4);
   86     if (!event) {
   87         fprintf(stderr, "Seem to be out of memory... yikes!\n");
   88         exit(EXIT_FAILURE);
   89     }
   90     event->wd = 0;
   91     event->mask = IN_ALL_EVENTS;
   92     event->len = 3;
   93     strcpy(event->name, "foo");
   94     FILE *devnull = fopen("/dev/null", "a");
   95     if (!devnull) {
   96         fprintf(stderr, "Couldn't open /dev/null: %s\n", strerror(errno));
   97         free(event);
   98         return;
   99     }
  100     if (-1 == inotifytools_fprintf(devnull, event, fmt)) {
  101         fprintf(stderr, "Something is wrong with your format string.\n");
  102         exit(EXIT_FAILURE);
  103     }
  104     free(event);
  105     fclose(devnull);
  106 }
  107 
  108 void output_event_csv(struct inotify_event *event) {
  109     char *filename = csv_escape(inotifytools_filename_from_wd(event->wd));
  110     if (filename != NULL)
  111         printf("%s,", filename);
  112 
  113     printf("%s,", csv_escape(inotifytools_event_to_str(event->mask)));
  114     if (event->len > 0)
  115         printf("%s", csv_escape(event->name));
  116     printf("\n");
  117 }
  118 
  119 void output_error(bool syslog, char *fmt, ...) {
  120     va_list va;
  121     va_start(va, fmt);
  122     if (syslog) {
  123         vsyslog(LOG_INFO, fmt, va);
  124     } else {
  125         vfprintf(stderr, fmt, va);
  126     }
  127     va_end(va);
  128 }
  129 
  130 int main(int argc, char **argv) {
  131     int events = 0;
  132     int orig_events;
  133     bool monitor = false;
  134     int quiet = 0;
  135     long int timeout = BLOCKING_TIMEOUT;
  136     int recursive = 0;
  137     bool csv = false;
  138     bool dodaemon = false;
  139     bool syslog = false;
  140     bool no_dereference = false;
  141     char *format = NULL;
  142     char *timefmt = NULL;
  143     char *fromfile = NULL;
  144     char *outfile = NULL;
  145     char *exc_regex = NULL;
  146     char *exc_iregex = NULL;
  147     char *inc_regex = NULL;
  148     char *inc_iregex = NULL;
  149     bool no_newline = false;
  150     int fd;
  151 
  152     // Parse commandline options, aborting if something goes wrong
  153     if (!parse_opts(&argc, &argv, &events, &monitor, &quiet, &timeout,
  154                     &recursive, &csv, &dodaemon, &syslog, &no_dereference,
  155                     &format, &timefmt, &fromfile, &outfile, &exc_regex,
  156                     &exc_iregex, &inc_regex, &inc_iregex, &no_newline)) {
  157         return EXIT_FAILURE;
  158     }
  159 
  160     if (!inotifytools_initialize()) {
  161         warn_inotify_init_error();
  162         return EXIT_FAILURE;
  163     }
  164 
  165     if (timefmt)
  166         inotifytools_set_printf_timefmt(timefmt);
  167     if ((exc_regex &&
  168          !inotifytools_ignore_events_by_regex(exc_regex, REG_EXTENDED)) ||
  169         (exc_iregex &&
  170          !inotifytools_ignore_events_by_regex(exc_iregex,
  171                                               REG_EXTENDED | REG_ICASE))) {
  172         fprintf(stderr, "Error in `exclude' regular expression.\n");
  173         return EXIT_FAILURE;
  174     }
  175     if ((inc_regex &&
  176          !inotifytools_ignore_events_by_inverted_regex(inc_regex,
  177                                                        REG_EXTENDED)) ||
  178         (inc_iregex &&
  179          !inotifytools_ignore_events_by_inverted_regex(
  180              inc_iregex, REG_EXTENDED | REG_ICASE))) {
  181         fprintf(stderr, "Error in `include' regular expression.\n");
  182         return EXIT_FAILURE;
  183     }
  184 
  185     if (format)
  186         validate_format(format);
  187 
  188     // Attempt to watch file
  189     // If events is still 0, make it all events.
  190     if (events == 0)
  191         events = IN_ALL_EVENTS;
  192     orig_events = events;
  193     if (monitor && recursive) {
  194         events = events | IN_CREATE | IN_MOVED_TO | IN_MOVED_FROM;
  195     }
  196     if (no_dereference) {
  197         events = events | IN_DONT_FOLLOW;
  198     }
  199 
  200     FileList list = construct_path_list(argc, argv, fromfile);
  201 
  202     if (0 == list.watch_files[0]) {
  203         fprintf(stderr, "No files specified to watch!\n");
  204         return EXIT_FAILURE;
  205     }
  206 
  207     // Daemonize - BSD double-fork approach
  208     if (dodaemon) {
  209         // Absolute path for outfile before entering the child.
  210         char *logfile = calloc(PATH_MAX + 1, sizeof(char));
  211         if (realpath(outfile, logfile) == NULL) {
  212             fprintf(stderr, "%s: %s\n", strerror(errno), outfile);
  213             return EXIT_FAILURE;
  214         }
  215 
  216 #ifdef HAVE_DAEMON
  217         if (daemon(0, 0)) {
  218             fprintf(stderr, "Failed to daemonize!\n");
  219             return EXIT_FAILURE;
  220         }
  221 #else
  222         pid_t pid = fork();
  223         if (pid < 0) {
  224             fprintf(stderr, "Failed to fork1 whilst daemonizing!\n");
  225             return EXIT_FAILURE;
  226         }
  227         if (pid > 0) {
  228             _exit(0);
  229         }
  230         if (setsid() < 0) {
  231             fprintf(stderr, "Failed to setsid whilst daemonizing!\n");
  232             return EXIT_FAILURE;
  233         }
  234         signal(SIGHUP, SIG_IGN);
  235         pid = fork();
  236         if (pid < 0) {
  237             fprintf(stderr, "Failed to fork2 whilst daemonizing!\n");
  238             return EXIT_FAILURE;
  239         }
  240         if (pid > 0) {
  241             _exit(0);
  242         }
  243         if (chdir("/") < 0) {
  244             fprintf(stderr, "Failed to chdir whilst daemonizing!\n");
  245             return EXIT_FAILURE;
  246         }
  247 #endif
  248 
  249         // Redirect stdin from /dev/null
  250         fd = open("/dev/null", O_RDONLY);
  251         if (fd != fileno(stdin)) {
  252             dup2(fd, fileno(stdin));
  253             close(fd);
  254         }
  255 
  256         // Redirect stdout to a file
  257         fd = open(logfile, O_WRONLY | O_CREAT | O_APPEND, 0600);
  258         if (fd < 0) {
  259             fprintf(stderr, "Failed to open output file %s\n", logfile);
  260             free(logfile);
  261             return EXIT_FAILURE;
  262         }
  263         free(logfile);
  264         if (fd != fileno(stdout)) {
  265             dup2(fd, fileno(stdout));
  266             close(fd);
  267         }
  268 
  269         // Redirect stderr to /dev/null
  270         fd = open("/dev/null", O_WRONLY);
  271         if (fd != fileno(stderr)) {
  272             dup2(fd, fileno(stderr));
  273             close(fd);
  274         }
  275 
  276     } else if (outfile != NULL) { // Redirect stdout to a file if specified
  277         fd = open(outfile, O_WRONLY | O_CREAT | O_APPEND, 0600);
  278         if (fd < 0) {
  279             fprintf(stderr, "Failed to open output file %s\n", outfile);
  280             return EXIT_FAILURE;
  281         }
  282         if (fd != fileno(stdout)) {
  283             dup2(fd, fileno(stdout));
  284             close(fd);
  285         }
  286     }
  287 
  288     if (syslog) {
  289         openlog("inotifywait", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_DAEMON);
  290     }
  291 
  292     if (!quiet) {
  293         if (recursive) {
  294             output_error(syslog, "Setting up watches.  Beware: since -r "
  295                                  "was given, this may take a while!\n");
  296         } else {
  297             output_error(syslog, "Setting up watches.\n");
  298         }
  299     }
  300 
  301     // now watch files
  302     for (int i = 0; list.watch_files[i]; ++i) {
  303         char const *this_file = list.watch_files[i];
  304         if ((recursive &&
  305              !inotifytools_watch_recursively_with_exclude(
  306                  this_file, events, list.exclude_files)) ||
  307             (!recursive && !inotifytools_watch_file(this_file, events))) {
  308             if (inotifytools_error() == ENOSPC) {
  309                 output_error(syslog,
  310                              "Failed to watch %s; upper limit on inotify "
  311                              "watches reached!\n",
  312                              this_file);
  313                 output_error(syslog,
  314                              "Please increase the amount of inotify watches "
  315                              "allowed per user via `/proc/sys/fs/inotify/"
  316                              "max_user_watches'.\n");
  317             } else {
  318                 output_error(syslog, "Couldn't watch %s: %s\n", this_file,
  319                              strerror(inotifytools_error()));
  320             }
  321             return EXIT_FAILURE;
  322         }
  323     }
  324 
  325     if (!quiet) {
  326         output_error(syslog, "Watches established.\n");
  327     }
  328 
  329     // Now wait till we get event
  330     struct inotify_event *event;
  331     char *moved_from = 0;
  332 
  333     do {
  334         event = inotifytools_next_event(timeout);
  335         if (!event) {
  336             if (!inotifytools_error()) {
  337                 return EXIT_TIMEOUT;
  338             } else {
  339                 output_error(syslog, "%s\n", strerror(inotifytools_error()));
  340                 return EXIT_FAILURE;
  341             }
  342         }
  343 
  344         if (quiet < 2 && (event->mask & orig_events)) {
  345             if (csv) {
  346                 output_event_csv(event);
  347             } else if (format) {
  348                 inotifytools_printf(event, format);
  349             } else {
  350                 inotifytools_printf(event, "%w %,e %f\n");
  351             }
  352         }
  353 
  354         // if we last had MOVED_FROM and don't currently have MOVED_TO,
  355         // moved_from file must have been moved outside of tree - so unwatch it.
  356         if (moved_from && !(event->mask & IN_MOVED_TO)) {
  357             if (!inotifytools_remove_watch_by_filename(moved_from)) {
  358                 output_error(syslog, "Error removing watch on %s: %s\n",
  359                              moved_from, strerror(inotifytools_error()));
  360             }
  361             free(moved_from);
  362             moved_from = 0;
  363         }
  364 
  365         if (monitor && recursive) {
  366             if ((event->mask & IN_CREATE) ||
  367                 (!moved_from && (event->mask & IN_MOVED_TO))) {
  368                 // New file - if it is a directory, watch it
  369                 static char *new_file;
  370 
  371                 nasprintf(&new_file, "%s%s",
  372                           inotifytools_filename_from_wd(event->wd),
  373                           event->name);
  374 
  375                 if (isdir(new_file) &&
  376                     !inotifytools_watch_recursively(new_file, events)) {
  377                     output_error(syslog,
  378                                  "Couldn't watch new directory %s: %s\n",
  379                                  new_file, strerror(inotifytools_error()));
  380                 }
  381                 free(new_file);
  382             } // IN_CREATE
  383             else if (event->mask & IN_MOVED_FROM) {
  384                 nasprintf(&moved_from, "%s%s/",
  385                           inotifytools_filename_from_wd(event->wd),
  386                           event->name);
  387                 // if not watched...
  388                 if (inotifytools_wd_from_filename(moved_from) == -1) {
  389                     free(moved_from);
  390                     moved_from = 0;
  391                 }
  392             } // IN_MOVED_FROM
  393             else if (event->mask & IN_MOVED_TO) {
  394                 if (moved_from) {
  395                     static char *new_name;
  396                     nasprintf(&new_name, "%s%s/",
  397                               inotifytools_filename_from_wd(event->wd),
  398                               event->name);
  399                     inotifytools_replace_filename(moved_from, new_name);
  400                     free(moved_from);
  401                     moved_from = 0;
  402                 } // moved_from
  403             }
  404         }
  405 
  406         fflush(NULL);
  407 
  408     } while (monitor);
  409 
  410     // If we weren't trying to listen for this event...
  411     if ((events & event->mask) == 0) {
  412         // ...then most likely something bad happened, like IGNORE etc.
  413         return EXIT_FAILURE;
  414     }
  415 
  416     return EXIT_SUCCESS;
  417 }
  418 
  419 bool parse_opts(int *argc, char ***argv, int *events, bool *monitor, int *quiet,
  420                 long int *timeout, int *recursive, bool *csv, bool *daemon,
  421                 bool *syslog, bool *no_dereference, char **format,
  422                 char **timefmt, char **fromfile, char **outfile,
  423                 char **exc_regex, char **exc_iregex, char **inc_regex,
  424                 char **inc_iregex, bool *no_newline) {
  425     assert(argc);
  426     assert(argv);
  427     assert(events);
  428     assert(monitor);
  429     assert(quiet);
  430     assert(timeout);
  431     assert(csv);
  432     assert(daemon);
  433     assert(syslog);
  434     assert(no_dereference);
  435     assert(format);
  436     assert(timefmt);
  437     assert(fromfile);
  438     assert(outfile);
  439     assert(exc_regex);
  440     assert(exc_iregex);
  441     assert(inc_regex);
  442     assert(inc_iregex);
  443 
  444     // Settings for options
  445     int new_event;
  446 
  447     // How many times --exclude has been specified
  448     unsigned int exclude_count = 0;
  449 
  450     // How many times --excludei has been specified
  451     unsigned int excludei_count = 0;
  452 
  453     const char *regex_warning =
  454         "only the last option will be taken into consideration.\n";
  455 
  456     // format provided by the user
  457     static char *customformat = NULL;
  458 
  459     // Short options
  460     static const char opt_string[] = "mrhcdsPqt:fo:e:";
  461 
  462     // Long options
  463     static const struct option long_opts[] = {
  464         {"help", no_argument, NULL, 'h'},
  465         {"event", required_argument, NULL, 'e'},
  466         {"monitor", no_argument, NULL, 'm'},
  467         {"quiet", no_argument, NULL, 'q'},
  468         {"timeout", required_argument, NULL, 't'},
  469         {"filename", no_argument, NULL, 'f'},
  470         {"recursive", no_argument, NULL, 'r'},
  471         {"csv", no_argument, NULL, 'c'},
  472         {"daemon", no_argument, NULL, 'd'},
  473         {"syslog", no_argument, NULL, 's'},
  474         {"no-dereference", no_argument, NULL, 'P'},
  475         {"format", required_argument, NULL, 'n'},
  476         {"no-newline", no_argument, NULL, '0'},
  477         {"timefmt", required_argument, NULL, 'i'},
  478         {"fromfile", required_argument, NULL, 'z'},
  479         {"outfile", required_argument, NULL, 'o'},
  480         {"exclude", required_argument, NULL, 'a'},
  481         {"excludei", required_argument, NULL, 'b'},
  482         {"include", required_argument, NULL, 'j'},
  483         {"includei", required_argument, NULL, 'k'},
  484         {NULL, 0, 0, 0},
  485     };
  486 
  487     // Get first option
  488     char curr_opt = getopt_long(*argc, *argv, opt_string, long_opts, NULL);
  489 
  490     // While more options exist...
  491     while ((curr_opt != '?') && (curr_opt != (char)-1)) {
  492         switch (curr_opt) {
  493         // --help or -h
  494         case 'h':
  495             print_help();
  496             // Shouldn't process any further...
  497             return false;
  498             break;
  499 
  500         // --monitor or -m
  501         case 'm':
  502             *monitor = true;
  503             break;
  504 
  505         // --quiet or -q
  506         case 'q':
  507             (*quiet)++;
  508             break;
  509 
  510         // --recursive or -r
  511         case 'r':
  512             (*recursive)++;
  513             break;
  514 
  515         // --csv or -c
  516         case 'c':
  517             (*csv) = true;
  518             break;
  519 
  520         // --daemon or -d
  521         case 'd':
  522             (*daemon) = true;
  523             (*monitor) = true;
  524             (*syslog) = true;
  525             break;
  526 
  527         // --syslog or -s
  528         case 's':
  529             (*syslog) = true;
  530             break;
  531 
  532         // --no-dereference or -P
  533         case 'P':
  534             (*no_dereference) = true;
  535             break;
  536 
  537         // --filename or -f
  538         case 'f':
  539             fprintf(stderr, "The '--filename' option no longer exists.  "
  540                             "The option it enabled in earlier\nversions of "
  541                             "inotifywait is now turned on by default.\n");
  542             return false;
  543             break;
  544 
  545         // --format
  546         case 'n':
  547             customformat = (char *)malloc(strlen(optarg) + 2);
  548             strcpy(customformat, optarg);
  549             break;
  550 
  551         // --no-newline
  552         case '0':
  553             (*no_newline) = true;
  554             break;
  555 
  556         // --timefmt
  557         case 'i':
  558             (*timefmt) = optarg;
  559             break;
  560 
  561         // --exclude
  562         case 'a':
  563             (*exc_regex) = optarg;
  564             exclude_count++;
  565             break;
  566 
  567         // --excludei
  568         case 'b':
  569             (*exc_iregex) = optarg;
  570             excludei_count++;
  571             break;
  572 
  573         // --include
  574         case 'j':
  575             (*inc_regex) = optarg;
  576             break;
  577 
  578         // --includei
  579         case 'k':
  580             (*inc_iregex) = optarg;
  581             break;
  582 
  583         // --fromfile
  584         case 'z':
  585             if (*fromfile) {
  586                 fprintf(stderr, "Multiple --fromfile options given.\n");
  587                 return false;
  588             }
  589             (*fromfile) = optarg;
  590             break;
  591 
  592         // --outfile
  593         case 'o':
  594             if (*outfile) {
  595                 fprintf(stderr, "Multiple --outfile options given.\n");
  596                 return false;
  597             }
  598             (*outfile) = optarg;
  599             break;
  600 
  601         // --timeout or -t
  602         case 't':
  603             if (!is_timeout_option_valid(timeout, optarg)) {
  604                 return false;
  605             }
  606             break;
  607 
  608         // --event or -e
  609         case 'e':
  610             // Get event mask from event string
  611             new_event = inotifytools_str_to_event(optarg);
  612 
  613             // If optarg was invalid, abort
  614             if (new_event == -1) {
  615                 fprintf(stderr, "'%s' is not a valid event!  Run with the "
  616                                 "'--help' option to see a list of "
  617                                 "events.\n",
  618                         optarg);
  619                 return false;
  620             }
  621 
  622             // Add the new event to the event mask
  623             (*events) = ((*events) | new_event);
  624 
  625             break;
  626         }
  627 
  628         curr_opt = getopt_long(*argc, *argv, opt_string, long_opts, NULL);
  629     }
  630 
  631     if (customformat) {
  632         if(!(*no_newline)) {
  633             strcat(customformat, "\n");
  634         }
  635         (*format) = customformat;
  636     }
  637 
  638     if (*exc_regex && *exc_iregex) {
  639         fprintf(stderr, "--exclude and --excludei cannot both be specified.\n");
  640         return false;
  641     }
  642 
  643     if (*inc_regex && *inc_iregex) {
  644         fprintf(stderr, "--include and --includei cannot both be specified.\n");
  645         return false;
  646     }
  647 
  648     if ((*inc_regex && *exc_regex) || (*inc_regex && *exc_iregex) ||
  649         (*inc_iregex && *exc_regex) || (*inc_iregex && *exc_iregex)) {
  650         fprintf(stderr,
  651                 "include and exclude regexp cannot both be specified.\n");
  652         return false;
  653     }
  654 
  655     if (*format && *csv) {
  656         fprintf(stderr, "-c and --format cannot both be specified.\n");
  657         return false;
  658     }
  659 
  660     if (!*format && *no_newline) {
  661         fprintf(stderr, "--no-newline cannot be specified without --format.\n");
  662         return false;
  663     }
  664 
  665     if (!*format && *timefmt) {
  666         fprintf(stderr, "--timefmt cannot be specified without --format.\n");
  667         return false;
  668     }
  669 
  670     if (*format && strstr(*format, "%T") && !*timefmt) {
  671         fprintf(stderr, "%%T is in --format string, but --timefmt was not "
  672                         "specified.\n");
  673         return false;
  674     }
  675 
  676     if (*daemon && *outfile == NULL) {
  677         fprintf(stderr, "-o must be specified with -d.\n");
  678         return false;
  679     }
  680 
  681     if (exclude_count > 1) {
  682         fprintf(stderr, "--exclude: %s", regex_warning);
  683     }
  684 
  685     if (excludei_count > 1) {
  686         fprintf(stderr, "--excludei: %s", regex_warning);
  687     }
  688 
  689     (*argc) -= optind;
  690     *argv = &(*argv)[optind];
  691 
  692     // If ? returned, invalid option
  693     return (curr_opt != '?');
  694 }
  695 
  696 void print_help() {
  697     printf("inotifywait %s\n", PACKAGE_VERSION);
  698     printf("Wait for a particular event on a file or set of files.\n");
  699     printf("Usage: inotifywait [ options ] file1 [ file2 ] [ file3 ] "
  700            "[ ... ]\n");
  701     printf("Options:\n");
  702     printf("\t-h|--help     \tShow this help text.\n");
  703     printf("\t@<file>       \tExclude the specified file from being "
  704            "watched.\n");
  705     printf("\t--exclude <pattern>\n"
  706            "\t              \tExclude all events on files matching the\n"
  707            "\t              \textended regular expression <pattern>.\n"
  708            "\t              \tOnly the last --exclude option will be\n"
  709            "\t              \ttaken into consideration.\n");
  710     printf("\t--excludei <pattern>\n"
  711            "\t              \tLike --exclude but case insensitive.\n");
  712     printf("\t--include <pattern>\n"
  713            "\t              \tExclude all events on files except the ones\n"
  714            "\t              \tmatching the extended regular expression\n"
  715            "\t              \t<pattern>.\n");
  716     printf("\t--includei <pattern>\n"
  717            "\t              \tLike --include but case insensitive.\n");
  718     printf("\t-m|--monitor  \tKeep listening for events forever or until "
  719            "--timeout expires.\n"
  720            "\t              \tWithout this option, inotifywait will exit after "
  721            "one event is received.\n");
  722     printf(
  723         "\t-d|--daemon   \tSame as --monitor, except run in the background\n"
  724         "\t              \tlogging events to a file specified by --outfile.\n"
  725         "\t              \tImplies --syslog.\n");
  726     printf("\t-P|--no-dereference\n"
  727            "\t              \tDo not follow symlinks.\n");
  728     printf("\t-r|--recursive\tWatch directories recursively.\n");
  729     printf("\t--fromfile <file>\n"
  730            "\t              \tRead files to watch from <file> or `-' for "
  731            "stdin.\n");
  732     printf("\t-o|--outfile <file>\n"
  733            "\t              \tPrint events to <file> rather than stdout.\n");
  734     printf("\t-s|--syslog   \tSend errors to syslog rather than stderr.\n");
  735     printf("\t-q|--quiet    \tPrint less (only print events).\n");
  736     printf("\t-qq           \tPrint nothing (not even events).\n");
  737     printf("\t--format <fmt>\tPrint using a specified printf-like format\n"
  738            "\t              \tstring; read the man page for more details.\n");
  739     printf("\t--no-newline  \tDon't print newline symbol after\n"
  740            "\t              \t--format string.\n");
  741     printf("\t--timefmt <fmt>\tstrftime-compatible format string for use with\n"
  742            "\t              \t%%T in --format string.\n");
  743     printf("\t-c|--csv      \tPrint events in CSV format.\n");
  744     printf("\t-t|--timeout <seconds>\n"
  745            "\t              \tWhen listening for a single event, time out "
  746            "after\n"
  747            "\t              \twaiting for an event for <seconds> seconds.\n"
  748            "\t              \tIf <seconds> is negative, inotifywait will never "
  749            "time "
  750            "out.\n");
  751     printf("\t-e|--event <event1> [ -e|--event <event2> ... ]\n"
  752            "\t\tListen for specific event(s).  If omitted, all events are \n"
  753            "\t\tlistened for.\n\n");
  754     printf("Exit status:\n");
  755     printf("\t%d  -  An event you asked to watch for was received.\n",
  756            EXIT_SUCCESS);
  757     printf("\t%d  -  An event you did not ask to watch for was received\n",
  758            EXIT_FAILURE);
  759     printf("\t      (usually delete_self or unmount), or some error "
  760            "occurred.\n");
  761     printf("\t%d  -  The --timeout option was given and no events occurred\n",
  762            EXIT_TIMEOUT);
  763     printf("\t      in the specified interval of time.\n\n");
  764     printf("Events:\n");
  765     print_event_descriptions();
  766 }