Welcome, guest | Sign In | My Account | Store | Cart

This is an exemple to show how to use the inotify module, it could be very usefull unchanged though.

A Watcher instance let you define callbacks for any event that occur on any file or directory and subdirectories.

The inotify module is from Recipe 576375

Python, 115 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
'''
    High level inotify wrapper
'''

from os import listdir
from os.path import join as opj, normpath, isdir
from threading import Thread, RLock
from Queue import Queue
from time import sleep

from inotify import Inotify, FLAGS, mask_str

globals().update(FLAGS)
ALL = ACCESS|MODIFY|ATTRIB|WRITE|CLOSE|OPEN|CREATE|DELETE

class Event(object):
    def __init__(self, wd, watcher, mask, cookie, name):
        self.wd=wd
        self.watcher=watcher
        self.mask=mask
        self.cookie=cookie
        self.name=name
    @property
    def watch(self):
        return self.watcher.watches[self.wd]
    @property
    def path(self):
        path=self.watch.path
        return opj(path, self.name) if self.name else path
    def __str__(self):
        return '%s -> %s' % (mask_str(self.mask), self.path)

class Watch(object):
    def __init__(self, wd, watcher, mask, path, callback, auto, _parent=None):
        self.wd=wd
        self.watcher=watcher
        self.mask=mask
        self.path=normpath(path)
        self.callback=callback
        self.auto=auto
        self._parent=_parent
        if isdir(self.path) and self.auto:
            for name in listdir(self.path):
                path =  opj(self.path, name)
                if isdir(path):
                    self.watcher.add(
                        path, mask, callback, auto=True, _parent=self)
    def __str__(self):
        return 'Watch %i %s %s -> %s' % (
            self.wd, self.path, mask_str(self.mask), self.callback.__name__)

def default(event):
    if event.mask not in (ISDIR|OPEN, ISDIR|CLOSE): print event

class Watcher(object):
    def __init__(self):
        self.inotify=Inotify()
        self.watches={}
        self.queue=Queue()
        self.lock=RLock()
        for t in (self._push, self._pull):
            t=Thread(target=t)
            t.setDaemon(True)
            t.start()
    def _push(self):
        while True:
            for wd, mask, cookie, name in self.inotify.read():
                self.queue.put(Event(wd, self, mask, cookie, name))
    def _pull(self):
        while True:
            event = self.queue.get()
            mask=event.mask
            self.lock.acquire()
            watch = self.watches.get(event.wd)
            self.lock.release()
            watch.callback(event)
            if mask&ISDIR and mask&CREATE and watch.auto:
                self.add(event.path, watch.mask,
                    watch.callback, auto=True, _parent=watch)
            if mask&IGNORED:
                self.rem(watch)
    def add(self, path, mask=ALL, callback=default, auto=True, _parent=None):
        self.lock.acquire()
        wd=self.inotify.add_watch(path, mask)
        watch = Watch(wd, self, mask, path, callback, auto, _parent)
        self.watches[wd] = watch
        self.lock.release()
        return watch
    def rem(self, watch):
        self.lock.acquire()
        for w in list(self.watches.values()):
            if w._parent==watch: self.rem(w)
        wd=watch.wd
        self.watches.pop(wd)
        self.lock.release()
    def close(self):
        self.inotify.close()

if __name__ == '__main__':

    def tail(event):
        fil, mask = event.path, mask_str(event.mask)
        print '%s %s\n\t%s\n' % (
            fil, mask, '\t'.join(open(fil).readlines()[-5:])
        )

    watcher = Watcher()
    watcher.add('/etc')
    watcher.add('/var/log', MODIFY, tail)
    try:
        while True: sleep(11)
    except KeyboardInterrupt:
        print
    finally:
        watcher.close()

If you run this module, you will see "ALL" the events that occur in the "/etc" directory (and subdirs). You will also see the last five lines of any file in "/var/log" (and subdirs) on which a "MODIFY" event occurs. (like "tail -f")