#!/usr/bin/perl # # Author: Holger Parplies # Version: 0.0001 # Disclaimer: quick-hack without any promises, warranties or anything :). # Copyright: well, GPL, I guess # 07.10.2008 use strict; use Getopt::Std; use lib '/usr/share/backuppc/lib'; # change this if not Debian/Ubuntu use BackupPC::Lib; use BackupPC::FileZIO; # use Encode 'from_to'; use File::Find; require 5.006; my %opts = ( d => '/var/lib/backuppc/pc', # directory to start from v => 0, # verbose mode, not recommended p => 0, # progress mode, noisy u => '', # uid whitelist X => '', # bogus permission whitelist D => 0, # debug output m => 100 * 1024 * 1024, # max acceptable attrib file size M => 0, # max acceptable file sizeDiv4GB val ); if (not getopts ('d:vDpu:X:m:M:', \%opts) or @ARGV != 0) { die "Usage: $0 [-d startdir] [-v] [-D] [-p] [-u uidlist] [-X permlist] [-m max-attrib-file-size] [-M max-file-div-4GB-size]\n"; } $| = 0; my $bpc = new BackupPC::Lib or die "Can't BackupPC::Lib::new\n"; my %Conf = $bpc -> Conf (); my $compress = $Conf {CompressLevel}; # vars my $fd; my $attrib_buf; my $chunk; my $rc; my $len; my $maxlen = 0; my $magic; my @list; my $name; my $id; my %uidmap = (); my %gidmap = (); my %permmap = (); my %typemap = (); while (($name, undef, $id) = getpwent ()) { $uidmap {$id} = $name; } foreach (split /,/, $opts {u}) { $uidmap {$_} = 'local'; } while (($name, undef, $id) = getgrent ()) { $gidmap {$id} = $name; } foreach (0777, 0775, 0755, 0770, 0750, 0751, 0700, 0744, 0700, 0711, 0710, 0555, 0550, 0500, 0666, 0664, 0644, 0660, 0640, 0600, 0444, 0440, 0400, 01777, 01775, 01755, 01750, 01700, 02777, 02775, 02770, 02755, 02750, 02700, 03775, 04755, 04750, 04751, 04711, 04555, 04551, 04511) { $permmap {$_} = 1; } foreach (split /,/, $opts {X}) { eval "\$permmap {$_} = 1;"; } foreach (0, 1, 2, 3, 4, 5, 6, 8, 9, 10) { $typemap {$_} = 1; } print "Users: ", (join ',', sort {$a <=> $b} keys %uidmap), "\n" if $opts {D}; print "Groups: ", (join ',', sort {$a <=> $b} keys %gidmap), "\n" if $opts {D}; find (\&check, $opts {d}); print "Max attrib file size: $maxlen bytes\n"; sub check { if ($_ eq 'attrib' and -f $_) { $fd = BackupPC::FileZIO -> open ($_, 0, $compress) or die "Can't FileZIO::open $File::Find::name!\n"; # read whole attrib file into memory unless unreasonably long (100MB) $rc = 1; $len = 0; $attrib_buf = ''; while ($rc > 0) { $rc = $fd -> read (\$chunk, 65536); if ($rc > 0) { $attrib_buf .= $chunk; $len += $rc; } die "$File::Find::name too long \@$len\n" if $len > $opts {m}; } $maxlen = $len if $len > $maxlen; print "$File::Find::name = $len bytes\n" if $opts {v}; print "$File::Find::name\r" if $opts {p}; # decode attrib structure if ($len < 4) { die "$File::Find::name too short: only $len bytes\n"; } ($magic, $attrib_buf) = unpack ('N a*', $attrib_buf); if ($magic != 0x17555555) { die "$File::Find::name has wrong magic number: 0x" . sprintf ('%08x', $magic) . "\n"; } @list = unpack ('(w/a* w6 N1)*', $attrib_buf); warn "\@list has " . scalar @list . " elements, strange\n" if @list % 8 != 0; for (my $i = 0; $i < @list; $i += 8) { printf "[%d] %o %i %i %i %i 0x%x %s\n", @list [$i + 1, $i + 2, $i + 3, $i + 4, $i + 5, $i + 6, $i + 7, $i] if $list [$i + 5] > $opts {M} or not exists $uidmap {$list [$i + 3]} or not exists $gidmap {$list [$i + 4]} or not exists $permmap {$list [$i + 2]} or not exists $typemap {$list [$i + 1]}; } $fd -> close (); } }