You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

172 regels
4.5 KiB

  1. #!/usr/bin/env perl
  2. #
  3. # ptree for linux/darwin/solaris. I got sick of ps and pstree on linux.
  4. # ptree works on solaris fine, but doesn't exist for darwin/linux/etc...
  5. #
  6. # TODO: Allow passing a regexp instead of a pid and passing multiple pids.
  7. #
  8. local $ENV{"PATH"} = '/bin:/usr/bin:/sbin:/usr/sbin';
  9. local $debug = 0;
  10. (exists($ENV{"DEBUG"})) ? $debug = 1 : undef;
  11. ($debug) ? local $| = 1 : undef; # disable buffering for STDERR and STDOUT
  12. sub debug_print {
  13. ($debug) && warn pop;
  14. };
  15. local @cmd = ('/bin/ps');
  16. local $init = 0;
  17. local $start = 1;
  18. if ($^O eq "linux"){
  19. push(@cmd, 'ajxSw');
  20. $start = 0;
  21. }elsif ($^O =~ m/darwin|freebsd/){
  22. push(@cmd, 'Ajwww');
  23. }elsif ($^O eq "solaris"){
  24. @cmd = ('/usr/ucb/ps');
  25. if ((-x "/bin/zonename") && !(qx(zonename) eq "global\n")){
  26. $init = qx(pgrep zsched);
  27. chomp($init);
  28. $start = $init;
  29. };
  30. push(@cmd, 'laxwww');
  31. }else{
  32. die "$^O isn't a known os to this script\n";
  33. };
  34. local @ps = qx(@cmd);
  35. ($?) ? die $cmd[0]." posix return code $?\n" : undef;
  36. local %proc;
  37. local @trail;
  38. (defined($ARGV[0])) ? $start = $ARGV[0] : undef;
  39. debug_print("Dump of raw line array data:\n");
  40. foreach my $x (@ps){
  41. my $cmd_index = 9;
  42. my $ppid = -1;
  43. my $pid = -1;
  44. next if ($x =~ m/.*PID.*/);
  45. my @line = split(m/\s+/,$x);
  46. splice(@line, 0, 1) unless ($line[0] =~ m/\d+/);
  47. splice(@line, 0, 1) if ("$line[0]" eq "");
  48. if ($^O eq "linux"){
  49. ($ppid,$pid) = @line;
  50. $cmd_index = 9;
  51. }elsif ($^O =~ m/darwin|freebsd/){
  52. ($pid,$ppid) = @line;
  53. $cmd_index = 8;
  54. }elsif ($^O eq "solaris"){
  55. (undef, undef, $pid,$ppid) = @line;
  56. for($x=$cmd_index; $x < 14; $x++){
  57. $cmd_index = ($line[$x] =~ m/\d+\:\d+/) ? ($x + 1) : $cmd_index;
  58. };
  59. };
  60. my $command = join(' ', @line[$cmd_index..$#line++]);
  61. (!defined $proc{$pid}) ? $proc{$pid}->{"children"} = [ ] : undef;
  62. (!defined $proc{$ppid}) ? $proc{$ppid}->{"children"} = [ ] : undef;
  63. $proc{$pid}->{"pid"} = $pid;
  64. $proc{$pid}->{"command"} = $command;
  65. $proc{$pid}->{"ppid"} = $ppid;
  66. push(@{$proc{$ppid}->{"children"}},$pid);
  67. debug_print(join(',', @line[0..($#line-1)])."\n");
  68. };
  69. if ($debug){
  70. debug_print("Done reading ps output\nDump of Hash\n");
  71. foreach my $key (sort({$a <=> $b} (keys %proc))){
  72. $ppid = $proc{$key}->{"ppid"};
  73. $command = $proc{$key}->{"command"};
  74. $children = join(',', @{$proc{$key}->{"children"}});
  75. debug_print("PID<$key> PPID<$ppid> Children<$children> Command<$command>\n");
  76. };
  77. };
  78. sub intrail{
  79. my $crumb = pop;
  80. my $ret = 0;
  81. map {$ret++ if ($crumb == $_)} @trail;
  82. return $ret;
  83. };
  84. sub addchildren{
  85. my $start_node = pop;
  86. foreach my $child (@{$proc{$start_node}->{"children"}}){
  87. next if (!defined($child) || ($start_node == $child));
  88. debug_print("Start ($start_node) Add child $child.\n");
  89. push(@trail, $child);
  90. addchildren($child);
  91. };
  92. };
  93. sub addparents{
  94. my $start_node = pop;
  95. my $parent = $proc{$start_node}->{"ppid"};
  96. return unless (defined($start_node));
  97. return if (($parent == $start_node) || !(defined($parent))); # At the top of the tree, or in a zone
  98. debug_print("Start ($start_node) Add parent $parent.\n");
  99. push(@trail, $parent);
  100. addparents($parent) if ($parent != $init);
  101. };
  102. sub printnode{
  103. my $start_node = pop;
  104. my $indent = pop;
  105. if (intrail($start_node)){
  106. my $pid = $proc{$start_node}->{"pid"};
  107. my $ppid = $proc{$start_node}->{"ppid"};
  108. my $cmdline = $proc{$start_node}->{"command"};
  109. my $indentation = ' 'x($indent);
  110. if ($pid == $init){
  111. my $s = $^O." kernel";
  112. if ($cmdline ne ''){
  113. $s = $s." <$cmdline>";
  114. };
  115. $cmdline = $s;
  116. };
  117. printf("%s%d %s\n", $indentation, $pid, $cmdline);
  118. foreach my $child (@{$proc{$start_node}->{"children"}}){
  119. next if ($pid == $child);
  120. printnode($indent+1,$child);
  121. };
  122. };
  123. };
  124. my $valid = 0;
  125. foreach my $j (keys %proc){ ($j == $start) ? $valid++ : undef; };
  126. debug_print("Starting from <$start>, validity is<$valid>\n");
  127. if ($valid){
  128. if (!$start){
  129. @trail = keys %proc;
  130. push(@trail, $start); push(@trail, 1);
  131. debug_print("Done with adding $start to trail.\n");
  132. }else{
  133. push(@trail, $start);
  134. debug_print("Adding children from $start.\n");
  135. addchildren($start);
  136. debug_print("Adding parents from $start.\n");
  137. addparents($start);
  138. };
  139. @trail = sort(@trail);
  140. debug_print("Trail is: ".join(',', @trail)."\nStarting at pid $start\ninit pid $init\n");
  141. print "PID COMMAND\n";
  142. my $startindent = 0;
  143. (intrail($startindent)) ? $startindent = -1 : undef;
  144. printnode($startindent,$init);
  145. }else{
  146. die "pid $start doesn't exist.\n";
  147. };
  148. exit 0;