from twisted.internet import protocol, reactor
from twisted.python import log
import socket, os, time
import _utmp, api, sys
POLL_INTERVAL = 5
def getPidCmd (pid) :
try :
fh = open("/proc/%d/cmdline" % pid, "r")
cmdline = fh.read()
fh.close()
return repr("%d:%s" % (pid, cmdline))
except IOError, OSError :
return "[%d]" % pid
class WtmpEntry (object) :
_ATTRS = (
"type", "pid", "line", "id", "user", "host", "exit", "session", "tv", "addr"
)
@staticmethod
def fromFile (file) :
bytes = file.read(_utmp.size())
if not bytes :
return
result = _utmp.parse(bytes)
wtmp = WtmpEntry()
for name, field in zip(wtmp._ATTRS, result) :
if isinstance(field, str) and name not in ("addr", ) :
field = field.rstrip("\0")
setattr(wtmp, name, field)
# convert the address
family = socket.AF_INET
addr = wtmp.addr[0:4]
for byte in wtmp.addr[4:] :
if byte :
family = socket.AF_INET6
addr = wtmp.addr
break
wtmp.addr = socket.inet_ntop(family, addr)
wtmp.pid = getPidCmd(wtmp.pid)
return wtmp
def __str__ (self) :
return " ".join("%s=%s" % (key, getattr(self, key)) for key in self._ATTRS)
class WtmpFile (object) :
def __init__ (self, path="/var/log/wtmp") :
self.path = path
self.file = open(path)
self.file.seek(0, os.SEEK_END)
def tryRead (self) :
return WtmpEntry.fromFile(self.file)
def read_entries (file) :
while True :
wtmp = read_entry(file)
if wtmp :
yield wtmp
else :
return
def follow_main () :
wtmp = WtmpFile()
while True :
item = wtmp.tryRead()
if item :
print item
else :
time.sleep(2)
def test_main () :
fh = open("/var/log/wtmp", "r")
for item in read_entries(fh) :
print item
class WtmpModule (api.Module) :
name = "wtmp"
version = 0x0001
def handleConnect (self) :
log.msg("Following default wtmp file...")
self.wtmp = WtmpFile()
log.msg("Starting poll timer")
self.poll()
log.msg("Running")
def poll (self) :
while True :
item = self.wtmp.tryRead()
if item :
log.msg(" -- %s" % item)
self.sendEvent("wtmp", str(item))
else :
return reactor.callLater(POLL_INTERVAL, self.poll)
if __name__ == '__main__' :
WtmpModule().run()