This module is meant to be as simple and straightforward as it gets.
| Python |
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 | '''
Low level inotify wrapper
'''
from os import read, close
from struct import unpack
from fcntl import ioctl
from termios import FIONREAD
from time import sleep
from ctypes import cdll, c_int, POINTER
from errno import errorcode
libc = cdll.LoadLibrary('libc.so.6')
libc.__errno_location.restype = POINTER(c_int)
def geterr(): return errorcode[libc.__errno_location().contents.value]
class Inotify(object):
def __init__(self):
self.fd = libc.inotify_init()
if self.fd == -1:
print 'inotify INIT err :', geterr()
raise OSError()
def read(self):
size_int = c_int()
while ioctl(self.fd, FIONREAD, size_int)==-1: sleep(1)
size = size_int.value
data = read(self.fd, size)
deb = 0
while deb < size:
fin = deb+16
wd, mask, cookie, name_len = unpack('iIII', data[deb:fin])
deb, fin = fin, fin+name_len
name = unpack('%ds' % name_len, data[deb:fin])
name = name[0].rstrip('\0')
deb = fin
yield wd, mask, cookie, name
def add_watch(self, path, mask):
wd = libc.inotify_add_watch(self.fd, path, mask)
if wd == -1: print 'inotify ADD err :', geterr()
return wd
def rm_watch(self, wd):
ret = libc.inotify_rm_watch(self.fd, wd)
if ret == -1: print 'inotify RM err :', geterr()
def close(self):
close(self.fd)
FLAGS = {
'ACCESS' : 0x00000001, # IN_ACCESS
'MODIFY' : 0x00000002, # IN_MODIFY
'ATTRIB' : 0x00000004, # IN_ATTRIB
'WRITE' : 0x00000008, # IN_CLOSE_WRITE
'CLOSE' : 0x00000010, # IN_CLOSE_NOWRITE
'OPEN' : 0x00000020, # IN_OPEN
'MOVED_FROM' : 0x00000040, # IN_MOVED_FROM
'MOVED_TO' : 0x00000080, # IN_MOVED_TO
'CREATE' : 0x00000100, # IN_CREATE
'DELETE' : 0x00000200, # IN_DELETE
'DELETE_SELF' : 0x00000400, # IN_DELETE_SELF
'MOVE_SELF' : 0x00000800, # IN_MOVE_SELF
'UNMOUNT' : 0x00002000, # IN_UNMOUNT
'Q_OVERFLOW' : 0x00004000, # IN_Q_OVERFLOW
'IGNORED' : 0x00008000, # IN_IGNORED
'ONLYDIR' : 0x01000000, # IN_ONLYDIR
'DONT_FOLLOW' : 0x02000000, # IN_DONT_FOLLOW
'MASK_ADD' : 0x20000000, # IN_MASK_ADD
'ISDIR' : 0x40000000, # IN_ISDIR
'ONESHOT' : 0x80000000, # IN_ONESHOT
}
def mask_str(mask):
return ' | '.join(name for name, val in FLAGS.items() if val & mask)
|
Discussion
This should work out of the box on any modern distro.
This module is not intended to be used directly, it should be used to build higher level modules, like the one you can see here


Comments
For some reason, this has stopped working for me since kernel 2.6.28 (Gentoo machines), with the following exception:
I need to apply the following patch to get it to work again:
Sign in to comment