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 subprocess
72
73 try:
74 from functools import reduce
75 except ImportError:
76 pass
77
78 try:
79 from glob import iglob as glob
80 except ImportError:
81
82 from glob import glob as glob
83
84 try:
85 import ctypes
86 import ctypes.util
87 except ImportError:
88 ctypes = None
89
90 try:
91 import inotify_syscalls
92 except ImportError:
93 inotify_syscalls = None
94
95
96 __author__ = "seb@dbzteam.org (Sebastien Martini)"
97
98 __version__ = "0.9.6"
99
100 __metaclass__ = type
101
102
103
104
105
106 COMPATIBILITY_MODE = False
110 """
111 Raised when no inotify support couldn't be found.
112 """
116
119 """
120 Abstract class wrapping access to inotify's functions. This is an
121 internal class.
122 """
123 @staticmethod
135
137 """
138 Return None is no errno code is available.
139 """
140 return self._get_errno()
141
143 code = self.get_errno()
144 if code is None:
145 return 'Errno: no errno support'
146 return 'Errno=%s (%s)' % (os.strerror(code), errno.errorcode[code])
147
150
156
159
163
164 self._last_errno = None
165
169
171 return self._last_errno
172
180
188
196
200 self._libc = None
201 self._get_errno_func = None
202
204 assert ctypes
205
206 try_libc_name = 'c'
207 if sys.platform.startswith('freebsd'):
208 try_libc_name = 'inotify'
209
210 libc_name = None
211 try:
212 libc_name = ctypes.util.find_library(try_libc_name)
213 except (OSError, IOError):
214 pass
215
216 if sys.version_info >= (2, 6):
217 self._libc = ctypes.CDLL(libc_name, use_errno=True)
218 self._get_errno_func = ctypes.get_errno
219 else:
220 self._libc = ctypes.CDLL(libc_name)
221 try:
222 location = self._libc.__errno_location
223 location.restype = ctypes.POINTER(ctypes.c_int)
224 self._get_errno_func = lambda: location().contents.value
225 except AttributeError:
226 pass
227
228
229 if (not hasattr(self._libc, 'inotify_init') or
230 not hasattr(self._libc, 'inotify_add_watch') or
231 not hasattr(self._libc, 'inotify_rm_watch')):
232 return False
233
234 self._libc.inotify_init.argtypes = []
235 self._libc.inotify_init.restype = ctypes.c_int
236 self._libc.inotify_add_watch.argtypes = [ctypes.c_int, ctypes.c_char_p,
237 ctypes.c_uint32]
238 self._libc.inotify_add_watch.restype = ctypes.c_int
239 self._libc.inotify_rm_watch.argtypes = [ctypes.c_int, ctypes.c_int]
240 self._libc.inotify_rm_watch.restype = ctypes.c_int
241 return True
242
244 if self._get_errno_func is not None:
245 return self._get_errno_func()
246 return None
247
249 assert self._libc is not None
250 return self._libc.inotify_init()
251
253 assert self._libc is not None
254 pathname = ctypes.create_string_buffer(pathname)
255 return self._libc.inotify_add_watch(fd, pathname, mask)
256
260
264 """Initialize logger instance."""
265 log = logging.getLogger("pyinotify")
266 console_handler = logging.StreamHandler()
267 console_handler.setFormatter(
268 logging.Formatter("[%(asctime)s %(name)s %(levelname)s] %(message)s"))
269 log.addHandler(console_handler)
270 log.setLevel(20)
271 return log
272
273 log = logger_init()
278 """
279 Access (read, write) inotify's variables through /proc/sys/. Note that
280 usually it requires administrator rights to update them.
281
282 Examples:
283 - Read max_queued_events attribute: myvar = max_queued_events.value
284 - Update max_queued_events attribute: max_queued_events.value = 42
285 """
287 self._base = "/proc/sys/fs/inotify"
288 self._attr = attr
289
291 """
292 Gets attribute's value.
293
294 @return: stored value.
295 @rtype: int
296 @raise IOError: if corresponding file in /proc/sys cannot be read.
297 """
298 file_obj = file(os.path.join(self._base, self._attr), 'r')
299 try:
300 val = int(file_obj.readline())
301 finally:
302 file_obj.close()
303 return val
304
306 """
307 Sets new attribute's value.
308
309 @param nval: replaces current value by nval.
310 @type nval: int
311 @raise IOError: if corresponding file in /proc/sys cannot be written.
312 """
313 file_obj = file(os.path.join(self._base, self._attr), 'w')
314 try:
315 file_obj.write(str(nval) + '\n')
316 finally:
317 file_obj.close()
318
319 value = property(get_val, set_val)
320
322 return '<%s=%d>' % (self._attr, self.get_val())
323
324
325
326
327
328
329
330
331
332
333
334 for attrname in ('max_queued_events', 'max_user_instances', 'max_user_watches'):
335 globals()[attrname] = ProcINotify(attrname)
339 """
340 Set of codes corresponding to each kind of events.
341 Some of these flags are used to communicate with inotify, whereas
342 the others are sent to userspace by inotify notifying some events.
343
344 @cvar IN_ACCESS: File was accessed.
345 @type IN_ACCESS: int
346 @cvar IN_MODIFY: File was modified.
347 @type IN_MODIFY: int
348 @cvar IN_ATTRIB: Metadata changed.
349 @type IN_ATTRIB: int
350 @cvar IN_CLOSE_WRITE: Writtable file was closed.
351 @type IN_CLOSE_WRITE: int
352 @cvar IN_CLOSE_NOWRITE: Unwrittable file closed.
353 @type IN_CLOSE_NOWRITE: int
354 @cvar IN_OPEN: File was opened.
355 @type IN_OPEN: int
356 @cvar IN_MOVED_FROM: File was moved from X.
357 @type IN_MOVED_FROM: int
358 @cvar IN_MOVED_TO: File was moved to Y.
359 @type IN_MOVED_TO: int
360 @cvar IN_CREATE: Subfile was created.
361 @type IN_CREATE: int
362 @cvar IN_DELETE: Subfile was deleted.
363 @type IN_DELETE: int
364 @cvar IN_DELETE_SELF: Self (watched item itself) was deleted.
365 @type IN_DELETE_SELF: int
366 @cvar IN_MOVE_SELF: Self (watched item itself) was moved.
367 @type IN_MOVE_SELF: int
368 @cvar IN_UNMOUNT: Backing fs was unmounted.
369 @type IN_UNMOUNT: int
370 @cvar IN_Q_OVERFLOW: Event queued overflowed.
371 @type IN_Q_OVERFLOW: int
372 @cvar IN_IGNORED: File was ignored.
373 @type IN_IGNORED: int
374 @cvar IN_ONLYDIR: only watch the path if it is a directory (new
375 in kernel 2.6.15).
376 @type IN_ONLYDIR: int
377 @cvar IN_DONT_FOLLOW: don't follow a symlink (new in kernel 2.6.15).
378 IN_ONLYDIR we can make sure that we don't watch
379 the target of symlinks.
380 @type IN_DONT_FOLLOW: int
381 @cvar IN_EXCL_UNLINK: Events are not generated for children after they
382 have been unlinked from the watched directory.
383 (new in kernel 2.6.36).
384 @type IN_EXCL_UNLINK: int
385 @cvar IN_MASK_ADD: add to the mask of an already existing watch (new
386 in kernel 2.6.14).
387 @type IN_MASK_ADD: int
388 @cvar IN_ISDIR: Event occurred against dir.
389 @type IN_ISDIR: int
390 @cvar IN_ONESHOT: Only send event once.
391 @type IN_ONESHOT: int
392 @cvar ALL_EVENTS: Alias for considering all of the events.
393 @type ALL_EVENTS: int
394 """
395
396
397
398
399 FLAG_COLLECTIONS = {'OP_FLAGS': {
400 'IN_ACCESS' : 0x00000001,
401 'IN_MODIFY' : 0x00000002,
402 'IN_ATTRIB' : 0x00000004,
403 'IN_CLOSE_WRITE' : 0x00000008,
404 'IN_CLOSE_NOWRITE' : 0x00000010,
405 'IN_OPEN' : 0x00000020,
406 'IN_MOVED_FROM' : 0x00000040,
407 'IN_MOVED_TO' : 0x00000080,
408 'IN_CREATE' : 0x00000100,
409 'IN_DELETE' : 0x00000200,
410 'IN_DELETE_SELF' : 0x00000400,
411
412 'IN_MOVE_SELF' : 0x00000800,
413 },
414 'EVENT_FLAGS': {
415 'IN_UNMOUNT' : 0x00002000,
416 'IN_Q_OVERFLOW' : 0x00004000,
417 'IN_IGNORED' : 0x00008000,
418 },
419 'SPECIAL_FLAGS': {
420 'IN_ONLYDIR' : 0x01000000,
421
422 'IN_DONT_FOLLOW' : 0x02000000,
423 'IN_EXCL_UNLINK' : 0x04000000,
424 'IN_MASK_ADD' : 0x20000000,
425
426 'IN_ISDIR' : 0x40000000,
427 'IN_ONESHOT' : 0x80000000,
428 },
429 }
430
432 """
433 Returns the event name associated to mask. IN_ISDIR is appended to
434 the result when appropriate. Note: only one event is returned, because
435 only one event can be raised at a given time.
436
437 @param mask: mask.
438 @type mask: int
439 @return: event name.
440 @rtype: str
441 """
442 ms = mask
443 name = '%s'
444 if mask & IN_ISDIR:
445 ms = mask - IN_ISDIR
446 name = '%s|IN_ISDIR'
447 return name % EventsCodes.ALL_VALUES[ms]
448
449 maskname = staticmethod(maskname)
450
451
452
453 EventsCodes.ALL_FLAGS = {}
454 EventsCodes.ALL_VALUES = {}
455 for flagc, valc in EventsCodes.FLAG_COLLECTIONS.items():
456
457
458 setattr(EventsCodes, flagc, valc)
459
460
461 EventsCodes.ALL_FLAGS.update(valc)
462
463
464
465 for name, val in valc.items():
466 globals()[name] = val
467 EventsCodes.ALL_VALUES[val] = name
468
469
470
471 ALL_EVENTS = reduce(lambda x, y: x | y, EventsCodes.OP_FLAGS.values())
472 EventsCodes.ALL_FLAGS['ALL_EVENTS'] = ALL_EVENTS
473 EventsCodes.ALL_VALUES[ALL_EVENTS] = 'ALL_EVENTS'
477 """
478 Event structure, represent events raised by the system. This
479 is the base class and should be subclassed.
480
481 """
483 """
484 Attach attributes (contained in dict_) to self.
485
486 @param dict_: Set of attributes.
487 @type dict_: dictionary
488 """
489 for tpl in dict_.items():
490 setattr(self, *tpl)
491
514
517
520 """
521 Raw event, it contains only the informations provided by the system.
522 It doesn't infer anything.
523 """
524 - def __init__(self, wd, mask, cookie, name):
525 """
526 @param wd: Watch Descriptor.
527 @type wd: int
528 @param mask: Bitmask of events.
529 @type mask: int
530 @param cookie: Cookie.
531 @type cookie: int
532 @param name: Basename of the file or directory against which the
533 event was raised in case where the watched directory
534 is the parent directory. None if the event was raised
535 on the watched item itself.
536 @type name: string or None
537 """
538
539
540 self._str = None
541
542 d = {'wd': wd,
543 'mask': mask,
544 'cookie': cookie,
545 'name': name.rstrip('\0')}
546 _Event.__init__(self, d)
547 log.debug(str(self))
548
550 if self._str is None:
551 self._str = _Event.__str__(self)
552 return self._str
553
556 """
557 This class contains all the useful informations about the observed
558 event. However, the presence of each field is not guaranteed and
559 depends on the type of event. In effect, some fields are irrelevant
560 for some kind of event (for example 'cookie' is meaningless for
561 IN_CREATE whereas it is mandatory for IN_MOVE_TO).
562
563 The possible fields are:
564 - wd (int): Watch Descriptor.
565 - mask (int): Mask.
566 - maskname (str): Readable event name.
567 - path (str): path of the file or directory being watched.
568 - name (str): Basename of the file or directory against which the
569 event was raised in case where the watched directory
570 is the parent directory. None if the event was raised
571 on the watched item itself. This field is always provided
572 even if the string is ''.
573 - pathname (str): Concatenation of 'path' and 'name'.
574 - src_pathname (str): Only present for IN_MOVED_TO events and only in
575 the case where IN_MOVED_FROM events are watched too. Holds the
576 source pathname from where pathname was moved from.
577 - cookie (int): Cookie.
578 - dir (bool): True if the event was raised against a directory.
579
580 """
599
602 """
603 ProcessEventError Exception. Raised on ProcessEvent error.
604 """
606 """
607 @param err: Exception error description.
608 @type err: string
609 """
610 PyinotifyError.__init__(self, err)
611
614 """
615 Abstract processing event class.
616 """
618 """
619 To behave like a functor the object must be callable.
620 This method is a dispatch method. Its lookup order is:
621 1. process_MASKNAME method
622 2. process_FAMILY_NAME method
623 3. otherwise calls process_default
624
625 @param event: Event to be processed.
626 @type event: Event object
627 @return: By convention when used from the ProcessEvent class:
628 - Returning False or None (default value) means keep on
629 executing next chained functors (see chain.py example).
630 - Returning True instead means do not execute next
631 processing functions.
632 @rtype: bool
633 @raise ProcessEventError: Event object undispatchable,
634 unknown event.
635 """
636 stripped_mask = event.mask - (event.mask & IN_ISDIR)
637 maskname = EventsCodes.ALL_VALUES.get(stripped_mask)
638 if maskname is None:
639 raise ProcessEventError("Unknown mask 0x%08x" % stripped_mask)
640
641
642 meth = getattr(self, 'process_' + maskname, None)
643 if meth is not None:
644 return meth(event)
645
646 meth = getattr(self, 'process_IN_' + maskname.split('_')[1], None)
647 if meth is not None:
648 return meth(event)
649
650 return self.process_default(event)
651
653 return '<%s>' % self.__class__.__name__
654
657 """
658 There is three kind of processing according to each event:
659
660 1. special handling (deletion from internal container, bug, ...).
661 2. default treatment: which is applied to the majority of events.
662 3. IN_ISDIR is never sent alone, he is piggybacked with a standard
663 event, he is not processed as the others events, instead, its
664 value is captured and appropriately aggregated to dst event.
665 """
667 """
668
669 @param wm: Watch Manager.
670 @type wm: WatchManager instance
671 @param notifier: Notifier.
672 @type notifier: Notifier instance
673 """
674 self._watch_manager = wm
675 self._notifier = notifier
676 self._mv_cookie = {}
677 self._mv = {}
678
680 """
681 Cleanup (delete) old (>1mn) records contained in self._mv_cookie
682 and self._mv.
683 """
684 date_cur_ = datetime.now()
685 for seq in [self._mv_cookie, self._mv]:
686 for k in seq.keys():
687 if (date_cur_ - seq[k][1]) > timedelta(minutes=1):
688 log.debug('Cleanup: deleting entry %s', seq[k][0])
689 del seq[k]
690
692 """
693 If the event affects a directory and the auto_add flag of the
694 targetted watch is set to True, a new watch is added on this
695 new directory, with the same attribute values than those of
696 this watch.
697 """
698 if raw_event.mask & IN_ISDIR:
699 watch_ = self._watch_manager.get_watch(raw_event.wd)
700 created_dir = os.path.join(watch_.path, raw_event.name)
701 if watch_.auto_add and not watch_.exclude_filter(created_dir):
702 addw = self._watch_manager.add_watch
703
704
705 addw_ret = addw(created_dir, watch_.mask,
706 proc_fun=watch_.proc_fun,
707 rec=False, auto_add=watch_.auto_add,
708 exclude_filter=watch_.exclude_filter)
709
710
711
712
713
714 created_dir_wd = addw_ret.get(created_dir)
715 if ((created_dir_wd is not None) and (created_dir_wd > 0) and
716 os.path.isdir(created_dir)):
717 try:
718 for name in os.listdir(created_dir):
719 inner = os.path.join(created_dir, name)
720 if self._watch_manager.get_wd(inner) is not None:
721 continue
722
723
724 if os.path.isfile(inner):
725
726 flags = IN_CREATE
727 elif os.path.isdir(inner):
728 flags = IN_CREATE | IN_ISDIR
729 else:
730
731 continue
732 rawevent = _RawEvent(created_dir_wd, flags, 0, name)
733 self._notifier.append_event(rawevent)
734 except OSError, err:
735 msg = "process_IN_CREATE, invalid directory %s: %s"
736 log.debug(msg % (created_dir, str(err)))
737 return self.process_default(raw_event)
738
740 """
741 Map the cookie with the source path (+ date for cleaning).
742 """
743 watch_ = self._watch_manager.get_watch(raw_event.wd)
744 path_ = watch_.path
745 src_path = os.path.normpath(os.path.join(path_, raw_event.name))
746 self._mv_cookie[raw_event.cookie] = (src_path, datetime.now())
747 return self.process_default(raw_event, {'cookie': raw_event.cookie})
748
750 """
751 Map the source path with the destination path (+ date for
752 cleaning).
753 """
754 watch_ = self._watch_manager.get_watch(raw_event.wd)
755 path_ = watch_.path
756 dst_path = os.path.normpath(os.path.join(path_, raw_event.name))
757 mv_ = self._mv_cookie.get(raw_event.cookie)
758 to_append = {'cookie': raw_event.cookie}
759 if mv_ is not None:
760 self._mv[mv_[0]] = (dst_path, datetime.now())
761
762
763
764
765
766 to_append['src_pathname'] = mv_[0]
767 elif (raw_event.mask & IN_ISDIR and watch_.auto_add and
768 not watch_.exclude_filter(dst_path)):
769
770
771
772
773 self._watch_manager.add_watch(dst_path, watch_.mask,
774 proc_fun=watch_.proc_fun,
775 rec=True, auto_add=True,
776 exclude_filter=watch_.exclude_filter)
777 return self.process_default(raw_event, to_append)
778
780 """
781 STATUS: the following bug has been fixed in recent kernels (FIXME:
782 which version ?). Now it raises IN_DELETE_SELF instead.
783
784 Old kernels were bugged, this event raised when the watched item
785 were moved, so we had to update its path, but under some circumstances
786 it was impossible: if its parent directory and its destination
787 directory wasn't watched. The kernel (see include/linux/fsnotify.h)
788 doesn't bring us enough informations like the destination path of
789 moved items.
790 """
791 watch_ = self._watch_manager.get_watch(raw_event.wd)
792 src_path = watch_.path
793 mv_ = self._mv.get(src_path)
794 if mv_:
795 dest_path = mv_[0]
796 watch_.path = dest_path
797
798
799 src_path += os.path.sep
800 src_path_len = len(src_path)
801
802
803
804 for w in self._watch_manager.watches.values():
805 if w.path.startswith(src_path):
806
807 w.path = os.path.join(dest_path, w.path[src_path_len:])
808 else:
809 log.error("The pathname '%s' of this watch %s has probably changed "
810 "and couldn't be updated, so it cannot be trusted "
811 "anymore. To fix this error move directories/files only "
812 "between watched parents directories, in this case e.g. "
813 "put a watch on '%s'.",
814 watch_.path, watch_,
815 os.path.normpath(os.path.join(watch_.path,
816 os.path.pardir)))
817 if not watch_.path.endswith('-unknown-path'):
818 watch_.path += '-unknown-path'
819 return self.process_default(raw_event)
820
822 """
823 Only signal an overflow, most of the common flags are irrelevant
824 for this event (path, wd, name).
825 """
826 return Event({'mask': raw_event.mask})
827
829 """
830 The watch descriptor raised by this event is now ignored (forever),
831 it can be safely deleted from the watch manager dictionary.
832 After this event we can be sure that neither the event queue nor
833 the system will raise an event associated to this wd again.
834 """
835 event_ = self.process_default(raw_event)
836 self._watch_manager.del_watch(raw_event.wd)
837 return event_
838
840 """
841 Commons handling for the followings events:
842
843 IN_ACCESS, IN_MODIFY, IN_ATTRIB, IN_CLOSE_WRITE, IN_CLOSE_NOWRITE,
844 IN_OPEN, IN_DELETE, IN_DELETE_SELF, IN_UNMOUNT.
845 """
846 watch_ = self._watch_manager.get_watch(raw_event.wd)
847 if raw_event.mask & (IN_DELETE_SELF | IN_MOVE_SELF):
848
849 dir_ = watch_.dir
850 else:
851 dir_ = bool(raw_event.mask & IN_ISDIR)
852 dict_ = {'wd': raw_event.wd,
853 'mask': raw_event.mask,
854 'path': watch_.path,
855 'name': raw_event.name,
856 'dir': dir_}
857 if COMPATIBILITY_MODE:
858 dict_['is_dir'] = dir_
859 if to_append is not None:
860 dict_.update(to_append)
861 return Event(dict_)
862
865 """
866 Process events objects, can be specialized via subclassing, thus its
867 behavior can be overriden:
868
869 Note: you should not override __init__ in your subclass instead define
870 a my_init() method, this method will be called automatically from the
871 constructor of this class with its optionals parameters.
872
873 1. Provide specialized individual methods, e.g. process_IN_DELETE for
874 processing a precise type of event (e.g. IN_DELETE in this case).
875 2. Or/and provide methods for processing events by 'family', e.g.
876 process_IN_CLOSE method will process both IN_CLOSE_WRITE and
877 IN_CLOSE_NOWRITE events (if process_IN_CLOSE_WRITE and
878 process_IN_CLOSE_NOWRITE aren't defined though).
879 3. Or/and override process_default for catching and processing all
880 the remaining types of events.
881 """
882 pevent = None
883
884 - def __init__(self, pevent=None, **kargs):
885 """
886 Enable chaining of ProcessEvent instances.
887
888 @param pevent: Optional callable object, will be called on event
889 processing (before self).
890 @type pevent: callable
891 @param kargs: This constructor is implemented as a template method
892 delegating its optionals keyworded arguments to the
893 method my_init().
894 @type kargs: dict
895 """
896 self.pevent = pevent
897 self.my_init(**kargs)
898
900 """
901 This method is called from ProcessEvent.__init__(). This method is
902 empty here and must be redefined to be useful. In effect, if you
903 need to specifically initialize your subclass' instance then you
904 just have to override this method in your subclass. Then all the
905 keyworded arguments passed to ProcessEvent.__init__() will be
906 transmitted as parameters to this method. Beware you MUST pass
907 keyword arguments though.
908
909 @param kargs: optional delegated arguments from __init__().
910 @type kargs: dict
911 """
912 pass
913
915 stop_chaining = False
916 if self.pevent is not None:
917
918
919
920
921
922 stop_chaining = self.pevent(event)
923 if not stop_chaining:
924 return _ProcessEvent.__call__(self, event)
925
928
930 """
931 By default this method only reports warning messages, you can overredide
932 it by subclassing ProcessEvent and implement your own
933 process_IN_Q_OVERFLOW method. The actions you can take on receiving this
934 event is either to update the variable max_queued_events in order to
935 handle more simultaneous events or to modify your code in order to
936 accomplish a better filtering diminishing the number of raised events.
937 Because this method is defined, IN_Q_OVERFLOW will never get
938 transmitted as arguments to process_default calls.
939
940 @param event: IN_Q_OVERFLOW event.
941 @type event: dict
942 """
943 log.warning('Event queue overflowed.')
944
946 """
947 Default processing event method. By default does nothing. Subclass
948 ProcessEvent and redefine this method in order to modify its behavior.
949
950 @param event: Event to be processed. Can be of any type of events but
951 IN_Q_OVERFLOW events (see method process_IN_Q_OVERFLOW).
952 @type event: Event instance
953 """
954 pass
955
958 """
959 Dummy class used to print events strings representations. For instance this
960 class is used from command line to print all received events to stdout.
961 """
963 """
964 @param out: Where events will be written.
965 @type out: Object providing a valid file object interface.
966 """
967 if out is None:
968 out = sys.stdout
969 self._out = out
970
972 """
973 Writes event string representation to file object provided to
974 my_init().
975
976 @param event: Event to be processed. Can be of any type of events but
977 IN_Q_OVERFLOW events (see method process_IN_Q_OVERFLOW).
978 @type event: Event instance
979 """
980 self._out.write(str(event))
981 self._out.write('\n')
982 self._out.flush()
983
986 """
987 Makes conditional chaining depending on the result of the nested
988 processing instance.
989 """
991 """
992 Method automatically called from base class constructor.
993 """
994 self._func = func
995
997 return not self._func(event)
998
999
1000 -class Stats(ProcessEvent):
1001 """
1002 Compute and display trivial statistics about processed events.
1003 """
1005 """
1006 Method automatically called from base class constructor.
1007 """
1008 self._start_time = time.time()
1009 self._stats = {}
1010 self._stats_lock = threading.Lock()
1011
1013 """
1014 Processes |event|.
1015 """
1016 self._stats_lock.acquire()
1017 try:
1018 events = event.maskname.split('|')
1019 for event_name in events:
1020 count = self._stats.get(event_name, 0)
1021 self._stats[event_name] = count + 1
1022 finally:
1023 self._stats_lock.release()
1024
1026 self._stats_lock.acquire()
1027 try:
1028 return self._stats.copy()
1029 finally:
1030 self._stats_lock.release()
1031
1033 stats = self._stats_copy()
1034
1035 elapsed = int(time.time() - self._start_time)
1036 elapsed_str = ''
1037 if elapsed < 60:
1038 elapsed_str = str(elapsed) + 'sec'
1039 elif 60 <= elapsed < 3600:
1040 elapsed_str = '%dmn%dsec' % (elapsed / 60, elapsed % 60)
1041 elif 3600 <= elapsed < 86400:
1042 elapsed_str = '%dh%dmn' % (elapsed / 3600, (elapsed % 3600) / 60)
1043 elif elapsed >= 86400:
1044 elapsed_str = '%dd%dh' % (elapsed / 86400, (elapsed % 86400) / 3600)
1045 stats['ElapsedTime'] = elapsed_str
1046
1047 l = []
1048 for ev, value in sorted(stats.items(), key=lambda x: x[0]):
1049 l.append(' %s=%s' % (output_format.field_name(ev),
1050 output_format.field_value(value)))
1051 s = '<%s%s >' % (output_format.class_name(self.__class__.__name__),
1052 ''.join(l))
1053 return s
1054
1055 - def dump(self, filename):
1056 """
1057 Dumps statistics.
1058
1059 @param filename: filename where stats will be dumped, filename is
1060 created and must not exist prior to this call.
1061 @type filename: string
1062 """
1063 flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL
1064 fd = os.open(filename, flags, 0600)
1065 os.write(fd, str(self))
1066 os.close(fd)
1067
1081 s = '\n'.join(map(func, sorted(stats.items(), key=lambda x: x[0])))
1082 return s
1083
1086 """
1087 Notifier Exception. Raised on Notifier error.
1088
1089 """
1091 """
1092 @param err: Exception string's description.
1093 @type err: string
1094 """
1095 PyinotifyError.__init__(self, err)
1096
1099 """
1100 Read notifications, process events.
1101
1102 """
1103 - def __init__(self, watch_manager, default_proc_fun=None, read_freq=0,
1104 threshold=0, timeout=None):
1105 """
1106 Initialization. read_freq, threshold and timeout parameters are used
1107 when looping.
1108
1109 @param watch_manager: Watch Manager.
1110 @type watch_manager: WatchManager instance
1111 @param default_proc_fun: Default processing method. If None, a new
1112 instance of PrintAllEvents will be assigned.
1113 @type default_proc_fun: instance of ProcessEvent
1114 @param read_freq: if read_freq == 0, events are read asap,
1115 if read_freq is > 0, this thread sleeps
1116 max(0, read_freq - (timeout / 1000)) seconds. But
1117 if timeout is None it may be different because
1118 poll is blocking waiting for something to read.
1119 @type read_freq: int
1120 @param threshold: File descriptor will be read only if the accumulated
1121 size to read becomes >= threshold. If != 0, you likely
1122 want to use it in combination with an appropriate
1123 value for read_freq because without that you would
1124 keep looping without really reading anything and that
1125 until the amount of events to read is >= threshold.
1126 At least with read_freq set you might sleep.
1127 @type threshold: int
1128 @param timeout: see read_freq above. If provided, it must be set in
1129 milliseconds. See
1130 https://docs.python.org/2/library/select.html#polling-objects
1131 @type timeout: int
1132 """
1133
1134 self._watch_manager = watch_manager
1135
1136 self._fd = self._watch_manager.get_fd()
1137
1138 self._pollobj = select.poll()
1139 self._pollobj.register(self._fd, select.POLLIN)
1140
1141 self._pipe = (-1, -1)
1142
1143 self._eventq = deque()
1144
1145 self._sys_proc_fun = _SysProcessEvent(self._watch_manager, self)
1146
1147 self._default_proc_fun = default_proc_fun
1148 if default_proc_fun is None:
1149 self._default_proc_fun = PrintAllEvents()
1150
1151 self._read_freq = read_freq
1152 self._threshold = threshold
1153 self._timeout = timeout
1154
1155 self._coalesce = False
1156
1157 self._eventset = set()
1158
1160 """
1161 Append a raw event to the event queue.
1162
1163 @param event: An event.
1164 @type event: _RawEvent instance.
1165 """
1166 self._eventq.append(event)
1167
1169 return self._default_proc_fun
1170
1172 """
1173 Coalescing events. Events are usually processed by batchs, their size
1174 depend on various factors. Thus, before processing them, events received
1175 from inotify are aggregated in a fifo queue. If this coalescing
1176 option is enabled events are filtered based on their unicity, only
1177 unique events are enqueued, doublons are discarded. An event is unique
1178 when the combination of its fields (wd, mask, cookie, name) is unique
1179 among events of a same batch. After a batch of events is processed any
1180 events is accepted again. By default this option is disabled, you have
1181 to explictly call this function to turn it on.
1182
1183 @param coalesce: Optional new coalescing value. True by default.
1184 @type coalesce: Bool
1185 """
1186 self._coalesce = coalesce
1187 if not coalesce:
1188 self._eventset.clear()
1189
1191 """
1192 Check for new events available to read, blocks up to timeout
1193 milliseconds.
1194
1195 @param timeout: If specified it overrides the corresponding instance
1196 attribute _timeout. timeout must be sepcified in
1197 milliseconds.
1198 @type timeout: int
1199
1200 @return: New events to read.
1201 @rtype: bool
1202 """
1203 while True:
1204 try:
1205
1206 if timeout is None:
1207 timeout = self._timeout
1208 ret = self._pollobj.poll(timeout)
1209 except select.error, err:
1210 if err[0] == errno.EINTR:
1211 continue
1212 else:
1213 raise
1214 else:
1215 break
1216
1217 if not ret or (self._pipe[0] == ret[0][0]):
1218 return False
1219
1220 return ret[0][1] & select.POLLIN
1221
1223 """
1224 Read events from device, build _RawEvents, and enqueue them.
1225 """
1226 buf_ = array.array('i', [0])
1227
1228 if fcntl.ioctl(self._fd, termios.FIONREAD, buf_, 1) == -1:
1229 return
1230 queue_size = buf_[0]
1231 if queue_size < self._threshold:
1232 log.debug('(fd: %d) %d bytes available to read but threshold is '
1233 'fixed to %d bytes', self._fd, queue_size,
1234 self._threshold)
1235 return
1236
1237 try:
1238
1239 r = os.read(self._fd, queue_size)
1240 except Exception, msg:
1241 raise NotifierError(msg)
1242 log.debug('Event queue size: %d', queue_size)
1243 rsum = 0
1244 while rsum < queue_size:
1245 s_size = 16
1246
1247 wd, mask, cookie, fname_len = struct.unpack('iIII',
1248 r[rsum:rsum+s_size])
1249
1250 fname, = struct.unpack('%ds' % fname_len,
1251 r[rsum + s_size:rsum + s_size + fname_len])
1252 rawevent = _RawEvent(wd, mask, cookie, fname)
1253 if self._coalesce:
1254
1255 raweventstr = str(rawevent)
1256 if raweventstr not in self._eventset:
1257 self._eventset.add(raweventstr)
1258 self._eventq.append(rawevent)
1259 else:
1260 self._eventq.append(rawevent)
1261 rsum += s_size + fname_len
1262
1264 """
1265 Routine for processing events from queue by calling their
1266 associated proccessing method (an instance of ProcessEvent).
1267 It also does internal processings, to keep the system updated.
1268 """
1269 while self._eventq:
1270 raw_event = self._eventq.popleft()
1271 if self._watch_manager.ignore_events:
1272 log.debug("Event ignored: %s" % repr(raw_event))
1273 continue
1274 watch_ = self._watch_manager.get_watch(raw_event.wd)
1275 if (watch_ is None) and not (raw_event.mask & IN_Q_OVERFLOW):
1276 if not (raw_event.mask & IN_IGNORED):
1277
1278
1279
1280 log.warning("Unable to retrieve Watch object associated to %s",
1281 repr(raw_event))
1282 continue
1283 revent = self._sys_proc_fun(raw_event)
1284 if watch_ and watch_.proc_fun:
1285 watch_.proc_fun(revent)
1286 else:
1287 self._default_proc_fun(revent)
1288 self._sys_proc_fun.cleanup()
1289 if self._coalesce:
1290 self._eventset.clear()
1291
1292 - def __daemonize(self, pid_file=None, stdin=os.devnull, stdout=os.devnull,
1293 stderr=os.devnull):
1294 """
1295 @param pid_file: file where the pid will be written. If pid_file=None
1296 the pid is written to
1297 /var/run/<sys.argv[0]|pyinotify>.pid, if pid_file=False
1298 no pid_file is written.
1299 @param stdin:
1300 @param stdout:
1301 @param stderr: files associated to common streams.
1302 """
1303 if pid_file is None:
1304 dirname = '/var/run/'
1305 basename = os.path.basename(sys.argv[0]) or 'pyinotify'
1306 pid_file = os.path.join(dirname, basename + '.pid')
1307
1308 if pid_file != False and os.path.lexists(pid_file):
1309 err = 'Cannot daemonize: pid file %s already exists.' % pid_file
1310 raise NotifierError(err)
1311
1312 def fork_daemon():
1313
1314
1315 pid = os.fork()
1316 if (pid == 0):
1317
1318 os.setsid()
1319 pid = os.fork()
1320 if (pid == 0):
1321
1322 os.chdir('/')
1323 os.umask(022)
1324 else:
1325
1326 os._exit(0)
1327 else:
1328
1329 os._exit(0)
1330
1331 fd_inp = os.open(stdin, os.O_RDONLY)
1332 os.dup2(fd_inp, 0)
1333 fd_out = os.open(stdout, os.O_WRONLY|os.O_CREAT, 0600)
1334 os.dup2(fd_out, 1)
1335 fd_err = os.open(stderr, os.O_WRONLY|os.O_CREAT, 0600)
1336 os.dup2(fd_err, 2)
1337
1338
1339 fork_daemon()
1340
1341
1342 if pid_file != False:
1343 flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL
1344 fd_pid = os.open(pid_file, flags, 0600)
1345 os.write(fd_pid, str(os.getpid()) + '\n')
1346 os.close(fd_pid)
1347
1348 atexit.register(lambda : os.unlink(pid_file))
1349
1351
1352 if self._read_freq > 0:
1353 cur_time = time.time()
1354 sleep_amount = self._read_freq - (cur_time - ref_time)
1355 if sleep_amount > 0:
1356 log.debug('Now sleeping %d seconds', sleep_amount)
1357 time.sleep(sleep_amount)
1358
1359 - def loop(self, callback=None, daemonize=False, **args):
1360 """
1361 Events are read only one time every min(read_freq, timeout)
1362 seconds at best and only if the size to read is >= threshold.
1363 After this method returns it must not be called again for the same
1364 instance.
1365
1366 @param callback: Functor called after each event processing iteration.
1367 Expects to receive the notifier object (self) as first
1368 parameter. If this function returns True the loop is
1369 immediately terminated otherwise the loop method keeps
1370 looping.
1371 @type callback: callable object or function
1372 @param daemonize: This thread is daemonized if set to True.
1373 @type daemonize: boolean
1374 @param args: Optional and relevant only if daemonize is True. Remaining
1375 keyworded arguments are directly passed to daemonize see
1376 __daemonize() method. If pid_file=None or is set to a
1377 pathname the caller must ensure the file does not exist
1378 before this method is called otherwise an exception
1379 pyinotify.NotifierError will be raised. If pid_file=False
1380 it is still daemonized but the pid is not written in any
1381 file.
1382 @type args: various
1383 """
1384 if daemonize:
1385 self.__daemonize(**args)
1386
1387
1388 while 1:
1389 try:
1390 self.process_events()
1391 if (callback is not None) and (callback(self) is True):
1392 break
1393 ref_time = time.time()
1394
1395 if self.check_events():
1396 self._sleep(ref_time)
1397 self.read_events()
1398 except KeyboardInterrupt:
1399
1400 log.debug('Pyinotify stops monitoring.')
1401 break
1402
1403 self.stop()
1404
1406 """
1407 Close inotify's instance (close its file descriptor).
1408 It destroys all existing watches, pending events,...
1409 This method is automatically called at the end of loop().
1410 Afterward it is invalid to access this instance.
1411 """
1412 if self._fd is not None:
1413 self._pollobj.unregister(self._fd)
1414 os.close(self._fd)
1415 self._fd = None
1416 self._sys_proc_fun = None
1417
1420 """
1421 This notifier inherits from threading.Thread for instanciating a separate
1422 thread, and also inherits from Notifier, because it is a threaded notifier.
1423
1424 Note that every functionality provided by this class is also provided
1425 through Notifier class. Moreover Notifier should be considered first because
1426 it is not threaded and could be easily daemonized.
1427 """
1428 - def __init__(self, watch_manager, default_proc_fun=None, read_freq=0,
1429 threshold=0, timeout=None):
1430 """
1431 Initialization, initialize base classes. read_freq, threshold and
1432 timeout parameters are used when looping.
1433
1434 @param watch_manager: Watch Manager.
1435 @type watch_manager: WatchManager instance
1436 @param default_proc_fun: Default processing method. See base class.
1437 @type default_proc_fun: instance of ProcessEvent
1438 @param read_freq: if read_freq == 0, events are read asap,
1439 if read_freq is > 0, this thread sleeps
1440 max(0, read_freq - (timeout / 1000)) seconds.
1441 @type read_freq: int
1442 @param threshold: File descriptor will be read only if the accumulated
1443 size to read becomes >= threshold. If != 0, you likely
1444 want to use it in combination with an appropriate
1445 value set for read_freq because without that you would
1446 keep looping without really reading anything and that
1447 until the amount of events to read is >= threshold. At
1448 least with read_freq you might sleep.
1449 @type threshold: int
1450 @param timeout: see read_freq above. If provided, it must be set in
1451 milliseconds. See
1452 https://docs.python.org/2/library/select.html#select.poll.poll
1453 @type timeout: int
1454 """
1455
1456 threading.Thread.__init__(self)
1457
1458 self._stop_event = threading.Event()
1459
1460 Notifier.__init__(self, watch_manager, default_proc_fun, read_freq,
1461 threshold, timeout)
1462
1463 self._pipe = os.pipe()
1464 self._pollobj.register(self._pipe[0], select.POLLIN)
1465
1467 """
1468 Stop notifier's loop. Stop notification. Join the thread.
1469 """
1470 self._stop_event.set()
1471 os.write(self._pipe[1], 'stop')
1472 threading.Thread.join(self)
1473 Notifier.stop(self)
1474 self._pollobj.unregister(self._pipe[0])
1475 os.close(self._pipe[0])
1476 os.close(self._pipe[1])
1477
1479 """
1480 Thread's main loop. Don't meant to be called by user directly.
1481 Call inherited start() method instead.
1482
1483 Events are read only once time every min(read_freq, timeout)
1484 seconds at best and only if the size of events to read is >= threshold.
1485 """
1486
1487
1488
1489
1490 while not self._stop_event.isSet():
1491 self.process_events()
1492 ref_time = time.time()
1493 if self.check_events():
1494 self._sleep(ref_time)
1495 self.read_events()
1496
1498 """
1499 Start thread's loop: read and process events until the method
1500 stop() is called.
1501 Never call this method directly, instead call the start() method
1502 inherited from threading.Thread, which then will call run() in
1503 its turn.
1504 """
1505 self.loop()
1506
1509 """
1510 This notifier inherits from asyncore.file_dispatcher in order to be able to
1511 use pyinotify along with the asyncore framework.
1512
1513 """
1514 - def __init__(self, watch_manager, default_proc_fun=None, read_freq=0,
1515 threshold=0, timeout=None, channel_map=None):
1516 """
1517 Initializes the async notifier. The only additional parameter is
1518 'channel_map' which is the optional asyncore private map. See
1519 Notifier class for the meaning of the others parameters.
1520
1521 """
1522 Notifier.__init__(self, watch_manager, default_proc_fun, read_freq,
1523 threshold, timeout)
1524 asyncore.file_dispatcher.__init__(self, self._fd, channel_map)
1525
1527 """
1528 When asyncore tells us we can read from the fd, we proceed processing
1529 events. This method can be overridden for handling a notification
1530 differently.
1531
1532 """
1533 self.read_events()
1534 self.process_events()
1535
1538 """
1539 Tornado ioloop adapter.
1540
1541 """
1542 - def __init__(self, watch_manager, ioloop, callback=None,
1543 default_proc_fun=None, read_freq=0, threshold=0, timeout=None,
1544 channel_map=None):
1545 """
1546 Note that if later you must call ioloop.close() be sure to let the
1547 default parameter to all_fds=False.
1548
1549 See example tornado_notifier.py for an example using this notifier.
1550
1551 @param ioloop: Tornado's IO loop.
1552 @type ioloop: tornado.ioloop.IOLoop instance.
1553 @param callback: Functor called at the end of each call to handle_read
1554 (IOLoop's read handler). Expects to receive the
1555 notifier object (self) as single parameter.
1556 @type callback: callable object or function
1557 """
1558 self.io_loop = ioloop
1559 self.handle_read_callback = callback
1560 Notifier.__init__(self, watch_manager, default_proc_fun, read_freq,
1561 threshold, timeout)
1562 ioloop.add_handler(self._fd, self.handle_read, ioloop.READ)
1563
1565 self.io_loop.remove_handler(self._fd)
1566 Notifier.stop(self)
1567
1569 """
1570 See comment in AsyncNotifier.
1571
1572 """
1573 self.read_events()
1574 self.process_events()
1575 if self.handle_read_callback is not None:
1576 self.handle_read_callback(self)
1577
1580 """
1581
1582 asyncio/trollius event loop adapter.
1583
1584 """
1585 - def __init__(self, watch_manager, loop, callback=None,
1586 default_proc_fun=None, read_freq=0, threshold=0, timeout=None):
1587 """
1588
1589 See examples/asyncio_notifier.py for an example usage.
1590
1591 @param loop: asyncio or trollius event loop instance.
1592 @type loop: asyncio.BaseEventLoop or trollius.BaseEventLoop instance.
1593 @param callback: Functor called at the end of each call to handle_read.
1594 Expects to receive the notifier object (self) as
1595 single parameter.
1596 @type callback: callable object or function
1597
1598 """
1599 self.loop = loop
1600 self.handle_read_callback = callback
1601 Notifier.__init__(self, watch_manager, default_proc_fun, read_freq,
1602 threshold, timeout)
1603 loop.add_reader(self._fd, self.handle_read)
1604
1608
1610 self.read_events()
1611 self.process_events()
1612 if self.handle_read_callback is not None:
1613 self.handle_read_callback(self)
1614
1617 """
1618 Represent a watch, i.e. a file or directory being watched.
1619
1620 """
1621 __slots__ = ('wd', 'path', 'mask', 'proc_fun', 'auto_add',
1622 'exclude_filter', 'dir')
1623
1624 - def __init__(self, wd, path, mask, proc_fun, auto_add, exclude_filter):
1625 """
1626 Initializations.
1627
1628 @param wd: Watch descriptor.
1629 @type wd: int
1630 @param path: Path of the file or directory being watched.
1631 @type path: str
1632 @param mask: Mask.
1633 @type mask: int
1634 @param proc_fun: Processing callable object.
1635 @type proc_fun:
1636 @param auto_add: Automatically add watches on new directories.
1637 @type auto_add: bool
1638 @param exclude_filter: Boolean function, used to exclude new
1639 directories from being automatically watched.
1640 See WatchManager.__init__
1641 @type exclude_filter: callable object
1642 """
1643 self.wd = wd
1644 self.path = path
1645 self.mask = mask
1646 self.proc_fun = proc_fun
1647 self.auto_add = auto_add
1648 self.exclude_filter = exclude_filter
1649 self.dir = os.path.isdir(self.path)
1650
1667
1670 """
1671 ExcludeFilter is an exclusion filter.
1672
1673 """
1675 """
1676 Examples:
1677 ef1 = ExcludeFilter(["/etc/rc.*", "/etc/hostname"])
1678 ef2 = ExcludeFilter("/my/path/exclude.lst")
1679 Where exclude.lst contains:
1680 /etc/rc.*
1681 /etc/hostname
1682
1683 Note: it is not possible to exclude a file if its encapsulating
1684 directory is itself watched. See this issue for more details
1685 https://github.com/seb-m/pyinotify/issues/31
1686
1687 @param arg_lst: is either a list of patterns or a filename from which
1688 patterns will be loaded.
1689 @type arg_lst: list of str or str
1690 """
1691 if isinstance(arg_lst, str):
1692 lst = self._load_patterns_from_file(arg_lst)
1693 elif isinstance(arg_lst, list):
1694 lst = arg_lst
1695 else:
1696 raise TypeError
1697
1698 self._lregex = []
1699 for regex in lst:
1700 self._lregex.append(re.compile(regex, re.UNICODE))
1701
1703 lst = []
1704 file_obj = file(filename, 'r')
1705 try:
1706 for line in file_obj.readlines():
1707
1708 pattern = line.strip()
1709 if not pattern or pattern.startswith('#'):
1710 continue
1711 lst.append(pattern)
1712 finally:
1713 file_obj.close()
1714 return lst
1715
1716 - def _match(self, regex, path):
1717 return regex.match(path) is not None
1718
1720 """
1721 @param path: Path to match against provided regexps.
1722 @type path: str
1723 @return: Return True if path has been matched and should
1724 be excluded, False otherwise.
1725 @rtype: bool
1726 """
1727 for regex in self._lregex:
1728 if self._match(regex, path):
1729 return True
1730 return False
1731
1734 """
1735 WatchManager Exception. Raised on error encountered on watches
1736 operations.
1737
1738 """
1740 """
1741 @param msg: Exception string's description.
1742 @type msg: string
1743 @param wmd: This dictionary contains the wd assigned to paths of the
1744 same call for which watches were successfully added.
1745 @type wmd: dict
1746 """
1747 self.wmd = wmd
1748 Exception.__init__(self, msg)
1749
1752 """
1753 Provide operations for watching files and directories. Its internal
1754 dictionary is used to reference watched items. When used inside
1755 threaded code, one must instanciate as many WatchManager instances as
1756 there are ThreadedNotifier instances.
1757
1758 """
1760 """
1761 Initialization: init inotify, init watch manager dictionary.
1762 Raise OSError if initialization fails, raise InotifyBindingNotFoundError
1763 if no inotify binding was found (through ctypes or from direct access to
1764 syscalls).
1765
1766 @param exclude_filter: boolean function, returns True if current
1767 path must be excluded from being watched.
1768 Convenient for providing a common exclusion
1769 filter for every call to add_watch.
1770 @type exclude_filter: callable object
1771 """
1772 self._ignore_events = False
1773 self._exclude_filter = exclude_filter
1774 self._wmd = {}
1775
1776 self._inotify_wrapper = INotifyWrapper.create()
1777 if self._inotify_wrapper is None:
1778 raise InotifyBindingNotFoundError()
1779
1780 self._fd = self._inotify_wrapper.inotify_init()
1781 if self._fd < 0:
1782 err = 'Cannot initialize new instance of inotify, %s'
1783 raise OSError(err % self._inotify_wrapper.str_errno())
1784
1786 """
1787 Close inotify's file descriptor, this action will also automatically
1788 remove (i.e. stop watching) all its associated watch descriptors.
1789 After a call to this method the WatchManager's instance become useless
1790 and cannot be reused, a new instance must then be instanciated. It
1791 makes sense to call this method in few situations for instance if
1792 several independant WatchManager must be instanciated or if all watches
1793 must be removed and no other watches need to be added.
1794 """
1795 os.close(self._fd)
1796
1798 """
1799 Return assigned inotify's file descriptor.
1800
1801 @return: File descriptor.
1802 @rtype: int
1803 """
1804 return self._fd
1805
1807 """
1808 Get watch from provided watch descriptor wd.
1809
1810 @param wd: Watch descriptor.
1811 @type wd: int
1812 """
1813 return self._wmd.get(wd)
1814
1816 """
1817 Remove watch entry associated to watch descriptor wd.
1818
1819 @param wd: Watch descriptor.
1820 @type wd: int
1821 """
1822 try:
1823 del self._wmd[wd]
1824 except KeyError, err:
1825 log.error('Cannot delete unknown watch descriptor %s' % str(err))
1826
1827 @property
1829 """
1830 Get a reference on the internal watch manager dictionary.
1831
1832 @return: Internal watch manager dictionary.
1833 @rtype: dict
1834 """
1835 return self._wmd
1836
1849
1850 - def __add_watch(self, path, mask, proc_fun, auto_add, exclude_filter):
1866
1867 - def __glob(self, path, do_glob):
1868 if do_glob:
1869 return glob(path)
1870 else:
1871 return [path]
1872
1873 - def add_watch(self, path, mask, proc_fun=None, rec=False,
1874 auto_add=False, do_glob=False, quiet=True,
1875 exclude_filter=None):
1876 """
1877 Add watch(s) on the provided |path|(s) with associated |mask| flag
1878 value and optionally with a processing |proc_fun| function and
1879 recursive flag |rec| set to True.
1880 Ideally |path| components should not be unicode objects. Note that
1881 although unicode paths are accepted there are converted to byte
1882 strings before a watch is put on that path. The encoding used for
1883 converting the unicode object is given by sys.getfilesystemencoding().
1884 If |path| is already watched it is ignored, but if it is called with
1885 option rec=True a watch is put on each one of its not-watched
1886 subdirectory.
1887
1888 @param path: Path to watch, the path can either be a file or a
1889 directory. Also accepts a sequence (list) of paths.
1890 @type path: string or list of strings
1891 @param mask: Bitmask of events.
1892 @type mask: int
1893 @param proc_fun: Processing object.
1894 @type proc_fun: function or ProcessEvent instance or instance of
1895 one of its subclasses or callable object.
1896 @param rec: Recursively add watches from path on all its
1897 subdirectories, set to False by default (doesn't
1898 follows symlinks in any case).
1899 @type rec: bool
1900 @param auto_add: Automatically add watches on newly created
1901 directories in watched parent |path| directory.
1902 If |auto_add| is True, IN_CREATE is ored with |mask|
1903 when the watch is added.
1904 @type auto_add: bool
1905 @param do_glob: Do globbing on pathname (see standard globbing
1906 module for more informations).
1907 @type do_glob: bool
1908 @param quiet: if False raises a WatchManagerError exception on
1909 error. See example not_quiet.py.
1910 @type quiet: bool
1911 @param exclude_filter: predicate (boolean function), which returns
1912 True if the current path must be excluded
1913 from being watched. This argument has
1914 precedence over exclude_filter passed to
1915 the class' constructor.
1916 @type exclude_filter: callable object
1917 @return: dict of paths associated to watch descriptors. A wd value
1918 is positive if the watch was added sucessfully,
1919 otherwise the value is negative. If the path was invalid
1920 or was already watched it is not included into this returned
1921 dictionary.
1922 @rtype: dict of {str: int}
1923 """
1924 ret_ = {}
1925
1926 if exclude_filter is None:
1927 exclude_filter = self._exclude_filter
1928
1929
1930 for npath in self.__format_param(path):
1931
1932 for apath in self.__glob(npath, do_glob):
1933
1934 for rpath in self.__walk_rec(apath, rec):
1935 if not exclude_filter(rpath):
1936 wd = ret_[rpath] = self.__add_watch(rpath, mask,
1937 proc_fun,
1938 auto_add,
1939 exclude_filter)
1940 if wd < 0:
1941 err = ('add_watch: cannot watch %s WD=%d, %s' % \
1942 (rpath, wd,
1943 self._inotify_wrapper.str_errno()))
1944 if quiet:
1945 log.error(err)
1946 else:
1947 raise WatchManagerError(err, ret_)
1948 else:
1949
1950
1951 ret_[rpath] = -2
1952 return ret_
1953
1955 """
1956 Get every wd from self._wmd if its path is under the path of
1957 one (at least) of those in lpath. Doesn't follow symlinks.
1958
1959 @param lpath: list of watch descriptor
1960 @type lpath: list of int
1961 @return: list of watch descriptor
1962 @rtype: list of int
1963 """
1964 for d in lpath:
1965 root = self.get_path(d)
1966 if root is not None:
1967
1968 yield d
1969 else:
1970
1971 continue
1972
1973
1974 if not os.path.isdir(root):
1975 continue
1976
1977
1978 root = os.path.normpath(root)
1979
1980 lend = len(root)
1981 for iwd in self._wmd.items():
1982 cur = iwd[1].path
1983 pref = os.path.commonprefix([root, cur])
1984 if root == os.sep or (len(pref) == lend and \
1985 len(cur) > lend and \
1986 cur[lend] == os.sep):
1987 yield iwd[1].wd
1988
1989 - def update_watch(self, wd, mask=None, proc_fun=None, rec=False,
1990 auto_add=False, quiet=True):
1991 """
1992 Update existing watch descriptors |wd|. The |mask| value, the
1993 processing object |proc_fun|, the recursive param |rec| and the
1994 |auto_add| and |quiet| flags can all be updated.
1995
1996 @param wd: Watch Descriptor to update. Also accepts a list of
1997 watch descriptors.
1998 @type wd: int or list of int
1999 @param mask: Optional new bitmask of events.
2000 @type mask: int
2001 @param proc_fun: Optional new processing function.
2002 @type proc_fun: function or ProcessEvent instance or instance of
2003 one of its subclasses or callable object.
2004 @param rec: Optionally adds watches recursively on all
2005 subdirectories contained into |wd| directory.
2006 @type rec: bool
2007 @param auto_add: Automatically adds watches on newly created
2008 directories in the watch's path corresponding to |wd|.
2009 If |auto_add| is True, IN_CREATE is ored with |mask|
2010 when the watch is updated.
2011 @type auto_add: bool
2012 @param quiet: If False raises a WatchManagerError exception on
2013 error. See example not_quiet.py
2014 @type quiet: bool
2015 @return: dict of watch descriptors associated to booleans values.
2016 True if the corresponding wd has been successfully
2017 updated, False otherwise.
2018 @rtype: dict of {int: bool}
2019 """
2020 lwd = self.__format_param(wd)
2021 if rec:
2022 lwd = self.__get_sub_rec(lwd)
2023
2024 ret_ = {}
2025 for awd in lwd:
2026 apath = self.get_path(awd)
2027 if not apath or awd < 0:
2028 err = 'update_watch: invalid WD=%d' % awd
2029 if quiet:
2030 log.error(err)
2031 continue
2032 raise WatchManagerError(err, ret_)
2033
2034 if mask:
2035 wd_ = self._inotify_wrapper.inotify_add_watch(self._fd, apath,
2036 mask)
2037 if wd_ < 0:
2038 ret_[awd] = False
2039 err = ('update_watch: cannot update %s WD=%d, %s' % \
2040 (apath, wd_, self._inotify_wrapper.str_errno()))
2041 if quiet:
2042 log.error(err)
2043 continue
2044 raise WatchManagerError(err, ret_)
2045
2046 assert(awd == wd_)
2047
2048 if proc_fun or auto_add:
2049 watch_ = self._wmd[awd]
2050
2051 if proc_fun:
2052 watch_.proc_fun = proc_fun
2053
2054 if auto_add:
2055 watch_.auto_add = auto_add
2056
2057 ret_[awd] = True
2058 log.debug('Updated watch - %s', self._wmd[awd])
2059 return ret_
2060
2073
2075 """
2076 Returns the watch descriptor associated to path. This method
2077 presents a prohibitive cost, always prefer to keep the WD
2078 returned by add_watch(). If the path is unknown it returns None.
2079
2080 @param path: Path.
2081 @type path: str
2082 @return: WD or None.
2083 @rtype: int or None
2084 """
2085 path = self.__format_path(path)
2086 for iwd in self._wmd.items():
2087 if iwd[1].path == path:
2088 return iwd[0]
2089
2091 """
2092 Returns the path associated to WD, if WD is unknown it returns None.
2093
2094 @param wd: Watch descriptor.
2095 @type wd: int
2096 @return: Path or None.
2097 @rtype: string or None
2098 """
2099 watch_ = self._wmd.get(wd)
2100 if watch_ is not None:
2101 return watch_.path
2102
2104 """
2105 Yields each subdirectories of top, doesn't follow symlinks.
2106 If rec is false, only yield top.
2107
2108 @param top: root directory.
2109 @type top: string
2110 @param rec: recursive flag.
2111 @type rec: bool
2112 @return: path of one subdirectory.
2113 @rtype: string
2114 """
2115 if not rec or os.path.islink(top) or not os.path.isdir(top):
2116 yield top
2117 else:
2118 for root, dirs, files in os.walk(top):
2119 yield root
2120
2121 - def rm_watch(self, wd, rec=False, quiet=True):
2122 """
2123 Removes watch(s).
2124
2125 @param wd: Watch Descriptor of the file or directory to unwatch.
2126 Also accepts a list of WDs.
2127 @type wd: int or list of int.
2128 @param rec: Recursively removes watches on every already watched
2129 subdirectories and subfiles.
2130 @type rec: bool
2131 @param quiet: If False raises a WatchManagerError exception on
2132 error. See example not_quiet.py
2133 @type quiet: bool
2134 @return: dict of watch descriptors associated to booleans values.
2135 True if the corresponding wd has been successfully
2136 removed, False otherwise.
2137 @rtype: dict of {int: bool}
2138 """
2139 lwd = self.__format_param(wd)
2140 if rec:
2141 lwd = self.__get_sub_rec(lwd)
2142
2143 ret_ = {}
2144 for awd in lwd:
2145
2146 wd_ = self._inotify_wrapper.inotify_rm_watch(self._fd, awd)
2147 if wd_ < 0:
2148 ret_[awd] = False
2149 err = ('rm_watch: cannot remove WD=%d, %s' % \
2150 (awd, self._inotify_wrapper.str_errno()))
2151 if quiet:
2152 log.error(err)
2153 continue
2154 raise WatchManagerError(err, ret_)
2155
2156
2157 if awd in self._wmd:
2158 del self._wmd[awd]
2159 ret_[awd] = True
2160 log.debug('Watch WD=%d (%s) removed', awd, self.get_path(awd))
2161 return ret_
2162
2163
2165 """
2166 Watch a transient file, which will be created and deleted frequently
2167 over time (e.g. pid file).
2168
2169 @attention: Currently under the call to this function it is not
2170 possible to correctly watch the events triggered into the same
2171 base directory than the directory where is located this watched
2172 transient file. For instance it would be wrong to make these
2173 two successive calls: wm.watch_transient_file('/var/run/foo.pid', ...)
2174 and wm.add_watch('/var/run/', ...)
2175
2176 @param filename: Filename.
2177 @type filename: string
2178 @param mask: Bitmask of events, should contain IN_CREATE and IN_DELETE.
2179 @type mask: int
2180 @param proc_class: ProcessEvent (or of one of its subclass), beware of
2181 accepting a ProcessEvent's instance as argument into
2182 __init__, see transient_file.py example for more
2183 details.
2184 @type proc_class: ProcessEvent's instance or of one of its subclasses.
2185 @return: Same as add_watch().
2186 @rtype: Same as add_watch().
2187 """
2188 dirname = os.path.dirname(filename)
2189 if dirname == '':
2190 return {}
2191 basename = os.path.basename(filename)
2192
2193 mask |= IN_CREATE | IN_DELETE
2194
2195 def cmp_name(event):
2196 if getattr(event, 'name') is None:
2197 return False
2198 return basename == event.name
2199 return self.add_watch(dirname, mask,
2200 proc_fun=proc_class(ChainIfTrue(func=cmp_name)),
2201 rec=False,
2202 auto_add=False, do_glob=False,
2203 exclude_filter=lambda path: False)
2204
2206 return self._ignore_events
2207
2209 self._ignore_events = nval
2210
2211 ignore_events = property(get_ignore_events, set_ignore_events,
2212 "Make watch manager ignoring new events.")
2213
2244
2245 output_format = RawOutputFormat()
2265
2268 """
2269 Use this function to turn on the compatibility mode. The compatibility
2270 mode is used to improve compatibility with Pyinotify 0.7.1 (or older)
2271 programs. The compatibility mode provides additional variables 'is_dir',
2272 'event_name', 'EventsCodes.IN_*' and 'EventsCodes.ALL_EVENTS' as
2273 Pyinotify 0.7.1 provided. Do not call this function from new programs!!
2274 Especially if there are developped for Pyinotify >= 0.8.x.
2275 """
2276 setattr(EventsCodes, 'ALL_EVENTS', ALL_EVENTS)
2277 for evname in globals():
2278 if evname.startswith('IN_'):
2279 setattr(EventsCodes, evname, globals()[evname])
2280 global COMPATIBILITY_MODE
2281 COMPATIBILITY_MODE = True
2282
2285 """
2286 By default the watched path is '/tmp' and all types of events are
2287 monitored. Events monitoring serves forever, type c^c to stop it.
2288 """
2289 from optparse import OptionParser
2290
2291 usage = "usage: %prog [options] [path1] [path2] [pathn]"
2292
2293 parser = OptionParser(usage=usage)
2294 parser.add_option("-v", "--verbose", action="store_true",
2295 dest="verbose", help="Verbose mode")
2296 parser.add_option("-r", "--recursive", action="store_true",
2297 dest="recursive",
2298 help="Add watches recursively on paths")
2299 parser.add_option("-a", "--auto_add", action="store_true",
2300 dest="auto_add",
2301 help="Automatically add watches on new directories")
2302 parser.add_option("-g", "--glob", action="store_true",
2303 dest="glob",
2304 help="Treat paths as globs")
2305 parser.add_option("-e", "--events-list", metavar="EVENT[,...]",
2306 dest="events_list",
2307 help=("A comma-separated list of events to watch for - "
2308 "see the documentation for valid options (defaults"
2309 " to everything)"))
2310 parser.add_option("-s", "--stats", action="store_true",
2311 dest="stats",
2312 help="Display dummy statistics")
2313 parser.add_option("-V", "--version", action="store_true",
2314 dest="version", help="Pyinotify version")
2315 parser.add_option("-f", "--raw-format", action="store_true",
2316 dest="raw_format",
2317 help="Disable enhanced output format.")
2318 parser.add_option("-c", "--command", action="store",
2319 dest="command",
2320 help="Shell command to run upon event")
2321
2322 (options, args) = parser.parse_args()
2323
2324 if options.verbose:
2325 log.setLevel(10)
2326
2327 if options.version:
2328 print(__version__)
2329
2330 if not options.raw_format:
2331 global output_format
2332 output_format = ColoredOutputFormat()
2333
2334 if len(args) < 1:
2335 path = '/tmp'
2336 else:
2337 path = args
2338
2339
2340 wm = WatchManager()
2341
2342 if options.stats:
2343 notifier = Notifier(wm, default_proc_fun=Stats(), read_freq=5)
2344 else:
2345 notifier = Notifier(wm, default_proc_fun=PrintAllEvents())
2346
2347
2348 mask = 0
2349 if options.events_list:
2350 events_list = options.events_list.split(',')
2351 for ev in events_list:
2352 evcode = EventsCodes.ALL_FLAGS.get(ev, 0)
2353 if evcode:
2354 mask |= evcode
2355 else:
2356 parser.error("The event '%s' specified with option -e"
2357 " is not valid" % ev)
2358 else:
2359 mask = ALL_EVENTS
2360
2361
2362 cb_fun = None
2363 if options.stats:
2364 def cb(s):
2365 sys.stdout.write(repr(s.proc_fun()))
2366 sys.stdout.write('\n')
2367 sys.stdout.write(str(s.proc_fun()))
2368 sys.stdout.write('\n')
2369 sys.stdout.flush()
2370 cb_fun = cb
2371
2372
2373 if options.command:
2374 def cb(s):
2375 subprocess.Popen(options.command, shell=True)
2376 cb_fun = cb
2377
2378 log.debug('Start monitoring %s, (press c^c to halt pyinotify)' % path)
2379
2380 wm.add_watch(path, mask, rec=options.recursive, auto_add=options.auto_add, do_glob=options.glob)
2381
2382 notifier.loop(callback=cb_fun)
2383
2384
2385 if __name__ == '__main__':
2386 command_line()
2387