fixbot/utmp.py
author Tero Marttila <terom@fixme.fi>
Fri, 05 Feb 2010 21:48:14 +0200
changeset 58 31a17b0b5159
parent 21 aa6df8f9c44a
permissions -rw-r--r--
remove concept of event_types, the event.type is now just sent as a string
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()