entangler 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/entangler.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'entangler/version'
2
+ require 'entangler/entangled_file'
3
+
4
+ module Entangler
5
+ class << self
6
+ attr_accessor :executor
7
+
8
+ def run(base_dir, opts = {})
9
+ opts = {mode: 'master'}.merge(opts)
10
+
11
+ require 'entangler/executor/base'
12
+ if opts[:mode] == 'master'
13
+ require 'entangler/executor/master'
14
+ self.executor = Entangler::Executor::Master.new(base_dir, opts)
15
+ elsif opts[:mode] == 'slave'
16
+ require 'entangler/executor/slave'
17
+ self.executor = Entangler::Executor::Slave.new(base_dir, opts)
18
+ end
19
+
20
+ self.executor.run
21
+ end
22
+ end
23
+ end
Binary file
Binary file
@@ -0,0 +1,7 @@
1
+ To compile notify.c, run
2
+
3
+ clang -framework CoreFoundation -framework CoreServices -o notify notify.c
4
+
5
+ or (if you don't have clang)
6
+
7
+ gcc -framework CoreFoundation -framework CoreServices -o notify notify.c
@@ -0,0 +1,12 @@
1
+ The notify utility continiously prints changes in a specified directory in the following format:
2
+
3
+ M changed/path/1
4
+ M changed/path/2
5
+ -
6
+
7
+
8
+ Where M stands for "Modifed", and "-" is the indicator of end of changeset
9
+
10
+ Utility only returns specific directories that have changed, it does not print
11
+ the files/directories that have been modified: you need to determine them
12
+ yourself
@@ -0,0 +1,63 @@
1
+ #include <CoreServices/CoreServices.h>
2
+ #include <CoreFoundation/CoreFoundation.h>
3
+ #include <sys/stat.h>
4
+
5
+ static void printChangesFunc(ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents, void *eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) {
6
+ char **paths = eventPaths;
7
+ int i;
8
+ for (i = 0; i < numEvents; i++) {
9
+ printf("M %s\n", paths[i]);
10
+ }
11
+ printf("-\n");
12
+ fflush(stdout);
13
+ }
14
+
15
+ void initFSEvents(const char *path) {
16
+
17
+ /* Define variables and create a CFArray object containing
18
+ CFString objects containing paths to watch.
19
+ */
20
+
21
+ CFStringRef mypath = CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8);
22
+ CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL);
23
+ void *callbackInfo = NULL; // could put stream-specific data here.
24
+ FSEventStreamRef stream;
25
+ CFAbsoluteTime latency = 0.1; /* Latency in seconds */
26
+
27
+ /* Create the stream, passing in a callback */
28
+ stream = FSEventStreamCreate(NULL,
29
+ &printChangesFunc,
30
+ callbackInfo,
31
+ pathsToWatch,
32
+ kFSEventStreamEventIdSinceNow, /* Or a previous event ID */
33
+ latency,
34
+ kFSEventStreamCreateFlagNone /* Flags explained in reference */
35
+ );
36
+
37
+ CFRelease(pathsToWatch);
38
+ CFRelease(mypath);
39
+
40
+ /* Create the stream before calling this. */
41
+ FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
42
+ FSEventStreamStart(stream);
43
+ }
44
+
45
+ int main (int argc, const char * argv[]) {
46
+
47
+ if(argc != 2) {
48
+ printf("Usage: %s <path>\n", argv[0]);
49
+ return 1;
50
+ }
51
+
52
+ struct stat tmp;
53
+
54
+ if(stat(argv[1], &tmp) != 0) {
55
+ perror("Invalid path");
56
+ return 2;
57
+ }
58
+
59
+ initFSEvents(argv[1]);
60
+ CFRunLoopRun();
61
+
62
+ return 0;
63
+ }
@@ -0,0 +1,4 @@
1
+ notify.c was built using dietlibc to be as small as possible (using "bin-i386/diet gcc -static -o notify notify.c").
2
+ If you want to compile it without dietlibc, you can just do
3
+
4
+ gcc -o notify notify.c
@@ -0,0 +1,18 @@
1
+ The notify utility continiously prints changes in a specified directory in the following format:
2
+
3
+ M changed/path/1
4
+ M changed/path/2
5
+ -
6
+
7
+ Where M stands for "Modifed", and "-" is the indicator of end of changeset
8
+
9
+ Utility only returns specific directories that have changed, it does not print
10
+ the files/directories that have been modified: you need to determine them
11
+ yourself.
12
+
13
+ Linux-specific notes:
14
+
15
+ 1. You might need to adjust '/proc/sys/fs/inotify/max_user_watches' to allow more directories to be watched
16
+ 2. If you have a lot of changes you might also want to increase queue size in /proc/sys/fs/inotify/max_queued_events
17
+ 3. Watched queue can overflow and notify utility can run out of watched directories.
18
+ When you get exit code 3, you need to restart the daemon and re-process all directories you are interested in.
@@ -0,0 +1,296 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <sys/types.h>
4
+ #include <sys/stat.h>
5
+ #include <sys/inotify.h>
6
+ #include <unistd.h>
7
+ #include <dirent.h>
8
+ #include <errno.h>
9
+ #include <stdlib.h>
10
+ #include <fcntl.h>
11
+ #include <sys/ioctl.h>
12
+
13
+ /* gcc should be able to optimize strlen() for constant strings */
14
+ #define PRINT(str) write(1, str, strlen(str))
15
+ #define ERROR(str) write(2, str, strlen(str))
16
+
17
+ #define EVENT_MASK (IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MODIFY|IN_MOVE_SELF\
18
+ |IN_MOVED_FROM|IN_MOVED_TO|IN_DONT_FOLLOW|IN_ONLYDIR|IN_ATTRIB)
19
+
20
+ #ifdef DEBUG
21
+ #define DEBUG_PRINT printf
22
+ #else
23
+ #define DEBUG_PRINT(...) /* printf actually adds about 7k to binary size :) */
24
+ #endif
25
+
26
+ typedef struct {
27
+ int wd;
28
+ int parent_wd;
29
+ char *name;
30
+ } _watchstruct;
31
+
32
+ char events_buf[PATH_MAX + sizeof(struct inotify_event) + 1];
33
+ static _watchstruct *watches;
34
+ int ifd = 0, max_watches;
35
+ char *watch_dir;
36
+
37
+ /* make directory path for watch descriptor (recursively) */
38
+ static void wd_path(int wd, char *path)
39
+ {
40
+ if (wd == 0) {
41
+ strcpy(path, watch_dir);
42
+ strcat(path, "/");
43
+ return;
44
+ }
45
+
46
+ if (wd < 0 || !watches[wd].name) {
47
+ DEBUG_PRINT("Recusive %d, %x\n", wd, watches[wd].name);
48
+ ERROR("Memory corrupted: asked path of deleted event\n");
49
+ exit(1);
50
+ }
51
+
52
+ wd_path(watches[wd].parent_wd, path);
53
+ if (watches[wd].name[0] == 0) return;
54
+
55
+ strcat(path, watches[wd].name);
56
+ strcat(path, "/");
57
+ }
58
+
59
+ static int add_dir_watch(int parent_wd, char *dir, char *dir_name, int no_print)
60
+ {
61
+ int wd = inotify_add_watch(ifd, dir, EVENT_MASK);
62
+ if (wd < 0) {
63
+ ERROR("Cannot add watch to '");
64
+ ERROR(dir);
65
+ ERROR("' using inotify: ");
66
+ if (errno == ENOSPC) {
67
+ ERROR("too many watches\nYou can increase number of user watches using /proc/sys/fs/inotify/max_user_watches");
68
+ } else {
69
+ ERROR(strerror(errno));
70
+ }
71
+ ERROR("\n");
72
+ if (errno != EACCES && errno != ENOENT) exit(1);
73
+ return wd;
74
+ }
75
+
76
+ if (wd >= max_watches) {
77
+ ERROR("\nToo many events; restart required to prevent watch descriptor overflow.\n");
78
+ exit(3);
79
+ }
80
+
81
+ dir_name = strdup(dir_name);
82
+ if (!dir_name) {
83
+ ERROR("Cannot strdup(dir_name)\n");
84
+ exit(1);
85
+ }
86
+
87
+ watches[wd].wd = wd;
88
+ watches[wd].parent_wd = parent_wd;
89
+ if (watches[wd].name) free(watches[wd].name);
90
+ watches[wd].name = dir_name;
91
+
92
+ if (!no_print) {
93
+ PRINT("M ");
94
+ PRINT(dir);
95
+ PRINT("\n");
96
+ }
97
+
98
+ return wd;
99
+ }
100
+
101
+ static void add_dir(int dir_wd, char *dir, int errors_fatal, int no_print)
102
+ {
103
+ char path[PATH_MAX + 1];
104
+ DIR *dh = opendir(dir);
105
+ struct dirent *ent;
106
+ struct stat st;
107
+ int dirl = strlen(dir), n = sizeof(path) - 1 - dirl, had_errors = 0, wd;
108
+
109
+ if (dirl > sizeof(path) - 3) {
110
+ ERROR("Too long path (not watched): ");
111
+ ERROR(dir);
112
+ ERROR("\n");
113
+
114
+ if (errors_fatal) exit(1);
115
+ return;
116
+ }
117
+
118
+ if (!dh) {
119
+ ERROR("Cannot opendir(");
120
+ ERROR(dir);
121
+ ERROR("): ");
122
+ ERROR(strerror(errno));
123
+ ERROR("\n");
124
+
125
+ if (errors_fatal) exit(1);
126
+ return;
127
+ }
128
+
129
+ strcpy(path, dir);
130
+
131
+ while ((ent = readdir(dh)) != NULL) {
132
+ if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, ".unrealsync")) continue;
133
+
134
+ path[dirl] = '/';
135
+ path[dirl + 1] = 0;
136
+ strncat(path + dirl, ent->d_name, n);
137
+ path[sizeof(path) - 1] = 0;
138
+ if (lstat(path, &st)) {
139
+ ERROR("Cannot lstat(");
140
+ ERROR(path);
141
+ ERROR("): ");
142
+ ERROR(strerror(errno));
143
+ ERROR("\n");
144
+ had_errors = 1;
145
+ continue;
146
+ }
147
+
148
+ if (S_ISDIR(st.st_mode)) {
149
+ wd = add_dir_watch(dir_wd, path, ent->d_name, no_print);
150
+ if (wd < 0) continue;
151
+ add_dir(wd, path, errors_fatal, no_print);
152
+ }
153
+ }
154
+
155
+ closedir(dh);
156
+
157
+ if (errors_fatal && had_errors) exit(1);
158
+ }
159
+
160
+ void debug_print_mask(uint32_t mask)
161
+ {
162
+ if (mask & IN_DELETE_SELF) DEBUG_PRINT("IN_DELETE_SELF ");
163
+ if (mask & IN_MOVE_SELF) DEBUG_PRINT("IN_MOVE_SELF ");
164
+ if (mask & IN_MOVED_FROM) DEBUG_PRINT("IN_MOVED_FROM ");
165
+ if (mask & IN_MOVED_TO) DEBUG_PRINT("IN_MOVED_TO ");
166
+ if (mask & IN_CLOSE_WRITE) DEBUG_PRINT("IN_CLOSE_WRITE ");
167
+ if (mask & IN_MODIFY) DEBUG_PRINT("IN_MODIFY ");
168
+ if (mask & IN_IGNORED) DEBUG_PRINT("IN_IGNORED ");
169
+ if (mask & IN_ISDIR) DEBUG_PRINT("IN_ISDIR ");
170
+ if (mask & IN_Q_OVERFLOW) DEBUG_PRINT("IN_Q_OVERFLOW ");
171
+ if (mask & IN_UNMOUNT) DEBUG_PRINT("IN_UNMOUNT ");
172
+ if (mask & IN_CREATE) DEBUG_PRINT("IN_CREATE ");
173
+ }
174
+
175
+ static int do_watch(int max_watches)
176
+ {
177
+ struct inotify_event *ev = (struct inotify_event*)events_buf;
178
+ ssize_t n = 0, wd;
179
+ char path[PATH_MAX + 1];
180
+
181
+ watches = (_watchstruct*) calloc(max_watches, sizeof(_watchstruct));
182
+ if (!watches) {
183
+ ERROR("Cannot allocate memory\n");
184
+ exit(1);
185
+ }
186
+
187
+ DEBUG_PRINT("Doing initial watches setup\n");
188
+
189
+ ifd = inotify_init();
190
+ if (ifd == -1) {
191
+ perror("Cannot init inotify");
192
+ exit(1);
193
+ }
194
+
195
+ wd = add_dir_watch(0, watch_dir, "", 1);
196
+ if (wd < 0) {
197
+ ERROR("Cannot add dir watch\n");
198
+ exit(1);
199
+ }
200
+ add_dir(wd, watch_dir, 1, 1);
201
+
202
+ while ((n = read(ifd, events_buf, sizeof(events_buf))) > 0) {
203
+ ev = (struct inotify_event*)events_buf;
204
+ while (n > 0) {
205
+ if (ev->mask & IN_Q_OVERFLOW) {
206
+ ERROR("Queue overflow, restart needed\n");
207
+ exit(3);
208
+ }
209
+
210
+ if (ev->mask & IN_IGNORED) {
211
+ free(watches[ev->wd].name);
212
+ watches[ev->wd].parent_wd = -1;
213
+ watches[ev->wd].name = NULL;
214
+ goto loop_end;
215
+ }
216
+
217
+ wd_path(ev->wd, path);
218
+ PRINT("M ");
219
+ PRINT(path);
220
+ PRINT("\n");
221
+ #ifdef DEBUG
222
+ if (ev->len) {
223
+ DEBUG_PRINT(" | ");
224
+ DEBUG_PRINT("%s", ev->name);
225
+ }
226
+ DEBUG_PRINT(" | ");
227
+ debug_print_mask(ev->mask);
228
+ #endif
229
+
230
+ if ((ev->mask & IN_DELETE) || (ev->mask & IN_MOVED_FROM)) {
231
+ goto loop_end;
232
+ }
233
+
234
+ if (ev->mask & IN_ISDIR) {
235
+ if (ev->len + strlen(path) > sizeof(path) - 1) {
236
+ ERROR("Too deep directory: ");
237
+ ERROR(path);
238
+ ERROR(ev->name);
239
+ ERROR("\n");
240
+ goto loop_end;
241
+ }
242
+ strcat(path, ev->name);
243
+ wd = add_dir_watch(ev->wd, path, ev->name, 0);
244
+ if (wd < 0) goto loop_end;
245
+ add_dir(ev->wd, path, 0, 0);
246
+ }
247
+
248
+ loop_end:
249
+ n -= sizeof(struct inotify_event) + ev->len;
250
+ ev = (struct inotify_event*) ((char*)ev + sizeof(struct inotify_event) + ev->len);
251
+ }
252
+
253
+ PRINT("-\n");
254
+ }
255
+
256
+ perror("Cannot read() inotify queue");
257
+ exit(1);
258
+ }
259
+
260
+ int main(int argc, char *argv[])
261
+ {
262
+ int fd, n;
263
+ char buf[12];
264
+
265
+ if (argc != 2) {
266
+ ERROR("Usage: notify <dir>\n");
267
+ return 1;
268
+ }
269
+
270
+ fd = open("/proc/sys/fs/inotify/max_user_watches", O_RDONLY);
271
+ if (fd < 0) {
272
+ perror("Cannot open /proc/sys/fs/inotify/max_user_watches");
273
+ return 1;
274
+ }
275
+
276
+ if ( (n = read(fd, buf, sizeof(buf) - 1)) < 0) {
277
+ perror("Cannot read() /proc/sys/fs/inotify/max_user_watches");
278
+ return 1;
279
+ }
280
+
281
+ buf[n] = 0;
282
+ max_watches = atoi(buf) * 2;
283
+ if (max_watches <= 0) {
284
+ ERROR("Incorrect number of watches: ");
285
+ ERROR(buf);
286
+ ERROR("\n");
287
+ return 1;
288
+ } else {
289
+ DEBUG_PRINT("Max watches: %d\n", max_watches);
290
+ }
291
+
292
+ watch_dir = argv[1];
293
+ do_watch(max_watches);
294
+
295
+ return 0;
296
+ }
@@ -0,0 +1,11 @@
1
+ The utility has been built using the following command under Ubuntu Linux 11.10 32-bit:
2
+
3
+ g++ -static -s -I. *.cpp /usr/lib/libpopt.a -o notify
4
+
5
+ Or, to achieve the minimal size of the binary:
6
+
7
+ g++ -static -s -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -I. *.cpp /usr/lib/libpopt.a -o notify
8
+
9
+ You might need to change path to libpopt to whatever location it is on your system.
10
+ Libpopt is the only dependency aside from g++ if you want to build the utility.
11
+ It comes pre-built statically with realsync, so it will most probably just work
@@ -0,0 +1,14 @@
1
+ This is a daemon that notifies about filesystem changes in the following form:
2
+
3
+ M /path/to/changed/file
4
+ M /path/to/other/changed/file
5
+ -
6
+
7
+ The daemon is based on kfsmd-0.3.3 and tuned a little bit to be more realtime
8
+ The original kfsmd-0.3.3 could be found at http://sourceforge.net/projects/witme/files/kfsmd/
9
+ The preferred way to use this daemon is to run the following:
10
+
11
+ ./notify watch /path/to/watch | uniq
12
+
13
+ You can get rid of "| uniq", but in this case you will get multiple lines per each file
14
+ for each type of event (e.g. OPEN/WRITE/CLOSE)
@@ -0,0 +1,165 @@
1
+ /******************************************************************************
2
+ *******************************************************************************
3
+ *******************************************************************************
4
+
5
+
6
+ kernel-filesystem-monitor-daemon-cat
7
+ Copyright (C) 2005 Ben Martin
8
+
9
+ This program is free software; you can redistribute it and/or modify
10
+ it under the terms of the GNU General Public License as published by
11
+ the Free Software Foundation; either version 2 of the License, or
12
+ (at your option) any later version.
13
+
14
+ This program is distributed in the hope that it will be useful,
15
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ GNU General Public License for more details.
18
+
19
+ You should have received a copy of the GNU General Public License
20
+ along with this program; if not, write to the Free Software
21
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
+
23
+ For more details see the COPYING file in the root directory of this
24
+ distribution.
25
+
26
+ $Id: kernel-filesystem-monitor-daemon-cat.cpp,v 1.3 2008/05/25 21:30:52 ben Exp $
27
+
28
+ *******************************************************************************
29
+ *******************************************************************************
30
+ ******************************************************************************/
31
+
32
+ #include <iostream>
33
+ #include "kernel-filesystem-monitor-daemon.hh"
34
+ #include <stdlib.h>
35
+
36
+ using namespace std;
37
+
38
+
39
+ const char* PROGRAM_NAME = "kernel-filesystem-monitor-cat";
40
+
41
+ void usage(poptContext optCon, int exitcode, char *error, char *addl)
42
+ {
43
+ poptPrintUsage(optCon, stderr, 0);
44
+ if (error) fprintf(stderr, "%s: %s0", error, addl);
45
+ exit(exitcode);
46
+ }
47
+
48
+ /********************************************************************************/
49
+ /********************************************************************************/
50
+ /********************************************************************************/
51
+ /********************************************************************************/
52
+ /********************************************************************************/
53
+ /********************************************************************************/
54
+
55
+
56
+
57
+ class KernelFileSystemMonitorDaemonCat
58
+ :
59
+ public KernelFileSystemMonitorDaemon
60
+ {
61
+ protected:
62
+
63
+ virtual void handle_event( struct inotify_event *pevent, time_t tt );
64
+ virtual void Closedown();
65
+ virtual void setupWorkingDirToPersistentDirIDMapping( long wd, const string& earl );
66
+
67
+ void
68
+ event_batch_start( time_t tt )
69
+ {}
70
+
71
+ void
72
+ event_batch_end( time_t tt )
73
+ {}
74
+
75
+
76
+ public:
77
+
78
+ string homedir;
79
+
80
+ KernelFileSystemMonitorDaemonCat()
81
+ {}
82
+ };
83
+
84
+
85
+ void
86
+ KernelFileSystemMonitorDaemonCat::setupWorkingDirToPersistentDirIDMapping(
87
+ long wd, const string& earl )
88
+ {
89
+ }
90
+
91
+ void
92
+ KernelFileSystemMonitorDaemonCat::handle_event( struct inotify_event *pevent, time_t tt )
93
+ {
94
+ print_event( pevent );
95
+ fflush(stdout);
96
+ }
97
+
98
+
99
+
100
+ void
101
+ KernelFileSystemMonitorDaemonCat::Closedown()
102
+ {
103
+ }
104
+
105
+ int main( int argc, char** argv )
106
+ {
107
+ unsigned long RunInForground = 0;
108
+ const char* homedir_CSTR = 0;
109
+
110
+ KernelFileSystemMonitorDaemonCat* daemon
111
+ = new KernelFileSystemMonitorDaemonCat();
112
+
113
+ struct poptOption optionsTable[] =
114
+ {
115
+ { "forground", 'F', POPT_ARG_NONE, &RunInForground, 0,
116
+ "Don't run the daemon in the background", "" },
117
+
118
+ { "homedir", 'H', POPT_ARG_STRING, &homedir_CSTR, 0,
119
+ "Home directory for user doing the monitoring", "" },
120
+
121
+ { 0, 0, POPT_ARG_INCLUDE_TABLE, daemon->getPopTable(), \
122
+ 0, "generic kfsmd daemon options:", 0 },
123
+
124
+ { "verbose", 'v', POPT_ARG_NONE, &Verbose, 0,
125
+ "output more info", "" },
126
+
127
+
128
+ POPT_AUTOHELP
129
+ POPT_TABLEEND
130
+ };
131
+ poptContext optCon;
132
+
133
+ optCon = poptGetContext(PROGRAM_NAME, argc, (const char**)argv, optionsTable, 0);
134
+ poptSetOtherOptionHelp(optCon, "[OPTIONS]* [IGNOREPFX URL]* [WATCH URL]+ ...");
135
+
136
+
137
+ /* Now do options processing */
138
+ char c=-1;
139
+ while ((c = poptGetNextOpt(optCon)) >= 0)
140
+ {
141
+ }
142
+
143
+ daemon->ParseWatchOptions( optCon );
144
+ daemon->setRunInForground( true );
145
+ daemon->setupSignalHandlers();
146
+
147
+ daemon->homedir = getHomeDir( homedir_CSTR );
148
+
149
+ try
150
+ {
151
+ if( Verbose )
152
+ cerr << "setting up watches" << endl;
153
+ daemon->setupWatches();
154
+ if( Verbose )
155
+ cerr << "calling run" << endl;
156
+ return daemon->run();
157
+ }
158
+ catch( exception& e )
159
+ {
160
+ cerr << "Exiting due to error reason:" << e.what() << endl;
161
+ }
162
+
163
+ return 0;
164
+ }
165
+