1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <stdint.h>
5#include <fcntl.h>
6#include <unistd.h>
7#include <sys/ioctl.h>
8#include <sys/inotify.h>
9#include <errno.h>
10
11int notify_main(int argc, char *argv[])
12{
13    int c;
14    int nfd, ffd;
15    int res;
16	char event_buf[512];
17    struct inotify_event *event;
18	int event_mask = IN_ALL_EVENTS;
19    int event_count = 1;
20	int print_files = 0;
21	int verbose = 2;
22	int width = 80;
23	char **file_names;
24	int file_count;
25	int id_offset = 0;
26	int i;
27	char *buf;
28
29    do {
30        c = getopt(argc, argv, "m:c:pv:w:");
31        if (c == EOF)
32            break;
33        switch (c) {
34        case 'm':
35            event_mask = strtol(optarg, NULL, 0);
36            break;
37        case 'c':
38            event_count = atoi(optarg);
39            break;
40		case 'p':
41			print_files = 1;
42			break;
43        case 'v':
44            verbose = atoi(optarg);
45            break;
46        case 'w':
47            width = atoi(optarg);
48            break;
49        case '?':
50            fprintf(stderr, "%s: invalid option -%c\n",
51                argv[0], optopt);
52            exit(1);
53        }
54    } while (1);
55
56    if (argc <= optind) {
57        fprintf(stderr, "Usage: %s [-m eventmask] [-c count] [-p] [-v verbosity] path [path ...]\n", argv[0]);
58		return 1;
59    }
60
61    nfd = inotify_init();
62    if(nfd < 0) {
63        fprintf(stderr, "inotify_init failed, %s\n", strerror(errno));
64        return 1;
65    }
66	file_names = argv + optind;
67	file_count = argc - optind;
68	for(i = 0; i < file_count; i++) {
69		res = inotify_add_watch(nfd, file_names[i], event_mask);
70		if(res < 0) {
71	        fprintf(stderr, "inotify_add_watch failed for %s, %s\n", file_names[i], strerror(errno));
72			return 1;
73		}
74		if(i == 0)
75			id_offset = -res;
76		if(res + id_offset != i) {
77			fprintf(stderr, "%s got unexpected id %d instead of %d\n", file_names[i], res, i);
78			return 1;
79		}
80	}
81
82	buf = malloc(width + 2);
83
84    while(1) {
85		int event_pos = 0;
86        res = read(nfd, event_buf, sizeof(event_buf));
87        if(res < (int)sizeof(*event)) {
88			if(errno == EINTR)
89				continue;
90            fprintf(stderr, "could not get event, %s\n", strerror(errno));
91            return 1;
92        }
93		//printf("got %d bytes of event information\n", res);
94		while(res >= (int)sizeof(*event)) {
95			int event_size;
96			event = (struct inotify_event *)(event_buf + event_pos);
97			if(verbose >= 2)
98		        printf("%s: %08x %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->cookie, event->len ? event->name : "");
99			else if(verbose >= 2)
100		        printf("%s: %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->len ? event->name : "");
101			else if(verbose >= 1)
102		        printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
103			if(print_files && (event->mask & IN_MODIFY)) {
104				char filename[512];
105				ssize_t read_len;
106				char *display_name;
107				int buflen;
108				strcpy(filename, file_names[event->wd + id_offset]);
109				if(event->len) {
110					strcat(filename, "/");
111					strcat(filename, event->name);
112				}
113				ffd = open(filename, O_RDONLY);
114				display_name = (verbose >= 2 || event->len == 0) ? filename : event->name;
115				buflen = width - strlen(display_name);
116				read_len = read(ffd, buf, buflen);
117				if(read_len > 0) {
118					if(read_len < buflen && buf[read_len-1] != '\n') {
119						buf[read_len] = '\n';
120						read_len++;
121					}
122					if(read_len == buflen) {
123						buf[--read_len] = '\0';
124						buf[--read_len] = '\n';
125						buf[--read_len] = '.';
126						buf[--read_len] = '.';
127						buf[--read_len] = '.';
128					}
129					else {
130						buf[read_len] = '\0';
131					}
132					printf("%s: %s", display_name, buf);
133				}
134				close(ffd);
135			}
136	        if(event_count && --event_count == 0)
137	            return 0;
138			event_size = sizeof(*event) + event->len;
139			res -= event_size;
140			event_pos += event_size;
141		}
142    }
143
144    return 0;
145}
146