summaryrefslogtreecommitdiff
path: root/FilesCheck.py
diff options
context:
space:
mode:
Diffstat (limited to 'FilesCheck.py')
-rw-r--r--FilesCheck.py1491
1 files changed, 0 insertions, 1491 deletions
diff --git a/FilesCheck.py b/FilesCheck.py
deleted file mode 100644
index db43d4a..0000000
--- a/FilesCheck.py
+++ /dev/null
@@ -1,1491 +0,0 @@
-# -*- coding: utf-8 -*-
-#############################################################################
-# File : FilesCheck.py
-# Package : rpmlint
-# Author : Frederic Lepied
-# Created on : Mon Oct 4 19:32:49 1999
-# Purpose : test various aspects on files: locations, owner, groups,
-# permission, setuid, setgid...
-#############################################################################
-
-from datetime import datetime
-import os
-import re
-import stat
-
-import rpm
-
-import AbstractCheck
-import Config
-from Filter import addDetails, printError, printWarning
-from Pkg import b2s, catcmd, getstatusoutput, is_utf8, is_utf8_bytestr, shquote
-
-
-# must be kept in sync with the filesystem package
-STANDARD_DIRS = (
- '/',
- '/bin',
- '/boot',
- '/etc',
- '/etc/X11',
- '/etc/opt',
- '/etc/profile.d',
- '/etc/skel',
- '/etc/xinetd.d',
- '/home',
- '/lib',
- '/lib/modules',
- '/lib64',
- '/media',
- '/mnt',
- '/mnt/cdrom',
- '/mnt/disk',
- '/mnt/floppy',
- '/opt',
- '/proc',
- '/root',
- '/run',
- '/sbin',
- '/selinux',
- '/srv',
- '/sys',
- '/tmp',
- '/usr',
- '/usr/X11R6',
- '/usr/X11R6/bin',
- '/usr/X11R6/doc',
- '/usr/X11R6/include',
- '/usr/X11R6/lib',
- '/usr/X11R6/lib64',
- '/usr/X11R6/man',
- '/usr/X11R6/man/man1',
- '/usr/X11R6/man/man2',
- '/usr/X11R6/man/man3',
- '/usr/X11R6/man/man4',
- '/usr/X11R6/man/man5',
- '/usr/X11R6/man/man6',
- '/usr/X11R6/man/man7',
- '/usr/X11R6/man/man8',
- '/usr/X11R6/man/man9',
- '/usr/X11R6/man/mann',
- '/usr/bin',
- '/usr/bin/X11',
- '/usr/etc',
- '/usr/games',
- '/usr/include',
- '/usr/lib',
- '/usr/lib/X11',
- '/usr/lib/games',
- '/usr/lib/gcc-lib',
- '/usr/lib/menu',
- '/usr/lib64',
- '/usr/lib64/gcc-lib',
- '/usr/local',
- '/usr/local/bin',
- '/usr/local/doc',
- '/usr/local/etc',
- '/usr/local/games',
- '/usr/local/info',
- '/usr/local/lib',
- '/usr/local/lib64',
- '/usr/local/man',
- '/usr/local/man/man1',
- '/usr/local/man/man2',
- '/usr/local/man/man3',
- '/usr/local/man/man4',
- '/usr/local/man/man5',
- '/usr/local/man/man6',
- '/usr/local/man/man7',
- '/usr/local/man/man8',
- '/usr/local/man/man9',
- '/usr/local/man/mann',
- '/usr/local/sbin',
- '/usr/local/share',
- '/usr/local/share/man',
- '/usr/local/share/man/man1',
- '/usr/local/share/man/man2',
- '/usr/local/share/man/man3',
- '/usr/local/share/man/man4',
- '/usr/local/share/man/man5',
- '/usr/local/share/man/man6',
- '/usr/local/share/man/man7',
- '/usr/local/share/man/man8',
- '/usr/local/share/man/man9',
- '/usr/local/share/man/mann',
- '/usr/local/src',
- '/usr/sbin',
- '/usr/share',
- '/usr/share/dict',
- '/usr/share/doc',
- '/usr/share/icons',
- '/usr/share/info',
- '/usr/share/man',
- '/usr/share/man/man1',
- '/usr/share/man/man2',
- '/usr/share/man/man3',
- '/usr/share/man/man4',
- '/usr/share/man/man5',
- '/usr/share/man/man6',
- '/usr/share/man/man7',
- '/usr/share/man/man8',
- '/usr/share/man/man9',
- '/usr/share/man/mann',
- '/usr/share/misc',
- '/usr/src',
- '/usr/tmp',
- '/var',
- '/var/cache',
- '/var/db',
- '/var/lib',
- '/var/lib/games',
- '/var/lib/misc',
- '/var/lib/rpm',
- '/var/local',
- '/var/log',
- '/var/mail',
- '/var/nis',
- '/var/opt',
- '/var/preserve',
- '/var/spool',
- '/var/spool/mail',
- '/var/tmp',
-)
-
-DEFAULT_GAMES_GROUPS = 'Games'
-
-DEFAULT_DANGLING_EXCEPTIONS = (
- ['consolehelper$', 'usermode-consoleonly'],
-)
-
-# Standard users and groups from LSB Core 4.0.0: 21.2 User & Group Names
-DEFAULT_STANDARD_USERS = ('root', 'bin', 'daemon', 'adm', 'lp', 'sync',
- 'shutdown', 'halt', 'mail', 'news', 'uucp',
- 'operator', 'man', 'nobody',)
-DEFAULT_STANDARD_GROUPS = ('root', 'bin', 'daemon', 'adm', 'lp', 'sync',
- 'shutdown', 'halt', 'mail', 'news', 'uucp',
- 'man', 'nobody',)
-
-DEFAULT_DISALLOWED_DIRS = (
- '/home',
- '/mnt',
- '/opt',
- '/tmp',
- '/usr/local',
- '/usr/tmp',
- '/var/local',
- '/var/lock',
- '/var/run',
- '/var/tmp',
-)
-
-compressions = r'\.(gz|z|Z|zip|bz2|lzma|xz|zst)'
-sub_bin_regex = re.compile(r'^(/usr)?/s?bin/\S+/')
-backup_regex = re.compile(r'(~|\#[^/]+\#|((\.orig|\.rej)(' + compressions + ')?))$')
-compr_regex = re.compile(compressions + r'$')
-absolute_regex = re.compile(r'^/([^/]+)')
-absolute2_regex = re.compile(r'^/?([^/]+)')
-points_regex = re.compile(r'^\.\./(.*)')
-doc_regex = re.compile(r'^/usr(/share|/X11R6)?/(doc|man|info)/|^/usr/share/gnome/help')
-bin_regex = re.compile(r'^/(?:usr/(?:s?bin|games)|s?bin)/(.*)')
-includefile_regex = re.compile(r'\.(c|h)(pp|xx)?$', re.IGNORECASE)
-develfile_regex = re.compile(r'\.(a|cmxa?|mli?|gir)$')
-buildconfigfile_regex = re.compile(r'(\.pc|/bin/.+-config)$')
-# room for improvement with catching more -R, but also for false positives...
-buildconfig_rpath_regex = re.compile(r'(?:-rpath|Wl,-R)\b')
-sofile_regex = re.compile(r'/lib(64)?/(.+/)?lib[^/]+\.so$')
-devel_regex = re.compile(r'(.*)-(debug(info|source)?|devel|headers|source|static)$')
-debuginfo_package_regex = re.compile(r'-debug(info)?$')
-debugsource_package_regex = re.compile(r'-debugsource$')
-use_debugsource = Config.getOption('UseDebugSource', False)
-lib_regex = re.compile(r'/lib(?:64)?/lib[^/]+(?:\.so\.[\d\.]+|-[\d\.]+\.so)$')
-ldconfig_regex = re.compile(r'^[^#]*ldconfig', re.MULTILINE)
-depmod_regex = re.compile(r'^[^#]*depmod', re.MULTILINE)
-install_info_regex = re.compile(r'^[^#]*install-info', re.MULTILINE)
-perl_temp_file_regex = re.compile(r'.*perl.*/(\.packlist|perllocal\.pod)$')
-scm_regex = re.compile(
- r'/(?:RCS|CVS)/[^/]+$|/\.(?:bzr|cvs|git|hg|svn)ignore$|'
- r',v$|/\.hgtags$|/\.(?:bzr|git|hg|svn)/|/(?:\.arch-ids|{arch})/')
-games_path_regex = re.compile(r'^/usr(/lib(64)?)?/games/')
-games_group_regex = re.compile(Config.getOption('RpmGamesGroups', DEFAULT_GAMES_GROUPS))
-dangling_exceptions = Config.getOption('DanglingSymlinkExceptions', DEFAULT_DANGLING_EXCEPTIONS)
-logrotate_regex = re.compile(r'^/etc/logrotate\.d/(.*)')
-module_rpms_ok = Config.getOption('KernelModuleRPMsOK', True)
-kernel_modules_regex = re.compile(r'^(?:/usr)/lib/modules/([0-9]+\.[0-9]+\.[0-9]+[^/]*?)/')
-kernel_package_regex = re.compile(r'^kernel(22)?(-)?(smp|enterprise|bigmem|secure|BOOT|i686-up-4GB|p3-smp-64GB)?')
-normal_zero_length_regex = re.compile(r'^/etc/security/console\.apps/|/\.nosearch$|/__init__\.py$')
-perl_regex = re.compile(r'^/usr/lib/perl5/(?:vendor_perl/)?([0-9]+\.[0-9]+)\.([0-9]+)/')
-python_regex = re.compile(r'^/usr/lib(?:64)?/python([.0-9]+)/')
-python_bytecode_regex_pep3147 = re.compile(r'^(.*)/__pycache__/(.*?)\.([^.]+)(\.opt-[12])?\.py[oc]$')
-python_bytecode_regex = re.compile(r'^(.*)(\.py[oc])$')
-python_default_version = Config.getOption('PythonDefaultVersion', None)
-perl_version_trick = Config.getOption('PerlVersionTrick', True)
-log_regex = re.compile(r'^/var/log/[^/]+$')
-lib_path_regex = re.compile(r'^(/usr(/X11R6)?)?/lib(64)?')
-lib_package_regex = re.compile(r'^(lib|.+-libs)')
-hidden_file_regex = re.compile(r'/\.[^/]*$')
-manifest_perl_regex = re.compile(r'^/usr/share/doc/perl-.*/MANIFEST(\.SKIP)?$')
-shebang_regex = re.compile(br'^#!\s*(\S+)(.*?)$', re.M)
-interpreter_regex = re.compile(r'^/(?:usr/)?(?:s?bin|games|libexec(?:/.+)?|(?:lib(?:64)?|share)/.+)/([^/]+)$')
-script_regex = re.compile(r'^/((usr/)?s?bin|etc/(rc\.d/init\.d|X11/xinit\.d|cron\.(hourly|daily|monthly|weekly)))/')
-sourced_script_regex = re.compile(r'^/etc/(bash_completion\.d|profile\.d)/')
-use_utf8 = Config.getOption('UseUTF8', Config.USEUTF8_DEFAULT)
-skipdocs_regex = re.compile(Config.getOption('SkipDocsRegexp', r'\.(?:rtf|x?html?|svg|ml[ily]?)$'), re.IGNORECASE)
-meta_package_regex = re.compile(Config.getOption('MetaPackageRegexp', r'^(bundle|task)-'))
-filesys_packages = ['filesystem'] # TODO: make configurable?
-quotes_regex = re.compile(r'[\'"]+')
-start_certificate_regex = re.compile(r'^-----BEGIN CERTIFICATE-----$')
-start_private_key_regex = re.compile(r'^----BEGIN PRIVATE KEY-----$')
-
-for idx in range(0, len(dangling_exceptions)):
- dangling_exceptions[idx][0] = re.compile(dangling_exceptions[idx][0])
-del idx
-
-use_relative_symlinks = Config.getOption("UseRelativeSymlinks", True)
-
-standard_groups = Config.getOption('StandardGroups', DEFAULT_STANDARD_GROUPS)
-standard_users = Config.getOption('StandardUsers', DEFAULT_STANDARD_USERS)
-
-disallowed_dirs = Config.getOption('DisallowedDirs', DEFAULT_DISALLOWED_DIRS)
-
-non_readable_regexs = (re.compile(r'^/var/log/'),
- re.compile(r'^/etc/(g?shadow-?|securetty)$'))
-
-man_base_regex = re.compile(r'^/usr(?:/share)?/man(?:/overrides)?/man[^/]+/(.+)\.[1-9n]')
-man_warn_regex = re.compile(r'^([^:]+:)\d+:\s*')
-man_nowarn_regex = re.compile(
- # From Lintian: ignore common undefined macros from pod2man << Perl 5.10
- r'\`(Tr|IX)\' not defined|'
- # .so entries won't resolve as we're dealing with stdin
- r'No such file or directory|'
- # TODO, better handling for these (see e.g. Lintian)
- r'(can\'t break|cannot adjust) line')
-man_warn_category = Config.getOption('ManWarningCategory', 'mac')
-
-fsf_license_regex = re.compile(br'(GNU((\s+(Library|Lesser|Affero))?(\s+General)?\s+Public|\s+Free\s+Documentation)\s+Licen[cs]e|(GP|FD)L)', re.IGNORECASE)
-fsf_wrong_address_regex = re.compile(br'(675\s+Mass\s+Ave|59\s+Temple\s+Place|Franklin\s+Steet|02139|02111-1307)', re.IGNORECASE)
-
-scalable_icon_regex = re.compile(r'^/usr(?:/local)?/share/icons/.*/scalable/')
-
-# "is binary" stuff borrowed from https://pypi.python.org/pypi/binaryornot
-# TODO: switch to it sometime later instead of embedding our own copy
-
-printable_extended_ascii = b'\n\r\t\f\b'
-if bytes is str:
- # Python 2 means we need to invoke chr() explicitly
- printable_extended_ascii += b''.join(map(chr, range(32, 256)))
-else:
- # Python 3 means bytes accepts integer input directly
- printable_extended_ascii += bytes(range(32, 256))
-
-
-def peek(filename, pkg, length=1024):
- """
- Peek into a file, return a chunk from its beginning and a flag if it
- seems to be a text file.
- """
- chunk = None
- try:
- with open(filename, 'rb') as fobj:
- chunk = fobj.read(length)
- except IOError as e: # eg. https://bugzilla.redhat.com/209876
- printWarning(pkg, 'read-error', e)
- return (chunk, False)
-
- if b'\0' in chunk:
- return (chunk, False)
-
- if not chunk: # Empty files are considered text
- return (chunk, True)
-
- fl = filename.lower()
-
- # PDF's are binary but often detected as text by the algorithm below
- if fl.endswith('.pdf') and chunk.startswith(b'%PDF-'):
- return (chunk, False)
- # Ditto RDoc RI files
- if fl.endswith('.ri') and '/ri/' in fl:
- return (chunk, False)
-
- # Binary if control chars are > 30% of the string
- control_chars = chunk.translate(None, printable_extended_ascii)
- nontext_ratio = float(len(control_chars)) / float(len(chunk))
- istext = nontext_ratio <= 0.30
-
- return (chunk, istext)
-
-
-# See Python sources for a full list of the values here.
-# https://github.com/python/cpython/blob/master/Lib/importlib/_bootstrap_external.py
-# https://github.com/python/cpython/blob/2.7/Python/import.c
-# https://github.com/python/cpython/commit/93602e3af70d3b9f98ae2da654b16b3382b68d50
-_python_magic_values = {
- '2.2': [60717],
- '2.3': [62011],
- '2.4': [62061],
- '2.5': [62131],
- '2.6': [62161],
- '2.7': [62211],
- '3.0': [3130],
- '3.1': [3150],
- '3.2': [3180],
- '3.3': [3230],
- '3.4': [3310],
- '3.5': [3350, 3351], # 3350 for < 3.5.2
- '3.6': [3379],
- '3.7': [3390, 3391, 3392, 3393, 3394],
-}
-
-
-def get_expected_pyc_magic(path):
- """
- .pyc/.pyo files embed a 4-byte magic value identifying which version of
- the python bytecode ABI they are for. Given a path to a .pyc/.pyo file,
- return a (magic ABI values, python version) tuple. For example,
- '/usr/lib/python3.1/foo.pyc' should return (3151, '3.1').
- The first value will be None if the python version was not resolved
- from the given pathname and the PythonDefaultVersion configuration
- variable is not set, or if we don't know the magic ABI values for the
- python version (no matter from which source the version came from).
- The second value will be None if a python version could not be resolved
- from the given pathname.
- """
-
- ver_from_path = None
- m = python_regex.search(path)
- if m:
- ver_from_path = m.group(1)
-
- expected_version = ver_from_path or python_default_version
- expected_magic_values = _python_magic_values.get(expected_version)
-
- if not expected_magic_values:
- return (None, ver_from_path)
-
- # In Python 2, if Py_UnicodeFlag is set, Python's import code uses a value
- # one higher, but this is off by default. In Python 3.0 and 3.1 (but no
- # longer in 3.2), it always uses the value one higher:
- if expected_version[:3] in ('3.0', '3.1'):
- expected_magic_values = [x + 1 for x in expected_magic_values]
-
- return (expected_magic_values, ver_from_path)
-
-
-def py_demarshal_long(b):
- """
- Counterpart to Python's PyMarshal_ReadLongFromFile, operating on the
- bytes in a string.
- """
- if isinstance(b, str):
- b = map(ord, b)
- return (b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24))
-
-
-def pyc_magic_from_chunk(chunk):
- """From given chunk (beginning of the file), return Python magic number"""
- return py_demarshal_long(chunk[:4]) & 0xffff
-
-
-def pyc_mtime_from_chunk(chunk):
- """From given chunk (beginning of the file), return mtime or None
-
- From Python 3.7, mtime is not always present.
-
- See https://www.python.org/dev/peps/pep-0552/#specification
- """
- magic = pyc_magic_from_chunk(chunk)
- second = py_demarshal_long(chunk[4:8])
- if magic >= _python_magic_values['3.7'][0]:
- if second == 0:
- return py_demarshal_long(chunk[8:12])
- return None # No mtime saved, TODO check hashes instead
- return second
-
-
-def python_bytecode_to_script(path):
- """
- Given a python bytecode path, give the path of the .py file
- (or None if not python bytecode).
- """
-
- res = python_bytecode_regex_pep3147.search(path)
- if res:
- return res.group(1) + '/' + res.group(2) + '.py'
-
- res = python_bytecode_regex.search(path)
- if res:
- return res.group(1) + '.py'
-
- return None
-
-
-def script_interpreter(chunk):
- res = shebang_regex.search(chunk) if chunk else None
- return (b2s(res.group(1)), b2s(res.group(2)).strip()) \
- if res and res.start() == 0 else (None, "")
-
-
-class FilesCheck(AbstractCheck.AbstractCheck):
-
- def __init__(self):
- AbstractCheck.AbstractCheck.__init__(self, 'FilesCheck')
-
- def check(self, pkg):
-
- if use_utf8:
- for filename in pkg.header[rpm.RPMTAG_FILENAMES] or ():
- if not is_utf8_bytestr(filename):
- printError(pkg, 'filename-not-utf8', b2s(filename))
-
- # Rest of the checks are for binary packages only
- if pkg.isSource():
- return
-
- files = pkg.files()
-
- # Check if the package is a development package
- devel_pkg = devel_regex.search(pkg.name)
-
- config_files = pkg.configFiles()
- ghost_files = pkg.ghostFiles()
- doc_files = pkg.docFiles()
- req_names = pkg.req_names()
- lib_package = lib_package_regex.search(pkg.name)
- is_kernel_package = kernel_package_regex.search(pkg.name)
- debuginfo_package = debuginfo_package_regex.search(pkg.name)
- debugsource_package = debugsource_package_regex.search(pkg.name)
-
- # report these errors only once
- perl_dep_error = False
- python_dep_error = False
- lib_file = False
- non_lib_file = None
- log_files = []
- logrotate_file = False
- debuginfo_srcs = False
- debuginfo_debugs = False
-
- if not doc_files:
- printWarning(pkg, 'no-documentation')
-
- if files:
- if meta_package_regex.search(pkg.name):
- printWarning(pkg, 'file-in-meta-package')
- elif debuginfo_package or debugsource_package:
- printError(pkg, 'empty-debuginfo-package')
-
- # Prefetch scriptlets, strip quotes from them (#169)
- postin = pkg[rpm.RPMTAG_POSTIN] or \
- pkg.scriptprog(rpm.RPMTAG_POSTINPROG)
- if postin:
- postin = quotes_regex.sub('', postin)
- postun = pkg[rpm.RPMTAG_POSTUN] or \
- pkg.scriptprog(rpm.RPMTAG_POSTUNPROG)
- if postun:
- postun = quotes_regex.sub('', postun)
-
- # Unique (rdev, inode) combinations
- hardlinks = {}
-
- # All executable files from standard bin dirs (basename => [paths])
- # Hack: basenames with empty paths links are symlinks (not subject
- # to duplicate binary check, but yes for man page existence check)
- bindir_exes = {}
-
- # All man page "base" names (without section etc extensions)
- man_basenames = set()
-
- for f, pkgfile in files.items():
- mode = pkgfile.mode
- user = pkgfile.user
- group = pkgfile.group
- link = pkgfile.linkto
- size = pkgfile.size
- rdev = pkgfile.rdev
- inode = pkgfile.inode
- is_doc = f in doc_files
- nonexec_file = False
-
- for match in AbstractCheck.macro_regex.findall(f):
- printWarning(pkg, 'unexpanded-macro', f, match)
- if standard_users and user not in standard_users:
- printWarning(pkg, 'non-standard-uid', f, user)
- if standard_groups and group not in standard_groups:
- printWarning(pkg, 'non-standard-gid', f, group)
-
- if not module_rpms_ok and kernel_modules_regex.search(f) and not \
- is_kernel_package:
- printError(pkg, "kernel-modules-not-in-kernel-packages", f)
-
- for i in disallowed_dirs:
- if f.startswith(i):
- printError(pkg, 'dir-or-file-in-%s' %
- '-'.join(i.split('/')[1:]), f)
-
- if f.startswith('/run/'):
- if f not in ghost_files:
- printWarning(pkg, 'non-ghost-in-run', f)
- elif f.startswith('/etc/systemd/system/'):
- printWarning(pkg, 'systemd-unit-in-etc', f)
- elif f.startswith('/etc/udev/rules.d/'):
- printWarning(pkg, 'udev-rule-in-etc', f)
- elif f.startswith('/etc/tmpfiles.d/'):
- printWarning(pkg, 'tmpfiles-conf-in-etc', f)
- elif sub_bin_regex.search(f):
- printError(pkg, 'subdir-in-bin', f)
- elif '/site_perl/' in f:
- printWarning(pkg, 'siteperl-in-perl-module', f)
-
- if backup_regex.search(f):
- printError(pkg, 'backup-file-in-package', f)
- elif scm_regex.search(f):
- printError(pkg, 'version-control-internal-file', f)
- elif f.endswith('/.htaccess'):
- printError(pkg, 'htaccess-file', f)
- elif hidden_file_regex.search(f) and not f.startswith("/etc/skel/") and not f.endswith("/.build-id"):
- printWarning(pkg, 'hidden-file-or-dir', f)
- elif manifest_perl_regex.search(f):
- printWarning(pkg, 'manifest-in-perl-module', f)
- elif f == '/usr/info/dir' or f == '/usr/share/info/dir':
- printError(pkg, 'info-dir-file', f)
-
- res = logrotate_regex.search(f)
- if res:
- logrotate_file = True
- if res.group(1) != pkg.name:
- printError(pkg, 'incoherent-logrotate-file', f)
-
- deps = [x[0] for x in pkg.requires() + pkg.recommends() + pkg.suggests()]
- if res and not ('logrotate' in deps) and pkg.name != "logrotate":
- printError(pkg, 'missing-dependency-to-logrotate', "for logrotate script", f)
- if f.startswith('/etc/cron.') \
- and not ('cron' in deps) and pkg.name != "cron":
- printError(pkg, 'missing-dependency-to-cron', "for cron script", f)
- if f.startswith('/etc/xinet.d/') \
- and not ('xinetd' in deps) and pkg.name != "xinetd":
- printError(pkg, 'missing-dependency-to-xinetd', "for xinet.d script", f)
-
- if link != '':
- ext = compr_regex.search(link)
- if ext:
- if not re.compile(r'\.%s$' % ext.group(1)).search(f):
- printError(pkg, 'compressed-symlink-with-wrong-ext',
- f, link)
-
- perm = mode & 0o7777
- mode_is_exec = mode & 0o111
-
- if log_regex.search(f):
- log_files.append(f)
-
- # Hardlink check
- for hardlink in hardlinks.get((rdev, inode), ()):
- if os.path.dirname(hardlink) != os.path.dirname(f):
- printWarning(pkg, 'cross-directory-hard-link', f, hardlink)
- hardlinks.setdefault((rdev, inode), []).append(f)
-
- # normal file check
- if stat.S_ISREG(mode):
-
- # set[ug]id bit check
- if stat.S_ISGID & mode or stat.S_ISUID & mode:
- if stat.S_ISUID & mode:
- printError(pkg, 'setuid-binary', f, user, "%o" % perm)
- if stat.S_ISGID & mode:
- if not (group == 'games' and
- (games_path_regex.search(f) or
- games_group_regex.search(
- pkg[rpm.RPMTAG_GROUP]))):
- printError(pkg, 'setgid-binary', f, group,
- "%o" % perm)
- if mode & 0o777 != 0o755:
- printError(pkg, 'non-standard-executable-perm', f,
- "%o" % perm)
-
- if not devel_pkg:
- if lib_path_regex.search(f):
- lib_file = True
- elif not is_doc:
- non_lib_file = f
-
- if log_regex.search(f):
- nonexec_file = True
- if user != 'root':
- printError(pkg, 'non-root-user-log-file', f, user)
- if group != 'root':
- printError(pkg, 'non-root-group-log-file', f, group)
- if f not in ghost_files:
- printError(pkg, 'non-ghost-file', f)
-
- chunk = None
- istext = False
- res = None
- try:
- res = os.access(pkgfile.path, os.R_OK)
- except UnicodeError as e: # e.g. non-ASCII, C locale, python 3
- printWarning(pkg, 'inaccessible-filename', f, e)
- else:
- if res:
- (chunk, istext) = peek(pkgfile.path, pkg)
-
- (interpreter, interpreter_args) = script_interpreter(chunk)
-
- if doc_regex.search(f):
- if not interpreter:
- nonexec_file = True
- if not is_doc:
- printError(pkg, 'not-listed-as-documentation', f)
-
- if devel_pkg and f.endswith('.typelib'):
- printError(pkg, 'non-devel-file-in-devel-package', f)
-
- # check ldconfig call in %post and %postun
- if lib_regex.search(f):
- if devel_pkg:
- printError(pkg, 'non-devel-file-in-devel-package', f)
- if not postin:
- printError(pkg, 'library-without-ldconfig-postin', f)
- else:
- if not ldconfig_regex.search(postin):
- printError(pkg, 'postin-without-ldconfig', f)
-
- if not postun:
- printError(pkg, 'library-without-ldconfig-postun', f)
- else:
- if not ldconfig_regex.search(postun):
- printError(pkg, 'postun-without-ldconfig', f)
-
- # check depmod call in %post and %postun
- res = not is_kernel_package and kernel_modules_regex.search(f)
- if res:
- kernel_version = res.group(1)
- kernel_version_regex = re.compile(
- r'\bdepmod\s+-a.*F\s+/boot/System\.map-' +
- re.escape(kernel_version) + r'\b.*\b' +
- re.escape(kernel_version) + r'\b',
- re.MULTILINE | re.DOTALL)
-
- if not postin or not depmod_regex.search(postin):
- printError(pkg, 'module-without-depmod-postin', f)
- # check that we run depmod on the right kernel
- elif not kernel_version_regex.search(postin):
- printError(pkg, 'postin-with-wrong-depmod', f)
-
- if not postun or not depmod_regex.search(postun):
- printError(pkg, 'module-without-depmod-postun', f)
- # check that we run depmod on the right kernel
- elif not kernel_version_regex.search(postun):
- printError(pkg, 'postun-with-wrong-depmod', f)
-
- # check install-info call in %post and %postun
- if f.startswith('/usr/share/info/'):
- if not postin:
- printError(pkg,
- 'info-files-without-install-info-postin', f)
- elif not install_info_regex.search(postin):
- printError(pkg, 'postin-without-install-info', f)
-
- preun = pkg[rpm.RPMTAG_PREUN] or \
- pkg.scriptprog(rpm.RPMTAG_PREUNPROG)
- if not postun and not preun:
- printError(pkg,
- 'info-files-without-install-info-postun', f)
- elif not ((postun and install_info_regex.search(postun)) or
- (preun and install_info_regex.search(preun))):
- printError(pkg, 'postin-without-install-info', f)
-
- # check perl temp file
- if perl_temp_file_regex.search(f):
- printWarning(pkg, 'perl-temp-file', f)
-
- is_buildconfig = istext and buildconfigfile_regex.search(f)
-
- # check rpaths in buildconfig files
- if is_buildconfig:
- ln = pkg.grep(buildconfig_rpath_regex, f)
- if ln:
- printError(pkg, 'rpath-in-buildconfig', f, 'lines', ln)
-
- res = bin_regex.search(f)
- if res:
- if not mode_is_exec:
- printWarning(pkg, 'non-executable-in-bin', f,
- "%o" % perm)
- else:
- exe = res.group(1)
- if "/" not in exe:
- bindir_exes.setdefault(exe, []).append(f)
-
- if (not devel_pkg and not is_doc and
- (is_buildconfig or includefile_regex.search(f) or
- develfile_regex.search(f))):
- printWarning(pkg, 'devel-file-in-non-devel-package', f)
- if mode & 0o444 != 0o444 and perm & 0o7000 == 0:
- ok_nonreadable = False
- for regex in non_readable_regexs:
- if regex.search(f):
- ok_nonreadable = True
- break
- if not ok_nonreadable:
- printError(pkg, 'non-readable', f, "%o" % perm)
- if size == 0 and not normal_zero_length_regex.search(f) and \
- f not in ghost_files:
- printError(pkg, 'zero-length', f)
-
- if mode & stat.S_IWOTH:
- printError(pkg, 'world-writable', f, "%o" % perm)
-
- if not perl_dep_error:
- res = perl_regex.search(f)
- if res:
- if perl_version_trick:
- vers = res.group(1) + '.' + res.group(2)
- else:
- vers = res.group(1) + res.group(2)
- if not (pkg.check_versioned_dep('perl-base', vers) or
- pkg.check_versioned_dep('perl', vers)):
- printError(pkg, 'no-dependency-on',
- 'perl-base', vers)
- perl_dep_error = True
-
- if not python_dep_error:
- res = python_regex.search(f)
- if (res and not
- any((pkg.check_versioned_dep(dep, res.group(1))
- for dep in (
- 'python', 'python-base', 'python(abi)')))):
- printError(pkg, 'no-dependency-on', 'python-base',
- res.group(1))
- python_dep_error = True
-
- source_file = python_bytecode_to_script(f)
- if source_file:
- if source_file in files:
- if chunk:
- # Verify that the magic ABI value embedded in the
- # .pyc header is correct
- found_magic = pyc_magic_from_chunk(chunk)
- exp_magic, exp_version = get_expected_pyc_magic(f)
- if exp_magic and found_magic not in exp_magic:
- found_version = 'unknown'
- for (pv, pm) in _python_magic_values.items():
- if found_magic in pm:
- found_version = pv
- break
- # If expected version was from the file path,
- # issue # an error, otherwise a warning.
- msg = (pkg,
- 'python-bytecode-wrong-magic-value',
- f, "expected %s (%s), found %d (%s)" %
- (" or ".join(map(str, exp_magic)),
- exp_version or python_default_version,
- found_magic, found_version))
- if exp_version is not None:
- printError(*msg)
- else:
- printWarning(*msg)
-
- # Verify that the timestamp embedded in the .pyc
- # header matches the mtime of the .py file:
- pyc_timestamp = pyc_mtime_from_chunk(chunk)
- # If it's a symlink, check target file mtime.
- srcfile = pkg.readlink(files[source_file])
- if not srcfile:
- printWarning(
- pkg, 'python-bytecode-without-source', f)
- elif (pyc_timestamp is not None and
- pyc_timestamp != srcfile.mtime):
- cts = datetime.fromtimestamp(
- pyc_timestamp).isoformat()
- sts = datetime.fromtimestamp(
- srcfile.mtime).isoformat()
- printError(
- pkg, 'python-bytecode-inconsistent-mtime',
- f, cts, srcfile.name, sts)
- else:
- printWarning(pkg, 'python-bytecode-without-source', f)
-
- # normal executable check
- if mode & stat.S_IXUSR and perm != 0o755:
- printError(pkg, 'non-standard-executable-perm',
- f, "%o" % perm)
- if mode_is_exec:
- if f in config_files:
- printError(pkg, 'executable-marked-as-config-file', f)
- if not nonexec_file:
- # doc_regex and log_regex checked earlier, no match,
- # check rest of usual cases here. Sourced scripts have
- # their own check, so disregard them here.
- nonexec_file = f.endswith('.pc') or \
- compr_regex.search(f) or \
- includefile_regex.search(f) or \
- develfile_regex.search(f) or \
- logrotate_regex.search(f)
- if nonexec_file:
- printWarning(pkg, 'spurious-executable-perm', f)
- elif f.startswith('/etc/') and f not in config_files and \
- f not in ghost_files:
- printWarning(pkg, 'non-conffile-in-etc', f)
-
- if pkg.arch == 'noarch' and f.startswith('/usr/lib64/python'):
- printError(pkg, 'noarch-python-in-64bit-path', f)
-
- if debuginfo_package:
- if f.endswith('.debug'):
- debuginfo_debugs = True
- else:
- debuginfo_srcs = True
-
- res = man_base_regex.search(f)
- if res:
- man_basenames.add(res.group(1))
- if use_utf8 and chunk:
- # TODO: sequence based invocation
- cmd = getstatusoutput(
- '%s %s | gtbl | groff -mtty-char -Tutf8 '
- '-P-c -mandoc -w%s >%s' %
- (catcmd(f), shquote(pkgfile.path),
- shquote(man_warn_category), os.devnull),
- shell=True, lc_all="en_US.UTF-8")
- for line in cmd[1].split("\n"):
- res = man_warn_regex.search(line)
- if not res or man_nowarn_regex.search(line):
- continue
- printWarning(pkg, "manual-page-warning", f,
- line[res.end(1):])
-
- if f.endswith(".svgz") and f[0:-1] not in files \
- and scalable_icon_regex.search(f):
- printWarning(pkg, "gzipped-svg-icon", f)
-
- if f.endswith('.pem') and f not in ghost_files:
- if pkg.grep(start_certificate_regex, f):
- printWarning(pkg, 'pem-certificate', f)
- if pkg.grep(start_private_key_regex, f):
- printError(pkg, 'pem-private-key', f)
-
- # text file checks
- if istext:
- # ignore perl module shebang -- TODO: disputed...
- if f.endswith('.pm'):
- interpreter = None
- # sourced scripts should not be executable
- if sourced_script_regex.search(f):
- if interpreter:
- printError(pkg,
- 'sourced-script-with-shebang', f,
- interpreter, interpreter_args)
- if mode_is_exec:
- printError(pkg, 'executable-sourced-script',
- f, "%o" % perm)
- # ...but executed ones should
- elif interpreter or mode_is_exec or script_regex.search(f):
- if interpreter:
- res = interpreter_regex.search(interpreter)
- if (mode_is_exec or script_regex.search(f)):
- if res and res.group(1) == 'env':
- printError(pkg, 'env-script-interpreter',
- f, interpreter,
- interpreter_args)
- elif not res:
- printError(pkg, 'wrong-script-interpreter',
- f, interpreter,
- interpreter_args)
- elif not nonexec_file and not \
- (lib_path_regex.search(f) and
- f.endswith('.la')):
- printError(pkg, 'script-without-shebang', f)
-
- if not mode_is_exec and not is_doc and \
- interpreter and interpreter.startswith("/"):
- printError(pkg, 'non-executable-script', f,
- "%o" % perm, interpreter,
- interpreter_args)
- if b'\r' in chunk:
- printError(
- pkg, 'wrong-script-end-of-line-encoding', f)
- elif is_doc and not skipdocs_regex.search(f):
- if b'\r' in chunk:
- printWarning(
- pkg, 'wrong-file-end-of-line-encoding', f)
- # We check only doc text files for UTF-8-ness;
- # checking everything may be slow and can generate
- # lots of unwanted noise.
- if use_utf8 and not is_utf8(pkgfile.path):
- printWarning(pkg, 'file-not-utf8', f)
- if fsf_license_regex.search(chunk) and \
- fsf_wrong_address_regex.search(chunk):
- printError(pkg, 'incorrect-fsf-address', f)
-
- elif is_doc and chunk and compr_regex.search(f):
- ff = compr_regex.sub('', f)
- if not skipdocs_regex.search(ff):
- # compressed docs, eg. info and man files etc
- if use_utf8 and not is_utf8(pkgfile.path):
- printWarning(pkg, 'file-not-utf8', f)
-
- # normal dir check
- elif stat.S_ISDIR(mode):
- if mode & 0o1002 == 2: # world writable w/o sticky bit
- printError(pkg, 'world-writable', f, "%o" % perm)
- if perm != 0o755:
- printError(pkg, 'non-standard-dir-perm', f, "%o" % perm)
- if pkg.name not in filesys_packages and f in STANDARD_DIRS:
- printError(pkg, 'standard-dir-owned-by-package', f)
- if hidden_file_regex.search(f) and not f.endswith("/.build-id"):
- printWarning(pkg, 'hidden-file-or-dir', f)
-
- # symbolic link check
- elif stat.S_ISLNK(mode):
-
- is_so = sofile_regex.search(f)
- if not devel_pkg and is_so and not link.endswith('.so'):
- printWarning(pkg, 'devel-file-in-non-devel-package', f)
-
- res = man_base_regex.search(f)
- if res:
- man_basenames.add(res.group(1))
- else:
- res = bin_regex.search(f)
- if res:
- exe = res.group(1)
- if "/" not in exe:
- bindir_exes.setdefault(exe, [])
-
- # absolute link
- r = absolute_regex.search(link)
- if r:
- if not is_so and link not in files and \
- link not in req_names:
- is_exception = False
- for e in dangling_exceptions:
- if e[0].search(link):
- is_exception = e[1]
- break
- if is_exception:
- if is_exception not in req_names:
- printWarning(pkg, 'no-dependency-on',
- is_exception)
- else:
- printWarning(pkg, 'dangling-symlink', f, link)
- linktop = r.group(1)
- r = absolute_regex.search(f)
- if r:
- filetop = r.group(1)
- if filetop == linktop or use_relative_symlinks:
- printWarning(pkg, 'symlink-should-be-relative',
- f, link)
- # relative link
- else:
- if not is_so:
- abslink = '%s/%s' % (os.path.dirname(f), link)
- abslink = os.path.normpath(abslink)
- if abslink not in files and abslink not in req_names:
- is_exception = False
- for e in dangling_exceptions:
- if e[0].search(link):
- is_exception = e[1]
- break
- if is_exception:
- if is_exception not in req_names:
- printWarning(pkg, 'no-dependency-on',
- is_exception)
- else:
- printWarning(pkg, 'dangling-relative-symlink',
- f, link)
- pathcomponents = f.split('/')[1:]
- r = points_regex.search(link)
- lastpop = None
- mylink = None
-
- while r:
- mylink = r.group(1)
- if len(pathcomponents) == 0:
- printError(pkg, 'symlink-has-too-many-up-segments',
- f, link)
- break
- else:
- lastpop = pathcomponents[0]
- pathcomponents = pathcomponents[1:]
- r = points_regex.search(mylink)
-
- if mylink and lastpop:
- r = absolute2_regex.search(mylink)
- linktop = r.group(1)
-
- # does the link go up and then down into the same
- # directory?
- # if linktop == lastpop:
- # printWarning(pkg, 'lengthy-symlink', f, link)
-
- # have we reached the root directory?
- if len(pathcomponents) == 0 and linktop != lastpop \
- and not use_relative_symlinks:
- # relative link into other toplevel directory
- printWarning(pkg, 'symlink-should-be-absolute', f,
- link)
- # check additional segments for mistakes like
- # `foo/../bar/'
- for linksegment in mylink.split('/'):
- if linksegment == '..':
- printError(
- pkg,
- 'symlink-contains-up-and-down-segments',
- f, link)
-
- if f.startswith('/etc/cron.d/'):
- if stat.S_ISLNK(mode):
- printError(pkg, 'symlink-crontab-file', f)
-
- if mode_is_exec:
- printError(pkg, 'executable-crontab-file', f)
-
- if stat.S_IWGRP & mode or stat.S_IWOTH & mode:
- printError(pkg, 'non-owner-writeable-only-crontab-file', f)
-
- if len(log_files) and not logrotate_file:
- printWarning(pkg, 'log-files-without-logrotate', sorted(log_files))
-
- if lib_package and lib_file and non_lib_file:
- printError(pkg, 'outside-libdir-files', non_lib_file)
-
- if not use_debugsource and debuginfo_package and debuginfo_debugs and not debuginfo_srcs:
- printError(pkg, 'debuginfo-without-sources')
-
- for exe, paths in bindir_exes.items():
- if len(paths) > 1:
- printWarning(pkg, "duplicate-executable", exe, paths)
- if exe not in man_basenames:
- printWarning(pkg, "no-manual-page-for-binary", exe)
-
-
-# Create an object to enable the auto registration of the test
-check = FilesCheck()
-
-addDetails(
-'no-documentation',
-'''The package contains no documentation (README, doc, etc).
-You have to include documentation files.''',
-
-'not-listed-as-documentation',
-'''The documentation files of this package are not listed with
-the standard %doc tag.''',
-
-'non-standard-uid',
-'''A file in this package is owned by a non standard user.
-Standard users are:
-%s.''' % ", ".join(standard_users),
-
-'non-standard-gid',
-'''A file in this package is owned by a non standard group.
-Standard groups are:
-%s.''' % ", ".join(standard_groups),
-
-'library-without-ldconfig-postin',
-'''This package contains a library and provides no %post scriptlet containing
-a call to ldconfig.''',
-
-'postin-without-ldconfig',
-'''This package contains a library and its %post scriptlet doesn't call
-ldconfig.''',
-
-'library-without-ldconfig-postun',
-'''This package contains a library and provides no %postun scriptlet containing
-a call to ldconfig.''',
-
-'postun-without-ldconfig',
-'''This package contains a library and its %postun doesn't call ldconfig.''',
-
-'info-files-without-install-info-postin',
-'''This package contains info files and provides no %post scriptlet containing
-a call to install-info.''',
-
-'postin-without-install-info',
-'This package contains info files and its %post doesn\'t call install-info.',
-
-'info-files-without-install-info-postun',
-'''This package contains info files and provides no %postun scriptlet
-containing a call to install-info.''',
-
-'postun-without-install-info',
-'''This package contains info files and its %postun doesn't call
-install-info.''',
-
-'perl-temp-file',
-'''You have a perl temporary file in your package. Usually, this
-file is beginning with a dot (.) and contain "perl" in its name.''',
-
-'non-ghost-in-run',
-'''A file or directory in the package is located in /run. Files installed
-in this directory should be marked as %ghost and created at runtime to work
-properly in tmpfs /run setups.''',
-
-'systemd-unit-in-etc',
-'''A systemd unit has been packaged in /etc/systemd/system. These units should
-be installed in the system unit dir instead.''',
-
-'udev-rule-in-etc',
-'''A udev rule has been packaged in /etc/udev/rules.d. These rules should be
-installed in the system rules dir instead.''',
-
-'tmpfiles-conf-in-etc',
-'''A tmpfiles config has been packaged in /etc/tmpfiles.d. These rules should be
-installed in the system tmpfiles dir instead.''',
-
-'subdir-in-bin',
-'''The package contains a subdirectory in /usr/bin. It's not permitted to
-create a subdir there. Create it in /usr/lib/ instead.''',
-
-'backup-file-in-package',
-'''You have a file whose name looks like one for backup files, usually created
-by an editor or resulting from applying unclean (fuzzy, or ones with line
-offsets) patches.''',
-
-'version-control-internal-file',
-'''You have included file(s) internally used by a version control system
-in the package. Move these files out of the package and rebuild it.''',
-
-'htaccess-file',
-'''You have individual apache configuration .htaccess file(s) in your package.
-Replace them by a central configuration file in /etc/, according to the web
-application packaging policy for your distribution.''',
-
-'info-dir-file',
-'''You have /usr/info/dir or /usr/share/info/dir in your package. It will cause
-conflicts with other packages and thus is not allowed. Please remove it and
-rebuild your package.''',
-
-'non-conffile-in-etc',
-'''A non-executable file in your package is being installed in /etc, but is not
-a configuration file. All non-executable files in /etc should be configuration
-files. Mark the file as %config in the spec file.''',
-
-'compressed-symlink-with-wrong-ext',
-'''The symlink points to a compressed file but doesn't use the same
-extension.''',
-
-'setuid-binary',
-'''The file is setuid; this may be dangerous, especially if this
-file is setuid root. Sometimes file capabilities can be used instead of
-setuid bits.''',
-
-'setgid-binary',
-'''The file is setgid. Usually this is a packaging bug. If this is a game,
-then, you should use the proper rpm group, or location.''',
-
-'non-standard-executable-perm',
-'''A standard executable should have permission set to 0755. If you get this
-message, it means that you have a wrong executable permissions in some files
-included in your package.''',
-
-'non-executable-in-bin',
-'''A file is being installed in /usr/bin, but is not an executable. Be sure
-that the file is an executable or that it has executable permissions.''',
-
-'devel-file-in-non-devel-package',
-'''A file that is needed only e.g. when developing or building software is
-included in a non-devel package. These files should go in devel packages.''',
-
-'non-devel-file-in-devel-package',
-'''A non-development file is located in a devel package.''',
-
-'non-standard-dir-perm',
-'''A standard directory should have permission set to 0755. If you get this
-message, it means that you have wrong directory permissions in some dirs
-included in your package.''',
-
-'spurious-executable-perm',
-'''The file is installed with executable permissions, but was identified as one
-that probably should not be executable. Verify if the executable bits are
-desired, and remove if not.''',
-
-'world-writable',
-'''A file or directory in the package is installed with world writable
-permissions, which is most likely a security issue.''',
-
-'standard-dir-owned-by-package',
-'''This package owns a directory that is part of the standard hierarchy, which
-can lead to default directory permissions or ownerships being changed to
-something non-standard.''',
-
-'no-dependency-on',
-'''
-''',
-
-'cross-directory-hard-link',
-'''File is hard linked across directories. This can cause problems in
-installations where the directories are located on different devices.''',
-
-'dangling-symlink',
-'''The target of the symbolic link does not exist within this package or its
-file based dependencies. Verify spelling of the link target and that the
-target is included in a package in this package's dependency chain.''',
-
-'symlink-should-be-relative',
-'''Absolute symlinks are problematic eg. when working with chroot environments.
-symlinks(8) is a tool that can be useful for creating/dealing with relative
-symlinks at package build time.''',
-
-'dangling-relative-symlink',
-'''The target of the symbolic link does not exist within this package or its
-file based dependencies. Verify spelling of the link target and that the
-target is included in a package in this package's dependency chain.''',
-
-'symlink-has-too-many-up-segments',
-'''
-''',
-
-'symlink-should-be-absolute',
-'''
-''',
-
-'symlink-contains-up-and-down-segments',
-'''
-''',
-
-'non-readable',
-'''The file can't be read by everybody. Review if this is expected.''',
-
-'incoherent-logrotate-file',
-'''Your logrotate file should be named /etc/logrotate.d/<package name>.''',
-
-'non-root-user-log-file',
-'''If you need log files owned by a non-root user, just create a subdir in
-/var/log and put your log files in it.''',
-
-'non-root-group-log-file',
-'''If you need log files owned by a non-root group, just create a subdir in
-/var/log and put your log files in it.''',
-
-'non-ghost-file',
-'''File should be tagged %ghost.''',
-
-'outside-libdir-files',
-'''This library package must not contain non library files to allow 64
-and 32 bits versions of the package to coexist.''',
-
-'hidden-file-or-dir',
-'''The file or directory is hidden. You should see if this is normal,
-and delete it from the package if not.''',
-
-'module-without-depmod-postin',
-'''This package contains a kernel module but provides no call to depmod in the
-%post scriptlet.''',
-
-'postin-with-wrong-depmod',
-'''This package contains a kernel module but its %post scriptlet calls depmod
-for the wrong kernel.''',
-
-'module-without-depmod-postun',
-'''This package contains a kernel module but provides no call to depmod in the
-%postun scriptlet.''',
-
-'postun-with-wrong-depmod',
-'''This package contains a kernel module but its %postun scriptlet calls depmod
-for the wrong kernel.''',
-
-'log-files-without-logrotate',
-'''This package contains files in /var/log/ without adding logrotate
-configuration for them.''',
-
-'unexpanded-macro',
-'''This package contains a file whose path contains something that looks like
-an unexpanded macro; this is often the sign of a misspelling. Please check your
-specfile.''',
-
-'manifest-in-perl-module',
-'''This perl module package contains a MANIFEST or a MANIFEST.SKIP file
-in the documentation directory.''',
-
-'siteperl-in-perl-module',
-'''This perl module package installs files under the subdirectory site_perl,
-while they must appear under vendor_perl.''',
-
-'executable-marked-as-config-file',
-'''Executables must not be marked as config files because that may
-prevent upgrades from working correctly. If you need to be able to
-customize an executable, make it for example read a config file in
-/etc/sysconfig.''',
-
-'sourced-script-with-shebang',
-'''This text file contains a shebang, but is meant to be sourced, not
-executed.''',
-
-'executable-sourced-script',
-'''This text file has executable bit set, but is meant to be sourced, not
-executed.''',
-
-'wrong-script-interpreter',
-'''This script uses an interpreter which is either an inappropriate one
-or located in an inappropriate directory for packaged system software.
-
-Alternatively, if the file should not be executed, then ensure that
-it is not marked as executable.
-''',
-
-'env-script-interpreter',
-'''This script uses 'env' as an interpreter.
-For the rpm runtime dependency detection to work, the shebang
-#!/usr/bin/env python
-
-needs to be patched into
-#!/usr/bin/python
-
-otherwise the package dependency generator merely adds a dependency
-on /usr/bin/env rather than the actual interpreter /usr/bin/python.
-
-Alternatively, if the file should not be executed, then ensure that
-it is not marked as executable or don't install it in a path that
-is reserved for executables.
-''',
-
-'non-executable-script',
-'''This text file contains a shebang or is located in a path dedicated for
-executables, but lacks the executable bits and cannot thus be executed. If
-the file is meant to be an executable script, add the executable bits,
-otherwise remove the shebang or move the file elsewhere.''',
-
-'script-without-shebang',
-'''This text file has executable bits set or is located in a path dedicated
-for executables, but lacks a shebang and cannot thus be executed. If the file
-is meant to be an executable script, add the shebang, otherwise remove the
-executable bits or move the file elsewhere.''',
-
-'wrong-script-end-of-line-encoding',
-'''This script has wrong end-of-line encoding, usually caused by creation or
-modification on a non-Unix system. It will prevent its execution.''',
-
-'wrong-file-end-of-line-encoding',
-'''This file has wrong end-of-line encoding, usually caused by creation or
-modification on a non-Unix system. It could prevent it from being displayed
-correctly in some circumstances.''',
-
-'file-not-utf8',
-'''The character encoding of this file is not UTF-8. Consider converting it
-in the specfile's %prep section for example using iconv(1).''',
-
-'filename-not-utf8',
-'''The character encoding of the name of this file is not UTF-8.
-Rename it.''',
-
-'file-in-meta-package',
-'''This package seems to be a meta-package (an empty package used to require
-other packages), but it is not empty. You should remove or rename it, see the
-option MetaPackageRegexp.''',
-
-'empty-debuginfo-package',
-'''This debuginfo package contains no files. This is often a sign of binaries
-being unexpectedly stripped too early during the build, rpmbuild not being able
-to strip the binaries, the package actually being a noarch one but erratically
-packaged as arch dependent, or something else. Verify what the case is, and
-if there's no way to produce useful debuginfo out of it, disable creation of
-the debuginfo package.''',
-
-'debuginfo-without-sources',
-'''This debuginfo package appears to contain debug symbols but no source files.
-This is often a sign of binaries being unexpectedly stripped too early during
-the build, or being compiled without compiler debug flags (which again often
-is a sign of distro's default compiler flags ignored which might have security
-consequences), or other compiler flags which result in rpmbuild's debuginfo
-extraction not working as expected. Verify that the binaries are not
-unexpectedly stripped and that the intended compiler flags are used.''',
-
-'missing-dependency-to-cron',
-'''This package installs a file in /etc/cron.*/ but
-doesn't require cron to be installed. as cron is not part of the essential packages,
-your package should explicitely require cron to make sure that your cron job is
-executed. If it is an optional feature of your package, recommend or suggest cron.''',
-
-'missing-dependency-to-logrotate',
-'''This package installs a file in /etc/logrotate.d/ but
-doesn't require logrotate to be installed. Because logrotate is not part of the essential packages,
-your package should explicitely depend on logrotate to make sure that your logrotate
-job is executed. If it is an optional feature of your package, recommend or suggest logrotate.''',
-
-'missing-dependency-to-xinetd',
-'''This package installs a file in /etc/xinetd.d/ but
-doesn't require xinetd to be installed. Because xinetd is not part of the essential packages,
-your package should explicitely depend on logrotate to make sure that your xinetd
-job is executed. If it is an optional feature of your package, recommend or suggest xinetd.''',
-
-'read-error',
-'''This file could not be read. A reason for this could be that the info about
-it in the rpm header indicates that it is supposed to be a readable normal file
-but it actually is not in the filesystem. Because of this, some checks will
-be skipped.''',
-
-'inaccessible-filename',
-'''An error occurred while trying to access this file due to some characters
-in its name. Because of this, some checks will be skipped. Access could work
-with some other locale settings.''',
-
-'executable-crontab-file',
-'''This crontab file has executable bit set, which is refused by newer version
-of cron''',
-
-'non-owner-writeable-only-crontab-file',
-'''This crontab file is writeable by other users as its owner, which is refused
-by newer version of cron and insecure''',
-
-'symlink-crontab-file',
-'''This crontab file is a symbolic link, which is insecure and refused by newer
-version of cron''',
-
-'rpath-in-buildconfig',
-'''This build configuration file contains rpaths which will be introduced into
-dependent packages.''',
-
-'python-bytecode-wrong-magic-value',
-'''The "magic" ABI version embedded in this python bytecode file isn't equal
-to that of the corresponding runtime, which will force the interpreter to
-recompile the .py source every time, ignoring the saved bytecode.''',
-
-'python-bytecode-inconsistent-mtime',
-'''The timestamp embedded in this python bytecode file isn't equal to the mtime
-of the original source file, which will force the interpreter to recompile the
-.py source every time, ignoring the saved bytecode.''',
-
-'python-bytecode-without-source',
-'''This python bytecode file (.pyo/.pyc) is not accompanied by its original
-source file (.py)''',
-
-'duplicate-executable',
-'''This executable file exists in more than one standard binary directories.
-It can cause problems when dirs in $PATH are reordered.''',
-
-'no-manual-page-for-binary',
-'''Each executable in standard binary directories should have a man page.''',
-
-'manual-page-warning',
-'''This man page may contain problems that can cause it not to be formatted
-as intended.''',
-
-'incorrect-fsf-address',
-'''The Free Software Foundation address in this file seems to be outdated or
-misspelled. Ask upstream to update the address, or if this is a license file,
-possibly the entire file with a new copy available from the FSF.''',
-
-'gzipped-svg-icon',
-'''Not all desktop environments that support SVG icons support them gzipped
-(.svgz). Install the icon as plain uncompressed SVG.''',
-
-'pem-certificate',
-'''Shipping a PEM certificate is likely wrong. If used for the default
-configuration, this is insecure ( since the certificate is public ). If this
-is used for validation, ie a CA certificate store, then this must be kept up
-to date due to CA compromise. The only valid reason is for testing purpose,
-so ignore this warning if this is the case.''',
-
-'pem-private-key',
-'''Private key in a .pem file should not be shipped in a rpm, unless
-this is for testing purpose ( ie, run by the test suite ). Shipping it
-as part of the example documentation mean that someone will sooner or later
-use it and setup a insecure configuration.'''
-)
-
-for i in disallowed_dirs:
- addDetails('dir-or-file-in-%s' % '-'.join(i.split('/')[1:]),
- '''A file in the package is located in %s. It's not permitted
-for packages to install files in this directory.''' % i)
-
-
-# FilesCheck.py ends here