pax_global_header00006660000000000000000000000064135341371540014520gustar00rootroot0000000000000052 comment=0a29661f9433cbf9fd02e8a8277ae33a5f120e1d python-utmp-0.9/000077500000000000000000000000001353413715400136745ustar00rootroot00000000000000python-utmp-0.9/COPYING000077700000000000000000000000001353413715400200772debian/copyrightustar00rootroot00000000000000python-utmp-0.9/INSTALL000066400000000000000000000004031353413715400147220ustar00rootroot00000000000000edit Makefile.common, especially the path you your python modules and python include file. Select suitable Makefile.target, where target is one of dumb, bsd, glibc, hpux, sunos, check DEFINES for your system. type $ make -f Makefile.target # make install python-utmp-0.9/Makefile000066400000000000000000000000321353413715400153270ustar00rootroot00000000000000 include Makefile.common python-utmp-0.9/Makefile.bsd000066400000000000000000000001451353413715400161030ustar00rootroot00000000000000 #for bsd systems, i.e. FreeBSD, NetBSD, OpenBSD DEFINES = -D_HAVE_UT_HOST include Makefile.common python-utmp-0.9/Makefile.common000066400000000000000000000012621353413715400166240ustar00rootroot00000000000000PYTHONVER?=3.7 PYTHONDIR=$(DESTDIR)/usr/lib/python$(PYTHONVER)/dist-packages/ PYTHONINCLUDE=/usr/include/python$(PYTHONVER)/ CC = gcc CFLAGS = -g -Wall -I$(PYTHONINCLUDE) $(DEFINES) LDFLAGS = all: utmpaccessmodule.so UTMPCONST.py utmpaccessmodule.o: utmpaccessmodule.c $(CC) $(CFLAGS) -fpic -c utmpaccessmodule.c utmpaccessmodule.so: utmpaccessmodule.o $(CC) $(CFLAGS) $(LDFLAGS) -fpic -shared utmpaccessmodule.o -o utmpaccessmodule.so UTMPCONST.py: constants.h makeconst.c makeconst.sh ./makeconst.sh $(CFLAGS) clean: rm -f *~ *.o utmpaccessmodule.so *.pyc UTMPCONST.py makeconst install: mkdir -p $(PYTHONDIR) cp -f utmpaccessmodule.so utmp.py UTMPCONST.py $(PYTHONDIR) python-utmp-0.9/Makefile.dumb000066400000000000000000000001111353413715400162530ustar00rootroot00000000000000 #for systems without suitable utmp DEFINES = include Makefile.common python-utmp-0.9/Makefile.glibc000066400000000000000000000005141353413715400164130ustar00rootroot00000000000000 #for glibc2 based systems, e.g. linux and hurd DEFINES = -D_HAVE_UT_SESSION -D_HAVE_UT_ADDR_V6 -D_HAVE_UT_EXIT \ -D_HAVE_UT_HOST -D_HAVE_UT_ID -D_HAVE_UT_TV -D_HAVE_UT_USER \ -D_HAVE_UTMPNAME -D_HAVE_SETUTENT -D_HAVE_GETUTENT \ -D_HAVE_ENDUTENT -D_HAVE_GETUTID -D_HAVE_GETUTLINE -D_HAVE_PUTUTLINE include Makefile.common python-utmp-0.9/Makefile.hpux000066400000000000000000000004341353413715400163200ustar00rootroot00000000000000 #for HP-UX B.10.20 DEFINES = -D_HAVE_UT_TYPE -D_HAVE_UT_PID -D_HAVE_UT_ID -D_HAVE_UT_EXIT \ -D_HAVE_UT_HOST -D_HAVE_UT_USER \ -D_HAVE_UTMPNAME -D_HAVE_SETUTENT -D_HAVE_GETUTENT \ -D_HAVE_ENDUTENT -D_HAVE_GETUTID -D_HAVE_GETUTLINE -D_HAVE_PUTUTLINE include Makefile.common python-utmp-0.9/Makefile.sunos000066400000000000000000000004641353413715400165060ustar00rootroot00000000000000 #for SunOS 5.6 DEFINES = -DUSE_UTMPX \ -D_HAVE_UT_TYPE -D_HAVE_UT_PID -D_HAVE_UT_ID -D_HAVE_UT_EXIT \ -D_HAVE_UT_HOST -D_HAVE_UT_TV -D_HAVE_UT_USER\ -D_HAVE_UTMPNAME -D_HAVE_SETUTENT -D_HAVE_GETUTENT \ -D_HAVE_ENDUTENT -D_HAVE_GETUTID -D_HAVE_GETUTLINE -D_HAVE_PUTUTLINE include Makefile.common python-utmp-0.9/README000066400000000000000000000164221353413715400145610ustar00rootroot00000000000000http://kassiopeia.juls.savba.sk/~garabik/software/python-utmp.html garabik @ kassiopeia.juls.savba.sk ================================================================== python-utmp consists of three modules, providing access to utmp records. It is quite difficult to access utmp record portably, because every UNIX has different structure of utmp files. Currently, python-utmp works on platforms which provide getutent, getutid, getutline, pututline, setutent, endutent and utmpname functions (such as GNU systems (Linux and hurd) and System V unices) and on BSD systems using simple utmp structure. python-utmp is known to work on linux with glibc2.0, glibc2.1, glibc2.2, glibc2.3; SunOS 5.6; HP-UX B.10.20; NetBSD 1.4.2; OpenBSD 2.9 Python 3.X support ------------------ Starting from version 0.8, there is now a partial python3 support. In particular, ut_line, ut_id, ut_user, ut_host are strings, not bytes. If any of these fields contain non-ASCII characters, utmpaccess module will try to convert them into strings using the default system encoding (usually utf-8). If the field happens to contain invalid utf-8 sequences, this will raise an exception. However, this should not happen under normal circumstances – strings in utmp should be ASCII only, so this indicates a pathological situation, probably a damage to the utmp file. Correct solution would be for utmpaccess to return bytes, and let utmp.py deal with it, by indicating that we want either bytes or strings. Some of the examples work with python3, converting others will be trivial. There was a big API change in version 0.7 – old interface has been kept for backward portability, but may be removed in the future. Usually, system provides functions for accessing utmp, but on *BSD systems the only way (IMHO) is to read utmp file as consisting of C-structures. It is difficult to unite both worlds. To make things worse, some OS'es (hint: SunOS :-)) use utmpx in parallel to utmp, utmpx containing more information. python-utmp provides getutent() & comp. as an emulation layer if native system is lacking these functions, providing ideal glibc-like utmp structure, emulating fields present in this structure but missing at the specific platform. Missing member: Default used instead: ut_type USER_PROCESS DEAD_PROCESS if ut_name and ut_host are empty EMPTY if ut_name, ut_host and ut_line are empty BOOT_TIME if ut_line is "~" ut_pid 0 ut_id ut_line ut_host '' ut_exit (0, 0) ut_tv.tv_sec ut_time ut_tv.tv_usec 0 ut_addr_v6 4*[0] ut_session 0 CAVEAT: If the native platform misses ut_type, it distinguishes between user processes and pseudo-entries by ut_line. python-utmp tries to guess the appropriate ut_type in this case. It might not guess correctly. Moreover, I have seen some quirks with ut_type==USER_PROCESS for date entries with linux. Therefore, date entries (with ut_line=="{" or ut_line=="|") are considered to be user processes for the time being. Similarly, if you write into utmp and your ut_type is not USER_PROCESS, corresponding ut_host and ut_user are cleared (=filled with zeros). Depending on your system, this may or may not be the right thing to do. It is correct at least with NetBSD. Reading from utmp and wtmp should be safe and bulletproof. Module "utmpaccess" provides low level access to utmp structure, in most cases you should use module "utmp" instead. utmpaccess provides following functions (see getutent(3) and utmp(5) for more information): ut_addr_v6 is a tuple of 4 integers, ut_exit is tuple of (e_termination, e_exit) ut_tv is tuple of (tv_sec, tv_usec) getutent(): returns None if there is an error (e.g. going past the end of utmp file) otherwise returns tuple of: (ut_type, ut_pid, ut_line, ut_id, ut_user, ut_host, ut_exit, ut_session, ut_tv, ut_addr_v6) getutid(ut_type[, ut_id]): returns None if there is an error (e.g. not found), otherwise returns tuple of: (ut_type, ut_pid, ut_line, ut_id, ut_user, ut_host, ut_exit, ut_session, ut_tv, ut_addr_v6) getutline(ut_line): returns None if there is an error (e.g. not found), otherwise returns tuple of: (ut_type, ut_pid, ut_line, ut_id, ut_user, ut_host, ut_exit, ut_session, ut_tv, ut_addr_v6) pututline(ut_type, ut_pid, ut_line, ut_id, ut_user, ut_host, ut_e_termination, ut_exit, ut_session, ut_tv, ut_addr_v6): returns None setutent(): returns None endutent() returns None utmpname(fname): returns None UTMPCONST.py provides convenient constants for work with utmpaccess.py, taken from system constants, or some sensibly made-up values if system does not provide them. (see UTMPCONST.py source) These constants are provided: EMPTY RUN_LVL BOOT_TIME NEW_TIME OLD_TIME INIT_PROCESS LOGIN_PROCESS USER_PROCESS DEAD_PROCESS ACCOUNTING UT_UNKNOWN UT_LINESIZE UT_NAMESIZE UT_HOSTSIZE UT_IDSIZE UTMP_FILE WTMP_FILE UT_IDSIZE if the size of ut_id (usually 4). If your system does not have ut_id, ut_id is simulated by ut_line, and UT_IDSIZE==UT_LINESIZE Module "utmp" provides class UtmpEntry, correcponding to one entry in UTMP/WTMP file. UtmpEntry has following attributes (values after "=" demonstrate default values) ut_type = EMPTY ut_pid = 0 ut_line = '' ut_id = '' ut_user = '' ut_host = '' ut_exit = (0, 0) ut_session = 0 ut_tv = (0, 0) ut_addr_v6 = (0, 0, 0, 0) You can initialize new UtmpEntry via several different ways: - passing a tuple to the constructor: >>> tpl = (USER_PROCESS, 1234, 'tty5', 'id', 'root', 'localhost', (0, 0), 0, (0, 0), (0, 0, 0, 0)) >>> entry1 = UtmpEntry(tpl) - using tuple as arguments: >>> entry2 = UtmpEntry(USER_PROCESS, 1234, 'tty5', 'id', 'root', 'localhost', (0, 0), 0, (0, 0), (0, 0, 0, 0)) - using dictionary >>> dic = { 'ut_type':USER_PROCESS, 'ut_pid':1234, 'ut_line':'tty5', 'ut_user':'root' } >>> entry3 = UtmpEntry(dic) - using named parameters: >>> entry4 = UtmpEntry(ut_type=USER_PROCESS, ut_pid=1234, ut_line='tty5', ut_user='root') Omitted parameters get the default values. - using already existing instance of UtmpEntry >>> entry5 = UtmpEntry(entry4) The preferred way is to get UtmpEntry from an existing UtmRecord, modify it according to your needs and write it back. UtmpEntry supports tuple- and dictionary-like interface, for compatibility with previous versions of python-utmp. So you can use entry5[0] or entry5['ut_type'] instead of entry5.ut_type. This will be probably removed in the future. Module "utmp" also provides class UtmpRecord with following methods: getutent() getutid(ut_type[, ut_id]): getutline(ut_line) pututline(UtmpEntry) for backward compatibility, you can use the same parameters as when creating UtmpEntry instance. setutent() endutent() old *_dict() methods are still kept for backward compatibility; they may be removed in the future. as of version 0.6, it also provides an iterator which enables you to write loops like this (it requires python>2.2): u = utmp.UtmpRecord() for i in u: # i is an UtmpEntry instance, as if returned by u.getutent() You pass filename for utmpname() when creating instance of the class, e.g. a=Utmp.UtmpRecord("/var/log/wtmp") python-utmp-0.9/TODO000066400000000000000000000000371353413715400143640ustar00rootroot00000000000000dummy module for Windows & Mac python-utmp-0.9/constants.h000066400000000000000000000036701353413715400160670ustar00rootroot00000000000000#include /* a bad hack, we should dynamically allocate the array */ #ifndef MAXPATHLEN # define MAXPATHLEN 1024 #endif #ifdef USE_UTMPX # include # define choice_utmp utmpx #else # include # define choice_utmp utmp #endif #ifndef _HAVE_UT_USER # define ut_user ut_name #endif struct choice_utmp utmp_entry; #define STRUCTSIZE ((long)sizeof(utmp_entry)) #ifndef UT_NAMESIZE # define UT_NAMESIZE sizeof(utmp_entry.ut_user) #endif #ifndef UT_LINESIZE # define UT_LINESIZE sizeof(utmp_entry.ut_line) #endif #ifdef _HAVE_UT_ID # define UT_IDSIZE sizeof(utmp_entry.ut_id) #else # define UT_IDSIZE UT_LINESIZE #endif #ifndef UT_HOSTSIZE # ifdef _HAVE_UT_HOST # define UT_HOSTSIZE sizeof(utmp_entry.ut_host) # else # define UT_HOSTSIZE 0 # endif #endif #ifndef UTMP_FILE # ifdef _PATH_UTMP /* newer BSD's */ # define UTMP_FILE _PATH_UTMP # else # define UTMP_FILE "/etc/utmp" # endif #endif #ifndef WTMP_FILE # ifdef _PATH_WTMP /* newer BSD's */ # define WTMP_FILE _PATH_WTMP # else # define WTMP_FILE "/etc/wtmp" # endif #endif #ifndef _HAVE_UT_TYPE # define EMPTY 0 # define RUN_LVL 1 # define BOOT_TIME 2 # define NEW_TIME 3 # define OLD_TIME 4 # define INIT_PROCESS 5 # define LOGIN_PROCESS 6 # define USER_PROCESS 7 # define DEAD_PROCESS 8 # define ACCOUNTING 9 # define UT_UNKNOWN EMPTY #else #ifndef EMPTY # define EMPTY 0 #endif #ifndef RUN_LVL # define RUN_LVL EMPTY #endif #ifndef BOOT_TIME # define BOOT_TIME EMPTY #endif #ifndef NEW_TIME # define NEW_TIME EMPTY #endif #ifndef OLD_TIME # define OLD_TIME EMPTY #endif #ifndef INIT_PROCESS # define INIT_PROCESS EMPTY #endif #ifndef LOGIN_PROCESS # define LOGIN_PROCESS EMPTY #endif #ifndef USER_PROCESS # define USER_PROCESS EMPTY #endif #ifndef DEAD_PROCESS # define DEAD_PROCESS EMPTY #endif #ifndef ACCOUNTING # define ACCOUNTING EMPTY #endif #ifndef UT_UNKNOWN # define UT_UNKNOWN EMPTY #endif #endif /* _HAVE_UT_TYPE */ python-utmp-0.9/debian/000077500000000000000000000000001353413715400151165ustar00rootroot00000000000000python-utmp-0.9/debian/changelog000066400000000000000000000120771353413715400167770ustar00rootroot00000000000000python-utmp (0.9-1) unstable; urgency=low * switch to quilt format * build python3 module (closes: #938246) * convert examples to python3 * fix UtmpEntry initialization in modern python -- Radovan Garabík Thu, 05 Sep 2019 09:51:02 +0200 python-utmp (0.8.3) unstable; urgency=high * remove depencency on hardening-wrapper (closes: #836649) -- Radovan Garabík Fri, 16 Sep 2016 16:03:24 +0200 python-utmp (0.8.2) unstable; urgency=low * switch to dh_python2 (closes: #786035) -- Radovan Garabík Thu, 04 Jun 2015 17:10:31 +0200 python-utmp (0.8+nmu1) unstable; urgency=low * Non-maintainer upload. * Update for python2.6 and remove dh_python call (closes: #561062) - Thanks to Scott Howard for the bug and the patch -- Scott Kitterman Wed, 10 Mar 2010 18:20:12 +0000 python-utmp (0.8+0.8.1) unstable; urgency=low * this was actually 0.8.1, but I forgot to upload it... bummer. * remove dh_python (closes: #561062), bump pyversions and python-support build dependency version -- Radovan Garabík Sun, 03 Jan 2010 17:15:24 +0100 python-utmp (0.8) unstable; urgency=low * support for python3 * __repr__ for UtmpRecord and UtmpEntry * incorporate Makefile changes by Pierre Habouzit -- Radovan Garabík Thu, 06 Aug 2009 17:49:55 +0200 python-utmp (0.7.4-0.1) unstable; urgency=low * Non-maintainer upload. * Update package to the last python policy (Closes: 373363). * Hack build system (make makefile aware of env using ?=). * remove prerm, postinst. * Avoid to install INSTALL file. -- Pierre Habouzit Sat, 1 Jul 2006 20:40:48 +0200 python-utmp (0.7.3) unstable; urgency=low * added python to Build-Depends (closes: #259124) -- Radovan Garabík Tue, 3 Aug 2004 07:52:58 +0200 python-utmp (0.7.2) unstable; urgency=low * NMU. * Fix python dependency (using dh_python). Closes: #207317. * Remove postinst/prerm files. -- Matthias Klose Fri, 5 Sep 2003 22:51:05 +0200 python-utmp (0.7.1) unstable; urgency=low * NMU. * Rebuild debian package with python2.3. * clean: remove .so module * control: add ${shlibs:Depends} -- Matthias Klose Tue, 19 Aug 2003 07:51:00 +0200 python-utmp (0.7) unstable; urgency=low * Utmp entries are not tuples/dictionaries anymore, but objects with attributes - as they should have been from the beginning -- Radovan Garabik Tue, 21 Jan 2003 15:39:45 +0100 python-utmp (0.6.1) unstable; urgency=low * rebuild debian package with python2.2 (closes: #160789) -- Radovan Garabik Tue, 24 Sep 2002 14:45:03 +0200 python-utmp (0.6) unstable; urgency=low * added iterator to UtmpRecord * debian package upgraded to work with python2.3 (closes: #160789) -- Radovan Garabik Mon, 23 Sep 2002 13:27:56 +0200 python-utmp (0.5.3) unstable; urgency=low * fix dependencies (closes: #121703) * fix postinst script * fix description -- Radovan Garabik Sat, 1 Dec 2001 19:28:53 +0100 python-utmp (0.5.2) unstable; urgency=low * upgraded debian package to python2.1 (closes: #118253) -- Radovan Garabik Tue, 16 Oct 2001 12:38:17 +0200 python2-utmp (0.5.1) unstable; urgency=low * moved Build-Depends where they belong (closes: #87270) -- Radovan Garabik Fri, 23 Feb 2001 20:39:10 +0100 python2-utmp (0.5) unstable; urgency=low * split makefiles by architecture * upgraded to python2 -- Radovan Garabik Mon, 19 Feb 2001 16:44:34 +0100 python-utmp (0.4) unstable; urgency=low * full read/write for all supported systems (including BSD) * better support for system without ut_id * support for SunOS utmpx * ut_exit and ut_tv are now tuples * ut_addr_v6 was not correctly returned, fixed * added proper casting of C variables -- Radovan Garabik Sun, 15 Oct 2000 13:04:03 +0400 python-utmp (0.3) unstable; urgency=low * preliminary read-only support for BSD systems * better support for systems without ut_type -- Radovan Garabik Sun, 1 Oct 2000 19:29:37 +0400 python-utmp (0.2) unstable; urgency=low * modules renamed * UTMPCONST.py generated from utmp.h * steps towards portability, now works on SunOS and HPUX, hopefully on wider range of SYSTEM V machines. -- Radovan Garabik Fri, 22 Sep 2000 11:22:59 +0400 python-utmp (0.1.1) unstable; urgency=low * rebuilt with a new GPG key -- Radovan Garabik Fri, 1 Sep 2000 08:35:34 +0200 python-utmp (0.1) unstable; urgency=low * Initial Release. -- Radovan Garabik Wed, 22 Mar 2000 15:22:23 +0100 python-utmp-0.9/debian/compat000066400000000000000000000000021353413715400163140ustar00rootroot000000000000009 python-utmp-0.9/debian/control000066400000000000000000000012041353413715400165160ustar00rootroot00000000000000Source: python-utmp Section: python Priority: optional Maintainer: Radovan Garabík Standards-Version: 4.4.0 Build-Depends: debhelper (>= 9), python3-all-dev, dh-python Package: python3-utmp Architecture: any Depends: ${python3:Depends}, ${shlibs:Depends}, ${misc:Depends} Provides: ${python3:Provides} Description: python module for working with utmp python-utmp provides 3 modules to access utmp and wtmp records. utmpaccess is lowlevel module wrapping glibc functions, UTMPCONST provides useful constants, and utmp is module build on top of utmpaccess module, providing object oriented interface. python-utmp-0.9/debian/copyright000066400000000000000000000013171353413715400170530ustar00rootroot00000000000000License loosely modelled after Just van Rossum's Python-Powered LOGO license: © 2000-2019 Radovan Garabík , hereafter referred to as THE AUTHOR, herewith grants you (THE USER) the right to use python-utmp (THE SOFTWARE). Blah blah blah blah. Blah NO WARRANTIES blah blah EXPLICIT blah blah blah blah OR IMPLIED blah blah blah. Blah. Blah blah Unlimited Redistribution and Modification of THE SOFTWARE by THE USER is Allowed by THE AUTHOR blah blah blah for Any Purpose blah blah blah blah blah blah blah. By Using THE SOFTWARE you Agree with this LICENSE blah blah blah blah. Blah. Blah. Blah blah. If you do not Agree with the LICENSE you should Better NOT Use THE SOFTWARE. python-utmp-0.9/debian/docs000066400000000000000000000000141353413715400157640ustar00rootroot00000000000000README TODO python-utmp-0.9/debian/examples000066400000000000000000000003471353413715400166630ustar00rootroot00000000000000examples/remove.py examples/who.py examples/last.py examples/scanutmp.py examples/finger.py examples/remove-old.py examples/who-old.py examples/last-old.py examples/scanutmp-old.py examples/vms-finger-old.py examples/finger-old.py python-utmp-0.9/debian/rules000077500000000000000000000033101353413715400161730ustar00rootroot00000000000000#!/usr/bin/make -f # Sample debian/rules that uses debhelper. # GNU copyright 1997 to 1999 by Joey Hess. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 # This is the debhelper compatability version to use. #export DH_COMPAT=5 export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed export DEB_BUILD_MAINT_OPTIONS = hardening=+all PYVERS := $(subst python,,$(shell py3versions -r)) clean: dh_testdir dh_testroot rm -f build-stamp -for ver in $(PYVERS); do \ $(MAKE) PYTHONVER=$$ver clean; done rm -f utmpaccessmodule.so dh_clean build: build-arch build-indep build-arch: build-stamp build-indep: build-stamp build-stamp: for ver in $(PYVERS); do \ $(MAKE) PYTHONVER=$$ver clean; \ $(MAKE) PYTHONVER=$$ver -f Makefile.glibc; \ done dh_testdir install: build dh_testdir dh_testroot dh_prep set -e; \ for ver in $(PYVERS); do \ $(MAKE) PYTHONVER=$$ver install DESTDIR=$(CURDIR)/debian/python3-utmp; \ done dh_installdirs # Build architecture-independent files here. binary-indep: ; # We have nothing to do by default. # Build architecture-dependent files here. binary-arch: build install # dh_installdebconf dh_installdocs dh_installexamples # dh_installmenu # dh_installemacsen # dh_installpam # dh_installinit # dh_installcron # dh_installmanpages # dh_installinfo # dh_undocumented dh_installchangelogs dh_link dh_strip dh_compress dh_fixperms dh_python3 # You may want to make some executables suid here. # dh_suidregister dh_makeshlibs dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install python-utmp-0.9/debian/source/000077500000000000000000000000001353413715400164165ustar00rootroot00000000000000python-utmp-0.9/debian/source/format000066400000000000000000000000151353413715400176250ustar00rootroot000000000000003.0 (quilt) python-utmp-0.9/examples/000077500000000000000000000000001353413715400155125ustar00rootroot00000000000000python-utmp-0.9/examples/dumputmp.py000077500000000000000000000001671353413715400177460ustar00rootroot00000000000000#!/usr/bin/python3 # dump utmp import utmp from UTMPCONST import * a = utmp.UtmpRecord() for b in a: print(b) python-utmp-0.9/examples/finger-old.py000077500000000000000000000123041353413715400201150ustar00rootroot00000000000000#!/usr/bin/python import utmp from UTMPCONST import * import time, pwd, grp, os, string, sys, socket, popen2 from stat import * from string import lower def getrealname(gec): # get real name from gecos fiels return string.split(gec,",",1)[0] def formatidle(t): if t<30: return "" if t<80: r = "%ss" % int(t) return r if t<60*80: return "%sm" % int(t/60) if t<60*60*28: return "%sh" % int(t/60/60) if t<60*60*24*20: return "%sd" % int(t/60/60/24) return "DEAD" def userlist(u, now, user=""): u.setutent() tnow = time.mktime(now) header = 0 output = [] # list of output lines, without header while 1: b = u.getutent_dict() if not b: break if b['ut_type'] == USER_PROCESS: username = b['ut_user'] if user and b['ut_user']<>user: continue try: pwnam = pwd.getpwnam(username) except KeyError: pwnam = '?' tty = b['ut_line'] t = time.localtime(b['ut_tv'][0]) then = time.mktime(t) if tnowlastlogin[0]: lastlogin = b['ut_tv'][0], b['ut_host'] u = utmp.UtmpRecord(WTMP_FILE) while 1: b = u.getutent_dict() if not b: break if b['ut_type'] in (USER_PROCESS, DEAD_PROCESS) and \ b['ut_user'] == user and \ b['ut_tv'][0]>lastlogin[0]: lastlogin = b['ut_tv'][0], b['ut_host'] u.endutent() return lastlogin def userplan(homedir): try: f = open(homedir+"/.plan", "r") print "Plan:" while 1: l = f.readline() if not l: break print string.rstrip(l) except: pass def oneuser(u, user): pwent = pwd.getpwnam(user) rn = getrealname(pwent[4]) print "Login name: %-30s In real life: %s" % (user, rn) print " Directory: %-30s Shell: %s" % (pwent[5], pwent[6]) print " %-30s Group: [%s]" % ("", grp.getgrgid(pwent[3])[0]) l, h = lastlogin(u, user) if not l: print "Never logged in." else: r = "Last login %-30s " % time.strftime("%A, %d-%b-%Y %H:%M", time.localtime(l)) if h: r = r+'from: '+h print r print userplan(pwent[5]) print if len(sys.argv) == 2 and "@" in sys.argv[1]: # remote user, host = string.split(sys.argv[1], "@", 1) try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) FINGER_PORT = 79 s.connect( (host, FINGER_PORT) ) s.send(user + '\r\n') while 1: buf = s.recv(1024) if not buf: break sys.stdout.write(buf) sys.stdout.flush() except socket.error, why: print "ERROR:", why sys.exit(0) now = time.localtime(time.time()) a = utmp.UtmpRecord() if len(sys.argv) == 1: # list of all local users r = userlist(a, now) if not r: print "No such processes." else: #first find out if user exists user = sys.argv[1] try: pwd.getpwnam(user) r = userlist(a, now, user) if not r: print '"%s" isn\'t logged in.' % user print oneuser(a, user) except KeyError: print '"%s" does not match any user of this system.' % user a.endutent() python-utmp-0.9/examples/finger.py000077500000000000000000000122311353413715400173400ustar00rootroot00000000000000#!/usr/bin/python3 import utmp from UTMPCONST import * import time, pwd, grp, os, string, sys, socket from stat import * def getrealname(gec): # get real name from gecos fiels return gec.split(",",1)[0] def formatidle(t): if t<30: return "" if t<80: r = "%ss" % int(t) return r if t<60*80: return "%sm" % int(t/60) if t<60*60*28: return "%sh" % int(t/60/60) if t<60*60*24*20: return "%sd" % int(t/60/60/24) return "DEAD" def userlist(u, now, user=""): u.setutent() tnow = time.mktime(now) header = 0 output = [] # list of output lines, without header while 1: b = u.getutent() if not b: break if b.ut_type == USER_PROCESS: username = b.ut_user if user and b.ut_user!=user: continue try: pwnam = pwd.getpwnam(username) except KeyError: pwnam = '?' tty = b.ut_line t = time.localtime(b.ut_tv[0]) then = time.mktime(t) if tnowlastlogin[0]: lastlogin = b.ut_tv[0], b.ut_host u = utmp.UtmpRecord(WTMP_FILE) while 1: b = u.getutent_dict() if not b: break if b.ut_type in (USER_PROCESS, DEAD_PROCESS) and \ b.ut_user == user and \ b.ut_tv[0]>lastlogin[0]: lastlogin = b.ut_tv[0], b.ut_host u.endutent() return lastlogin def userplan(homedir): try: f = open(homedir+"/.plan", "r") print("Plan:") while 1: l = f.readline() if not l: break print (string.rstrip(l)) except IOError: pass def oneuser(u, user): pwent = pwd.getpwnam(user) rn = getrealname(pwent[4]) print ("Login name: %-30s In real life: %s" % (user, rn)) print (" Directory: %-30s Shell: %s" % (pwent[5], pwent[6])) print (" %-30s Group: [%s]" % ("", grp.getgrgid(pwent[3])[0])) l, h = lastlogin(u, user) if not l: print("Never logged in.") else: r = "Last login %-30s " % time.strftime("%A, %d-%b-%Y %H:%M", time.localtime(l)) if h: r = r+'from: '+h print(r) print('\n') userplan(pwent[5]) print('\n') if len(sys.argv) == 2 and "@" in sys.argv[1]: # remote user, host = sys.argv[1].split("@", 1) try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) FINGER_PORT = 79 s.connect( (host, FINGER_PORT) ) s.send(user + '\r\n') while 1: buf = s.recv(1024) if not buf: break sys.stdout.write(buf) sys.stdout.flush() except socket.error: print ("ERROR connecting") raise sys.exit(0) now = time.localtime(time.time()) a = utmp.UtmpRecord() if len(sys.argv) == 1: # list of all local users r = userlist(a, now) if not r: print ("No such processes.") else: #first find out if user exists user = sys.argv[1] try: pwd.getpwnam(user) r = userlist(a, now, user) if not r: print ('"%s" isn\'t logged in.' % user) print oneuser(a, user) except KeyError: print ('"%s" does not match any user of this system.' % user) a.endutent() python-utmp-0.9/examples/last-old.py000077500000000000000000000005611353413715400176100ustar00rootroot00000000000000#!/usr/bin/python # poor man's last import utmp from UTMPCONST import * import time a = utmp.UtmpRecord(WTMP_FILE) print "%-10s %-10s %-30s %-20s" % ("USER", "TTY", "HOST", "LOGIN") while 1: b = a.getutent() if not b: break if b[0] == USER_PROCESS: print "%-10s %-10s %-30s %-20s" % (b[4], b[2], b[5], time.ctime(b[8][0])) a.endutent() python-utmp-0.9/examples/last.py000077500000000000000000000006101353413715400170270ustar00rootroot00000000000000#!/usr/bin/python3 # poor man's last import utmp from UTMPCONST import * import time a = utmp.UtmpRecord(WTMP_FILE) print ("%-10s %-10s %-30s %-20s" % ("USER", "TTY", "HOST", "LOGIN")) while 1: b = a.getutent() if not b: break if b[0] == USER_PROCESS: print ("%-10s %-10s %-30s %-20s" % (b.ut_user, b.ut_line, b.ut_host, time.ctime(b.ut_tv[0]))) a.endutent() python-utmp-0.9/examples/remove-old.py000077500000000000000000000005361353413715400201440ustar00rootroot00000000000000#!/usr/bin/python # remove tty given as argument from utmp file import utmp, sys from UTMPCONST import * a = utmp.UtmpRecord() line = sys.argv[1] b = a.getutline_dict(line) if not b: print line, "is not occupied, cannot remove." sys.exit() b['ut_type'] = DEAD_PROCESS b['ut_line'] = '' b['ut_user'] = '' a.pututline_dict(b) a.endutent() python-utmp-0.9/examples/remove.py000077500000000000000000000005011353413715400173600ustar00rootroot00000000000000#!/usr/bin/python3 # remove tty given as argument from utmp file import utmp, sys from UTMPCONST import * a = utmp.UtmpRecord() line = sys.argv[1] b = a.getutline(line) if not b: print (line, "is not occupied, cannot remove.") sys.exit() b.ut_type = DEAD_PROCESS b.ut_line = '' b.ut_user = '' a.pututline(b) python-utmp-0.9/examples/scanutmp-old.py000077500000000000000000000016301353413715400204750ustar00rootroot00000000000000#!/usr/bin/python # scan utmp and remove bogus entries # works only for systems that have ut_pid # linux has, BSD has not import utmp from UTMPCONST import * import time, os, string a = utmp.UtmpRecord() print "Removing bogus entries:" print "%-10s %-10s %5s %-25s %-20s" % ("USER", "TTY", "PID", "HOST", "LOGIN") ps = os.popen("ps aux").readlines()[1:] #ps = os.popen("ps -edf").readlines()[1:] pids = {} for i in ps: user, pid = string.split(i)[:2] pids[int(pid)] = user while 1: b = a.getutent() if not b: break if b[0] == USER_PROCESS: if (not pids.has_key(b[1])) or b[4]<>pids[b[1]]: print "%-10s %-10s %5i %-25s %-20s" % (b[4], b[2], b[1], b[5], time.ctime(b[8][0])) b = list(b) b[0] = DEAD_PROCESS b[4] = '' b[8] = (0, 0) a.pututline(b) a.getutent() # to move to next entry a.endutent() python-utmp-0.9/examples/scanutmp.py000077500000000000000000000020141353413715400177160ustar00rootroot00000000000000#!/usr/bin/python3 # scan utmp and remove bogus entries # works only for systems that have ut_pid # linux has, BSD has not # alert: sshd runs the master process as root, but writes its pid and the real user # into utmp, thus these entries will be removed, even if correct import utmp from UTMPCONST import * import time, os, string a = utmp.UtmpRecord() print ("Removing bogus entries:") print ("%-10s %-10s %5s %-25s %-20s" % ("USER", "TTY", "PID", "HOST", "LOGIN")) ps = os.popen("ps aux").readlines()[1:] #ps = os.popen("ps -edf").readlines()[1:] pids = {} for i in ps: user, pid = i.split()[:2] pids[int(pid)] = user for b in a: if b.ut_type == USER_PROCESS: if (b.ut_pid not in pids) or b.ut_user!=pids[b.ut_pid]: print ("%-10s %-10s %5i %-25s %-20s" % (b.ut_user, b.ut_line, b.ut_pid, b.ut_host, time.ctime(b.ut_tv[0]))) b.ut_type = DEAD_PROCESS b.ut_host = '' b.ut_tv = (0, 0) a.pututline(b) a.getutent() # to move to next entry python-utmp-0.9/examples/vms-finger-old.py000077500000000000000000000160421353413715400207230ustar00rootroot00000000000000#!/usr/bin/python import utmp from UTMPCONST import * import time, pwd, grp, os, string, sys, socket from stat import * from string import upper def boguslist(): # get list of (pid, tty, commandname) # bogus because we are just guessing by the output of ps pscmd = "ps ac" # seems to be common psoutput = os.popen(pscmd).readlines() output = [] del psoutput[0] for i in psoutput: l = string.split(i) pid, tty, command = int(l[0]), l[1], l[-1] output.append( (pid, tty, command) ) return output def proctable(): #make table of ttys and corresponding pids global proctbl proctbl = {} for i in boguslist(): if not proctbl.has_key(i[1]): proctbl[i[1]] = [] proctbl[i[1]].append( (i[0], i[2]) ) def header(now, boottime, ops, ver): print "Consortium for global VMSfication" print time.strftime("%A, %d-%b-%Y %H:%M,", now), "%s V%s" %(ops, ver) print "Cluster contains 1 node, formed", \ time.strftime("%A, %d-%b-%Y %H:%M", time.localtime(boottime)) print def getrealname(gec): # get real name from gecos fiels return string.split(gec,",",1)[0] def userlist(u, now, node, user=""): proctable() u.setutent() tnow = time.mktime(now) header = 0 output = [] # list of output lines, without header while 1: b = u.getutent_dict() if not b: break if b['ut_type'] == USER_PROCESS: username = b['ut_user'] if user and b['ut_user']<>user: continue try: pwnam = pwd.getpwnam(username) except KeyError: continue realname = getrealname(pwnam[4]) username = upper(username) # yeah, right :-) if 0: try: # this works on linux and freebsd # unfortunately, even if it works, # it does not work well because it always returns shell... f = open("/proc/%i/cmdline" % b['ut_pid'], "r") program = f.read() program = os.path.split(program)[1] except: program = "?" tty = b['ut_line'] program = max(proctbl[tty])[1] program = string.split(program, ".")[0] # SunOS uses dots in names shell = os.path.split(pwnam[6])[1] if program == shell or (program[0]=="-" and program[1:]==shell): program = "$" t = time.localtime(b['ut_tv'][0]) then = time.mktime(t) if tnowlastlogin: lastlogin = b['ut_tv'][0] u = utmp.UtmpRecord(WTMP_FILE) while 1: b = u.getutent_dict() if not b: break if b['ut_type'] in (USER_PROCESS, DEAD_PROCESS) and \ b['ut_user'] == user and \ b['ut_tv'][0]>lastlogin: lastlogin = b['ut_tv'][0] u.endutent() return lastlogin def userplan(homedir): try: f = open(homedir+"/.plan", "r") print "Plan:" while 1: l = f.readline() if not l: break print string.rstrip(l) except: pass def oneuser(u, user): pwent = pwd.getpwnam(user) print "Login name: %-28sIn real life: %s" % \ (upper(user), getrealname(pwent[4])) print " Directory: %-37sUIC: [%s,%s] ([%i,%i])" % \ (pwent[5], upper(grp.getgrgid(pwent[3])[0]), upper(user), pwent[3], pwent[2]) l = lastlogin(u, user) if not l: print "Never logged in." else: print "Last login:", time.strftime("%A, %d-%b-%Y %H:%M", time.localtime(l)) print userplan(pwent[5]) def guessbotttime(u): # try to find out boot time boottime = os.stat("/")[ST_CTIME] #fallback u.setutent() while 1: b = u.getutent_dict() if not b: break if b['ut_type'] == BOOT_TIME: boottime = b['ut_tv'][0] return boottime if len(sys.argv) == 2 and "@" in sys.argv[1]: # remote user, host = string.split(sys.argv[1], "@", 1) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) FINGER_PORT = 79 s.connect( (host, FINGER_PORT) ) s.send(user + '\r\n') while 1: buf = s.recv(1024) if not buf: break sys.stdout.write(buf) sys.stdout.flush() sys.exit(0) un = os.uname() ops = un[0] node = un[1] ver = un[2] node = upper(node) now = time.localtime(time.time()) a = utmp.UtmpRecord() boottime = guessbotttime(a) if len(sys.argv) == 1: # list of all local users header(now, boottime, ops, ver) r = userlist(a, now, node) if not r: print "No such processes." else: #first find out if user exists user = sys.argv[1] try: pwd.getpwnam(user) r = userlist(a, now, node, user) if not r: print upper(user), "isn't logged in." print oneuser(a, user) except KeyError: lou = [] # list of matching users if len(user)>=3: for i in pwd.getpwall(): rn = getrealname(i[4]) if string.count(upper(rn), upper(user)): lou.append( (i[0], rn) ) if not lou: print upper(user), "does not match any user of this system." else: print 'Users who have "%s" in their real names:' % upper(user) for i in lou: print "%-13s- %s" % (upper(i[0]), i[1]) a.endutent() python-utmp-0.9/examples/who-old.py000077500000000000000000000006561353413715400174470ustar00rootroot00000000000000#!/usr/bin/python # poor man's who import utmp from UTMPCONST import * import time a = utmp.UtmpRecord() print "%-10s %-10s %5s %-25s %-20s" % ("USER", "TTY", "PID", "HOST", "LOGIN") for b in a: # example of using an iterator if b['ut_type'] == USER_PROCESS: print "%-10s %-10s %5i %-25s %-20s" % \ (b['ut_user'], b['ut_line'], b['ut_pid'], b['ut_host'], time.ctime(b['ut_tv'][0])) a.endutent() python-utmp-0.9/examples/who.py000077500000000000000000000006771353413715400166760ustar00rootroot00000000000000#!/usr/bin/python3 # poor man's who import utmp from UTMPCONST import * import time a = utmp.UtmpRecord() print ("%-10s %-10s %5s %-25s %-20s" % ("USER", "TTY", "PID", "HOST", "LOGIN")) for b in a: # example of using an iterator if b.ut_type == USER_PROCESS: print ( "%-10s %-10s %5i %-25s %-20s" % \ (b.ut_user, b.ut_line, b.ut_pid, b.ut_host, time.ctime(b.ut_tv[0])) ) a.endutent() python-utmp-0.9/makeconst.c000066400000000000000000000010741353413715400160260ustar00rootroot00000000000000#include #include #include "constants.h" #define PRL(s) printf(#s" = %i\n", s); #define PRLS(s) printf(#s" = \"%s\"\n", s); int main(void) { PRL(EMPTY); PRL(RUN_LVL); PRL(BOOT_TIME); PRL(NEW_TIME); PRL(OLD_TIME); PRL(INIT_PROCESS); PRL(LOGIN_PROCESS); PRL(USER_PROCESS); PRL(DEAD_PROCESS); PRL(ACCOUNTING); PRL(UT_UNKNOWN); printf("\n"); PRL(UT_LINESIZE); PRL(UT_NAMESIZE); PRL(UT_HOSTSIZE); PRL(UT_IDSIZE); printf("\n"); PRLS(UTMP_FILE); PRLS(WTMP_FILE); return 0; } python-utmp-0.9/makeconst.sh000077500000000000000000000001271353413715400162170ustar00rootroot00000000000000#!/bin/sh gcc -Wall -pedantic makeconst.c $* -o makeconst ./makeconst > UTMPCONST.py python-utmp-0.9/utmp.py000066400000000000000000000141311353413715400152330ustar00rootroot00000000000000import utmpaccess from UTMPCONST import * import types class UtmpEntry: def __init__(self, *arg, **dictarg): self.clear() if len(arg)==1: arg = arg[0] if (type(arg)==tuple or type(arg)==list) and arg: self.ut_type, self.ut_pid, self.ut_line, \ self.ut_id, self.ut_user, self.ut_host, \ self.ut_exit, self.ut_session, self.ut_tv, \ self.ut_addr_v6 = arg elif type(arg)==dict: for i in arg.keys(): self[i] = arg[i] elif type(arg)==type(self): self.ut_type, self.ut_pid, self.ut_line, \ self.ut_id, self.ut_user, self.ut_host, \ self.ut_exit, self.ut_session, self.ut_tv, \ self.ut_addr_v6 = arg.ut_type, arg.ut_pid, arg.ut_line, \ arg.ut_id, arg.ut_user, arg.ut_host, \ arg.ut_exit, arg.ut_session, arg.ut_tv, \ arg.ut_addr_v6 for i in dictarg.keys(): self[i] = dictarg[i] def clear(self): self.ut_type = EMPTY self.ut_pid = 0 self.ut_line = '' self.ut_id = '' self.ut_user = '' self.ut_host = '' self.ut_exit = (0, 0) self.ut_session = 0 self.ut_tv = (0, 0) self.ut_addr_v6 = (0, 0, 0, 0) def _as_tuple(self): return (self.ut_type, self.ut_pid, self.ut_line, \ self.ut_id, self.ut_user, self.ut_host, \ self.ut_exit, self.ut_session, self.ut_tv, \ self.ut_addr_v6) def __getitem__(self, item): if item=='ut_type' or item==0: return self.ut_type elif item=='ut_pid' or item==1: return self.ut_pid elif item=='ut_line' or item==2: return self.ut_line elif item=='ut_id' or item==3: return self.ut_id elif item=='ut_user' or item==4: return self.ut_user elif item=='ut_host' or item==5: return self.ut_host elif item=='ut_exit' or item==6: return self.ut_exit elif item=='ut_session' or item==7: return self.ut_session elif item=='ut_tv' or item==8: return self.ut_tv elif item=='ut_addr_v6' or item==9: return self.ut_addr_v6 else: raise IndexError("Bad key used to access UtmpEntry: "+repr(item)) def __setitem__(self, item, val): if item=='ut_type' or item==0: self.ut_type=val elif item=='ut_pid' or item==1: self.ut_pid=val elif item=='ut_line' or item==2: self.ut_line=val elif item=='ut_id' or item==3: self.ut_id=val elif item=='ut_user' or item==4: self.ut_user=val elif item=='ut_host' or item==5: self.ut_host=val elif item=='ut_exit' or item==6: self.ut_exit=val elif item=='ut_session' or item==7: self.ut_session=val elif item=='ut_tv' or item==8: self.ut_tv=val elif item=='ut_addr_v6' or item==9: self.ut_addr_v6=val else: raise IndexError("Bad key used to access UtmpEntry: "+repr(item)) def __repr__(self): fs = [] for key in 'ut_type', 'ut_pid', 'ut_line', \ 'ut_id', 'ut_user', 'ut_host', \ 'ut_exit', 'ut_session', 'ut_tv', \ 'ut_addr_v6': fs.append( key+'='+repr(self[key]) ) fs = ', '.join(fs) r = fs r = 'utmp.UtmpEntry( %s )' % fs return r class UtmpRecord: def __init__(self, fname=None): if fname: utmpaccess.utmpname(fname) self.fname = fname self.setutent() def _makeclass(self, a): if not a: return None return UtmpEntry(a) def setutent(self): "rewinds the file pointer to the beginning of the utmp file." utmpaccess.setutent() def endutent(self): "closes the utmp file." utmpaccess.endutent() def getutent(self): """reads a line from the current file position in the utmp file. It returns an UtmpEntry instance corresponding to a given line.""" return self._makeclass(utmpaccess.getutent()) def __iter__(self): return self def __next__(self): r = self.getutent() if not r: raise StopIteration return r next = __next__ def pututline(self, *ut, **dictut): """writes the UtmpEntry provided as parameter into the utmp file. It uses getutid() to search for the proper place in the file to insert the new entry. If it cannot find an appropriate slot for ut, pututline() will append the new entry to the end of the file.""" if len(ut) == 1: # one tuple passed as argument u=ut[0] else: u = ut u = UtmpEntry(u, **dictut) utmpaccess.pututline(*u._as_tuple()) def getutid(self, ut_type, ut_id=''): """searches forward from the current file position in the utmp file based upon ut_type. If ut_type is RUN_LVL, BOOT_TIME, NEW_TIME, or OLD_TIME, getutid() will find the first entry whose ut_type field matches ut_type argument. If ut_type is one of INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS, getutid() will find the first entry whose ut_id field matches ut_id argument.""" return self._makeclass(utmpaccess.getutid(ut_type, ut_id)) def getutline(self, ut_line): """searches forward from the current file position in the utmp file. It scans entries whose ut_type is USER_PROCESS or LOGIN_PROCESS and returns the first one whose ut_line field matches ut_lie argument.""" return self._makeclass(utmpaccess.getutline(ut_line)) getutent_dict = getutent pututline_dict = pututline getutid_dict = getutid getutline_dict = getutline def __del__(self): self.endutent() def __repr__(self): if not self.fname: fname = '' return 'utmp.UtmpRecord(%s)' % fname python-utmp-0.9/utmpaccessmodule.c000066400000000000000000000300341353413715400174150ustar00rootroot00000000000000#include "Python.h" #include "constants.h" /* define out "ideal" struct utmp, based on glibc utmp */ struct myutmp { short ut_type; /* type of login */ pid_t ut_pid; /* pid of login process */ char ut_line[UT_LINESIZE + 1]; /* device name of tty - "/dev/" */ char ut_id[UT_IDSIZE + 1]; /* init id or abbrev. ttyname */ char ut_user[UT_NAMESIZE + 1]; /* user name */ char ut_host[UT_HOSTSIZE + 1]; /* hostname for remote login */ short int e_termination; /* process termination status. */ short int e_exit; /* process exit status. */ long ut_session; /* session ID, used for windowing */ long tv_sec; /* time entry was made. */ long tv_usec; int32_t ut_addr_v6[4]; /* IP address of remote host. */ }; /* some helper functions */ /* return ut_type of system utmp struct, making it up if it is without one */ int checktype(s) struct choice_utmp *s; { #ifdef _HAVE_UT_TYPE return s->ut_type; #else int r; r = USER_PROCESS; /* pretend everything to be of type USER_PROCESS */ if ((s->ut_user[0] == '\0') && (s->ut_host[0] == '\0')) { if (s->ut_line[0] == '\0') /* empty record */ r = EMPTY; else r = DEAD_PROCESS; } else { if (!strncmp(s->ut_line, "~", UT_LINESIZE)) /* reboot or shutdown */ r = BOOT_TIME; } /* { and | are NOT included, because at least at my linux box they are entered with ut_type USER_PROCESS, which does not seem to be quite correct */ return r; #endif } /* return pointer to ut_id, or ut_line if it is without ut_id */ char *checkid(s) struct choice_utmp *s; { #ifdef _HAVE_UT_ID return s->ut_id; #else return s->ut_line; #endif } /* copy system utmp to our ideal one, using default values if system utmp does not have all the fields we have */ void system2my(m, s) struct myutmp *m; struct choice_utmp *s; { m->ut_type = checktype(s); #ifdef _HAVE_UT_PID m->ut_pid = s->ut_pid; #else m->ut_pid = 0; #endif strncpy(m->ut_line, s->ut_line, UT_LINESIZE); strncpy(m->ut_id, checkid(s), UT_IDSIZE); strncpy(m->ut_user, s->ut_user, UT_NAMESIZE); #ifdef _HAVE_UT_HOST strncpy(m->ut_host, s->ut_host, UT_HOSTSIZE); #else m->ut_host[0] = '\0'; #endif #ifdef _HAVE_UT_EXIT m->e_termination = s->ut_exit.e_termination; m->e_exit = s->ut_exit.e_exit; #else m->e_termination = 0; m->e_exit = 0; #endif #ifdef _HAVE_UT_TV m->tv_sec = s->ut_tv.tv_sec; m->tv_usec = s->ut_tv.tv_usec; #else m->tv_sec = s->ut_time; m->tv_usec = 0; #endif #ifdef _HAVE_UT_ADDR_V6 memcpy(m->ut_addr_v6, s->ut_addr_v6, 4 * sizeof(int32_t)); #else memset(m->ut_addr_v6, 0, 4 * sizeof(int32_t)); #endif #ifdef _HAVE_UT_SESSION m->ut_session = s->ut_session; #else m->ut_session = 0; #endif m->ut_line[UT_LINESIZE] = '\0'; m->ut_user[UT_NAMESIZE] = '\0'; m->ut_host[UT_HOSTSIZE] = '\0'; m->ut_id[UT_IDSIZE] = '\0'; } /* copy our ideal utmp to system one, copy only those fields system utmp has */ void my2system(s, m) struct myutmp *m; struct choice_utmp *s; { #ifdef _HAVE_UT_HOST strncpy(s->ut_host, m->ut_host, UT_HOSTSIZE); #endif strncpy(s->ut_user, m->ut_user, UT_NAMESIZE); #ifdef _HAVE_UT_TYPE s->ut_type = m->ut_type; #else if ((m->ut_type != USER_PROCESS) && (m->ut_type == BOOT_TIME)) { memset(s->ut_user, 0, UT_NAMESIZE); # ifdef _HAVE_UT_HOST memset(s->ut_host, 0, UT_HOSTSIZE); # endif } #endif #ifdef _HAVE_UT_PID s->ut_pid = m->ut_pid; #endif #ifdef _HAVE_UT_ID strncpy(checkid(s), m->ut_id, UT_IDSIZE); #endif strncpy(s->ut_line, m->ut_line, UT_LINESIZE); #ifdef _HAVE_UT_EXIT s->ut_exit.e_termination = m->e_termination; s->ut_exit.e_exit = m->e_exit; #endif #ifdef _HAVE_UT_TV s->ut_tv.tv_sec = m->tv_sec; s->ut_tv.tv_usec = m->tv_usec; #else s->ut_time = m->tv_sec; #endif #ifdef _HAVE_UT_ADDR_V6 memcpy(s->ut_addr_v6, m->ut_addr_v6, 4 * sizeof(int32_t)); #endif #ifdef _HAVE_UT_SESSION s->ut_session = m->ut_session; #endif } #define OUTVALUE(entry) \ "(hlssss(hh)l(ll)(llll))", \ entry->ut_type, \ (long)(entry->ut_pid), \ entry->ut_line, \ entry->ut_id, \ entry->ut_user, \ entry->ut_host, \ entry->e_termination, \ entry->e_exit, \ entry->ut_session, \ entry->tv_sec, \ entry->tv_usec, \ (long)(entry->ut_addr_v6[0]), \ (long)(entry->ut_addr_v6[1]), \ (long)(entry->ut_addr_v6[2]), \ (long)(entry->ut_addr_v6[3]) #ifndef _HAVE_SETUTENT static char _utmpfilename[MAXPATHLEN] = UTMP_FILE; static long _offset = 0; static struct choice_utmp _utmprec; #endif #ifndef _HAVE_UTMPNAME void my_utmpname(name) char *name; { strncpy(_utmpfilename, name, sizeof(_utmpfilename)); } #else # ifdef USE_UTMPX # define my_utmpname utmpxname # else # define my_utmpname utmpname # endif #endif static PyObject *utmp_utmpname(self, args) PyObject *self; PyObject *args; { char *fname; if (!PyArg_ParseTuple(args, "s", &fname)) return NULL; my_utmpname(fname); Py_INCREF(Py_None); return Py_None; } #ifndef _HAVE_SETUTENT void my_setutent(void) { _offset = 0; } #else # ifdef USE_UTMPX # define my_setutent setutxent # else # define my_setutent setutent # endif #endif static PyObject *utmp_setutent(self, args) PyObject *self; PyObject *args; { if (!PyArg_ParseTuple(args, "")) return NULL; my_setutent(); Py_INCREF(Py_None); return Py_None; } #ifndef _HAVE_GETUTENT struct choice_utmp *my_getutent() { FILE *f; size_t l; int r; f = fopen(_utmpfilename, "rb"); if (f == NULL) { PyErr_SetFromErrno(PyExc_IOError); return NULL; } r = fseek(f, (long) _offset * STRUCTSIZE, SEEK_SET); if (r == -1) { return NULL; } _offset++; /* now it points _after_ the record just read */ l = fread(&_utmprec, STRUCTSIZE, 1, f); fclose(f); if (l == 1) return &_utmprec; else return NULL; } #else # ifdef USE_UTMPX # define my_getutent getutxent # else # define my_getutent getutent # endif #endif static PyObject *utmp_getutent(self, args) PyObject *self; PyObject *args; { struct choice_utmp *entry; struct myutmp myentry; if (!PyArg_ParseTuple(args, "")) return NULL; entry = my_getutent(); if (!entry) { Py_INCREF(Py_None); return Py_None; }; system2my(&myentry, entry); return Py_BuildValue(OUTVALUE((&myentry))); } #ifndef _HAVE_GETUTID struct choice_utmp *my_getutid(u) struct choice_utmp *u; { int t; struct choice_utmp *a; t = checktype(u); if ((t == RUN_LVL) || (t == BOOT_TIME) || (t == NEW_TIME) || (t == OLD_TIME)) while ((a = my_getutent())) { if (t == checktype(a)) return a; } else if ((t == INIT_PROCESS) || (t == LOGIN_PROCESS) || (t == USER_PROCESS) || (t == DEAD_PROCESS)) while ((a = my_getutent())) { if (!strncmp(checkid(a), checkid(u), UT_IDSIZE)) return a; } return NULL; } #else # ifdef USE_UTMPX # define my_getutid getutxid # else # define my_getutid getutid # endif #endif static PyObject *utmp_getutid(self, args) /* args are ut_type[, ut_id] */ PyObject *self; PyObject *args; { struct myutmp myentry; struct choice_utmp entry; struct choice_utmp *nentry; struct myutmp mynentry; short ut_type; char *ut_id = ""; if (!PyArg_ParseTuple(args, "h|s", &ut_type, &ut_id)) return NULL; myentry.ut_type = ut_type; strncpy(myentry.ut_id, ut_id, UT_IDSIZE); my2system(&entry, &myentry); nentry = my_getutid(&entry); if (!nentry) { Py_INCREF(Py_None); return Py_None; }; system2my(&mynentry, nentry); return Py_BuildValue(OUTVALUE((&mynentry))); } #ifndef _HAVE_GETUTLINE struct choice_utmp *my_getutline(u) struct choice_utmp *u; { struct choice_utmp *a; int t; while ((a = my_getutent())) { t = checktype(a); if (((t == USER_PROCESS) || (t == LOGIN_PROCESS)) && (!strncmp(a->ut_line, u->ut_line, UT_LINESIZE))) return a; } return NULL; } #else # ifdef USE_UTMPX # define my_getutline getutxline # else # define my_getutline getutline # endif #endif static PyObject *utmp_getutline(self, args) /* args is ut_line */ PyObject *self; PyObject *args; { struct choice_utmp entry; struct choice_utmp *nentry; struct myutmp mynentry; char *ut_line; if (!PyArg_ParseTuple(args, "s", &ut_line)) return NULL; strncpy(entry.ut_line, ut_line, UT_LINESIZE); nentry = my_getutline(&entry); if (!nentry) { Py_INCREF(Py_None); return Py_None; }; system2my(&mynentry, nentry); return Py_BuildValue(OUTVALUE((&mynentry))); } #ifndef _HAVE_PUTUTLINE void my_pututline(u) struct choice_utmp *u; { struct choice_utmp *a; FILE *f; int r; _offset--; /* if we are at the correct line, offset points after it */ a = my_getutid(u); if (!a) { f = fopen(_utmpfilename, "ab"); if (f == NULL) { /* PyErr_SetFromErrno (PyExc_IOError);*/ return; } fwrite(u, STRUCTSIZE, 1, f); fclose(f); } else { f = fopen(_utmpfilename, "r+b"); if (f == NULL) { /* PyErr_SetFromErrno (PyExc_IOError);*/ return; } _offset--; if (_offset < 0) { PyErr_SetFromErrno(PyExc_IOError); return; } r = fseek(f, (long) _offset * STRUCTSIZE, SEEK_SET); if (r == -1) { /* something went wrong */ PyErr_SetFromErrno(PyExc_IOError); return; } fwrite(u, STRUCTSIZE, 1, f); fclose(f); } } #else # ifdef USE_UTMPX # define my_pututline pututxline # else # define my_pututline pututline # endif #endif static PyObject *utmp_pututline(self, args) PyObject *self; PyObject *args; { struct choice_utmp entry; struct myutmp myentry; char *ut_line, *ut_id, *ut_user, *ut_host; long ut_addr_v6[4]; /* what if we are on platform where sizeof(int)=16 (minix?) ? */ /* let's play it safe */ long ut_pid; /* we have to cheat here because sizeof(pid_t) is unknown */ /* just hope it is not more than sizeof(long) */ unsigned short int i; if (!PyArg_ParseTuple(args, "hlssss(hh)l(ll)(llll)", &myentry.ut_type, &ut_pid, &ut_line, &ut_id, &ut_user, &ut_host, &myentry.e_termination, &myentry.e_exit, &myentry.ut_session, &myentry.tv_sec, &myentry.tv_usec, &ut_addr_v6[0], &ut_addr_v6[1], &ut_addr_v6[2], &ut_addr_v6[3])) return NULL; myentry.ut_pid = (pid_t) ut_pid; for (i = 0; i < 4; i++) myentry.ut_addr_v6[i] = (int32_t) ut_addr_v6[i]; strncpy(myentry.ut_line, ut_line, UT_LINESIZE); strncpy(myentry.ut_id, ut_id, UT_IDSIZE); strncpy(myentry.ut_user, ut_user, UT_NAMESIZE); strncpy(myentry.ut_host, ut_host, UT_HOSTSIZE); my2system(&entry, &myentry); my_pututline(&entry); Py_INCREF(Py_None); return Py_None; } #ifndef _HAVE_ENDUTENT void my_endutent() { } #else # ifdef USE_UTMPX # define my_endutent endutxent # else # define my_endutent endutent # endif #endif static PyObject *utmp_endutent(self, args) PyObject *self; PyObject *args; { if (!PyArg_ParseTuple(args, "")) return NULL; my_endutent(); Py_INCREF(Py_None); return Py_None; } static PyMethodDef UtmpMethods[] = { {"utmpname", utmp_utmpname, METH_VARARGS}, {"setutent", utmp_setutent, METH_VARARGS}, {"getutent", utmp_getutent, METH_VARARGS}, {"endutent", utmp_endutent, METH_VARARGS}, {"getutid", utmp_getutid, METH_VARARGS}, {"getutline", utmp_getutline, METH_VARARGS}, {"pututline", utmp_pututline, METH_VARARGS}, {NULL, NULL} /* Sentinel */ }; #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef utmpaccessmodule = { PyModuleDef_HEAD_INIT, "utmpaccess", /* name of module */ NULL, /* module documentation, may be NULL */ -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ UtmpMethods }; PyMODINIT_FUNC PyInit_utmpaccess(void) { return PyModule_Create(&utmpaccessmodule); } #else void initutmpaccess() { (void) Py_InitModule("utmpaccess", UtmpMethods); } #endif