#!/usr/bin/perl -w
# $Id: jailadmin 138 2004-11-19 21:04:24Z kirk $
# This software was written by Kirk Strauser <kirk@strauser.com>, and may be
# freely distributed under the terms of the BSD License.
#
# Please submit any changes to this program back to the author so that they
# can be easily distributed to other others who might be interested.
use strict;
use Jail;
############################################################
#### Variable declaration ####
############################################################
my $server;
my $oper;
my @serverlist = ();
my @jails = Jail::getJailList();
############################################################
#### Configuration options ####
############################################################
my %opt =
(
'psstyle' => 'new'
);
############################################################
#### Argument processing ####
############################################################
if (@ARGV < 1)
{
print <<__EOHELP__;
Usage: $0 operation serverspec
Where serverspec is the name of one a jail environments to act upon, a
space-seperated list of names, or "all"; and operation is one of:
list List the names of all configured jails
start Launch the server
stop Stop all processes in the server (really nasty right now)
status Display a list of active processes in the server
__EOHELP__
exit -1;
}
$oper = shift @ARGV;
@serverlist = Jail::canonicalizeList(@ARGV);
############################################################
#### Main ####
############################################################
if ($oper eq 'list')
{
print "Configured jails:\n";
foreach $server (@jails)
{
print " $server\n";
}
exit;
}
########################################
## Get a jail's status
########################################
if ($oper eq 'status')
{
foreach $server (sort @serverlist)
{
print "Server: $server\n\n";
unless (Jail::isRunning($server))
{
print "That server is not running.\n\n\n";
next;
}
# The following code isn't pretty, but it would take a lot of
# space to do this stuff elegantly. Basically, it creates a
# table of process data with each column justified
# appropriately, either with a fixed format, or with one
# relative to the widest entry in that column. I'm sure that
# there are CPAN modules that do the same thing, but an
# important design requirement for this project is that it not
# rely on any outside dependencies unless absolutely
# necessary.
my %procinfo = Jail::getProcInfo($server);
my @pids = keys %procinfo;
# The key in this hash is the title of the resulting table.
# The "keyf" field is the printf formatting string that
# affects the contents of the cell. The "titlef" field is the
# printf formatting string that affects the title cell. The
# "order" field controls the sorting order of the fields. The
# "key" field is the key in the %procinfo hash that contains
# the cell's value.
my %coldef =
(
'USER' => { 'keyf' => '%%-%ds',
'order' => 1 },
'PID' => { 'keyf' => '%%%ds',
'order' => 2 },
'%CPU' => { 'keyf' => '%%5.1f',
'order' => 3 },
'%MEM' => { 'keyf' => '%%5.1f',
'order' => 4 },
'RSS' => { 'keyf' => '%%%ds',
'order' => 5 },
'TT' => { 'keyf' => '%%-%ds',
'order' => 6 },
'STAT' => { 'keyf' => '%%-%ds',
'order' => 7 },
'TIME' => { 'keyf' => '%%%ds',
'order' => 8 },
'COMMAND' => { 'keyf' => '%%s',
'order' => 9 }
);
# Get the list of column titles, sorted by the numeric value
# in "order".
my @columntitles = sort { $coldef{$a}{'order'} <=> $coldef{$b}{'order'} } keys %coldef;
# Calculate the column key from the column title if needed
foreach my $name (@columntitles)
{
next if defined $coldef{$name}{'key'};
my $key = lc $name;
$key =~ s/^\W+//;
$coldef{$name}{'key'} = $key;
}
# Find the longest value in each column
foreach my $name (@columntitles)
{
my $longest = (sort { $b <=> $a }
length $name,
map { length $procinfo{$_}{$coldef{$name}{'key'}} } @pids)[0];
# Use that information to build the "keyf" field.
$coldef{$name}{'keyf'} = sprintf $coldef{$name}{'keyf'}, $longest;
# If the "titlef" field is defined, then use the length
# information to build it.
if (defined $coldef{$name}{'titlef'})
{
$coldef{$name}{'titlef'} = sprintf $coldef{$name}{'titlef'}, $longest;
}
# If it's not, then base it off the "keyf" field.
else
{
$coldef{$name}{'titlef'} = $coldef{$name}{'keyf'};
# Replace printf strings like "%5.1f" with "%5s".
$coldef{$name}{'titlef'} =~ s/(\d+).*$/$1s/;
}
}
# Print the table header
my $formatstring = join ' ', map { $coldef{$_}{'titlef'} } @columntitles;
printf "$formatstring\n", @columntitles;
# Print the table body
$formatstring = join ' ', map { $coldef{$_}{'keyf'} } @columntitles;
foreach my $pid (sort @pids)
{
printf "$formatstring\n", map { $procinfo{$pid}{$coldef{$_}{'key'}} } @ columntitles;
}
print "\n\n";
}
}
########################################
## Start a jail
########################################
elsif ($oper eq 'start')
{
foreach $server (sort @serverlist)
{
print "Starting server $server...\n";
# Check for processes already running in that jailspace
if (Jail::isRunning($server))
{
print STDERR "ERROR: That jail already seems to be running\n";
next;
}
Jail::mount($server);
Jail::launch($server);
}
}
########################################
## Stop a jail
########################################
elsif ($oper eq 'stop')
{
my @queue = @serverlist;
my %state;
my $initialstate = 1;
foreach my $i (1 .. Jail::maxparallel())
{
my $server = shift @queue;
last unless $server;
$state{$server} = $initialstate;
}
while (keys %state)
{
my $sleep = 0;
foreach my $server (sort (keys %state))
{
print "--- Server: $server state $state{$server}\n";
my $sleeprequest;
($state{$server}, $sleeprequest) = Jail::stop($server, $state{$server});
$sleep = $sleeprequest if $sleeprequest > $sleep;
if (not $state{$server})
{
# Remove this server from the action list
delete $state{$server};
# Add a new server if any are left.
my $server = shift @queue;
$state{$server} = $initialstate if $server;
}
}
# Now, sleep for a few seconds if any of the servers need it.
sleep $sleep if $sleep;
}
}
else
{
print STDERR <<__EOOPTIONS__;
ERROR: "$oper" is not a valid operation. The requested operation must be
one of 'start', 'stop', or 'status'
__EOOPTIONS__
exit -1;
}
syntax highlighted by Code2HTML, v. 0.9.1