#!/usr/bin/perl # change the line above to the location of your perl interpretter # Remember to run: # chmod 755 my_pstree.pl # before executing it # Usage: # .../my_pstree.pl [ user_name ] # If no user_name given, the user_name of the current user is assumed use strict; use warnings; my $name; if(@ARGV) { # user name given? $name = $ARGV[0]; } else { my $ruid = $<; # get real user id of the process $name = getpwuid($ruid); # get real user name } my $PSFH; # file handle for ps -ef command listing my @user_ps_lines = (); # collects process info lines from ps -el for the user my $n_user_lines = 0; # number of process lines for the used my %parents = (); # arrays of processes with the same parent's pid (ppid) my %kids = (); # hash of process pid's (process id's) # open pipe to 'ps -ef' UNIX command and collect output open($PSFH, "/bin/ps -ef |") || "die cannot run the ps -ef\n"; # run ps -ef while (my $line = <$PSFH>) { # analyze output from ps -ef, line by line $line =~ s/^\s+|\s+$//gmx; # remove trailing blanks from front and back if($line =~ /^$name/) { # if process is owned by the user my ($user_name, $pid, $ppid) = split(/\s+/, $line); # print STDOUT "$n_user_lines($user_name, $pid,$ppid): $line\n"; $line = substr($line, 0, 150) if length($line) > 150; # truncate long push(@user_ps_lines, $line); # save a line at n_user_lines element # append to the list of processes with a given ppid push(@{$parents{$ppid}}, { line => $n_user_lines, pid => $pid }); # create lookup of pid -> ppid $kids{$pid} = $ppid; $n_user_lines++; } } close($PSFH); # find the parent processes that are not owned by the user print STDOUT "Process tree for user $name:\n", " |___. USER PID PPID ...\n\n\n"; if($name eq 'root') { # for a root, all processes descend from process 0. print_tree(0, 0); } else { # processes of regular user descend from processes owned by root for my $ppid ( sort keys %parents ) { if(not exists($kids{$ppid})) { # root ownes them, not user print_tree(1, $ppid); } } } # print_tree($indent, $ppid): # $indent -- amount of indent at the beginning of line # $ppid -- parent process id # recursively traverses the tree of processes and prints them indented # depending on the number of ancestors. Note, that in UNIX a kid has # only one parent, but a parent can have several kids). sub print_tree { my ($indent, $ppid) = @_; $indent++; if(exists($parents{$ppid})) { my $list = $parents{$ppid}; my $n = 0; for my $kid ( @{$list} ) { my $line = $kid->{line}; my $pid = $kid->{pid}; my $space = ""; if($indent > 1) { $space = " " x ($indent-1) . "|___. "; } print STDOUT "$space $user_ps_lines[$line]\n"; print_tree($indent, $pid); $n++; } print STDOUT "\n"; } return; }