tcl−inotify − File−system notification service for Tcl |
package require inotify inotify create watch handler inotify info watch add pathname flags watch del pathname watch queue watch read watch info rename watch {} |
This is a Tcl extension that provides an interface to the inotify file system notification service of the Linux kernel. Inotify is a Linux kernel subsystem that provides file system event notifications. It was written by John McCutchan with help from Robert Love and later Amy Griffis to replace dnotify. It was included in the mainline kernel from release 2.6.13, and could be compiled into 2.6.12 and possibly earlier releases by use of a patch. Its function is essentially an extension to filesystems to notice changes to the filesystem, and report those changes to applications. inotify create watch handler Creates an inotify instance in the form of a new Tcl command, named watch. Whenever there are events for this instance, handler procedure is executed with a single argument, the instanceId. On success the command returns instanceId, otherwise an error is generated that needs to be catched. inotify info It returns a list of length n * 3, where n is the number of active instances. Every triplet is comprised by: instanceId handler watch. The command can generate errors that need to be catched. watch add pathname flags Adds a watch to the inotify instance that corresponds to watch command. The new watch monitors the pathname object (which can be a file or a directory) for the events specified by flags. On success the command returns watchId, otherwise an error is generated that needs to be catched. watch del pathname Removes the watch associated with pathname.The command can generate errors that need to be catched. watch queue Returns the bytes in the kernel buffer that are occupied by inotify events which haven’t been processed yet (pending). watch read Returns a list of dictionaries, one for each pending
event for the inotify instance that corresponds to the
watch command. The format of the dictionary is: watch info It returns a list of length n * 3, where n is the number of active instances. Every triplet is comprised by: pathname watchId flags. The command can generate errors that need to be catched. rename watch {} Removes all the instance that corresponds to the watch command, and all associated watches. PARAMETERS instanceId is a number that uniquely identifies a set of watches that are handled by the same handler procedure. watchId is a number that uniquely identifies a watch. handler is a procedure (with optional namespace), that is executed every time there are events in the kernel event queue for the corresponding instanceId. The events can be read in batch by the handler procedure by invoking watch read. The instanceId is provided as an argument to the handler. cookie is used to associate two different events, one IN_MOVED_FROM and one IN_MOVED_TO that involve the same file/directory. flags is a string composed of single character event identifiers. The following events are supported: Id Name Description n IN_CREATE File was created. r IN_ACCESS File was read from. w IN_MODIFY File was written to. a IN_ATTRIB File’s metadata (inode or xattr) was changed. C IN_CLOSE_WRITE File was closed (and was open for writing). c IN_CLOSE_NOWRITE File was closed (and was not open for writing). o IN_OPEN File was opened. m IN_MOVED_FROM File was moved away from watch. M IN_MOVED_TO File was moved to watch. d IN_DELETE File was deleted. s IN_DELETE_SELF The watch itself was deleted. In addition to the above, for event registration only, the following are also supported: (only for the watch add command) Id Name Description 1 IN_ONESHOT The watch will be automatically removed during generation of the first event. _ IN_CLOSE IN_CLOSE_WRITE | IN_CLOSE_NOWRITE > IN_MOVE IN_MOVED_FROM | IN_MOVED_TO * IN_ALL_EVENTS Bitwise OR of all events. In a similar manner, the following are specific for event reporting: (only for the watch read command) Id Name Description u IN_UNMOUNT The backing filesystem was unmounted. f IN_Q_OVERFLOW The inotify queue overflowed. i IN_IGNORED The watch was automatically removed, because the file was deleted or its filesystem was unmounted. D IN_ISDIR The event occurred against a directory. |
# Monitor a directory for all events, and cause some to trigger package require inotify set num 0 proc handler { fd } { variable term variable num puts "____________________________________________" puts "Invocation:$num" puts "Instance: $fd" puts "Remaining:[watch queue]" puts "Inotify Info:[inotify info]" puts "Watch Info:[watch info]" set events [watch read] puts "Events (raw):$events0 # In single−threaded scripts, reading this buffer always gives the data that caused to invoke the handler foreach {watchId flags cookie filepath} $events { puts "Watch:$watchId" puts "Flags:$flags" puts "Cookie:$cookie" puts "Object:$filepath0 } incr num if {$num >= 5} { set term 1 } } set fd [inotify create "watch" "::handler"] puts Created set wd [watch add [pwd] {*}] puts Added watch remove [pwd] puts Removed set wd [watch add [pwd] {*}] puts Added after 1000 [list exec echo a > test.txt] after 2000 [list exec mv test.txt delme.txt] after 3000 [list exec rm delme.txt] after 4000 [list exec ls] after 5000 [list set term 1] set term 0 puts "waiting.." vwait term puts "0xiting.." rename watch {} rename inotify {} |
Created Added Removed Added waiting.. ____________________________________________ Invocation: 0 Instance: 5 Remaining: 0 Inotify Info: 5 ::handler watch Watch Info: /tmp/inotify 2 * Events (raw): 1 i 0 {} Watch: 1 Flags: i Cookie: 0 Object: ____________________________________________ Invocation: 1 Instance: 5 Remaining: 0 Inotify Info: 5 ::handler watch Watch Info: /tmp/inotify 2 * Events (raw): 2 n 0 test.txt 2 o 0 test.txt 2 w 0 test.txt 2 C 0 test.txt Watch: 2 Flags: n Cookie: 0 Object: test.txt Watch: 2 Flags: o Cookie: 0 Object: test.txt Watch: 2 Flags: w Cookie: 0 Object: test.txt Watch: 2 Flags: C Cookie: 0 Object: test.txt ____________________________________________ Invocation: 2 Instance: 5 Remaining: 0 Inotify Info: 5 ::handler watch Watch Info: /tmp/inotify 2 * Events (raw): 2 m 585 test.txt 2 M 585 delme.txt Watch: 2 Flags: m Cookie: 585 Object: test.txt Watch: 2 Flags: M Cookie: 585 Object: delme.txt ____________________________________________ Invocation: 3 Instance: 5 Remaining: 0 Inotify Info: 5 ::handler watch Watch Info: /tmp/inotify 2 * Events (raw): 2 d 0 delme.txt Watch: 2 Flags: d Cookie: 0 Object: delme.txt ____________________________________________ Invocation: 4 Instance: 5 Remaining: 0 Inotify Info: 5 ::handler watch Watch Info: /tmp/inotify 2 * Events (raw): 2 oD 0 {} 2 cD 0 {} Watch: 2 Flags: oD Cookie: 0 Object: Watch: 2 Flags: cD Cookie: 0 Object: exiting.. |
# An efficient tailf implementation using inotify package require inotify package provide tailf namespace eval tailf { namespace export add rem array set File2wd {} array set Wd2info {} inotify create ::tailf::watch ::tailf::handler proc getpos {filepath} { set fd [open $filepath r] seek $fd 0 end set pos [tell $fd] close $fd return $pos } proc handler {args} { variable File2wd variable Wd2info while {[watch queue]} { set events [watch read] foreach {wd flags cookie filepath} $events { if {! [info exists Wd2info($wd)]} { return } set diff {} set callback [lindex $Wd2info($wd) 1] set filepath [lindex $Wd2info($wd) 2] set old [lindex $Wd2info($wd) 0] set new [getpos $filepath] set Wd2info($wd) [lreplace $Wd2info($wd) 0 0 $new] if {$new < $old} { set old 0 } if {$old != $new} { set fd [open $filepath r] seek $fd $old while {[gets $fd line] >= 0} { append diff "$line" "0 } close $fd } eval [list $callback $filepath $diff] } } return } proc add {filepath callback} { variable File2wd variable Wd2info if {[file exists $filepath] && [file isfile $filepath]} { set pos [getpos $filepath] set wd [watch add $filepath {w}] set File2wd($filepath) $wd set Wd2info($wd) [list $pos $callback $filepath] } else { error "is either not a file, or does not exist" } } proc rem {filepath} { variable File2wd variable Wd2info if {! [info exists ::tailf::File($filepath)]} { error "$filepath is not monitored, or watch has been removed" } set wd $File2wd($filepath) unset Wd2info($wd) unset File2wd($filepath) watch del $filepath } } ;# namespace end proc puts_hdlr {filepath diff} { puts −nonewline $diff } ::tailf::add "delme.txt" puts_hdlr set a {} vwait a |
Alexandros Stergiakis <sterg@kth.se> |
Copyright (C) 2008 Alexandros Stergiakis This program is free software: you can redistribute it
and/or This program is distributed in the hope that it will be
useful, You should have received a copy of the GNU General Public
License |