Exemple #1
0
    def check_file(self, pkg, filename):
        root = pkg.dirName()
        f = root + filename
        st = getstatusoutput(('desktop-file-validate', f), True)
        if st[0]:
            error_printed = False
            for line in st[1].splitlines():
                if 'error: ' in line:
                    printError(pkg, 'invalid-desktopfile', filename,
                               line.split('error: ')[1])
                    error_printed = True
            if not error_printed:
                printError(pkg, 'invalid-desktopfile', filename)
        if not is_utf8(f):
            printError(pkg, 'non-utf8-desktopfile', filename)

        cfp = RawConfigParser()
        cfp.read(f)
        binary = None
        if cfp.has_option('Desktop Entry', 'Exec'):
            binary = cfp.get('Desktop Entry', 'Exec').split(' ', 1)[0]
        if binary:
            found = False
            if binary.startswith('/'):
                found = os.path.exists(root + binary)
            else:
                for i in STANDARD_BIN_DIRS:
                    if os.path.exists(root + i + binary):
                        # no need to check if the binary is +x, rpmlint does it
                        # in another place
                        found = True
                        break
            if not found:
                printWarning(pkg, 'desktopfile-without-binary', filename,
                             binary)
    def check_url(self, pkg, tag, url):
        """Check that URL points to something that seems to exist.
           Return info() of the response if available."""
        if not self.network_enabled:
            if self.verbose:
                printInfo(pkg, 'network-checks-disabled', url)
            return

        if self.verbose:
            printInfo(pkg, 'checking-url', url,
                      '(timeout %s seconds)' % self.network_timeout)

        # Could use timeout kwarg to urlopen, but that's python >= 2.6 only
        socket.setdefaulttimeout(self.network_timeout)
        res = None
        try:
            opener = urllib2.build_opener(_HeadRedirectHandler())
            opener.addheaders = [('User-Agent',
                                  'rpmlint/%s' % Config.__version__)]
            res = opener.open(_HeadRequest(url))
        except Exception:
            e = sys.exc_info()[1]
            errstr = str(e) or repr(e) or type(e)
            printWarning(pkg, 'invalid-url', '%s:' % tag, url, errstr)
        info = None
        if res:
            info = res.info()
            res.close()
        return info
Exemple #3
0
    def check_file(self, pkg, filename):
        root = pkg.dirName()
        f = root + filename
        st = getstatusoutput(('desktop-file-validate', f), True)
        if st[0]:
            error_printed = False
            for line in st[1].splitlines():
                if 'error: ' in line:
                    printError(pkg, 'invalid-desktopfile', filename,
                               line.split('error: ')[1])
                    error_printed = True
            if not error_printed:
                printError(pkg, 'invalid-desktopfile', filename)
        if not is_utf8(f):
            printError(pkg, 'non-utf8-desktopfile', filename)

        cfp = RawConfigParser()
        cfp.read(f)
        binary = None
        if cfp.has_option('Desktop Entry', 'Exec'):
            binary = cfp.get('Desktop Entry', 'Exec').split(' ', 1)[0]
        if binary:
            found = False
            if binary.startswith('/'):
                found = os.path.exists(root + binary)
            else:
                for i in STANDARD_BIN_DIRS:
                    if os.path.exists(root + i + binary):
                        # no need to check if the binary is +x, rpmlint does it
                        # in another place
                        found = True
                        break
            if not found:
                printWarning(pkg, 'desktopfile-without-binary', filename,
                             binary)
Exemple #4
0
    def check_url(self, pkg, tag, url):
        """
        Check that URL points to something that seems to exist.
        Return info() of the response if available.
        """
        if not self.network_enabled:
            if self.verbose:
                printInfo(pkg, 'network-checks-disabled', url)
            return

        if self.verbose:
            printInfo(pkg, 'checking-url', url,
                      '(timeout %s seconds)' % self.network_timeout)

        res = None
        try:
            opener = urllib2.build_opener(_HeadRedirectHandler())
            opener.addheaders = [('User-Agent',
                                  'rpmlint/%s' % Config.__version__)]
            res = opener.open(_HeadRequest(url), timeout=self.network_timeout)
        except Exception as e:
            errstr = str(e) or repr(e) or type(e)
            printWarning(pkg, 'invalid-url', '%s:' % tag, url, errstr)
        info = None
        if res:
            info = res.info()
            res.close()
        return info
Exemple #5
0
    def check_binary(self, pkg):
        prereq = [x[0] for x in pkg.prereq()]
        files = pkg.files()

        for tag in Pkg.SCRIPT_TAGS:
            script = pkg[tag[0]]

            if not isinstance(script, list):
                prog = pkg.scriptprog(tag[1])
                if prog:
                    prog = prog.split()[0]
                self.check_aux(pkg, files, prog, script, tag[2], prereq)
            else:
                prog = pkg[tag[1]]
                for idx in range(0, len(prog)):
                    self.check_aux(pkg, files, prog[idx], script[idx], tag[2], prereq)

        ghost_files = pkg.ghostFiles()
        if ghost_files:
            postin = pkg[rpm.RPMTAG_POSTIN]
            prein = pkg[rpm.RPMTAG_PREIN]
            for f in ghost_files:
                if f in pkg.missingOkFiles():
                    continue
                if not postin and not prein:
                    printWarning(pkg, "ghost-files-without-postin")
                if (not postin or f not in postin) and (not prein or f not in prein):
                    printWarning(pkg, "postin-without-ghost-file-creation", f)
Exemple #6
0
    def check_binary(self, pkg):
        prereq = [x[0] for x in pkg.prereq()]
        files = pkg.files()

        for tag in Pkg.SCRIPT_TAGS:
            script = pkg[tag[0]]

            if not isinstance(script, list):
                prog = pkg.scriptprog(tag[1])
                if prog:
                    prog = prog.split()[0]
                self.check_aux(pkg, files, prog, script, tag[2], prereq)
            else:
                prog = pkg[tag[1]]
                for idx in range(0, len(prog)):
                    self.check_aux(pkg, files, prog[idx], script[idx], tag[2],
                                   prereq)

        ghost_files = pkg.ghostFiles()
        if ghost_files:
            postin = pkg[rpm.RPMTAG_POSTIN]
            prein = pkg[rpm.RPMTAG_PREIN]
            for f in ghost_files:
                if f in pkg.missingOkFiles():
                    continue
                if not postin and not prein:
                    printWarning(pkg, 'ghost-files-without-postin')
                if (not postin or f not in postin) and \
                        (not prein or f not in prein):
                    printWarning(pkg, 'postin-without-ghost-file-creation', f)
    def check_url(self, pkg, tag, url):
        """
        Check that URL points to something that seems to exist.
        Return info() of the response if available.
        """
        if not self.network_enabled:
            if self.verbose:
                printInfo(pkg, 'network-checks-disabled', url)
            return

        if self.verbose:
            printInfo(pkg, 'checking-url', url,
                      '(timeout %s seconds)' % self.network_timeout)

        res = None
        try:
            opener = urllib2.build_opener(_HeadRedirectHandler())
            opener.addheaders = [('User-Agent',
                                  'rpmlint/%s' % Config.__version__)]
            res = opener.open(_HeadRequest(url), timeout=self.network_timeout)
        except Exception as e:
            errstr = str(e) or repr(e) or type(e)
            printWarning(pkg, 'invalid-url', '%s:' % tag, url, errstr)
        info = None
        if res:
            with contextlib.closing(res):
                info = res.info()
        return info
Exemple #8
0
    def check(self, pkg):
        # Check only binary package
        if pkg.isSource():
            return

        prereq = [x[0] for x in pkg.prereq()]
        files = pkg.files()

        for tag in script_tags:
            script = pkg[tag[0]]

            if not isinstance(script, types.ListType):
                prog = pkg.scriptprog(tag[1])
                if prog:
                    prog = prog.split()[0]
                self.check_aux(pkg, files, prog, script, tag[2], prereq)
            else:
                prog = pkg[tag[1]]
                for idx in range(0, len(prog)):
                    self.check_aux(
                        pkg, files, prog[idx], script[idx], tag[2], prereq)

        ghost_files = pkg.ghostFiles()
        if ghost_files:
            postin = pkg[rpm.RPMTAG_POSTIN]
            prein = pkg[rpm.RPMTAG_PREIN]
            if not postin and not prein:
                printWarning(pkg, 'ghost-files-without-postin')
            else:
                for f in ghost_files:
                    if (not postin or f not in postin) and \
                       (not prein or f not in prein) and \
                       f not in pkg.missingOkFiles():
                        printWarning(pkg,
                                     'postin-without-ghost-file-creation', f)
    def check_metapackage(self, pkg, spec):
        '''SCL metapackage spec checks'''

        # Examine subpackages
        runtime = subpackage_runtime.search(spec)
        if not runtime:
            printError(pkg, 'no-runtime-in-scl-metapackage')

        build = subpackage_build.search(spec)
        if not build:
            printError(pkg, 'no-build-in-scl-metapackage')
        else:
            # Get (B)Rs section for build subpackage
            end = index_or_sub(spec[build.end():], '%package', -1)
            if 'scl-utils-build' not in \
               ' '.join(self.get_requires(spec[build.end():end])):
                printWarning(pkg,
                             'scl-build-without-requiring-scl-utils-build')

        alien = subpackage_alien.search(spec)
        if alien:
            printError(pkg, 'weird-subpackage-in-scl-metapackage',
                       alien.group()[9:])

        # Get (B)Rs section for main package
        end = index_or_sub(spec, '%package', -1)
        if 'scl-utils-build' not in \
           ' '.join(self.get_build_requires(spec[:end])):
            printError(pkg, 'scl-metapackage-without-scl-utils-build-br')

        # Enter %install section
        install_start = index_or_sub(spec, '%install')
        install_end = index_or_sub(spec, '%check')
        if not install_end:
            install_end = index_or_sub(spec, '%clean')
        if not install_end:
            install_end = index_or_sub(spec, '%files')
        if not install_end:
            install_end = index_or_sub(spec, '%changelog', -1)
        # Search %scl_install
        if not scl_install.search(spec[install_start:install_end]):
            printError(pkg, 'scl-metapackage-without-%scl_install')
        if noarch.search(spec[:install_start]) and \
           libdir.search(spec[install_start:install_end]):
            printError(pkg, 'noarch-scl-metapackage-with-libdir')

        # Analyze %files
        files = self.get_files(spec)
        if files:
            printWarning(pkg, 'scl-main-metapackage-contains-files',
                         ', '.join(files))
        if runtime:
            if not scl_files.search(
                    '\n'.join(self.get_files(spec, 'runtime'))):
                printError(pkg, 'scl-runtime-package-without-%scl_files')
        if build:
            if not scl_macros.search(
                    '\n'.join(self.get_files(spec, 'build'))):
                printError(pkg, 'scl-build-package-without-rpm-macros')
Exemple #10
0
 def _unexpanded_macros(self, pkg, tagname, value, is_url=False):
     if not value:
         return
     for match in AbstractCheck.macro_regex.findall(str(value)):
         # Do not warn about %XX URL escapes
         if is_url and re.match('^%[0-9A-F][0-9A-F]$', match, re.I):
             continue
         printWarning(pkg, 'unexpanded-macro', tagname, match)
Exemple #11
0
    def check_metapackage(self, pkg, spec):
        '''SCL metapackage spec checks'''

        # Examine subpackages
        runtime = subpackage_runtime.search(spec)
        if not runtime:
            printError(pkg, 'no-runtime-in-scl-metapackage')

        build = subpackage_build.search(spec)
        if not build:
            printError(pkg, 'no-build-in-scl-metapackage')
        else:
            # Get (B)Rs section for build subpackage
            end = index_or_sub(spec[build.end():], '%package', -1)
            if 'scl-utils-build' not in \
               ' '.join(self.get_requires(spec[build.end():end])):
                printWarning(pkg,
                             'scl-build-without-requiring-scl-utils-build')

        alien = subpackage_alien.search(spec)
        if alien:
            printError(pkg, 'weird-subpackage-in-scl-metapackage',
                       alien.group()[9:])

        # Get (B)Rs section for main package
        end = index_or_sub(spec, '%package', -1)
        if 'scl-utils-build' not in \
           ' '.join(self.get_build_requires(spec[:end])):
            printError(pkg, 'scl-metapackage-without-scl-utils-build-br')

        # Enter %install section
        install_start = index_or_sub(spec, '%install')
        install_end = index_or_sub(spec, '%check')
        if not install_end:
            install_end = index_or_sub(spec, '%clean')
        if not install_end:
            install_end = index_or_sub(spec, '%files')
        if not install_end:
            install_end = index_or_sub(spec, '%changelog', -1)
        # Search %scl_install
        if not scl_install.search(spec[install_start:install_end]):
            printError(pkg, 'scl-metapackage-without-%scl_install')
        if noarch.search(spec[:install_start]) and \
           libdir.search(spec[install_start:install_end]):
            printError(pkg, 'noarch-scl-metapackage-with-libdir')

        # Analyze %files
        files = self.get_files(spec)
        if files:
            printWarning(pkg, 'scl-main-metapackage-contains-files',
                         ', '.join(files))
        if runtime:
            if not scl_files.search('\n'.join(self.get_files(spec,
                                                             'runtime'))):
                printError(pkg, 'scl-runtime-package-without-%scl_files')
        if build:
            if not scl_macros.search('\n'.join(self.get_files(spec, 'build'))):
                printError(pkg, 'scl-build-package-without-rpm-macros')
Exemple #12
0
    def check_scl_spec(self, pkg, spec):
        '''SCL ready spec checks'''

        # For the entire spec
        if not pkg_name.search(spec):
            printWarning(pkg, 'missing-pkg_name-definition')
        if scl_prefix_noncond.search(self.remove_scl_conds(spec)):
            printWarning(pkg, 'scl-prefix-without-condition')
        if not scl_prefix.search(self.get_name(spec)):
            printError(pkg, 'name-without-scl-prefix')
        for item in self.get_obsoletes_and_conflicts(spec):
            if not scl_prefix.search(item):
                printError(pkg, 'obsoletes-or-conflicts-without-scl-prefix')
                break
        for item in self.get_provides(spec):
            if not scl_prefix.search(item):
                printError(pkg, 'provides-without-scl-prefix')
                break
        setup_opts = setup.search(spec)
        if setup_opts:
            if '-n' not in setup_opts.groups()[0]:
                printError(pkg, 'scl-setup-without-n')

        # Examine main package and subpackages one by one
        borders = []
        borders.append(0)  # main package starts at the beginning
        while True:
            more = subpackage_any.search(spec[borders[-1]:])
            if not more:
                break
            splits = more.groups()[1].split()
            if len(splits) > 1 and splits[0] == '-n':
                if not scl_prefix_start.search(splits[-1]):
                    printError(pkg, 'subpackage-with-n-without-scl-prefix')
            # current end is counted only from last one
            borders.append(borders[-1] + more.end())
        subpackages = [(borders[i], borders[i + 1])
                       for i in range(len(borders) - 1)]
        for subpackage in subpackages:
            ok = False
            for require in self.get_requires(
                    spec[subpackage[0]:subpackage[1]]):
                # Remove flase entries
                if not require or require == ':':
                    continue
                # If it starts with %{name}, it,s fine
                # If it starts with SCL prefix, it's fine
                # If it is scl-runtime, it's the best
                if name_small.search(require) or \
                   scl_prefix_start.search(require) or \
                   scl_runtime.match(require):
                    ok = True
                    break
            if not ok:
                printError(pkg,
                           'doesnt-require-scl-runtime-or-other-scl-package')
                break
 def _unexpanded_macros(self, pkg, tagname, value, is_url=False):
     if not value:
         return
     # str(value) because value might be a list
     for match in AbstractCheck.macro_regex.findall(str(value)):
         # Do not warn about %XX URL escapes
         if is_url and re.match('^%[0-9A-F][0-9A-F]$', match, re.I):
             continue
         printWarning(pkg, 'unexpanded-macro', tagname, match)
    def check_scl_spec(self, pkg, spec):
        '''SCL ready spec checks'''

        # For the entire spec
        if not pkg_name.search(spec):
            printWarning(pkg, 'missing-pkg_name-definition')
        if scl_prefix_noncond.search(self.remove_scl_conds(spec)):
            printWarning(pkg, 'scl-prefix-without-condition')
        if not scl_prefix.search(self.get_name(spec)):
            printError(pkg, 'name-without-scl-prefix')
        for item in self.get_obsoletes_and_conflicts(spec):
            if not scl_prefix.search(item):
                printError(pkg, 'obsoletes-or-conflicts-without-scl-prefix')
                break
        for item in self.get_provides(spec):
            if not scl_prefix.search(item):
                printError(pkg, 'provides-without-scl-prefix')
                break
        setup_opts = setup.search(spec)
        if setup_opts:
            if '-n' not in setup_opts.groups()[0]:
                printError(pkg, 'scl-setup-without-n')

        # Examine main package and subpackages one by one
        borders = []
        borders.append(0)  # main package starts at the beginning
        while True:
            more = subpackage_any.search(spec[borders[-1]:])
            if not more:
                break
            splits = more.groups()[1].split()
            if len(splits) > 1 and splits[0] == '-n':
                if not scl_prefix_start.search(splits[-1]):
                    printError(pkg, 'subpackage-with-n-without-scl-prefix')
            # current end is counted only from last one
            borders.append(borders[-1]+more.end())
        subpackages = [(borders[i], borders[i+1])
                       for i in range(len(borders)-1)]
        for subpackage in subpackages:
            ok = False
            for require in self.get_requires(spec[subpackage[0]:subpackage[1]]):
                # Remove flase entries
                if not require or require == ':':
                    continue
                # If it starts with %{name}, it,s fine
                # If it starts with SCL prefix, it's fine
                # If it is scl-runtime, it's the best
                if name_small.search(require) or \
                   scl_prefix_start.search(require) or \
                   scl_runtime.match(require):
                    ok = True
                    break
            if not ok:
                printError(pkg,
                           'doesnt-require-scl-runtime-or-other-scl-package')
                break
Exemple #15
0
 def _unexpanded_macros(self, pkg, tagname, value, is_url=False):
     if not value:
         return
     if not isinstance(value, (list, tuple)):
         value = [value]
     for val in value:
         for match in AbstractCheck.macro_regex.findall(val):
             # Do not warn about %XX URL escapes
             if is_url and re.match('^%[0-9A-F][0-9A-F]$', match, re.I):
                 continue
             printWarning(pkg, 'unexpanded-macro', tagname, match)
Exemple #16
0
    def check_binary(self, pkg):
        config_files = pkg.configFiles()
        noreplace_files = pkg.noreplaceFiles()

        for c in config_files:
            if c.startswith("/var/lib/games/"):
                printError(pkg, "score-file-must-not-be-conffile", c)
            elif not c.startswith("/etc/") and not c.startswith("/var/"):
                printWarning(pkg, "non-etc-or-var-file-marked-as-conffile", c)

            if c not in noreplace_files:
                printWarning(pkg, "conffile-without-noreplace-flag", c)
Exemple #17
0
 def check_binary(self, pkg):
     files = pkg.files()
     if not files:
         return
     try:
         # check for files then
         for c in self.checks_:
             for f in files:
                 if c['file_re'].search(f) and \
                         not c['name_re'].search(pkg.name):
                     raise NamingPolicyNotAppliedException
     except NamingPolicyNotAppliedException:
         printWarning(pkg, c['pkg_name'] + '-naming-policy-not-applied', f)
 def check_binary(self, pkg):
     files = pkg.files()
     if not files:
         return
     try:
         # check for files then
         for c in self.checks_:
             for f in files:
                 if c['file_re'].search(f) and \
                         not c['name_re'].search(pkg.name):
                     raise NamingPolicyNotAppliedException
     except NamingPolicyNotAppliedException:
         printWarning(pkg, c['pkg_name'] + '-naming-policy-not-applied', f)
Exemple #19
0
    def check_metapackage(self, pkg, spec):
        """SCL metapackage spec checks"""

        # Examine subpackages
        runtime = subpackage_runtime.search(spec)
        if not runtime:
            printError(pkg, "no-runtime-in-scl-metapackage")

        build = subpackage_build.search(spec)
        if not build:
            printError(pkg, "no-build-in-scl-metapackage")
        else:
            # Get (B)Rs section for build subpackage
            end = index_or_sub(spec[build.end() :], "%package", -1)
            if "scl-utils-build" not in " ".join(self.get_requires(spec[build.end() : end])):
                printWarning(pkg, "scl-build-without-requiring-scl-utils-build")

        alien = subpackage_alien.search(spec)
        if alien:
            printError(pkg, "weird-subpackage-in-scl-metapackage", alien.group()[9:])

        # Get (B)Rs section for main package
        end = index_or_sub(spec, "%package", -1)
        if "scl-utils-build" not in " ".join(self.get_build_requires(spec[:end])):
            printError(pkg, "scl-metapackage-without-scl-utils-build-br")

        # Enter %install section
        install_start = index_or_sub(spec, "%install")
        install_end = index_or_sub(spec, "%check")
        if not install_end:
            install_end = index_or_sub(spec, "%clean")
        if not install_end:
            install_end = index_or_sub(spec, "%files")
        if not install_end:
            install_end = index_or_sub(spec, "%changelog", -1)
        # Search %scl_install
        if not scl_install.search(spec[install_start:install_end]):
            printError(pkg, "scl-metapackage-without-%scl_install")
        if noarch.search(spec[:install_start]) and libdir.search(spec[install_start:install_end]):
            printError(pkg, "noarch-scl-metapackage-with-libdir")

        # Analyze %files
        files = self.get_files(spec)
        if files:
            printWarning(pkg, "scl-main-metapackage-contains-files", ", ".join(files))
        if runtime:
            if not scl_files.search("\n".join(self.get_files(spec, "runtime"))):
                printError(pkg, "scl-runtime-package-without-%scl_files")
        if build:
            if not scl_macros.search("\n".join(self.get_files(spec, "build"))):
                printError(pkg, "scl-build-package-without-rpm-macros")
Exemple #20
0
    def check(self, pkg):
        # Check only binary package
        if pkg.isSource():
            return

        initscript_list = []
        for fname, pkgfile in pkg.files().items():

            if not fname.startswith('/etc/init.d/') and \
                    not fname.startswith('/etc/rc.d/init.d/'):
                continue

            basename = os.path.basename(fname)
            initscript_list.append(basename)
            if pkgfile.mode & 0500 != 0500:
                printError(pkg, 'init-script-non-executable', fname)

            if "." in basename:
                printError(pkg, 'init-script-name-with-dot', fname)

            # check chkconfig call in %post and %preun
            postin = pkg[rpm.RPMTAG_POSTIN] or \
                pkg.scriptprog(rpm.RPMTAG_POSTINPROG)
            if not postin:
                printError(pkg, 'init-script-without-chkconfig-postin', fname)
            elif not chkconfig_regex.search(postin):
                printError(pkg, 'postin-without-chkconfig', fname)

            preun = pkg[rpm.RPMTAG_PREUN] or \
                pkg.scriptprog(rpm.RPMTAG_PREUNPROG)
            if not preun:
                printError(pkg, 'init-script-without-chkconfig-preun', fname)
            elif not chkconfig_regex.search(preun):
                printError(pkg, 'preun-without-chkconfig', fname)

            status_found = False
            reload_found = False
            chkconfig_content_found = False
            subsys_regex_found = False
            in_lsb_tag = False
            in_lsb_description = False
            lastline = ''
            lsb_tags = {}
            # check common error in file content
            content = None
            try:
                content = Pkg.readlines(pkgfile.path)
            except Exception, e:
                printWarning(pkg, 'read-error', e)
                continue
Exemple #21
0
 def check_summary(self, pkg, lang, ignored_words):
     summary = pkg.langtag(rpm.RPMTAG_SUMMARY, lang)
     if use_utf8:
         if not Pkg.is_utf8_bytestr(summary):
             printError(pkg, 'tag-not-utf8', 'Summary', lang)
         summary = Pkg.to_unicode(summary)
     else:
         summary = Pkg.b2s(summary)
     self._unexpanded_macros(pkg, 'Summary(%s)' % lang, summary)
     spell_check(pkg, summary, 'Summary(%s)', lang, ignored_words)
     if '\n' in summary:
         printError(pkg, 'summary-on-multiple-lines', lang)
     if summary[0] != summary[0].upper():
         printWarning(pkg, 'summary-not-capitalized', lang, summary)
     if summary[-1] == '.':
         printWarning(pkg, 'summary-ended-with-dot', lang, summary)
     if len(summary) > max_line_len:
         printError(pkg, 'summary-too-long', lang, summary)
     if leading_space_regex.search(summary):
         printError(pkg, 'summary-has-leading-spaces', lang, summary)
     res = forbidden_words_regex.search(summary)
     if res and Config.getOption('ForbiddenWords'):
         printWarning(pkg, 'summary-use-invalid-word', lang, res.group(1))
     if pkg.name:
         sepchars = r'[\s%s]' % punct
         res = re.search(r'(?:^|\s)(%s)(?:%s|$)' %
                         (re.escape(pkg.name), sepchars),
                         summary, re.IGNORECASE | re.UNICODE)
         if res:
             printWarning(pkg, 'name-repeated-in-summary', lang,
                          res.group(1))
Exemple #22
0
    def check(self, pkg):

        if pkg.isSource():
            return

        alt_files = set()
        for script in (pkg.header[tag]
                       for tag in (rpm.RPMTAG_POSTIN, rpm.RPMTAG_PREIN,
                                   rpm.RPMTAG_POSTTRANS)):
            alt_files.update(self.read_ghost_files(Pkg.b2s(script)))

        files = pkg.files()
        ghost_files = pkg.ghostFiles()

        for af in alt_files:
            # /etc/alternatives/$(basename) should be a ghost file
            etc_alt_file = "/etc/alternatives/%s" % os.path.basename(af)

            if etc_alt_file not in files:
                printWarning(pkg, 'suse-alternative-link-missing',
                             etc_alt_file)
            elif etc_alt_file not in ghost_files:
                printWarning(pkg, 'suse-alternative-link-not-ghost',
                             etc_alt_file)

            # generic-name should be a symlink to /etc/alternatives/$(basename)
            if af not in files:
                printWarning(pkg, 'suse-alternative-generic-name-missing', af)
            elif not stat.S_ISLNK(files[af].mode):
                printWarning(pkg, 'suse-alternative-generic-name-not-symlink',
                             af)
Exemple #23
0
 def check_summary(self, pkg, lang, ignored_words):
     summary = pkg.langtag(rpm.RPMTAG_SUMMARY, lang)
     if use_utf8:
         if not Pkg.is_utf8_bytestr(summary):
             printError(pkg, 'tag-not-utf8', 'Summary', lang)
         summary = Pkg.to_unicode(summary)
     else:
         summary = Pkg.b2s(summary)
     self._unexpanded_macros(pkg, 'Summary(%s)' % lang, summary)
     spell_check(pkg, summary, 'Summary(%s)', lang, ignored_words)
     if '\n' in summary:
         printError(pkg, 'summary-on-multiple-lines', lang)
     if summary[0] != summary[0].upper():
         printWarning(pkg, 'summary-not-capitalized', lang, summary)
     if summary[-1] == '.':
         printWarning(pkg, 'summary-ended-with-dot', lang, summary)
     if len(summary) > max_line_len:
         printError(pkg, 'summary-too-long', lang, summary)
     if leading_space_regex.search(summary):
         printError(pkg, 'summary-has-leading-spaces', lang, summary)
     res = forbidden_words_regex.search(summary)
     if res and Config.getOption('ForbiddenWords'):
         printWarning(pkg, 'summary-use-invalid-word', lang, res.group(1))
     if pkg.name:
         sepchars = '[\s' + punct + ']'
         res = re.search('(?:^|\s)(%s)(?:%s|$)' %
                         (re.escape(pkg.name), sepchars),
                         summary, re.IGNORECASE | re.UNICODE)
         if res:
             printWarning(pkg, 'name-repeated-in-summary', lang,
                          res.group(1))
Exemple #24
0
    def check(self, pkg):

        if pkg.isSource():
            return

        alt_files = set()
        for script in (pkg.header[tag]
                       for tag in (rpm.RPMTAG_POSTIN,
                                   rpm.RPMTAG_PREIN,
                                   rpm.RPMTAG_POSTTRANS)):
            alt_files.update(self.read_ghost_files(script))

        files = pkg.files()
        ghost_files = pkg.ghostFiles()

        for af in alt_files:
            # /etc/alternatives/$(basename) should be a ghost file
            etc_alt_file = "/etc/alternatives/%s" % os.path.basename(af)

            if etc_alt_file not in files:
                printWarning(pkg,
                             'suse-alternative-link-missing', etc_alt_file)
            elif etc_alt_file not in ghost_files:
                printWarning(pkg,
                             'suse-alternative-link-not-ghost', etc_alt_file)

            # generic-name should be a symlink to /etc/alternatives/$(basename)
            if af not in files:
                printWarning(pkg,
                             'suse-alternative-generic-name-missing', af)
            elif not stat.S_ISLNK(files[af].mode):
                printWarning(pkg,
                             'suse-alternative-generic-name-not-symlink', af)
Exemple #25
0
 def check_source(self, pkg):
     # process file list
     spec_file = None
     for fname, pkgfile in pkg.files().items():
         if fname.endswith('.spec'):
             if spec_file:
                 printError(pkg, 'multiple-specfiles', spec_file, fname)
             else:
                 spec_file = fname
         elif source_regex.search(fname) and compress_ext and \
                 not fname.endswith(compress_ext):
             printWarning(pkg, 'source-or-patch-not-compressed',
                          compress_ext, fname)
         perm = pkgfile.mode & 0o7777
         if perm not in valid_src_perms:
             printWarning(pkg, 'strange-permission', fname, "%o" % perm)
Exemple #26
0
 def check_source(self, pkg):
     # process file list
     spec_file = None
     for fname, pkgfile in pkg.files().items():
         if fname.endswith('.spec'):
             if spec_file:
                 printError(pkg, 'multiple-specfiles', spec_file, fname)
             else:
                 spec_file = fname
         elif source_regex.search(fname) and compress_ext and \
                 not fname.endswith(compress_ext):
             printWarning(pkg, 'source-or-patch-not-compressed',
                          compress_ext, fname)
         perm = pkgfile.mode & 0o7777
         if perm not in valid_src_perms:
             printWarning(pkg, 'strange-permission', fname, "%o" % perm)
    def check_file(self, pkg, filename):
        pkgfile = pkg.files()[filename]

        if not (stat.S_ISREG(pkgfile.mode) and
                pkgfile.magic.startswith('POSIX shell script')):
            return

        try:
            status, output = Pkg.getstatusoutput(["dash", "-n", filename])
            if status == 2:
                printWarning(pkg, "bin-sh-syntax-error", filename)
            status, output = Pkg.getstatusoutput(
                ["checkbashisms", filename])
            if status == 1:
                printInfo(pkg, "potential-bashisms", filename)
        except (FileNotFoundError, UnicodeDecodeError):
            pass
Exemple #28
0
    def check(self, pkg):
        for fname, pkgfile in pkg.files().items():
            path = pkgfile.path
            if zip_regex.search(fname) and os.path.exists(path) and \
               stat.S_ISREG(os.lstat(path)[stat.ST_MODE]) and \
               zipfile.is_zipfile(path):
                z = None  # TODO ZipFile is context manager in 2.7+
                try:
                    z = zipfile.ZipFile(path, 'r')
                    badcrc = z.testzip()
                    if badcrc:
                        printError(pkg, 'bad-crc-in-zip', badcrc, fname)
                except zipfile.error:
                    printWarning(pkg, 'unable-to-read-zip',
                                 '%s: %s' % (fname, sys.exc_info()[1]))
                else:
                    compressed = False
                    for zinfo in z.infolist():
                        if zinfo.compress_type != zipfile.ZIP_STORED:
                            compressed = True
                            break
                    if not compressed:
                        printWarning(pkg, 'uncompressed-zip', fname)

                    # additional jar checks
                    if jar_regex.search(fname):
                        try:
                            mf = Pkg.b2s(z.read('META-INF/MANIFEST.MF'))
                            if classpath_regex.search(mf):
                                printWarning(pkg, 'class-path-in-manifest',
                                             fname)
                        except KeyError:
                            # META-INF/* are optional:
                            # http://java.sun.com/j2se/1.4/docs/guide/jar/jar.html
                            pass
                        try:
                            zinfo = z.getinfo('META-INF/INDEX.LIST')
                            if not want_indexed_jars:
                                printWarning(pkg, 'jar-indexed', fname)
                        except KeyError:
                            if want_indexed_jars:
                                printWarning(pkg, 'jar-not-indexed', fname)
                            pass

                z and z.close()
Exemple #29
0
    def check(self, pkg):
        for fname, pkgfile in pkg.files().items():
            path = pkgfile.path
            if zip_regex.search(fname) and os.path.exists(path) and \
               stat.S_ISREG(os.lstat(path)[stat.ST_MODE]) and \
               zipfile.is_zipfile(path):
                z = None  # TODO ZipFile is context manager in 2.7+
                try:
                    z = zipfile.ZipFile(path, 'r')
                    badcrc = z.testzip()
                    if badcrc:
                        printError(pkg, 'bad-crc-in-zip', badcrc, fname)
                except zipfile.error:
                    printWarning(pkg, 'unable-to-read-zip', '%s: %s' %
                                 (fname, sys.exc_info()[1]))
                else:
                    compressed = False
                    for zinfo in z.infolist():
                        if zinfo.compress_type != zipfile.ZIP_STORED:
                            compressed = True
                            break
                    if not compressed:
                        printWarning(pkg, 'uncompressed-zip', fname)

                    # additional jar checks
                    if jar_regex.search(fname):
                        try:
                            mf = Pkg.b2s(z.read('META-INF/MANIFEST.MF'))
                            if classpath_regex.search(mf):
                                printWarning(pkg,
                                             'class-path-in-manifest', fname)
                        except KeyError:
                            # META-INF/* are optional:
                            # http://java.sun.com/j2se/1.4/docs/guide/jar/jar.html
                            pass
                        try:
                            zinfo = z.getinfo('META-INF/INDEX.LIST')
                            if not want_indexed_jars:
                                printWarning(pkg, 'jar-indexed', fname)
                        except KeyError:
                            if want_indexed_jars:
                                printWarning(pkg, 'jar-not-indexed', fname)
                            pass

                z and z.close()
Exemple #30
0
    def check_binary(self, pkg):
        '''SCL binary package checks'''
        # Assume that no dash in package name means no SCL
        splits = pkg.name.split('-')
        if len(splits) < 2:
            return
        scl_name = splits[0]
        # While we are here, check if it's a runtime/build package
        is_runtime = splits[-1] == 'runtime'
        is_build = splits[-1] == 'build'
        del splits

        # Now test if there is /opt/foo/ dir
        good = False
        for fname in pkg.files().keys():
            if startdir.search(fname):
                good = True
                break
        if not good:
            return

        # Test if our dir is named the same way as scl
        good = True
        for fname in pkg.files().keys():
            if not startdir.search(fname):
                if allowed_etc.search(fname) or allowed_var.search(fname) or \
                   fname.startswith('/usr/bin/'):
                    continue
                if fname.startswith('/etc/rpm/'):
                    if not is_build:
                        printWarning(pkg, 'scl-rpm-macros-outside-of-build',
                                     fname)
                    continue
                if is_runtime and \
                   fname == os.path.join('/etc/scl/prefixes', scl_name):
                    continue
                printError(pkg, 'file-outside-of-scl-tree', fname)
            else:
                if fname.split('/')[3] != scl_name:
                    good = False

        if not good:
            printError(pkg, 'scl-name-screwed-up')
 def check_description(self, pkg, lang, ignored_words):
     description = pkg.langtag(rpm.RPMTAG_DESCRIPTION, lang)
     self._unexpanded_macros(pkg, '%%description -l %s' % lang, description)
     utf8desc = description
     if use_utf8:
         utf8desc = Pkg.to_utf8(description).decode('utf-8')
     spell_check(pkg, utf8desc, '%%description -l %s', lang, ignored_words)
     for l in utf8desc.splitlines():
         if len(l) > max_line_len:
             printError(pkg, 'description-line-too-long', lang, l)
         res = forbidden_words_regex.search(l)
         if res and Config.getOption('ForbiddenWords'):
             printWarning(pkg, 'description-use-invalid-word', lang,
                          res.group(1))
         res = tag_regex.search(l)
         if res:
             printWarning(pkg, 'tag-in-description', lang, res.group(1))
     if use_utf8 and not Pkg.is_utf8_str(description):
         printError(pkg, 'tag-not-utf8', '%description', lang)
 def check_description(self, pkg, lang, ignored_words):
     description = pkg.langtag(rpm.RPMTAG_DESCRIPTION, lang)
     self._unexpanded_macros(pkg, '%%description -l %s' % lang, description)
     utf8desc = description
     if use_utf8:
         utf8desc = Pkg.to_utf8(description).decode('utf-8')
     spell_check(pkg, utf8desc, '%%description -l %s', lang, ignored_words)
     for l in utf8desc.splitlines():
         if len(l) > max_line_len:
             printError(pkg, 'description-line-too-long', lang, l)
         res = forbidden_words_regex.search(l)
         if res and Config.getOption('ForbiddenWords'):
             printWarning(pkg, 'description-use-invalid-word', lang,
                          res.group(1))
         res = tag_regex.search(l)
         if res:
             printWarning(pkg, 'tag-in-description', lang, res.group(1))
     if use_utf8 and not Pkg.is_utf8_str(description):
         printError(pkg, 'tag-not-utf8', '%description', lang)
    def check_binary(self, pkg):
        '''SCL binary package checks'''
        # Assume that no dash in package name means no SCL
        splits = pkg.name.split('-')
        if len(splits) < 2:
            return
        scl_name = splits[0]
        # While we are here, check if it's a runtime/build package
        is_runtime = splits[-1] == 'runtime'
        is_build = splits[-1] == 'build'
        del splits

        # Now test if there is /opt/foo/ dir
        good = False
        for fname in pkg.files().keys():
            if startdir.search(fname):
                good = True
                break
        if not good:
            return

        # Test if our dir is named the same way as scl
        good = True
        for fname in pkg.files().keys():
            if not startdir.search(fname):
                if allowed_etc.search(fname) or allowed_var.search(fname) or \
                   fname.startswith('/usr/bin/'):
                    continue
                if fname.startswith('/etc/rpm/'):
                    if not is_build:
                        printWarning(pkg, 'scl-rpm-macros-outside-of-build',
                                     fname)
                    continue
                if is_runtime and \
                   fname == os.path.join('/etc/scl/prefixes', scl_name):
                    continue
                printError(pkg, 'file-outside-of-scl-tree', fname)
            else:
                if fname.split('/')[3] != scl_name:
                    good = False

        if not good:
            printError(pkg, 'scl-name-screwed-up')
Exemple #34
0
    def __checkRequirements(self, pkg):

        doc_files = pkg.docFiles()
        files = pkg.files()

        reqs = {}
        for fname, pkgfile in files.items():
            reqs[fname] = [x[0] for x in pkgfile.requires]

        core_reqs = {}  # dependencies of non-doc files
        doc_reqs = {}  # dependencies of doc files

        for dep in pkg.header.dsFromHeader():
            # skip deps which were found by find-requires
            if dep.Flags() & rpm.RPMSENSE_FIND_REQUIRES != 0:
                continue
            core_reqs[dep.N()] = []

        # register things which are provided by the package
        for i in pkg.header[rpm.RPMTAG_PROVIDES]:
            core_reqs[b2s(i)] = []
        for i in files:
            core_reqs[i] = []

        for i in files:
            if not reqs[i]:
                continue  # skip empty dependencies
            if i in doc_files:
                target = doc_reqs
            else:
                target = core_reqs

            for r in reqs[i]:
                if r not in target:
                    target[r] = []
                target[r].append(i)

        # go through the calculated requirements of the %doc files
        for (dep, req_files) in doc_reqs.items():
            if dep not in core_reqs:
                for f in req_files:
                    printWarning(pkg, "doc-file-dependency", f, dep)
Exemple #35
0
    def __checkRequirements(self, pkg):

        doc_files = pkg.docFiles()
        files = pkg.files()

        reqs = {}
        for fname, pkgfile in files.items():
            reqs[fname] = [x[0] for x in pkgfile.requires]

        core_reqs = {}  # dependencies of non-doc files
        doc_reqs = {}   # dependencies of doc files

        for dep in pkg.header.dsFromHeader():
            # skip deps which were found by find-requires
            if dep.Flags() & rpm.RPMSENSE_FIND_REQUIRES != 0:
                continue
            core_reqs[dep.N()] = []

        # register things which are provided by the package
        for i in pkg.header[rpm.RPMTAG_PROVIDES]:
            core_reqs[b2s(i)] = []
        for i in files:
            core_reqs[i] = []

        for i in files:
            if not reqs[i]:
                continue  # skip empty dependencies
            if i in doc_files:
                target = doc_reqs
            else:
                target = core_reqs

            for r in reqs[i]:
                if r not in target:
                    target[r] = []
                target[r].append(i)

        # go through the calculated requirements of the %doc files
        for (dep, req_files) in doc_reqs.items():
            if dep not in core_reqs:
                for f in req_files:
                    printWarning(pkg, "doc-file-dependency", f, dep)
Exemple #36
0
    def check(self, pkg):
        # Check only binary package
        if pkg.isSource():
            return

        var_list = []
        usr_list = []

        for fname in pkg.files():
            s = FHSCheck.usr_regex.search(fname)
            if s:
                d = s.group(1)
                if d not in FHSCheck.usr_subdir and d not in usr_list:
                    printWarning(pkg, "non-standard-dir-in-usr", d)
                    usr_list.append(d)
            else:
                s = FHSCheck.var_regex.search(fname)
                if s:
                    d = s.group(1)
                    if d in var_list:
                        continue
                    if d in FHSCheck.var_fsstnd:
                        printWarning(pkg, "FSSTND-dir-in-var", fname)
                        var_list.append(d)
                    elif d not in FHSCheck.var_subdir:
                        printWarning(pkg, "non-standard-dir-in-var", d)
                        var_list.append(d)
Exemple #37
0
    def check_url(self, pkg, tag, url):
        """Check that URL points to something that seems to exist.
           Return info() of the response if available."""
        if not self.network_enabled:
            if self.verbose:
                printInfo(pkg, 'network-checks-disabled', url)
            return

        if self.verbose:
            printInfo(pkg, 'checking-url', url,
                      '(timeout %s seconds)' % self.network_timeout)

        # Could use timeout kwarg to urlopen, but that's python >= 2.6 only
        socket.setdefaulttimeout(self.network_timeout)
        res = None
        try:
            opener = urllib2.build_opener(_HeadRedirectHandler())
            opener.addheaders = [('User-Agent',
                                  'rpmlint/%s' % Config.__version__)]
            res = opener.open(_HeadRequest(url))
        except Exception, e:
            errstr = str(e) or repr(e) or type(e)
            printWarning(pkg, 'invalid-url', '%s:' % tag, url, errstr)
Exemple #38
0
    def check(self, pkg):
        # Check only binary package
        if pkg.isSource():
            return

        pre = pkg[rpm.RPMTAG_PREIN] or pkg.scriptprog(rpm.RPMTAG_PREINPROG)
        post = pkg[rpm.RPMTAG_POSTIN] or pkg.scriptprog(rpm.RPMTAG_POSTINPROG)

        preun = pkg[rpm.RPMTAG_PREUN] or pkg.scriptprog(rpm.RPMTAG_PREUNPROG)
        postun = pkg[rpm.RPMTAG_POSTUN] or pkg.scriptprog(rpm.RPMTAG_POSTUNPROG)

        for fname, pkgfile in pkg.files().items():

            if CHECKED_UNITS_REGEXP.search(fname):
                processed = {'pre': False, 'post': False, 'preun': False, 'postun': False}

                escaped_basename = re.escape(os.path.basename(fname))
                PRE_POST_PATTERN = re.compile(r'for service in .*' + escaped_basename)
                PREUN_PATTERN = re.compile(r'systemctl stop .*' + escaped_basename)
                POSTUN_PATTERN = re.compile(r'systemctl try-restart .*' + escaped_basename)

                for line in pre.split("\n"):
                    if PRE_POST_PATTERN.search(line):
                        processed['pre'] = True
                        break
                for line in post.split("\n"):
                    if PRE_POST_PATTERN.search(line):
                        processed['post'] = True
                        break
                for line in preun.split("\n"):
                    if PREUN_PATTERN.search(line):
                        processed['preun'] = True
                        break
                for line in postun.split("\n"):
                    if POSTUN_PATTERN.search(line):
                        processed['postun'] = True
                        break

                if not processed['pre']:
                    printWarning(pkg, 'systemd-service-without-service_add_pre', os.path.basename(fname))
                if not processed['post']:
                    printWarning(pkg, 'systemd-service-without-service_add_post', os.path.basename(fname))
                if not processed['preun']:
                    printWarning(pkg, 'systemd-service-without-service_del_preun', os.path.basename(fname))
                if not processed['postun']:
                    printWarning(pkg, 'systemd-service-without-service_del_postun', os.path.basename(fname))
    def check(self, pkg):
        # Check only binary package
        if pkg.isSource():
            return

        pre = pkg[rpm.RPMTAG_PREIN] or pkg.scriptprog(pkg[rpm.RPMTAG_PREINPROG])
        post = pkg[rpm.RPMTAG_POSTIN] or pkg.scriptprog(pkg[rpm.RPMTAG_POSTINPROG])

        preun = pkg[rpm.RPMTAG_PREUN] or pkg.scriptprog(pkg[rpm.RPMTAG_PREUNPROG])
        postun = pkg[rpm.RPMTAG_POSTUN] or pkg.scriptprog(pkg[rpm.RPMTAG_POSTUNPROG])

        for fname, pkgfile in pkg.files().items():

            if CHECKED_UNITS_REGEXP.search( fname ):
                processed = { 'pre': False, 'post': False, 'preun': False, 'postun': False }

                escaped_basename = re.escape( os.path.basename( fname ) )
                PRE_POST_PATTERN = re.compile( 'for service in .*' + escaped_basename )
                PREUN_PATTERN = re.compile( 'systemctl stop .*' + escaped_basename )
                POSTUN_PATTERN = re.compile( 'systemctl try-restart .*' + escaped_basename )
                
                for line in pre.split( "\n" ):
                    if PRE_POST_PATTERN.search( line ):
                        processed['pre'] = True
                        break
                for line in post.split( "\n" ):
                    if PRE_POST_PATTERN.search( line ):
                        processed['post'] = True
                        break
                for line in preun.split( "\n" ):
                    if PREUN_PATTERN.search( line ):
                        processed['preun'] = True
                        break
                for line in postun.split( "\n" ):
                    if POSTUN_PATTERN.search( line ):
                        processed['postun'] = True
                        break

                if not processed['pre']:
                    printWarning( pkg, 'systemd-service-without-service_add_pre', os.path.basename( fname ) )
                if not processed['post']:
                    printWarning( pkg, 'systemd-service-without-service_add_post', os.path.basename( fname ) )
                if not processed['preun']:
                    printWarning( pkg, 'systemd-service-without-service_del_preun', os.path.basename( fname ) )
                if not processed['postun']:
                    printWarning( pkg, 'systemd-service-without-service_del_postun', os.path.basename( fname ) )
Exemple #40
0
    def check_binary(self, pkg):
        if vendor and pkg[rpm.RPMTAG_VENDOR] != vendor:
            printWarning(pkg, "invalid-vendor", pkg[rpm.RPMTAG_VENDOR])

        if distribution and pkg[rpm.RPMTAG_DISTRIBUTION] != distribution:
            printWarning(pkg, "invalid-distribution",
                         pkg[rpm.RPMTAG_DISTRIBUTION])

        if compress_ext:
            for fname in pkg.files():
                if man_regex.search(fname):
                    if not fname.endswith(compress_ext):
                        printWarning(pkg, 'manpage-not-compressed',
                                     compress_ext, fname)
                elif info_regex.search(fname) and \
                        not fname.endswith("/info/dir"):
                    if not fname.endswith(compress_ext):
                        printWarning(pkg, 'infopage-not-compressed',
                                     compress_ext, fname)
Exemple #41
0
    def check(self, pkg):
        # Check will be performed only on the source package
        if not pkg.isSource():
            return

        # Find name of the specfile
        spec = None
        for fname, pkgfile in pkg.files().items():
            if not fname.endswith(".spec"):
                continue

            try:
                f = open(pkgfile.path, "r")
            except Exception, e:
                printWarning(pkg, 'read-error', fname, e)
                continue

            fedora = rhel = False
            line_no = 0
            for line in f:
                line_no += 1

                # Check only conditional expressions
                if not "%if" in line:
                    continue

                if "0%{?fedora}" in line:
                    fedora = True
                elif "%{?fedora}" in line:
                    printWarning(pkg, "malformed-fedora-conditional",
                                 "%s:%d" % (fname, line_no))
                if "0%{?rhel}" in line:
                    rhel = True
                elif "%{?rhel}" in line:
                    printWarning(pkg, "malformed-rhel-conditional",
                                 "%s:%d" % (fname, line_no))

            # If there is a fedora check there should also be a rhel check
            if fedora and not rhel:
                printWarning(pkg, "no-rhel-conditional", fname)

            f.close()
Exemple #42
0
    def check(self, pkg):
        # Check will be performed only on the source package
        if not pkg.isSource():
            return

        # Find name of the specfile
        spec = None
        for fname, pkgfile in pkg.files().items():
            if not fname.endswith(".spec"):
                continue

            try:
                f = open(pkgfile.path, "r")
            except Exception, e:
                printWarning(pkg, 'read-error', fname, e)
                continue

            fedora = rhel = False
            line_no = 0
            for line in f:
                line_no += 1

                # Check only conditional expressions
                if not "%if" in line:
                    continue

                if "0%{?fedora}" in line:
                    fedora = True
                elif "%{?fedora}" in line:
                    printWarning(pkg, "malformed-fedora-conditional",
                                 "%s:%d" % (fname, line_no))
                if "0%{?rhel}" in line:
                    rhel = True
                elif "%{?rhel}" in line:
                    printWarning(pkg, "malformed-rhel-conditional",
                                 "%s:%d" % (fname, line_no))

            # If there is a fedora check there should also be a rhel check
            if fedora and not rhel:
                printWarning(pkg, "no-rhel-conditional", fname)

            f.close()
Exemple #43
0
 def parse_desktop_file(self, pkg, root, f, filename):
     cfp = cfgparser.RawConfigParser()
     try:
         with codecs.open(f, encoding='utf-8') as inputf:
             cfp.readfp(inputf, filename)
     except cfgparser.DuplicateSectionError as e:
         printError(
             pkg, 'desktopfile-duplicate-section', filename,
             '[%s]' % e.section)
     except cfgparser.MissingSectionHeaderError:
         printError(
             pkg, 'desktopfile-missing-header', filename)
     except cfgparser.Error as e:
         # Only in Python >= 3.2
         if (hasattr(cfgparser, 'DuplicateOptionError') and
                 isinstance(e, cfgparser.DuplicateOptionError)):
             printError(
                 pkg, 'desktopfile-duplicate-option', filename,
                 '[%s]/%s' % (e.section, e.option))
         else:
             printWarning(
                 pkg, 'invalid-desktopfile', filename,
                 e.message.partition(':')[0])
     except UnicodeDecodeError as e:
         printWarning(
             pkg, 'invalid-desktopfile', filename, 'No valid Unicode')
     else:
         binary = None
         if cfp.has_option('Desktop Entry', 'Exec'):
             binary = cfp.get('Desktop Entry', 'Exec').partition(' ')[0]
         if binary:
             found = False
             if binary.startswith('/'):
                 found = os.path.exists(root + binary)
             else:
                 for i in STANDARD_BIN_DIRS:
                     if os.path.exists(root + i + '/' + binary):
                         # no need to check if the binary is +x, rpmlint does it
                         # in another place
                         found = True
                         break
             if not found:
                 printWarning(
                     pkg, 'desktopfile-without-binary', filename, binary)
Exemple #44
0
 def parse_desktop_file(self, pkg, root, f, filename):
     cfp = cfgparser.RawConfigParser()
     try:
         with codecs.open(f, encoding='utf-8') as inputf:
             cfp.readfp(inputf, filename)
     except cfgparser.DuplicateSectionError as e:
         printError(pkg, 'desktopfile-duplicate-section', filename,
                    '[%s]' % e.section)
     except cfgparser.MissingSectionHeaderError:
         printError(pkg, 'desktopfile-missing-header', filename)
     except cfgparser.Error as e:
         # Only in Python >= 3.2
         if (hasattr(cfgparser, 'DuplicateOptionError')
                 and isinstance(e, cfgparser.DuplicateOptionError)):
             printError(pkg, 'desktopfile-duplicate-option', filename,
                        '[%s]/%s' % (e.section, e.option))
         else:
             printWarning(pkg, 'invalid-desktopfile', filename,
                          e.message.partition(':')[0])
     except UnicodeDecodeError as e:
         printWarning(pkg, 'invalid-desktopfile', filename,
                      'No valid Unicode')
     else:
         binary = None
         if cfp.has_option('Desktop Entry', 'Exec'):
             binary = cfp.get('Desktop Entry', 'Exec').partition(' ')[0]
         if binary:
             found = False
             if binary.startswith('/'):
                 found = os.path.exists(root + binary)
             else:
                 for i in STANDARD_BIN_DIRS:
                     if os.path.exists(root + i + '/' + binary):
                         # no need to check if the binary is +x, rpmlint does it
                         # in another place
                         found = True
                         break
             if not found:
                 printWarning(pkg, 'desktopfile-without-binary', filename,
                              binary)
Exemple #45
0
    def check_binary(self, pkg):
        var_list = []
        usr_list = []

        for fname in pkg.files():
            s = FHSCheck.usr_regex.search(fname)
            if s:
                d = s.group(1)
                if d not in FHSCheck.usr_subdir and d not in usr_list:
                    printWarning(pkg, "non-standard-dir-in-usr", d)
                    usr_list.append(d)
            else:
                s = FHSCheck.var_regex.search(fname)
                if s:
                    d = s.group(1)
                    if d in var_list:
                        continue
                    if d in FHSCheck.var_fsstnd:
                        printWarning(pkg, "FSSTND-dir-in-var", fname)
                        var_list.append(d)
                    elif d not in FHSCheck.var_subdir:
                        printWarning(pkg, "non-standard-dir-in-var", d)
                        var_list.append(d)
    def __init__(self, pkg, path, file, is_ar, is_shlib):
        self.readelf_error = False
        self.needed = []
        self.rpath = []
        self.undef = []
        self.unused = []
        self.comment = False
        self.soname = False
        self.non_pic = True
        self.stack = False
        self.exec_stack = False
        self.exit_calls = []
        fork_called = False
        self.tail = ''

        self.setgid = False
        self.setuid = False
        self.setgroups = False
        self.chroot = False
        self.chdir = False
        self.chroot_near_chdir = False
        self.mktemp = False

        is_debug = path.endswith('.debug')

        cmd = ['env', 'LC_ALL=C', 'readelf', '-W', '-S', '-l', '-d', '-s']
        cmd.append(path)
        res = Pkg.getstatusoutput(cmd)
        if not res[0]:
            for l in res[1].splitlines():

                if BinaryInfo.mktemp_call_regex.search(l):
                    self.mktemp = True

                if BinaryInfo.setgid_call_regex.search(l):
                    self.setgid = True

                if BinaryInfo.setuid_call_regex.search(l):
                    self.setuid = True

                if BinaryInfo.setgroups_call_regex.search(l):
                    self.setgroups = True

                if BinaryInfo.chdir_call_regex.search(l):
                    self.chdir = True

                if BinaryInfo.chroot_call_regex.search(l):
                    self.chroot = True

                r = BinaryInfo.needed_regex.search(l)
                if r:
                    self.needed.append(r.group(1))
                    continue

                r = BinaryInfo.rpath_regex.search(l)
                if r:
                    for p in r.group(1).split(':'):
                        self.rpath.append(p)
                    continue

                if BinaryInfo.comment_regex.search(l):
                    self.comment = True
                    continue

                if BinaryInfo.pic_regex.search(l):
                    self.non_pic = False
                    continue

                r = BinaryInfo.soname_regex.search(l)
                if r:
                    self.soname = r.group(1)
                    continue

                r = BinaryInfo.stack_regex.search(l)
                if r:
                    self.stack = True
                    flags = r.group(1)
                    if flags and BinaryInfo.stack_exec_regex.search(flags):
                        self.exec_stack = True
                    continue

                if is_shlib:
                    r = BinaryInfo.exit_call_regex.search(l)
                    if r:
                        self.exit_calls.append(r.group(1))
                        continue
                    r = BinaryInfo.fork_call_regex.search(l)
                    if r:
                        fork_called = True
                        continue

            if self.non_pic:
                self.non_pic = 'TEXTREL' in res[1]

            # Ignore all exit() calls if fork() is being called.
            # Does not have any context at all but without this kludge, the
            # number of false positives would probably be intolerable.
            if fork_called:
                self.exit_calls = []

            # check if chroot is near chdir (since otherwise, chroot is called
            # without chdir)
            if self.chroot and self.chdir:
                # FIXME this check is too slow, because forking for objdump is
                # quite slow according to a quick test and that's quite visible
                # on a server like postfix
                res = Pkg.getstatusoutput(
                    ('env', 'LC_ALL=C', 'objdump', '-d', path))
                if not res[0]:
                    call = []
                    # we want that :
                    # 401eb8:   e8 c3 f0 ff ff          callq  400f80 <free@plt>
                    for l in res[1].splitlines():
                        # call is for x86 32 bits, callq for x86_64
                        if l.find('callq ') >= 0 or l.find('call ') >= 0:
                            call.append(l.rpartition(' ')[2])
                    for index, c in enumerate(call):
                        if c.find('chroot@plt') >= 0:
                            for i in call[index - 2:index + 2]:
                                if i.find('chdir@plt'):
                                    self.chroot_near_chdir = True
        else:
            self.readelf_error = True
            printWarning(pkg, 'binaryinfo-readelf-failed', file,
                         re.sub('\n.*', '', res[1]))

        fobj = None
        try:
            fobj = open(path, 'rb')
            fobj.seek(-12, os.SEEK_END)
            self.tail = Pkg.b2s(fobj.read())
        except Exception:
            e = sys.exc_info()[1]
            printWarning(pkg, 'binaryinfo-tail-failed %s: %s' % (file, e))
        if fobj:
            fobj.close()

        # Undefined symbol and unused direct dependency checks make sense only
        # for installed packages.
        # skip debuginfo: https://bugzilla.redhat.com/190599
        if not is_ar and not is_debug and isinstance(pkg, Pkg.InstalledPkg):
            # We could do this with objdump, but it's _much_ simpler with ldd.
            res = Pkg.getstatusoutput(
                ('env', 'LC_ALL=C', 'ldd', '-d', '-r', path))
            if not res[0]:
                for l in res[1].splitlines():
                    undef = BinaryInfo.undef_regex.search(l)
                    if undef:
                        self.undef.append(undef.group(1))
                if self.undef:
                    cmd = self.undef[:]
                    cmd.insert(0, 'c++filt')
                    try:
                        res = Pkg.getstatusoutput(cmd)
                        if not res[0]:
                            self.undef = res[1].splitlines()
                    except:
                        pass
            else:
                printWarning(pkg, 'ldd-failed', file)
            res = Pkg.getstatusoutput(
                ('env', 'LC_ALL=C', 'ldd', '-r', '-u', path))
            if res[0]:
                # Either ldd doesn't grok -u (added in glibc 2.3.4) or we have
                # unused direct dependencies
                in_unused = False
                for l in res[1].splitlines():
                    if not l.rstrip():
                        pass
                    elif l.startswith('Unused direct dependencies'):
                        in_unused = True
                    elif in_unused:
                        unused = BinaryInfo.unused_regex.search(l)
                        if unused:
                            self.unused.append(unused.group(1))
                        else:
                            in_unused = False
    def check_binary(self, pkg):
        files = pkg.files()
        exec_files = []
        has_lib = False
        version = None
        binary = False
        binary_in_usr_lib = False
        has_usr_lib_file = False

        multi_pkg = False
        srpm = pkg[rpm.RPMTAG_SOURCERPM]
        if srpm:
            res = srcname_regex.search(Pkg.b2s(srpm))
            if res:
                multi_pkg = (pkg.name != res.group(1))

        for fname, pkgfile in files.items():

            if not stat.S_ISDIR(pkgfile.mode) and usr_lib_regex.search(fname):
                has_usr_lib_file = True
                if not binary_in_usr_lib and \
                        usr_lib_exception_regex.search(fname):
                    # Fake that we have binaries there to avoid
                    # only-non-binary-in-usr-lib false positives
                    binary_in_usr_lib = True

            is_elf = 'ELF' in pkgfile.magic
            is_ar = 'current ar archive' in pkgfile.magic
            is_ocaml_native = 'Objective caml native' in pkgfile.magic
            is_lua_bytecode = 'Lua bytecode' in pkgfile.magic
            is_binary = is_elf or is_ar or is_ocaml_native or is_lua_bytecode

            if not is_binary:
                if reference_regex.search(fname):
                    lines = pkg.grep(invalid_dir_ref_regex, fname)
                    if lines:
                        printError(pkg, 'invalid-directory-reference', fname,
                                   '(line %s)' % ", ".join(lines))
                continue

            # binary files only from here on

            binary = True

            if has_usr_lib_file and not binary_in_usr_lib and \
                    usr_lib_regex.search(fname):
                binary_in_usr_lib = True

            if pkg.arch == 'noarch':
                printError(
                    pkg, 'arch-independent-package-contains-binary-or-object',
                    fname)
                continue

            # arch dependent packages only from here on

            # in /usr/share ?
            if fname.startswith('/usr/share/'):
                printError(pkg, 'arch-dependent-file-in-usr-share', fname)

            # in /etc ?
            if fname.startswith('/etc/'):
                printError(pkg, 'binary-in-etc', fname)

            if pkg.arch == 'sparc' and sparc_regex.search(pkgfile.magic):
                printError(pkg, 'non-sparc32-binary', fname)

            if is_ocaml_native or is_lua_bytecode or fname.endswith('.o') or \
                    fname.endswith('.static'):
                continue

            # stripped ?
            if 'not stripped' in pkgfile.magic:
                printWarning(pkg, 'unstripped-binary-or-object', fname)

            # inspect binary file
            is_shlib = so_regex.search(fname)
            bin_info = BinaryInfo(pkg, pkgfile.path, fname, is_ar, is_shlib)

            if is_shlib:
                has_lib = True

            # shared libs
            if is_shlib and not bin_info.readelf_error:

                # so name in library
                if not bin_info.soname:
                    printWarning(pkg, 'no-soname', fname)
                else:
                    if not validso_regex.search(bin_info.soname):
                        printError(pkg, 'invalid-soname', fname,
                                   bin_info.soname)
                    else:
                        (directory, base) = dir_base(fname)
                        try:
                            symlink = directory + bin_info.soname
                            link = files[symlink].linkto
                            if link not in (fname, base, ''):
                                printError(pkg, 'invalid-ldconfig-symlink',
                                           fname, link)
                        except KeyError:
                            if base.startswith("lib") or \
                               base.startswith("ld-"):
                                printError(pkg, 'no-ldconfig-symlink', fname)

                    res = soversion_regex.search(bin_info.soname)
                    if res:
                        soversion = res.group(1) or res.group(2)
                        if version is None:
                            version = soversion
                        elif version != soversion:
                            version = -1

                if bin_info.non_pic:
                    printError(pkg, 'shlib-with-non-pic-code', fname)

                # It could be useful to check these for others than shared
                # libs only, but that has potential to generate lots of
                # false positives and noise.
                for s in bin_info.undef:
                    printWarning(pkg, 'undefined-non-weak-symbol', fname, s)
                for s in bin_info.unused:
                    printWarning(pkg, 'unused-direct-shlib-dependency', fname,
                                 s)

                # calls exit() or _exit()?
                for ec in bin_info.exit_calls:
                    printWarning(pkg, 'shared-lib-calls-exit', fname, ec)

            # rpath ?
            if bin_info.rpath:
                for p in bin_info.rpath:
                    if p in system_lib_paths or not usr_lib_regex.search(p):
                        printError(pkg, 'binary-or-shlib-defines-rpath', fname,
                                   bin_info.rpath)
                        break

            is_exec = 'executable' in pkgfile.magic
            is_shobj = 'shared object' in pkgfile.magic

            if not is_exec and not is_shobj:
                continue

            if is_shobj and not is_exec and '.so' not in fname and \
                    bin_regex.search(fname):
                # pkgfile.magic does not contain "executable" for PIEs
                is_exec = True

            if is_exec:

                if bin_regex.search(fname):
                    exec_files.append(fname)

                if ocaml_mixed_regex.search(bin_info.tail):
                    printWarning(pkg, 'ocaml-mixed-executable', fname)

                if not is_shobj and pie_exec_re and pie_exec_re.search(fname):
                    printError(pkg, 'non-position-independent-executable',
                               fname)

            if bin_info.readelf_error:
                continue

            if not bin_info.needed and not (bin_info.soname
                                            and ldso_soname_regex.search(
                                                bin_info.soname)):
                if is_shobj:
                    printError(pkg,
                               'shared-lib-without-dependency-information',
                               fname)
                else:
                    printError(pkg, 'statically-linked-binary', fname)

            else:
                # linked against libc ?
                if "libc." not in fname and \
                   (not bin_info.soname or
                    ("libc." not in bin_info.soname and
                     not ldso_soname_regex.search(bin_info.soname))):

                    found_libc = False
                    for lib in bin_info.needed:
                        if "libc." in lib:
                            found_libc = True
                            break

                    if not found_libc:
                        if is_shobj:
                            printError(pkg, 'library-not-linked-against-libc',
                                       fname)
                        else:
                            printError(pkg, 'program-not-linked-against-libc',
                                       fname)

            if bin_info.stack:
                if bin_info.exec_stack:
                    printWarning(pkg, 'executable-stack', fname)
            elif not bin_info.readelf_error and (
                    pkg.arch.endswith("86") or pkg.arch.startswith("pentium")
                    or pkg.arch in ("athlon", "x86_64")):
                printError(pkg, 'missing-PT_GNU_STACK-section', fname)

            if bin_info.setgid and bin_info.setuid and not bin_info.setgroups:
                printError(pkg, 'missing-call-to-setgroups-before-setuid',
                           fname)

            if bin_info.chroot:
                if not bin_info.chdir or not bin_info.chroot_near_chdir:
                    printError(pkg, 'missing-call-to-chdir-with-chroot', fname)

            if bin_info.mktemp:
                printError(pkg, 'call-to-mktemp', fname)

        if has_lib:
            for f in exec_files:
                printError(pkg, 'executable-in-library-package', f)
            for f in files:
                res = numeric_dir_regex.search(f)
                fn = res and res.group(1) or f
                if f not in exec_files and not so_regex.search(f) and \
                        not versioned_dir_regex.search(fn):
                    printError(pkg, 'non-versioned-file-in-library-package', f)
            if version and version != -1 and version not in pkg.name:
                printError(pkg, 'incoherent-version-in-name', version)

        if not binary and not multi_pkg and pkg.arch != 'noarch':
            printError(pkg, 'no-binary')

        if has_usr_lib_file and not binary_in_usr_lib:
            printWarning(pkg, 'only-non-binary-in-usr-lib')
    def check(self, pkg):
        if pkg.isSource():
            return

        # file names handled by systemd-tmpfiles
        tmp_files = set()
        postin = pkg[rpm.RPMTAG_POSTIN]
        prein = pkg[rpm.RPMTAG_PREIN]

        # see tmpfiles.d(5)
        interesting_types = ('f', 'F', 'w', 'd', 'D', 'p', 'L', 'c', 'b')

        for fn, pkgfile in pkg.files().items():
            if not fn.startswith('/usr/lib/tmpfiles.d/'):
                continue
            if not stat.S_ISREG(pkgfile.mode):
                printWarning(pkg, "tmpfile-not-regular-file", fn)
                continue

            basename = os.path.basename(fn)
            pattern = re.compile(
                r'systemd-tmpfiles --create .*%s' % re.escape(basename))
            if (not postin or not pattern.search(postin)) and \
                    (not prein or not pattern.search(prein)):
                printWarning(pkg,
                             'postin-without-tmpfile-creation', fn)

            with open(pkgfile.path) as inputf:
                for line in inputf:
                    # skip comments
                    line = line.split('#')[0].split('\n')[0]
                    line = line.lstrip()
                    if not len(line):
                        continue
                    line = re.split(r'\s+', line)
                    # format is
                    # Type Path        Mode UID  GID  Age Argument
                    # we only need type and path
                    if len(line) < 3:
                        continue
                    t = line[0]
                    p = line[1]
                    if t.endswith('!'):
                        t = t[:-1]
                    if t not in interesting_types:
                        continue

                    tmp_files.add(p)

                    if p not in pkg.files():
                        printWarning(pkg, "tmpfile-not-in-filelist", p)
                        continue
                    if not pkg.files()[p].is_ghost:
                        printWarning(pkg, "tmpfile-not-ghost", p)

        # now check remaining ghost files that are not already
        # handled by systemd-tmpfiles
        ghost_files = set(pkg.ghostFiles()) - tmp_files
        if ghost_files:
            for f in ghost_files:
                if f in pkg.missingOkFiles():
                    continue
                if not postin and not prein:
                    printWarning(pkg, 'ghost-files-without-postin')
                if (not postin or f not in postin) and \
                        (not prein or f not in prein):
                    printWarning(pkg,
                                 'postin-without-ghost-file-creation', f)
Exemple #49
0
    def check_binary(self, pkg):
        files = pkg.files()
        menus = []

        for fname, pkgfile in files.items():
            # Check menu files
            res = menu_file_regex.search(fname)
            mode = pkgfile.mode
            if res:
                basename = res.group(1)
                if not stat.S_ISREG(mode):
                    printError(pkg, 'non-file-in-menu-dir', fname)
                else:
                    if basename != pkg.name:
                        printWarning(pkg, 'non-coherent-menu-filename', fname)
                    if mode & 0o444 != 0o444:
                        printError(pkg, 'non-readable-menu-file', fname)
                    if mode & 0o111:
                        printError(pkg, 'executable-menu-file', fname)
                    menus.append(fname)
            else:
                # Check old menus from KDE and GNOME
                res = old_menu_file_regex.search(fname)
                if res:
                    if stat.S_ISREG(mode):
                        printError(pkg, 'old-menu-entry', fname)
                else:
                    # Check non transparent xpm files
                    res = xpm_ext_regex.search(fname)
                    if res:
                        if stat.S_ISREG(mode) and not pkg.grep(
                                'None",', fname):
                            printWarning(pkg, 'non-transparent-xpm', fname)
                if fname.startswith('/usr/lib64/menu'):
                    printError(pkg, 'menu-in-wrong-dir', fname)

        if menus:
            postin = pkg[rpm.RPMTAG_POSTIN] or \
                pkg.scriptprog(rpm.RPMTAG_POSTINPROG)
            if not postin:
                printError(pkg, 'menu-without-postin')
            elif not update_menus_regex.search(postin):
                printError(pkg, 'postin-without-update-menus')

            postun = pkg[rpm.RPMTAG_POSTUN] or \
                pkg.scriptprog(rpm.RPMTAG_POSTUNPROG)
            if not postun:
                printError(pkg, 'menu-without-postun')
            elif not update_menus_regex.search(postun):
                printError(pkg, 'postun-without-update-menus')

            directory = pkg.dirName()
            for f in menus:
                # remove comments and handle cpp continuation lines
                cmd = Pkg.getstatusoutput(('/lib/cpp', directory + f), True)[1]

                for line in cmd.splitlines():
                    if not line.startswith('?'):
                        continue
                    res = package_regex.search(line)
                    if res:
                        package = res.group(1)
                        if package != pkg.name:
                            printWarning(pkg,
                                         'incoherent-package-value-in-menu',
                                         package, f)
                    else:
                        printInfo(pkg, 'unable-to-parse-menu-entry', line)

                    command = True
                    res = command_regex.search(line)
                    if res:
                        command_line = (res.group(1) or res.group(2)).split()
                        command = command_line[0]
                        for launcher in launchers:
                            if not launcher[0].search(command):
                                continue
                            found = False
                            if launcher[1]:
                                found = '/bin/' + command_line[0] in files or \
                                    '/usr/bin/' + command_line[0] in files or \
                                    '/usr/X11R6/bin/' + command_line[0] \
                                    in files
                                if not found:
                                    for l in launcher[1]:
                                        if l in pkg.req_names():
                                            found = True
                                            break
                                if not found:
                                    printError(
                                        pkg,
                                        'use-of-launcher-in-menu-but-no-requires-on',
                                        launcher[1][0])
                            command = command_line[1]
                            break

                        if command[0] == '/':
                            if command not in files:
                                printWarning(pkg,
                                             'menu-command-not-in-package',
                                             command)
                        elif not ('/bin/' + command in files
                                  or '/usr/bin/' + command in files
                                  or '/usr/X11R6/bin/' + command in files):
                            printWarning(pkg, 'menu-command-not-in-package',
                                         command)
                    else:
                        printWarning(pkg, 'missing-menu-command')
                        command = False

                    res = longtitle_regex.search(line)
                    if res:
                        grp = res.groups()
                        title = grp[1] or grp[2]
                        if title[0] != title[0].upper():
                            printWarning(pkg, 'menu-longtitle-not-capitalized',
                                         title)
                        res = version_regex.search(title)
                        if res:
                            printWarning(pkg, 'version-in-menu-longtitle',
                                         title)
                    else:
                        printError(pkg, 'no-longtitle-in-menu', f)
                        title = None

                    res = title_regex.search(line)
                    if res:
                        grp = res.groups()
                        title = grp[1] or grp[2]
                        if title[0] != title[0].upper():
                            printWarning(pkg, 'menu-title-not-capitalized',
                                         title)
                        res = version_regex.search(title)
                        if res:
                            printWarning(pkg, 'version-in-menu-title', title)
                        if '/' in title:
                            printError(pkg, 'invalid-title', title)
                    else:
                        printError(pkg, 'no-title-in-menu', f)
                        title = None

                    res = needs_regex.search(line)
                    if res:
                        grp = res.groups()
                        needs = (grp[1] or grp[2]).lower()
                        if needs in ('x11', 'text', 'wm'):
                            res = section_regex.search(line)
                            if res:
                                grp = res.groups()
                                section = grp[1] or grp[2]
                                # don't warn entries for sections
                                if command and section not in valid_sections:
                                    printError(pkg, 'invalid-menu-section',
                                               section, f)
                            else:
                                printInfo(pkg, 'unable-to-parse-menu-section',
                                          line)
                        elif needs not in standard_needs:
                            printInfo(pkg, 'strange-needs', needs, f)
                    else:
                        printInfo(pkg, 'unable-to-parse-menu-needs', line)

                    res = icon_regex.search(line)
                    if res:
                        icon = res.group(1)
                        if not icon_ext_regex.search(icon):
                            printWarning(pkg, 'invalid-menu-icon-type', icon)
                        if icon[0] == '/' and needs == 'x11':
                            printWarning(pkg, 'hardcoded-path-in-menu-icon',
                                         icon)
                        else:
                            for path in icon_paths:
                                if (path[0] + icon) not in files:
                                    printError(
                                        pkg, path[1] + '-icon-not-in-package',
                                        icon, f)
                    else:
                        printWarning(pkg, 'no-icon-in-menu', title)

                    res = xdg_migrated_regex.search(line)
                    if res:
                        if not res.group(1).lower() == "true":
                            printError(pkg, 'non-xdg-migrated-menu')
                    else:
                        printError(pkg, 'non-xdg-migrated-menu')
Exemple #50
0
    def check_aux(self, pkg, files, prog, script, tag, prereq):
        if script:
            if prog:
                if prog not in valid_shells:
                    printError(pkg, 'invalid-shell-in-' + tag, prog)
                if prog in empty_shells:
                    printError(pkg, 'non-empty-' + tag, prog)
            if prog in syntaxcheck_shells or prog == '/usr/bin/perl':
                if percent_regex.search(script):
                    printWarning(pkg, 'percent-in-' + tag)
                if bracket_regex.search(script):
                    printWarning(pkg, 'spurious-bracket-in-' + tag)
                res = dangerous_command_regex.search(script)
                if res:
                    printWarning(pkg, 'dangerous-command-in-' + tag,
                                 res.group(2))
                res = selinux_regex.search(script)
                if res:
                    printError(pkg, 'forbidden-selinux-command-in-' + tag,
                               res.group(2))

                if 'update-menus' in script:
                    menu_error = True
                    for f in files:
                        if menu_regex.search(f):
                            menu_error = False
                            break
                    if menu_error:
                        printError(pkg,
                                   'update-menus-without-menu-file-in-' + tag)
                if tmp_regex.search(script):
                    printError(pkg, 'use-tmp-in-' + tag)
                for c in prereq_assoc:
                    if c[0].search(script):
                        found = False
                        for p in c[1]:
                            if p in prereq or p in files:
                                found = True
                                break
                        if not found:
                            printError(pkg, 'no-prereq-on', c[1][0])

            if prog in syntaxcheck_shells:
                if incorrect_shell_script(prog, script):
                    printError(pkg, 'shell-syntax-error-in-' + tag)
                if home_regex.search(script):
                    printError(pkg, 'use-of-home-in-' + tag)
                res = bogus_var_regex.search(script)
                if res:
                    printWarning(pkg, 'bogus-variable-use-in-' + tag,
                                 res.group(1))

            if prog == '/usr/bin/perl':
                if incorrect_perl_script(prog, script):
                    printError(pkg, 'perl-syntax-error-in-' + tag)
            elif prog.endswith('sh'):
                res = single_command_regex.search(script)
                if res:
                    printWarning(pkg, 'one-line-command-in-' + tag,
                                 res.group(1))

        elif prog not in empty_shells and prog in valid_shells:
            printWarning(pkg, 'empty-' + tag)
    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 Exception:
                    pass
            pass

        std_dirs = dirs.intersection(("/lib", "/lib64", "/usr/lib", "/usr/lib64", "/opt/kde3/lib", "/opt/kde3/lib64"))

        # 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)
Exemple #52
0
    def check(self, pkg):

        packager = pkg[rpm.RPMTAG_PACKAGER]
        if packager:
            self._unexpanded_macros(pkg, 'Packager', packager)
            if Config.getOption('Packager') and \
               not packager_regex.search(packager):
                printWarning(pkg, 'invalid-packager', packager)
        else:
            printError(pkg, 'no-packager-tag')

        version = pkg[rpm.RPMTAG_VERSION]
        if version:
            self._unexpanded_macros(pkg, 'Version', version)
            res = invalid_version_regex.search(version)
            if res:
                printError(pkg, 'invalid-version', version)
        else:
            printError(pkg, 'no-version-tag')

        release = pkg[rpm.RPMTAG_RELEASE]
        if release:
            self._unexpanded_macros(pkg, 'Release', release)
            if release_ext and not extension_regex.search(release):
                printWarning(pkg, 'not-standard-release-extension', release)
        else:
            printError(pkg, 'no-release-tag')

        epoch = pkg[rpm.RPMTAG_EPOCH]
        if epoch is None:
            if use_epoch:
                printError(pkg, 'no-epoch-tag')
        else:
            if epoch > 99:
                printWarning(pkg, 'unreasonable-epoch', epoch)
            epoch = str(epoch)

        if use_epoch:
            for tag in ("obsoletes", "conflicts", "provides", "recommends",
                        "suggests", "enhances", "supplements"):
                for x in (x for x in getattr(pkg, tag)()
                          if x[1] and x[2][0] is None):
                    printWarning(pkg, 'no-epoch-in-%s' % tag,
                                 Pkg.formatRequire(*x))

        name = pkg.name
        deps = pkg.requires() + pkg.prereq()
        devel_depend = False
        is_devel = FilesCheck.devel_regex.search(name)
        is_source = pkg.isSource()
        for d in deps:
            value = Pkg.formatRequire(*d)
            if use_epoch and d[1] and d[2][0] is None and \
                    not d[0].startswith('rpmlib('):
                printWarning(pkg, 'no-epoch-in-dependency', value)
            for r in INVALID_REQUIRES:
                if r.search(d[0]):
                    printError(pkg, 'invalid-dependency', d[0])

            if d[0].startswith('/usr/local/'):
                printError(pkg, 'invalid-dependency', d[0])

            if is_source:
                if lib_devel_number_regex.search(d[0]):
                    printError(pkg, 'invalid-build-requires', d[0])
            elif not is_devel:
                if not devel_depend and FilesCheck.devel_regex.search(d[0]):
                    printError(pkg, 'devel-dependency', d[0])
                    devel_depend = True
                if not d[1]:
                    res = lib_package_regex.search(d[0])
                    if res and not res.group(1):
                        printError(pkg, 'explicit-lib-dependency', d[0])

            if d[1] == rpm.RPMSENSE_EQUAL and d[2][2] is not None:
                printWarning(pkg, 'requires-on-release', value)
            self._unexpanded_macros(pkg, 'dependency %s' % (value,), value)

        self._unexpanded_macros(pkg, 'Name', name)
        if not name:
            printError(pkg, 'no-name-tag')
        else:
            if is_devel and not is_source:
                base = is_devel.group(1)
                dep = None
                has_so = False
                for fname in pkg.files():
                    if fname.endswith('.so'):
                        has_so = True
                        break
                if has_so:
                    base_or_libs = base + '/' + base + '-libs/lib' + base
                    # try to match *%_isa as well (e.g. "(x86-64)", "(x86-32)")
                    base_or_libs_re = re.compile(
                        r'^(lib)?%s(-libs)?(\(\w+-\d+\))?$' % re.escape(base))
                    for d in deps:
                        if base_or_libs_re.match(d[0]):
                            dep = d
                            break
                    if not dep:
                        printWarning(pkg, 'no-dependency-on', base_or_libs)
                    elif version:
                        exp = (epoch, version, None)
                        sexp = Pkg.versionToString(exp)
                        if not dep[1]:
                            printWarning(pkg, 'no-version-dependency-on',
                                         base_or_libs, sexp)
                        elif dep[2][:2] != exp[:2]:
                            printWarning(pkg,
                                         'incoherent-version-dependency-on',
                                         base_or_libs,
                                         Pkg.versionToString((dep[2][0],
                                                              dep[2][1], None)),
                                         sexp)
                    res = devel_number_regex.search(name)
                    if not res:
                        printWarning(pkg, 'no-major-in-name', name)
                    else:
                        if res.group(3):
                            prov = res.group(1) + res.group(2) + '-devel'
                        else:
                            prov = res.group(1) + '-devel'

                        if prov not in (x[0] for x in pkg.provides()):
                            printWarning(pkg, 'no-provides', prov)

        # List of words to ignore in spell check
        ignored_words = set()
        for pf in pkg.files():
            ignored_words.update(pf.split('/'))
        ignored_words.update((x[0] for x in pkg.provides()))
        ignored_words.update((x[0] for x in pkg.requires()))
        ignored_words.update((x[0] for x in pkg.conflicts()))
        ignored_words.update((x[0] for x in pkg.obsoletes()))

        langs = pkg[rpm.RPMTAG_HEADERI18NTABLE]

        summary = pkg[rpm.RPMTAG_SUMMARY]
        if summary:
            if not langs:
                self._unexpanded_macros(pkg, 'Summary', Pkg.b2s(summary))
            else:
                for lang in langs:
                    self.check_summary(pkg, lang, ignored_words)
        else:
            printError(pkg, 'no-summary-tag')

        description = pkg[rpm.RPMTAG_DESCRIPTION]
        if description:
            if not langs:
                self._unexpanded_macros(pkg, '%description',
                                        Pkg.b2s(description))
            else:
                for lang in langs:
                    self.check_description(pkg, lang, ignored_words)
        else:
            printError(pkg, 'no-description-tag')

        group = pkg[rpm.RPMTAG_GROUP]
        self._unexpanded_macros(pkg, 'Group', group)
        if not group:
            printError(pkg, 'no-group-tag')
        elif VALID_GROUPS and group not in VALID_GROUPS:
            printWarning(pkg, 'non-standard-group', group)

        buildhost = pkg[rpm.RPMTAG_BUILDHOST]
        self._unexpanded_macros(pkg, 'BuildHost', buildhost)
        if not buildhost:
            printError(pkg, 'no-buildhost-tag')
        elif Config.getOption('ValidBuildHost') and \
                not valid_buildhost_regex.search(buildhost):
            printWarning(pkg, 'invalid-buildhost', buildhost)

        changelog = pkg[rpm.RPMTAG_CHANGELOGNAME]
        if not changelog:
            printError(pkg, 'no-changelogname-tag')
        else:
            clt = pkg[rpm.RPMTAG_CHANGELOGTEXT]
            if use_version_in_changelog:
                ret = changelog_version_regex.search(Pkg.b2s(changelog[0]))
                if not ret and clt:
                    # we also allow the version specified as the first
                    # thing on the first line of the text
                    ret = changelog_text_version_regex.search(Pkg.b2s(clt[0]))
                if not ret:
                    printWarning(pkg, 'no-version-in-last-changelog')
                elif version and release:
                    srpm = pkg[rpm.RPMTAG_SOURCERPM] or ''
                    # only check when source name correspond to name
                    if srpm[0:-8] == '%s-%s-%s' % (name, version, release):
                        expected = [version + '-' + release]
                        if epoch is not None:  # regardless of use_epoch
                            expected[0] = str(epoch) + ':' + expected[0]
                        # Allow EVR in changelog without release extension,
                        # the extension is often a macro or otherwise dynamic.
                        if release_ext:
                            expected.append(
                                extension_regex.sub('', expected[0]))
                        if ret.group(1) not in expected:
                            if len(expected) == 1:
                                expected = expected[0]
                            printWarning(pkg, 'incoherent-version-in-changelog',
                                         ret.group(1), expected)

            if use_utf8:
                if clt:
                    changelog = changelog + clt
                for s in changelog:
                    if not Pkg.is_utf8_bytestr(s):
                        printError(pkg, 'tag-not-utf8', '%changelog')
                        break

            clt = pkg[rpm.RPMTAG_CHANGELOGTIME][0]
            if clt:
                clt -= clt % (24 * 3600)  # roll back to 00:00:00, see #246
                if clt < oldest_changelog_timestamp:
                    printWarning(pkg, 'changelog-time-overflow',
                                 time.strftime("%Y-%m-%d", time.gmtime(clt)))
                elif clt > time.time():
                    printError(pkg, 'changelog-time-in-future',
                               time.strftime("%Y-%m-%d", time.gmtime(clt)))

#         for provide_name in (x[0] for x in pkg.provides()):
#             if name == provide_name:
#                 printWarning(pkg, 'package-provides-itself')
#                 break

        def split_license(license):
            return (x.strip() for x in
                    (l for l in license_regex.split(license) if l))

        rpm_license = pkg[rpm.RPMTAG_LICENSE]
        if not rpm_license:
            printError(pkg, 'no-license')
        else:
            valid_license = True
            if rpm_license not in VALID_LICENSES:
                for l1 in split_license(rpm_license):
                    if l1 in VALID_LICENSES:
                        continue
                    for l2 in split_license(l1):
                        if l2 not in VALID_LICENSES:
                            printWarning(pkg, 'invalid-license', l2)
                            valid_license = False
            if not valid_license:
                self._unexpanded_macros(pkg, 'License', rpm_license)

        for tag in ('URL', 'DistURL', 'BugURL'):
            if hasattr(rpm, 'RPMTAG_%s' % tag.upper()):
                url = Pkg.b2s(pkg[getattr(rpm, 'RPMTAG_%s' % tag.upper())])
                self._unexpanded_macros(pkg, tag, url, is_url=True)
                if url:
                    (scheme, netloc) = urlparse(url)[0:2]
                    if not scheme or not netloc or "." not in netloc or \
                            scheme not in ('http', 'https', 'ftp') or \
                            (Config.getOption('InvalidURL') and
                             invalid_url_regex.search(url)):
                        printWarning(pkg, 'invalid-url', tag, url)
                    else:
                        self.check_url(pkg, tag, url)
                elif tag == 'URL':
                    printWarning(pkg, 'no-url-tag')

        obs_names = [x[0] for x in pkg.obsoletes()]
        prov_names = [x[0] for x in pkg.provides()]

        for o in (x for x in obs_names if x not in prov_names):
            printWarning(pkg, 'obsolete-not-provided', o)
        for o in pkg.obsoletes():
            value = Pkg.formatRequire(*o)
            self._unexpanded_macros(pkg, 'Obsoletes %s' % (value,), value)

        # TODO: should take versions, <, <=, =, >=, > into account here
        #       https://bugzilla.redhat.com/460872
        useless_provides = []
        for p in prov_names:
            if prov_names.count(p) != 1 and p not in useless_provides:
                useless_provides.append(p)
        for p in useless_provides:
            printError(pkg, 'useless-provides', p)

        for p in pkg.provides():
            value = Pkg.formatRequire(*p)
            self._unexpanded_macros(pkg, 'Provides %s' % (value,), value)

        for c in pkg.conflicts():
            value = Pkg.formatRequire(*c)
            self._unexpanded_macros(pkg, 'Conflicts %s' % (value,), value)

        obss = pkg.obsoletes()
        if obss:
            provs = pkg.provides()
            for prov in provs:
                for obs in obss:
                    if Pkg.rangeCompare(obs, prov):
                        printWarning(pkg, 'self-obsoletion',
                                     '%s obsoletes %s' %
                                     (Pkg.formatRequire(*obs),
                                      Pkg.formatRequire(*prov)))

        expfmt = rpm.expandMacro("%{_build_name_fmt}")
        if pkg.isSource():
            # _build_name_fmt often (always?) ends up not outputting src/nosrc
            # as arch for source packages, do it ourselves
            expfmt = re.sub(r'(?i)%\{?ARCH\b\}?', pkg.arch, expfmt)
        expected = pkg.header.sprintf(expfmt).split("/")[-1]
        basename = os.path.basename(pkg.filename)
        if basename != expected:
            printWarning(pkg, 'non-coherent-filename', basename, expected)

        for tag in ('Distribution', 'DistTag', 'ExcludeArch', 'ExcludeOS',
                    'Vendor'):
            if hasattr(rpm, 'RPMTAG_%s' % tag.upper()):
                res = Pkg.b2s(pkg[getattr(rpm, 'RPMTAG_%s' % tag.upper())])
                self._unexpanded_macros(pkg, tag, res)

        for path in private_so_paths:
            for fname, pkgfile in pkg.files().items():
                if fname.startswith(path):
                    for prov in pkgfile.provides:
                        if so_dep_regex.search(prov[0]):
                            printWarning(pkg, "private-shared-object-provides",
                                         fname, Pkg.formatRequire(*prov))
Exemple #53
0
    def check_binary(self, pkg):
        initscript_list = []
        for fname, pkgfile in pkg.files().items():

            if not fname.startswith('/etc/init.d/') and \
                    not fname.startswith('/etc/rc.d/init.d/'):
                continue

            basename = os.path.basename(fname)
            initscript_list.append(basename)
            if pkgfile.mode & 0o500 != 0o500:
                printError(pkg, 'init-script-non-executable', fname)

            if "." in basename:
                printError(pkg, 'init-script-name-with-dot', fname)

            # check chkconfig call in %post and %preun
            postin = pkg[rpm.RPMTAG_POSTIN] or \
                pkg.scriptprog(rpm.RPMTAG_POSTINPROG)
            if not postin:
                printError(pkg, 'init-script-without-chkconfig-postin', fname)
            elif not chkconfig_regex.search(postin):
                printError(pkg, 'postin-without-chkconfig', fname)

            preun = pkg[rpm.RPMTAG_PREUN] or \
                pkg.scriptprog(rpm.RPMTAG_PREUNPROG)
            if not preun:
                printError(pkg, 'init-script-without-chkconfig-preun', fname)
            elif not chkconfig_regex.search(preun):
                printError(pkg, 'preun-without-chkconfig', fname)

            status_found = False
            reload_found = False
            chkconfig_content_found = False
            subsys_regex_found = False
            in_lsb_tag = False
            in_lsb_description = False
            lastline = ''
            lsb_tags = {}
            # check common error in file content
            content = None
            try:
                content = [x for x in Pkg.readlines(pkgfile.path)]
            except Exception as e:
                printWarning(pkg, 'read-error', e)
                continue
            content_str = "".join(content)
            for line in content:
                line = line[:-1]  # chomp
                # TODO check if there is only one line like this
                if line.startswith('### BEGIN INIT INFO'):
                    in_lsb_tag = True
                    continue
                if line.endswith('### END INIT INFO'):
                    in_lsb_tag = False
                    for kw, vals in lsb_tags.items():
                        if len(vals) != 1:
                            printError(pkg, 'redundant-lsb-keyword', kw)

                    for kw in RECOMMENDED_LSB_KEYWORDS:
                        if kw not in lsb_tags:
                            printWarning(pkg, 'missing-lsb-keyword',
                                         "%s in %s" % (kw, fname))
                if in_lsb_tag:
                    # TODO maybe we do not have to handle this ?
                    if lastline.endswith('\\'):
                        line = lastline + line
                    else:
                        res = lsb_tags_regex.search(line)
                        if not res:
                            cres = lsb_cont_regex.search(line)
                            if not (in_lsb_description and cres):
                                in_lsb_description = False
                                printError(
                                    pkg, 'malformed-line-in-lsb-comment-block',
                                    line)
                            else:
                                lsb_tags["Description"][-1] += \
                                    " " + cres.group(1)
                        else:
                            tag = res.group(1)
                            if not tag.startswith('X-') and \
                                    tag not in LSB_KEYWORDS:
                                printError(pkg, 'unknown-lsb-keyword', line)
                            else:
                                in_lsb_description = (tag == 'Description')
                                if tag not in lsb_tags:
                                    lsb_tags[tag] = []
                                lsb_tags[tag].append(res.group(2))
                    lastline = line

                if not status_found and status_regex.search(line):
                    status_found = True

                if not reload_found and reload_regex.search(line):
                    reload_found = True

                res = chkconfig_content_regex.search(line)
                if res:
                    chkconfig_content_found = True
                    if use_deflevels:
                        if res.group(1) == '-':
                            printWarning(pkg, 'no-default-runlevel', fname)
                    elif res.group(1) != '-':
                        printWarning(pkg, 'service-default-enabled', fname)

                res = subsys_regex.search(line)
                if res:
                    subsys_regex_found = True
                    name = res.group(1)
                    if use_subsys and name != basename:
                        error = True
                        if name[0] == '$':
                            value = Pkg.substitute_shell_vars(
                                name, content_str)
                            if value == basename:
                                error = False
                        else:
                            i = name.find('}')
                            if i != -1:
                                name = name[0:i]
                                error = name != basename
                        if error and len(name):
                            if name[0] == '$':
                                printWarning(pkg, 'incoherent-subsys', fname,
                                             name)
                            else:
                                printError(pkg, 'incoherent-subsys', fname,
                                           name)

            if "Default-Start" in lsb_tags:
                if "".join(lsb_tags["Default-Start"]):
                    printWarning(pkg, 'service-default-enabled', fname)

            if not status_found:
                printError(pkg, 'no-status-entry', fname)
            if not reload_found:
                printWarning(pkg, 'no-reload-entry', fname)
            if not chkconfig_content_found:
                printError(pkg, 'no-chkconfig-line', fname)
            if not subsys_regex_found and use_subsys:
                printError(pkg, 'subsys-not-used', fname)
            elif subsys_regex_found and not use_subsys:
                printError(pkg, 'subsys-unsupported', fname)

        if len(initscript_list) == 1:
            pkgname = re.sub("-sysvinit$", "", pkg.name.lower())
            goodnames = (pkgname, pkgname + 'd')
            if initscript_list[0] not in goodnames:
                printWarning(pkg, 'incoherent-init-script-name',
                             initscript_list[0], str(goodnames))
Exemple #54
0
    def check_binary(self, pkg):
        files = pkg.files()
        exec_files = []
        has_lib = False
        version = None
        binary = False
        binary_in_usr_lib = False
        has_usr_lib_file = False

        multi_pkg = False
        srpm = pkg[rpm.RPMTAG_SOURCERPM]
        if srpm:
            res = srcname_regex.search(srpm)
            if res:
                multi_pkg = (pkg.name != res.group(1))

        for fname, pkgfile in files.items():

            if not stat.S_ISDIR(pkgfile.mode) and usr_lib_regex.search(fname):
                has_usr_lib_file = True
                if not binary_in_usr_lib and \
                        usr_lib_exception_regex.search(fname):
                    # Fake that we have binaries there to avoid
                    # only-non-binary-in-usr-lib false positives
                    binary_in_usr_lib = True

            is_elf = pkgfile.magic.startswith('ELF ')
            is_ar = 'current ar archive' in pkgfile.magic
            is_ocaml_native = 'Objective caml native' in pkgfile.magic
            is_lua_bytecode = 'Lua bytecode' in pkgfile.magic
            is_binary = is_elf or is_ar or is_ocaml_native or is_lua_bytecode

            if not is_binary:
                if reference_regex.search(fname):
                    lines = pkg.grep(invalid_dir_ref_regex, fname)
                    if lines:
                        printError(pkg, 'invalid-directory-reference', fname,
                                   '(line %s)' % ", ".join(lines))
                continue

            # binary files only from here on

            binary = True

            if has_usr_lib_file and not binary_in_usr_lib and \
                    usr_lib_regex.search(fname):
                binary_in_usr_lib = True

            if pkg.arch == 'noarch':
                printError(
                    pkg,
                    'arch-independent-package-contains-binary-or-object',
                    fname)
                continue

            # arch dependent packages only from here on

            # in /usr/share ?
            if fname.startswith('/usr/share/'):
                printError(pkg, 'arch-dependent-file-in-usr-share', fname)

            # in /etc ?
            if fname.startswith('/etc/'):
                printError(pkg, 'binary-in-etc', fname)

            if pkg.arch == 'sparc' and sparc_regex.search(pkgfile.magic):
                printError(pkg, 'non-sparc32-binary', fname)

            if is_ocaml_native or is_lua_bytecode or fname.endswith('.o') or \
                    fname.endswith('.static'):
                continue

            # stripped ?
            if 'not stripped' in pkgfile.magic:
                printWarning(pkg, 'unstripped-binary-or-object', fname)

            # inspect binary file
            is_shlib = so_regex.search(fname)
            bin_info = BinaryInfo(pkg, pkgfile.path, fname, is_ar, is_shlib)

            if is_shlib:
                has_lib = True

            # shared libs
            if is_shlib and not bin_info.readelf_error:

                # so name in library
                if not bin_info.soname:
                    printWarning(pkg, 'no-soname', fname)
                else:
                    if not validso_regex.search(bin_info.soname):
                        printError(pkg, 'invalid-soname', fname,
                                   bin_info.soname)
                    else:
                        (directory, base) = dir_base(fname)
                        try:
                            symlink = directory + bin_info.soname
                            link = files[symlink].linkto
                            if link not in (fname, base, ''):
                                printError(pkg, 'invalid-ldconfig-symlink',
                                           fname, link)
                        except KeyError:
                            if base.startswith("lib") or \
                               base.startswith("ld-"):
                                printError(pkg, 'no-ldconfig-symlink', fname)

                    res = soversion_regex.search(bin_info.soname)
                    if res:
                        soversion = res.group(1) or res.group(2)
                        if version is None:
                            version = soversion
                        elif version != soversion:
                            version = -1

                if bin_info.non_pic:
                    printError(pkg, 'shlib-with-non-pic-code', fname)

                # It could be useful to check these for others than shared
                # libs only, but that has potential to generate lots of
                # false positives and noise.
                for s in bin_info.undef:
                    printWarning(pkg, 'undefined-non-weak-symbol', fname, s)
                for s in bin_info.unused:
                    printWarning(pkg, 'unused-direct-shlib-dependency',
                                 fname, s)

                # calls exit() or _exit()?
                for ec in bin_info.exit_calls:
                    printWarning(pkg, 'shared-lib-calls-exit', fname, ec)

            for ec in bin_info.forbidden_calls:
                printWarning(pkg, ec, fname,
                             BinaryInfo.forbidden_functions[ec]['f_name'])

            # rpath ?
            if bin_info.rpath:
                for p in bin_info.rpath:
                    if p in system_lib_paths or not usr_lib_regex.search(p):
                        printError(pkg, 'binary-or-shlib-defines-rpath',
                                   fname, bin_info.rpath)
                        break

            is_exec = 'executable' in pkgfile.magic
            is_shobj = 'shared object' in pkgfile.magic

            if not is_exec and not is_shobj:
                continue

            if is_shobj and not is_exec and '.so' not in fname and \
                    bin_regex.search(fname):
                # pkgfile.magic does not contain "executable" for PIEs
                is_exec = True

            if is_exec:

                if bin_regex.search(fname):
                    exec_files.append(fname)

                if ocaml_mixed_regex.search(bin_info.tail):
                    printWarning(pkg, 'ocaml-mixed-executable', fname)

                if not is_shobj and pie_exec_re and pie_exec_re.search(fname):
                    printError(pkg, 'non-position-independent-executable',
                               fname)

            if bin_info.readelf_error:
                continue

            if not bin_info.needed and not (
                    bin_info.soname and
                    ldso_soname_regex.search(bin_info.soname)):
                if is_shobj:
                    printError(pkg,
                               'shared-lib-without-dependency-information',
                               fname)
                else:
                    printError(pkg, 'statically-linked-binary', fname)

            else:
                # linked against libc ?
                if "libc." not in fname and \
                   (not bin_info.soname or
                    ("libc." not in bin_info.soname and
                     not ldso_soname_regex.search(bin_info.soname))):

                    found_libc = False
                    for lib in bin_info.needed:
                        if "libc." in lib:
                            found_libc = True
                            break

                    if not found_libc:
                        if is_shobj:
                            printError(pkg, 'library-not-linked-against-libc',
                                       fname)
                        else:
                            printError(pkg, 'program-not-linked-against-libc',
                                       fname)

            if bin_info.stack:
                if bin_info.exec_stack:
                    printWarning(pkg, 'executable-stack', fname)
            elif not bin_info.readelf_error and (
                    pkg.arch.endswith("86") or
                    pkg.arch.startswith("pentium") or
                    pkg.arch in ("athlon", "x86_64")):
                printError(pkg, 'missing-PT_GNU_STACK-section', fname)

            if bin_info.setgid and bin_info.setuid and not bin_info.setgroups:
                printError(pkg, 'missing-call-to-setgroups-before-setuid',
                           fname)

            if bin_info.chroot and not bin_info.chroot_near_chdir:
                printError(pkg, 'missing-call-to-chdir-with-chroot', fname)

            if bin_info.mktemp:
                printError(pkg, 'call-to-mktemp', fname)

        if has_lib:
            for f in exec_files:
                printError(pkg, 'executable-in-library-package', f)
            for f in files:
                res = numeric_dir_regex.search(f)
                fn = res and res.group(1) or f
                if f not in exec_files and not so_regex.search(f) and \
                        not versioned_dir_regex.search(fn):
                    printError(pkg, 'non-versioned-file-in-library-package', f)
            if version and version != -1 and version not in pkg.name:
                printError(pkg, 'incoherent-version-in-name', version)

        if not binary and not multi_pkg and pkg.arch != 'noarch':
            printError(pkg, 'no-binary')

        if has_usr_lib_file and not binary_in_usr_lib:
            printWarning(pkg, 'only-non-binary-in-usr-lib')
Exemple #55
0
    def __init__(self, pkg, path, fname, is_ar, is_shlib):
        self.readelf_error = False
        self.needed = []
        self.rpath = []
        self.undef = []
        self.unused = []
        self.comment = False
        self.soname = False
        self.non_pic = True
        self.stack = False
        self.exec_stack = False
        self.exit_calls = []
        self.forbidden_calls = []
        fork_called = False
        self.tail = ''

        self.setgid = False
        self.setuid = False
        self.setgroups = False
        self.chroot = False
        self.chdir = False
        self.chroot_near_chdir = False
        self.mktemp = False

        is_debug = path.endswith('.debug')
        # Currently this implementation works only on specific
        # architectures due to reliance on arch specific assembly.
        if (pkg.arch.startswith('armv') or pkg.arch == 'aarch64'):
            # 10450:   ebffffec        bl      10408 <chroot@plt>
            BinaryInfo.objdump_call_regex = re.compile(br'\sbl\s+(.*)')
        elif (pkg.arch.endswith('86') or pkg.arch == 'x86_64'):
            # 401eb8:   e8 c3 f0 ff ff          callq  400f80 <chdir@plt>
            BinaryInfo.objdump_call_regex = re.compile(br'callq?\s(.*)')
        else:
            BinaryInfo.objdump_call_regex = None

        res = Pkg.getstatusoutput(
            ('readelf', '-W', '-S', '-l', '-d', '-s', path))
        if not res[0]:
            lines = res[1].splitlines()
            for line in lines:
                r = BinaryInfo.needed_regex.search(line)
                if r:
                    self.needed.append(r.group(1))
                    continue

                r = BinaryInfo.rpath_regex.search(line)
                if r:
                    for p in r.group(1).split(':'):
                        self.rpath.append(p)
                    continue

                if BinaryInfo.comment_regex.search(line):
                    self.comment = True
                    continue

                if BinaryInfo.pic_regex.search(line):
                    self.non_pic = False
                    continue

                r = BinaryInfo.soname_regex.search(line)
                if r:
                    self.soname = r.group(1)
                    continue

                r = BinaryInfo.stack_regex.search(line)
                if r:
                    self.stack = True
                    flags = r.group(1)
                    if flags and BinaryInfo.stack_exec_regex.search(flags):
                        self.exec_stack = True
                    continue

                if line.startswith("Symbol table"):
                    break

            for line in lines:
                r = BinaryInfo.call_regex.search(line)
                if not r:
                    continue
                line = r.group(1)

                if BinaryInfo.mktemp_call_regex.search(line):
                    self.mktemp = True

                if BinaryInfo.setgid_call_regex.search(line):
                    self.setgid = True

                if BinaryInfo.setuid_call_regex.search(line):
                    self.setuid = True

                if BinaryInfo.setgroups_call_regex.search(line):
                    self.setgroups = True

                if BinaryInfo.chdir_call_regex.search(line):
                    self.chdir = True

                if BinaryInfo.chroot_call_regex.search(line):
                    self.chroot = True

                if BinaryInfo.forbidden_functions:
                    for r_name, func in BinaryInfo.forbidden_functions.items():
                        ret = func['f_regex'].search(line)
                        if ret:
                            self.forbidden_calls.append(r_name)

                if is_shlib:
                    r = BinaryInfo.exit_call_regex.search(line)
                    if r:
                        self.exit_calls.append(r.group(1))
                        continue
                    r = BinaryInfo.fork_call_regex.search(line)
                    if r:
                        fork_called = True
                        continue

            # check if we don't have a string that will automatically
            # waive the presence of a forbidden call
            if self.forbidden_calls:
                res = Pkg.getstatusoutput(('strings', path))
                if not res[0]:
                    for line in res[1].splitlines():
                        # as we need to remove elements, iterate backwards
                        for i in range(len(self.forbidden_calls) - 1, -1, -1):
                            func = self.forbidden_calls[i]
                            f = BinaryInfo.forbidden_functions[func]
                            if 'waiver_regex' not in f:
                                continue
                            r = f['waiver_regex'].search(line)
                            if r:
                                del self.forbidden_calls[i]

            if self.non_pic:
                self.non_pic = 'TEXTREL' in res[1]

            # Ignore all exit() calls if fork() is being called.
            # Does not have any context at all but without this kludge, the
            # number of false positives would probably be intolerable.
            if fork_called:
                self.exit_calls = []

            # check if chroot is near chdir (since otherwise, chroot is called
            # without chdir)
            if not BinaryInfo.objdump_call_regex and self.chroot and self.chdir:
                # On some architectures, e.g. PPC, it is to difficult to
                # find the actual invocations of chroot/chdir, if both
                # exist assume chroot is fine
                self.chroot_near_chdir = True

            elif self.chroot and self.chdir:
                p = subprocess.Popen(('objdump', '-d', path),
                                     stdout=subprocess.PIPE, bufsize=-1,
                                     env=dict(os.environ, LC_ALL="C"))
                with p.stdout:
                    index = 0
                    chroot_index = -99
                    chdir_index = -99
                    for line in p.stdout:
                        res = BinaryInfo.objdump_call_regex.search(line)
                        if not res:
                            continue
                        if b'@plt' not in res.group(1):
                            pass
                        elif b'chroot@plt' in res.group(1):
                            chroot_index = index
                            if abs(chroot_index - chdir_index) <= 2:
                                self.chroot_near_chdir = True
                                break
                        elif b'chdir@plt' in res.group(1):
                            chdir_index = index
                            if abs(chroot_index - chdir_index) <= 2:
                                self.chroot_near_chdir = True
                                break
                        index += 1
                if p.wait() and not self.chroot_near_chdir:
                    printWarning(pkg, 'binaryinfo-objdump-failed', fname)
                    self.chroot_near_chdir = True  # avoid false positive
                elif chroot_index == -99 and chdir_index == -99:
                    self.chroot_near_chdir = True  # avoid false positive

        else:
            self.readelf_error = True
            # Go and others are producing ar archives that don't have ELF
            # headers, so don't complain about it
            if not is_ar:
                printWarning(pkg, 'binaryinfo-readelf-failed',
                             fname, re.sub('\n.*', '', res[1]))

        try:
            with open(path, 'rb') as fobj:
                fobj.seek(-12, os.SEEK_END)
                self.tail = Pkg.b2s(fobj.read())
        except Exception as e:
            printWarning(pkg, 'binaryinfo-tail-failed %s: %s' % (fname, e))

        # Undefined symbol and unused direct dependency checks make sense only
        # for installed packages.
        # skip debuginfo: https://bugzilla.redhat.com/190599
        if not is_ar and not is_debug and isinstance(pkg, Pkg.InstalledPkg):
            # We could do this with objdump, but it's _much_ simpler with ldd.
            res = Pkg.getstatusoutput(('ldd', '-d', '-r', path))
            if not res[0]:
                for line in res[1].splitlines():
                    undef = BinaryInfo.undef_regex.search(line)
                    if undef:
                        self.undef.append(undef.group(1))
                if self.undef:
                    try:
                        res = Pkg.getstatusoutput(['c++filt'] + self.undef)
                        if not res[0]:
                            self.undef = res[1].splitlines()
                    except OSError:
                        pass
            else:
                printWarning(pkg, 'ldd-failed', fname)
            res = Pkg.getstatusoutput(('ldd', '-r', '-u', path))
            if res[0]:
                # Either ldd doesn't grok -u (added in glibc 2.3.4) or we have
                # unused direct dependencies
                in_unused = False
                for line in res[1].splitlines():
                    if not line.rstrip():
                        pass
                    elif line.startswith('Unused direct dependencies'):
                        in_unused = True
                    elif in_unused:
                        unused = BinaryInfo.unused_regex.search(line)
                        if unused:
                            self.unused.append(unused.group(1))
                        else:
                            in_unused = False
Exemple #56
0
    def check_aux(self, pkg, files, prog, script, tag, prereq):
        if script:
            if prog:
                if prog not in valid_shells:
                    printError(pkg, "invalid-shell-in-" + tag, prog)
                if prog in empty_shells:
                    printError(pkg, "non-empty-" + tag, prog)
            if prog in syntaxcheck_shells or prog == "/usr/bin/perl":
                if percent_regex.search(script):
                    printWarning(pkg, "percent-in-" + tag)
                if bracket_regex.search(script):
                    printWarning(pkg, "spurious-bracket-in-" + tag)
                res = dangerous_command_regex.search(script)
                if res:
                    printWarning(pkg, "dangerous-command-in-" + tag, res.group(2))
                res = selinux_regex.search(script)
                if res:
                    printError(pkg, "forbidden-selinux-command-in-" + tag, res.group(2))

                if "update-menus" in script:
                    menu_error = True
                    for f in files:
                        if menu_regex.search(f):
                            menu_error = False
                            break
                    if menu_error:
                        printError(pkg, "update-menus-without-menu-file-in-" + tag)
                if tmp_regex.search(script):
                    printError(pkg, "use-tmp-in-" + tag)
                for c in prereq_assoc:
                    if c[0].search(script):
                        found = False
                        for p in c[1]:
                            if p in prereq or p in files:
                                found = True
                                break
                        if not found:
                            printError(pkg, "no-prereq-on", c[1][0])

            if prog in syntaxcheck_shells:
                if incorrect_shell_script(prog, script):
                    printError(pkg, "shell-syntax-error-in-" + tag)
                if home_regex.search(script):
                    printError(pkg, "use-of-home-in-" + tag)
                res = bogus_var_regex.search(script)
                if res:
                    printWarning(pkg, "bogus-variable-use-in-" + tag, res.group(1))

            if prog == "/usr/bin/perl":
                if incorrect_perl_script(prog, script):
                    printError(pkg, "perl-syntax-error-in-" + tag)
            elif prog.endswith("sh"):
                res = single_command_regex.search(script)
                if res:
                    printWarning(pkg, "one-line-command-in-" + tag, res.group(1))

        elif prog not in empty_shells and prog in valid_shells:
            printWarning(pkg, "empty-" + tag)
Exemple #57
0
    def check_binary(self, pkg):
        files = pkg.files()
        menus = []

        for fname, pkgfile in files.items():
            # Check menu files
            res = menu_file_regex.search(fname)
            mode = pkgfile.mode
            if res:
                basename = res.group(1)
                if not stat.S_ISREG(mode):
                    printError(pkg, 'non-file-in-menu-dir', fname)
                else:
                    if basename != pkg.name:
                        printWarning(pkg, 'non-coherent-menu-filename', fname)
                    if mode & 0o444 != 0o444:
                        printError(pkg, 'non-readable-menu-file', fname)
                    if mode & 0o111:
                        printError(pkg, 'executable-menu-file', fname)
                    menus.append(fname)
            else:
                # Check old menus from KDE and GNOME
                res = old_menu_file_regex.search(fname)
                if res:
                    if stat.S_ISREG(mode):
                        printError(pkg, 'old-menu-entry', fname)
                else:
                    # Check non transparent xpm files
                    res = xpm_ext_regex.search(fname)
                    if res:
                        if stat.S_ISREG(mode) and not pkg.grep('None",', fname):
                            printWarning(pkg, 'non-transparent-xpm', fname)
                if fname.startswith('/usr/lib64/menu'):
                    printError(pkg, 'menu-in-wrong-dir', fname)

        if menus:
            postin = pkg[rpm.RPMTAG_POSTIN] or \
                pkg.scriptprog(rpm.RPMTAG_POSTINPROG)
            if not postin:
                printError(pkg, 'menu-without-postin')
            elif not update_menus_regex.search(postin):
                printError(pkg, 'postin-without-update-menus')

            postun = pkg[rpm.RPMTAG_POSTUN] or \
                pkg.scriptprog(rpm.RPMTAG_POSTUNPROG)
            if not postun:
                printError(pkg, 'menu-without-postun')
            elif not update_menus_regex.search(postun):
                printError(pkg, 'postun-without-update-menus')

            directory = pkg.dirName()
            for f in menus:
                # remove comments and handle cpp continuation lines
                cmd = Pkg.getstatusoutput(('/lib/cpp', directory + f), True)[1]

                for line in cmd.splitlines():
                    if not line.startswith('?'):
                        continue
                    res = package_regex.search(line)
                    if res:
                        package = res.group(1)
                        if package != pkg.name:
                            printWarning(pkg,
                                         'incoherent-package-value-in-menu',
                                         package, f)
                    else:
                        printInfo(pkg, 'unable-to-parse-menu-entry', line)

                    command = True
                    res = command_regex.search(line)
                    if res:
                        command_line = (res.group(1) or res.group(2)).split()
                        command = command_line[0]
                        for launcher in launchers:
                            if not launcher[0].search(command):
                                continue
                            found = False
                            if launcher[1]:
                                found = '/bin/' + command_line[0] in files or \
                                    '/usr/bin/' + command_line[0] in files or \
                                    '/usr/X11R6/bin/' + command_line[0] \
                                    in files
                                if not found:
                                    for l in launcher[1]:
                                        if l in pkg.req_names():
                                            found = True
                                            break
                                if not found:
                                    printError(pkg,
                                               'use-of-launcher-in-menu-but-no-requires-on',
                                               launcher[1][0])
                            command = command_line[1]
                            break

                        if command[0] == '/':
                            if command not in files:
                                printWarning(
                                    pkg, 'menu-command-not-in-package',
                                    command)
                        elif not ('/bin/' + command in files or
                                  '/usr/bin/' + command in files or
                                  '/usr/X11R6/bin/' + command in files):
                            printWarning(pkg, 'menu-command-not-in-package',
                                         command)
                    else:
                        printWarning(pkg, 'missing-menu-command')
                        command = False

                    res = longtitle_regex.search(line)
                    if res:
                        grp = res.groups()
                        title = grp[1] or grp[2]
                        if title[0] != title[0].upper():
                            printWarning(pkg, 'menu-longtitle-not-capitalized',
                                         title)
                        res = version_regex.search(title)
                        if res:
                            printWarning(pkg, 'version-in-menu-longtitle',
                                         title)
                    else:
                        printError(pkg, 'no-longtitle-in-menu', f)
                        title = None

                    res = title_regex.search(line)
                    if res:
                        grp = res.groups()
                        title = grp[1] or grp[2]
                        if title[0] != title[0].upper():
                            printWarning(pkg, 'menu-title-not-capitalized',
                                         title)
                        res = version_regex.search(title)
                        if res:
                            printWarning(pkg, 'version-in-menu-title', title)
                        if '/' in title:
                            printError(pkg, 'invalid-title', title)
                    else:
                        printError(pkg, 'no-title-in-menu', f)
                        title = None

                    res = needs_regex.search(line)
                    if res:
                        grp = res.groups()
                        needs = (grp[1] or grp[2]).lower()
                        if needs in ('x11', 'text', 'wm'):
                            res = section_regex.search(line)
                            if res:
                                grp = res.groups()
                                section = grp[1] or grp[2]
                                # don't warn entries for sections
                                if command and section not in valid_sections:
                                    printError(pkg, 'invalid-menu-section',
                                               section, f)
                            else:
                                printInfo(pkg, 'unable-to-parse-menu-section',
                                          line)
                        elif needs not in standard_needs:
                            printInfo(pkg, 'strange-needs', needs, f)
                    else:
                        printInfo(pkg, 'unable-to-parse-menu-needs', line)

                    res = icon_regex.search(line)
                    if res:
                        icon = res.group(1)
                        if not icon_ext_regex.search(icon):
                            printWarning(pkg, 'invalid-menu-icon-type', icon)
                        if icon[0] == '/' and needs == 'x11':
                            printWarning(pkg, 'hardcoded-path-in-menu-icon',
                                         icon)
                        else:
                            for path in icon_paths:
                                if (path[0] + icon) not in files:
                                    printError(
                                        pkg, path[1] + '-icon-not-in-package',
                                        icon, f)
                    else:
                        printWarning(pkg, 'no-icon-in-menu', title)

                    res = xdg_migrated_regex.search(line)
                    if res:
                        if not res.group(1).lower() == "true":
                            printError(pkg, 'non-xdg-migrated-menu')
                    else:
                        printError(pkg, 'non-xdg-migrated-menu')
Exemple #58
0
def spell_check(pkg, str, fmt, lang, ignored):

    dict_found = True
    warned = set()
    if enchant:
        if lang == 'C':
            lang = 'en_US'

        checker = _enchant_checkers.get(lang)
        if not checker and lang not in _enchant_checkers:
            try:
                checker = enchant.checker.SpellChecker(
                    lang, filters=[enchant.tokenize.EmailFilter,
                                   enchant.tokenize.URLFilter,
                                   enchant.tokenize.WikiWordFilter])
            except enchant.DictNotFoundError:
                printInfo(pkg, 'enchant-dictionary-not-found', lang)
                pass
            _enchant_checkers[lang] = checker

        if checker:
            # squeeze whitespace to ease leading context check
            checker.set_text(re.sub(r'\s+', ' ', str))
            if use_utf8:
                uppername = Pkg.to_unicode(pkg.header[rpm.RPMTAG_NAME]).upper()
            else:
                uppername = pkg.name.upper()
            upperparts = uppername.split('-')
            if lang.startswith('en'):
                ups = [x + "'S" for x in upperparts]
                upperparts.extend(ups)
            for err in checker:

                # Skip already warned and ignored words
                if err.word in warned or err.word in ignored:
                    continue

                # Skip all capitalized words that do not start a sentence
                if err.word[0].isupper() and not \
                        sentence_break_regex.search(checker.leading_context(3)):
                    continue

                upperword = err.word.upper()

                # Skip all uppercase words
                if err.word == upperword:
                    continue

                # Skip errors containing package name or equal to a
                # "component" of it, case insensitively
                if uppername in upperword or upperword in upperparts:
                    continue

                # Work around enchant's digit tokenizing behavior:
                # http://github.com/rfk/pyenchant/issues/issue/3
                if checker.leading_context(1).isdigit() or \
                        checker.trailing_context(1).isdigit():
                    continue

                # Warn and suggest
                sug = ', '.join(checker.suggest()[:3])
                if sug:
                    sug = '-> %s' % sug
                printWarning(pkg, 'spelling-error', fmt % lang, err.word, sug)
                warned.add(err.word)

        else:
            dict_found = False

    if not enchant or not dict_found:
        for seq in str.split():
            for word in re.split(r'[^a-z]+', seq.lower()):
                if len(word) == 0:
                    continue
                correct = BAD_WORDS.get(word)
                if not correct:
                    continue
                if word[0] == '\'':
                    word = word[1:]
                if word[-1] == '\'':
                    word = word[:-1]
                if word in warned or word in ignored:
                    continue
                printWarning(pkg, 'spelling-error', fmt % lang, word, '->',
                             correct)
                warned.add(word)