#!/usr/local/bin/perl

# cutwtmp - schneide dem Protokoll der letzten Logins mal die Haare
# $Id: cutwtmp,v 1.5 1995/04/07 07:52:16 czyborra Exp $

# cutwtmp kann sinnvollerweise nur von root benutzt werden, root läßt
# es immer gleich als periodischen Cronjob laufen, darum sind
# Kommandozeilenparameter unnötig, allein zu Testzwecken werden
# Environmentvariablen honoriert.

# Wie alte Vorgänge gelten als verjährt?

$keepdays = $ENV{'KEEPDAYS'} || 35;

# Wo befinden sich die wtmp-Dateien?

chdir ($_ = $ENV{'WTMPHOME'} || '/var/adm') || die "Can't enter $_: $!\n";

# SunOS 5 hat eine etwas andere struct utmp.

$ut_name = -d '/kernel' ? "a8" : "x8a8";

# Die wtmp-Datei hat auf allen Systemen den Zeiteintrag an der
# gleichen Stelle.

&cutwtmp ('wtmp', 36, 'x32L');

# SunOS5 hat zusätzlich noch eine großzügigere wtmpx, die unter
# anderem mehr Platz für den Hostnamen bereitstellt.  Sie muß auch
# gekürzt werden.

&cutwtmp ('wtmpx', 372, 'x80L') if -e 'wtmpx';

# Das Kürzen selbst funktioniert ganz simpel: da die Einträge in
# chronologischer Ordnung vorliegen und es die vorderen Einträge also
# gelöscht werden sollen, können wir einfach die zu bewahrenden
# Einträge von hinten nach vorne kopieren und das überstehende Ende
# abschneiden.

sub cutwtmp
{
    ($filename, $blocksize, $timestamp) = @_;

    open (STDIN, $filename)       || &cantopen('reading');
    open (STDOUT, "+< $filename") || &cantopen('writing');

    # Nachdem die Datei erfolgreich zum Lesen und Schreiben geöffnet
    # wurde, kann es zu keinen nennenswerten Fehlern mehr kommen.  Wir
    # brauchen ja keinen zusätzlichen Plattenplatz, und eine
    # Speicherknappheit wird hoffentlich von perl selbst erkannt.

    while (read (STDIN, $_, $blocksize) == $blocksize || 
	   read (STDIN, $_, $blocksize) == $blocksize )
    {
	$who= unpack ($ut_name, $_);
	$age= $^T - unpack ($timestamp, $_);
	$age/= 86400;

	# Uli wünscht manchmal Sachen.

	print unless $who =~ /^\./
	    || $who =~ /^ftp\b/ && $age > 1 
	    || $age > $keepdays;
    }

    # Nach dem ersten EOF wird noch einmal zu lesen versucht, da das
    # EOF ja von einem abgearbeiteten stdio-Buffer stammen kann und
    # möglicherweise nicht mehr das tatsächliche Dateiende
    # signalisiert.  Zwischen dem allerletzten read und dem truncate
    # existiert ein kleines ungeschütztes Zeitfenster.  Daten, die in
    # genau dem Moment von außen eintreffen, gehen verloren.  Das
    # Risiko ist minimal.

    truncate (STDOUT, tell STDOUT);

}

sub cantopen { die "Can't open $filename for @_: $!\n"; }
