SHA256
1
0
forked from pool/rpmlint

Accepting request 137011 from devel:openSUSE:Factory:rpmlint

- Remove check for /var/lock and /var/run since it's in upstream
  rpmlint already.

- Add README.packaging.txt to explain packaging of file
  rpmlint-checks-$VERSION.tar.gz
- Package all *py files into rpmlint-checks tarball
- Add _service file to update rpmlint-checks tarball
- Add /etc/systemd.d, /etc/modules-load.d and /etc/tmpfiles.d to the
  blacklist, only users should write here.
- Blacklist the directories used by systemd.
- Remove SuSEconfig directories (update patch suse-filesystem.diff)
- Add warnings about files on tmpfs in /var/lock or /var/run.

- restore LibraryPolicy from git

OBS-URL: https://build.opensuse.org/request/show/137011
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/rpmlint?expand=0&rev=169
This commit is contained in:
Stephan Kulow 2012-10-05 11:48:02 +00:00 committed by Git OBS Bridge
commit 666b20d48b
28 changed files with 72 additions and 2952 deletions

View File

@ -1,47 +0,0 @@
#############################################################################
# File : BashismsCheck.py
# Package : rpmlint
# Author : Guido Berhoerster
# Purpose : check /bin/sh shell scripts for bashisms
#############################################################################
import re
import AbstractCheck
import Config
import Pkg
from Filter import *
class BashismsCheck(AbstractCheck.AbstractFilesCheck):
RE_BIN_SH = re.compile('#!\s*(/usr)?/bin/sh(\s+|$)')
def __init__(self):
AbstractCheck.AbstractFilesCheck.__init__(self, "BashismsCheck", ".*")
def check_file(self, pkg, filename):
try:
f = open(filename)
except:
return
try:
first_line = f.read(256).split("\n")[0]
if self.RE_BIN_SH.match(first_line):
status, output = Pkg.getstatusoutput(["dash", "-n", filename])
if status == 2:
printWarning(pkg, "bin-sh-syntax-error", filename)
try:
status, output = Pkg.getstatusoutput(["checkbashisms", filename])
if status == 1:
printInfo(pkg, "potential-bashisms", filename)
except Exception, x:
printError(pkg, 'rpmlint-exception', "%(file)s raised an exception: %(x)s" % {'file':filename, 'x':x})
finally:
f.close()
check = BashismsCheck()
if Config.info:
addDetails('bin-sh-syntax-error',
'''A /bin/sh shell script contains a syntax error.''',
'potential-bashisms',
'''checkbashisms reported potential bashisms in a /bin/sh shell
script, you might want to manually check this script for bashisms.''')

View File

@ -1,132 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : BrandingPolicyCheck.py
# Package : rpmlint
# Author : Dirk Mueller
# Purpose : Verify that branding related things comply
#############################################################################
from Filter import *
import AbstractCheck
import rpm
import re
import commands
import stat
import Config
import os
import string
import Pkg
class BrandingPolicyCheck(AbstractCheck.AbstractCheck):
def __init__(self):
self.map = []
AbstractCheck.AbstractCheck.__init__(self, "BrandingPolicyCheck")
def check(self, pkg):
if pkg.isSource():
return
pkg_requires = set(map(lambda x: string.split(x[0],'(')[0], pkg.requires()))
pkg_conflicts = set(map(lambda x: x[0], pkg.conflicts()))
# verify that only generic branding is required by non-branding packages
for r in pkg.requires():
if (pkg.name.find('-branding-') < 0 and
(r[0].find('-theme-') >= 0 or r[0].find('-branding-') >= 0)):
printError(pkg,'suse-branding-specific-branding-req', r[0])
if r[0].endswith('branding') or r[0].endswith('theme'):
# XXX: that startswith 1 breaks with openSUSE 20...
if (r[1] != rpm.RPMSENSE_EQUAL or not r[2][1].startswith('1')):
printError(pkg,'suse-branding-unversioned-requires', r[0])
# verify that it doesn't conflict with branding
for r in pkg_conflicts:
if r.startswith("otherproviders("):
continue
if r.find('-theme-') >= 0 or r.find('-branding-') >= 0:
printError(pkg,'suse-branding-branding-conflict', r)
if pkg.name.find('-branding-') < 0:
return
branding_basename=pkg.name.partition('-branding-')[0]
branding_style=pkg.name.partition('-branding-')[2]
generic_branding = ("%s-branding" % (branding_basename))
pkg_provides = set(map(lambda x: string.split(x[0],'(')[0], pkg.provides()))
pkg_supplements = set(map(lambda x: x[0], pkg.supplements()))
# verify that it only supplements with packageand
found_correct=False
correct_supplement="packageand(%s:branding-%s)" % (branding_basename, branding_style)
for s in pkg_supplements:
if s.startswith('packageand('):
if s != correct_supplement:
printError(pkg,'suse-branding-wrong-branding-supplement', s)
else:
found_correct=True
else:
printError(pkg,'suse-branding-excessive-supplement', s)
if not found_correct:
printError(pkg,'suse-branding-supplement-missing', correct_supplement)
# nothing else
for r in pkg.recommends():
printError(pkg,'suse-branding-excessive-recommends', r[0])
for r in pkg.suggests():
printError(pkg,'suse-branding-excessive-suggests', r[0])
for r in pkg.enhances():
printError(pkg,'suse-branding-excessive-enhances', r[0])
# check for provide foo-branding
branding_provide=None
for p in pkg.provides():
if p[0] == generic_branding:
branding_provide=p
break
# check for Conflicts: otherproviders(kde4-kdm-branding)
conflict_prop = "otherproviders(%s)" % (generic_branding)
have_conflict_prop = False
for c in pkg_conflicts:
if c == conflict_prop:
have_conflict_prop = True
break
if not have_conflict_prop:
printError(pkg,'suse-branding-missing-conflicts', conflict_prop)
if not branding_provide:
printError(pkg,'suse-branding-no-branding-provide')
else:
if (len(branding_provide) < 2 or branding_provide[1] != rpm.RPMSENSE_EQUAL):
printError(pkg, 'suse-branding-unversioned-provides', branding_provide[0])
for r in pkg.requires():
if r[0].find('-theme-') >= 0 or r[0].find('-branding-') >= 0:
if (r[1] != rpm.RPMSENSE_EQUAL or not r[2][1].startswith('1')):
printError(pkg, 'suse-branding-unversioned-requires', r[0])
check=BrandingPolicyCheck()
if Config.info:
addDetails(
'suse-branding-specific-branding-req',
"""bla""",
'suse-branding-no-branding-provides',
"""Please add a provides entry similar to 'Provides: %name-branding = %version'.""",
'suse-branding-unversioned-provides',
"""Please make sure that your provides entry reads like 'Provides: %name-branding = %version'.""",
'suse-branding-supplement-missing',
"""branding packages should provide a supplemnent in the form
Supplements: packageand(basepackage:branding-<flavour>)
""",
'suse-branding-unversioned-requires',
"""Please make sure that your requires entry reads like 'Requires: %name-branding = <versionnumber>'.""",
'suse-branding-missing-conflicts',
"""Any branding flavor package that provides the generic branding
must also conflict with all other branding packages via a special
otherproviders()""",
)

View File

@ -1,85 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : CheckAlternativesGhostFiles.py
# Package : rpmlint
# Author : Michal Vyskocil
# Purpose : Check if files used by update-alternatives are marked as %ghost
#############################################################################
from Filter import *
import AbstractCheck
import rpm
class CheckAlternativesGhostFiles(AbstractCheck.AbstractCheck):
INSTALL="--install"
SLAVE="--slave"
def __init__(self):
AbstractCheck.AbstractCheck.__init__(self, "CheckAlternativesGhostFiles")
@classmethod
def read_ghost_files(cls, script):
ghost_files = []
if not script or not 'update-alternatives' in script:
return ghost_files
for command in ( \
c.replace('\\\n', '').strip() \
for c in script.split('update-alternatives') \
if cls.INSTALL in c):
#parse install
command_args = []
for arg in command.split(None):
if not arg.startswith("--"):
command_args.append(arg)
ghost_files.append(command_args[0])
if cls.SLAVE in command:
for sc in ( \
c.strip() \
for c in command[command.index(cls.SLAVE):].split(cls.SLAVE) \
if c.strip() != ''):
xs = sc.split(None, 2)
ghost_files.append(xs[0])
return ghost_files
def check(self, pkg):
if pkg.isSource():
return
alt_files = []
for script in (pkg.header[tag] for tag in (rpm.RPMTAG_POSTIN, rpm.RPMTAG_PREIN, rpm.RPMTAG_POSTTRANS)):
alt_files.extend(self.read_ghost_files(script))
files = pkg.files()
ghost_files = pkg.ghostFiles()
for af in (af for af in alt_files if not af in ghost_files):
if af in files:
printWarning(pkg, 'generic-name-not-marked-as-ghost %s' % (af))
else:
printWarning(pkg, 'generic-name-not-in-filelist %s' % af)
check=CheckAlternativesGhostFiles()
if Config.info:
addDetails(
'generic-name-not-marked-as-ghost',
'''The update-alternatives generic name is not marked as a ghost in the %files section.
This causes problems during update. Mark it as a %ghost in %files section.''',
'generic-name-not-in-filelist',
'''The update-alternatives generic name is not in a filelist of package.
Add it to list marked as %ghost. Note: this error will be raised,
if you use a hash ($) in file name, use rpm macros in spec file instead.''',
)

View File

@ -1,49 +0,0 @@
#############################################################################
# File : CheckBuilDate.py
# Package : rpmlint
# Author : Cristian Rodriguez
# Purpose : Check for binaries containing build date
#############################################################################
from Filter import *
import AbstractCheck
import rpm
import re
import os
import commands
import Config
import stat
import time
class BuildDateCheck(AbstractCheck.AbstractFilesCheck):
def __init__(self):
AbstractCheck.AbstractFilesCheck.__init__(self, "CheckBuildDate", ".*")
self.looksliketime = re.compile('(2[0-3]|[01]?[0-9]):([0-5]?[0-9]):([0-5]?[0-9])')
self.istoday = re.compile(time.strftime("%b %e %Y"))
def check_file(self, pkg, filename):
if filename.startswith('/usr/lib/debug') or pkg.isSource():
return
if not stat.S_ISREG(pkg.files()[filename].mode):
return
grep_date = pkg.grep(self.istoday, filename)
grep_time = pkg.grep(self.looksliketime, filename)
if len(grep_date):
if len(grep_time):
printError(pkg, "file-contains-date-and-time", filename)
else:
printWarning(pkg, "file-contains-current-date", filename)
check=BuildDateCheck()
if Config.info:
addDetails(
'file-contains-current-date',
"""Your file contains the current date, this may cause the package to rebuild in excess.""",
'file-contains-date-and-time',
"""Your file uses __DATE and __TIME__ this causes the package to rebuild when not needed"""
)

View File

@ -1,41 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : CheckBuildRoot.py
# Package : rpmlint
# Author : Dirk Mueller, Stephan Kulow
# Purpose : Check for files containing $RPM_BUILD_ROOT
#############################################################################
from Filter import *
import AbstractCheck
import rpm
import re
import os
import commands
import Config
import stat
class BuildRootCheck(AbstractCheck.AbstractFilesCheck):
def __init__(self):
AbstractCheck.AbstractFilesCheck.__init__(self, "CheckBuildRoot", ".*")
t = rpm.expandMacro('%buildroot')
for m in ('name', 'version', 'release'):
t = t.replace("%%{%s}" % (m), "[\w\!-\.]{1,20}")
self.build_root_re = re.compile(t)
def check_file(self, pkg, filename):
if filename.startswith('/usr/lib/debug') or pkg.isSource():
return
if not stat.S_ISREG(pkg.files()[filename].mode):
return
if len(pkg.grep(self.build_root_re, filename)):
printError(pkg, "file-contains-buildroot", filename)
check=BuildRootCheck()
if Config.info:
addDetails(
'file-contains-buildroot',
"Your file contains traces of $RPM_BUILD_ROOT."
)

View File

@ -1,89 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : CheckCommonFiles.py
# Package : rpmlint
# Author : Dirk Mueller
# Purpose : Check for common files being packaged
#############################################################################
from Filter import *
import AbstractCheck
import rpm
import re
import commands
import stat
import Config
import os
import string
class CommonFilesCheck(AbstractCheck.AbstractCheck):
def __init__(self):
self.map = []
AbstractCheck.AbstractCheck.__init__(self, "CheckCommonFiles")
self.sources_am_re = re.compile('([\w\d_]+_SOURCES\s*=|\s*SUBDIRS\s*=)')
def check(self, pkg):
if pkg.isSource():
return
files = pkg.files()
for f in files.keys():
if f in pkg.ghostFiles():
continue
md5 = files[f].md5
if len(md5) and md5 in (
'c59cbaf0df9bcf35feca0d0f1fc01dae',
'cf8c4d1a5ab88db006c47ae2b51a6b30',
'5d4638159851671944108691f23e4f28',
'0d6be33865b76025c20b48bcac87adb7'):
printError(pkg, "generic-build-instructions", f)
# bnc 379919
#if len(md5) and md5 in (
# '94d55d512a9ba36caa9b7df079bae19f'):
# printError(pkg, "duplicated-file-gpl-v2", f)
#if len(md5) and md5 in (
# 'd32239bcb673463ab874e80d47fae504'):
# printError(pkg, "duplicated-file-gpl-v3", f)
# bsd causes the false positive COPYING.BSD
if len(md5) and f.rsplit('/',1)[1][0].lower() == 'r' and f.rsplit('.',1)[-1].lower() in (
'aix', 'bsd', 'dos', 'hpux', 'irix', 'os2', 'mac', 'macos', 'tru64',
'sco', 'vms', 'win32', 'win', 'solaris'):
printWarning(pkg, "non-linux-readme", f)
if f.endswith("/Makefile.am") and f[:-3] + ".in" in files and f in pkg.docFiles():
if not len(pkg.grep(self.sources_am_re, f)):
printError(pkg, "makefile-junk", f)
printError(pkg, "makefile-junk", f[:-3] + ".in")
if f[:-3] in files:
printError(pkg, "makefile-junk", f[:-3])
check=CommonFilesCheck()
if Config.info:
addDetails(
'generic-build-instructions',
"""Your package contains a file that contains the FSF generic
configure/make/make install instructions. Those are useless
for a binary package. Consider removing it to save 3kb of rpm size.""",
'duplicated-file-gpl-v3',
"""Your package contains a file that contains the FSF GPLv3
license. If you really have to ship it, consider symlinking it
from the licenses package.""",
'duplicated-file-gpl-v2',
"""Your package contains a file that contains the FSF GPLv2
license. If you really have to ship it, consider symlinking it
from the licenses package.""",
'non-linux-readme',
"""Your package contains a file that contains instructions
for non-linux platforms. They're most likely unneccessary bloat,
consider removing them from your package.""",
'makefile-junk',
"""Your package contains makefiles that only make sense in a
source package. Did you package a complete directory from the
tarball by using %doc? Consider removing Makefile* from this
directory at the end of your %install section to reduce package bloat."""
)

View File

@ -1,57 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : CheckDBUSServices.py
# Package : rpmlint
# Author : Ludwig Nussel
# Purpose : Check for DBUS services that are not authorized by the security team
#############################################################################
# http://techbase.kde.org/Development/Tutorials/D-Bus/Autostart_Services
from Filter import *
import AbstractCheck
import re
import os
import string
SERVICES_WHITELIST = Config.getOption('DBUSServices.WhiteList', ()) # set of file names
# need to end with / so we don't catch directories
_dbus_system_paths = [
"/usr/share/dbus-1/system-services/",
"/etc/dbus-1/system.d/"
]
class DBUSServiceCheck(AbstractCheck.AbstractCheck):
def __init__(self):
AbstractCheck.AbstractCheck.__init__(self, "CheckDBUSServices")
def check(self, pkg):
global SERVICES_WHITELIST
global _dbus_system_paths
if pkg.isSource():
return
files = pkg.files()
for f in files:
if f in pkg.ghostFiles():
continue
for p in _dbus_system_paths:
if f.startswith(p):
bn = f[len(p):]
if not bn in SERVICES_WHITELIST:
printError(pkg, "suse-dbus-unauthorized-service", f)
check=DBUSServiceCheck()
if Config.info:
addDetails(
'suse-dbus-unauthorized-service',
"""The package installs a DBUS system service file. If the package
is intended for inclusion in any SUSE product please open a bug
report to request review of the service by the security team.""",
)

View File

@ -1,80 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : CheckDBusPolicy.py
# Package : rpmlint
# Author : Ludwig Nussel
# Purpose : Check for broken DBus policies
#############################################################################
# causes extraction of package if it contains files in /etc/dbus-1/system.d/
from Filter import *
import AbstractCheck
from xml.dom.minidom import parse
class DBusPolicyCheck(AbstractCheck.AbstractCheck):
def __init__(self):
AbstractCheck.AbstractCheck.__init__(self, "CheckDBusPolicy")
def check(self, pkg):
if pkg.isSource():
return
files = pkg.files()
for f in files:
if f in pkg.ghostFiles():
continue
# catch xml exceptions
try:
if f.startswith("/etc/dbus-1/system.d/"):
send_policy_seen = False
lf = pkg.dirName() + f
xml = parse(lf)
for p in xml.getElementsByTagName("policy"):
for allow in p.getElementsByTagName("allow"):
if ( allow.hasAttribute('send_interface') \
or allow.hasAttribute('send_member') \
or allow.hasAttribute('send_path')) \
and not allow.hasAttribute('send_destination'):
send_policy_seen = True
printError(pkg, 'dbus-policy-allow-without-destination', "%(file)s: %(xml)s" % { 'file':f, 'xml':allow.toxml() })
elif allow.hasAttribute('send_destination'):
send_policy_seen = True
if allow.hasAttribute('receive_sender') \
or allow.hasAttribute('receive_interface'):
printInfo(pkg, 'dbus-policy-allow-receive', "%(file)s: %(xml)s" % { 'file':f, 'xml':allow.toxml() })
for deny in p.getElementsByTagName("deny"):
if ( deny.hasAttribute('send_interface') \
and not deny.hasAttribute('send_destination')):
printError(pkg, 'dbus-policy-deny-without-destination', "%(file)s: %(xml)s" % { 'file':f, 'xml':deny.toxml() })
if not send_policy_seen:
printError(pkg, 'dbus-policy-missing-allow', "%(file)s does not allow communication" % { 'file':f })
except Exception, x:
printError(pkg, 'rpmlint-exception', "%(file)s raised an exception: %(x)s" % {'file':f, 'x':x})
continue
check=DBusPolicyCheck()
if Config.info:
addDetails(
'dbus-policy-allow-without-destination',
"""'allow' directives must always specify a 'send_destination'""",
'dbus-policy-allow-receive',
"""allow receive_* is normally not needed as that is the default""",
'dbus-policy-deny-without-destination',
"""'deny' directives must always specify a 'send_destination' otherwise messages to other services could be blocked""",
'dbus-policy-missing-allow',
"""every dbus config normally needs a line of the form
<allow send_destination="org.foo.bar"/>
or similar. If that is missing the service will not work with a dbus that uses
deny as default policy""",
'rpmlint-exception',
"""A python exception was raised which prevents further analysis""",
)

View File

@ -1,97 +0,0 @@
# vim:sw=4:et
#---------------------------------------------------------------
# Module : rpmlint
# File : CheckExecDocs.py
# Author : Stephan Kulow, Dirk Mueller
# Purpose : Check for executable files in %doc
#---------------------------------------------------------------
from Filter import *
import AbstractCheck
import rpm
import re
import commands
import stat
import Config
import os
import string
def ignore_pkg(name):
if name.startswith('bundle-'):
return True
if name.find('-devel') != -1:
return True
if name.find('-doc') != -1:
return True
return False
def lang_ignore_pkg(name):
if ignore_pkg(name):
return True
if name.endswith('-lang'):
return True
if name.find('-trans-') != -1:
return True
return False
class ExecDocsCheck(AbstractCheck.AbstractCheck):
def __init__(self):
self.map = []
AbstractCheck.AbstractCheck.__init__(self, "CheckExecDocs")
def check(self, pkg):
if pkg.isSource():
return
files = pkg.files()
complete_size=0
lang_size=0
for f, pkgfile in files.items():
if stat.S_ISREG(pkgfile.mode):
complete_size += pkgfile.size
if pkgfile.lang != '':
lang_size += pkgfile.size
doc_size=0
for f in pkg.docFiles():
if stat.S_ISREG(files[f].mode):
doc_size += files[f].size
if doc_size * 2 >= complete_size \
and doc_size > 100*1024 and (complete_size - doc_size) * 20 > complete_size \
and not ignore_pkg(pkg.name):
printWarning(pkg, "package-with-huge-docs", ("%3d%%" % (doc_size * 100 / complete_size)) )
if lang_size * 2 >= complete_size \
and lang_size > 100*1024 and (complete_size - lang_size) * 20 > complete_size \
and not lang_ignore_pkg(pkg.name):
printWarning(pkg, "package-with-huge-translation", ("%3d%%" % (lang_size * 100 / complete_size)))
for f in pkg.docFiles():
mode=files[f].mode
if not stat.S_ISREG(mode) or not mode & 0111:
continue
for ext in ['txt', 'gif', 'jpg', 'html', 'pdf', 'ps', 'pdf.gz', 'ps.gz']:
if f.endswith("." + ext):
printError(pkg, 'executable-docs', f)
for name in ['README', 'NEWS', 'COPYING', 'AUTHORS']:
if f.endswith("/" + name):
printError(pkg, 'executable-docs', f)
check=ExecDocsCheck()
if Config.info:
addDetails(
'executable-docs',
"Documentation should not be executable.",
'package-with-huge-docs',
"""More than half the size of your package is documentation.
Consider splitting it into a -doc subpackage.""",
'package-with-huge-translation',
"""More than half the size of your package is language-specific.
Consider splitting it into a -lang subpackage."""
)

View File

@ -1,444 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : CheckFilelist.py
# Package : rpmlint
# Author : Ludwig Nussel
# Purpose : Check for wrongly packaged files and FHS violations
#############################################################################
from Filter import *
import AbstractCheck
import re
import os
import string
import fnmatch
from rpm import RPMTAG_VENDOR
_defaulterror = 'suse-filelist-forbidden'
_defaultmsg = '%(file)s is not allowed in SUSE'
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') \
or pkg.name.endswith('-debuginfo-64bit') \
or pkg.name.endswith('-debugsource') \
or pkg.name.endswith('-debug'):
return True
def notsymlink(pkg, f):
mode = pkg.files()[f].mode
type = (mode>>12)&017
return type != 012
def ghostfile(pkg, f):
ghosts = pkg.ghostFiles()
return f in ghosts
_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 = [
{
'bad': [
'*/.xvpics',
'*.orig',
'*.orig.gz',
'/usr/share/*/.libs*',
'/usr/share/*/.deps*',
'/var/adm/setup',
'/etc/httpd/*',
'/etc/init.d/*/*',
'/usr/share/locale/LC_MESSAGES',
],
},
{
'error': 'suse-filelist-forbidden-sysconfig',
'details': '''Please use /var/adm/fillup-templates/sysconfig.<packagename>
and call %fillup_and_insserv to install new sysconfig files''',
'good': [
'/etc/sysconfig/cbq',
'/etc/sysconfig/scripts',
'/etc/sysconfig/scripts/*',
'/etc/sysconfig/network',
'/etc/sysconfig/network/*',
'/etc/sysconfig/hardware',
'/etc/sysconfig/hardware/*',
'/etc/sysconfig/isdn',
'/etc/sysconfig/isdn/scripts',
'/etc/sysconfig/isdn/scripts/*',
'/etc/sysconfig/SuSEfirewall2.d',
'/etc/sysconfig/SuSEfirewall2.d/*',
'/etc/sysconfig/uml',
],
'bad': [
'/var/adm/fillup-templates/rc.config.*',
'/etc/sysconfig/*',
'/etc/rc.config.d/*',
],
},
{
'error': 'suse-filelist-forbidden-perl-dir',
'details': '''perl files installed a non-vendor installed path,
which is not allowed in SUSE.''',
'bad': [
'/usr/lib/perl5/site_perl/*',
],
},
{
'error': 'suse-filelist-forbidden-backup-file',
'details': 'backup files (e.g. files ending in ~, .swp or .bak) are not allowed',
'bad': [
'*~',
'*.bak',
'*/.*.swp',
],
'ignorefileif': ghostfile,
},
{
'error': 'suse-filelist-forbidden-devel-in-lib',
'details': 'please move la files, static libs and .so symlinks to /usr/lib(64)',
'bad': [
"/lib/*.la",
"/lib/*.a",
"/lib64/*.la",
"/lib64/*.a",
]
},
{
'error': 'suse-filelist-forbidden-devel-in-lib',
'details': 'please move la files, static libs and .so symlinks to /usr/lib(64)',
'good': [
# exception for pam
"/lib/security/*.so",
"/lib64/security/*.so",
],
'bad': [
"/lib/*.so",
"/lib64/*.so",
],
# some libs without proper soname are packaged directly
'ignorefileif': notsymlink,
},
{
'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': [
"/etc/X11/app-defaults/*",
"/usr/local/man/*/*",
"/var/lib/games",
"/var/lib/games/*",
"/usr/sbin/*/*",
"/sbin/init.d",
"/sbin/init.d/*",
"/bin/*/*",
]
},
{
'error': 'suse-filelist-forbidden-yast2',
'msg': '%(file)s is not allowed anymore in YaST2',
'bad': [
'/usr/lib/YaST2/*.ycp',
'/usr/lib/YaST2/*.y2cc',
'/usr/lib/YaST2/*.*.scr',
],
},
{
'error': 'suse-filelist-forbidden-srv',
'details': """Please use /srv for ftp and http data""",
'bad': [
'/usr/local/ftp',
'/usr/local/http',
],
},
{
'error': 'suse-filelist-forbidden-games',
'details': """static data has to be in /usr/share/games, variable in /var/games""",
'bad': [
'/usr/games/bin',
'/usr/games/lib',
'/usr/games/*/*',
],
},
{
'error': 'suse-filelist-forbidden-noarch',
'msg': '%(file)s is not allowed in a noarch package',
'bad': [
'/lib64',
'/lib64/*',
'/usr/lib64',
'/usr/lib64/*',
'/usr/X11R6/lib64',
'/usr/X11R6/lib64/*',
'/opt/gnome/lib64',
'/opt/gnome/lib64/*',
'/opt/kde3/lib64',
'/opt/kde3/lib64/*',
'/usr/lib/pkgconfig/*',
'/usr/lib/perl5/vendor_perl/5.*/*-linux-*/*',
],
'ignorepkgif': notnoarch,
},
{
'error': 'suse-filelist-forbidden-debuginfo',
'msg': '%(file)s may only be packaged in the -debuginfo subpackage',
'bad': [
'/usr/lib/debug/*',
],
'ignorepkgif': isdebuginfo,
},
{
'error': 'suse-filelist-forbidden-locale',
'details': """Please use nb or nb_NO (and nn for nynorsk)"""
"""see https://bugzilla.novell.com/show_bug.cgi?id=42748""",
'bad': [
'/opt/gnome/share/locale/no',
'/opt/gnome/share/locale/no/*',
'/opt/kde3/share/locale/no',
'/opt/kde3/share/locale/no/*',
'/usr/share/locale/no',
'/usr/share/locale/no/*',
'/usr/share/vim/*/lang/no',
'/usr/share/vim/*/lang/no/*',
],
},
{
'error': 'suse-filelist-forbidden-xorg',
'details': """Please use the updated paths for Xorg 7.1 and above""",
'bad': [
'/usr/X11R6/*',
],
'ignorepkgif': isfilesystem,
},
{
'error': 'suse-filelist-forbidden-suseconfig',
'details': """Adding new SuSEconfig scripts is not accepted for openSUSE 10.2 and newer""",
'good': [
'/sbin/conf.d/SuSEconfig.cjk-latex',
'/sbin/conf.d/SuSEconfig.fonts',
'/sbin/conf.d/SuSEconfig.ghostscript-cjk',
'/sbin/conf.d/SuSEconfig.glib2',
'/sbin/conf.d/SuSEconfig.icu',
'/sbin/conf.d/SuSEconfig.isdn',
'/sbin/conf.d/SuSEconfig.ispell',
'/sbin/conf.d/SuSEconfig.kde',
'/sbin/conf.d/SuSEconfig.kdm3',
'/sbin/conf.d/SuSEconfig.mailman',
'/sbin/conf.d/SuSEconfig.news',
'/sbin/conf.d/SuSEconfig.pbs',
'/sbin/conf.d/SuSEconfig.perl',
'/sbin/conf.d/SuSEconfig.permissions',
'/sbin/conf.d/SuSEconfig.postfix',
'/sbin/conf.d/SuSEconfig.prelink',
'/sbin/conf.d/SuSEconfig.scim',
'/sbin/conf.d/SuSEconfig.scpm',
'/sbin/conf.d/SuSEconfig.sendmail',
'/sbin/conf.d/SuSEconfig.susehelp',
'/sbin/conf.d/SuSEconfig.tetex',
'/sbin/conf.d/SuSEconfig.texlive',
'/sbin/conf.d/SuSEconfig.words',
'/sbin/conf.d/SuSEconfig.xjdic',
],
'bad': [
'/sbin/conf.d/*',
],
},
{
'error': 'suse-filelist-forbidden-opt',
'details': """/opt may not be used by a distribution. It is reserved for 3rd party packagers""",
},
]
class FilelistCheck(AbstractCheck.AbstractCheck):
def __init__(self):
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'])):
pattern = check['good'][i]
if '*' in pattern:
r = fnmatch.translate(pattern)
check['good'][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
files = pkg.files()
if not files:
printWarning(pkg, 'suse-filelist-empty', 'packages without any files are discouraged in SUSE')
return
for check in _checks:
if 'ignorepkgif' in check:
if check['ignorepkgif'](pkg):
continue
if 'msg' in check:
msg = check['msg']
else:
msg = _defaultmsg
if 'error' in check:
error = check['error']
else:
error = _defaulterror
if 'good' in check or 'bad' in check:
for f in files.keys():
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:
printError(pkg, error, msg % { 'file':f } )
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, pkgfile in files.items():
type = (pkgfile.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
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()
if Config.info:
for check in _checks:
if not 'details' in check:
continue
if not 'error' in check:
continue
addDetails('suse-filelist-forbidden', """
Your package installs files or directories in a location that have
previously been blacklisted. Please have a look at the particular
file and see if the SUSE Packaging Guidelines propose a better place
on where to install the file or not install it at all.""")
addDetails(check['error'], check['details'])

View File

@ -1,185 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : CheckGNOMEMacros.py
# Package : rpmlint
# Author : Vincent Untz
# Purpose : Check for GNOME related packaging errors
#############################################################################
import re
import string
import rpm
from Filter import *
import AbstractCheck
import Config
## FIXME
# Maybe detect packages installing icons in other themes than hicolor and not
# updating the icon cache for those themes?
_gnome_post_postun_checks = [
('glib2-gsettings-schema',
re.compile('^/usr/share/glib-2.0/schemas/.+\.gschema.xml$'),
'glib2-tools',
re.compile('^[^#]*glib-compile-schemas', re.MULTILINE),
True),
('glib2-gio-module',
re.compile('^/usr/lib(?:64)?/gio/modules/'),
'glib2-tools',
re.compile('^[^#]*gio-querymodules', re.MULTILINE),
True),
('gdk-pixbuf-loader',
re.compile('^/usr/lib(?:64)?/gdk-pixbuf-2.0/[^/]+/loaders/'),
'gdk-pixbuf-query-loaders',
re.compile('^[^#]*gdk-pixbuf-query-loaders', re.MULTILINE),
True),
('gtk2-immodule',
re.compile('^/usr/lib(?:64)?/gtk-2.0/[^/]+/immodules/'),
'gtk2',
re.compile('^[^#]*gtk-query-immodules-2.0', re.MULTILINE),
True),
('gtk3-immodule',
re.compile('^/usr/lib(?:64)?/gtk-3.0/[^/]+/immodules/'),
'gtk3-tools',
re.compile('^[^#]*gtk-query-immodules-3.0', re.MULTILINE),
True),
# Not fatal since it would make too many things fail
('hicolor-icon-cache',
re.compile('^/usr/share/icons/hicolor/'),
None,
re.compile('^[^#]*gtk-update-icon-cache', re.MULTILINE),
False),
('mime-database',
re.compile('^/usr/share/mime/packages/.+\.xml$'),
None,
re.compile('^[^#]*update-mime-database', re.MULTILINE),
True),
# Not fatal since it would make too many things fail
('desktop-database',
re.compile('^/usr/share/applications/.+\.desktop$'),
None,
re.compile('^[^#]*update-desktop-database', re.MULTILINE),
False)
]
_gnome_gconf_filename_re = re.compile('^/usr/share/GConf/schemas/.+\.schemas$')
_gnome_gconf_sciptlet_re = re.compile('^[^#]*gconftool-2', re.MULTILINE)
class GNOMECheck(AbstractCheck.AbstractCheck):
def __init__(self):
AbstractCheck.AbstractCheck.__init__(self, "CheckGNOMEMacros")
def check(self, pkg):
if pkg.isSource():
return
ghosts = pkg.ghostFiles()
pkg_requires = set(map(lambda x: string.split(x[0],'(')[0], pkg.requires()))
postin = pkg[rpm.RPMTAG_POSTIN] or pkg[rpm.RPMTAG_POSTINPROG]
postun = pkg[rpm.RPMTAG_POSTUN] or pkg[rpm.RPMTAG_POSTUNPROG]
posttrans = pkg[rpm.RPMTAG_POSTTRANS] or pkg[rpm.RPMTAG_POSTTRANSPROG]
for filename in (x for x in pkg.files() if x not in ghosts):
for (name, file_re, required, post_re, fatal) in _gnome_post_postun_checks:
if fatal:
gnomePrint = printError
else:
gnomePrint = printWarning
if file_re.search(filename):
if required and required not in pkg_requires:
gnomePrint(pkg, 'suse-' + name + '-missing-requires', filename)
if not postin or not post_re.search(postin):
gnomePrint(pkg, 'suse-' + name + '-missing-postin', filename)
if not postun or not post_re.search(postun):
gnomePrint(pkg, 'suse-' + name + '-missing-postun', filename)
if _gnome_gconf_filename_re.search(filename):
if not ((postin and _gnome_gconf_sciptlet_re.search(postin)) or
(posttrans and _gnome_gconf_sciptlet_re.search(posttrans))):
printError(pkg, 'suse-gconf-schema-missing-scriptlets', filename)
check=GNOMECheck()
if Config.info:
addDetails(
'suse-glib2-gsettings-schema-missing-requires',
'''A GSettings schema is in your package, but there is no dependency for the tool to recompile the schema database. Use %glib2_gsettings_schema_requires.''',
'suse-glib2-gsettings-schema-missing-postin',
'''A GSettings schema is in your package, but the schema database is not recompiled in the %post scriptlet. Use %glib2_gsettings_schema_post.''',
'suse-glib2-gsettings-schema-missing-postun',
'''A GSettings schema is in your package, but the schema database is not recompiled in the %postun scriptlet. Use %glib2_gsettings_schema_postun.''',
'suse-glib2-gio-module-missing-requires',
'''A GIO module is in your package, but there is no dependency for the tool to rebuild the GIO module cache. Use %glib2_gio_module_requires.''',
'suse-glib2-gio-module-missing-postin',
'''A GIO module is in your package, but the GIO module cache is not rebuilt in the %post scriptlet. Use %glib2_gio_module_post.''',
'suse-glib2-gio-module-missing-postun',
'''A GIO module is in your package, but the GIO module cache is not rebuilt in the %postun scriptlet. Use %glib2_gio_module_postun.''',
'suse-gdk-pixbuf-loader-missing-requires',
'''A gdk-pixbuf loader is in your package, but there is no dependency for the tool to rebuild the gdk-pixbuf loader cache. Use %gdk_pixbuf_loader_requires.''',
'suse-gdk-pixbuf-loader-missing-postin',
'''A gdk-pixbuf loader is in your package, but the gdk-pixbuf loader cache is not rebuilt in the %post scriptlet. Use %gdk_pixbuf_loader_post.''',
'suse-gdk-pixbuf-loader-missing-postun',
'''A gdk-pixbuf loader is in your package, but the gdk-pixbuf loader cache is not rebuilt in the %postun scriptlet. Use %gdk_pixbuf_loader_postun.''',
'suse-gtk2-immodule-missing-requires',
'''A GTK+ 2 IM module is in your package, but there is no dependency for the tool to rebuild the GTK+ 2 IM module cache. Use %gtk2_immodule_requires.''',
'suse-gtk2-immodule-missing-postin',
'''A GTK+ 2 IM module is in your package, but the GTK+ 2 IM module cache is not rebuilt in the %post scriptlet. Use %gtk2_immodule_post.''',
'suse-gtk2-immodule-missing-postun',
'''A GTK+ 2 IM module is in your package, but the GTK+ 2 IM module cache is not rebuilt in the %postun scriptlet. Use %gtk2_immodule_postun.''',
'suse-gtk3-immodule-missing-requires',
'''A GTK+ 3 IM module is in your package, but there is no dependency for the tool to rebuild the GTK+ 3 IM module cache. Use %gtk3_immodule_requires.''',
'suse-gtk3-immodule-missing-postin',
'''A GTK+ 3 IM module is in your package, but the GTK+ 3 IM module cache is not rebuilt in the %post scriptlet. Use %gtk3_immodule_post.''',
'suse-gtk3-immodule-missing-postun',
'''A GTK+ 3 IM module is in your package, but the GTK+ 3 IM module cache is not rebuilt in the %postun scriptlet. Use %gtk3_immodule_postun.''',
'suse-hicolor-icon-cache-missing-postin',
'''An icon for the hicolor theme is in your package, but the hicolor icon cache is not rebuilt in the %post scriptlet. Use %icon_theme_cache_post.''',
'suse-hicolor-icon-cache-missing-postun',
'''An icon for the hicolor theme is in your package, but the hicolor icon cache is not rebuilt in the %postun scriptlet. Use %icon_theme_cache_postun.''',
'suse-mime-database-missing-postin',
'''A MIME definition is in your package, but the MIME database is not rebuilt in the %post scriptlet. Use %mime_database_post.''',
'suse-mime-database-missing-postun',
'''A MIME definition is in your package, but the MIME database is not rebuilt in the %postun scriptlet. Use %mime_database_postun.''',
'suse-desktop-database-missing-postin',
'''A desktop file is in your package, but the desktop database is not rebuilt in the %post scriptlet. Use %desktop_database_post.''',
'suse-desktop-database-missing-postun',
'''A desktop file is in your package, but the desktop database is not rebuilt in the %postun scriptlet. Use %desktop_database_postun.''',
'suse-gconf-schema-missing-scriptlets',
'''A GConf schema is in your package, but the GConf configuration is not updated by scriptlets. Please use the gconf RPM macros.'''
)

View File

@ -1,51 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : CheckIconSizes.py
# Package : rpmlint
# Author : Dirk Mueller
# Purpose : Check for common scaling errors in icons
#############################################################################
from Filter import *
import AbstractCheck
import rpm
import re
import commands
import stat
import Config
import os
import string
class IconSizesCheck(AbstractCheck.AbstractCheck):
def __init__(self):
AbstractCheck.AbstractCheck.__init__(self, "CheckIconSizes")
self.file_size_regex = re.compile('/icons/[^/]+/(\d+)x(\d+)/')
self.info_size_regex = re.compile('(\d+) x (\d+)')
def check(self, pkg):
if pkg.isSource():
return
for fname, pkgfile in pkg.files().items():
res = self.file_size_regex.search(fname)
if res:
sizes = (res.group(1), res.group(2))
res = self.info_size_regex.search(pkgfile.magic)
if res:
actualsizes = (res.group(1), res.group(2))
if abs(int(sizes[0])-int(actualsizes[0])) > 2 or \
abs(int(sizes[1])-int(actualsizes[1])) > 2:
printError(pkg,"wrong-icon-size", fname, "expected:",
"x".join(sizes), "actual:", "x".join(actualsizes))
check=IconSizesCheck()
if Config.info:
addDetails(
'wrong-icon-size',
"""Your icon file is installed in a fixed-size directory, but has a largely incorrect size.
Some desktop environments (e.g. GNOME) display them incorrectly."""
)

View File

@ -1,114 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : CheckInitScripts.py
# Package : rpmlint
# Author : Dirk Mueller
# Purpose : Check for common mistakes in init scripts
#############################################################################
from Filter import *
import AbstractCheck
import rpm
import re
import commands
import stat
import Config
import os
import string
insserv_regex=re.compile('^\s*sbin/insserv', re.MULTILINE)
preun_regex=re.compile('^\s*/etc/init.d/\S+ stop', re.MULTILINE)
class CheckInitScripts(AbstractCheck.AbstractFilesCheck):
def __init__(self):
AbstractCheck.AbstractFilesCheck.__init__(self, "CheckInitScripts", "/etc/init.d/.*")
def check(self, pkg):
if pkg.isSource():
return
files = pkg.files()
bins_list = filter(lambda f: (f.startswith("/usr/bin") \
or f.startswith("/usr/sbin")) and stat.S_ISREG(files[f].mode), files.keys())
for f, pkgfile in files.items():
if f in pkg.ghostFiles() or not stat.S_ISREG(pkgfile.mode) or not f.startswith("/etc/init.d/"):
continue
boot_script = f.startswith('/etc/init.d/boot.')
input_f = file(pkg.dirName() + '/' + f, "r")
found_remote_fs = False
for l in input_f:
if l.startswith('# Required-Start') or l.startswith('# Should-Start'):
for dep in l.split()[2:]:
if dep.startswith('$') and dep not in ('$local_fs',
'$named',
'$network',
'$portmap',
'$remote_fs',
'$syslog',
'$time',
'$null',
'$ALL'):
printError(pkg, "init-script-undefined-dependency", f, dep)
if dep in ('portmap', 'syslog', 'named', 'network', 'ntp', 'ntpd', 'xntpd'):
printWarning(pkg, "init-script-non-var-dependency", f, dep)
if dep in ('$remote_fs'):
found_remote_fs = True
if l.startswith('# X-UnitedLinux-Should'):
printWarning(pkg, "obsolete-init-keyword", f, l)
if l.startswith('# Default-Start'):
for dep in l.split()[2:]:
if boot_script and dep not in ('B', 'S'):
printError(pkg, "init-script-boot_d", f)
if not boot_script and dep in ('B'):
printError(pkg, "init-script-not-boot_d", f, dep)
if dep == '4':
printError(pkg, "init-script-runlevel-4", f)
if not found_remote_fs and bins_list:
printWarning(pkg, "non-remote_fs-dependency", f)
check=CheckInitScripts()
if Config.info:
addDetails(
'init-script-undefined-dependency',
"""Your package contains a /etc/init.d script that specifies a
dependency that is not listed in /etc/insserv.conf. Check for
typos.""",
'init-script-non-var-dependency',
"""Your package contains a /etc/init.d script that specifies
a hardcoded dependency that likely should be a variable dependency.
For example portmap should actually be $portmap, and similar.""",
'obsolete-init-keyword',
"""Your package contains a /etc/init.d script that specifies
an obsolete keyword, like X-UnitedLinux-Should-Start. Consider
using the LSB equivalent Should-Start instead.""",
'init-script-boot_d',
"""The init script has a "boot." prefix but actually lacks 'B' in
'Default-Start'. Either rename the script or add
'B' to 'Default-Start'""",
'init-script-not-boot_d',
"""The init script specifies that it should be run in level 'B' but
doesn't have a "boot." prefix. Either rename the script or remove
the 'B' from 'Default-Start'""",
'non-remote_fs-dependency',
"""Your package contains a /etc/init.d script that does not specify
$remote_fs as a start dependency, but the package also contains
files packaged in /usr. Make sure that your start script does not
call any of them, or add the missing $remote_fs dependency.""",
'init-script-runlevel-4',
"""The init script refers to runlevel 4 which is admin defined. No
distribution script must use it. Remove '4' from 'Default-Start'.""",
)

View File

@ -1,119 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : CheckKDE4Deps.py
# Package : rpmlint
# Author : Dirk Mueller
# Purpose : Check for KDE4 related packaging errors
#############################################################################
from Filter import *
import AbstractCheck
import rpm
import re
import os
import string
import commands
import Config
import Pkg
import stat
_kde4_pimlibs=(
"libgpgme++-pth.so.1.1.0",
"libgpgme++-pthread.so.1.1.0",
"libgpgme++.so.1.1.0",
"libkabc.so.4",
"libkabc_file_core.so.4",
"libkblog.so.4",
"libkcal.so.4",
"libkimap.so.4",
"libkldap.so.4",
"libkmime.so.4",
"libkpimidentities.so.4",
"libkpimutils.so.4",
"libkresources.so.4",
"libktnef.so.4",
"libkxmlrpcclient.so.4",
"libmailtransport.so.4",
"libqgpgme.so.1.0.0",
"libsyndication.so.4"
)
_kde4_libkdepim4 = (
"libkdepim.so.4",
"libkontactinterfaces.so.4",
"libkleopatraclientcore.so.0.2.0",
"libkleopatraclientgui.so.0.2.0",
)
_kde4_libakonadi4 = (
"libakonadi-kde.so.4",
"libakonadi-kabc.so.4",
"libakonadi-kcal.so.4",
"libakonadi-kmime.so.4",
"libakonadiprotocolinternals.so.1",
)
class KDE4Check(AbstractCheck.AbstractCheck):
def __init__(self):
AbstractCheck.AbstractCheck.__init__(self, "CheckKDE4Deps")
def check(self, pkg):
if pkg.isSource():
return
pkg_requires = set(map(lambda x: string.split(x[0],'(')[0], pkg.requires()))
if not "libkdecore.so.5" in pkg_requires:
return
if not pkg.name.startswith("lib"):
if not "kdebase4-runtime" in pkg_requires:
printError(pkg,"suse-kde4-missing-runtime-dependency")
kdepimlibs4_dep=False
for r in pkg_requires:
if r in _kde4_pimlibs:
kdepimlibs4_dep=True
break
libkdepim4_dep=False
for r in pkg_requires:
if r in _kde4_libkdepim4:
libkdepim4_dep =True
break
libakonadi4_dep=False
for r in pkg_requires:
if r in _kde4_libakonadi4:
libakonadi4_dep =True
break
if not pkg.name.startswith("lib"):
if "kdepimlibs4" in pkg_requires and not kdepimlibs4_dep:
printError(pkg,"suse-kde4-excessive-dependency", "%kde4_pimlibs_requires")
if not "kdepimlibs4" in pkg_requires and kdepimlibs4_dep:
printError(pkg,"suse-kde4-missing-dependency", "%kde4_pimlibs_requires")
if "libkdepim4" in pkg_requires and not libkdepim4_dep:
printError(pkg,"suse-kde4-excessive-dependency", "libkdepim4")
if not "libkdepim4" in pkg_requires and libkdepim4_dep:
printError(pkg,"suse-kde4-missing-dependency", "libkdepim4")
if "akonadi-runtime" in pkg_requires and not libakonadi4_dep:
printError(pkg,"suse-kde4-excessive-dependency", "%kde4_akonadi_requires")
if not "akonadi-runtime" in pkg_requires and libakonadi4_dep:
printError(pkg,"suse-kde4-missing-dependency", "%kde4_akonadi_requires")
check=KDE4Check()
if Config.info:
addDetails('suse-kde4-missing-runtime-dependency',
"""Please add %kde4_runtime_requires to the (sub-)package to have the right versioned
dependency on the KDE version it was built against.""",
'suse-kde4-missing-dependency',
"""The package builds against a KDE4 related library, but it is missing the runtime
depencency macro. please add the suggested macro to the (sub-)package listing in
the spec file."""
)

View File

@ -1,97 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : CheckLogrotate.py
# Package : rpmlint
# Author : Ludwig Nussel
# Purpose : Check for insecure logrotate directories
#############################################################################
from Filter import *
import AbstractCheck
import re
import os
import string
class LogrotateCheck(AbstractCheck.AbstractCheck):
def __init__(self):
AbstractCheck.AbstractCheck.__init__(self, "CheckLogrotate")
def check(self, pkg):
if pkg.isSource():
return
files = pkg.files()
dirs = {}
for f, pkgfile in files.items():
if f in pkg.ghostFiles():
continue
if f.startswith("/etc/logrotate.d/"):
try:
for n, o in self.parselogrotateconf(pkg.dirName(), f).items():
if n in dirs and dirs[n] != o:
printError(pkg, "logrotate-duplicate", n)
else:
dirs[n] = o
except Exception, x:
printError(pkg, 'rpmlint-exception', "%(file)s raised an exception: %(x)s" % {'file':f, 'x':x})
for d in sorted(dirs.keys()):
if not d in files:
if d != '/var/log':
printError(pkg, 'suse-logrotate-log-dir-not-packaged', d)
continue
mode = files[d].mode&0777
if files[d].user != 'root' and (dirs[d] is None or dirs[d][0] != files[d].user):
printError(pkg, 'suse-logrotate-user-writable-log-dir', \
"%s %s:%s %04o"%(d, files[d].user, files[d].group, mode))
elif files[d].group != 'root' and mode&020 and (dirs[d] is None or dirs[d][1] != files[d].group):
printError(pkg, 'suse-logrotate-user-writable-log-dir', \
"%s %s:%s %04o"%(d, files[d].user, files[d].group, mode))
# extremely primitive logrotate parser
def parselogrotateconf(self, root, f):
dirs = {}
fd = open('/'.join((root, f)))
currentdirs = []
for line in fd.readlines():
line = line.strip()
if line.startswith('#'):
continue
if not currentdirs:
if line.endswith('{'):
insection = True
for logfile in line.split(' '):
logfile = logfile.strip()
if len(logfile) == 0 or logfile == '{':
continue
dn = os.path.dirname(logfile)
if not dn in dirs:
currentdirs.append(dn)
dirs[dn] = None
else:
if line.endswith('}'):
currentdirs = []
elif line.startswith("su "):
a = line.split(" ")
for dn in currentdirs:
dirs[dn] = (a[1], a[2])
return dirs
check=LogrotateCheck()
if Config.info:
addDetails(
'suse-logrotate-duplicate',
"""There are dupliated logrotate entries with different settings for
the specified file""",
'suse-logrotate-user-writable-log-dir',
"""The log directory is writable by unprivileged users. Please fix
the permissions so only root can write there or add the 'su' option
to your logrotate config""",
'suse-logrotate-log-dir-not-packaged',
"""Please add the specified directory to the file list to be able to
check permissions"""
)

View File

@ -1,49 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : CheckPAMModules.py
# Package : rpmlint
# Author : Ludwig Nussel
# Purpose : Check for pam modules that are not authorized by the security team
#############################################################################
from Filter import *
import AbstractCheck
import re
import os
import string
PAM_WHITELIST = Config.getOption('PAMModules.WhiteList', ()) # set of file names
pam_module_re = re.compile('^(?:/usr)?/lib(?:64)?/security/([^/]+\.so)$')
class PAMModulesCheck(AbstractCheck.AbstractCheck):
def __init__(self):
AbstractCheck.AbstractCheck.__init__(self, "CheckPAMModules")
def check(self, pkg):
global PAM_WHITELIST
if pkg.isSource():
return
files = pkg.files()
for f in files:
if f in pkg.ghostFiles():
continue
m = pam_module_re.match(f)
if m:
bn = m.groups()[0]
if not bn in PAM_WHITELIST:
printError(pkg, "suse-pam-unauthorized-module", bn)
check=PAMModulesCheck()
if Config.info:
addDetails(
'suse-pam-unauthorized-module',
"""The package installs a PAM module. If the package
is intended for inclusion in any SUSE product please open a bug
report to request review of the service by the security team.""",
)

View File

@ -1,63 +0,0 @@
# vim:sw=4:et
#---------------------------------------------------------------
# Module : rpmlint
# File : CheckPkgConfig
# Author : Stephan Kulow, Dirk Mueller
# Purpose : Check for errors in Pkgconfig files
#---------------------------------------------------------------
from Filter import *
import AbstractCheck
import rpm
import re
import commands
import Config
import os
import stat
class PkgConfigCheck(AbstractCheck.AbstractFilesCheck):
def __init__(self):
AbstractCheck.AbstractFilesCheck.__init__(self, "CheckPkgConfig", ".*/pkgconfig/.*\.pc$")
# currently causes too many failures (2008-03-05)
#self.suspicious_dir=re.compile('(?:/usr/src/\w+/BUILD|/var/tmp|/tmp|/home|\@\w{1,50}\@)')
self.suspicious_dir=re.compile('(?:/usr/src/\w+/BUILD|/var/tmp|/tmp|/home)')
def check(self, pkg):
# check for references to /lib when in lib64 mode
if pkg.arch in ('x86_64', 'ppc64', 's390x'):
self.wronglib_dir=re.compile('-L/usr/lib\\b')
else:
self.wronglib_dir=re.compile('-L/usr/lib64\\b')
AbstractCheck.AbstractFilesCheck.check(self, pkg)
def check_file(self, pkg, filename):
if pkg.isSource() or not stat.S_ISREG(pkg.files()[filename].mode):
return
if pkg.grep(self.suspicious_dir, filename):
printError(pkg, "invalid-pkgconfig-file", filename)
pc_file=file(pkg.dirName() + "/" + filename, "r")
for l in pc_file:
if l.startswith('Libs:') and self.wronglib_dir.search(l):
printError(pkg, 'pkgconfig-invalid-libs-dir', filename, l)
check=PkgConfigCheck()
if Config.info:
addDetails(
'invalid-pkgconfig-file',
'''Your .pc file appears to be invalid. Possible causes are:
- it contains traces of $RPM_BUILD_ROOT or $RPM_BUILD_DIR.
- it contains unreplaced macros (@have_foo@)
- it references invalid paths (e.g. /home or /tmp)
Please double-check and report false positives.
''',
'pkgconfig-invalid-libs-dir',
''' Your .pc file contains -L/usr/lib or -L/lib and is built for a lib64 target,
or contains references to -L/usr/lib64 or -L/lib64 and is built for a lib target.
Please remove the wrong library paths from the pc file.'''
)

View File

@ -1,153 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : CheckPolkitPrivs.py
# Package : rpmlint
# Author : Ludwig Nussel
# Purpose : Check for /etc/polkit-default-privs violations
#############################################################################
from Filter import *
import AbstractCheck
import Config
import re
import os
from xml.dom.minidom import parse
POLKIT_PRIVS_WHITELIST = Config.getOption('PolkitPrivsWhiteList', ()) # set of file names
POLKIT_PRIVS_FILES = Config.getOption('PolkitPrivsFiles', [ "/etc/polkit-default-privs.standard" ])
class PolkitCheck(AbstractCheck.AbstractCheck):
def __init__(self):
AbstractCheck.AbstractCheck.__init__(self, "CheckPolkitPrivs")
self.privs = {}
for filename in POLKIT_PRIVS_FILES:
if os.path.exists(filename):
self._parsefile(filename)
def _parsefile(self,filename):
for line in file(filename):
line = line.split('#')[0].split('\n')[0]
if len(line):
line = re.split(r'\s+', line)
priv = line[0]
value = line[1]
self.privs[priv] = value
def check(self, pkg):
if pkg.isSource():
return
files = pkg.files()
permfiles = {}
# first pass, find additional files
for f in files:
if f in pkg.ghostFiles():
continue
if f.startswith("/etc/polkit-default-privs.d/"):
bn = f[28:]
if not bn in POLKIT_PRIVS_WHITELIST:
printError(pkg, "polkit-unauthorized-file", f)
if bn.endswith(".restrictive") or bn.endswith(".standard") or bn.endswith(".relaxed"):
bn = bn.split('.')[0]
if not bn in permfiles:
permfiles[bn] = 1
for f in permfiles:
f = pkg.dirName() + "/etc/polkit-default-privs.d/" + f
if os.path.exists(f+".restrictive"):
self._parsefile(f + ".restrictive")
elif os.path.exists(f+".standard"):
self._parsefile(f + ".standard")
elif os.path.exists(f+".relaxed"):
self._parsefile(f + ".relaxed")
else:
self._parsefile(f)
for f in files:
if f in pkg.ghostFiles():
continue
# catch xml exceptions
try:
if f.startswith("/usr/share/PolicyKit/policy/")\
or f.startswith("/usr/share/polkit-1/actions/"):
xml = parse(pkg.dirName() + f)
for a in xml.getElementsByTagName("action"):
action = a.getAttribute('id')
if not action in self.privs:
iserr = 0
foundno = 0
foundundef = 0
settings = {}
try:
defaults = a.getElementsByTagName("defaults")[0]
for i in defaults.childNodes:
if not i.nodeType == i.ELEMENT_NODE:
continue
if i.nodeName in ('allow_any', 'allow_inactive', 'allow_active'):
settings[i.nodeName] = i.firstChild.data
except:
iserr = 1
for i in ('allow_any', 'allow_inactive', 'allow_active'):
if not i in settings:
foundundef = 1
settings[i] = '??'
elif settings[i].find("auth_admin") != 0:
if settings[i] == 'no':
foundno = 1
else:
iserr = 1
if iserr:
printError(pkg, 'polkit-unauthorized-privilege', '%s (%s:%s:%s)' % (action, \
settings['allow_any'], settings['allow_inactive'], settings['allow_active']))
else:
printInfo(pkg, 'polkit-untracked-privilege', '%s (%s:%s:%s)' % (action, \
settings['allow_any'], settings['allow_inactive'], settings['allow_active']))
if foundno or foundundef:
printInfo(pkg,
'polkit-cant-acquire-privilege', '%s (%s:%s:%s)' % (action, \
settings['allow_any'], settings['allow_inactive'], settings['allow_active']))
except Exception, x:
printError(pkg, 'rpmlint-exception', "%(file)s raised an exception: %(x)s" % {'file':f, 'x':x})
continue
check=PolkitCheck()
if Config.info:
addDetails(
'polkit-unauthorized-file',
"""If the package is intended for inclusion in any SUSE product
please open a bug report to request review of the package by the
security team""",
'polkit-unauthorized-privilege',
"""The package allows unprivileged users to carry out privileged
operations without authentication. This could cause security
problems if not done carefully. If the package is intended for
inclusion in any SUSE product please open a bug report to request
review of the package by the security team""",
'polkit-untracked-privilege',
"""The privilege is not listed in /etc/polkit-default-privs.*
which makes it harder for admins to find. If the package is intended
for inclusion in any SUSE product please open a bug report to
request review of the package by the security team""",
'polkit-cant-acquire-privilege',
"""Usability can be improved by allowing users to acquire privileges
via authentication. Use e.g. 'auth_admin' instead of 'no' and make
sure to define 'allow_any'. This is an issue only if the privilege
is not listed in /etc/polkit-default-privs.*""")

View File

@ -1,271 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : CheckSUIDPermissions.py
# Package : rpmlint
# Author : Ludwig Nussel
# Purpose : Check for /etc/permissions violations
#############################################################################
from Filter import *
import AbstractCheck
import re
import os
import string
import rpm
_permissions_d_whitelist = (
"lprng",
"lprng.paranoid",
"mail-server",
"mail-server.paranoid",
"postfix",
"postfix.paranoid",
"sendmail",
"sendmail.paranoid",
"squid",
"texlive",
"texlive.texlive",
)
class SUIDCheck(AbstractCheck.AbstractCheck):
def __init__(self):
AbstractCheck.AbstractCheck.__init__(self, "CheckSUIDPermissions")
self.perms = {}
files = [ "/etc/permissions", "/etc/permissions.secure" ]
for file in files:
if os.path.exists(file):
self._parsefile(file)
def _parsefile(self,file):
lnr = 0
lastfn = None
for line in open(file):
lnr+=1
line = line.split('#')[0].split('\n')[0]
line = line.lstrip()
if not len(line):
continue
if line.startswith("+capabilities "):
line = line[len("+capabilities "):]
if lastfn:
self.perms[lastfn]['fscaps'] = line
continue
line = re.split(r'\s+', line)
if len(line) == 3:
fn = line[0]
owner = line[1].replace('.', ':')
mode = line[2]
self.perms[fn] = { "owner" : owner, "mode" : int(mode,8)&07777}
# for permissions that don't change and therefore
# don't need special handling
if file == '/etc/permissions':
self.perms[fn]['static'] = True
else:
print >>sys.stderr, "invalid line %d " % lnr
def check(self, pkg):
global _permissions_d_whitelist
if pkg.isSource():
return
files = pkg.files()
permfiles = {}
# first pass, find and parse permissions.d files
for f in files.keys():
if f in pkg.ghostFiles():
continue
if f.startswith("/etc/permissions.d/"):
bn = f[19:]
if not bn in _permissions_d_whitelist:
printError(pkg, "permissions-unauthorized-file", f)
bn = bn.split('.')[0]
if not bn in permfiles:
permfiles[bn] = 1
for f in permfiles:
f = pkg.dirName() + "/etc/permissions.d/" + f
if os.path.exists(f+".secure"):
self._parsefile(f + ".secure")
else:
self._parsefile(f)
need_set_permissions = False
found_suseconfig = False
# second pass, find permissions violations
for f, pkgfile in files.items():
if pkgfile.filecaps:
printError(pkg, 'permissions-fscaps', '%(file)s has fscaps "%(caps)s"' % \
{ 'file':f, 'caps':pkgfile.filecaps})
mode = pkgfile.mode
owner = pkgfile.user+':'+pkgfile.group
# S_IFSOCK 014 socket
# S_IFLNK 012 symbolic link
# S_IFREG 010 regular file
# S_IFBLK 006 block device
# S_IFDIR 004 directory
# S_IFCHR 002 character device
# S_IFIFO 001 FIFO
type = (mode>>12)&017;
mode &= 07777
need_verifyscript = False
if f in self.perms or (type == 04 and f+"/" in self.perms):
if type == 012:
printWarning(pkg, "permissions-symlink", f)
continue
need_verifyscript = True
m = 0
o = "invalid"
if type == 04:
if f in self.perms:
printWarning(pkg, 'permissions-dir-without-slash', f)
else:
f += '/'
if type == 010 and mode&0111:
# pie binaries have 'shared object' here
if 'ELF' in pkgfile.magic and not 'shared object' in pkgfile.magic:
printError(pkg, 'non-position-independent-executable', f)
m = self.perms[f]['mode']
o = self.perms[f]['owner']
if mode != m:
printError(pkg, 'permissions-incorrect', '%(file)s has mode 0%(mode)o but should be 0%(m)o' % \
{ 'file':f, 'mode':mode, 'm':m })
if owner != o:
printError(pkg, 'permissions-incorrect-owner', '%(file)s belongs to %(owner)s but should be %(o)s' % \
{ 'file':f, 'owner':owner, 'o':o })
elif type != 012:
if f+'/' in self.perms:
printWarning(pkg, 'permissions-file-as-dir', f+' is a file but listed as directory')
if mode&06000:
need_verifyscript = True
msg = '%(file)s is packaged with setuid/setgid bits (0%(mode)o)' % { 'file':f, 'mode':mode }
if type != 04:
printError(pkg, 'permissions-file-setuid-bit', msg)
else:
printWarning(pkg, 'permissions-directory-setuid-bit', msg)
if type == 010:
if not 'shared object' in pkgfile.magic:
printError(pkg, 'non-position-independent-executable', f)
if mode&02:
need_verifyscript = True
printError(pkg, 'permissions-world-writable', \
'%(file)s is packaged with world writable permissions (0%(mode)o)' % \
{ 'file':f, 'mode':mode })
script = pkg[rpm.RPMTAG_POSTIN] or pkg.scriptprog(pkg[rpm.RPMTAG_POSTINPROG])
found = False
if script:
for line in script.split("\n"):
if "chkstat -n" in line and f in line:
found = True
break
if "SuSEconfig --module permissions" in line:
found = True
found_suseconfig = True
break
if need_verifyscript and \
(not f in self.perms or not 'static' in self.perms[f]):
if not script or not found:
printError(pkg, 'permissions-missing-postin', \
"missing %%set_permissions %s in %%post" % f)
need_set_permissions = True
script = pkg[rpm.RPMTAG_VERIFYSCRIPT] or pkg[rpm.RPMTAG_VERIFYSCRIPTPROG]
found = False
if script:
for line in script.split("\n"):
if "/chkstat" in line and f in line:
found = True
break
if not script or not found:
printWarning(pkg, 'permissions-missing-verifyscript', \
"missing %%verify_permissions -e %s" % f)
if need_set_permissions:
if not 'permissions' in map(lambda x: x[0], pkg.prereq()):
printError(pkg, 'permissions-missing-requires', \
"missing 'permissions' in PreReq")
if found_suseconfig:
printInfo(pkg, 'permissions-suseconfig-obsolete', \
"%run_permissions is obsolete")
check=SUIDCheck()
if Config.info:
addDetails(
'permissions-unauthorized-file',
"""If the package is intended for inclusion in any SUSE product
please open a bug report to request review of the package by the
security team""",
'permissions-symlink',
"""permissions handling for symlinks is useless. Please contact
security@suse.de to remove the entry.""",
'permissions-dir-without-slash',
"""the entry in the permissions file refers to a directory. Please
contact security@suse.de to append a slash to the entry in order to
avoid security problems.""",
'permissions-file-as-dir',
"""the entry in the permissions file refers to a directory but the
package actually contains a file. Please contact security@suse.de to
remove the slash.""",
'permissions-incorrect',
"""please use the %attr macro to set the correct permissions.""",
'permissions-incorrect-owner',
"""please use the %attr macro to set the correct ownership.""",
'permissions-file-setuid-bit',
"""If the package is intended for inclusion in any SUSE product
please open a bug report to request review of the program by the
security team""",
'permissions-directory-setuid-bit',
"""If the package is intended for inclusion in any SUSE product
please open a bug report to request review of the package by the
security team""",
'permissions-world-writable',
"""If the package is intended for inclusion in any SUSE product
please open a bug report to request review of the package by the
security team""",
'permissions-fscaps',
"""Packaging file capabilities is currently not supported. Please
use normal permissions instead. You may contact the security team to
request an entry that sets capabilities in /etc/permissions
instead.""",
'permissions-missing-postin',
"""Please add an appropriate %post section""",
'permissions-missing-requires',
"""Please add \"PreReq: permissions\"""",
'permissions-missing-verifyscript',
"""Please add a %verifyscript section""",
'permissions-suseconfig-obsolete',
"""The %run_permissions macro calls SuSEconfig which sets permissions for all
files in the system. Please use %set_permissions <filename> instead
to only set permissions for files contained in this package""",
)

View File

@ -1,100 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : DuplicatesCheck.py
# Package : rpmlint
# Author : Stephan Kulow
# Purpose : Check for duplicate files being packaged separately
#############################################################################
from Filter import *
import AbstractCheck
import rpm
import re
import commands
import stat
import Config
import os
import string
def get_prefix(file):
pathlist = string.split(file, '/')
if len(pathlist) == 3:
return "/".join(pathlist[0:2])
return "/".join(pathlist[0:3])
class DuplicatesCheck(AbstractCheck.AbstractCheck):
def __init__(self):
self.map = []
AbstractCheck.AbstractCheck.__init__(self, "DuplicatesCheck")
def check(self, pkg):
if pkg.isSource():
return
md5s = {}
sizes = {}
files = pkg.files()
configFiles = pkg.configFiles()
for f, pkgfile in files.items():
if f in pkg.ghostFiles():
continue
if not stat.S_ISREG(pkgfile.mode):
continue
md5s.setdefault(pkgfile.md5, set()).add(f)
sizes[pkgfile.md5] = pkgfile.size
sum=0
for f in md5s:
duplicates=md5s[f]
if len(duplicates) == 1: continue
one=duplicates.pop()
one_is_config = False
if one in configFiles:
one_is_config = True
partition=get_prefix(one)
st = os.stat(pkg.dirName() + '/' + one)
diff = 1 + len(duplicates) - st[stat.ST_NLINK]
if diff <= 0:
for dupe in duplicates:
if partition != get_prefix(dupe):
printError(pkg,"hardlink-across-partition",one,dupe)
if one_is_config and dupe in configFiles:
printError(pkg,"hardlink-across-config-files",one,dupe)
continue
for dupe in duplicates:
if partition != get_prefix(dupe):
diff = diff - 1
sum += sizes[f] * diff
if sizes[f] and diff > 0:
printWarning(pkg, 'files-duplicate', one,":".join(duplicates))
if sum > 100000:
printError(pkg, 'files-duplicated-waste', sum)
check=DuplicatesCheck()
if Config.info:
addDetails(
'files-duplicated-waste',
"""Your package contains duplicated files that are not hard- or symlinks.
You should use the %fdupes macro to link the files to one.""",
'hardlink-across-partition',
"""Your package contains two files that are apparently hardlinked and
that are likely on different partitions. Installation of such an RPM will fail
due to RPM being unable to unpack the hardlink. do not hardlink across
the first two levels of a path, e.g. between /srv/ftp and /srv/www or
/etc and /usr. """,
'hardlink-across-config-files',
"""Your package contains two config files that are apparently hardlinked.
Hardlinking a config file is probably not what you want. Please double
check and report false positives."""
)

View File

@ -1,90 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : KMPPolicyCheck.py
# Package : rpmlint
# Author : Dirk Mueller
# Purpose : Verify that kmp's have proper dependencies
#############################################################################
from Filter import *
import AbstractCheck
import rpm
import re
import commands
import stat
import Config
import os
import string
import Pkg
class KMPPolicyCheck(AbstractCheck.AbstractCheck):
def __init__(self):
self.map = []
AbstractCheck.AbstractCheck.__init__(self, "KMPPolicyCheck")
def check(self, pkg):
if pkg.isSource() or pkg.name.find('-kmp-') < 0:
return
pkg_requires = set(map(lambda x: string.split(x[0],'(')[0], pkg.requires()))
pkg_conflicts = set(map(lambda x: string.split(x[0],'(')[0], pkg.conflicts()))
kernel_flavour="kernel-" + pkg.name.partition('-kmp-')[2]
# verify that Requires: kernel_flavour is present
have_requires=False
for r in pkg_requires:
if r == kernel_flavour:
have_requires = True
break
if not have_requires:
printError(pkg, 'suse-policy-kmp-missing-requires', kernel_flavour)
# verify that exactly one enhances on the kernel flavor is present
if len(pkg.enhances()) > 1:
printError(pkg, 'suse-policy-kmp-excessive-enhances', str(pkg.enhances()))
elif len(pkg.enhances()) < 1:
printError(pkg, 'suse-policy-kmp-missing-enhances', kernel_flavour)
# check that only modalias supplements are present
have_only_modalias=True
have_modalias=False
have_proper_suppl=False
for s in pkg.supplements():
if s[0].startswith('modalias('):
have_modalias = True
continue
if s[0].startswith('packageand(%s:' % (kernel_flavour)):
have_proper_suppl = True
continue
printWarning(pkg, 'suse-policy-kmp-excessive-supplements', s[0])
have_only_modalias = False
if not have_modalias and not have_proper_suppl:
printError(pkg, 'suse-policy-kmp-missing-supplements')
check=KMPPolicyCheck()
if Config.info:
addDetails(
'suse-policy-kmp-missing-requires',
"""Make sure you have extended '%suse_kernel_module_package' by
'-p %_sourcedir/preamble', a file named 'preamble' as source and there
specified 'Requires: kernel-%1'.
""",
'suse-policy-kmp-excessive-enhances',
""" """,
'suse-policy-kmp-missing-enhances',
"""Make sure you have extended '%suse_kernel_module_package' by
'-p %_sourcedir/preamble', a file named 'preamble' as source and there
specified 'Enhances: kernel-%1'.
""",
'suse-policy-kmp-excessive-supplements',
""" """,
'suse-policy-kmp-missing-supplements',
"""Make sure your 'BuildRequires:' include 'kernel-syms' and 'module-init-tools'
for proper dependencies to be built.
""",
)

View File

@ -1,477 +0,0 @@
# vim:sw=4:et
#############################################################################
# File : LibraryPolicyCheck.py
# Package : rpmlint
# Author : Richard Guenther
# Purpose : Verify shared library packaging policy rules
#############################################################################
from Filter import *
import AbstractCheck
import rpm
import re
import commands
import stat
import Config
import os
import string
import Pkg
_policy_legacy_exceptions = (
"libacl1",
"libaio1",
"libalut0",
"libapr-1-0",
"libaprutil-1-0",
"libartskde1",
"libattr1",
"libcdaudio1",
"libcdk4",
"libcheck0",
"libchewing3",
"libchm0",
"libclucene0",
"libdar4",
"libdbh-4_5-4",
"libdbus-qt-1-1",
"libdm0",
"libdns_sd1",
"libefence0",
"libEMF1",
"libevolutionglue",
"libf2c0",
"libffi4",
"libflaim5_2",
"libfontenc1",
"libfreeradius-client2",
"libgcc_s1",
"libgcc_s4", # only for hppa
"libgconfmm-2_6-1",
"libgfortran3",
"libgif4",
"libgimpprint1",
"libgladesharpglue-2",
"libglibsharpglue-2",
"libgltt0",
"libglut3",
"libGLw1",
"libgmcop1",
"libgnet-2_0-0",
"libgnomecanvasmm-2_6-1",
"libgnomecups-1_0-1",
"libgnomemm-2_6-1",
"libgnomeprintui-2-2-0",
"libgnomesharpglue-2",
"libgnomeuimm-2_6-1",
"libgomp1",
"libgsfglue",
"libgsf-gnome-1-114",
"libgtksourceview-1_0-0",
"libgtkspell0",
"libhangul0",
"libICE6",
"libid3-3_8-3",
"libid3tag0",
"libidn11",
"libiec61883-0",
"libieee1284-3",
"libilbc0",
"libind_helper0",
"libiterm1",
"libjackasyn0",
"libkakasi2",
"libkeyutils1",
"libksba8",
"liblo0",
"libmal0",
"libmcrypt4",
"libmdbodbc0",
"libmeanwhile1",
"libmhash2",
"libmikmod2",
"libmng1",
"libnet6-1_3-0",
"libnl1",
"libnscd1",
"libobjc3",
"libodbcinstQ1",
"liboil-0_3-0",
"liboop4",
"libopenal0",
"libopenal1",
"libpgeasy3",
"libportaudio2",
"libqnotify0",
"libQt3Support4",
"libqtc1",
"libqtsharp0",
"libQtSql4",
"libquadmath0",
"librdf0",
"librsync1",
"libsamplerate0",
"libsecprog0",
"libsexy2",
"libsigc-1_2-5",
"libSM6",
"libsndfile1",
"libstdc++6",
"libstroke0",
"libthai0",
"libutempter0",
"libvisual-0_4-0",
"libXau6",
"libxclass0_9_2",
"libXdmcp6",
"libXext6",
"libxfce4util4",
"libxfcegui4-4",
"libXfixes3",
"libxflaim3_2",
"libXiterm1",
"libxkbfile1",
"libxml2-2",
"libXp6",
"libXprintUtil1",
"libXrender1",
"libXt6",
"libXv1",
"libz1",
"libzio0"
)
_essential_dependencies = (
"ld-linux.so.2",
"libacl.so.1",
"libanl.so.1",
"libanonymous.so.2",
"libattr.so.1",
"libaudit.so.0",
"libauparse.so.0",
"libBrokenLocale.so.1",
"libbz2.so.1",
"libcidn.so.1",
"libck-connector.so.0",
"libcom_err.so.2",
"libcrack.so.2",
"libcrypto.so.0.9.8",
"libcrypt.so.1",
"libc.so.6",
"libdbus-1.so.3",
"libdbus-glib-1.so.2",
"libdes425.so.3",
"libdl.so.2",
"libexpat.so.1",
"libform.so.5",
"libformw.so.5",
"libgcc_s.so.1",
"libgcrypt.so.11",
"libgdbm_compat.so.3",
"libgdbm.so.3",
"libgfortran3",
"libgio-2.0.so.0",
"libglib-2.0.so.0",
"libgmodule-2.0.so.0",
"libgobject-2.0.so.0",
"libgpg-error.so.0",
"libgssapi_krb5.so.2",
"libgssrpc.so.4",
"libgthread-2.0.so.0",
"libhal.so.1",
"libhal-storage.so.1",
"libhd.so.14",
"libhistory.so.5",
"libk5crypto.so.3",
"libkadm5clnt.so.5",
"libkadm5srv.so.5",
"libkdb5.so.4",
"libkeyutils.so.1",
"libkrb4.so.2",
"libkrb5.so.3",
"libkrb5support.so.0",
"libksba.so.8",
"liblber-2.4.so.2",
"libldap-2.4.so.2",
"libldap_r-2.4.so.2",
"liblogin.so.2",
"liblog_syslog.so.1",
"libltdl.so.3",
"libmagic.so.1",
"libmenu.so.5",
"libmenuw.so.5",
"libm.so.6",
"libncurses.so.5",
"libncursesw.so.5",
"libnscd.so.1",
"libnsl.so.1",
"libnss_compat.so.2",
"libnss_dns.so.2",
"libnss_files.so.2",
"libnss_hesiod.so.2",
"libnss_nisplus.so.2",
"libnss_nis.so.2",
"libopenct.so.1",
"libopensc.so.2",
"libpamc.so.0",
"libpam_misc.so.0",
"libpam.so.0",
"libpanel.so.5",
"libpanelw.so.5",
"libparted-1.8.so.8",
"libpcrecpp.so.0",
"libpcreposix.so.0",
"libpcre.so.0",
"libpcsclite.so.1",
"libpkcs15init.so.2",
"libpolkit-dbus.so.2",
"libpolkit-grant.so.2",
"libpolkit.so.2",
"libpopt.so.0",
"libpthread.so.0",
"libpth.so.20",
"libreadline.so.5",
"libresmgr.so.0.9.8",
"libresmgr.so.1",
"libresolv.so.2",
"librt.so.1",
"libsasl2.so.2",
"libsasldb.so.2",
"libscconf.so.2",
"libslp.so.1",
"libsmbios.so.1",
"libssl.so.0.9.8",
"libss.so.2",
"libstdc++.so.6",
"libthread_db.so.1",
"libtic.so.5",
"libusb-0.1.so.4",
"libusbpp-0.1.so.4",
"libutil.so.1",
"libuuid.so.1",
"libvolume_id.so.0",
"libwrap.so.0",
"libX11.so.6",
"libX11-xcb.so.1",
"libXau.so.6",
"libxcb-composite.so.0",
"libxcb-damage.so.0",
"libxcb-dpms.so.0",
"libxcb-glx.so.0",
"libxcb-randr.so.0",
"libxcb-record.so.0",
"libxcb-render.so.0",
"libxcb-res.so.0",
"libxcb-screensaver.so.0",
"libxcb-shape.so.0",
"libxcb-shm.so.0",
"libxcb.so.1",
"libxcb-sync.so.0",
"libxcb-xevie.so.0",
"libxcb-xf86dri.so.0",
"libxcb-xfixes.so.0",
"libxcb-xinerama.so.0",
"libxcb-xlib.so.0",
"libxcb-xprint.so.0",
"libxcb-xtest.so.0",
"libxcb-xvmc.so.0",
"libxcb-xv.so.0",
"libxcrypt.so.1",
"libzio.so.0",
"libz.so.1",
)
from BinariesCheck import BinaryInfo
def libname_from_soname (soname):
libname = string.split(soname, '.so.')
if len(libname) == 2:
if libname[0][-1:].isdigit():
libname = string.join(libname, '-')
else:
libname = string.join(libname, '')
else:
libname = soname[:-3]
libname = libname.replace('.', '_')
return libname
class LibraryPolicyCheck(AbstractCheck.AbstractCheck):
def __init__(self):
self.map = []
AbstractCheck.AbstractCheck.__init__(self, "LibraryPolicyCheck")
def check(self, pkg):
global _policy_legacy_exceptions
if pkg.isSource():
return
# Only check unsuffixed lib* packages
if pkg.name.endswith('-devel') or pkg.name.endswith('-doc'):
return
files = pkg.files()
# Search for shared libraries in this package
libs = set()
libs_needed = set()
libs_to_dir = dict()
dirs = set()
reqlibs = set()
pkg_requires = set(map(lambda x: string.split(x[0],'(')[0], pkg.requires()))
for f, pkgfile in files.items():
if f.find('.so.') != -1 or f.endswith('.so'):
filename = pkg.dirName() + '/' + f
try:
if stat.S_ISREG(files[f].mode) and 'ELF' in pkgfile.magic:
bi = BinaryInfo(pkg, filename, f, False, True)
libs_needed = libs_needed.union(bi.needed)
if bi.soname != 0:
lib_dir = string.join(f.split('/')[:-1], '/')
libs.add(bi.soname)
libs_to_dir[bi.soname] = lib_dir
dirs.add(lib_dir)
if bi.soname in pkg_requires:
# But not if the library is used by the pkg itself
# This avoids program packages with their own private lib
# FIXME: we'd need to check if somebody else links to this lib
reqlibs.add(bi.soname)
except:
pass
pass
std_dirs = dirs.intersection(('/lib', '/lib64', '/usr/lib', '/usr/lib64',
'/opt/kde3/lib', '/opt/kde3/lib64'))
non_std_dirs = dirs.difference(std_dirs)
# If this is a program package (all libs it provides are
# required by itself), bail out
if not pkg.name.startswith("lib") and len(libs.difference(reqlibs)) == 0:
return
std_lib_package = False
if pkg.name.startswith("lib") and pkg.name[-1].isdigit():
std_lib_package = True
# ignore libs in a versioned non_std_dir
if std_lib_package:
for lib in libs.copy():
lib_dir = libs_to_dir[lib]
if lib_dir.startswith("/opt/kde3"):
continue
for lib_part in lib_dir.split('/'):
if len(lib_part) == 0:
continue
if lib_part[-1].isdigit() and not lib_part.endswith("lib64"):
libs.remove(lib)
break
# Check for non-versioned libs in a std lib package
if std_lib_package:
for lib in libs.copy():
if not lib[-1].isdigit():
printWarning(pkg, "shlib-unversioned-lib", lib)
libs.remove(lib)
# If this package should be or should be splitted into shlib
# package(s)
if len(libs) > 0 and len(std_dirs) > 0:
# If the package contains a single shlib, name after soname
if len(libs) == 1:
soname = libs.copy().pop()
libname = libname_from_soname (soname)
if libname.startswith('lib') and pkg.name != libname and \
pkg.name != libname + "-mini":
if libname in _policy_legacy_exceptions:
printWarning(pkg, 'shlib-legacy-policy-name-error', libname)
else:
printError(pkg, 'shlib-policy-name-error', libname)
elif not pkg.name[-1:].isdigit():
printError(pkg, 'shlib-policy-missing-suffix')
if (not pkg.name.startswith('lib')) or pkg.name.endswith('-lang'):
return
if not libs:
if pkg.name in _policy_legacy_exceptions:
printWarning(pkg, 'shlib-legacy-policy-missing-lib', pkg.name)
else:
printError(pkg, 'shlib-policy-missing-lib')
# Verify no non-lib stuff is in the package
dirs = set()
for f in files:
if os.path.isdir(pkg.dirName()+f):
dirs.add(f)
# Verify shared lib policy package doesn't have hard dependency on non-lib packages
if std_lib_package:
for dep in pkg.requires():
if (dep[0].startswith('rpmlib(') or dep[0].startswith('config(')):
continue
if (dep[1] & (rpm.RPMSENSE_GREATER | rpm.RPMSENSE_EQUAL)) == rpm.RPMSENSE_EQUAL:
printWarning(pkg, "shlib-fixed-dependency", Pkg.formatRequire(dep[0], dep[1], dep[2]))
# Verify non-lib stuff does not add dependencies
if libs:
for dep in pkg_requires.difference(_essential_dependencies):
if dep.find('.so.') != -1 and not dep in libs and not dep in libs_needed:
printError(pkg, 'shlib-policy-excessive-dependency', dep)
# Check for non-versioned directories beyond sysdirs in package
sysdirs = [ '/lib', '/lib64', '/usr/lib', '/usr/lib64',
'/usr/share/doc/packages', '/usr/share' ]
cdirs = set()
for sysdir in sysdirs:
done = set()
for dir in dirs:
if dir.startswith(sysdir + '/'):
ssdir = string.split(dir[len(sysdir)+1:],'/')[0]
if not ssdir[-1].isdigit():
cdirs.add(sysdir+'/'+ssdir)
done.add(dir)
dirs = dirs.difference(done)
map(lambda dir: printError(pkg, 'shlib-policy-nonversioned-dir', dir), cdirs)
check=LibraryPolicyCheck()
if Config.info:
addDetails(
'shlib-policy-missing-suffix',
"""Your package containing shared libraries does not end in a digit and
should probably be split.""",
'shlib-policy-devel-file',
"""Your shared library package contains development files. Split them into
a -devel subpackage.""",
'shlib-policy-name-error',
"""Your package contains a single shared library but is not named after its SONAME.""",
'shlib-policy-nonversioned-dir',
"""Your shared library package contains non-versioned directories. Those will not
allow to install multiple versions of the package in parallel.""",
'shlib-legacy-policy-name-error',
"""Your shared library package is not named after its SONAME, but it has been added to the list
of legacy exceptions. Please do not rename the package until SONAME changes, but if you have
to rename it for another reason, make sure you name it correctly.""",
'shlib-policy-excessive-dependency',
"""Your package starts with 'lib' as part of its name, but also contains binaries
that have more dependencies than those that already required by the libraries.
Those binaries should probably not be part of the library package, but split into
a seperate one to reduce the additional dependencies for other users of this library.""",
'shlib-policy-missing-lib',
"""Your package starts with 'lib' as part of its name, but does not provide
any libraries. It must not be called a lib-package then. Give it a more
sensible name.""",
'shlib-fixed-dependency',
"""Your shared library package requires a fixed version of another package. The
intention of the Shared Library Policy is to allow parallel installation of
multiple versions of the same shared library, hard dependencies likely make that
impossible. Please remove this dependency and instead move it to the runtime uses
of your library.""",
'shlib-unversioned-lib',
"""Your package matches the Shared Library Policy Naming Scheme but contains an
unversioned library. Therefore it is very unlikely that your package can be installed
in parallel to another version of this library package. Consider moving unversioned
parts into a runtime package."""
)

13
README.packaging.txt Normal file
View File

@ -0,0 +1,13 @@
The files from rpmlint-checks are the content of the git tree. If you need
to make changes, you have the following options:
* Make them in git and update the package from git (you can send merge
request if you don't have write access)
* Create a patch, add the patch to the package and let one of the
maintainers commit it for you
The online repository is at:
https://github.com/openSUSE/rpmlint-checks
For building the package from git run the service directly:
osc service disabledrun

11
_service Normal file
View File

@ -0,0 +1,11 @@
<services>
<service name="tar_scm" mode="disabled">
<param name="version">master</param>
<param name="url">http://github.com/openSUSE/rpmlint-checks.git</param>
<param name="scm">git</param>
</service>
<service name="recompress" mode="disabled">
<param name="compression">gz</param>
<param name="file">*.tar</param>
</service>
</services>

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b008d03b16dfff7121469c26e17aa2c161bed0493565396c6b6ca229dd0e5615
size 28984

View File

@ -1,3 +1,27 @@
-------------------------------------------------------------------
Thu Oct 4 07:39:05 UTC 2012 - aj@suse.de
- Remove check for /var/lock and /var/run since it's in upstream
rpmlint already.
-------------------------------------------------------------------
Wed Sep 26 13:10:02 UTC 2012 - aj@suse.de
- Add README.packaging.txt to explain packaging of file
rpmlint-checks-$VERSION.tar.gz
- Package all *py files into rpmlint-checks tarball
- Add _service file to update rpmlint-checks tarball
- Add /etc/systemd.d, /etc/modules-load.d and /etc/tmpfiles.d to the
blacklist, only users should write here.
- Blacklist the directories used by systemd.
- Remove SuSEconfig directories (update patch suse-filesystem.diff)
- Add warnings about files on tmpfs in /var/lock or /var/run.
-------------------------------------------------------------------
Wed Sep 26 09:16:37 UTC 2012 - dmueller@suse.com
- restore LibraryPolicy from git
-------------------------------------------------------------------
Sat Sep 15 07:00:29 UTC 2012 - coolo@suse.com

View File

@ -28,33 +28,12 @@ Group: System/Packages
Version: 1.4
Release: 0
Source0: http://rpmlint.zarb.org/download/rpmlint-%{version}.tar.xz
Source1: config
Source1001: config.in
Source3: DuplicatesCheck.py
Source4: CheckBuildRoot.py
Source5: CheckExecDocs.py
Source6: CheckPkgConfig.py
Source7: LibraryPolicyCheck.py
Source8: CheckCommonFiles.py
Source9: CheckInitScripts.py
Source10: CheckIconSizes.py
Source11: BrandingPolicyCheck.py
Source12: CheckKDE4Deps.py
Source13: KMPPolicyCheck.py
Source14: CheckSUIDPermissions.py
Source15: CheckPolkitPrivs.py
Source16: CheckDBUSServices.py
Source17: CheckFilelist.py
Source18: CheckDBusPolicy.py
Source19: CheckAlternativesGhostFiles.py
Source20: rpmgroups.config
Source21: BashismsCheck.py
Source22: CheckGNOMEMacros.py
Source23: CheckBuildDate.py
Source24: pie.config
Source25: licenses.config
Source26: CheckLogrotate.py
Source27: CheckPAMModules.py
Source1: rpmlint-checks-master.tar.gz
Source2: config
Source3: config.in
Source10: rpmgroups.config
Source11: pie.config
Source12: licenses.config
Source100: syntax-validator.py
Url: http://rpmlint.zarb.org/
BuildRoot: %{_tmppath}/%{name}-%{version}-build
@ -69,6 +48,10 @@ Requires: findutils
Requires: python-magic
Requires: rpm-python
BuildArch: noarch
#
# Read README.packaging.txt before making any changes to this
# package
#
Patch0: rpmlint-suse.diff
Patch1: suse-checks.diff
Patch2: suse-version.diff
@ -148,7 +131,7 @@ Authors:
Gwenole Beauchesne <gbeauchesne@mandriva.com>
%prep
%setup -q -n rpmlint-%{version}
%setup -q -n rpmlint-%{version} -a1
%patch0
%patch1
%patch2
@ -214,29 +197,10 @@ Authors:
%patch88
%patch89
%patch90 -p1
cp -p %{SOURCE1} .
cp -p %{SOURCE3} .
cp -p %{SOURCE4} .
cp -p %{SOURCE5} .
cp -p %{SOURCE6} .
cp -p %{SOURCE7} .
cp -p %{SOURCE8} .
cp -p %{SOURCE9} .
cp -p %{SOURCE10} .
cp -p %{SOURCE11} .
cp -p %{SOURCE12} .
cp -p %{SOURCE13} .
cp -p %{SOURCE14} .
cp -p %{SOURCE15} .
cp -p %{SOURCE16} .
cp -p %{SOURCE17} .
cp -p %{SOURCE18} .
cp -p %{SOURCE19} .
cp -p %{SOURCE21} .
cp -p %{SOURCE22} .
cp -p %{SOURCE23} .
cp -p %{SOURCE26} .
cp -p %{SOURCE27} .
cp -p %{SOURCE2} .
# Only move top-level python files
chmod 0755 rpmlint-checks-master/*.py
mv rpmlint-checks-master/*.py .
%build
make %{?_smp_mflags}
@ -249,10 +213,10 @@ mv $RPM_BUILD_ROOT/etc/rpmlint/config $RPM_BUILD_ROOT/usr/share/rpmlint/config
head -n 8 $RPM_BUILD_ROOT/usr/share/rpmlint/config > $RPM_BUILD_ROOT/etc/rpmlint/config
# make sure that the package is sane
python -tt %{SOURCE100} $RPM_BUILD_ROOT/usr/share/rpmlint/*.py $RPM_BUILD_ROOT/usr/share/rpmlint/config
%__install -m 644 %{SOURCE20} %{buildroot}/%{_sysconfdir}/rpmlint/
%__install -m 644 %{SOURCE24} %{buildroot}/%{_sysconfdir}/rpmlint/
%__install -m 644 %{SOURCE10} %{buildroot}/%{_sysconfdir}/rpmlint/
%__install -m 644 %{SOURCE11} %{buildroot}/%{_sysconfdir}/rpmlint/
cp %{SOURCE25} licenses.config
cp %{SOURCE12} licenses.config
# note there is a tab character behind the -d, so don't copy&paste lightly
cut '-d ' -f1 /usr/lib/obs/service/format_spec_file.files/licenses_changes.txt | tail -n +2 | sort -u | while read l; do
sed -i -e "s/\(#VALIDLICENSES\)/\1\n '$l',/" licenses.config

View File

@ -2,13 +2,12 @@ Index: FilesCheck.py
===================================================================
--- FilesCheck.py.orig
+++ FilesCheck.py
@@ -29,65 +29,114 @@ STANDARD_DIRS = (
@@ -29,65 +29,112 @@ STANDARD_DIRS = (
'/',
'/bin',
'/boot',
+ '/dev',
'/etc',
+ '/etc/SuSEconfig',
'/etc/X11',
+ '/etc/aliases.d',
+ '/etc/cron.d',
@ -80,7 +79,6 @@ Index: FilesCheck.py
+ '/root/bin',
'/sbin',
- '/selinux',
+ '/sbin/conf.d',
'/srv',
+ '/srv/ftp',
+ '/srv/www',
@ -144,7 +142,7 @@ Index: FilesCheck.py
'/usr/local/lib',
'/usr/local/lib64',
'/usr/local/man',
@@ -103,24 +152,415 @@ STANDARD_DIRS = (
@@ -103,24 +150,415 @@ STANDARD_DIRS = (
'/usr/local/man/mann',
'/usr/local/sbin',
'/usr/local/share',
@ -571,7 +569,7 @@ Index: FilesCheck.py
'/usr/share/man',
'/usr/share/man/man1',
'/usr/share/man/man2',
@@ -132,28 +572,60 @@ STANDARD_DIRS = (
@@ -132,28 +570,57 @@ STANDARD_DIRS = (
'/usr/share/man/man8',
'/usr/share/man/man9',
'/usr/share/man/mann',
@ -595,9 +593,6 @@ Index: FilesCheck.py
'/var',
+ '/var/X11R6',
+ '/var/adm',
+ '/var/adm/SuSEconfig',
+ '/var/adm/SuSEconfig/bin',
+ '/var/adm/SuSEconfig/md5',
+ '/var/adm/backup',
+ '/var/adm/backup/rpmdb',
+ '/var/adm/backup/sysconfig',