-
Notifications
You must be signed in to change notification settings - Fork 0
/
orthos.c
364 lines (327 loc) · 9.98 KB
/
orthos.c
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
/*******************************************************************************
* $Id$
*******************************************************************************
* Orthos
* A daemon to watch several files, alerting when they are modified without
* prior authorization.
*
*******************************************************************************
* Copyright 2014 Danny Sauer
*
* 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.
*
*/
#include "orthos.h"
int main(int argc, char* ARGV[], char* ENV[]){
int i=0, e=0;
int len=0;
int handle;
char* fail_to_watch = "Failed to watch";
char msg[NAME_MAX + sizeof(fail_to_watch) + 4]; /* null, space & 2 quotes */
char buffer[EVENT_BUF_LEN];
struct stat s;
struct inotify_event* event;
struct avl_tree* dirs;
if( argc < 2 ){
printf( "Usage: %s file [file2 .. fileN]\n", ARGV[0] );
return 1;
}
if( -1 == (handle = inotify_init()) ){
e = errno;
perror( "Failed to initialize inotify");
return e;
}
/* new tree which will use event_cmp to compare */
if( NULL == (dirs = avl_create(event_cmp)) ){
e = errno;
perror( "Failed to initialize inotify");
return e;
}
struct event_map* a = malloc(sizeof(struct event_map*));
a->wd = 1;
struct event_map* b = malloc(sizeof(struct event_map*));
b->wd = 2;
struct event_map* c = malloc(sizeof(struct event_map*));
c->wd = 3;
struct event_map* d = malloc(sizeof(struct event_map*));
d->wd = 4;
avl_insert(dirs, a);
avl_insert(dirs, c);
avl_insert(dirs, b);
avl_insert(dirs, d);
return 0;
/*
* add watches
*/
for( i=1; i<argc; i++ ){
// Verify that this is something we can watch
if( -1 == lstat( ARGV[i], &s ) ){
e = errno;
snprintf( msg, sizeof(msg), "%s '%s'", fail_to_watch, ARGV[i] );
perror( msg );
// return e;
continue;
}
if( ! S_ISDIR(s.st_mode) ){
errno = ENOTDIR;
e = errno;
snprintf( msg, sizeof(msg), "%s '%s'", fail_to_watch, ARGV[i] );
perror( msg );
// return 1;
continue;
}
/* DEBUG */
printf("Monitoring '%s'\n", ARGV[i]);
if( -1 == inotify_add_watch( handle, ARGV[i], IN_ALL_EVENTS ) ){
e = errno;
snprintf( msg, sizeof(msg), "%s '%s'", fail_to_watch, ARGV[i] );
perror( msg );
// return e;
}
}
/*
* actual monitoring
*/
if( -1 == (len = read( handle, buffer, EVENT_BUF_LEN )) ){
e = errno;
perror( "Failed to read from inotify handle" );
return e;
}
i = 0;
while( i < len ){
event = ( struct inotify_event* ) &buffer[ i ];
printf( "Event detected on %s\n", event->name );
i += EVENT_SIZE + event->len;
}
return 0;
}
signed int event_cmp(
const struct event_map* const a,
const struct event_map* const b
){
if( a == NULL && b == NULL ){
return 0;
}
if( a == NULL ){
return -1;
}
if( b == NULL ){
return 1;
}
if( a->wd > b->wd ){
return 1;
}
if( a->wd < b->wd ){
return -1;
}
return 0;
}
/*
* We need to store the "file descriptor to directory name" mappings in some
* kind of structure. In general, we'll expect to be looking up mappings more
* often than we'll be creating new ones, so we can afford a minor trade-offs
* in insertion speed compared to retreival speed. We want to be somewhat
* memory-efficient, though, so just allocating an array to hold all possible
* integers is not a great idea. :) I think that a balanced binary search tree
* (an "AVL tree") makes for a good solution here. So, here's an
* implementation. There's some good documentation on how AVL trees work
* located at http://adtinfo.org/libavl.html/AVL-Trees.html
*
* The data stored is an event_map struct, which contains an integer watch
* descriptor. So, we'll use that as the sorted key.
*/
/*
* rebalancing includes updating the balance fator of a node. The balance
* factor is the height of the right tree minus the height of the left tree.
* So, the factor is negative if the left is taller, positive if the right is
* taller, and 0 if they're equal.
*/
/*
* create a new avl tree
*/
struct avl_tree* avl_create( signed int (*cmp)(const void*, const void*) ) {
struct avl_tree* tree;
if( NULL == (tree = malloc( sizeof(*tree) )) ){
return NULL;
}
/* init tree */
tree->root = NULL;
tree->compare = cmp;
return tree;
}
/*
* return the data field from a tree node
*/
void * avl_lookup(
const struct avl_tree* const tree,
const void* const data
){
struct avl_tree_node* n;
int cmp;
//assert( tree != NULL && data != NULL );
if( tree == NULL || data == NULL ){
errno = EINVAL;
return NULL;
}
for( n = tree->root; n != NULL; ){
cmp = tree->compare( data, n->data);
if( cmp > 0 ){
n = n->right;
}
else if( cmp < 0 ){
n = n->left;
}
else{
return n->data;
}
}
/* not found */
return NULL;
}
void* avl_insert(
struct avl_tree* tree,
void* data // this may actually end up changed; we store a pointer
){
int cmp;
struct avl_tree_node* n; /* current node */
struct avl_tree_node* np; /* node's parent */
//struct avl_tree_node* z; /* last non-zero node */
//struct avl_tree_node* zp; /* last non-zero node's parent */
struct avl_tree_node* newnode;
/* track path we took to the insertion so we can adjust balance */
/* using a linked list because arrays are limiting */
/* I might use all of your memory! All of it! Bwa hah ha ha ha! */
struct path_element {
struct path_element *previous;
struct avl_tree_node *parent_node;
struct avl_tree_node *node;
int direction;
};
struct path_element* path;
struct path_element* p;
/* sanity check */
if( tree == NULL || data == NULL ){
/* explode! */
return NULL;
}
/* init variables */
cmp = 0;
n = tree->root;
np = n;
//z = n; /* should z / zp start at NULL instead? */
//zp = NULL;
p = NULL;
path = p;
/* find insertion point */
while( n != NULL ){
cmp = tree->compare( data, n->data );
// if they match, then we're done
if( cmp == 0 ){
return n->data;
}
/*
if( n->balance != 0 ){
z = n;
zp = np;
}
*/
// Add a new component to the path
p = malloc(sizeof(*p));
p->previous = path;
p->direction = cmp;
p->parent_node = np;
p->node = n;
/* I got to "node" from "parent_node" in direction "cmp" */
path = p;
printf( "Moving %i\n", cmp);
// On to the next node!
np = n;
n = (cmp < 0 ) ? n->left : n->right;
}
/* create and insert node */
if( NULL == (newnode = malloc(sizeof( *newnode ))) ){
/* free temporary linked list */
p = path;
while( NULL != p ){
free(path);
p = p->previous;
}
// maybe set errno? It's probably already set.
return NULL;
}
newnode->data = data;
newnode->left = NULL;
newnode->right = NULL;
newnode->balance = 0;
if( np == NULL ){
/* we never entered the loop and the tree is empty */
tree->root = newnode;
}
else if( cmp < 0 ){
np->left = newnode;
}
else{
np->right = newnode;
}
struct event_map *d = (struct event_map*)data;
printf("data: '%i' (wd=%i)\n", (int)data, d->wd);
printf("new pointer: '%i'\n", (int)(newnode->data));
printf("root pointer: '%i'\n", (int)(tree->root->data));
if( path == NULL ){
/* we never entered the loop, but the tree is not empty */
/* also, no need to free temporary linked list */
return newnode->data;
}
/* add final node to path structure, to make the loop easier */
/* do I really need to do this? */
p = malloc(sizeof(*p));
p->previous = path;
p->direction = cmp;
p->parent_node = np;
p->node = newnode;
path = p;
/* update balance factor */
p = path;
while( NULL != p->previous ){ // path never includes the root node
// direction will be -1 or +1
p->parent_node->balance += p->direction;
/* if parent went to 0, then we're done climbing
* if parent went to -2 or +2, then we need to rotate
* if parent went to -1 or +1, then we keep propagating
*/
//struct event_map* d = (struct event_map*)p->parent_node->data;
d = (struct event_map*)p->parent_node->data;
printf("node parent (%i) balance changed to %i\n",
d->wd,
p->parent_node->balance);
if( 0 == p->parent_node->balance ){
break;
}
else if( p->parent_node->balance < -1
|| p->parent_node->balance > 1
){
// rotate parent node
// break;
}
p = p->previous;
}
/* rebalance */
/* We have a linked list that needs free'd */
p = path;
while( NULL != p ){
free(path);
p = p->previous;
}
printf("Ok!\n");
}
/* end orthos.c */