summaryrefslogtreecommitdiff
path: root/common/inotify_helpers.c
blob: a875b8ce4e50f377883f6f476d73bfa6c5d6e12b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <string.h> /* for strlen(3), memcpy(3) */
#include <stdio.h> /* for printf(3) */
#include <stdlib.h> /* for realloc(3) */
#include <unistd.h> /* for read(2) */
#include "inotify_helpers.h"



struct strbuf {
	char *str; 
	size_t len;
	size_t cap;
};

static
void
strbufcat(struct strbuf *a, const char *b) {
	size_t blen = strlen(b);
	while (a->cap <= (a->len + blen)) {
		a->cap += 256;
		a->str = realloc(a->str, a->cap);
	}
	memcpy(&(a->str[a->len]), b, blen+1);
	a->len += blen;
}



static
const char *in_mask_bits[] = {
	/* main */
	"IN_ACCESS",		// 0
	"IN_MODIFY",		// 1
	"IN_ATTRIB",		// 2
	"IN_CLOSE_WRITE",	// 3
	"IN_CLOSE_NOWRITE",	// 4
	"IN_OPEN",		// 5
	"IN_MOVED_FROM",	// 6
	"IN_MOVED_TO",		// 7
	"IN_CREATE",		// 8
	"IN_DELETE",		// 9
	"IN_DELETE_SELF",	// 10
	"IN_MOVE_SELF", 	// 11
	/* gap */
	"<invalid-12>", 	// 12
	/* events sent by the kernel */
	"IN_UNMOUNT",		// 13
	"IN_Q_OVERFLOW",	// 14
	"IN_IGNORED",		// 15
	/* gap */
	"<invalid-16>", 	// 16
	"<invalid-17>", 	// 17
	"<invalid-18>", 	// 18
	"<invalid-19>", 	// 19
	"<invalid-20>", 	// 20
	"<invalid-21>", 	// 21
	"<invalid-22>", 	// 22
	"<invalid-23>", 	// 23
	/* special flags */
	"IN_ONLYDIR",		// 24
	"IN_DONT_FOLLOW",	// 25
	"IN_EXCL_UNLINK",	// 26
	"<invalid-27>", 	// 27
	"<invalid-28>", 	// 28
	"IN_MASK_ADD",		// 29
	"IN_ISDIR",		// 30
	"IN_ONESHOT",		// 31
};

char *
inotify_mask2str(uint32_t mask) {
	struct strbuf out = { 0 };
	for (size_t i = 0;
	     i < sizeof(in_mask_bits)/sizeof(in_mask_bits[0]);
	     i++) {
		if (mask & (1 << i)) {
			if (out.len > 0)
				strbufcat(&out, " | ");
			strbufcat(&out, in_mask_bits[i]);
		}
	}
	return out.str;
}



int
inotify_print_event(struct inotify_event *event) {
	char *mask = inotify_mask2str(event->mask);
	int ret = printf("{\t.wd=%d;\n"
	                 "\t.mask=%s;\n"
	                 "\t.cookie=%u;\n"
	                 "\t.len=%u;\n"
	                 "\t.name=\"%s\"; }\n",
	                 event->wd,
	                 mask,
	                 event->cookie,
	                 event->len,
	                 event->len > 0 ? event->name : "");
	free(mask);
	return ret;
}



#define	EVENT_PTR(BUF)	((struct inotify_event *)&((BUF)->dat[(BUF)->pos]))
#define	EVENT_SIZE(BUF)	(sizeof(struct inotify_event) + EVENT_PTR(BUF)->len)

struct inotify_event *
inotify_next_event_r(int fd, struct inotify_buffer *buf) {
	if (((ssize_t)(buf->len - buf->pos - sizeof(struct inotify_event)) > 0)
	 && ((ssize_t)(buf->len - buf->pos - EVENT_SIZE(buf))              > 0)) {
		buf->pos += EVENT_SIZE(buf);
	} else {
		do {
			buf->len = read(fd, buf->dat, sizeof(buf->dat));
		} while (buf->len == 0);
		buf->pos = 0;
		if (buf->len < 0) {
			return NULL;
		}
	}
	return EVENT_PTR(buf);
}

struct inotify_event *
inotify_next_event(int fd) {
	static struct inotify_buffer buf = { 0 };
	return inotify_next_event_r(fd, &buf);
}