URI: 
       twendy can now watch multiple files at the same time - 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 5c5a9f30ea0bb497b1307cff891931e08591ab71
   DIR parent bdb6607a79f68266c32227b5f4948f945265dfad
  HTML Author: z3bra <willy@mailoo.org>
       Date:   Fri, 27 Mar 2015 20:09:06 +0100
       
       wendy can now watch multiple files at the same time
       
       Diffstat:
         M wendy.c                             |     138 +++++++++++++++++++++-----------
       
       1 file changed, 92 insertions(+), 46 deletions(-)
       ---
   DIR diff --git a/wendy.c b/wendy.c
       t@@ -18,6 +18,7 @@
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
       +#include <linux/limits.h>
        #include <string.h>
        #include <sys/inotify.h>
        
       t@@ -29,27 +30,36 @@
        #define DEFAULT_FILE    "." /* defaults to current directory */
        #define DEFAULT_CHECK   1   /* defaults to 1 second */
        
       +struct node_t {
       +    int wd;
       +    char path[PATH_MAX];
       +    struct node_t *next;
       +};
       +
        extern char **environ;
        
       -void
       +int verbose = 0, nb = 0;
       +struct node_t *head = NULL;
       +
       +    void
        usage()
        {
            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-v           : talk to me, program\n"
       -          "\t-e command   : command to launch (must be the last argument!)\n",
       -         stdout);
       +            "[-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-v           : talk to me, program\n"
       +            "\t-e command   : command to launch (must be the last argument!)\n",
       +            stdout);
            exit(1);
        }
        
       -void
       +    void
        list_events()
        {
            fprintf(stdout,
       t@@ -81,11 +91,11 @@ list_events()
                    IN_MOVE_SELF,
                    IN_ALL_EVENTS,
                    IN_UNMOUNT
       -           );
       +                );
            exit(0);
        }
        
       -int
       +    int
        execvpe(const char *program, char **argv, char **envp)
        {
            char **saved = environ;
       t@@ -96,27 +106,82 @@ execvpe(const char *program, char **argv, char **envp)
            return rc;
        }
        
       -int
       +    struct node_t *
       +add_node(int wd, const char *path)
       +{
       +    struct node_t *n = NULL;
       +
       +    n = malloc(sizeof(struct node_t));
       +
       +    if (!n)
       +        return NULL;
       +
       +    n->wd = wd;
       +    strncpy(n->path, path, PATH_MAX);
       +
       +    n->next = head ? head : NULL;
       +    head = n;
       +
       +    return n;
       +}
       +
       +    const char *
       +wd_name(int wd)
       +{
       +    struct node_t *n = head;
       +
       +    while (n && n->wd != wd)
       +        n = n->next;
       +
       +    return n ? n->path : "unknown";
       +}
       +
       +    int
       +watch_node(int fd, const char *path, uint32_t mask)
       +{
       +    int wd = -1;
       +
       +    /* add a watcher on the file */
       +    wd  = inotify_add_watch(fd, path, mask);
       +
       +    if (wd < 0) {
       +        perror("inotify_add_watch");
       +        exit(1);
       +    }
       +
       +    add_node(wd, path);
       +    nb++;
       +
       +    return wd;
       +}
       +
       +    int
        main (int argc, char **argv)
        {
       -    int  fd, wd, len, i = 0, timeout = 0, ignore = 0, verbose = 0;
       +    int  fd, len, i = 0, timeout = 0, ignore = 0;
            uint32_t mask = 0;
            char buf[BUF_LEN];
       -    char *file = NULL, **cmd = NULL;
       +    char **cmd = NULL;
            struct inotify_event *ev;
        
            if ((argc == 2 && argv[1][0] == '-' && argv[1][1] == 'h')) usage();
        
       +    /* get file descriptor */
       +    fd = inotify_init();
       +    if (fd < 0)
       +        perror("inotify_init");
       +
       +
            /* parse option given. see usage() above */
            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 'm': mask = atoi(argv[++i]); break;
                    case 'l': list_events(); break;
                    case 'v': verbose += 1; break;
       -            case 'f': file = argv[++i]; break;
       +            case 'f': watch_node(fd, argv[++i], mask); break;
                    case 't': timeout = atoi(argv[++i]); break;
                    case 'e': cmd = &argv[++i]; ignore=1; break;
                    default: usage();
       t@@ -124,29 +189,10 @@ main (int argc, char **argv)
            }
        
            /* test given arguments */
       -    if (!file)      { file = DEFAULT_FILE; }
            if (!timeout)   { timeout = DEFAULT_CHECK; }
        
       -    /* get file descriptor */
       -    fd = inotify_init();
       -    if (fd < 0)
       -        perror("inotify_init");
       -
       -add_watch:
       -    /* add a watcher on the file */
       -    wd  = inotify_add_watch(fd, file, mask);
       -
       -    if (wd < 0) {
       -        perror("inotify_add_watch");
       -        exit(1);
       -    }
       -
       -    if (verbose) {
       -        printf( "watching file %s with event mask %u\n", file, mask);
       -    }
       -
            /* start looping */
       -    for (;;) {
       +    while (nb>0) {
        
                /* get every event raised, and queue them */
                len = read(fd, buf, BUF_LEN);
       t@@ -163,13 +209,13 @@ add_watch:
                    /* get events one by one */
                    ev = (struct inotify_event *) &buf[i];
        
       -            if (ev->mask & IN_IGNORED) {
       -                printf("watch removed, attemting to create another\n");
       -                goto add_watch;
       -            }
       -
                    if (verbose) {
       -                printf("%u: %s\n", ev->mask, ev->len ? ev->name : file);
       +                if (ev->mask & IN_IGNORED) {
       +                    printf("! %s\n", ev->len? ev->name: wd_name(ev->wd));
       +                    nb--;
       +                }
       +
       +                printf("%-3u %s\n", ev->mask, ev->len? ev->name: wd_name(ev->wd));
                    }
        
                    /*