#!/usr/bin/perl
################################################################################
# #
# ext|scripts (C) 2000-2004 Pavel Novikov (pavel@ext.by) #
# #
################################################################################
################################################################################
#
# This one makes "top(1)" and then maps pids to jails.
#
# Usage: ./jtop.pl [<top options>] [lj|long_jails] [ll|long_lines] [b|batch] [<delay in seconds>] [i|install]
#
# TODO:
#
# - sort by jail
# - interactive mode
#
#:-)
use strict;
#:)
eval
{
require Term::ReadKey;
};
#no buffer
$|=1;
#constants
my $TOP_BIN="/usr/bin/top";
my $TOP_OPTIONS;
my $DIR_PROC="/proc";
my $FILE_STATUS="status";
#get sizes
my ($MAX_WIDTH,$MAX_HEIGHT)=(80,25);
eval
{
($MAX_WIDTH,$MAX_HEIGHT)=Term::ReadKey::GetTerminalSize();
};
#other defaults
my $MAX_LINE_SIZE=$MAX_WIDTH;
my $MAX_LINE_COUNT=$MAX_HEIGHT;
my $O_CUT_LINES=1;
my $O_CUT_JAILS=1;
my $O_BATCH=0;
my $O_DELAY=2;
my $JAIL_DEAD="<died>";
#clear sign - tricky shit
my $CLEAR=`/usr/bin/clear`;
my $CTL=$CLEAR;
$CTL=~s;H.*$;H;gsmio;
#this will kill us
local($SIG{INT})=sub{$O_BATCH=1;};
#strip shit
sub strip
{
#come on
my $line=shift;
#leading spacing ones
$line=~s{^\s\s*(.*)$}{$1}gs;
#trailing spacing ones
$line=~s{^(.*)\s\s*$}{$1}gs;
#add eol
return($line);
}
#read options
while(my $option=shift)
{
if(($option eq 'lj')||($option eq 'long_jails'))
{
$O_CUT_JAILS=0;
}
elsif(($option eq 'll')||($option eq 'long_lines'))
{
$O_CUT_LINES=0;
}
elsif(($option eq 'b')||($option eq 'batch'))
{
$O_BATCH=1;
}
elsif($option =~ '^(\d\d*)$')
{
$O_DELAY=$1;
}
elsif(($option eq "i")||($option eq "install"))
{
system("cd /usr/ports/devel/p5-Term-ReadKey && make install");
exit(0);
}
else
{
$TOP_OPTIONS=$TOP_OPTIONS." ".$option;
}
}
if(!$TOP_OPTIONS){$TOP_OPTIONS=" -Stbnq";}
#use only as much as we need
$TOP_OPTIONS=$TOP_OPTIONS." -d1 ".($MAX_LINE_COUNT-5);
#cycling
for(;;)
{
#data
my @lines;
my %pids;
my $pid_line=-1;
my $pid_position=-1;
my $max_jail=length('JAIL');
#flush data
#open a pipe
if(open(P,$TOP_BIN.$TOP_OPTIONS." |"))
{
#fetch data
my $c=0;
while(<P>)
{
#fix & save
chomp($_);
my $line=$_;
push(@lines,$line);
#split data
my @line=split(/\s\s*/,&strip($line));
#header
if($pid_position==-1)
{
my $i=0;
foreach my $field (@line)
{
if($field eq 'PID')
{
$pid_position=$i;
$pid_line=$c;
last;
}
++$i;
}
}
#line
else
{
if($pid_position>=0)
{
my $pid=@line[$pid_position];
if(open(F,"<".$DIR_PROC."/".$pid."/".$FILE_STATUS))
{
while(<F>)
{
chomp($_);
my @data=split(/\s\s*/,$_);
my $jail=$data[$#data];
if($jail)
{
if($O_CUT_JAILS)
{
$jail=~s/^([^\.]*)\..*$/$1/gsmi;
}
$pids{$pid}=$jail;
if(length($jail) > $max_jail){$max_jail=length($jail);}
}
}
close(F);
}
else
{
$pids{$pid}=$JAIL_DEAD;
if(length($JAIL_DEAD) > $max_jail){$max_jail=length($JAIL_DEAD);}
}
}
}
#next
++$c;
}
#close the pipe
close(P);
#make a format
my $f;
if($O_CUT_LINES)
{
$f="%".$max_jail."s %-.".($MAX_LINE_SIZE-$max_jail-1)."s";
}
else
{
$f="%".$max_jail."s %s";
}
#clear
print "$CTL";
#output
my $i=0;
foreach my $line (@lines)
{
if(&strip($line))
{
if(($i>=$pid_line)&&(&strip($line)))
{
my @data=split(/\s\s*/,&strip($line));
if($i==$pid_line){print (" " x $MAX_WIDTH)."\n";}
my $o=sprintf($f,($i==$pid_line)?'JAIL':$pids{$data[$pid_position]},$line);
if(length($o)<$MAX_WIDTH)
{
$o=$o.(" " x ($MAX_WIDTH-length($o)));
}
print $o."\n";
}
else
{
my $o=sprintf($f,$line);
if(length($o)<$MAX_WIDTH)
{
$o=$o.(" " x ($MAX_WIDTH-length($o)));
}
print $o."\n";
}
}
++$i;
if($i>$MAX_LINE_COUNT){last;}
}
}
#check if batch
if($O_BATCH){last;}
#delay
sleep($O_DELAY);
}
syntax highlighted by Code2HTML, v. 0.9.1