Created
August 12, 2011 20:49
-
-
Save mpg/1142965 to your computer and use it in GitHub Desktop.
list files in /etc not belonging to an installed Debian package
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
# etcorphan - list files in /etc not belonging to an installed Debian package | |
# | |
# Usage: etcorphan [ exclude_file... ] | |
# | |
# A lot of files don't formally belong to any package (eg because they are | |
# generated by an installation script) but are legitimate. You may want to | |
# ignore those files. The exclude files indicated on the command line use | |
# basically the same format as gitignore: one pattern per linei (supported | |
# metacharacters: * ? [], patterns starting with a / are anchored at the | |
# root), lines starting with a # are comments. Negated patterns are not | |
# supported. See example after the END mark, covering files from a basic | |
# Debian system. | |
# | |
# Manuel Pégourié-Gonnard, 2011. WTFPL v2. | |
use warnings; | |
use strict; | |
use IPC::Open3; | |
use File::Find; | |
exit(main()); | |
sub main { | |
get_excludes(); | |
get_files(); | |
check_files(); | |
exit; | |
} | |
# populate the @excludes list from files on the command line | |
my @excludes; | |
sub get_excludes { | |
while (my $line = <>) { | |
# ignore comments and empty lines | |
next if $line =~ /^\s*$/; | |
next if $line =~ /^#/; | |
chomp $line; | |
# store the correspondig regex | |
push @excludes, glob2pat($line); | |
} | |
} | |
# turn a shell-style pattern (as used in ignore files) into a regex | |
# arg: a shell pattern | |
# ret: a regex | |
sub glob2pat { | |
my ($globstr) = @_; | |
# remember if glob is anchored before changing it | |
my $anchored = ($globstr =~ s!^/!!); | |
# turn glob into a regex | |
# adapted from http://docstore.mik.ua/orelly/perl/cookbook/ch06_10.htm | |
my %patmap = ( '*' => '[^/]*', '?' => '.', '[' => '[', ']' => ']', ); | |
$globstr =~ s[ (.) ][ $patmap{$1} || "\Q$1" ]gex; | |
# fix anchoring in the resulting regex | |
my $regex = $anchored | |
? qr!^$globstr(?:$|/)! | |
: qr!(?:^|/)$globstr(?:$|/)!; | |
return $regex; | |
} | |
# tell if a file is accepted according to the @excludes list | |
# arg: relative pathname, ie without the initial '/etc/' part | |
# ret: boolean | |
sub accepted { | |
my $name = shift; | |
for my $pat (@excludes) { | |
return 0 if $name =~ /$pat/; | |
} | |
return 1; | |
} | |
# populate the @files list with acceptable files from /etc | |
# items are stored as pathnames relative to /etc | |
my @files; | |
sub get_files { | |
my $wanted = sub { | |
my $abspath = $File::Find::name; | |
(my $relpath = $abspath) =~ s!^/etc/!!; | |
if (accepted($relpath)) { | |
push @files, $relpath unless -d $abspath | |
} else { | |
$File::Find::prune = 1; | |
} | |
}; | |
find($wanted, '/etc/'); | |
} | |
# check files in the @files list and print unkown files | |
sub check_files { | |
# dpkg-query needs absolute pathanames | |
my @paths = map { "/etc/$_" } @files; | |
# prepare filehandles for dpkg-query, we need only its output | |
open my $in, '<', '/dev/null'; | |
open my $err, '>', '/dev/null'; | |
my $out; | |
# actually check the files, getting a cluttered list of know files | |
my $pid = open3($in, $out, $err, 'dpkg-query', '-S', @paths); | |
my @outlines = <$out>; | |
waitpid($pid, 0); | |
# turn the cluttered list of know files into a hash whose keys | |
# are pathnames relative to /etc | |
my %found; | |
for my $line (@outlines) { | |
chomp $line; | |
# dpkg-query's ouput looks like | |
# <package-name>: /etc/relpath | |
$line =~ s!^[^ ]+: /etc/!!; | |
$found{$line}++; | |
} | |
# report unknown files | |
for my $file (@files) { | |
print "$file\n" unless $found{$file}; | |
} | |
} | |
__END__ | |
# example exclude file | |
# generated links | |
/rc?.d | |
/ssl/certs/*.[01] | |
/ssl/certs/*.pem | |
/alternatives | |
# private | |
/ssl/private | |
# misc | |
adduser.conf | |
aliases | |
apt/apt.conf.d/00CDMountPoint | |
apt/apt.conf.d/00trustcdrom | |
apt/listchanges.conf | |
apt/secring.gpg | |
apt/sources.list | |
apt/trustdb.gpg | |
apt/trusted.gpg | |
ca-certificates.conf | |
console-setup/cached.kmap.gz | |
console-setup/Lat15-Fixed16.psf.gz | |
default/console-setup | |
default/exim4 | |
default/grub | |
default/keyboard | |
default/locale | |
default/nfs-common | |
default/portmap | |
default/rcS | |
dictionaries-common/default.aff | |
dictionaries-common/default.hash | |
dictionaries-common/ispell-default | |
dictionaries-common/words | |
dpkg/origins/default | |
environment | |
exim4/update-exim4.conf.conf | |
fstab | |
group | |
group- | |
gshadow | |
gshadow- | |
hostname | |
hosts | |
hosts.allow | |
hosts.deny | |
idmapd.conf | |
initramfs-tools/conf.d/resume | |
initramfs-tools/modules | |
inittab | |
inputrc | |
kernel-img.conf | |
ld.so.conf | |
locale.gen | |
localtime | |
mailcap | |
mailname | |
modules | |
motd | |
motd.tail | |
network/interfaces | |
networks | |
nsswitch.conf | |
pam.d/common-account | |
pam.d/common-auth | |
pam.d/common-password | |
pam.d/common-session | |
pam.d/common-session-noninteractive | |
passwd | |
passwd- | |
profile | |
python/debian_config | |
rc.local | |
security/opasswd | |
sgml/catalog | |
sgml/xml-core.cat | |
shadow | |
shadow- | |
shells | |
ssh/sshd_config | |
ssh/ssh_host_dsa_key | |
ssh/ssh_host_dsa_key.pub | |
ssh/ssh_host_rsa_key | |
ssh/ssh_host_rsa_key.pub | |
ssl/certs/ca-certificates.crt | |
timezone | |
udev/rules.d/70-persistent-cd.rules | |
udev/rules.d/70-persistent-net.rules | |
X11/X | |
X11/Xwrapper.config | |
xml/catalog | |
xml/xml-core.xml |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment