Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 213 lines (193 sloc) 4.36 KB
#!/usr/bin/perl
#
# A Perl script for evaluating and summarising which executables in
# the given directories depend on the old 32-bit stat() family APIs.
#
# Usage: summarise_stat.pl directory [...]
#
# Copyright (c) 2007,2013 Silicon Graphics, Inc. All Rights Reserved.
# By Greg Banks <gnb@melbourne.sgi.com>
#
# Updated 20130511 to correctly diagnose 64b executables
#
# 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
#
use strict;
use warnings;
my @pathnames; # file and directories to read, from the commandline
my @summ;
my $nbroken = 0;
my $total = 0;
my $debug = 0;
my @broken_by_status;
# Parse arguments
@pathnames = @ARGV;
my @status_strings =
(
"cannot be read (permission denied)",
"are scripts (shell, perl, whatever)",
"are 64-bit executables",
"don't use any stat() family calls at all",
"use 32-bit stat() family interfaces only",
"use 64-bit stat64() family interfaces only",
"use both 32-bit and 64-bit stat() family interfaces",
);
my @status_broken = (
0,
0,
0,
0,
1,
0,
1
);
sub MAX_STATUS { return 6 };
sub status
{
my ($r) = @_;
return 0 if ($r->{no_perm});
return 1 if ($r->{not_exe});
return 2 if ($r->{elf64b});
return 3 + ($r->{used64} ? 2 : 0) + ($r->{used32} ? 1 : 0);
}
map { $summ[$_] = 0 } (0..MAX_STATUS);
map { $broken_by_status[$_] = [] } (0..MAX_STATUS);
# Function to scan a file
sub scan_file
{
my ($path) = @_;
my $fh;
my %res =
(
elf64b => 0,
used32 => 0,
used64 => 0,
not_exe => 0,
no_perm => 0,
);
open $fh,'-|', "file -L \"$path\" 2>&1"
or return;
$_ = readline $fh;
chomp;
if (m/ELF 64-bit/)
{
$res{elf64b} = 1;
}
close $fh;
$fh = undef;
open $fh,'-|', "nm -uD \"$path\" 2>&1"
or return;
while (<$fh>)
{
chomp;
if (m/File format not recogni[sz]ed/)
{
$res{not_exe} = 1;
}
elsif (m/Permission denied/)
{
$res{no_perm} = 1;
}
elsif (m/^\s+U __(|l|f)xstat$/)
{
$res{used32}++;
}
elsif (m/^\s+U __(|l|f)xstat64$/)
{
$res{used64}++;
}
}
close $fh;
print "$res{used32} $res{used64} $res{not_exe} $res{no_perm} $res{elf64b} $path\n" if $debug;
my $s = status(\%res);
if ($status_broken[$s])
{
push(@{$broken_by_status[$s]}, $path);
$nbroken++;
}
$summ[$s]++;
$total++;
}
# Function to scan a directory
sub scan_directory
{
my ($path) = @_;
my $dh;
return unless opendir($dh,$path);
while (my $d = readdir $dh)
{
next if ($d =~ m/^\./);
print "$path/$d\n" if $debug;
scan_path("$path/$d");
}
closedir $dh;
}
# Function to scan something that might be a file or a directory
sub scan_path
{
my ($path) = @_;
print "scan_path($path)\n" if $debug;
if ( -l $path )
{
# Ignore symlinks to files
return if ( -f $path );
# Follow symlinks to directories, but avoid deep recursion
# on silly compatibility symlinks like /usr/bin/X11 -> .
return if ( readlink($path) eq "." );
}
if ( -d $path )
{
scan_directory($path);
}
elsif ( -e $path )
{
scan_file($path);
}
}
# Scan files and directories specified in the commandline
foreach my $path (@pathnames)
{
scan_path($path);
}
if ( !$total )
{
printf "No files found.\n";
exit;
}
# generate a summary
print "Summary by status\n";
print "-----------------\n";
foreach my $s (0..MAX_STATUS)
{
next if $summ[$s] == 0;
printf "%7d %4.1f%% %s%s\n",
$summ[$s], (100.0 * $summ[$s] / $total), $status_strings[$s],
($status_broken[$s] ? " [BROKEN]" : "");
}
printf "%7d %4.1f%% BROKEN\n",
$nbroken, (100.0 * $nbroken / $total);
# list all broken files
if ($nbroken)
{
print "List of broken files\n";
print "--------------------\n";
foreach my $s (0..MAX_STATUS)
{
next if !$status_broken[$s];
next if !scalar(@{$broken_by_status[$s]});
printf "These %s\n", $status_strings[$s];
map { printf " %s\n", $_; } @{$broken_by_status[$s]};
}
}