1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """
24 pyinotify
25
26 @author: Sebastien Martini
27 @license: MIT License
28 @contact: seb@dbzteam.org
29 """
32 """Indicates exceptions raised by a Pyinotify class."""
33 pass
34
37 """
38 Raised on unsupported Python versions.
39 """
41 """
42 @param version: Current Python version
43 @type version: string
44 """
45 PyinotifyError.__init__(self,
46 ('Python %s is unsupported, requires '
47 'at least Python 2.4') % version)
48
51 """
52 Raised when libc couldn't be loaded or when inotify functions werent
53 provided.
54 """
58
59
60
61 import sys
62 if sys.version < '2.4':
63 raise UnsupportedPythonVersionError(sys.version)
64
65
66
67 import threading
68 import os
69 import select
70 import struct
71 import fcntl
72 import errno
73 import termios
74 import array
75 import logging
76 import atexit
77 from collections import deque
78 from datetime import datetime, timedelta
79 import time
80 import fnmatch
81 import re
82 import ctypes
83 import ctypes.util
84 import asyncore
85 import glob
86
87 try:
88 from functools import reduce
89 except ImportError:
90 pass
91
92 __author__ = "seb@dbzteam.org (Sebastien Martini)"
93
94 __version__ = "0.9.1"
95
96 __metaclass__ = type
97
98
99
100
101
102 COMPATIBILITY_MODE = False
103
104
105
106 LIBC = None
107 strerrno = None
110 global strerrno
111 global LIBC
112
113 libc = None
114 try:
115 libc = ctypes.util.find_library('c')
116 except (OSError, IOError):
117 pass
118
119 if sys.version_info[0] >= 2 and sys.version_info[1] >= 6:
120 LIBC = ctypes.CDLL(libc, use_errno=True)
121 def _strerrno():
122 code = ctypes.get_errno()
123 return ' Errno=%s (%s)' % (os.strerror(code), errno.errorcode[code])
124 strerrno = _strerrno
125 else:
126 LIBC = ctypes.CDLL(libc)
127 strerrno = lambda : ''
128
129
130 if (not hasattr(LIBC, 'inotify_init') or
131 not hasattr(LIBC, 'inotify_add_watch') or
132 not hasattr(LIBC, 'inotify_rm_watch')):
133 raise UnsupportedLibcVersionError()
134
135 load_libc()
139 """
140 Pyinotify logger used for logging unicode strings.
141 """
142 - def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None,
143 extra=None):
144 rv = UnicodeLogRecord(name, level, fn, lno, msg, args, exc_info, func)
145 if extra is not None:
146 for key in extra:
147 if (key in ["message", "asctime"]) or (key in rv.__dict__):
148 raise KeyError("Attempt to overwrite %r in LogRecord" % key)
149 rv.__dict__[key] = extra[key]
150 return rv
151
154 - def __init__(self, name, level, pathname, lineno,
155 msg, args, exc_info, func=None):
156 py_version = sys.version_info
157
158 if py_version[0] >= 2 and py_version[1] >= 5:
159 logging.LogRecord.__init__(self, name, level, pathname, lineno,
160 msg, args, exc_info, func)
161 else:
162 logging.LogRecord.__init__(self, name, level, pathname, lineno,
163 msg, args, exc_info)
164
166 msg = self.msg
167 if not isinstance(msg, (unicode, str)):
168 try:
169 msg = str(self.msg)
170 except UnicodeError:
171 pass
172 if self.args:
173 if isinstance(self.args, tuple):
174 def str_to_unicode(s):
175 """Return unicode string."""
176 if not isinstance(s, str):
177 return s
178 return unicode(s, sys.getfilesystemencoding())
179 args = tuple([str_to_unicode(m) for m in self.args])
180 else:
181 args = self.args
182 msg = msg % args
183 if not isinstance(msg, unicode):
184 msg = unicode(msg, sys.getfilesystemencoding())
185 return msg
186
190 """Initialize logger instance."""
191 logging.setLoggerClass(PyinotifyLogger)
192 log = logging.getLogger("pyinotify")
193 console_handler = logging.StreamHandler()
194 console_handler.setFormatter(
195 logging.Formatter("[%(asctime)s %(name)s %(levelname)s] %(message)s"))
196 log.addHandler(console_handler)
197 log.setLevel(20)
198 return log
199
200 log = logger_init()
205 """
206 Access (read, write) inotify's variables through sysctl. Usually it
207 requires administrator rights to update them.
208
209 Examples:
210 - Read max_queued_events attribute: myvar = max_queued_events.value
211 - Update max_queued_events attribute: max_queued_events.value = 42
212 """
213
214 inotify_attrs = {'max_user_instances': 1,
215 'max_user_watches': 2,
216 'max_queued_events': 3}
217
222
224 """
225 Gets attribute's value.
226
227 @return: stored value.
228 @rtype: int
229 """
230 oldv = ctypes.c_int(0)
231 size = ctypes.c_int(ctypes.sizeof(oldv))
232 LIBC.sysctl(self._attr, 3,
233 ctypes.c_voidp(ctypes.addressof(oldv)),
234 ctypes.addressof(size),
235 None, 0)
236 return oldv.value
237
239 """
240 Sets new attribute's value.
241
242 @param nval: replaces current value by nval.
243 @type nval: int
244 """
245 oldv = ctypes.c_int(0)
246 sizeo = ctypes.c_int(ctypes.sizeof(oldv))
247 newv = ctypes.c_int(nval)
248 sizen = ctypes.c_int(ctypes.sizeof(newv))
249 LIBC.sysctl(self._attr, 3,
250 ctypes.c_voidp(ctypes.addressof(oldv)),
251 ctypes.addressof(sizeo),
252 ctypes.c_voidp(ctypes.addressof(newv)),
253 ctypes.addressof(sizen))
254
255 value = property(get_val, set_val)
256
258 return '<%s=%d>' % (self._attrname, self.get_val())
259
260
261
262
263
264
265
266 for attrname in ('max_queued_events', 'max_user_instances', 'max_user_watches'):
267 globals()[attrname] = SysCtlINotify(attrname)
271 """
272 Set of codes corresponding to each kind of events.
273 Some of these flags are used to communicate with inotify, whereas
274 the others are sent to userspace by inotify notifying some events.
275
276 @cvar IN_ACCESS: File was accessed.
277 @type IN_ACCESS: int
278 @cvar IN_MODIFY: File was modified.
279 @type IN_MODIFY: int
280 @cvar IN_ATTRIB: Metadata changed.
281 @type IN_ATTRIB: int
282 @cvar IN_CLOSE_WRITE: Writtable file was closed.
283 @type IN_CLOSE_WRITE: int
284 @cvar IN_CLOSE_NOWRITE: Unwrittable file closed.
285 @type IN_CLOSE_NOWRITE: int
286 @cvar IN_OPEN: File was opened.
287 @type IN_OPEN: int
288 @cvar IN_MOVED_FROM: File was moved from X.
289 @type IN_MOVED_FROM: int
290 @cvar IN_MOVED_TO: File was moved to Y.
291 @type IN_MOVED_TO: int
292 @cvar IN_CREATE: Subfile was created.
293 @type IN_CREATE: int
294 @cvar IN_DELETE: Subfile was deleted.
295 @type IN_DELETE: int
296 @cvar IN_DELETE_SELF: Self (watched item itself) was deleted.
297 @type IN_DELETE_SELF: int
298 @cvar IN_MOVE_SELF: Self (watched item itself) was moved.
299 @type IN_MOVE_SELF: int
300 @cvar IN_UNMOUNT: Backing fs was unmounted.
301 @type IN_UNMOUNT: int
302 @cvar IN_Q_OVERFLOW: Event queued overflowed.
303 @type IN_Q_OVERFLOW: int
304 @cvar IN_IGNORED: File was ignored.
305 @type IN_IGNORED: int
306 @cvar IN_ONLYDIR: only watch the path if it is a directory (new
307 in kernel 2.6.15).
308 @type IN_ONLYDIR: int
309 @cvar IN_DONT_FOLLOW: don't follow a symlink (new in kernel 2.6.15).
310 IN_ONLYDIR we can make sure that we don't watch
311 the target of symlinks.
312 @type IN_DONT_FOLLOW: int
313 @cvar IN_MASK_ADD: add to the mask of an already existing watch (new
314 in kernel 2.6.14).
315 @type IN_MASK_ADD: int
316 @cvar IN_ISDIR: Event occurred against dir.
317 @type IN_ISDIR: int
318 @cvar IN_ONESHOT: Only send event once.
319 @type IN_ONESHOT: int
320 @cvar ALL_EVENTS: Alias for considering all of the events.
321 @type ALL_EVENTS: int
322 """
323
324
325
326
327 FLAG_COLLECTIONS = {'OP_FLAGS': {
328 'IN_ACCESS' : 0x00000001,
329 'IN_MODIFY' : 0x00000002,
330 'IN_ATTRIB' : 0x00000004,
331 'IN_CLOSE_WRITE' : 0x00000008,
332 'IN_CLOSE_NOWRITE' : 0x00000010,
333 'IN_OPEN' : 0x00000020,
334 'IN_MOVED_FROM' : 0x00000040,
335 'IN_MOVED_TO' : 0x00000080,
336 'IN_CREATE' : 0x00000100,
337 'IN_DELETE' : 0x00000200,
338 'IN_DELETE_SELF' : 0x00000400,
339
340 'IN_MOVE_SELF' : 0x00000800,
341 },
342 'EVENT_FLAGS': {
343 'IN_UNMOUNT' : 0x00002000,
344 'IN_Q_OVERFLOW' : 0x00004000,
345 'IN_IGNORED' : 0x00008000,
346 },
347 'SPECIAL_FLAGS': {
348 'IN_ONLYDIR' : 0x01000000,
349
350 'IN_DONT_FOLLOW' : 0x02000000,
351 'IN_MASK_ADD' : 0x20000000,
352
353 'IN_ISDIR' : 0x40000000,
354 'IN_ONESHOT' : 0x80000000,
355 },
356 }
357
359 """
360 Returns the event name associated to mask. IN_ISDIR is appended to
361 the result when appropriate. Note: only one event is returned, because
362 only one event can be raised at a given time.
363
364 @param mask: mask.
365 @type mask: int
366 @return: event name.
367 @rtype: str
368 """
369 ms = mask
370 name = '%s'
371 if mask & IN_ISDIR:
372 ms = mask - IN_ISDIR
373 name = '%s|IN_ISDIR'
374 return name % EventsCodes.ALL_VALUES[ms]
375
376 maskname = staticmethod(maskname)
377
378
379
380 EventsCodes.ALL_FLAGS = {}
381 EventsCodes.ALL_VALUES = {}
382 for flagc, valc in EventsCodes.FLAG_COLLECTIONS.items():
383
384
385 setattr(EventsCodes, flagc, valc)
386
387
388 EventsCodes.ALL_FLAGS.update(valc)
389
390
391
392 for name, val in valc.items():
393 globals()[name] = val
394 EventsCodes.ALL_VALUES[val] = name
395
396
397
398 ALL_EVENTS = reduce(lambda x, y: x | y, EventsCodes.OP_FLAGS.values())
399 EventsCodes.ALL_FLAGS['ALL_EVENTS'] = ALL_EVENTS
400 EventsCodes.ALL_VALUES[ALL_EVENTS] = 'ALL_EVENTS'
404 """
405 Event structure, represent events raised by the system. This
406 is the base class and should be subclassed.
407
408 """
410 """
411 Attach attributes (contained in dict_) to self.
412
413 @param dict_: Set of attributes.
414 @type dict_: dictionary
415 """
416 for tpl in dict_.items():
417 setattr(self, *tpl)
418
441
444
447 """
448 Raw event, it contains only the informations provided by the system.
449 It doesn't infer anything.
450 """
451 - def __init__(self, wd, mask, cookie, name):
452 """
453 @param wd: Watch Descriptor.
454 @type wd: int
455 @param mask: Bitmask of events.
456 @type mask: int
457 @param cookie: Cookie.
458 @type cookie: int
459 @param name: Basename of the file or directory against which the
460 event was raised in case where the watched directory
461 is the parent directory. None if the event was raised
462 on the watched item itself.
463 @type name: string or None
464 """
465
466
467 self._str = None
468
469 d = {'wd': wd,
470 'mask': mask,
471 'cookie': cookie,
472 'name': name.rstrip('\0')}
473 _Event.__init__(self, d)
474 log.debug(str(self))
475
477 if self._str is None:
478 self._str = _Event.__str__(self)
479 return self._str
480
483 """
484 This class contains all the useful informations about the observed
485 event. However, the presence of each field is not guaranteed and
486 depends on the type of event. In effect, some fields are irrelevant
487 for some kind of event (for example 'cookie' is meaningless for
488 IN_CREATE whereas it is mandatory for IN_MOVE_TO).
489
490 The possible fields are:
491 - wd (int): Watch Descriptor.
492 - mask (int): Mask.
493 - maskname (str): Readable event name.
494 - path (str): path of the file or directory being watched.
495 - name (str): Basename of the file or directory against which the
496 event was raised in case where the watched directory
497 is the parent directory. None if the event was raised
498 on the watched item itself. This field is always provided
499 even if the string is ''.
500 - pathname (str): Concatenation of 'path' and 'name'.
501 - src_pathname (str): Only present for IN_MOVED_TO events and only in
502 the case where IN_MOVED_FROM events are watched too. Holds the
503 source pathname from where pathname was moved from.
504 - cookie (int): Cookie.
505 - dir (bool): True if the event was raised against a directory.
506
507 """
509 """
510 Concretely, this is the raw event plus inferred infos.
511 """
512 _Event.__init__(self, raw)
513 self.maskname = EventsCodes.maskname(self.mask)
514 if COMPATIBILITY_MODE:
515 self.event_name = self.maskname
516 try:
517 if self.name:
518 self.pathname = os.path.abspath(os.path.join(self.path,
519 self.name))
520 else:
521 self.pathname = os.path.abspath(self.path)
522 except AttributeError, err:
523
524
525 log.debug(err)
526
529 """
530 ProcessEventError Exception. Raised on ProcessEvent error.
531 """
533 """
534 @param err: Exception error description.
535 @type err: string
536 """
537 PyinotifyError.__init__(self, err)
538
541 """
542 Abstract processing event class.
543 """
545 """
546 To behave like a functor the object must be callable.
547 This method is a dispatch method. Its lookup order is:
548 1. process_MASKNAME method
549 2. process_FAMILY_NAME method
550 3. otherwise calls process_default
551
552 @param event: Event to be processed.
553 @type event: Event object
554 @return: By convention when used from the ProcessEvent class:
555 - Returning False or None (default value) means keep on
556 executing next chained functors (see chain.py example).
557 - Returning True instead means do not execute next
558 processing functions.
559 @rtype: bool
560 @raise ProcessEventError: Event object undispatchable,
561 unknown event.
562 """
563 stripped_mask = event.mask - (event.mask & IN_ISDIR)
564 maskname = EventsCodes.ALL_VALUES.get(stripped_mask)
565 if maskname is None:
566 raise ProcessEventError("Unknown mask 0x%08x" % stripped_mask)
567
568
569 meth = getattr(self, 'process_' + maskname, None)
570 if meth is not None:
571 return meth(event)
572
573 meth = getattr(self, 'process_IN_' + maskname.split('_')[1], None)
574 if meth is not None:
575 return meth(event)
576
577 return self.process_default(event)
578
580 return '<%s>' % self.__class__.__name__
581
584 """
585 There is three kind of processing according to each event:
586
587 1. special handling (deletion from internal container, bug, ...).
588 2. default treatment: which is applied to the majority of events.
589 3. IN_ISDIR is never sent alone, he is piggybacked with a standard
590 event, he is not processed as the others events, instead, its
591 value is captured and appropriately aggregated to dst event.
592 """
594 """
595
596 @param wm: Watch Manager.
597 @type wm: WatchManager instance
598 @param notifier: Notifier.
599 @type notifier: Notifier instance
600 """
601 self._watch_manager = wm
602 self._notifier = notifier
603 self._mv_cookie = {}
604 self._mv = {}
605
607 """
608 Cleanup (delete) old (>1mn) records contained in self._mv_cookie
609 and self._mv.
610 """
611 date_cur_ = datetime.now()
612 for seq in [self._mv_cookie, self._mv]:
613 for k in seq.keys():
614 if (date_cur_ - seq[k][1]) > timedelta(minutes=1):
615 log.debug('Cleanup: deleting entry %s', seq[k][0])
616 del seq[k]
617
619 """
620 If the event affects a directory and the auto_add flag of the
621 targetted watch is set to True, a new watch is added on this
622 new directory, with the same attribute values than those of
623 this watch.
624 """
625 if raw_event.mask & IN_ISDIR:
626 watch_ = self._watch_manager.get_watch(raw_event.wd)
627 created_dir = os.path.join(watch_.path, raw_event.name)
628 if watch_.auto_add and not watch_.exclude_filter(created_dir):
629 addw = self._watch_manager.add_watch
630
631
632 addw_ret = addw(created_dir, watch_.mask,
633 proc_fun=watch_.proc_fun,
634 rec=False, auto_add=watch_.auto_add,
635 exclude_filter=watch_.exclude_filter)
636
637
638
639
640
641 created_dir_wd = addw_ret.get(created_dir)
642 if (created_dir_wd is not None) and created_dir_wd > 0:
643 for name in os.listdir(created_dir):
644 inner = os.path.join(created_dir, name)
645 if (os.path.isdir(inner) and
646 self._watch_manager.get_wd(inner) is None):
647
648
649 rawevent = _RawEvent(created_dir_wd,
650 IN_CREATE | IN_ISDIR,
651 0, name)
652 self._notifier.append_event(rawevent)
653 return self.process_default(raw_event)
654
656 """
657 Map the cookie with the source path (+ date for cleaning).
658 """
659 watch_ = self._watch_manager.get_watch(raw_event.wd)
660 path_ = watch_.path
661 src_path = os.path.normpath(os.path.join(path_, raw_event.name))
662 self._mv_cookie[raw_event.cookie] = (src_path, datetime.now())
663 return self.process_default(raw_event, {'cookie': raw_event.cookie})
664
666 """
667 Map the source path with the destination path (+ date for
668 cleaning).
669 """
670 watch_ = self._watch_manager.get_watch(raw_event.wd)
671 path_ = watch_.path
672 dst_path = os.path.normpath(os.path.join(path_, raw_event.name))
673 mv_ = self._mv_cookie.get(raw_event.cookie)
674 to_append = {'cookie': raw_event.cookie}
675 if mv_ is not None:
676 self._mv[mv_[0]] = (dst_path, datetime.now())
677
678
679
680
681
682 to_append['src_pathname'] = mv_[0]
683 elif (raw_event.mask & IN_ISDIR and watch_.auto_add and
684 not watch_.exclude_filter(dst_path)):
685
686
687
688
689 self._watch_manager.add_watch(dst_path, watch_.mask,
690 proc_fun=watch_.proc_fun,
691 rec=True, auto_add=True,
692 exclude_filter=watch_.exclude_filter)
693 return self.process_default(raw_event, to_append)
694
696 """
697 STATUS: the following bug has been fixed in recent kernels (FIXME:
698 which version ?). Now it raises IN_DELETE_SELF instead.
699
700 Old kernels were bugged, this event raised when the watched item
701 were moved, so we had to update its path, but under some circumstances
702 it was impossible: if its parent directory and its destination
703 directory wasn't watched. The kernel (see include/linux/fsnotify.h)
704 doesn't bring us enough informations like the destination path of
705 moved items.
706 """
707 watch_ = self._watch_manager.get_watch(raw_event.wd)
708 src_path = watch_.path
709 mv_ = self._mv.get(src_path)
710 if mv_:
711 dest_path = mv_[0]
712 watch_.path = dest_path
713
714
715 src_path += os.path.sep
716 src_path_len = len(src_path)
717
718
719
720 for w in self._watch_manager.watches.values():
721 if w.path.startswith(src_path):
722
723 w.path = os.path.join(dest_path, w.path[src_path_len:])
724 else:
725 log.error("The pathname '%s' of this watch %s has probably changed "
726 "and couldn't be updated, so it cannot be trusted "
727 "anymore. To fix this error move directories/files only "
728 "between watched parents directories, in this case e.g. "
729 "put a watch on '%s'.",
730 watch_.path, watch_,
731 os.path.normpath(os.path.join(watch_.path,
732 os.path.pardir)))
733 if not watch_.path.endswith('-unknown-path'):
734 watch_.path += '-unknown-path'
735 return self.process_default(raw_event)
736
738 """
739 Only signal an overflow, most of the common flags are irrelevant
740 for this event (path, wd, name).
741 """
742 return Event({'mask': raw_event.mask})
743
745 """
746 The watch descriptor raised by this event is now ignored (forever),
747 it can be safely deleted from the watch manager dictionary.
748 After this event we can be sure that neither the event queue nor
749 the system will raise an event associated to this wd again.
750 """
751 event_ = self.process_default(raw_event)
752 self._watch_manager.del_watch(raw_event.wd)
753 return event_
754
756 """
757 Commons handling for the followings events:
758
759 IN_ACCESS, IN_MODIFY, IN_ATTRIB, IN_CLOSE_WRITE, IN_CLOSE_NOWRITE,
760 IN_OPEN, IN_DELETE, IN_DELETE_SELF, IN_UNMOUNT.
761 """
762 watch_ = self._watch_manager.get_watch(raw_event.wd)
763 if raw_event.mask & (IN_DELETE_SELF | IN_MOVE_SELF):
764
765 dir_ = watch_.dir
766 else:
767 dir_ = bool(raw_event.mask & IN_ISDIR)
768 dict_ = {'wd': raw_event.wd,
769 'mask': raw_event.mask,
770 'path': watch_.path,
771 'name': raw_event.name,
772 'dir': dir_}
773 if COMPATIBILITY_MODE:
774 dict_['is_dir'] = dir_
775 if to_append is not None:
776 dict_.update(to_append)
777 return Event(dict_)
778
781 """
782 Process events objects, can be specialized via subclassing, thus its
783 behavior can be overriden:
784
785 Note: you should not override __init__ in your subclass instead define
786 a my_init() method, this method will be called automatically from the
787 constructor of this class with its optionals parameters.
788
789 1. Provide specialized individual methods, e.g. process_IN_DELETE for
790 processing a precise type of event (e.g. IN_DELETE in this case).
791 2. Or/and provide methods for processing events by 'family', e.g.
792 process_IN_CLOSE method will process both IN_CLOSE_WRITE and
793 IN_CLOSE_NOWRITE events (if process_IN_CLOSE_WRITE and
794 process_IN_CLOSE_NOWRITE aren't defined though).
795 3. Or/and override process_default for catching and processing all
796 the remaining types of events.
797 """
798 pevent = None
799
800 - def __init__(self, pevent=None, **kargs):
801 """
802 Enable chaining of ProcessEvent instances.
803
804 @param pevent: Optional callable object, will be called on event
805 processing (before self).
806 @type pevent: callable
807 @param kargs: This constructor is implemented as a template method
808 delegating its optionals keyworded arguments to the
809 method my_init().
810 @type kargs: dict
811 """
812 self.pevent = pevent
813 self.my_init(**kargs)
814
816 """
817 This method is called from ProcessEvent.__init__(). This method is
818 empty here and must be redefined to be useful. In effect, if you
819 need to specifically initialize your subclass' instance then you
820 just have to override this method in your subclass. Then all the
821 keyworded arguments passed to ProcessEvent.__init__() will be
822 transmitted as parameters to this method. Beware you MUST pass
823 keyword arguments though.
824
825 @param kargs: optional delegated arguments from __init__().
826 @type kargs: dict
827 """
828 pass
829
831 stop_chaining = False
832 if self.pevent is not None:
833
834
835
836
837
838 stop_chaining = self.pevent(event)
839 if not stop_chaining:
840 return _ProcessEvent.__call__(self, event)
841
844
846 """
847 By default this method only reports warning messages, you can overredide
848 it by subclassing ProcessEvent and implement your own
849 process_IN_Q_OVERFLOW method. The actions you can take on receiving this
850 event is either to update the variable max_queued_events in order to
851 handle more simultaneous events or to modify your code in order to
852 accomplish a better filtering diminishing the number of raised events.
853 Because this method is defined, IN_Q_OVERFLOW will never get
854 transmitted as arguments to process_default calls.
855
856 @param event: IN_Q_OVERFLOW event.
857 @type event: dict
858 """
859 log.warning('Event queue overflowed.')
860
862 """
863 Default processing event method. By default does nothing. Subclass
864 ProcessEvent and redefine this method in order to modify its behavior.
865
866 @param event: Event to be processed. Can be of any type of events but
867 IN_Q_OVERFLOW events (see method process_IN_Q_OVERFLOW).
868 @type event: Event instance
869 """
870 pass
871
874 """
875 Dummy class used to print events strings representations. For instance this
876 class is used from command line to print all received events to stdout.
877 """
879 """
880 @param out: Where events will be written.
881 @type out: Object providing a valid file object interface.
882 """
883 if out is None:
884 out = sys.stdout
885 self._out = out
886
888 """
889 Writes event string representation to file object provided to
890 my_init().
891
892 @param event: Event to be processed. Can be of any type of events but
893 IN_Q_OVERFLOW events (see method process_IN_Q_OVERFLOW).
894 @type event: Event instance
895 """
896 self._out.write(str(event))
897 self._out.write('\n')
898 self._out.flush()
899
902 """
903 Makes conditional chaining depending on the result of the nested
904 processing instance.
905 """
907 """
908 Method automatically called from base class constructor.
909 """
910 self._func = func
911
913 return not self._func(event)
914
915
916 -class Stats(ProcessEvent):
917 """
918 Compute and display trivial statistics about processed events.
919 """
921 """
922 Method automatically called from base class constructor.
923 """
924 self._start_time = time.time()
925 self._stats = {}
926 self._stats_lock = threading.Lock()
927
929 """
930 Processes |event|.
931 """
932 self._stats_lock.acquire()
933 try:
934 events = event.maskname.split('|')
935 for event_name in events:
936 count = self._stats.get(event_name, 0)
937 self._stats[event_name] = count + 1
938 finally:
939 self._stats_lock.release()
940
942 self._stats_lock.acquire()
943 try:
944 return self._stats.copy()
945 finally:
946 self._stats_lock.release()
947
949 stats = self._stats_copy()
950
951 elapsed = int(time.time() - self._start_time)
952 elapsed_str = ''
953 if elapsed < 60:
954 elapsed_str = str(elapsed) + 'sec'
955 elif 60 <= elapsed < 3600:
956 elapsed_str = '%dmn%dsec' % (elapsed / 60, elapsed % 60)
957 elif 3600 <= elapsed < 86400:
958 elapsed_str = '%dh%dmn' % (elapsed / 3600, (elapsed % 3600) / 60)
959 elif elapsed >= 86400:
960 elapsed_str = '%dd%dh' % (elapsed / 86400, (elapsed % 86400) / 3600)
961 stats['ElapsedTime'] = elapsed_str
962
963 l = []
964 for ev, value in sorted(stats.items(), key=lambda x: x[0]):
965 l.append(' %s=%s' % (output_format.field_name(ev),
966 output_format.field_value(value)))
967 s = '<%s%s >' % (output_format.class_name(self.__class__.__name__),
968 ''.join(l))
969 return s
970
971 - def dump(self, filename):
972 """
973 Dumps statistics.
974
975 @param filename: filename where stats will be dumped, filename is
976 created and must not exist prior to this call.
977 @type filename: string
978 """
979 flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL
980 fd = os.open(filename, flags, 0600)
981 os.write(fd, str(self))
982 os.close(fd)
983
997 s = '\n'.join(map(func, sorted(stats.items(), key=lambda x: x[0])))
998 return s
999
1002 """
1003 Notifier Exception. Raised on Notifier error.
1004
1005 """
1007 """
1008 @param err: Exception string's description.
1009 @type err: string
1010 """
1011 PyinotifyError.__init__(self, err)
1012
1015 """
1016 Read notifications, process events.
1017
1018 """
1019 - def __init__(self, watch_manager, default_proc_fun=None, read_freq=0,
1020 threshold=0, timeout=None):
1021 """
1022 Initialization. read_freq, threshold and timeout parameters are used
1023 when looping.
1024
1025 @param watch_manager: Watch Manager.
1026 @type watch_manager: WatchManager instance
1027 @param default_proc_fun: Default processing method. If None, a new
1028 instance of PrintAllEvents will be assigned.
1029 @type default_proc_fun: instance of ProcessEvent
1030 @param read_freq: if read_freq == 0, events are read asap,
1031 if read_freq is > 0, this thread sleeps
1032 max(0, read_freq - timeout) seconds. But if
1033 timeout is None it may be different because
1034 poll is blocking waiting for something to read.
1035 @type read_freq: int
1036 @param threshold: File descriptor will be read only if the accumulated
1037 size to read becomes >= threshold. If != 0, you likely
1038 want to use it in combination with an appropriate
1039 value for read_freq because without that you would
1040 keep looping without really reading anything and that
1041 until the amount of events to read is >= threshold.
1042 At least with read_freq set you might sleep.
1043 @type threshold: int
1044 @param timeout:
1045 http://docs.python.org/lib/poll-objects.html#poll-objects
1046 @type timeout: int
1047 """
1048
1049 self._watch_manager = watch_manager
1050
1051 self._fd = self._watch_manager.get_fd()
1052
1053 self._pollobj = select.poll()
1054 self._pollobj.register(self._fd, select.POLLIN)
1055
1056 self._pipe = (-1, -1)
1057
1058 self._eventq = deque()
1059
1060 self._sys_proc_fun = _SysProcessEvent(self._watch_manager, self)
1061
1062 self._default_proc_fun = default_proc_fun
1063 if default_proc_fun is None:
1064 self._default_proc_fun = PrintAllEvents()
1065
1066 self._read_freq = read_freq
1067 self._threshold = threshold
1068 self._timeout = timeout
1069
1070 self._coalesce = False
1071
1072 self._eventset = set()
1073
1075 """
1076 Append a raw event to the event queue.
1077
1078 @param event: An event.
1079 @type event: _RawEvent instance.
1080 """
1081 self._eventq.append(event)
1082
1084 return self._default_proc_fun
1085
1087 """
1088 Coalescing events. Events are usually processed by batchs, their size
1089 depend on various factors. Thus, before processing them, events received
1090 from inotify are aggregated in a fifo queue. If this coalescing
1091 option is enabled events are filtered based on their unicity, only
1092 unique events are enqueued, doublons are discarded. An event is unique
1093 when the combination of its fields (wd, mask, cookie, name) is unique
1094 among events of a same batch. After a batch of events is processed any
1095 events is accepted again. By default this option is disabled, you have
1096 to explictly call this function to turn it on.
1097
1098 @param coalesce: Optional new coalescing value. True by default.
1099 @type coalesce: Bool
1100 """
1101 self._coalesce = coalesce
1102 if not coalesce:
1103 self._eventset.clear()
1104
1106 """
1107 Check for new events available to read, blocks up to timeout
1108 milliseconds.
1109
1110 @param timeout: If specified it overrides the corresponding instance
1111 attribute _timeout.
1112 @type timeout: int
1113
1114 @return: New events to read.
1115 @rtype: bool
1116 """
1117 while True:
1118 try:
1119
1120 if timeout is None:
1121 timeout = self._timeout
1122 ret = self._pollobj.poll(timeout)
1123 except select.error, err:
1124 if err[0] == errno.EINTR:
1125 continue
1126 else:
1127 raise
1128 else:
1129 break
1130
1131 if not ret or (self._pipe[0] == ret[0][0]):
1132 return False
1133
1134 return ret[0][1] & select.POLLIN
1135
1137 """
1138 Read events from device, build _RawEvents, and enqueue them.
1139 """
1140 buf_ = array.array('i', [0])
1141
1142 if fcntl.ioctl(self._fd, termios.FIONREAD, buf_, 1) == -1:
1143 return
1144 queue_size = buf_[0]
1145 if queue_size < self._threshold:
1146 log.debug('(fd: %d) %d bytes available to read but threshold is '
1147 'fixed to %d bytes', self._fd, queue_size,
1148 self._threshold)
1149 return
1150
1151 try:
1152
1153 r = os.read(self._fd, queue_size)
1154 except Exception, msg:
1155 raise NotifierError(msg)
1156 log.debug('Event queue size: %d', queue_size)
1157 rsum = 0
1158 while rsum < queue_size:
1159 s_size = 16
1160
1161 wd, mask, cookie, fname_len = struct.unpack('iIII',
1162 r[rsum:rsum+s_size])
1163
1164 fname, = struct.unpack('%ds' % fname_len,
1165 r[rsum + s_size:rsum + s_size + fname_len])
1166 rawevent = _RawEvent(wd, mask, cookie, fname)
1167 if self._coalesce:
1168
1169 raweventstr = str(rawevent)
1170 if raweventstr not in self._eventset:
1171 self._eventset.add(raweventstr)
1172 self._eventq.append(rawevent)
1173 else:
1174 self._eventq.append(rawevent)
1175 rsum += s_size + fname_len
1176
1178 """
1179 Routine for processing events from queue by calling their
1180 associated proccessing method (an instance of ProcessEvent).
1181 It also does internal processings, to keep the system updated.
1182 """
1183 while self._eventq:
1184 raw_event = self._eventq.popleft()
1185 watch_ = self._watch_manager.get_watch(raw_event.wd)
1186 if watch_ is None:
1187
1188
1189
1190 log.warning("Unable to retrieve Watch object associated to %s",
1191 repr(raw_event))
1192 continue
1193 revent = self._sys_proc_fun(raw_event)
1194 if watch_ and watch_.proc_fun:
1195 watch_.proc_fun(revent)
1196 else:
1197 self._default_proc_fun(revent)
1198 self._sys_proc_fun.cleanup()
1199 if self._coalesce:
1200 self._eventset.clear()
1201
1202 - def __daemonize(self, pid_file=None, stdin=os.devnull, stdout=os.devnull,
1203 stderr=os.devnull):
1204 """
1205 pid_file: file where the pid will be written. If pid_file=None the pid
1206 is written to /var/run/<sys.argv[0]|pyinotify>.pid, if
1207 pid_file=False no pid_file is written.
1208 stdin, stdout, stderr: files associated to common streams.
1209 """
1210 if pid_file is None:
1211 dirname = '/var/run/'
1212 basename = os.path.basename(sys.argv[0]) or 'pyinotify'
1213 pid_file = os.path.join(dirname, basename + '.pid')
1214
1215 if pid_file != False and os.path.lexists(pid_file):
1216 err = 'Cannot daemonize: pid file %s already exists.' % pid_file
1217 raise NotifierError(err)
1218
1219 def fork_daemon():
1220
1221
1222 pid = os.fork()
1223 if (pid == 0):
1224
1225 os.setsid()
1226 pid = os.fork()
1227 if (pid == 0):
1228
1229 os.chdir('/')
1230 os.umask(022)
1231 else:
1232
1233 os._exit(0)
1234 else:
1235
1236 os._exit(0)
1237
1238 fd_inp = os.open(stdin, os.O_RDONLY)
1239 os.dup2(fd_inp, 0)
1240 fd_out = os.open(stdout, os.O_WRONLY|os.O_CREAT, 0600)
1241 os.dup2(fd_out, 1)
1242 fd_err = os.open(stderr, os.O_WRONLY|os.O_CREAT, 0600)
1243 os.dup2(fd_err, 2)
1244
1245
1246 fork_daemon()
1247
1248
1249 if pid_file != False:
1250 flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL
1251 fd_pid = os.open(pid_file, flags, 0600)
1252 os.write(fd_pid, str(os.getpid()) + '\n')
1253 os.close(fd_pid)
1254
1255 atexit.register(lambda : os.unlink(pid_file))
1256
1257
1259
1260 if self._read_freq > 0:
1261 cur_time = time.time()
1262 sleep_amount = self._read_freq - (cur_time - ref_time)
1263 if sleep_amount > 0:
1264 log.debug('Now sleeping %d seconds', sleep_amount)
1265 time.sleep(sleep_amount)
1266
1267
1268 - def loop(self, callback=None, daemonize=False, **args):
1269 """
1270 Events are read only one time every min(read_freq, timeout)
1271 seconds at best and only if the size to read is >= threshold.
1272 After this method returns it must not be called again for the same
1273 instance.
1274
1275 @param callback: Functor called after each event processing iteration.
1276 Expects to receive the notifier object (self) as first
1277 parameter. If this function returns True the loop is
1278 immediately terminated otherwise the loop method keeps
1279 looping.
1280 @type callback: callable object or function
1281 @param daemonize: This thread is daemonized if set to True.
1282 @type daemonize: boolean
1283 @param args: Optional and relevant only if daemonize is True. Remaining
1284 keyworded arguments are directly passed to daemonize see
1285 __daemonize() method. If pid_file=None or is set to a
1286 pathname the caller must ensure the file does not exist
1287 before this method is called otherwise an exception
1288 pyinotify.NotifierError will be raised. If pid_file=False
1289 it is still daemonized but the pid is not written in any
1290 file.
1291 @type args: various
1292 """
1293 if daemonize:
1294 self.__daemonize(**args)
1295
1296
1297 while 1:
1298 try:
1299 self.process_events()
1300 if (callback is not None) and (callback(self) is True):
1301 break
1302 ref_time = time.time()
1303
1304 if self.check_events():
1305 self._sleep(ref_time)
1306 self.read_events()
1307 except KeyboardInterrupt:
1308
1309 log.debug('Pyinotify stops monitoring.')
1310 break
1311
1312 self.stop()
1313
1314
1316 """
1317 Close inotify's instance (close its file descriptor).
1318 It destroys all existing watches, pending events,...
1319 This method is automatically called at the end of loop().
1320 """
1321 self._pollobj.unregister(self._fd)
1322 os.close(self._fd)
1323
1326 """
1327 This notifier inherits from threading.Thread for instanciating a separate
1328 thread, and also inherits from Notifier, because it is a threaded notifier.
1329
1330 Note that every functionality provided by this class is also provided
1331 through Notifier class. Moreover Notifier should be considered first because
1332 it is not threaded and could be easily daemonized.
1333 """
1334 - def __init__(self, watch_manager, default_proc_fun=None, read_freq=0,
1335 threshold=0, timeout=None):
1336 """
1337 Initialization, initialize base classes. read_freq, threshold and
1338 timeout parameters are used when looping.
1339
1340 @param watch_manager: Watch Manager.
1341 @type watch_manager: WatchManager instance
1342 @param default_proc_fun: Default processing method. See base class.
1343 @type default_proc_fun: instance of ProcessEvent
1344 @param read_freq: if read_freq == 0, events are read asap,
1345 if read_freq is > 0, this thread sleeps
1346 max(0, read_freq - timeout) seconds.
1347 @type read_freq: int
1348 @param threshold: File descriptor will be read only if the accumulated
1349 size to read becomes >= threshold. If != 0, you likely
1350 want to use it in combination with an appropriate
1351 value set for read_freq because without that you would
1352 keep looping without really reading anything and that
1353 until the amount of events to read is >= threshold. At
1354 least with read_freq you might sleep.
1355 @type threshold: int
1356 @param timeout:
1357 see http://docs.python.org/lib/poll-objects.html#poll-objects
1358 @type timeout: int
1359 """
1360
1361 threading.Thread.__init__(self)
1362
1363 self._stop_event = threading.Event()
1364
1365 Notifier.__init__(self, watch_manager, default_proc_fun, read_freq,
1366 threshold, timeout)
1367
1368 self._pipe = os.pipe()
1369 self._pollobj.register(self._pipe[0], select.POLLIN)
1370
1372 """
1373 Stop notifier's loop. Stop notification. Join the thread.
1374 """
1375 self._stop_event.set()
1376 os.write(self._pipe[1], 'stop')
1377 threading.Thread.join(self)
1378 Notifier.stop(self)
1379 self._pollobj.unregister(self._pipe[0])
1380 os.close(self._pipe[0])
1381 os.close(self._pipe[1])
1382
1384 """
1385 Thread's main loop. Don't meant to be called by user directly.
1386 Call inherited start() method instead.
1387
1388 Events are read only once time every min(read_freq, timeout)
1389 seconds at best and only if the size of events to read is >= threshold.
1390 """
1391
1392
1393
1394
1395 while not self._stop_event.isSet():
1396 self.process_events()
1397 ref_time = time.time()
1398 if self.check_events():
1399 self._sleep(ref_time)
1400 self.read_events()
1401
1403 """
1404 Start thread's loop: read and process events until the method
1405 stop() is called.
1406 Never call this method directly, instead call the start() method
1407 inherited from threading.Thread, which then will call run() in
1408 its turn.
1409 """
1410 self.loop()
1411
1414 """
1415 This notifier inherits from asyncore.file_dispatcher in order to be able to
1416 use pyinotify along with the asyncore framework.
1417
1418 """
1419 - def __init__(self, watch_manager, default_proc_fun=None, read_freq=0,
1420 threshold=0, timeout=None, channel_map=None):
1421 """
1422 Initializes the async notifier. The only additional parameter is
1423 'channel_map' which is the optional asyncore private map. See
1424 Notifier class for the meaning of the others parameters.
1425
1426 """
1427 Notifier.__init__(self, watch_manager, default_proc_fun, read_freq,
1428 threshold, timeout)
1429 asyncore.file_dispatcher.__init__(self, self._fd, channel_map)
1430
1432 """
1433 When asyncore tells us we can read from the fd, we proceed processing
1434 events. This method can be overridden for handling a notification
1435 differently.
1436
1437 """
1438 self.read_events()
1439 self.process_events()
1440
1443 """
1444 Represent a watch, i.e. a file or directory being watched.
1445
1446 """
1447 - def __init__(self, wd, path, mask, proc_fun, auto_add, exclude_filter):
1448 """
1449 Initializations.
1450
1451 @param wd: Watch descriptor.
1452 @type wd: int
1453 @param path: Path of the file or directory being watched.
1454 @type path: str
1455 @param mask: Mask.
1456 @type mask: int
1457 @param proc_fun: Processing callable object.
1458 @type proc_fun:
1459 @param auto_add: Automatically add watches on new directories.
1460 @type auto_add: bool
1461 @param exclude_filter: Boolean function, used to exclude new
1462 directories from being automatically watched.
1463 See WatchManager.__init__
1464 @type exclude_filter: callable object
1465 """
1466 self.wd = wd
1467 self.path = path
1468 self.mask = mask
1469 self.proc_fun = proc_fun
1470 self.auto_add = auto_add
1471 self.exclude_filter = exclude_filter
1472 self.dir = os.path.isdir(self.path)
1473
1490
1493 """
1494 ExcludeFilter is an exclusion filter.
1495 """
1497 """
1498 Examples:
1499 ef1 = ExcludeFilter(["^/etc/rc.*", "^/etc/hostname"])
1500 ef2 = ExcludeFilter("/my/path/exclude.lst")
1501 Where exclude.lst contains:
1502 ^/etc/rc.*
1503 ^/etc/hostname
1504
1505 @param arg_lst: is either a list of patterns or a filename from which
1506 patterns will be loaded.
1507 @type arg_lst: list of str or str
1508 """
1509 if isinstance(arg_lst, str):
1510 lst = self._load_patterns_from_file(arg_lst)
1511 elif isinstance(arg_lst, list):
1512 lst = arg_lst
1513 else:
1514 raise TypeError
1515
1516 self._lregex = []
1517 for regex in lst:
1518 self._lregex.append(re.compile(regex, re.UNICODE))
1519
1521 lst = []
1522 file_obj = file(filename, 'r')
1523 try:
1524 for line in file_obj.readlines():
1525
1526 pattern = line.strip()
1527 if not pattern or pattern.startswith('#'):
1528 continue
1529 lst.append(pattern)
1530 finally:
1531 file_obj.close()
1532 return lst
1533
1534 - def _match(self, regex, path):
1535 return regex.match(path) is not None
1536
1538 """
1539 @param path: Path to match against provided regexps.
1540 @type path: str
1541 @return: Return True if path has been matched and should
1542 be excluded, False otherwise.
1543 @rtype: bool
1544 """
1545 for regex in self._lregex:
1546 if self._match(regex, path):
1547 return True
1548 return False
1549
1552 """
1553 WatchManager Exception. Raised on error encountered on watches
1554 operations.
1555
1556 """
1558 """
1559 @param msg: Exception string's description.
1560 @type msg: string
1561 @param wmd: This dictionary contains the wd assigned to paths of the
1562 same call for which watches were successfully added.
1563 @type wmd: dict
1564 """
1565 self.wmd = wmd
1566 Exception.__init__(self, msg)
1567
1570 """
1571 Provide operations for watching files and directories. Its internal
1572 dictionary is used to reference watched items. When used inside
1573 threaded code, one must instanciate as many WatchManager instances as
1574 there are ThreadedNotifier instances.
1575
1576 """
1577 - def __init__(self, exclude_filter=lambda path: False):
1578 """
1579 Initialization: init inotify, init watch manager dictionary.
1580 Raise OSError if initialization fails.
1581
1582 @param exclude_filter: boolean function, returns True if current
1583 path must be excluded from being watched.
1584 Convenient for providing a common exclusion
1585 filter for every call to add_watch.
1586 @type exclude_filter: callable object
1587 """
1588 self._exclude_filter = exclude_filter
1589 self._wmd = {}
1590 self._fd = LIBC.inotify_init()
1591 if self._fd < 0:
1592 err = 'Cannot initialize new instance of inotify%s' % strerrno()
1593 raise OSError(err)
1594
1596 """
1597 Close inotify's file descriptor, this action will also automatically
1598 remove (i.e. stop watching) all its associated watch descriptors.
1599 After a call to this method the WatchManager's instance become useless
1600 and cannot be reused, a new instance must then be instanciated. It
1601 makes sense to call this method in few situations for instance if
1602 several independant WatchManager must be instanciated or if all watches
1603 must be removed and no other watches need to be added.
1604 """
1605 os.close(self._fd)
1606
1608 """
1609 Return assigned inotify's file descriptor.
1610
1611 @return: File descriptor.
1612 @rtype: int
1613 """
1614 return self._fd
1615
1617 """
1618 Get watch from provided watch descriptor wd.
1619
1620 @param wd: Watch descriptor.
1621 @type wd: int
1622 """
1623 return self._wmd.get(wd)
1624
1626 """
1627 Remove watch entry associated to watch descriptor wd.
1628
1629 @param wd: Watch descriptor.
1630 @type wd: int
1631 """
1632 try:
1633 del self._wmd[wd]
1634 except KeyError, err:
1635 log.error(str(err))
1636
1637 @property
1639 """
1640 Get a reference on the internal watch manager dictionary.
1641
1642 @return: Internal watch manager dictionary.
1643 @rtype: dict
1644 """
1645 return self._wmd
1646
1659
1660 - def __add_watch(self, path, mask, proc_fun, auto_add, exclude_filter):
1661 """
1662 Add a watch on path, build a Watch object and insert it in the
1663 watch manager dictionary. Return the wd value.
1664 """
1665 byte_path = self.__format_path(path)
1666 wd_ = LIBC.inotify_add_watch(self._fd,
1667 ctypes.create_string_buffer(byte_path),
1668 mask)
1669 if wd_ < 0:
1670 return wd_
1671 watch_ = Watch(wd=wd_, path=byte_path, mask=mask, proc_fun=proc_fun,
1672 auto_add=auto_add, exclude_filter=exclude_filter)
1673 self._wmd[wd_] = watch_
1674 log.debug('New %s', watch_)
1675 return wd_
1676
1677 - def __glob(self, path, do_glob):
1678 if do_glob:
1679 return glob.iglob(path)
1680 else:
1681 return [path]
1682
1683 - def add_watch(self, path, mask, proc_fun=None, rec=False,
1684 auto_add=False, do_glob=False, quiet=True,
1685 exclude_filter=None):
1686 """
1687 Add watch(s) on the provided |path|(s) with associated |mask| flag
1688 value and optionally with a processing |proc_fun| function and
1689 recursive flag |rec| set to True.
1690 Ideally |path| components should not be unicode objects. Note that
1691 although unicode paths are accepted there are converted to byte
1692 strings before a watch is put on that path. The encoding used for
1693 converting the unicode object is given by sys.getfilesystemencoding().
1694 If |path| si already watched it is ignored, but if it is called with
1695 option rec=True a watch is put on each one of its not-watched
1696 subdirectory.
1697
1698 @param path: Path to watch, the path can either be a file or a
1699 directory. Also accepts a sequence (list) of paths.
1700 @type path: string or list of strings
1701 @param mask: Bitmask of events.
1702 @type mask: int
1703 @param proc_fun: Processing object.
1704 @type proc_fun: function or ProcessEvent instance or instance of
1705 one of its subclasses or callable object.
1706 @param rec: Recursively add watches from path on all its
1707 subdirectories, set to False by default (doesn't
1708 follows symlinks in any case).
1709 @type rec: bool
1710 @param auto_add: Automatically add watches on newly created
1711 directories in watched parent |path| directory.
1712 @type auto_add: bool
1713 @param do_glob: Do globbing on pathname (see standard globbing
1714 module for more informations).
1715 @type do_glob: bool
1716 @param quiet: if False raises a WatchManagerError exception on
1717 error. See example not_quiet.py.
1718 @type quiet: bool
1719 @param exclude_filter: predicate (boolean function), which returns
1720 True if the current path must be excluded
1721 from being watched. This argument has
1722 precedence over exclude_filter passed to
1723 the class' constructor.
1724 @type exclude_filter: callable object
1725 @return: dict of paths associated to watch descriptors. A wd value
1726 is positive if the watch was added sucessfully,
1727 otherwise the value is negative. If the path was invalid
1728 or was already watched it is not included into this returned
1729 dictionary.
1730 @rtype: dict of {str: int}
1731 """
1732 ret_ = {}
1733
1734 if exclude_filter is None:
1735 exclude_filter = self._exclude_filter
1736
1737
1738 for npath in self.__format_param(path):
1739
1740 for apath in self.__glob(npath, do_glob):
1741
1742 for rpath in self.__walk_rec(apath, rec):
1743 if self.get_wd(rpath) is not None:
1744
1745
1746
1747 continue
1748 if not exclude_filter(rpath):
1749 wd = ret_[rpath] = self.__add_watch(rpath, mask,
1750 proc_fun,
1751 auto_add,
1752 exclude_filter)
1753 if wd < 0:
1754 err = 'add_watch: cannot watch %s WD=%d%s'
1755 err = err % (rpath, wd, strerrno())
1756 if quiet:
1757 log.error(err)
1758 else:
1759 raise WatchManagerError(err, ret_)
1760 else:
1761
1762
1763 ret_[rpath] = -2
1764 return ret_
1765
1767 """
1768 Get every wd from self._wmd if its path is under the path of
1769 one (at least) of those in lpath. Doesn't follow symlinks.
1770
1771 @param lpath: list of watch descriptor
1772 @type lpath: list of int
1773 @return: list of watch descriptor
1774 @rtype: list of int
1775 """
1776 for d in lpath:
1777 root = self.get_path(d)
1778 if root is not None:
1779
1780 yield d
1781 else:
1782
1783 continue
1784
1785
1786 if not os.path.isdir(root):
1787 continue
1788
1789
1790 root = os.path.normpath(root)
1791
1792 lend = len(root)
1793 for iwd in self._wmd.items():
1794 cur = iwd[1].path
1795 pref = os.path.commonprefix([root, cur])
1796 if root == os.sep or (len(pref) == lend and \
1797 len(cur) > lend and \
1798 cur[lend] == os.sep):
1799 yield iwd[1].wd
1800
1801 - def update_watch(self, wd, mask=None, proc_fun=None, rec=False,
1802 auto_add=False, quiet=True):
1803 """
1804 Update existing watch descriptors |wd|. The |mask| value, the
1805 processing object |proc_fun|, the recursive param |rec| and the
1806 |auto_add| and |quiet| flags can all be updated.
1807
1808 @param wd: Watch Descriptor to update. Also accepts a list of
1809 watch descriptors.
1810 @type wd: int or list of int
1811 @param mask: Optional new bitmask of events.
1812 @type mask: int
1813 @param proc_fun: Optional new processing function.
1814 @type proc_fun: function or ProcessEvent instance or instance of
1815 one of its subclasses or callable object.
1816 @param rec: Optionally adds watches recursively on all
1817 subdirectories contained into |wd| directory.
1818 @type rec: bool
1819 @param auto_add: Automatically adds watches on newly created
1820 directories in the watch's path corresponding to
1821 |wd|.
1822 @type auto_add: bool
1823 @param quiet: If False raises a WatchManagerError exception on
1824 error. See example not_quiet.py
1825 @type quiet: bool
1826 @return: dict of watch descriptors associated to booleans values.
1827 True if the corresponding wd has been successfully
1828 updated, False otherwise.
1829 @rtype: dict of {int: bool}
1830 """
1831 lwd = self.__format_param(wd)
1832 if rec:
1833 lwd = self.__get_sub_rec(lwd)
1834
1835 ret_ = {}
1836 for awd in lwd:
1837 apath = self.get_path(awd)
1838 if not apath or awd < 0:
1839 err = 'update_watch: invalid WD=%d' % awd
1840 if quiet:
1841 log.error(err)
1842 continue
1843 raise WatchManagerError(err, ret_)
1844
1845 if mask:
1846 addw = LIBC.inotify_add_watch
1847 wd_ = addw(self._fd, ctypes.create_string_buffer(apath), mask)
1848 if wd_ < 0:
1849 ret_[awd] = False
1850 err = 'update_watch: cannot update %s WD=%d%s'
1851 err = err % (apath, wd_, strerrno())
1852 if quiet:
1853 log.error(err)
1854 continue
1855 raise WatchManagerError(err, ret_)
1856
1857 assert(awd == wd_)
1858
1859 if proc_fun or auto_add:
1860 watch_ = self._wmd[awd]
1861
1862 if proc_fun:
1863 watch_.proc_fun = proc_fun
1864
1865 if auto_add:
1866 watch_.auto_add = auto_add
1867
1868 ret_[awd] = True
1869 log.debug('Updated watch - %s', self._wmd[awd])
1870 return ret_
1871
1884
1886 """
1887 Returns the watch descriptor associated to path. This method
1888 presents a prohibitive cost, always prefer to keep the WD
1889 returned by add_watch(). If the path is unknown it returns None.
1890
1891 @param path: Path.
1892 @type path: str
1893 @return: WD or None.
1894 @rtype: int or None
1895 """
1896 path = self.__format_path(path)
1897 for iwd in self._wmd.items():
1898 if iwd[1].path == path:
1899 return iwd[0]
1900
1902 """
1903 Returns the path associated to WD, if WD is unknown it returns None.
1904
1905 @param wd: Watch descriptor.
1906 @type wd: int
1907 @return: Path or None.
1908 @rtype: string or None
1909 """
1910 watch_ = self._wmd.get(wd)
1911 if watch_ is not None:
1912 return watch_.path
1913
1915 """
1916 Yields each subdirectories of top, doesn't follow symlinks.
1917 If rec is false, only yield top.
1918
1919 @param top: root directory.
1920 @type top: string
1921 @param rec: recursive flag.
1922 @type rec: bool
1923 @return: path of one subdirectory.
1924 @rtype: string
1925 """
1926 if not rec or os.path.islink(top) or not os.path.isdir(top):
1927 yield top
1928 else:
1929 for root, dirs, files in os.walk(top):
1930 yield root
1931
1932 - def rm_watch(self, wd, rec=False, quiet=True):
1933 """
1934 Removes watch(s).
1935
1936 @param wd: Watch Descriptor of the file or directory to unwatch.
1937 Also accepts a list of WDs.
1938 @type wd: int or list of int.
1939 @param rec: Recursively removes watches on every already watched
1940 subdirectories and subfiles.
1941 @type rec: bool
1942 @param quiet: If False raises a WatchManagerError exception on
1943 error. See example not_quiet.py
1944 @type quiet: bool
1945 @return: dict of watch descriptors associated to booleans values.
1946 True if the corresponding wd has been successfully
1947 removed, False otherwise.
1948 @rtype: dict of {int: bool}
1949 """
1950 lwd = self.__format_param(wd)
1951 if rec:
1952 lwd = self.__get_sub_rec(lwd)
1953
1954 ret_ = {}
1955 for awd in lwd:
1956
1957 wd_ = LIBC.inotify_rm_watch(self._fd, awd)
1958 if wd_ < 0:
1959 ret_[awd] = False
1960 err = 'rm_watch: cannot remove WD=%d%s' % (awd, strerrno())
1961 if quiet:
1962 log.error(err)
1963 continue
1964 raise WatchManagerError(err, ret_)
1965
1966
1967 if awd in self._wmd:
1968 del self._wmd[awd]
1969 ret_[awd] = True
1970 log.debug('Watch WD=%d (%s) removed', awd, self.get_path(awd))
1971 return ret_
1972
1973
1975 """
1976 Watch a transient file, which will be created and deleted frequently
1977 over time (e.g. pid file).
1978
1979 @attention: Currently under the call to this function it is not
1980 possible to correctly watch the events triggered into the same
1981 base directory than the directory where is located this watched
1982 transient file. For instance it would be wrong to make these
1983 two successive calls: wm.watch_transient_file('/var/run/foo.pid', ...)
1984 and wm.add_watch('/var/run/', ...)
1985
1986 @param filename: Filename.
1987 @type filename: string
1988 @param mask: Bitmask of events, should contain IN_CREATE and IN_DELETE.
1989 @type mask: int
1990 @param proc_class: ProcessEvent (or of one of its subclass), beware of
1991 accepting a ProcessEvent's instance as argument into
1992 __init__, see transient_file.py example for more
1993 details.
1994 @type proc_class: ProcessEvent's instance or of one of its subclasses.
1995 @return: Same as add_watch().
1996 @rtype: Same as add_watch().
1997 """
1998 dirname = os.path.dirname(filename)
1999 if dirname == '':
2000 return {}
2001 basename = os.path.basename(filename)
2002
2003 mask |= IN_CREATE | IN_DELETE
2004
2005 def cmp_name(event):
2006 if getattr(event, 'name') is None:
2007 return False
2008 return basename == event.name
2009 return self.add_watch(dirname, mask,
2010 proc_fun=proc_class(ChainIfTrue(func=cmp_name)),
2011 rec=False,
2012 auto_add=False, do_glob=False,
2013 exclude_filter=lambda path: False)
2014
2044
2045 output_format = RawOutputFormat()
2065
2068 """
2069 Use this function to turn on the compatibility mode. The compatibility
2070 mode is used to improve compatibility with Pyinotify 0.7.1 (or older)
2071 programs. The compatibility mode provides additional variables 'is_dir',
2072 'event_name', 'EventsCodes.IN_*' and 'EventsCodes.ALL_EVENTS' as
2073 Pyinotify 0.7.1 provided. Do not call this function from new programs!!
2074 Especially if there are developped for Pyinotify >= 0.8.x.
2075 """
2076 setattr(EventsCodes, 'ALL_EVENTS', ALL_EVENTS)
2077 for evname in globals():
2078 if evname.startswith('IN_'):
2079 setattr(EventsCodes, evname, globals()[evname])
2080 global COMPATIBILITY_MODE
2081 COMPATIBILITY_MODE = True
2082
2085 """
2086 By default the watched path is '/tmp' and all types of events are
2087 monitored. Events monitoring serves forever, type c^c to stop it.
2088 """
2089 from optparse import OptionParser
2090
2091 usage = "usage: %prog [options] [path1] [path2] [pathn]"
2092
2093 parser = OptionParser(usage=usage)
2094 parser.add_option("-v", "--verbose", action="store_true",
2095 dest="verbose", help="Verbose mode")
2096 parser.add_option("-r", "--recursive", action="store_true",
2097 dest="recursive",
2098 help="Add watches recursively on paths")
2099 parser.add_option("-a", "--auto_add", action="store_true",
2100 dest="auto_add",
2101 help="Automatically add watches on new directories")
2102 parser.add_option("-e", "--events-list", metavar="EVENT[,...]",
2103 dest="events_list",
2104 help=("A comma-separated list of events to watch for - "
2105 "see the documentation for valid options (defaults"
2106 " to everything)"))
2107 parser.add_option("-s", "--stats", action="store_true",
2108 dest="stats",
2109 help="Display dummy statistics")
2110 parser.add_option("-V", "--version", action="store_true",
2111 dest="version", help="Pyinotify version")
2112 parser.add_option("-f", "--raw-format", action="store_true",
2113 dest="raw_format",
2114 help="Disable enhanced output format.")
2115
2116 (options, args) = parser.parse_args()
2117
2118 if options.verbose:
2119 log.setLevel(10)
2120
2121 if options.version:
2122 print(__version__)
2123
2124 if not options.raw_format:
2125 global output_format
2126 output_format = ColoredOutputFormat()
2127
2128 if len(args) < 1:
2129 path = '/tmp'
2130 else:
2131 path = args
2132
2133
2134 wm = WatchManager()
2135
2136 if options.stats:
2137 notifier = Notifier(wm, default_proc_fun=Stats(), read_freq=5)
2138 else:
2139 notifier = Notifier(wm, default_proc_fun=PrintAllEvents())
2140
2141
2142 mask = 0
2143 if options.events_list:
2144 events_list = options.events_list.split(',')
2145 for ev in events_list:
2146 evcode = EventsCodes.ALL_FLAGS.get(ev, 0)
2147 if evcode:
2148 mask |= evcode
2149 else:
2150 parser.error("The event '%s' specified with option -e"
2151 " is not valid" % ev)
2152 else:
2153 mask = ALL_EVENTS
2154
2155
2156 cb_fun = None
2157 if options.stats:
2158 def cb(s):
2159 sys.stdout.write(repr(s.proc_fun()))
2160 sys.stdout.write('\n')
2161 sys.stdout.write(str(s.proc_fun()))
2162 sys.stdout.write('\n')
2163 sys.stdout.flush()
2164 cb_fun = cb
2165
2166 log.debug('Start monitoring %s, (press c^c to halt pyinotify)' % path)
2167
2168 wm.add_watch(path, mask, rec=options.recursive, auto_add=options.auto_add)
2169
2170 notifier.loop(callback=cb_fun)
2171
2172
2173 if __name__ == '__main__':
2174 command_line()
2175