URI: 
       tMerge branch 'master' of z3bra.org:wendy - wendy - watch files/directories and run commands on any event
  HTML git clone git://z3bra.org/wendy
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit d9b41bb26d563a50964b320cbe9f2634e7c0c784
   DIR parent 44ee3d650cfbd4e583dfac2f978ceb82d031f6c2
  HTML Author: z3bra <willy@mailoo.org>
       Date:   Wed, 12 Feb 2014 13:37:01 +0100
       
       Merge branch 'master' of z3bra.org:wendy
       
       Diffstat:
         M Makefile                            |       4 +---
         M README                              |      38 ++++++++++++++++++++++++++++---
         M wendy.c                             |      76 ++++++++++++++++++++++++++-----
       
       3 files changed, 100 insertions(+), 18 deletions(-)
       ---
   DIR diff --git a/Makefile b/Makefile
       t@@ -14,9 +14,7 @@ wendy : wendy.o
        all : wendy
        
        clean :
       -        ${RM} wendy
       -        ${RM} -f *.o
       -        ${RM} -f *~
       +        ${RM} -f wendy *.o *~
        
        path:
                @echo PREFIX: ${PREFIX}
   DIR diff --git a/README b/README
       t@@ -12,13 +12,45 @@ specific command when an event occurs.
        The program is made the moire simple possible, to leave the room to unlimited
        uses. Be creative !
        
       +Every event raised by inotify is handled. Just sum them up to watch multiple
       +event at the same time. Here is the full table:
       +(see inotify(1) for a better explanation of those events)
       +
       +    IN_ACCESS ........ 1
       +    IN_MODIFY ........ 2
       +    IN_ATTRIB ........ 4
       +    IN_CLOSE_WRITE ... 8
       +    IN_CLOSE_NOWRITE . 16
       +    IN_OPEN .......... 32
       +    IN_MOVED_FROM .... 64
       +    IN_MOVED_TO ...... 128
       +    IN_CREATE ........ 256
       +    IN_DELETE ........ 512
       +    IN_DELETE_SELF ... 1024
       +    IN_MOVE_SELF ..... 2048
       +
       +To watch for both creation AND deletion in a directory, do some math:
       +
       +    256 + 512 = 768
       +
       +then, pass that value to wendy so that she can watch after both of them (did I
       +just say 'she'?).
       +
       +For more convenience, the IN_CREATE, IN_DELETE and IN_MODIFY events are bound to
       +(respectively) -C, -D and -M.
       +
        Here are some examples:
        
            # Tell me whenever I have a new mail
       -    wendy -C ~/mails/INBOX/new -t 60 -e espeak "You got a new mail"
       +    wendy -C -d ~/mails/INBOX/new -t 60 -e espeak "You got a new mail"
        
            # On-the-fly recompilation
       -    wendy -M -f ~/src/dev/program/source.c -t 1 -e make
       +    wendy -M -q -d ~/src/dev/program/ -f source.c -t 1 -e make
       +    # or eventually
       +    wendy -l | grep -i close_write
       +    IN_CLOSE_WRITE ... 8
       +    wendy -m 8 -q -d ~/src/dev/program/ -f source.c -t 1 -e make
       +
        
            # Get up to date with community based projects
       -    wendy -DMC -f /mnt/nfs/project/ -t 30 -e notify-send 'project updated'
       +    wendy -D -M -C -d /mnt/nfs/project/ -t 30 -e notify-send 'project updated'
   DIR diff --git a/wendy.c b/wendy.c
       t@@ -34,18 +34,53 @@ extern char **environ;
        void
        usage()
        {
       -    fputs("usage: wendy [-C] [-D] [-M] [-f file] [-t timeout] "
       -          "-e command [arguments]\n"
       -          "\t-C           : raise creation events\n"
       +    fputs("usage: wendy [-C] [-D] [-M] [-m mask] [-l] [-f file] [-t timeout] [-q] "
       +          "[-e command [args] ..]\n"
       +          "\t-C           : raise creation events (default)\n"
                  "\t-D           : raise deletion events\n"
                  "\t-M           : raise modification events\n"
       +          "\t-m mask      : set mask manually (see -l))\n"
       +          "\t-l           : list events mask values\n"
                  "\t-f file      : file to watch (everything is a file)\n"
                  "\t-t timeout   : time between event check (in seconds)\n"
       +          "\t-q           : don't talk to me, program\n"
                  "\t-e command   : command to launch (must be the last argument!)\n",
                 stdout);
            exit(1);
        }
        
       +void
       +list_events()
       +{
       +    fprintf(stdout,
       +            "IN_ACCESS ........ %u\n"
       +            "IN_MODIFY ........ %u\n"
       +            "IN_ATTRIB ........ %u\n"
       +            "IN_CLOSE_WRITE ... %u\n"
       +            "IN_CLOSE_NOWRITE . %u\n"
       +            "IN_OPEN .......... %u\n"
       +            "IN_MOVED_FROM .... %u\n"
       +            "IN_MOVED_TO ...... %u\n"
       +            "IN_CREATE ........ %u\n"
       +            "IN_DELETE ........ %u\n"
       +            "IN_DELETE_SELF ... %u\n"
       +            "IN_MOVE_SELF ..... %u\n",
       +            IN_ACCESS,
       +            IN_MODIFY,
       +            IN_ATTRIB,
       +            IN_CLOSE_WRITE,
       +            IN_CLOSE_NOWRITE,
       +            IN_OPEN,
       +            IN_MOVED_FROM,
       +            IN_MOVED_TO,
       +            IN_CREATE,
       +            IN_DELETE,
       +            IN_DELETE_SELF,
       +            IN_MOVE_SELF
       +           );
       +    exit(0);
       +}
       +
        int
        execvpe(const char *program, char **argv, char **envp)
        {
       t@@ -60,7 +95,8 @@ execvpe(const char *program, char **argv, char **envp)
        int
        main (int argc, char **argv)
        {
       -    int  fd, wd, len, mask = 0, i = 0, timeout = 0, ignore = 0;
       +    int  fd, wd, len, i = 0, timeout = 0, ignore = 0, quiet = 0;
       +    uint32_t mask = 0;
            char buf[BUF_LEN];
            char *file = NULL, **cmd = NULL;
            struct inotify_event *ev;
       t@@ -68,22 +104,24 @@ main (int argc, char **argv)
            if ((argc == 2 && argv[1][0] == '-' && argv[1][1] == 'h')) usage();
        
            /* parse option given. see usage() above */
       -    for(i = 1; (i + 1 < argc) && (argv[i][0] == '-') && !ignore; i++) {
       +    for(i = 1; (i < argc) && (argv[i][0] == '-') && !ignore; i++) {
                switch (argv[i][1]) {
                    case 'C': mask |= IN_CREATE; break;
                    case 'D': mask |= IN_DELETE; break;
                    case 'M': mask |= IN_MODIFY; break;
       +            case 'm': mask |= atoi(argv[++i]); break;
       +            case 'l': list_events(); break;
       +            case 'q': quiet = 1; break;
                    case 'f': file = argv[++i]; break;
                    case 't': timeout = atoi(argv[++i]); break;
                    case 'e': cmd = &argv[++i]; ignore=1; break;
       +            default: usage();
                }
            }
        
            /* test given arguments */
            if (!file)      { file = DEFAULT_FILE; }
            if (!timeout)   { timeout = DEFAULT_CHECK; }
       -    if (!cmd)       { usage(); }
       -    if (!mask)      { mask |= IN_CREATE; }
        
            /* get file descriptor */
            fd = inotify_init();
       t@@ -96,8 +134,12 @@ main (int argc, char **argv)
            if (wd < 0)
                perror("inotify_add_watch");
        
       +    if (!quiet) {
       +        printf( "watching file %s with event mask %u\n", file, mask);
       +    }
       +
            /* start looping */
       -    while (1) {
       +    for (;;) {
                /* get every event raised, and queue them */
                len = read(fd, buf, BUF_LEN);
        
       t@@ -114,13 +156,23 @@ main (int argc, char **argv)
                    /* get events one by one */
                    ev = (struct inotify_event *) &buf[i]; 
        
       -            if (ev->len > 0) {
       +            if (!quiet && ev->len > 0) {
                        printf("event on file %s: %u\n", ev->name, ev->mask);
                    }
        
       -            /* OMG a new event ! Quick, raise an alert ! */
       -            if (!fork()) {
       -                execvpe(cmd[0], cmd, environ);
       +            /*
       +             * do not do anything if no command given.
       +             * Also only execute the command if the file concerned by the event
       +             * is the one we're watching, or if we're not looking for a specific
       +             * file.
       +             *
       +             * If you don't undersand this sentence, don't worry. Me neither.
       +             * Just trust the if().
       +             */
       +            if (cmd && !(file && strncmp(file, ev->name, 255))) {
       +
       +                /* OMG a new event ! Quick, raise an alert ! */
       +                if (!fork()) { execvpe(cmd[0], cmd, environ); }
                    }
        
                    /* jump to the next one */