/* * inotify-watch.c * * Watch a file or directory for changes using inotify * * Copyright (c) 2008-2009 Tobias Klauser * * All rights reserved. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #define log(fmt, args...) do { \ struct timeval now; \ char buf[sizeof("XX:XX:XX")]; \ if (gettimeofday(&now, NULL) == 0 && \ strftime(buf, sizeof(buf), "%T", localtime(&now.tv_sec)) != 0) { \ fprintf(stdout, "%s.%06lu " fmt, buf, now.tv_usec, ##args); \ } } while(0) #define log_cont(fmt, args...) fprintf(stdout, fmt, ##args) #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x)) #define DECLARE_M2STR(x) { x, #x } struct mask2string { uint32_t mask; const char *desc; }; static const struct mask2string events[] = { DECLARE_M2STR(IN_ACCESS), DECLARE_M2STR(IN_MODIFY), DECLARE_M2STR(IN_ATTRIB), DECLARE_M2STR(IN_CLOSE_WRITE), DECLARE_M2STR(IN_CLOSE_NOWRITE), DECLARE_M2STR(IN_OPEN), DECLARE_M2STR(IN_MOVED_FROM), DECLARE_M2STR(IN_MOVED_TO), DECLARE_M2STR(IN_CREATE), DECLARE_M2STR(IN_DELETE), DECLARE_M2STR(IN_DELETE_SELF), DECLARE_M2STR(IN_MOVE_SELF), DECLARE_M2STR(IN_UNMOUNT), DECLARE_M2STR(IN_Q_OVERFLOW), DECLARE_M2STR(IN_IGNORED), /* special flags */ DECLARE_M2STR(IN_ONLYDIR), DECLARE_M2STR(IN_DONT_FOLLOW), DECLARE_M2STR(IN_MASK_ADD), DECLARE_M2STR(IN_ONESHOT), }; static void inotify_print_event(struct inotify_event *inev) { unsigned int i; /* stat? */ log("(%s) wd=%04x, cookie=%04x, len=%04x, name=\"%s\" :", inev->mask & IN_ISDIR ? "dir" : "file", inev->wd, inev->cookie, inev->len, inev->len > 0 ? inev->name : ""); for (i = 0; i < ARRAY_SIZE(events); i++) if (inev->mask & events[i].mask) log_cont(" %s", events[i].desc); log_cont("\n"); } int main(int argc, char *argv[]) { int fd, len; int *watches; struct inotify_event *inev; char buf[1024]; if (argc < 2) { fprintf(stderr, "Usage: %s ...\n", *argv); exit(EXIT_FAILURE); } ++argv; fd = inotify_init(); if (fd < 0) { perror("inotify_init"); exit(EXIT_FAILURE); } watches = malloc((argc - 1) * sizeof(int)); if (!watches) { perror("malloc"); exit(EXIT_FAILURE); } while (*argv) { *watches = inotify_add_watch(fd, *argv, IN_ALL_EVENTS|IN_UNMOUNT); if (*watches < 0) { perror("inotify_add_watch"); exit(EXIT_FAILURE); } ++watches; ++argv; } while (1) { len = read(fd, buf, sizeof(buf)); inev = (struct inotify_event *) &buf; while (len > 0) { inotify_print_event(inev); len -= sizeof(struct inotify_event) + inev->len; inev = (struct inotify_event *) ((char *) inev + sizeof(struct inotify_event) + inev->len); } } return 0; }