#!/usr/bin/perl
#########################################################################
#
# LOMAC - Low Water-Mark Mandatory Access Control for Linux 
# Copyright (C) 1999 TIS Labs at Network Associates, Inc.
# Copyright (C) 2000 - 2001 NAI Labs
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
# License as published by the Free Software Foundation.  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.
#
#
# lps - a script which calls ps, and prints the level of a given
#       process after its pid in ps's output.
#
# Tim Fraser <tfraser@tislabs.com>        : initial implementation
# John Thiltges <jthiltg1@bigred.unl.edu> : adapted to use lomac.pm
#
#########################################################################

use lib "/opt/lomac/bin";
use lomac;

#
# Step 0 - Make sure LOMAC is operational.
#

if (linfo("-c")) {
    die "LOMAC not operating.\n";
}

#
# Step 1 - Execute ps with our command line arguments and put its
#          output into <PSOUT>.
#

# Use join() to put all the args stored in this script's @ARGV array
# into the scalar $psargs, so we can pass them on to /bin/ps.
$psargs = join( ' ', @ARGV );
# Execute /bin/ps with $psargs and put its output into <PSOUT>.
open( PSOUT, "/bin/ps $psargs|" ) || die "Can't execute /bin/ps";

#
# Step 2 - Look for the PID label in the first line of /bin/ps output.
#          If not found, complain.  If found, note its index, so we'll
#          know where to add our level output later.
#

#Transfer the output from <PSOUT> to the @psout array for manipulation.
@psout = <PSOUT>;

# Put the index of the PID header label into $pidindex.  
# Do not be confused by the PPID header.

#if ($psout[0] =~ /^(.*)\s+PID\b/) {
#    $pidindex = length($1);
#}
$pidindex = index( $psout[ 0 ], "  PID" );

#bomb out if no PID header found
if( $pidindex == -1 ) {
	die "ERROR - you must specify ps flags that print a PID header.\n";
}

# calculate the index of the level column - it should start 3 after
# $pidindex, since "  PID" is 5 chars long.
$pidfieldwidth = 5;   # constant width of PID field
$levelindex = $pidindex + $pidfieldwidth;


#
# Step 3 - Output a new line of headers with our "LVL" header inserted.
#
#

# print substring of header line leading up to our "LVL" header.
print substr( $psout[ 0 ], 0, $levelindex );

# print our "LVL" header.
print " LVL";

# print out the remainder of the original ps header.
print substr( $psout[ 0 ], $levelindex );


#
# Step 4 - Output the remaining lines of ps output, inserting
#          level numbers as we go.
#

for( $psline = 1; $psline <= $#psout; $psline++ ) {

	# Often, the output of /bin/ps will contain an entry for
	# /bin/ps itself.  However, by the time we get to asking
	# about levels in this loop, the /bin/ps process has
	# usually exited.  Thus, we'll get a level of -1 for
	# the /bin/ps line of stored /bin/ps output.  So, we
	# find the level of a given line of /bin/ps output first,
	# and don't bother printing the line if the level comes
	# back as -1.

	# Make $pid hold the pid value for this line of ps output
	$pid = substr( $psout[ $psline ], $pidindex, $pidfieldwidth );

	# Make $level hold the level number for $pid.
	$level = level("-p",$pid);

	if( $level != -1 ) {

		# print substring of line leading up to our level column.
		print substr( $psout[ $psline ], 0, $levelindex );

		printf( "%4u", $level );

		# print out the remainder of the original ps header.
		print substr( $psout[ $psline ], $levelindex );
	}

}
