#!/usr/bin/perl use User::Utmp qw(utmpname getut putut); use constant LOGIN_PROCESS => 6; use constant USER_PROCESS => 7; use constant DEAD_PROCESS => 8; my $debug = 0; my ($start,$end,$utmp) = @ARGV; utmpname($utmp || "/etc/wtmp"); @utmp = getut(); foreach $utmp (@utmp) { my ($user,$line,$type,$time) = @$utmp{'ut_user','ut_line','ut_type','ut_time'}; next if $type < USER_PROCESS; # we just care about logins and logouts next unless $line; # entries for user logins never have a blank line next unless $user =~ /\w/; # skip pseudo-logins with no username my ($sec,$min,$hour,$mday,$mon,$year) = localtime($time); my $date = sprintf("%04d-%02d-%02d", $year+1900, $mon+1, $mday); my $hour = sprintf("%02d:%02d:%02d", $hour, $min, $sec); next if $start && $date lt $start; next if $end && $date gt $end; printf "user: %8s line: %12s type: %s time: %s %s\n", $user, $line, $type, $date, $hour if $debug; if ($type == USER_PROCESS) { $logins++; # total logins for all users $logins{$user}++; # total number of times this user logged on ++$multlogins && ++$multlogins{$user} if $loggedin{$user}; $loggedin{$user}++; # number of "current" logins at this point $user{$line} = $user; # which user is on this line? } elsif ($type == DEAD_PROCESS) { next unless $user{$line} eq $user; $loggedin{$user}--; delete $user{$line}; } } print "\nSummary of logins"; print " after $start" if $start; print " before $end" if $end; print "\n"; @users = keys %logins; $users = @users; $avglogins = sprintf "%.2d", ($logins/$users); foreach $user (@users) { printf "%8s logged in %6d times (%d multiple)\n", $user, $logins{$user}, $multlogins{$user}; } print <