2009-01-24 05:18:08 +08:00
|
|
|
# -*- coding: utf-8 -*-
|
2000-07-05 22:42:16 +08:00
|
|
|
#############################################################################
|
2005-04-16 04:01:46 +08:00
|
|
|
# Project : Mandriva Linux
|
2000-07-05 22:42:16 +08:00
|
|
|
# Module : rpmlint
|
|
|
|
# File : PostCheck.py
|
|
|
|
# Version : $Id$
|
|
|
|
# Author : Frederic Lepied
|
|
|
|
# Created On : Wed Jul 5 13:30:17 2000
|
|
|
|
# Purpose : Check post/pre scripts
|
|
|
|
#############################################################################
|
|
|
|
|
|
|
|
from Filter import *
|
|
|
|
import AbstractCheck
|
|
|
|
import rpm
|
|
|
|
import re
|
2000-08-01 03:45:17 +08:00
|
|
|
import os
|
2006-09-15 06:18:32 +08:00
|
|
|
import Pkg
|
2008-10-30 04:36:07 +08:00
|
|
|
import tempfile
|
2002-07-11 14:19:13 +08:00
|
|
|
import types
|
2000-08-01 03:45:17 +08:00
|
|
|
|
2008-10-30 07:01:44 +08:00
|
|
|
DEFAULT_VALID_SHELLS = ('<lua>',
|
|
|
|
'/bin/sh',
|
|
|
|
'/bin/bash',
|
|
|
|
'/sbin/sash',
|
|
|
|
'/usr/bin/perl',
|
|
|
|
'/sbin/ldconfig',
|
|
|
|
)
|
|
|
|
|
|
|
|
DEFAULT_EMPTY_SHELLS = ('/sbin/ldconfig',
|
|
|
|
)
|
|
|
|
|
|
|
|
extract_dir = Config.getOption('ExtractDir', tempfile.gettempdir())
|
|
|
|
valid_shells = Config.getOption('ValidShells', DEFAULT_VALID_SHELLS)
|
|
|
|
empty_shells = Config.getOption('ValidEmptyShells', DEFAULT_EMPTY_SHELLS)
|
2006-06-06 00:05:50 +08:00
|
|
|
# shells that grok the -n switch for debugging
|
|
|
|
syntaxcheck_shells = ('/bin/sh', '/bin/bash')
|
2000-08-01 03:45:17 +08:00
|
|
|
|
2008-04-30 03:48:11 +08:00
|
|
|
percent_regex = re.compile('^[^#]*%{?\w{3,}', re.MULTILINE)
|
2008-10-30 07:01:44 +08:00
|
|
|
bracket_regex = re.compile('^[^#]*if.*[^ :\]]\]', re.MULTILINE)
|
|
|
|
home_regex = re.compile('[^a-zA-Z]+~/|\${?HOME(\W|$)', re.MULTILINE)
|
|
|
|
dangerous_command_regex = re.compile("(^|[;\|`]|&&|$\()\s*(?:\S*/s?bin/)?(cp|mv|ln|tar|rpm|chmod|chown|rm|cpio|install|perl|userdel|groupdel)\s", re.MULTILINE)
|
|
|
|
selinux_regex = re.compile("(^|[;\|`]|&&|$\()\s*(?:\S*/s?bin/)?(chcon|runcon)\s", re.MULTILINE)
|
|
|
|
single_command_regex = re.compile("^[ \n]*([^ \n]+)[ \n]*$")
|
|
|
|
update_menu_regex = re.compile('update-menus', re.MULTILINE)
|
|
|
|
tmp_regex = re.compile('\s(/var)?/tmp', re.MULTILINE)
|
|
|
|
menu_regex = re.compile('^/usr/lib/menu/|^/etc/menu-methods/|^/usr/share/applications/')
|
|
|
|
bogus_var_regex = re.compile('(\${?RPM_BUILD_(ROOT|DIR)}?)')
|
2000-10-12 13:09:02 +08:00
|
|
|
|
2002-05-02 04:04:09 +08:00
|
|
|
prereq_assoc = (
|
|
|
|
# ['chkconfig', ('chkconfig', '/sbin/chkconfig')],
|
|
|
|
['chkfontpath', ('chkfontpath', '/usr/sbin/chkfontpath')],
|
2002-08-08 15:35:54 +08:00
|
|
|
['rpm-helper', ('rpm-helper',)],
|
2002-05-02 04:04:09 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
for p in prereq_assoc:
|
|
|
|
p[0] = re.compile('^[^#]+' + p[0], re.MULTILINE)
|
2005-11-28 05:49:15 +08:00
|
|
|
|
2006-06-28 22:01:13 +08:00
|
|
|
# pychecker fix
|
|
|
|
del p
|
|
|
|
|
2007-05-13 03:35:50 +08:00
|
|
|
script_tags = [
|
|
|
|
(rpm.RPMTAG_PREIN, rpm.RPMTAG_PREINPROG, '%pre'),
|
|
|
|
(rpm.RPMTAG_POSTIN, rpm.RPMTAG_POSTINPROG, '%post'),
|
|
|
|
(rpm.RPMTAG_PREUN, rpm.RPMTAG_PREUNPROG, '%preun'),
|
|
|
|
(rpm.RPMTAG_POSTUN, rpm.RPMTAG_POSTUNPROG, '%postun'),
|
|
|
|
(rpm.RPMTAG_TRIGGERSCRIPTS, rpm.RPMTAG_TRIGGERSCRIPTPROG, '%trigger'),
|
|
|
|
]
|
|
|
|
if hasattr(rpm, "RPMTAG_PRETRANS"):
|
|
|
|
script_tags.append(
|
|
|
|
(rpm.RPMTAG_PRETRANS, rpm.RPMTAG_PRETRANSPROG, '%pretrans'))
|
|
|
|
if hasattr(rpm, "RPMTAG_POSTTRANS"):
|
|
|
|
script_tags.append(
|
|
|
|
(rpm.RPMTAG_POSTTRANS, rpm.RPMTAG_POSTTRANSPROG, '%posttrans'))
|
|
|
|
|
2006-06-06 00:05:50 +08:00
|
|
|
def incorrect_shell_script(prog, shellscript):
|
2000-08-01 03:45:17 +08:00
|
|
|
if not shellscript:
|
|
|
|
return 0
|
2006-06-06 00:05:50 +08:00
|
|
|
# TODO: test that "prog" is available/executable
|
2007-05-14 03:15:39 +08:00
|
|
|
tmpfile, tmpname = Pkg.mktemp()
|
|
|
|
try:
|
|
|
|
tmpfile.write(shellscript)
|
|
|
|
tmpfile.close()
|
|
|
|
ret = Pkg.getstatusoutput((prog, '-n', tmpname))
|
|
|
|
finally:
|
|
|
|
tmpfile.close()
|
|
|
|
os.remove(tmpname)
|
2000-08-01 03:45:17 +08:00
|
|
|
return ret[0]
|
2000-07-05 22:42:16 +08:00
|
|
|
|
2006-06-06 14:40:18 +08:00
|
|
|
def incorrect_perl_script(prog, perlscript):
|
2000-08-29 06:08:02 +08:00
|
|
|
if not perlscript:
|
|
|
|
return 0
|
2006-06-06 00:05:50 +08:00
|
|
|
# TODO: test that "prog" is available/executable
|
2007-05-14 03:15:39 +08:00
|
|
|
tmpfile, tmpname = Pkg.mktemp()
|
|
|
|
try:
|
|
|
|
tmpfile.write(perlscript)
|
|
|
|
tmpfile.close()
|
|
|
|
ret = Pkg.getstatusoutput((prog, '-wc', tmpname))
|
|
|
|
finally:
|
|
|
|
tmpfile.close()
|
|
|
|
os.remove(tmpname)
|
2000-08-29 06:08:02 +08:00
|
|
|
return ret[0]
|
|
|
|
|
2000-07-05 22:42:16 +08:00
|
|
|
class PostCheck(AbstractCheck.AbstractCheck):
|
2005-11-28 05:49:15 +08:00
|
|
|
|
2000-07-05 22:42:16 +08:00
|
|
|
def __init__(self):
|
2002-07-11 14:19:13 +08:00
|
|
|
AbstractCheck.AbstractCheck.__init__(self, 'PostCheck')
|
2000-07-05 22:42:16 +08:00
|
|
|
|
2001-11-15 00:34:02 +08:00
|
|
|
def check(self, pkg):
|
2005-11-28 05:49:15 +08:00
|
|
|
# Check only binary package
|
|
|
|
if pkg.isSource():
|
|
|
|
return
|
2000-07-05 22:42:16 +08:00
|
|
|
|
2008-10-30 07:01:44 +08:00
|
|
|
prereq = map(lambda x: x[0], pkg.prereq())
|
|
|
|
files = pkg.files().keys()
|
2005-11-28 05:49:15 +08:00
|
|
|
|
2007-05-13 03:35:50 +08:00
|
|
|
for tag in script_tags:
|
2000-07-05 22:42:16 +08:00
|
|
|
script = pkg[tag[0]]
|
2000-08-01 03:45:17 +08:00
|
|
|
prog = pkg[tag[1]]
|
2001-02-02 14:51:57 +08:00
|
|
|
|
2002-07-11 14:19:13 +08:00
|
|
|
if type(script) != types.ListType:
|
2002-08-08 15:35:54 +08:00
|
|
|
self.check_aux(pkg, files, prog, script, tag, prereq)
|
2002-07-11 14:19:13 +08:00
|
|
|
else:
|
|
|
|
for idx in range(0, len(prog)):
|
2002-08-08 15:35:54 +08:00
|
|
|
self.check_aux(pkg, files, prog[idx], script[idx], tag, prereq)
|
2005-11-28 05:49:15 +08:00
|
|
|
|
2008-10-30 07:01:44 +08:00
|
|
|
ghost_files = pkg.ghostFiles()
|
2001-02-02 14:51:57 +08:00
|
|
|
if ghost_files:
|
2008-10-30 07:01:44 +08:00
|
|
|
postin = pkg[rpm.RPMTAG_POSTIN]
|
|
|
|
prein = pkg[rpm.RPMTAG_PREIN]
|
2004-02-13 04:24:42 +08:00
|
|
|
if not postin and not prein:
|
2001-09-15 00:01:20 +08:00
|
|
|
printWarning(pkg, 'ghost-files-without-postin')
|
2001-02-02 14:51:57 +08:00
|
|
|
else:
|
|
|
|
for f in ghost_files:
|
2007-08-13 02:19:03 +08:00
|
|
|
if (not postin or postin.find(f) == -1) and \
|
|
|
|
(not prein or prein.find(f) == -1) and \
|
|
|
|
not f in pkg.missingOkFiles():
|
2001-05-18 17:21:06 +08:00
|
|
|
printWarning(pkg, 'postin-without-ghost-file-creation', f)
|
2002-07-11 14:19:13 +08:00
|
|
|
|
2002-08-08 15:35:54 +08:00
|
|
|
def check_aux(self, pkg, files, prog, script, tag, prereq):
|
2002-07-11 14:19:13 +08:00
|
|
|
if script:
|
|
|
|
if prog:
|
|
|
|
if not prog in valid_shells:
|
|
|
|
printError(pkg, 'invalid-shell-in-' + tag[2], prog)
|
2005-03-20 05:31:22 +08:00
|
|
|
if prog in empty_shells:
|
|
|
|
printError(pkg, 'non-empty-' + tag[2], prog)
|
2006-06-06 00:05:50 +08:00
|
|
|
if prog in syntaxcheck_shells or prog == '/usr/bin/perl':
|
2007-05-12 16:55:05 +08:00
|
|
|
if percent_regex.search(script):
|
2002-07-11 14:19:13 +08:00
|
|
|
printWarning(pkg, 'percent-in-' + tag[2])
|
|
|
|
if bracket_regex.search(script):
|
|
|
|
printWarning(pkg, 'spurious-bracket-in-' + tag[2])
|
2008-10-30 07:01:44 +08:00
|
|
|
res = dangerous_command_regex.search(script)
|
2002-07-11 14:19:13 +08:00
|
|
|
if res:
|
|
|
|
printWarning(pkg, 'dangerous-command-in-' + tag[2], res.group(2))
|
2008-10-30 07:01:44 +08:00
|
|
|
res = selinux_regex.search(script)
|
2006-11-09 03:31:27 +08:00
|
|
|
if res:
|
|
|
|
printError(pkg, 'forbidden-selinux-command-in-' + tag[2], res.group(2))
|
|
|
|
|
2002-07-11 14:19:13 +08:00
|
|
|
if update_menu_regex.search(script):
|
2008-10-30 07:01:44 +08:00
|
|
|
menu_error = 1
|
2002-07-11 14:19:13 +08:00
|
|
|
for f in files:
|
|
|
|
if menu_regex.search(f):
|
2008-10-30 07:01:44 +08:00
|
|
|
menu_error = 0
|
2002-07-11 14:19:13 +08:00
|
|
|
break
|
|
|
|
if menu_error:
|
|
|
|
printError(pkg, 'update-menus-without-menu-file-in-' + tag[2])
|
|
|
|
if tmp_regex.search(script):
|
|
|
|
printError(pkg, 'use-tmp-in-' + tag[2])
|
|
|
|
for c in prereq_assoc:
|
|
|
|
if c[0].search(script):
|
2008-10-30 07:01:44 +08:00
|
|
|
found = 0
|
2002-07-11 14:19:13 +08:00
|
|
|
for p in c[1]:
|
|
|
|
if p in prereq or p in files:
|
2008-10-30 07:01:44 +08:00
|
|
|
found = 1
|
2002-07-11 14:19:13 +08:00
|
|
|
break
|
|
|
|
if not found:
|
|
|
|
printError(pkg, 'no-prereq-on', c[1][0])
|
2005-11-28 05:49:15 +08:00
|
|
|
|
2006-06-06 00:05:50 +08:00
|
|
|
if prog in syntaxcheck_shells:
|
|
|
|
if incorrect_shell_script(prog, script):
|
2002-07-11 14:19:13 +08:00
|
|
|
printError(pkg, 'shell-syntax-error-in-' + tag[2])
|
|
|
|
if home_regex.search(script):
|
|
|
|
printError(pkg, 'use-of-home-in-' + tag[2])
|
2008-10-30 07:01:44 +08:00
|
|
|
res = bogus_var_regex.search(script)
|
2002-07-11 14:19:13 +08:00
|
|
|
if res:
|
|
|
|
printWarning(pkg, 'bogus-variable-use-in-' + tag[2], res.group(1))
|
|
|
|
|
|
|
|
if prog == '/usr/bin/perl':
|
2006-06-06 00:05:50 +08:00
|
|
|
if incorrect_perl_script(prog, script):
|
2002-07-11 14:19:13 +08:00
|
|
|
printError(pkg, 'perl-syntax-error-in-' + tag[2])
|
2005-11-28 05:49:15 +08:00
|
|
|
|
2008-10-30 07:01:44 +08:00
|
|
|
res = single_command_regex.search(script)
|
2002-07-11 14:19:13 +08:00
|
|
|
if res:
|
|
|
|
printWarning(pkg, 'one-line-command-in-' + tag[2], res.group(1))
|
|
|
|
else:
|
2005-03-20 05:31:22 +08:00
|
|
|
if prog not in empty_shells and prog in valid_shells:
|
2002-07-11 14:19:13 +08:00
|
|
|
printWarning(pkg, 'empty-' + tag[2])
|
|
|
|
|
2000-07-05 22:42:16 +08:00
|
|
|
# Create an object to enable the auto registration of the test
|
2008-10-30 07:01:44 +08:00
|
|
|
check = PostCheck()
|
2000-07-05 22:42:16 +08:00
|
|
|
|
2001-06-20 19:32:12 +08:00
|
|
|
# Add information about checks
|
|
|
|
if Config.info:
|
|
|
|
addDetails(
|
2006-11-09 02:47:59 +08:00
|
|
|
'postin-without-ghost-file-creation',
|
|
|
|
'''A file tagged as ghost is not created during %prein nor during %postin.''',
|
|
|
|
)
|
2007-05-13 03:35:50 +08:00
|
|
|
for scriptlet in ('%pre', '%post', '%preun', '%postun', '%trigger', \
|
|
|
|
'%triggerin', '%triggerprein', '%triggerun', '%triggerpostun', \
|
|
|
|
'%pretrans', '%posttrans'):
|
2006-11-09 02:47:59 +08:00
|
|
|
addDetails(
|
|
|
|
'one-line-command-in-%s' % scriptlet,
|
|
|
|
'''You should use %s -p <command> instead of using:
|
2001-06-20 19:32:12 +08:00
|
|
|
|
2006-11-09 02:47:59 +08:00
|
|
|
%s
|
2001-06-20 19:32:12 +08:00
|
|
|
<command>
|
|
|
|
|
2004-02-12 15:17:25 +08:00
|
|
|
It will avoid the fork of a shell interpreter to execute your command as
|
2006-11-09 02:47:59 +08:00
|
|
|
well as allows rpm to automatically mark the dependency on your command
|
|
|
|
for the excecution of the scriptlet.''' % (scriptlet, scriptlet),
|
2001-06-20 19:32:12 +08:00
|
|
|
|
2007-05-12 16:55:05 +08:00
|
|
|
'percent-in-%s' % scriptlet,
|
|
|
|
'''The %s scriptlet contains a "%%" in a context which might indicate it being
|
|
|
|
fallout from an rpm macro/variable which was not expanded during build.
|
|
|
|
Investigate whether this is the case and fix if appropriate.''' % scriptlet,
|
|
|
|
|
2006-11-09 02:47:59 +08:00
|
|
|
'spurious-bracket-in-%s' % scriptlet,
|
|
|
|
'''The %s scriptlet contains an "if []" construct without a space before
|
|
|
|
the "]".''' % scriptlet,
|
2006-11-09 03:31:27 +08:00
|
|
|
|
|
|
|
'forbidden-selinux-command-in-%s' % scriptlet,
|
|
|
|
'''A command which requires intimate knowledge about a specific SELinux
|
|
|
|
policy type was found in the scriptlet. These types are subject to change
|
|
|
|
on a policy version upgrade. Use the restorecon command which queries the
|
2006-11-09 03:34:35 +08:00
|
|
|
currently loaded policy for the correct type instead.''',
|
2001-06-20 19:32:12 +08:00
|
|
|
)
|
|
|
|
|
2000-07-05 22:42:16 +08:00
|
|
|
# PostCheck.py ends here
|
2006-04-01 16:09:17 +08:00
|
|
|
|
|
|
|
# Local variables:
|
|
|
|
# indent-tabs-mode: nil
|
|
|
|
# py-indent-offset: 4
|
|
|
|
# End:
|
|
|
|
# ex: ts=4 sw=4 et
|