#include <sys/inotify.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>
#include <string.h>
#include <errno.h>

#define EVENT_SIZE  (sizeof (struct inotify_event))
#define BUF_LEN        (1024 * (EVENT_SIZE + 16))

int main(int argc, char** argv)
{
    int ifd, len = 0, i = 0, selectret = 0, maxfd, retryselect, pid;
    fd_set set;
    char buf[BUF_LEN]; 
    char *tmp;
    struct inotify_event *event;
    struct stat file_stat;

    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s <dirtowatch>\n", argv[0]);
        exit(-1);
    }

    ifd = inotify_init();

    if (ifd < 0)
    {
    	perror("inotify_init");
    	return -1;
    }

    if (inotify_add_watch(ifd, argv[1], IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE | IN_DELETE) == -1)
    {
        perror("inotify_add_watch");
        return -1;
    }

    while (1)
    {		
        /* set up fds and max */
        FD_ZERO(&set);
        FD_SET(ifd, &set);
        maxfd = ifd;

        retryselect = 1;
        while (retryselect)
        {
            /* use select to get activity on any of the fds */
            selectret = select(maxfd + 1, &set, NULL, NULL, NULL);

            if (selectret == -1)
            {
                if (errno == EINTR)
                    retryselect = 1;
                else
                    exit(-2);
            }
            else
                retryselect = 0;
        }
            
        /* handle any events on the inotify fd */
        if (FD_ISSET(ifd, &set))
        {
            len = read(ifd, buf, BUF_LEN);
            while (i < len)
            {
                event = (struct inotify_event *) &buf[i];
                if (event->len && (event->mask & IN_CLOSE_WRITE || event->mask & IN_MOVED_TO))
                {
                    tmp = malloc(strlen(argv[1]) + 1 + strlen(event->name) + 1);
                    sprintf(tmp, "%s/%s", argv[1], event->name);

                    printf("IN_CLOSE_WRITE: %s", tmp);

                    if (stat(tmp, &file_stat) == -1)
                        perror("STAT FAILED");
                    else
                        printf("\tsize: %d\tlast mod time: %d\n", file_stat.st_size, file_stat.st_mtime);
                    free(tmp);

                }
                else if (event->len && (event->mask & IN_CREATE && event->mask & IN_ISDIR))
                {
                    printf("IN_CREATE(DIR): %s\n", event->name);
                }
                else if (event->len && (event->mask & IN_DELETE && event->mask & IN_ISDIR))
                {
                    printf("IN_DELETE(DIR): %s\n", event->name);
                }
                
                i += EVENT_SIZE + event->len;
            }
            i = 0;
        }
    } 

    return 0;
} 
