echeck-stat-brokeness (4788B)
1 #!/usr/bin/perl 2 # 3 # This script was taken from the source below and is licenses under different 4 # terms. It is renamed to fit the naming convention of all other tools. 5 # -- Christoph Lohmann <20h@r-36.net>, 2015-09-09 6 # 7 # A Perl script for evaluating and summarising which executables in 8 # the given directories depend on the old 32-bit stat() family APIs. 9 # 10 # Usage: summarise_stat.pl directory [...] 11 # 12 # Copyright (c) 2007,2013 Silicon Graphics, Inc. All Rights Reserved. 13 # By Greg Banks <gnb@melbourne.sgi.com> 14 # 15 # Updated 20130511 to correctly diagnose 64b executables 16 # 17 # This program is free software; you can redistribute it and/or modify 18 # it under the terms of the GNU General Public License as published by 19 # the Free Software Foundation; either version 2 of the License, or 20 # (at your option) any later version. 21 # 22 # This program is distributed in the hope that it will be useful, 23 # but WITHOUT ANY WARRANTY; without even the implied warranty of 24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 # GNU General Public License for more details. 26 # 27 # You should have received a copy of the GNU General Public License 28 # along with this program; if not, write to the Free Software 29 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 30 # 31 32 use strict; 33 use warnings; 34 35 my @pathnames; # file and directories to read, from the commandline 36 my @summ; 37 my $nbroken = 0; 38 my $total = 0; 39 my $debug = 0; 40 my @broken_by_status; 41 42 # Parse arguments 43 @pathnames = @ARGV; 44 if ( scalar @pathnames == 0 ) 45 { 46 my $baseargv0 = (split /\//, $0)[-1]; 47 die "usage: $baseargv0 path0 [path1 ...]\n" 48 } 49 50 my @status_strings = 51 ( 52 "cannot be read (permission denied)", 53 "are scripts (shell, perl, whatever)", 54 "are 64-bit executables", 55 "don't use any stat() family calls at all", 56 "use 32-bit stat() family interfaces only", 57 "use 64-bit stat64() family interfaces only", 58 "use both 32-bit and 64-bit stat() family interfaces", 59 ); 60 my @status_broken = ( 61 0, 62 0, 63 0, 64 0, 65 1, 66 0, 67 1 68 ); 69 70 sub MAX_STATUS { return 6 }; 71 sub status 72 { 73 my ($r) = @_; 74 return 0 if ($r->{no_perm}); 75 return 1 if ($r->{not_exe}); 76 return 2 if ($r->{elf64b}); 77 return 3 + ($r->{used64} ? 2 : 0) + ($r->{used32} ? 1 : 0); 78 } 79 80 map { $summ[$_] = 0 } (0..MAX_STATUS); 81 map { $broken_by_status[$_] = [] } (0..MAX_STATUS); 82 83 # Function to scan a file 84 sub scan_file 85 { 86 my ($path) = @_; 87 my $fh; 88 89 my %res = 90 ( 91 elf64b => 0, 92 used32 => 0, 93 used64 => 0, 94 not_exe => 0, 95 no_perm => 0, 96 ); 97 98 open $fh,'-|', "file -L \"$path\" 2>&1" 99 or return; 100 $_ = readline $fh; 101 chomp; 102 if (m/ELF 64-bit/) 103 { 104 $res{elf64b} = 1; 105 } 106 close $fh; 107 $fh = undef; 108 109 open $fh,'-|', "nm -uD \"$path\" 2>&1" 110 or return; 111 while (<$fh>) 112 { 113 chomp; 114 115 if (m/File format not recogni[sz]ed/) 116 { 117 $res{not_exe} = 1; 118 } 119 elsif (m/Permission denied/) 120 { 121 $res{no_perm} = 1; 122 } 123 elsif (m/^\s+U __(|l|f)xstat$/) 124 { 125 $res{used32}++; 126 } 127 elsif (m/^\s+U __(|l|f)xstat64$/) 128 { 129 $res{used64}++; 130 } 131 } 132 close $fh; 133 134 print "$res{used32} $res{used64} $res{not_exe} $res{no_perm} $res{elf64b} $path\n" if $debug; 135 136 my $s = status(\%res); 137 if ($status_broken[$s]) 138 { 139 push(@{$broken_by_status[$s]}, $path); 140 $nbroken++; 141 } 142 $summ[$s]++; 143 $total++; 144 } 145 146 # Function to scan a directory 147 sub scan_directory 148 { 149 my ($path) = @_; 150 my $dh; 151 return unless opendir($dh,$path); 152 while (my $d = readdir $dh) 153 { 154 next if ($d =~ m/^\./); 155 print "$path/$d\n" if $debug; 156 scan_path("$path/$d"); 157 } 158 closedir $dh; 159 } 160 161 # Function to scan something that might be a file or a directory 162 sub scan_path 163 { 164 my ($path) = @_; 165 print "scan_path($path)\n" if $debug; 166 if ( -l $path ) 167 { 168 # Ignore symlinks to files 169 return if ( -f $path ); 170 # Follow symlinks to directories, but avoid deep recursion 171 # on silly compatibility symlinks like /usr/bin/X11 -> . 172 return if ( readlink($path) eq "." ); 173 } 174 if ( -d $path ) 175 { 176 scan_directory($path); 177 } 178 elsif ( -e $path ) 179 { 180 scan_file($path); 181 } 182 } 183 184 # Scan files and directories specified in the commandline 185 foreach my $path (@pathnames) 186 { 187 scan_path($path); 188 } 189 190 if ( !$total ) 191 { 192 printf "No files found.\n"; 193 exit; 194 } 195 196 # generate a summary 197 print "Summary by status\n"; 198 print "-----------------\n"; 199 foreach my $s (0..MAX_STATUS) 200 { 201 next if $summ[$s] == 0; 202 printf "%7d %4.1f%% %s%s\n", 203 $summ[$s], (100.0 * $summ[$s] / $total), $status_strings[$s], 204 ($status_broken[$s] ? " [BROKEN]" : ""); 205 } 206 printf "%7d %4.1f%% BROKEN\n", 207 $nbroken, (100.0 * $nbroken / $total); 208 209 # list all broken files 210 if ($nbroken) 211 { 212 print "List of broken files\n"; 213 print "--------------------\n"; 214 foreach my $s (0..MAX_STATUS) 215 { 216 next if !$status_broken[$s]; 217 next if !scalar(@{$broken_by_status[$s]}); 218 printf "These %s\n", $status_strings[$s]; 219 map { printf " %s\n", $_; } @{$broken_by_status[$s]}; 220 } 221 }