blob: 7fc6b744bb7c9d6baeee6dd6afdcd6a9bc91246f [file] [log] [blame]
/*
* Copyright 2012-2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* A simple program that uses the inotify api to watch a directory given as
* argument. If any of the files in that directory suffers any change,
* this program will output the name of the file, without including the
* whole path.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/inotify.h>
#include <sys/stat.h>
#include <unistd.h>
static void die(const char *tag) {
perror(tag);
exit(1);
}
static void close_and_die(int fd, const char *tag) {
close(fd);
die(tag);
}
int main(int argc, const char **argv) {
int inotify_fd, len, i, nr_dirs = argc-1;
int *dir_wds;
char buf[4096], *ptr;
struct inotify_event *event;
if (argc < 2) {
fprintf(stderr,
"usage: %s <dirname>...\n"
" Outputs the name of the files in the given "
" directories that have been modified.\n",
argv[0]);
exit(2);
}
for (i = 0; i < nr_dirs; ++i) {
const char *dir_name = argv[1+i];
// Sanity checks.
struct stat sb;
if (stat(dir_name, &sb) == 0) {
if (!S_ISDIR(sb.st_mode)) {
fprintf(stderr, "%s is not a directory\n", dir_name);
exit(1);
}
} else {
if (mkdir(dir_name, S_IRWXU | S_IRWXG | S_IRWXO))
die("mkdir");
}
}
inotify_fd = inotify_init();
if (inotify_fd < 0)
die("inotify_init");
dir_wds = calloc(nr_dirs, sizeof(*dir_wds));
if (!dir_wds)
die("calloc");
for (i = 0; i < nr_dirs; i++) {
dir_wds[i] = inotify_add_watch(inotify_fd, argv[1+i],
IN_MOVE | IN_CREATE | IN_DELETE | IN_MODIFY);
if (dir_wds[i] < 0)
die("inotify_add_watch");
}
while (1) {
len = read(inotify_fd, buf, sizeof(buf));
if (len == 0) {
fprintf(stderr, "inotify read EOF");
break;
}
if (len < 0) {
if (errno == EINTR || errno == EAGAIN)
continue;
close_and_die(inotify_fd, "inotify read");
}
for (ptr = buf; ptr < buf + len; ptr += event->len + sizeof(*event)) {
event = (struct inotify_event *)ptr;
// Check to see if the the event struct is not incomplete.
if (ptr + sizeof(*event) > buf + len) {
fprintf(stderr, "inotify: incomplete inotify event\n");
break;
}
if (event->mask & (IN_IGNORED | IN_UNMOUNT)) {
die("bailing out, non-existing directory");
} else if (event->mask & IN_Q_OVERFLOW) {
fprintf(stderr, "inotify: event queue overflowed\n");
break;
} else if (event->mask & IN_ISDIR) {
fprintf(stderr, "inotify: directory triggered event, will ignore\n");
continue;
}
if (event->len && ptr + sizeof(*event) + event->len <= buf + len) {
// Pathname is null terminated.
fprintf(stdout, "%s\n", event->name);
fflush(stdout);
}
}
}
free(dir_wds);
close(inotify_fd);
return 0;
}