Ménage
* autologout : script nazi pour tuer les gens en provenance du serveur BDE, s'pô juste. * syncmail : CVS is from the past * wwho : ça a pas l'air furieusement utile, et en plus comme l'encoding est pas déclaré, on peut même pas le lancer.
This commit is contained in:
parent
8af4309b8b
commit
509386924d
3 changed files with 0 additions and 0 deletions
39
archive/autologout.py
Executable file
39
archive/autologout.py
Executable file
|
@ -0,0 +1,39 @@
|
|||
#! /usr/bin/env python
|
||||
|
||||
import re, commands
|
||||
import crans.utils.logs
|
||||
log = crans.utils.logs.getFileLogger('autologout')
|
||||
|
||||
# pour chaque ligne du w
|
||||
for w in commands.getoutput("w -h").split('\n') :
|
||||
if not w : continue
|
||||
# on splite
|
||||
w = w.split()
|
||||
|
||||
if w[0] in ['cohen','segaud']:
|
||||
continue
|
||||
|
||||
# on verifie que c'est une connection du bde
|
||||
hosts = ['bde.crans.org','cableur.crans.org','cableuse.crans.org','venus.crans.org']
|
||||
if w[2] not in [ h[0:16] for h in hosts ] :
|
||||
continue
|
||||
|
||||
# on verifie qu'on a depase le timeout
|
||||
if re.match('^\d*\.\d*s$', w[4]) or re.match('^[0-4]:\d*m$', w[4]) :
|
||||
continue
|
||||
|
||||
# on reccuperre les processus s le tty
|
||||
ps = commands.getoutput('ps auwwx | grep "%s" | head -n 1' % w[1] ).split()
|
||||
|
||||
# on verrifie que c'est le bon user
|
||||
if ps[0] != w[0] :
|
||||
continue
|
||||
|
||||
# on verifie qu'on a pas de tty
|
||||
if ps[6] != '?' :
|
||||
continue
|
||||
|
||||
# on tue le process
|
||||
commands.getoutput('kill %s' % ps[1] )
|
||||
log.info("%s a ete deconnecte" % ps[0])
|
||||
#print ps
|
485
archive/syncmail
Executable file
485
archive/syncmail
Executable file
|
@ -0,0 +1,485 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: iso-8859-15 -*-
|
||||
|
||||
# Copyright (c) 2002, 2003, Barry Warsaw, Fred Drake, and contributors
|
||||
# All rights reserved.
|
||||
# See the accompanying LICENSE file for details.
|
||||
|
||||
# NOTE: Until SourceForge installs a modern version of Python on the cvs
|
||||
# servers, this script MUST be compatible with Python 1.5.2.
|
||||
|
||||
"""Complicated notification for CVS checkins.
|
||||
|
||||
This script is used to provide email notifications of changes to the CVS
|
||||
repository. These email changes will include context diffs of the changes.
|
||||
Really big diffs will be trimmed.
|
||||
|
||||
This script is run from a CVS loginfo file (see $CVSROOT/CVSROOT/loginfo). To
|
||||
set this up, create a loginfo entry that looks something like this:
|
||||
|
||||
mymodule /path/to/this/script %%s some-email-addr@your.domain
|
||||
|
||||
In this example, whenever a checkin that matches `mymodule' is made, this
|
||||
script is invoked, which will generate the diff containing email, and send it
|
||||
to some-email-addr@your.domain.
|
||||
|
||||
Note: This module used to also do repository synchronizations via
|
||||
rsync-over-ssh, but since the repository has been moved to SourceForge,
|
||||
this is no longer necessary. The syncing functionality has been ripped
|
||||
out in the 3.0, which simplifies it considerably. Access the 2.x versions
|
||||
to refer to this functionality. Because of this, the script is misnamed.
|
||||
|
||||
It no longer makes sense to run this script from the command line. Doing so
|
||||
will only print out this usage information.
|
||||
|
||||
Usage:
|
||||
|
||||
%(PROGRAM)s [options] <%%S> email-addr [email-addr ...]
|
||||
|
||||
Where options are:
|
||||
|
||||
--cvsroot=<path>
|
||||
Use <path> as the environment variable CVSROOT. Otherwise this
|
||||
variable must exist in the environment.
|
||||
|
||||
--context=#
|
||||
-C #
|
||||
Include # lines of context around lines that differ (default: 2).
|
||||
|
||||
-c
|
||||
Produce a context diff (default).
|
||||
|
||||
-m hostname
|
||||
--mailhost hostname
|
||||
The hostname of an available SMTP server. The default is
|
||||
'localhost'.
|
||||
|
||||
-u
|
||||
Produce a unified diff (smaller).
|
||||
|
||||
-S TEXT
|
||||
--subject-prefix=TEXT
|
||||
Prepend TEXT to the email subject line.
|
||||
|
||||
-R ADDR
|
||||
--reply-to=ADDR
|
||||
Add a "Reply-To: ADDR" header to the email message.
|
||||
|
||||
--charset=charset
|
||||
Add a encoding header to message.
|
||||
|
||||
--quiet / -q
|
||||
Don't print as much status to stdout.
|
||||
|
||||
--fromhost=hostname
|
||||
-f hostname
|
||||
The hostname that email messages appear to be coming from. The From:
|
||||
header of the outgoing message will look like user@hostname. By
|
||||
default, hostname is the machine's fully qualified domain name.
|
||||
|
||||
--help / -h
|
||||
Print this text.
|
||||
|
||||
The rest of the command line arguments are:
|
||||
|
||||
<%%S>
|
||||
CVS %%s loginfo expansion. When invoked by CVS, this will be a single
|
||||
string containing the directory the checkin is being made in, relative
|
||||
to $CVSROOT, followed by the list of files that are changing. If the
|
||||
%%s in the loginfo file is %%{sVv}, context diffs for each of the
|
||||
modified files are included in any email messages that are generated.
|
||||
|
||||
email-addrs
|
||||
At least one email address.
|
||||
"""
|
||||
__version__ = '1.2'
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import time
|
||||
import string
|
||||
import getopt
|
||||
import smtplib
|
||||
import pwd
|
||||
import socket
|
||||
|
||||
try:
|
||||
from socket import getfqdn
|
||||
except ImportError:
|
||||
def getfqdn():
|
||||
# Python 1.5.2 :(
|
||||
hostname = socket.gethostname()
|
||||
byaddr = socket.gethostbyaddr(socket.gethostbyname(hostname))
|
||||
aliases = byaddr[1]
|
||||
aliases.insert(0, byaddr[0])
|
||||
aliases.insert(0, hostname)
|
||||
for fqdn in aliases:
|
||||
if '.' in fqdn:
|
||||
break
|
||||
else:
|
||||
fqdn = 'localhost.localdomain'
|
||||
return fqdn
|
||||
|
||||
|
||||
from cStringIO import StringIO
|
||||
|
||||
# Which SMTP server to do we connect to?
|
||||
MAILHOST = 'localhost'
|
||||
MAILPORT = 25
|
||||
|
||||
# Diff trimming stuff
|
||||
DIFF_HEAD_LINES = 20
|
||||
DIFF_TAIL_LINES = 20
|
||||
DIFF_TRUNCATE_IF_LARGER = 1000
|
||||
|
||||
COMMASPACE = ', '
|
||||
|
||||
PROGRAM = sys.argv[0]
|
||||
|
||||
BINARY_EXPLANATION_LINES = [
|
||||
"(This appears to be a binary file; contents omitted.)\n"
|
||||
]
|
||||
|
||||
NOVERSION = "Couldn't generate diff; no version number found for file: %s"
|
||||
BACKSLASH = "Couldn't generate diff: backslash in filespec's filename: %s"
|
||||
|
||||
|
||||
|
||||
def usage(code, msg=''):
|
||||
print __doc__ % globals()
|
||||
if msg:
|
||||
print msg
|
||||
sys.exit(code)
|
||||
|
||||
|
||||
|
||||
def calculate_diff(entry, contextlines):
|
||||
file = entry.name
|
||||
oldrev = entry.revision
|
||||
newrev = entry.new_revision
|
||||
|
||||
# Make sure we can find a CVS version number
|
||||
if oldrev is None and newrev is None:
|
||||
return NOVERSION % file
|
||||
|
||||
if string.find(file, "'") <> -1:
|
||||
# Those crazy users put single-quotes in their file names! Now we
|
||||
# have to escape everything that is meaningful inside double-quotes.
|
||||
filestr = string.replace(file, '\\', '\\\\')
|
||||
filestr = string.replace(filestr, '`', '\`')
|
||||
filestr = string.replace(filestr, '"', '\"')
|
||||
filestr = string.replace(filestr, '$', '\$')
|
||||
# and quote it with double-quotes.
|
||||
filestr = '"' + filestr + '"'
|
||||
else:
|
||||
# quote it with single-quotes.
|
||||
filestr = "'" + file + "'"
|
||||
if oldrev is None:
|
||||
# File is being added.
|
||||
try:
|
||||
if os.path.exists(file):
|
||||
fp = open(file)
|
||||
else:
|
||||
update_cmd = "cvs -fn update -r %s -p %s" % (newrev, filestr)
|
||||
fp = os.popen(update_cmd)
|
||||
lines = fp.readlines()
|
||||
fp.close()
|
||||
# Is this a binary file? Let's look at the first few
|
||||
# lines to figure it out:
|
||||
#for line in lines[:5]:
|
||||
# for c in string.rstrip(line):
|
||||
# if c in string.whitespace:
|
||||
# continue
|
||||
# if c < ' ' or c > chr(127):
|
||||
# lines = BINARY_EXPLANATION_LINES[:]
|
||||
# break
|
||||
lines.insert(0, '--- NEW FILE: %s ---\n' % file)
|
||||
except IOError, e:
|
||||
lines = ['***** Error reading new file: ',
|
||||
str(e), '\n***** file: ', file, ' cwd: ', os.getcwd()]
|
||||
elif newrev is None:
|
||||
lines = ['--- %s DELETED ---\n' % file]
|
||||
else:
|
||||
# File has been changed.
|
||||
# This /has/ to happen in the background, otherwise we'll run into CVS
|
||||
# lock contention. What a crock.
|
||||
if contextlines > 0:
|
||||
difftype = "-C " + str(contextlines)
|
||||
else:
|
||||
difftype = "-u"
|
||||
diffcmd = "/usr/bin/cvs -f diff -kk %s --minimal -r %s -r %s %s" \
|
||||
% (difftype, oldrev, newrev, filestr)
|
||||
fp = os.popen(diffcmd)
|
||||
lines = fp.readlines()
|
||||
# ignore the error code, it always seems to be 1 :(
|
||||
fp.close()
|
||||
if len(lines) > DIFF_TRUNCATE_IF_LARGER:
|
||||
removedlines = len(lines) - DIFF_HEAD_LINES - DIFF_TAIL_LINES
|
||||
del lines[DIFF_HEAD_LINES:-DIFF_TAIL_LINES]
|
||||
lines.insert(DIFF_HEAD_LINES,
|
||||
'[...%d lines suppressed...]\n' % removedlines)
|
||||
return string.join(lines, '')
|
||||
|
||||
|
||||
|
||||
rfc822_specials_re = re.compile(r'[\(\)\<\>\@\,\;\:\\\"\.\[\]]')
|
||||
|
||||
def quotename(name):
|
||||
if name and rfc822_specials_re.search(name):
|
||||
return '"%s"' % string.replace(name, '"', '\\"')
|
||||
else:
|
||||
return name
|
||||
|
||||
|
||||
|
||||
def blast_mail(subject, people, entries, contextlines, fromhost, replyto, charset):
|
||||
# cannot wait for child process or that will cause parent to retain cvs
|
||||
# lock for too long. Urg!
|
||||
if not os.fork():
|
||||
# in the child
|
||||
# give up the lock you cvs thang!
|
||||
time.sleep(2)
|
||||
# Create the smtp connection to the localhost
|
||||
conn = smtplib.SMTP()
|
||||
conn.connect(MAILHOST, MAILPORT)
|
||||
user = os.getenv("SUDO_USER", pwd.getpwuid(os.getuid())[0])
|
||||
|
||||
# Modif pour avoir le bon from (=> signature automatique)
|
||||
if user=="root" :
|
||||
for proc in os.popen("ps --no-headers -o user -t $(ps --no-headers -o tty %s)" % os.getpid() ).readlines() :
|
||||
userp=string.strip(proc)
|
||||
if userp=="root" : break
|
||||
else : user=userp
|
||||
|
||||
name = string.split(pwd.getpwnam(user)[4], ',')[0]
|
||||
domain = fromhost or getfqdn()
|
||||
host = string.split(domain,'.')[0]
|
||||
address = '%s@crans.org' % user
|
||||
s = StringIO()
|
||||
sys.stdout = s
|
||||
datestamp = time.strftime('%a, %d %b %Y %H:%M:%S +0000',
|
||||
time.gmtime(time.time()))
|
||||
try:
|
||||
vars = {'address' : address,
|
||||
'name' : quotename(name),
|
||||
'people' : string.join(people, COMMASPACE),
|
||||
'subject' : subject,
|
||||
'host' : host,
|
||||
'version' : __version__,
|
||||
'date' : datestamp,
|
||||
}
|
||||
print '''\
|
||||
From: %(name)s <%(address)s>
|
||||
To: %(people)s''' % vars
|
||||
if replyto:
|
||||
print 'Reply-To: %s' % replyto
|
||||
print "X-Bloublou: %s" % charset
|
||||
if charset:
|
||||
print 'MIME-Version: 1.0\nContent-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit' % charset
|
||||
print '''\
|
||||
Subject: CVS commit sur %(host)s : %(subject)s
|
||||
X-CVSinfo: CRANS
|
||||
Date: %(date)s
|
||||
X-Mailer: Python syncmail %(version)s <http://sf.net/projects/cvs-syncmail>
|
||||
''' % vars
|
||||
s.write(sys.stdin.read())
|
||||
# append the diffs if available
|
||||
print
|
||||
for entry in entries:
|
||||
print calculate_diff(entry, contextlines)
|
||||
finally:
|
||||
sys.stdout = sys.__stdout__
|
||||
resp = conn.sendmail(address, people, s.getvalue())
|
||||
conn.close()
|
||||
os._exit(0)
|
||||
|
||||
|
||||
|
||||
class CVSEntry:
|
||||
def __init__(self, name, revision, timestamp, conflict, options, tagdate):
|
||||
self.name = name
|
||||
self.revision = revision
|
||||
self.timestamp = timestamp
|
||||
self.conflict = conflict
|
||||
self.options = options
|
||||
self.tagdate = tagdate
|
||||
|
||||
def get_entry(prefix, mapping, line, filename):
|
||||
line = string.strip(line)
|
||||
parts = string.split(line, "/")
|
||||
_, name, revision, timestamp, options, tagdate = parts
|
||||
key = namekey(prefix, name)
|
||||
try:
|
||||
entry = mapping[key]
|
||||
except KeyError:
|
||||
if revision == "0":
|
||||
revision = None
|
||||
if string.find(timestamp, "+") != -1:
|
||||
timestamp, conflict = tuple(string.split(timestamp, "+"))
|
||||
else:
|
||||
conflict = None
|
||||
entry = CVSEntry(key, revision, timestamp, conflict,
|
||||
options, tagdate)
|
||||
mapping[key] = entry
|
||||
return entry
|
||||
|
||||
def namekey(prefix, name):
|
||||
if prefix:
|
||||
return os.path.join(prefix, name)
|
||||
else:
|
||||
return name
|
||||
|
||||
def load_change_info(prefix=None):
|
||||
if prefix is not None:
|
||||
entries_fn = os.path.join(prefix, "CVS", "Entries")
|
||||
else:
|
||||
entries_fn = os.path.join("CVS", "Entries")
|
||||
entries_log_fn = entries_fn + ".Log"
|
||||
mapping = {}
|
||||
f = open(entries_fn)
|
||||
while 1:
|
||||
line = f.readline()
|
||||
if not line:
|
||||
break
|
||||
## if string.strip(line) == "D":
|
||||
## continue
|
||||
# we could recurse down subdirs, except the Entries.Log files
|
||||
# we need haven't been written to the subdirs yet, so it
|
||||
# doesn't do us any good
|
||||
## if line[0] == "D":
|
||||
## name = string.split(line, "/")[1]
|
||||
## dirname = namekey(prefix, name)
|
||||
## if os.path.isdir(dirname):
|
||||
## m = load_change_info(dirname)
|
||||
## mapping.update(m)
|
||||
if line[0] == "/":
|
||||
# normal file
|
||||
get_entry(prefix, mapping, line, entries_fn)
|
||||
# else: bogus Entries line
|
||||
f.close()
|
||||
if os.path.isfile(entries_log_fn):
|
||||
f = open(entries_log_fn)
|
||||
while 1:
|
||||
line = f.readline()
|
||||
if not line:
|
||||
break
|
||||
if line[1:2] != ' ':
|
||||
# really old version of CVS
|
||||
break
|
||||
entry = get_entry(prefix, mapping, line[2:], entries_log_fn)
|
||||
parts = string.split(line, "/")[1:]
|
||||
if line[0] == "A":
|
||||
# adding a file
|
||||
entry.new_revision = parts[1]
|
||||
elif line[0] == "R":
|
||||
# removing a file
|
||||
entry.new_revision = None
|
||||
f.close()
|
||||
for entry in mapping.values():
|
||||
if not hasattr(entry, "new_revision"):
|
||||
#print 'confused about file', entry.name, '-- ignoring'
|
||||
del mapping[entry.name]
|
||||
return mapping
|
||||
|
||||
def load_branch_name():
|
||||
tag_fn = os.path.join("CVS", "Tag")
|
||||
if os.path.isfile(tag_fn):
|
||||
f = open(tag_fn)
|
||||
line = string.strip(f.readline())
|
||||
f.close()
|
||||
if line[:1] == "T":
|
||||
return line[1:]
|
||||
return None
|
||||
|
||||
# scan args for options
|
||||
def main():
|
||||
# XXX Should really move all the options to an object, just to
|
||||
# avoid threading so many positional args through everything.
|
||||
if '- Imported sources NONE NONE' in sys.argv[1:] :
|
||||
# Cas d'un cvs import
|
||||
print "Syncmail : import ignorés"
|
||||
sys.exit(0)
|
||||
if '- New directory NONE NONE' in sys.argv[1:] :
|
||||
# Cas de l'ajout d'un répertoir
|
||||
print "Syncmail : ajout de répertoires ignorés"
|
||||
sys.exit(0)
|
||||
try:
|
||||
opts, args = getopt.getopt(
|
||||
sys.argv[1:], 'hC:cuS:R:qf:m:',
|
||||
['fromhost=', 'context=', 'cvsroot=', 'mailhost=',
|
||||
'subject-prefix=', 'reply-to=',
|
||||
'help', 'quiet', 'charset='])
|
||||
except getopt.error, msg:
|
||||
usage(1, msg)
|
||||
|
||||
# parse the options
|
||||
contextlines = 2
|
||||
verbose = 1
|
||||
subject_prefix = ""
|
||||
replyto = None
|
||||
charset = 'iso-8859-15'
|
||||
fromhost = None
|
||||
for opt, arg in opts:
|
||||
if opt in ('-h', '--help'):
|
||||
usage(0)
|
||||
elif opt == '--cvsroot':
|
||||
os.environ['CVSROOT'] = arg
|
||||
elif opt in ('-C', '--context'):
|
||||
contextlines = int(arg)
|
||||
elif opt == '-c':
|
||||
if contextlines <= 0:
|
||||
contextlines = 2
|
||||
elif opt == '-u':
|
||||
contextlines = 0
|
||||
elif opt in ('-S', '--subject-prefix'):
|
||||
subject_prefix = arg
|
||||
elif opt in ('-R', '--reply-to'):
|
||||
replyto = arg
|
||||
elif opt == '--charset':
|
||||
charset = arg
|
||||
elif opt in ('-q', '--quiet'):
|
||||
verbose = 0
|
||||
elif opt in ('-f', '--fromhost'):
|
||||
fromhost = arg
|
||||
elif opt in ('-m', '--mailhost'):
|
||||
global MAILHOST
|
||||
MAILHOST = arg
|
||||
|
||||
# What follows is the specification containing the files that were
|
||||
# modified. The argument actually must be split, with the first component
|
||||
# containing the directory the checkin is being made in, relative to
|
||||
# $CVSROOT, followed by the list of files that are changing.
|
||||
if not args:
|
||||
usage(1, 'No CVS module specified')
|
||||
subject = subject_prefix + args[0]
|
||||
specs = string.split(args[0])
|
||||
del args[0]
|
||||
|
||||
# The remaining args should be the email addresses
|
||||
if not args:
|
||||
usage(1, 'No recipients specified')
|
||||
|
||||
# Now do the mail command
|
||||
people = args
|
||||
|
||||
if specs[-3:] == ['-', 'Imported', 'sources']:
|
||||
print 'Not sending email for imported sources.'
|
||||
return
|
||||
|
||||
branch = load_branch_name()
|
||||
changes = load_change_info()
|
||||
|
||||
if verbose:
|
||||
print 'Mailing %s...' % string.join(people, COMMASPACE)
|
||||
print 'Generating notification message...'
|
||||
blast_mail(subject, people, changes.values(),
|
||||
contextlines, fromhost, replyto, charset)
|
||||
if verbose:
|
||||
print 'Generating notification message... done.'
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
sys.exit(0)
|
231
archive/wwho.py
Executable file
231
archive/wwho.py
Executable file
|
@ -0,0 +1,231 @@
|
|||
#! /usr/bin/env python
|
||||
import os,string, getopt,time,sys,struct
|
||||
""" usage : wwho [date] [-b secs (backwards)] [-p precision (sec/m/h/d)] [-l (last)]
|
||||
[-a (all last msgs)] [-f wtmp_file] [-d (debug)]
|
||||
DATE (2000 May 22 06:12:08)
|
||||
|
||||
wfile : idem, except : [-a (access)] FILE
|
||||
|
||||
ça marche. mais la recherche ds le wtmp pour construire _sessions_ est
|
||||
pas du tout optimale -> lent pour un gros wtmp.
|
||||
Améliorations à prévoir..
|
||||
"""
|
||||
optlist, args = getopt.getopt(sys.argv[1:], "adlb:p:f:")
|
||||
|
||||
date=""
|
||||
emul_last=0
|
||||
all_last=0
|
||||
debug=0
|
||||
datesec=0
|
||||
precision=2
|
||||
utmpF="/var/log/wtmp"
|
||||
if len(args)>0 :
|
||||
date=args[0]
|
||||
print "cmd_line_date : %s" %date
|
||||
for i in optlist :
|
||||
if i[0] =='-l' : emul_last=1
|
||||
if i[0] =='-a' : all_last=1
|
||||
if i[0] =='-d' : debug=1
|
||||
if i[0] =='-b' : datesec=time.time()-float(i[1])
|
||||
if i[0] =='-p' : precision=float(i[1])
|
||||
if i[0] =='-f' : utmpF=i[1]
|
||||
if debug : print "Option found : "+repr(i)
|
||||
|
||||
if debug : print " argv[0] : %s" % sys.argv[0]
|
||||
|
||||
if not datesec :
|
||||
if date :
|
||||
if string.lower(os.path.basename(sys.argv[0]))=="wfile.py" :
|
||||
datesec=os.path.getmtime(date) #modif time
|
||||
if all_last : #access time
|
||||
datesec=os.stat(date)[7]
|
||||
# datesec=os.path.getatime(date) #BUG ! donne mtime !
|
||||
all_last=0
|
||||
print " Chosen file Time : %s" \
|
||||
%time.ctime(datesec)
|
||||
else :
|
||||
t=time.strptime(date,"%Y %b %d %H:%M:%S")
|
||||
#we still have to guess the DaylightSsavingTime flag -> -1
|
||||
t2=[ t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],-1]
|
||||
datesec = time.mktime(t2)
|
||||
else : datesec =time.time()
|
||||
|
||||
def unpackstr(s, i=0):
|
||||
for c in s:
|
||||
if c == '\000': break
|
||||
i = i + 1
|
||||
return s[:i]
|
||||
|
||||
def msectime(secs,usecs) :
|
||||
t=time.localtime(secs)
|
||||
s=time.strftime("%d %b %Y %T",t)
|
||||
s=s+ ( ".%06d"%usecs )[0:4]
|
||||
#s=s+ time.strftime(" %z %Z",time.localtime(secs))
|
||||
return s
|
||||
|
||||
|
||||
if debug : print " Date : %s // datesec : "% date + repr(datesec)
|
||||
print "Finding who were here at %s, with precision %fs."\
|
||||
% (msectime(datesec,0),precision)
|
||||
|
||||
# the C struct declaration (on AIX 4.2.1)
|
||||
# char ut_user[8];
|
||||
# char ut_id[14];
|
||||
# char ut_line[12];
|
||||
# short ut_type;
|
||||
# pid_t ut_pid; (int)
|
||||
# short ut_exit.e_termination;
|
||||
# short ut_exit.e_exit;
|
||||
# time_t ut_time; (long)
|
||||
# char ut_host[16];
|
||||
# the format string to represent that structure
|
||||
|
||||
""" cf utmp.h , ou man utmp :
|
||||
#define UT_LINESIZE 32
|
||||
#define UT_NAMESIZE 32
|
||||
#define UT_HOSTSIZE 256
|
||||
|
||||
/* The structure describing the status of a terminated process. This
|
||||
type is used in `struct utmp' below. */
|
||||
struct exit_status
|
||||
{
|
||||
short int e_termination; /* Process termination status. */
|
||||
short int e_exit; /* Process exit status. */
|
||||
};
|
||||
|
||||
/* The structure describing an entry in the user accounting database. */
|
||||
struct utmp
|
||||
{
|
||||
short int ut_type; /* Type of login. */
|
||||
pid_t ut_pid; /* Process ID of login process. */
|
||||
char ut_line[UT_LINESIZE=32]; /* Devicename. */
|
||||
char ut_id[4]; /* Inittab ID. */
|
||||
char ut_user[UT_NAMESIZE=32]; /* Username. */
|
||||
char ut_host[UT_HOSTSIZE=256]; /* Hostname for remote login. */
|
||||
struct exit_status ut_exit; /* Exit status of a process marked
|
||||
as DEAD_PROCESS. */
|
||||
long int ut_session; /* Session ID, used for windowing. */
|
||||
struct timeval ut_tv; /* Time entry was made. */
|
||||
int32_t ut_addr_v6[4]; /* Internet address of remote host. */
|
||||
char __unused[20]; /* Reserved for future use. */
|
||||
};
|
||||
"""
|
||||
fmt="hi32s4s32s256shhlii4i20s"
|
||||
#fmt="2s4s32s4s32s256s4s8s8s16s20s"
|
||||
|
||||
""" constants (for ut_type):
|
||||
"""
|
||||
UT_EMPTY = 0
|
||||
UT_RUN_LVL = 1
|
||||
UT_BOOT_TIME = 2
|
||||
UT_NEW_TIME = 3
|
||||
UT_OLD_TIME = 4
|
||||
UT_INIT_PROCESS = 5
|
||||
UT_LOGIN_PROCESS = 6
|
||||
UT_USER_PROCESS = 7
|
||||
UT_DEAD_PROCESS = 8
|
||||
UT_ACCOUNTING = 9
|
||||
record_size = struct.calcsize(fmt)
|
||||
# read who is logged on to a UNIX system
|
||||
file = open(utmpF, 'rb')
|
||||
|
||||
sessions={}
|
||||
suspects=[]
|
||||
|
||||
def evdisp(event,zt,rev) :
|
||||
( ut_t,ut_ut,zt_t,zt_ut,u,l,h,p,id,typ) =event
|
||||
if not zt :
|
||||
if zt_t: zt=msectime(zt_t,zt_ut)
|
||||
else : zt=" -stillNow-"
|
||||
if rev :
|
||||
t=zt;
|
||||
zt=msectime(ut_t,ut_ut)
|
||||
else :
|
||||
t=msectime(ut_t,ut_ut)
|
||||
return '%-8s %-8s %d/%-2d/%-6d %-4s [%-24s]=>[%-24s] (%s)' % \
|
||||
(u, l, typ,1,p, id, t, zt, h)
|
||||
|
||||
def rewind(sessions,n,criter,event) :
|
||||
i=n
|
||||
( ut_time,ut_utime,zt_time,zt_utime,user,line,host,pid,sessid,type) =event
|
||||
i0=1
|
||||
while i>i0 :
|
||||
i=i-1
|
||||
closethis=0
|
||||
if criter=='all' :
|
||||
closethis=1
|
||||
if criter =='line':
|
||||
closethis=(sessions[i][5] == line)
|
||||
if closethis : i0=i
|
||||
|
||||
if closethis :
|
||||
( ut_t,ut_ut,zt_t,zt_ut,u,l,h,p,id,typ)=ev=sessions[i]
|
||||
if zt_t !=0 :
|
||||
if criter=='all' : continue
|
||||
if all_last :
|
||||
s="-ERR: "
|
||||
s=s+evdisp(ev,"",1)
|
||||
else :
|
||||
ev=sessions[i]=( ut_t,ut_ut,ut_time,ut_utime,u,l,h,p,id,typ)
|
||||
if all_last :
|
||||
s="-CLOS "
|
||||
s=s+evdisp(ev,"",1)
|
||||
if all_last :
|
||||
print s
|
||||
|
||||
block = file.read(record_size)
|
||||
n=1
|
||||
while block:
|
||||
( type,pid,line,id,user,host,exit_1,exit_2,ut_session,ut_time,ut_utime,\
|
||||
ip1,ip2,ip3,ip4,unused) = \
|
||||
struct.unpack(fmt, block)
|
||||
user = unpackstr(user) # remove the null characters
|
||||
line = unpackstr(line)
|
||||
host = unpackstr(host)
|
||||
id = unpackstr(id)
|
||||
|
||||
event = ( ut_time,ut_utime,0,0,user,line,host,pid,id,type)
|
||||
|
||||
if type and all_last :
|
||||
s='USER: '
|
||||
s=s+evdisp(event," -n/a-",0)
|
||||
print s
|
||||
if user in ['LOGIN','reboot','shutdown'] :
|
||||
"Crash & such : everybody logs off.."
|
||||
rewind(sessions,n,'all',event)
|
||||
|
||||
if type == 7 and user :
|
||||
sessions[n]=event
|
||||
n=n+1
|
||||
|
||||
if type == 8 :
|
||||
rewind(sessions,n,'line',event)
|
||||
|
||||
block=file.read(record_size)
|
||||
file.close()
|
||||
|
||||
print "Number of entries : %d" %n
|
||||
|
||||
evs=sessions.values()
|
||||
evs.sort(lambda x, y: cmp(y[0]+y[1]*1e-7,x[0]+x[1]*1e-7) )
|
||||
i=0
|
||||
for ev in evs:
|
||||
i=i+1
|
||||
(ut_t,ut_ut,zt_t,zt_ut,u,l,h,p,id,typ)=ev
|
||||
if emul_last : print evdisp(ev,"",0)
|
||||
if datesec <360000 :
|
||||
# secret feature : giving a near-epoch date does that :
|
||||
if precision >0 and zt_t-ut_t < precision : continue
|
||||
if precision <0 and zt_t-ut_t > -precision : continue
|
||||
else :
|
||||
if datesec + precision < ut_t : continue
|
||||
if zt_t !=0 and zt_t + precision <datesec : continue
|
||||
if emul_last : print "----SUSPECT"
|
||||
suspects.append(ev)
|
||||
|
||||
print "\nAnd Now the \"suspects\" :"
|
||||
|
||||
suspects.sort(lambda x, y: cmp(x[2]-x[0], y[2]-y[0]))
|
||||
for ev in suspects :
|
||||
(ut_t,ut_ut,zt_t,zt_ut,u,l,h,p,id,typ)=ev
|
||||
print evdisp(ev,"",0)
|
Loading…
Add table
Add a link
Reference in a new issue