解决方案变成了这个,它不依赖于 C 编译器。
sub which {
# Input:
# @programs = programs to find the path to
# Returns:
# @full_path = full paths to @programs. Nothing if not found
my @which;
for my $prg (@_) {
push @which, map { $_."/".$prg } grep { -x $_."/".$prg } split(":",$ENV{'PATH'});
}
return @which;
}
{
my ($regexp,%fakename);
sub parent_shell {
# Input:
# $pid = pid to see if (grand)*parent is a shell
# Returns:
# $shellpath = path to shell - undef if no shell found
my $pid = shift;
if(not $regexp) {
# All shells known to mankind
#
# ash bash csh dash fdsh fish fizsh ksh ksh93 mksh pdksh
# posh rbash rush rzsh sash sh static-sh tcsh yash zsh
my @shells = qw(ash bash csh dash fdsh fish fizsh ksh
ksh93 mksh pdksh posh rbash rush rzsh
sash sh static-sh tcsh yash zsh -sh -csh);
# Can be formatted as:
# [sh] -sh sh busybox sh
# /bin/sh /sbin/sh /opt/csw/sh
# NOT: foo.sh sshd crash flush pdflush scosh fsflush ssh
my $shell = "(?:".join("|",@shells).")";
$regexp = '^((\[)('. $shell. ')(\])|(|\S+/|busybox )('. $shell. '))($| )';
%fakename = (
# csh and tcsh disguise themselves as -sh/-csh
"-sh" => ["csh", "tcsh"],
"-csh" => ["tcsh", "csh"],
);
}
my ($children_of_ref, $parent_of_ref, $name_of_ref) = pid_table();
my $shellpath;
my $testpid = $pid;
while($testpid) {
if($name_of_ref->{$testpid} =~ /$regexp/o) {
$shellpath = (which($3.$6,@{$fakename{$3.$6}}))[0];
$shellpath and last;
}
$testpid = $parent_of_ref->{$testpid};
}
return $shellpath;
}
}
{
my %pid_parentpid_cmd;
sub pid_table {
# return two tables:
# pid -> children of pid
# pid -> pid of parent
# pid -> commandname
if(not %pid_parentpid_cmd) {
# Filter for SysV-style `ps`
my $sysv = q( ps -ef | perl -ane '1..1 and /^(.*)CO?MM?A?N?D/ and $s=length $1;).
q(s/^.{$s}//; print "@F[1,2] $_"' );
# BSD-style `ps`
my $bsd = q(ps -o pid,ppid,command -ax);
# TODO test these on Cygwin, darwin
%pid_parentpid_cmd =
(
'aix' => $sysv,
'cygwin' => $sysv,
'dec_osf' => $sysv,
'darwin' => $bsd,
'dragonfly' => $bsd,
'freebsd' => $bsd,
'gnu' => $sysv,
'hpux' => $sysv,
'linux' => $sysv,
'mirbsd' => $bsd,
'netbsd' => $bsd,
'nto' => $sysv,
'openbsd' => $bsd,
'solaris' => $sysv,
'svr5' => $sysv,
);
}
$pid_parentpid_cmd{$^O} or die("pid_parentpid_cmd for $^O missing");
my (@pidtable,%parent_of,%children_of,%name_of);
# Table with pid -> children of pid
@pidtable = `$pid_parentpid_cmd{$^O}`;
my $p=$$;
for (@pidtable) {
# must match: 24436 21224 busybox ash
/(\S+)\s+(\S+)\s+(\S+.*)/ or die("pidtable format: $_");
$parent_of{$1} = $2;
push @{$children_of{$2}}, $1;
$name_of{$1} = $3;
}
return(\%children_of, \%parent_of, \%name_of);
}
}