#!/usr/bin/perl
#
# ptree - print the OpenBSD process list as a tree
# Copyright (C) 2002 - Anthony Tonns
# 
# 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
# of the License, 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.
# 
#
# initially written
# ATonns Sun Oct 24 21:27:56 EDT 1999
#
# updated to sort by starttime of process
# ATonns Mon Jun 24 17:54:12 EDT 2002
#
# fixed bug where children processes were dropped from the list if
# they started on the same jiffie as the parent and appeared earlier
# in the list
# ATonns Mon Jul 22 22:03:36 EDT 2002
#
# hacked to bits for OpenBSD (uses "ps ajxwww")
# ATonns Sun Sep  1 13:01:03 EDT 2002
#
#

use strict;

my %foundprocs;

# truncate width of cmdline
# (length 0 means unlimited)
my $termwidth = "132";

# get procs;
open(PS,"ps ajxwww |");
my @ps = <PS>;
close PS;

# get rid of header line
shift @ps;

# get data for printing ptree
my $basepid=1;
my $proc;
foreach $proc (@ps) {

#USER       PID  PPID  PGID   SESS JOBC  STAT TT       TIME COMMAND
#tony      7348  5721  7348 13f7d2d0    1 I+    p0    0:00.12 vi ptree
        my ($user,$pid,$ppid,$pgid,$sess,$jobc,$stat,$tt,$time,$cmdline) = split(/\s+/,$proc,10);
        chomp($cmdline);
#       print qq!user $user\n!;
#       print qq!pid $pid\n!;
#       print qq!ppid $ppid\n!;
#       print qq!pgid $pgid\n!;
#       print qq!sess $sess\n!;
#       print qq!jobc $jobc\n!;
#       print qq!stat $stat\n!;
#       print qq!tt $tt\n!;
#       print qq!time $time\n!;
#       print qq!cmdline $cmdline\n!;
#       print qq!---\n!;

	# create data structure and add pid
	if (defined $foundprocs{$pid}) {
#		print "!!! $pid !!!\n";
	} else {
		$foundprocs{$pid}->{"children"}=[ ];
	}
	$foundprocs{$pid}->{"pid"}=$pid;
	$foundprocs{$pid}->{"ppid"}=$ppid;
	$foundprocs{$pid}->{"cmdline"}=$cmdline;

#	print qq!pid: "$foundprocs{$pid}->{"pid"}" !;
#	print qq!ppid: "$foundprocs{$pid}->{"ppid"}" !;
#	print qq!cmdline: "$foundprocs{$pid}->{"cmdline"}" !;
#	print "\n";

	push(@{$foundprocs{$ppid}->{"children"}},$pid);
}

# recurse the tree
printnode(0,$foundprocs{1});

sub printnode
{
	my ($level,$node) = @_;
	print "  "x$level;
	print $node->{"pid"} . " ";
	print $node->{"cmdline"};
	print "\n";
	my $child;
	foreach $child (@{$node->{"children"}}) {
		printnode($level+1,$foundprocs{$child});
	}
}

