diff --git a/CheckFilelist.py b/CheckFilelist.py index 8486cc8..34cf9de 100644 --- a/CheckFilelist.py +++ b/CheckFilelist.py @@ -3,7 +3,7 @@ # File : CheckFilelist.py # Package : rpmlint # Author : Ludwig Nussel -# Purpose : Check for wrongly packaged files +# Purpose : Check for wrongly packaged files and FHS violations ############################################################################# from Filter import * @@ -12,13 +12,17 @@ import re import os import string import fnmatch +from rpm import RPMTAG_VENDOR _defaulterror = 'suse-filelist-forbidden' -_defaultmsg = '%(file)s is not allowed anymore in SUSE Linux' +_defaultmsg = '%(file)s is not allowed in SUSE Linux' def notnoarch(pkg): return pkg.arch != 'noarch' +def isfilesystem(pkg): + return pkg.name == 'filesystem' + def isdebuginfo(pkg): if pkg.name.endswith('-debuginfo') \ or pkg.name.endswith('-debuginfo-32bit') \ @@ -34,6 +38,52 @@ def notsymlink(pkg, f): type = (mode>>12)&017 return type != 012 +_goodprefixes = ( + '/bin/', + '/boot/', + '/etc/', + '/lib/', + '/lib64/', + '/media/', + # SUSE policy handled in separate check + '/opt/', + '/sbin/', + '/srv/', + # SUSE policy handled in separate check + '/usr/X11R6/', + '/usr/bin/', + '/usr/games/', + '/usr/include/', + '/usr/lib/', + '/usr/lib64/', + '/usr/sbin/', + '/usr/share/', + # actually only linux is allowed by fhs + '/usr/src/linux', + '/usr/src/debug/', + '/usr/src/packages/', + '/var/account/', + '/var/cache/', + '/var/crash/', + '/var/games/', + '/var/lib/', + '/var/lock/', + '/var/log/', + '/var/mail/', + '/var/opt/', + '/var/run/', + '/var/spool/', + '/var/yp/', + # those are not in FHS! + '/var/adm/', + '/var/nis/', + '/emul/', + ) + +# computed from goodprefixes. +# Directories that are only allowed to have defined subdirs (such as /usr) +_restricteddirs = set() + _checks = [ { 'good': [ @@ -74,8 +124,6 @@ _checks = [ '/etc/rc.config.d/*', '/etc/init.d/*/*', '/usr/share/locale/LC_MESSAGES', - '/usr/X11R6/lib/locale', - '/usr/X11R6/lib/X11/locale/LC_MESSAGES*', '/opt/gnome', '/usr/lib/perl5/site_perl/*', '/usr/lib/perl5/vendor_perl/5.*/auto', @@ -84,7 +132,7 @@ _checks = [ }, { 'error': 'suse-filelist-forbidden-devel-in-lib', - 'details': 'please move la files, static libs and .so symlinks out of /', + 'details': 'please move la files, static libs and .so symlinks to /usr/lib(64)', 'bad': [ "/lib/*.la", "/lib/*.a", @@ -94,7 +142,7 @@ _checks = [ }, { 'error': 'suse-filelist-forbidden-devel-in-lib', - 'details': 'please move la files, static libs and .so symlinks out of /', + 'details': 'please move la files, static libs and .so symlinks to /usr/lib(64)', 'good': [ # exception for pam "/lib/security/*.so", @@ -108,13 +156,10 @@ _checks = [ 'ignorefileif': notsymlink, }, { - 'error': 'suse-filelist-forbidden-fhs22', - 'msg': '%(file)s is not allowed in FHS 2.2', + 'error': 'suse-filelist-forbidden-fhs23', + 'msg': '%(file)s is not allowed in FHS 2.3', 'details': 'see http://www.pathname.com/fhs/ to find a better location', 'bad': [ - "/usr/dict", - "/var/locale", - "/var/locale/*", "/etc/X11/app-defaults/*", "/usr/local/man/*/*", "/var/lib/games", @@ -196,19 +241,9 @@ _checks = [ 'error': 'suse-filelist-forbidden-xorg', 'details': """Please use the updated paths for Xorg 7.1 and above""", 'bad': [ - '/usr/X11R6/include/X11', - '/usr/X11R6/include/X11/*', - '/usr/X11R6/lib/X11', - '/usr/X11R6/lib/X11/*', - '/usr/X11R6/lib/modules', - '/usr/X11R6/lib/modules/*', - '/usr/X11R6/lib64/modules', - '/usr/X11R6/lib64/modules/*', - '/usr/X11R6/lib/X11/app-defaults', - '/usr/X11R6/lib/X11/app-defaults/*', - '/usr/X11R6/lib64/X11/app-defaults', - '/usr/X11R6/lib64/X11/app-defaults/*', + '/usr/X11R6/*', ], + 'ignorepkgif': isfilesystem, }, { 'error': 'suse-filelist-forbidden-suseconfig', @@ -264,150 +299,6 @@ _checks = [ { 'error': 'suse-filelist-forbidden-opt', 'details': """/opt may not be used by a distribution. It is reserved for 3rd party packagers""", - 'good': [ - # KDE3 legacy exception - '/opt/kde3', - '/opt/kde3/*', - ], - 'bad': [ - '/opt/*', - ], - }, - { - 'error': 'suse-filelist-forbidden-fhs22', - 'good': [ - '/bin', - '/bin/*', - '/boot', - '/boot/*', - '/cdrom', - '/dev', - '/dev/*', - '/etc', - '/etc/*', - '/floppy', - '/home', - '/lib', - '/lib/*', - '/lib64', - '/lib64/*', - '/media', - '/media/*', - '/mnt', - '/opt', - # handled in separate check - '/opt/*', - '/proc', - '/root', - '/root/.exrc', - '/root/.gnupg', - '/root/.gnupg/*', - '/root/.kbackrc', - '/root/.xinitrc', - '/root/bin', - '/sbin', - '/sbin/*', - '/subdomain', - '/sys', - '/tmp', - '/tmp/.X11-unix', - '/tmp/.ICE-unix', - '/usr', - '/usr/*-linux-libc5', - '/usr/*-linux-libc5/*', - '/usr/*-linux', - '/usr/*-linux/*', - '/usr/X11', - '/usr/X11R6', - '/usr/X11R6/*', - '/usr/bin', - '/usr/bin/*', - '/usr/games', - '/usr/games/*', - '/usr/include', - '/usr/include/*', - '/usr/lib', - '/usr/lib/*', - '/usr/lib64', - '/usr/lib64/*', - '/usr/local', - '/usr/local/bin', - '/usr/local/games', - '/usr/local/include', - '/usr/local/lib', - '/usr/local/lib64', - '/usr/local/man', - '/usr/local/man/*', - '/usr/local/sbin', - '/usr/local/share', - '/usr/local/src', - '/usr/sbin', - '/usr/sbin/*', - '/usr/share', - '/usr/share/*', - '/usr/spool', - '/usr/src', - '/usr/src/debug*', - '/usr/src/linux*', - '/usr/src/kernel-modules*', - '/usr/src/packages', - '/usr/src/packages/*', - '/usr/src/bxform*', - '/usr/src/dicts', - '/usr/src/dicts/*', - '/usr/tmp', - '/var', - '/var/X11R6', - '/var/X11R6/*', - '/var/account', - '/var/account/*', - '/var/agentx', - '/var/agentx/*', - '/var/cache', - '/var/cache/*', - '/var/crash', - '/var/crash/*', - '/var/games', - '/var/games/*', - '/var/lib', - '/var/lib/*', - '/var/local', - '/var/lock', - '/var/lock/*', - '/var/log', - '/var/log/*', - '/var/mail', - '/var/mail/*', - '/var/opt', - '/var/opt/*', - '/var/preserve', - '/var/run', - '/var/run/*', - '/var/spool', - '/var/spool/*', - '/var/tmp', - '/var/tmp/vi.recover', - '/var/yp', - '/var/yp/*', - # we have these below /var, but not nice to have: - '/var/adm', - '/var/adm/*', - '/var/db', - '/var/db/*', - '/var/nis', - '/var/nis/*', - '/var/heimdal', - # allowed, but not nice to have: - '/afs', - '/afs/*', - '/emul', - '/emul/*', - '/srv', - '/srv/*', - ], - 'bad': [ - '*', - ] }, ] @@ -416,6 +307,11 @@ class FilelistCheck(AbstractCheck.AbstractCheck): AbstractCheck.AbstractCheck.__init__(self, "CheckFilelist") import re + _restricteddirs.add('/') + for d in _goodprefixes: + if d.count('/') > 2: + _restricteddirs.add(d[0:-1].rpartition('/')[0]) + for check in _checks: if 'good' in check: for i in range(len(check['good'])): @@ -424,16 +320,19 @@ class FilelistCheck(AbstractCheck.AbstractCheck): r = fnmatch.translate(pattern) check['good'][i] = re.compile(r) - for i in range(len(check['bad'])): - pattern = check['bad'][i] - if '*' in pattern: - r = fnmatch.translate(pattern) - check['bad'][i] = re.compile(r) + if 'bad' in check: + for i in range(len(check['bad'])): + pattern = check['bad'][i] + if '*' in pattern: + r = fnmatch.translate(pattern) + check['bad'][i] = re.compile(r) def check(self, pkg): global _checks global _defaultmsg global _defaulterror + global _goodprefixes + global _restricteddirs if pkg.isSource(): return @@ -441,7 +340,7 @@ class FilelistCheck(AbstractCheck.AbstractCheck): files = pkg.files() if not files: - printError(pkg, 'suse-filelist-empty', 'packages without any files are not allowed anymore in SUSE Linux') + printError(pkg, 'suse-filelist-empty', 'packages without any files are not allowed in SUSE Linux') return for check in _checks: @@ -460,24 +359,77 @@ class FilelistCheck(AbstractCheck.AbstractCheck): else: error = _defaulterror - for f in files: - ok = False - if 'good' in check: - for g in check['good']: - if (not isinstance(g, str) and g.match(f)) or g == f: - ok = True - break - if ok: + if 'good' in check or 'bad' in check: + for f in files: + ok = False + if 'good' in check: + for g in check['good']: + if (not isinstance(g, str) and g.match(f)) or g == f: + ok = True + break + if ok: + continue + + if 'bad' in check: + for b in check['bad']: + if 'ignorefileif' in check: + if check['ignorefileif'](pkg, f): + continue + if (not isinstance(b, str) and b.match(f)) or b == f: + m = msg % { 'file':f } + printError(pkg, error, m) + + invalidfhs = set() + invalidopt = set() + + if pkg.header[RPMTAG_VENDOR] and pkg.header[RPMTAG_VENDOR].find('SUSE') != -1: + isSUSE = True + else: + isSUSE = False + + # the checks here only warn about a directory once rather + # than reporting potentially hundreds of files individually + for f in files: + enreg = files[f] + mode = enreg[0] + type = (mode>>12)&017 + + # append / to directories + if type == 04: + f += '/' + + if not f.startswith(_goodprefixes): + base = f.rpartition('/') + pfx = None + # find the first invalid path component (/usr/foo/bar/baz -> /usr) + while base[0] and not base[0].startswith(_goodprefixes) and not base[0] in _restricteddirs: + pfx = base[0] + base = base[0].rpartition('/') + + if not pfx: + invalidfhs.add(f) + else: + invalidfhs.add(pfx) + + if f.startswith('/opt'): + try: + provider = f.split('/')[2] + except: + continue + # legacy exception + if provider == 'kde3': + continue + if isSUSE and (provider == 'suse' or provider == 'novell'): continue - for b in check['bad']: - if 'ignorefileif' in check: - if check['ignorefileif'](pkg, f): - continue - if (not isinstance(b, str) and b.match(f)) or b == f: - m = msg % { 'file':f } - printError(pkg, error, m) + d = '/opt/'+provider + invalidopt.add(d) + for f in invalidfhs: + printError(pkg, 'suse-filelist-forbidden-fhs23', "%(file)s is not allowed in FHS 2.3" % { 'file': f }) + + for f in invalidopt: + printError(pkg, 'suse-filelist-forbidden-opt', '%(file)s is not allowed for official SUSE packages' % { 'file': f }) check=FilelistCheck() diff --git a/rpmlint.changes b/rpmlint.changes index 0136cc7..23b5348 100644 --- a/rpmlint.changes +++ b/rpmlint.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Tue Jan 13 15:59:15 CET 2009 - lnussel@suse.de + +- CheckFilelist: optimize FHS check to only complain about wrong + directories rather than hundreds of individual files + ------------------------------------------------------------------- Mon Jan 12 10:48:19 CET 2009 - lnussel@suse.de diff --git a/rpmlint.spec b/rpmlint.spec index 2d218f3..c8c1dbf 100644 --- a/rpmlint.spec +++ b/rpmlint.spec @@ -22,7 +22,7 @@ Name: rpmlint BuildRequires: rpm-python Summary: Rpm correctness checker Version: 0.84 -Release: 9 +Release: 11 Source0: %{name}-%{version}.tar.bz2 Source1: config Source1001: config.in @@ -220,6 +220,9 @@ rm -rf $RPM_BUILD_ROOT /usr/share/man/man1/rpmlint.1.gz %changelog +* Tue Jan 13 2009 lnussel@suse.de +- CheckFilelist: optimize FHS check to only complain about wrong + directories rather than hundreds of individual files * Mon Jan 12 2009 lnussel@suse.de - CheckFilelist: add exceptions for kde and pam - CheckPolkitPrivs: use info instead of warning to avoid badness assignment