#!/usr/bin/perl

################################################################################
#                                                                              #
#  ext|scripts (C) 2000-2004 Pavel Novikov (pavel@ext.by)                      #
#                                                                              #
################################################################################

################################################################################
#
#  This one makes "ps(1)" and then maps pids to jails.
#
#  Usage: ./jps.pl [<ps options>] [lj|long_jails] [ll|long_lines] [i|install]
#
#  TODO:
#
#   - sort by jail
#


#:-)
use strict;

#:)
eval
{
require Term::ReadKey;
};

#no buffer
$|=1;

#constants
my $PS_BIN="/bin/ps";
my $PS_OPTIONS;
my $DIR_PROC="/proc";
my $FILE_STATUS="status";

#data
my @lines;
my %pids;
my $pid_position=-1;
my $max_jail=length('JAIL');

#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 $O_CUT_LINES=1;
my $O_CUT_JAILS=1;
my $JAIL_DEAD="<died>";

#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 "i")||($option eq "install"))
	{
		system("cd /usr/ports/devel/p5-Term-ReadKey && make install");
		exit(0);
	}
	else
	{
		$PS_OPTIONS=$PS_OPTIONS." ".$option;
	}
}
if(!$PS_OPTIONS){$PS_OPTIONS=" -axuf";}

#open a pipe
if(open(P,$PS_BIN.$PS_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($c==0)
		{
			my $i=0;
			foreach my $field (@line)
			{
				if($field eq 'PID')
				{
					$pid_position=$i;
					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\n";
	}
	else
	{
		$f="%".$max_jail."s %s\n";
	}

	#output
	my $i=0;
	foreach my $line (@lines)
	{
		my @data=split(/\s\s*/,&strip($line));
		printf($f,($i==0)?'JAIL':$pids{$data[$pid_position]},$line);
		++$i;
	}

}


syntax highlighted by Code2HTML, v. 0.9.1