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:
commit
666b20d48b
@ -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.''')
|
@ -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()""",
|
||||
)
|
@ -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.''',
|
||||
|
||||
)
|
@ -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"""
|
||||
)
|
@ -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."
|
||||
)
|
@ -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."""
|
||||
)
|
@ -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.""",
|
||||
)
|
@ -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""",
|
||||
)
|
@ -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."""
|
||||
)
|
444
CheckFilelist.py
444
CheckFilelist.py
@ -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'])
|
@ -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.'''
|
||||
|
||||
)
|
@ -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."""
|
||||
)
|
@ -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'.""",
|
||||
)
|
119
CheckKDE4Deps.py
119
CheckKDE4Deps.py
@ -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."""
|
||||
)
|
@ -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"""
|
||||
)
|
@ -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.""",
|
||||
)
|
@ -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.'''
|
||||
)
|
@ -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.*""")
|
@ -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""",
|
||||
)
|
@ -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."""
|
||||
)
|
@ -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.
|
||||
""",
|
||||
)
|
@ -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
13
README.packaging.txt
Normal 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
11
_service
Normal 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>
|
3
rpmlint-checks-master.tar.gz
Normal file
3
rpmlint-checks-master.tar.gz
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b008d03b16dfff7121469c26e17aa2c161bed0493565396c6b6ca229dd0e5615
|
||||
size 28984
|
@ -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
|
||||
|
||||
|
72
rpmlint.spec
72
rpmlint.spec
@ -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
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user