C module to handle utmp entires
authorTero Marttila <terom@paivola.fi>
Fri, 21 Mar 2008 01:53:51 +0200
changeset 7 6a49fc285842
parent 6 614161f85d9b
child 8 3d648daf9538
C module to handle utmp entires

committer: Tero Marttila <terom@paivola.fi>
_utmp.c
setup.py
utmp.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/_utmp.c	Fri Mar 21 01:53:51 2008 +0200
@@ -0,0 +1,57 @@
+#include <Python.h>
+
+#include <utmp.h>
+
+#include <stdio.h>
+
+PyObject *parse (PyObject *self, PyObject *args) {
+    char *bytes;
+    size_t size;
+
+    struct utmp *item;
+    
+    /* not unicode */
+    if (!PyArg_ParseTuple(args, "t#", &bytes, &size))
+        return NULL;
+
+    if (size != sizeof(struct utmp)) {
+        PyErr_SetString(PyExc_ValueError, "given buffer is of the wrong length");
+        return NULL;
+    }
+
+    item = (struct utmp *) bytes;
+    
+    /* parse utmp from bytes to result */
+    return Py_BuildValue("hIs#s#s#s#(hh)i(ii)s#",
+        item->ut_type, item->ut_pid,
+        item->ut_line, sizeof(item->ut_line),
+        item->ut_id, sizeof(item->ut_id),
+        item->ut_user, sizeof(item->ut_user),
+        item->ut_host, sizeof(item->ut_host),
+        item->ut_exit.e_termination, item->ut_exit.e_exit,
+        item->ut_session,
+        item->ut_tv.tv_sec, item->ut_tv.tv_usec,
+        item->ut_addr_v6, sizeof(item->ut_addr_v6)
+    );
+}
+
+PyObject *size (PyObject *self, PyObject *args) {
+    /* return the size of an UTMP struct */
+
+    if (!PyArg_ParseTuple(args, ""))
+        return NULL;
+
+    return PyInt_FromSsize_t(sizeof(struct utmp));
+}
+
+static PyMethodDef module_methods[] = {
+    {"parse",       parse,      METH_VARARGS,   "parse a utmp struct from a byte string"},
+    {"size",        size,       METH_VARARGS,   "return the size of an utmp record in bytes"},
+    {NULL}
+};
+
+PyMODINIT_FUNC init_utmp(void) {
+    PyObject *m;
+
+    m = Py_InitModule3("_utmp", module_methods, "utmp struct parsing");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup.py	Fri Mar 21 01:53:51 2008 +0200
@@ -0,0 +1,10 @@
+from distutils.core import setup, Extension
+
+_utmp = Extension('_utmp', sources=['_utmp.c'])
+
+setup(
+    name        = "FixBot",
+    version     = "0.1",
+    description = "IRC bot for sysadmin things",
+    ext_modules = [_utmp],
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utmp.py	Fri Mar 21 01:53:51 2008 +0200
@@ -0,0 +1,50 @@
+import socket
+
+import _utmp
+
+class WtmpEntry (object) :
+    _ATTRS = (
+        "type", "pid", "line", "id", "user", "host", "exit", "session", "tv", "addr_v6"
+    )
+
+    def __str__ (self) :
+        return " ".join("%s=%s" % (key, getattr(self, key)) for key in self._ATTRS)
+
+def read_entry (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_v6", ) :
+            field = field.rstrip("\0")
+
+        setattr(wtmp, name, field)
+    
+    wtmp.addr_v6 = socket.inet_ntop(socket.AF_INET6, wtmp.addr_v6)
+
+    return wtmp
+
+def read_entries (file) :
+    while True :
+        wtmp = read_entry(file)
+
+        if wtmp :
+            yield wtmp
+        else :
+            return
+
+def test_main () :
+    fh = open("/var/log/wtmp", "r")
+    
+    for item in read_entries(fh) :
+        print item
+
+if __name__ == '__main__' :
+    test_main()
+