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