#!/usr/bin/env perl # efing -- extended fast finger (local) # written by Vincent Lefevre. # Send comments / bug reports / etc. to # Latest version on # https://www.vinc17.net/unix/ # http://www.vinc17.org/unix/ # Note: efing was written for Solaris and NIS+. It may not work # on other systems. Use it at your own risk! # Usage: efing [-bcfhimpv] [-k[+][]] [ ...] # -b: suppress printing of the user's home directory and shell. # -c: suppress printing of the last .rc access time. # -h: suppress printing of the .project file. # -i: suppress printing of the user id and group id. # -m: match arguments only on user name (not passwd line). # -p: suppress printing of the .plan file. # -v: output version information and exit. # -k[+][]: color for keywords. =head1 NAME efing - extended fast finger (local) =head1 SYNOPSIS efing [-bcfhimpv] [-k[+][I]] [I ...] =head1 DESCRIPTION A bit like B, B displays information about local users: =over 4 =item * the user name and the user's full name =item * the user id, the group id and the group name =item * the user's home directory and login shell =item * time the user logged in if currently logged in, or the time the user last logged in, and the terminal or host from which the user logged in =item * last F<.EshellErc> access time =item * the first line of the F<$HOME/.project> file, if it exists =item * the contents of the F<$HOME/.plan> file, if it exists =back Arguments contain user names (logins) or strings to match (in fact, Perl regular expressions). If no argument is given, B displays information about you. =head1 OPTIONS =over 4 =item -b suppress printing of the user's home directory and shell. =item -c suppress printing of the last F<.EshellErc> access time. =item -h suppress printing of the .project file. =item -i suppress printing of the user id and group id. =item -k[+][I] color for keywords (integer). If a + is present, keywords are written in bold. =item -m match arguments only on user name (not passwd line). =item -p suppress printing of the .plan file. =item -v output version information and exit. =back =head1 ENVIRONMENT =over 10 =item HOME User's home directory. =item LL_HOSTSIZE (optional) Size of struct lastlog field ll_host, in octets. =item LL_LINESIZE (optional) Size of struct lastlog field ll_line, in octets. =item LL_TIMESIZE (optional) Size of struct lastlog field ll_time, in bits. =item MAIL User's mail file. =item USER User name. =back =head1 FILES =over 20 =item F<$HOME/.plan> user's plan =item F<$HOME/.project> user's projects =item F time of last login =item F accounting (OSF1) =item F accounting (Solaris) =item F accounting (Linux) =back =head1 SEE ALSO finger(1) =head1 NOTE B was written in 1996 for Solaris and NIS+. It has then been ported to some versions of Linux and to OSF1. It has not been tested everywhere, so it may not work on your system. Use it at your own risk! =head1 AUTHOR Vincent Lefevre . Mail comments and bug reports about B to . =head1 AVAILABILITY The latest version is available at or . =cut my ($procvers) = '$Id: efing 119750 2019-07-26 08:17:51Z vinc17/zira $' =~ /^.Id: (\S+ \d+ \d{4}-\d\d-\d\d \d\d:\d\d:\d\d)Z / or die; ######################################################################## require 5.001; use integer; use strict; my ($color,%opt,$bold,$c0,$c1); my ($llsize,$llfmt,$noll); while ($ARGV[0] =~ /^-./) { $_ = shift; /^-k(\+?)(\d*)$/ and $bold = $1, $color = $2, next; @_ = split //; foreach (@_[1..$#_]) { index('bchimpv', $_) >= 0 or die < 1) and $c0 = `tput setaf $color`; $bold ne '' and $c0 .= `tput bold`; $c0 ne '' and $c1 = `tput sgr0`; } my ($flag,$i); foreach (@ARGV ? @ARGV : $ENV{USER}) { my $u = $_; @_ = getpwnam($u) and &finger(@_[0..3,6..8]), next; $opt{'m'} and next; open PASSWD,"niscat passwd.org_dir|" or die; while () { /$u/i and chomp, &finger(split /:/) } close PASSWD; } sub finger { $flag = ''; $i++ and print "\n"; my ($name,$room,$ophone,$hphone) = split /,/, $_[4]; print $c0, 'Login name: ', $c1, substr($_[0].' 'x28,0,28), $c0, 'In real life: ', $c1, "$name\n"; print $c0, 'User id: ', $c1, substr($_[2].' 'x31,0,31), $c0, 'Group id: ', $c1, "$_[3] (", scalar getgrgid($_[3]), ")\n" unless ($opt{'i'}); print $c0, 'Directory: ', $c1, substr($_[5].' 'x29,0,29), $_[6] eq '' ? "\n" : ($c0, 'Shell: ', $c1, "$_[6]\n") unless ($opt{'b'}); &roomphones($room eq '' ? $ophone eq '' ? (undef, undef, undef) : ('Office Phone: ', 26, $ophone) : ('Office: ', 32, $ophone ne '' ? "$room, $ophone" : $room), $hphone); if (open UTMPX, '/var/adm/utmpx') # Solaris { my ($buff, @a); while (read(UTMPX, $buff, 372) == 372 and @a = (unpack "A32A4A32ls4l7sA256", $buff)[0,2,4,8,16]) { $a[0] eq $_[0] && $a[2] == 7 or next; &plog('On since ', @a[3,1,4]); &pidl($a[1]); } close UTMPX; } elsif (open UTMP, '/var/adm/utmp') # OSF1 { my ($buff, @a); while (read(UTMP, $buff, 156) == 156 and @a = (unpack "A32A14A32sA8lA64", $buff)[0,2,3,5,6]) { $a[0] eq $_[0] && $a[2] == 7 or next; &plog('On since ', @a[3,1,4]); &pidl($a[1]); } close UTMP; } elsif (open UTMP, '/var/run/utmp') # Linux { my ($buff, @a); while (read(UTMP, $buff, 384) == 384 and @a = (unpack "sslA32A4A32A256ssll", $buff)[0,3,5,6,10]) { $a[0] == 7 && $a[2] eq $_[0] or next; &plog('On since ', @a[4,1,3]); &pidl($a[1]); } close UTMP; } if (!$flag && &llparam and open LL, '/var/adm/lastlog') { if (seek LL, $llsize*$_[2], 0) { my ($buff, @a); read(LL, $buff, $llsize) == $llsize && (@a = unpack $llfmt, $buff)[0] and &plog('Last login ', @a); } $flag or print $c0, 'Never logged in.', $c1, "\n"; close LL; } unless ($opt{'c'}) { my $xrc = $_[6] =~ /\/(\w+sh)$/ ? $1.'rc' : 'profile'; my $t = (stat "$_[5]/.$xrc")[8]; if ($xrc eq 'tcshrc') { my $c = (stat "$_[5]/.cshrc")[8]; $c > $t and ($xrc,$t) = ('cshrc',$c); } print $c0, "Last $xrc access ", $c1, localtime($t)."\n" if ($t); } my ($maildir) = $ENV{MAIL} =~ m:(.*)/:; if (open MAILDIRS, "$ENV{HOME}/.maildirs") { while () { /(\d+)\s+(\d+)\s+(.+)/ && $1 <= $_[3] && $_[3] <= $2 and $maildir = $3 } close MAILDIRS; } my @m = stat "$maildir/$_[0]"; print $m[7] ? ($m[8] < $m[9] ? $c0.'New mail received '.$c1. localtime($m[9]).";\n ".$c0.'unread since '.$c1 : $c0.'Mail last read '.$c1). localtime($m[8])."\n" : $c0.'No unread mail'.$c1."\n"; if (!$opt{'h'} and open PROJECT, "$_[5]/.project") { print $c0.'Project: '.$c1.; close PROJECT; } unless ($opt{'p'}) { if (open PLAN, "$_[5]/.plan") { print $c0, 'Plan:', $c1, "\n", ; close PLAN; } else { print $c0, 'No Plan.', $c1, "\n" } } } sub plog { print $c0, $_[0], $c1, substr(localtime($_[1]), 4, 15), $c0, ' on ', $c1, $_[2]; print $c0, ' from ', $c1, $1 if ($_[3] =~ /([\040-\377]+)/); print "\n"; $flag = 1; } sub pidl ($) { my $file = "/dev/$_[0]"; $_[0] eq 'console' && -e "/dev/kbd" and $file = "/dev/kbd"; my $t = (stat $file)[8] or return; my $i = time - $t; $i >= 3600 and &idle($i/60, 'hour', 'minute'), return; $i > 10 and &idle($i, 'minute', 'second'); } sub idle ($$$) { my ($a, $b) = ($_[0]/60, $_[0]%60); $a and print "$a $_[1]".($a > 1 ? 's ' : ' '); $b and print "$b $_[2]".($b > 1 ? 's ' : ' ') unless ($a > 10); print $c0, 'Idle Time', $c1, "\n"; } sub llparam { $noll and return 0; $llsize and return 1; $noll = 1; my $ts = $ENV{'LL_TIMESIZE'}; my $ls = $ENV{'LL_LINESIZE'}; my $hs = $ENV{'LL_HOSTSIZE'}; unless ($ts && $ls && $hs) { my $cache = "$ENV{HOME}/.efing/llcache.$ENV{HOST}"; open CACHE, "<$cache" or &llcache($cache) && open CACHE, "<$cache" or return 0; ($ts) = =~ /^time:\s+(\d+)\s*$/; ($ls) = =~ /^line:\s+(\d+)\s*$/; ($hs) = =~ /^host:\s+(\d+)\s*$/; close CACHE; } $ts =~ /^(\d+)$/ or return 0; if ($1 == 32) { $llfmt = 'L'; $llsize = 4; } elsif ($1 == 64) { $llfmt = 'Q'; $llsize = 8; } else { return 0; } $ls =~ /^(\d+)$/ or return 0; $llfmt .= "A$1"; $llsize += $1; $hs =~ /^(\d+)$/ or return 0; $llfmt .= "A$1"; $llsize += $1; $noll = 0; return 1; } sub llcache ($) { my ($cache) = @_; my $prg = <<'EOF'; #include #include #include #include int main(void) { struct lastlog ll = {0}; printf ("time: %d\n", sizeof(ll.ll_time) * CHAR_BIT); printf ("line: %d\n", sizeof(ll.ll_line) * (CHAR_BIT/8)); printf ("host: %d\n", sizeof(ll.ll_host) * (CHAR_BIT/8)); return 0; } EOF my $tmp = "/tmp/efingtmp.$<.$$"; $cache =~ m:^(.+/): and mkdir $1, 0777; my $ret; if (open TMP, ">$tmp.c") { print TMP $prg; close TMP and ((system 'gcc', "$tmp.c", '-o', $tmp and system 'cc', "$tmp.c", '-o', $tmp) or system "$tmp > $cache" or $ret = 1); } unlink $tmp, "$tmp.c"; return $ret; } sub roomphones { if (defined $_[0]) { print $c0, $_[0], $c1; print $_[3] ne '' ? substr($_[2].' 'x$_[1],0,$_[1]) : "$_[2]\n"; } $_[3] ne '' and print $c0, 'Home Phone: ', $c1, $_[3], "\n"; }