| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <stdint.h> | |
| #include <fcntl.h> | |
| #include <sys/ioctl.h> | |
| #include <sys/inotify.h> | |
| #include <errno.h> | |
| int notify_main(int argc, char *argv[]) | |
| { | |
| int c; | |
| int nfd, ffd; | |
| int res; | |
| char event_buf[512]; | |
| struct inotify_event *event; | |
| int event_mask = IN_ALL_EVENTS; | |
| int event_count = 1; | |
| int print_files = 0; | |
| int verbose = 2; | |
| int width = 80; | |
| char **file_names; | |
| int file_count; | |
| int id_offset = 0; | |
| int i; | |
| char *buf; | |
| do { | |
| c = getopt(argc, argv, "m:c:pv:w:"); | |
| if (c == EOF) | |
| break; | |
| switch (c) { | |
| case 'm': | |
| event_mask = strtol(optarg, NULL, 0); | |
| break; | |
| case 'c': | |
| event_count = atoi(optarg); | |
| break; | |
| case 'p': | |
| print_files = 1; | |
| break; | |
| case 'v': | |
| verbose = atoi(optarg); | |
| break; | |
| case 'w': | |
| width = atoi(optarg); | |
| break; | |
| case '?': | |
| fprintf(stderr, "%s: invalid option -%c\n", | |
| argv[0], optopt); | |
| exit(1); | |
| } | |
| } while (1); | |
| if (argc <= optind) { | |
| fprintf(stderr, "Usage: %s [-m eventmask] [-c count] [-p] [-v verbosity] path [path ...]\n", argv[0]); | |
| return 1; | |
| } | |
| nfd = inotify_init(); | |
| if(nfd < 0) { | |
| fprintf(stderr, "inotify_init failed, %s\n", strerror(errno)); | |
| return 1; | |
| } | |
| file_names = argv + optind; | |
| file_count = argc - optind; | |
| for(i = 0; i < file_count; i++) { | |
| res = inotify_add_watch(nfd, file_names[i], event_mask); | |
| if(res < 0) { | |
| fprintf(stderr, "inotify_add_watch failed for %s, %s\n", file_names[i], strerror(errno)); | |
| return 1; | |
| } | |
| if(i == 0) | |
| id_offset = -res; | |
| if(res + id_offset != i) { | |
| fprintf(stderr, "%s got unexpected id %d instead of %d\n", file_names[i], res, i); | |
| return 1; | |
| } | |
| } | |
| buf = malloc(width + 2); | |
| while(1) { | |
| int event_pos = 0; | |
| res = read(nfd, event_buf, sizeof(event_buf)); | |
| if(res < (int)sizeof(*event)) { | |
| if(errno == EINTR) | |
| continue; | |
| fprintf(stderr, "could not get event, %s\n", strerror(errno)); | |
| return 1; | |
| } | |
| //printf("got %d bytes of event information\n", res); | |
| while(res >= (int)sizeof(*event)) { | |
| int event_size; | |
| event = (struct inotify_event *)(event_buf + event_pos); | |
| if(verbose >= 2) | |
| printf("%s: %08x %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->cookie, event->len ? event->name : ""); | |
| else if(verbose >= 2) | |
| printf("%s: %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->len ? event->name : ""); | |
| else if(verbose >= 1) | |
| printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : ""); | |
| if(print_files && (event->mask & IN_MODIFY)) { | |
| char filename[512]; | |
| ssize_t read_len; | |
| char *display_name; | |
| int buflen; | |
| strcpy(filename, file_names[event->wd + id_offset]); | |
| if(event->len) { | |
| strcat(filename, "/"); | |
| strcat(filename, event->name); | |
| } | |
| ffd = open(filename, O_RDONLY); | |
| display_name = (verbose >= 2 || event->len == 0) ? filename : event->name; | |
| buflen = width - strlen(display_name); | |
| read_len = read(ffd, buf, buflen); | |
| if(read_len > 0) { | |
| if(read_len < buflen && buf[read_len-1] != '\n') { | |
| buf[read_len] = '\n'; | |
| read_len++; | |
| } | |
| if(read_len == buflen) { | |
| buf[--read_len] = '\0'; | |
| buf[--read_len] = '\n'; | |
| buf[--read_len] = '.'; | |
| buf[--read_len] = '.'; | |
| buf[--read_len] = '.'; | |
| } | |
| else { | |
| buf[read_len] = '\0'; | |
| } | |
| printf("%s: %s", display_name, buf); | |
| } | |
| close(ffd); | |
| } | |
| if(event_count && --event_count == 0) | |
| return 0; | |
| event_size = sizeof(*event) + event->len; | |
| res -= event_size; | |
| event_pos += event_size; | |
| } | |
| } | |
| return 0; | |
| } |