#!/usr/bin/perl

# Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
# based on vps by Krischan Jodies
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

# Wrapper for ps. Adds security context number and name
# to the PID column.
#
# (c) 2002 krischan.jodies@sernet.de
# version 1.0

# 1.1        Added error messages

if ($ARGV[0] eq "--help") {
   exec("ps @ARGV");
   exit;
} 


$lockdir = "/var/run/vservers";

$pid_length = 5;
get_server_names();
$context=get_context("self");

if ($context == -1) {
   print "Can not find my security context. Is this a ctx kernel?\n";
   exit;
}
if ($context != 1) {
   exec("@PKGLIBDIR@/chcontext-compat --silent --ctx 1 $0 @ARGV");
   print "Can not execute chcontext\n";
   exit; # not reached
} 


if (! open PS, "ps @ARGV|") {
   print "Can not execute ps\n";
   exit;
}
while (<PS>) {
  chomp;
  push @ps,$_;
}

$header = shift @ps;
$header =~ /(.*)  PID(.+)/;
$left = $1;
$right = $2;
$left_length  = length($left);
print "${left}  PID CONTEXT       ${right}\n";
foreach $line (@ps) {
   $pid =  substr $line,$left_length,$pid_length;
   print   substr $line,0,$left_length;
   print "$pid";
   $context = get_context($pid);
   $context_name = getcontextname($context);
   printf " %-3s %-10s",$context,$context_name;
   print   substr $line,$left_length + $pid_length;
   print "\n";
   
}

exit;

sub get_context
{
   my $pid = $_[0];
   $pid =~ s/ //g;
   open STATUS, "/proc/$pid/status";
   while (<STATUS>)
   {
      chomp;
      if (/s_context: (\d+)/) {
         close STATUS;   
         return $1;
      }
   }
   close STATUS;
   return -1;
}

sub getcontextname {
   if (exists $name{$_[0]}) {
      return $name{$_[0]};
   }
   if    ($_[0] == 1) {
      return "ALL_PROCS";
   }
   elsif ($_[0] == 0) {
      return "MAIN";
   }
   return "UNKNOWN";
}


sub get_server_names 
{
    opendir LOCKDIR, "$lockdir";
    while ($file=readdir(LOCKDIR)) {
       if (-f "$lockdir/$file") {
          open FILE, "$lockdir/$file";
          $file =~ s/(.+)\.ctx/$1/;
          while (<FILE>) {
             if (/S_CONTEXT=(\d+)/) {
                $name{$1} = $file;
             }
          }
       }
    }
}
