/* --*- c -*-- * * placed in the public domain by Patrice Dumas, Dec 2008. * */ #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/inotify.h> #include <libgen.h> #include <sys/types.h> #include <dirent.h> typedef struct fcron_watched_file { char * filename; int already_here; } fcron_watched_file; #ifndef SYSCONFDIR # define SYSCONFDIR "/etc" #endif #ifndef CRONDIR #define CRONDIR SYSCONFDIR "/cron.d" #endif fcron_watched_file watched_config_files [] = { { SYSCONFDIR "/crontab", 0 }, { SYSCONFDIR "/fcrontab", 0 }, { CRONDIR, 0 }, {NULL, 0} }; /* size of the event structure, not counting name */ #define EVENT_SIZE (sizeof (struct inotify_event)) /* 1024 events with filenames of length 1024 */ #define BUF_LEN (1024 * (EVENT_SIZE + 1024)) char events_buffer[BUF_LEN]; int main(int argc, char *argv[]) { int fd; int watch_desc; int watch_desc_sysconfdir; int watch_sysconfdir = 0; fcron_watched_file *watched_file; struct stat st; int debug = 0; fd = inotify_init(); if (fd < 0) { perror("inotify_init()"); return EXIT_FAILURE; } /* * if file or dir exist, add a watch, otherwise set a watch on the up * directory to watch file appear */ for (watched_file = watched_config_files; watched_file->filename != NULL; watched_file++) { if (lstat(watched_file->filename, &st) == 0) { watch_desc = inotify_add_watch(fd, watched_file->filename, IN_CLOSE_WRITE | IN_ATTRIB | IN_MOVED_TO | IN_MOVED_FROM | IN_MOVE_SELF | IN_DELETE); if (watch_desc < 0) { if (lstat(watched_file->filename, &st) == 0) { fprintf(stderr, "inotify_add_watch(%s): %s\n", watched_file->filename, strerror(errno)); close(fd); return EXIT_FAILURE; } else /* file was removed between the first stat and inotify_add_watch */ return EXIT_SUCCESS; } watched_file->already_here = 1; if (debug) fprintf(stderr, "File/dir already there: %s\n", watched_file->filename); } else if (! watch_sysconfdir) { watch_desc_sysconfdir = inotify_add_watch(fd, SYSCONFDIR, IN_CREATE | IN_MOVED_TO); if (watch_desc_sysconfdir < 0) { perror("inotify_add_watch("SYSCONFDIR")"); close(fd); return EXIT_FAILURE; } if (debug) fprintf(stderr, "Watching " SYSCONFDIR " (for %s)\n", watched_file->filename); watch_sysconfdir = 1; } } /* the loop is needed in case a file or directory is missing * since in that case we don't exit if another file is added in * SYSCONFDIR */ while (1) { fd_set fds; int rc; int len; int i = 0; FD_ZERO(&fds); FD_SET(fd, &fds); rc = select(fd+1, &fds, NULL, NULL, NULL); if (rc < 0) { perror("select()"); close(fd); return EXIT_FAILURE; } len = read (fd, events_buffer, BUF_LEN); if (len < 0) { perror ("read"); close(fd); return EXIT_FAILURE; } else if (!len) {/* what does it mean ?*/ /* in doubt it is as if something changed */ return EXIT_SUCCESS; } while (i < len) { struct inotify_event *event; event = (struct inotify_event *) &events_buffer[i]; if (debug) { printf ("wd=%d mask=%u cookie=%u len=%u\n", event->wd, event->mask, event->cookie, event->len); if (event->len) printf ("name=%s\n", event->name); } if (watch_sysconfdir && (event->wd == watch_desc_sysconfdir) && event->len) { for (watched_file = watched_config_files; watched_file->filename != NULL; watched_file++) { if ((strcmp(event->name, basename(watched_file->filename)) == 0) && (!watched_file->already_here)) return EXIT_SUCCESS; } i += EVENT_SIZE + event->len; } else return EXIT_SUCCESS; } } }