entangler 0.4.1 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,727 +0,0 @@
1
- /******************************************************************************
2
- *******************************************************************************
3
- *******************************************************************************
4
-
5
-
6
- kernel-filesystem-monitor-daemon
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.cpp,v 1.4 2008/05/25 21:30:52 ben Exp $
27
-
28
- *******************************************************************************
29
- *******************************************************************************
30
- ******************************************************************************/
31
-
32
- #include <sys/types.h>
33
- #include <unistd.h>
34
- #include <sys/stat.h>
35
- #include <fcntl.h>
36
- #include <sys/ioctl.h>
37
- #include <dirent.h>
38
- #include <sys/poll.h>
39
- #include <signal.h>
40
- #include <string.h>
41
- #include <errno.h>
42
- #include <syslog.h>
43
- #include <stdlib.h>
44
- #include <limits.h>
45
-
46
- #include <sys/inotify.h>
47
- //#include "inotify-syscalls.h"
48
-
49
- #include <iostream>
50
- #include <sstream>
51
-
52
- #include <kernel-filesystem-monitor-daemon.hh>
53
-
54
- static bool WantToQuit = false;
55
- unsigned long Verbose = 0;
56
-
57
- //#ifdef IN_CREATE_SUBDIR
58
- //#define MY_CREATE_SUBDIR_MASK IN_CREATE_SUBDIR | IN_CREATE_FILE
59
- //#else
60
- #define MY_CREATE_SUBDIR_MASK IN_CREATE
61
- //#endif
62
-
63
- static void sig_term_cb(int sign)
64
- {
65
- syslog( LOG_INFO, "preparing to exit... pid:%d", getpid() );
66
- WantToQuit = true;
67
- }
68
-
69
- static void sig_usr1_cb(int sign)
70
- {
71
- sig_term_cb(sign);
72
- }
73
-
74
- static void sig_usr2_cb(int sign)
75
- {
76
- /* ping */
77
- if( Verbose )
78
- {
79
- syslog( LOG_INFO, "got a ping! pid:%d", getpid() );
80
- }
81
- }
82
-
83
- struct tolowerstr : public std::unary_function< std::string , std::string >
84
- {
85
- /**
86
- */
87
- inline std::string operator()(const std::string& x) const
88
- {
89
- std::string ret = x;
90
-
91
- for( std::string::iterator p = ret.begin(); p != ret.end(); ++p )
92
- {
93
- *p = ::tolower( *p );
94
- }
95
-
96
- return ret;
97
- }
98
- };
99
-
100
- static bool starts_with( const string& s, const string& starting )
101
- {
102
- int starting_len = starting.length();
103
- int s_len = s.length();
104
-
105
- if( s_len < starting_len )
106
- return false;
107
-
108
- return !s.compare( 0, starting_len, starting );
109
- }
110
-
111
- string getHomeDir( const char* homedir_CSTR )
112
- {
113
- if( homedir_CSTR )
114
- return homedir_CSTR;
115
- if( const char* en = getenv( "HOME" ) )
116
- return en;
117
- return "";
118
- // cerr << "Can not work out your home directory! use the --homedir argument\n";
119
- // exit(1);
120
- }
121
-
122
-
123
-
124
- /********************************************************************************/
125
- /********************************************************************************/
126
- /********************************************************************************/
127
-
128
- KernelFileSystemMonitorDaemon::KernelFileSystemMonitorDaemon()
129
- :
130
- m_runInForground( 0 ),
131
- watch_mask( IN_ATTRIB |
132
- IN_MOVED_FROM |
133
- IN_MOVED_TO |
134
- MY_CREATE_SUBDIR_MASK |
135
-
136
- #ifdef IN_DELETE_FILE
137
- IN_DELETE_FILE |
138
- #endif
139
- #ifdef IN_DELETE
140
- IN_DELETE |
141
- #endif
142
- IN_CLOSE_WRITE
143
- ),
144
- dev_fd( 0 ),
145
- m_inotify_queue_threshold_bytes( 8 * 1024 ),
146
- m_nanosleep_ns( 50 * 1000 * 1000 ),
147
- m_inotify_queue_sleep_threshold_ns( 200 * 1000 * 1000 )
148
- {
149
- // watch_mask = IN_ALL_EVENTS;
150
- }
151
- KernelFileSystemMonitorDaemon::~KernelFileSystemMonitorDaemon()
152
- {
153
- }
154
-
155
-
156
- void
157
- KernelFileSystemMonitorDaemon::background_into_daemon()
158
- {
159
- pid_t pid = 0;
160
-
161
- if((pid = fork()) < 0 )
162
- {
163
- syslog( LOG_EMERG, "can't fork()", 0 );
164
- exit( 1 );
165
- }
166
- else if( pid != 0 )
167
- exit(0);
168
-
169
- setsid();
170
- chdir("/");
171
- umask(0);
172
- }
173
-
174
-
175
- void
176
- KernelFileSystemMonitorDaemon::priv_handle_event( struct inotify_event *pevent, time_t tt )
177
- {
178
- handle_event( pevent, tt );
179
- }
180
-
181
- void
182
- KernelFileSystemMonitorDaemon::event_batch_start( time_t tt )
183
- {
184
- }
185
-
186
- void
187
- KernelFileSystemMonitorDaemon::event_batch_end( time_t tt )
188
- {
189
- }
190
-
191
-
192
- void
193
- KernelFileSystemMonitorDaemon::setupSignalHandlers()
194
- {
195
- struct sigaction newinth;
196
- newinth.sa_handler = sig_term_cb;
197
- sigemptyset(&newinth.sa_mask);
198
- newinth.sa_flags = SA_RESTART;
199
- if( -1 == sigaction( SIGTERM, &newinth, NULL))
200
- {
201
- syslog( LOG_ERR, "ERROR: can not setup signal handling. reason:%s", strerror(errno) );
202
- exit(2);
203
- }
204
- if( -1 == sigaction( SIGQUIT, &newinth, NULL))
205
- {
206
- syslog( LOG_ERR, "ERROR: can not setup signal handling. reason:%s", strerror(errno) );
207
- exit(2);
208
- }
209
-
210
- newinth.sa_handler = sig_usr1_cb;
211
- sigemptyset(&newinth.sa_mask);
212
- newinth.sa_flags = SA_RESTART;
213
- if( -1 == sigaction( SIGUSR1, &newinth, NULL))
214
- {
215
- syslog( LOG_ERR, "ERROR: can not setup signal handling. reason:%s", strerror(errno) );
216
- exit(2);
217
- }
218
-
219
- newinth.sa_handler = sig_usr2_cb;
220
- sigemptyset(&newinth.sa_mask);
221
- newinth.sa_flags = SA_RESTART;
222
- if( -1 == sigaction( SIGUSR2, &newinth, NULL))
223
- {
224
- syslog( LOG_ERR, "ERROR: can not setup signal handling. reason:%s", strerror(errno) );
225
- exit(2);
226
- }
227
- }
228
-
229
- void
230
- KernelFileSystemMonitorDaemon::priv_Closedown()
231
- {
232
- Closedown();
233
- }
234
-
235
- void
236
- KernelFileSystemMonitorDaemon::print_event (struct inotify_event *event)
237
- {
238
- if( m_runInForground )
239
- {
240
- if (event->len)
241
- {
242
- cout << "M " << m_workingDirToURL[event->wd] << "/" << event->name << endl;
243
- // cout << "-" << endl;
244
- }
245
- #if 0
246
- cout << "event on wd:" << event->wd << " " << m_workingDirToURL[event->wd];
247
- if (event->len)
248
- {
249
- cout << " filename:" << event->name;
250
- }
251
- cout << endl;
252
- print_mask( cout, event->mask );
253
- if (event->len)
254
- {
255
- cout << " URL:" << m_workingDirToURL[event->wd] << "/" << event->name
256
- << endl;
257
- }
258
- #endif
259
- }
260
- else
261
- {
262
- stringstream maskss;
263
- print_mask( maskss, event->mask );
264
- syslog( LOG_DEBUG, "event on wd:%s mask:%s file:%s\n",
265
- m_workingDirToURL[event->wd].c_str(),
266
- maskss.str().c_str(),
267
- event->name );
268
- }
269
- }
270
-
271
-
272
- bool
273
- KernelFileSystemMonitorDaemon::shouldAddSubObject( int wd, const std::string& fn )
274
- {
275
- struct stat statbuf;
276
-
277
- if( fn == "." || fn == ".." )
278
- return false;
279
-
280
- int rc = lstat( fn.c_str(), &statbuf );
281
- if( !rc )
282
- {
283
- candidateObject( wd, fn, statbuf );
284
- if( S_ISDIR( statbuf.st_mode) )
285
- {
286
- return true;
287
- }
288
- }
289
- return false;
290
- }
291
-
292
- void
293
- KernelFileSystemMonitorDaemon::candidateObject( int wd, const std::string& fn, struct stat& statbuf )
294
- {
295
- }
296
-
297
-
298
-
299
- void
300
- KernelFileSystemMonitorDaemon::Closedown()
301
- {
302
- }
303
-
304
-
305
- void
306
- KernelFileSystemMonitorDaemon::setRunInForground( bool v )
307
- {
308
- m_runInForground = v;
309
- }
310
-
311
-
312
- bool
313
- KernelFileSystemMonitorDaemon::shouldWatch( const string& earl )
314
- {
315
- for( m_ignorePrefixes_t::iterator ci = m_ignorePrefixes.begin();
316
- ci != m_ignorePrefixes.end(); ++ci )
317
- {
318
- if( starts_with( earl, *ci ) )
319
- return false;
320
- }
321
-
322
- return true;
323
- }
324
-
325
- bool
326
- KernelFileSystemMonitorDaemon::handle_create_subdir_event_by_maybe_watching(
327
- struct inotify_event *pevent, time_t tt )
328
- {
329
- // cerr << "pevent->mask:" << hex << pevent->mask
330
- // << " MY_CREATE_SUBDIR_MASK:" << hex << MY_CREATE_SUBDIR_MASK
331
- // << dec
332
- // << endl;
333
-
334
- if ( pevent->mask & MY_CREATE_SUBDIR_MASK )
335
- {
336
- string dirName = m_workingDirToURL[ pevent->wd ];
337
- chdir( dirName.c_str() );
338
- // cerr << "have dirname:" << dirName << endl;
339
-
340
- if( shouldAddSubObject( pevent->wd, pevent->name ) )
341
- {
342
- string earl = dirName + "/" + pevent->name;
343
- m_watchRoots.push_back( earl );
344
- return true;
345
- }
346
- }
347
- return false;
348
- }
349
-
350
-
351
-
352
-
353
- void
354
- KernelFileSystemMonitorDaemon::add_watches_recursive( const string& earl )
355
- {
356
- if( !shouldWatch( earl ) )
357
- return;
358
-
359
- // struct inotify_watch_request req;
360
-
361
- int fd = open ( earl.c_str(), O_RDONLY);
362
-
363
- if (fd < 0)
364
- {
365
- syslog( LOG_WARNING, "not monitoring:%s reason:%s", earl.c_str(), strerror(errno));
366
- return;
367
- }
368
-
369
- fchdir(fd);
370
- // req.fd = fd;
371
- // req.mask = IN_CREATE_SUBDIR;
372
- // long wd = ioctl( dev_fd, INOTIFY_WATCH, &req );
373
- long wd = inotify_add_watch( dev_fd, earl.c_str(), MY_CREATE_SUBDIR_MASK );
374
- m_workingDirToURL[ wd ] = earl;
375
- setupWorkingDirToPersistentDirIDMapping( wd, earl );
376
-
377
- //
378
- // Gather up the subdirectory names into dirNames
379
- //
380
- typedef list< string > dirNames_t;
381
- dirNames_t dirNames;
382
-
383
- DIR *d;
384
- struct dirent *e;
385
- if ((d = opendir (earl.c_str())) == NULL)
386
- {
387
- syslog( LOG_WARNING, "not monitoring:%s reason:%s", earl.c_str(), strerror(errno));
388
- }
389
- else
390
- {
391
- while( e = readdir(d) )
392
- {
393
- if( shouldAddSubObject( wd, e->d_name ) )
394
- {
395
- dirNames.push_back( e->d_name );
396
- if( Verbose )
397
- cerr << "might add monitor for:" << e->d_name << endl;
398
- }
399
- }
400
- closedir (d);
401
- }
402
-
403
- //
404
- // Check to see if a new directory was created while
405
- // we were readdir()ing
406
- //
407
- {
408
- // cerr << "***** BEGIN ****** checking bg info url:" << earl << endl;
409
-
410
- const int buf_sz = 16 * 1024;
411
- char buf[ buf_sz + 1 ];
412
- int event_count = 0;
413
-
414
- unsigned int nfds = 1;
415
- struct pollfd ufds;
416
- ufds.fd = dev_fd;
417
- ufds.events = POLLIN;
418
- ufds.revents = 0;
419
-
420
- int poll_rc = poll( &ufds, nfds, 0 );
421
- for( ; poll_rc ; poll_rc = poll( &ufds, nfds, 0 ) )
422
- {
423
- size_t len = read( dev_fd, buf, buf_sz);
424
- if( !len )
425
- break;
426
-
427
- size_t buf_iter = 0;
428
-
429
- // cerr << "buf_iter:" << buf_iter << " len:" << len << endl;
430
- // cerr << "dev_fd:" << dev_fd << endl;
431
-
432
- while (buf_iter < len)
433
- {
434
- /* Parse events and queue them ! */
435
- struct inotify_event * pevent
436
- = (struct inotify_event *)&buf[buf_iter];
437
-
438
- handle_create_subdir_event_by_maybe_watching( pevent, 0 );
439
-
440
- int event_size = sizeof(struct inotify_event) + pevent->len;
441
- buf_iter += event_size;
442
- event_count++;
443
- }
444
- }
445
- // cerr << "***** END ****** checking bg info url:" << earl << endl;
446
- }
447
-
448
- //
449
- // switch to monitoring all interesting things for this directory.
450
- //
451
- // req.fd = fd;
452
- // req.mask = watch_mask;
453
- // wd = ioctl( dev_fd, INOTIFY_WATCH, &req );
454
- wd = inotify_add_watch( dev_fd, earl.c_str(), watch_mask );
455
- close (fd);
456
-
457
- //
458
- // Monitor the subdirectories
459
- //
460
- for( dirNames_t::const_iterator di = dirNames.begin();
461
- di != dirNames.end(); ++di )
462
- {
463
- add_watches_recursive( earl + "/" + *di );
464
- }
465
-
466
- }
467
-
468
- void
469
- KernelFileSystemMonitorDaemon::addIgnorePrefix( const string& s )
470
- {
471
- m_ignorePrefixes.push_back( s );
472
- }
473
-
474
- void
475
- KernelFileSystemMonitorDaemon::ParseWatchOptions( poptContext& optCon )
476
- {
477
- string opcode = "";
478
- while( const char* tmpCSTR = poptGetArg(optCon) )
479
- {
480
- string s = tmpCSTR;
481
- string ls = tolowerstr()(s);
482
-
483
- // cerr << " s:" << s << endl;
484
-
485
- if( ls == "ignorepfx" )
486
- {
487
- opcode = ls;
488
- continue;
489
- }
490
- if( ls == "watch" )
491
- {
492
- opcode = ls;
493
- continue;
494
- }
495
-
496
- if( opcode == "ignorepfx" )
497
- {
498
- m_ignorePrefixes.push_back( s );
499
- }
500
- else if( opcode == "watch" )
501
- {
502
- if( Verbose )
503
- cerr << "setting up watch for:" << s << endl;
504
- m_watchRoots.push_back( s );
505
- }
506
- }
507
-
508
- }
509
-
510
-
511
- void
512
- KernelFileSystemMonitorDaemon::setupWatches()
513
- {
514
- if( !dev_fd )
515
- {
516
- // dev_fd = open ("/dev/inotify", O_RDONLY);
517
- dev_fd = inotify_init();
518
- if( dev_fd < 0 )
519
- {
520
- syslog( LOG_ERR, "Exiting due to failure to open inotify device reason:%s", strerror(errno));
521
- cerr << "Exiting due to failure to open /dev/inotify device reason:" << strerror(errno)
522
- << endl;
523
- exit( 1 );
524
- }
525
- }
526
-
527
- if( m_watchRoots.empty() )
528
- {
529
- cerr << "No directories/files to watch have been specified!" << endl;
530
- }
531
- else
532
- {
533
- for( stringlist_t::const_iterator ci = m_watchRoots.begin();
534
- ci != m_watchRoots.end(); ++ci )
535
- {
536
- add_watches_recursive( *ci );
537
- }
538
- }
539
- }
540
-
541
- void
542
- KernelFileSystemMonitorDaemon::HandleSleepForQueueSize()
543
- {
544
- unsigned long long time_slept = 0;
545
-
546
- while( !WantToQuit )
547
- {
548
- unsigned int bytesAvailable = 0;
549
- int iorc = ioctl( dev_fd, FIONREAD, &bytesAvailable, 0 );
550
- if( iorc < 0 )
551
- {
552
- // error
553
- }
554
-
555
- syslog( LOG_DEBUG,
556
- "HandleQ() bytesAvailable:%d iorc:%d "
557
- "queue_threshold_bytes:%d "
558
- "queue_sleep_threshold_ns:%d time_slept:%d",
559
- bytesAvailable, iorc,
560
- m_inotify_queue_threshold_bytes,
561
- m_inotify_queue_sleep_threshold_ns,
562
- time_slept );
563
- // cerr << "HandleQ() bytesAvailable:" << bytesAvailable
564
- // << " iorc:" << iorc
565
- // << " queue_threshold_bytes:" << m_inotify_queue_threshold_bytes
566
- // << " queue_sleep_threshold_ns:" << m_inotify_queue_sleep_threshold_ns
567
- // << " time_slept:" << time_slept
568
- // << endl;
569
-
570
- if( time_slept >= m_inotify_queue_sleep_threshold_ns )
571
- {
572
- if( !bytesAvailable )
573
- {
574
- time_slept = 0;
575
-
576
- unsigned int nfds = 1;
577
- struct pollfd ufds;
578
- ufds.fd = dev_fd;
579
- ufds.events = POLLIN;
580
- ufds.revents = 0;
581
-
582
- // if the system is idle we should really switch to
583
- // poll() here so that we are not a burden
584
- int poll_rc = poll( &ufds, nfds, -1 );
585
- syslog( LOG_DEBUG, "after poll() rc:%d", poll_rc );
586
-
587
- continue;
588
- }
589
-
590
- return;
591
- }
592
-
593
- if( bytesAvailable >= m_inotify_queue_threshold_bytes )
594
- {
595
- return;
596
- }
597
-
598
- //
599
- // Time to go for a little kip
600
- //
601
- struct timespec nts;
602
- nts.tv_sec = 0;
603
- nts.tv_nsec = m_nanosleep_ns;
604
- struct timespec rem;
605
- bzero( &rem, sizeof(rem) );
606
-
607
- while( nanosleep( &nts, &rem ) < 0 )
608
- {
609
- if( WantToQuit )
610
- return;
611
-
612
- if( errno == EINTR )
613
- {
614
- nts = rem;
615
- bzero( &rem, sizeof(rem) );
616
- continue;
617
- }
618
- else
619
- {
620
- // error
621
- break;
622
- }
623
- }
624
- time_slept += m_nanosleep_ns;
625
- continue;
626
- }
627
- }
628
-
629
-
630
- int
631
- KernelFileSystemMonitorDaemon::run()
632
- {
633
- // cerr << "KernelFileSystemMonitorDaemon::run() starting" << endl;
634
-
635
- chdir("/");
636
-
637
- const int buf_sz = 32 * 1024;
638
- char buf[ buf_sz + 1 ];
639
- int event_count = 0;
640
-
641
- while( true )
642
- {
643
- HandleSleepForQueueSize();
644
- syslog( LOG_DEBUG, "After HandleSleepForQueueSize()", 0 );
645
-
646
- if( WantToQuit )
647
- {
648
- Closedown();
649
- return 0;
650
- }
651
-
652
- if( size_t len = read( dev_fd, buf, buf_sz) )
653
- {
654
- if( len > SSIZE_MAX )
655
- continue;
656
-
657
- time_t tt = time( 0 );
658
-
659
- size_t buf_iter = 0;
660
- bool have_new_subdirs_to_watch = false;
661
-
662
- // cerr << "buf_iter:" << buf_iter << " len:" << len << endl;
663
- // cerr << "dev_fd:" << dev_fd << endl;
664
-
665
- event_batch_start( tt );
666
-
667
- while (buf_iter < len)
668
- {
669
- /* Parse events and queue them ! */
670
- struct inotify_event * pevent
671
- = (struct inotify_event *)&buf[buf_iter];
672
-
673
- have_new_subdirs_to_watch |=
674
- handle_create_subdir_event_by_maybe_watching( pevent, tt );
675
- handle_event( pevent, tt );
676
-
677
- int event_size = sizeof(struct inotify_event) + pevent->len;
678
- buf_iter += event_size;
679
- event_count++;
680
- }
681
-
682
- event_batch_end( tt );
683
-
684
- cout << "-" << endl;
685
-
686
- if( have_new_subdirs_to_watch )
687
- setupWatches();
688
- }
689
- }
690
-
691
- // cerr << "KernelFileSystemMonitorDaemon::run() exiting" << endl;
692
- return 0;
693
-
694
- }
695
-
696
-
697
- struct ::poptOption*
698
- KernelFileSystemMonitorDaemon::getPopTable()
699
- {
700
- static struct poptOption optionsTable[] =
701
- {
702
- { "inotify-queue-threshold-bytes", 0, POPT_ARG_INT, &m_inotify_queue_threshold_bytes, 0,
703
- "number of bytes that should be available on /dev/inotify before reading", "" },
704
-
705
- { "inotify-queue-sleep-threshold-ns", 0, POPT_ARG_INT, &m_inotify_queue_sleep_threshold_ns, 0,
706
- "after this time read the inotify queue anyway", "" },
707
-
708
- { "inotify-sleep-delay-ns", 0, POPT_ARG_INT, &m_nanosleep_ns, 0,
709
- "nanoseconds to sleep if /dev/inotify is not full enough", "" },
710
-
711
- POPT_TABLEEND
712
- };
713
- return optionsTable;
714
- }
715
-
716
-
717
-
718
-
719
-
720
-
721
-
722
-
723
-
724
-
725
-
726
-
727
-