1 # -*- coding: utf-8 -*-
2 #############################################################################
3 # Project : Mandriva Linux
6 # Version : $Id: PostCheck.py 1885 2011-09-13 18:15:29Z scop $
7 # Author : Frederic Lepied
8 # Created On : Wed Jul 5 13:30:17 2000
9 # Purpose : Check post/pre scripts
10 #############################################################################
18 from Filter import addDetails, printError, printWarning
24 DEFAULT_VALID_SHELLS = ('<lua>',
32 DEFAULT_EMPTY_SHELLS = ('/sbin/ldconfig',
35 valid_shells = Config.getOption('ValidShells', DEFAULT_VALID_SHELLS)
36 empty_shells = Config.getOption('ValidEmptyShells', DEFAULT_EMPTY_SHELLS)
37 # shells that grok the -n switch for debugging
38 syntaxcheck_shells = ('/bin/sh', '/bin/bash')
40 percent_regex = re.compile('^[^#]*%{?\w{3,}', re.MULTILINE)
41 bracket_regex = re.compile('^[^#]*if.*[^ :\]]\]', re.MULTILINE)
42 home_regex = re.compile('[^a-zA-Z]+~/|\${?HOME(\W|$)', re.MULTILINE)
43 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)
44 selinux_regex = re.compile("(^|[;\|`]|&&|$\()\s*(?:\S*/s?bin/)?(chcon|runcon)\s", re.MULTILINE)
45 single_command_regex = re.compile("^[ \n]*([^ \n]+)[ \n]*$")
46 tmp_regex = re.compile('^[^#]*\s(/var)?/tmp', re.MULTILINE)
47 menu_regex = re.compile('^/usr/lib/menu/|^/etc/menu-methods/|^/usr/share/applications/')
48 bogus_var_regex = re.compile('(\${?RPM_BUILD_(ROOT|DIR)}?)')
51 # ['chkconfig', ('chkconfig', '/sbin/chkconfig')],
52 ['chkfontpath', ('chkfontpath', '/usr/sbin/chkfontpath')],
53 ['rpm-helper', ('rpm-helper',)],
56 for p in prereq_assoc:
57 p[0] = re.compile('^[^#]+' + p[0], re.MULTILINE)
63 (rpm.RPMTAG_PREIN, rpm.RPMTAG_PREINPROG, '%pre'),
64 (rpm.RPMTAG_POSTIN, rpm.RPMTAG_POSTINPROG, '%post'),
65 (rpm.RPMTAG_PREUN, rpm.RPMTAG_PREUNPROG, '%preun'),
66 (rpm.RPMTAG_POSTUN, rpm.RPMTAG_POSTUNPROG, '%postun'),
67 (rpm.RPMTAG_TRIGGERSCRIPTS, rpm.RPMTAG_TRIGGERSCRIPTPROG, '%trigger'),
68 (rpm.RPMTAG_PRETRANS, rpm.RPMTAG_PRETRANSPROG, '%pretrans'),
69 (rpm.RPMTAG_POSTTRANS, rpm.RPMTAG_POSTTRANSPROG, '%posttrans'),
70 (rpm.RPMTAG_VERIFYSCRIPT, rpm.RPMTAG_VERIFYSCRIPTPROG, '%verifyscript'),
73 def incorrect_shell_script(prog, shellscript):
76 # TODO: test that "prog" is available/executable
77 tmpfile, tmpname = Pkg.mktemp()
79 tmpfile.write(shellscript)
81 ret = Pkg.getstatusoutput((prog, '-n', tmpname))
87 def incorrect_perl_script(prog, perlscript):
90 # TODO: test that "prog" is available/executable
91 tmpfile, tmpname = Pkg.mktemp()
93 tmpfile.write(perlscript)
95 ret = Pkg.getstatusoutput((prog, '-wc', tmpname))
101 class PostCheck(AbstractCheck.AbstractCheck):
104 AbstractCheck.AbstractCheck.__init__(self, 'PostCheck')
106 def check(self, pkg):
107 # Check only binary package
111 prereq = [x[0] for x in pkg.prereq()]
114 for tag in script_tags:
117 if not isinstance(script, types.ListType):
118 prog = pkg.scriptprog(tag[1])
120 prog = prog.split()[0]
121 self.check_aux(pkg, files, prog, script, tag[2], prereq)
124 for idx in range(0, len(prog)):
126 pkg, files, prog[idx], script[idx], tag[2], prereq)
128 ghost_files = pkg.ghostFiles()
130 postin = pkg[rpm.RPMTAG_POSTIN]
131 prein = pkg[rpm.RPMTAG_PREIN]
132 if not postin and not prein:
133 printWarning(pkg, 'ghost-files-without-postin')
135 for f in ghost_files:
136 if (not postin or f not in postin) and \
137 (not prein or f not in prein) and \
138 f not in pkg.missingOkFiles():
140 'postin-without-ghost-file-creation', f)
142 def check_aux(self, pkg, files, prog, script, tag, prereq):
145 if prog not in valid_shells:
146 printError(pkg, 'invalid-shell-in-' + tag, prog)
147 if prog in empty_shells:
148 printError(pkg, 'non-empty-' + tag, prog)
149 if prog in syntaxcheck_shells or prog == '/usr/bin/perl':
150 if percent_regex.search(script):
151 printWarning(pkg, 'percent-in-' + tag)
152 if bracket_regex.search(script):
153 printWarning(pkg, 'spurious-bracket-in-' + tag)
154 res = dangerous_command_regex.search(script)
156 printWarning(pkg, 'dangerous-command-in-' + tag,
158 res = selinux_regex.search(script)
160 printError(pkg, 'forbidden-selinux-command-in-' + tag,
163 if 'update-menus' in script:
166 if menu_regex.search(f):
170 printError(pkg, 'update-menus-without-menu-file-in-' +
172 if tmp_regex.search(script):
173 printError(pkg, 'use-tmp-in-' + tag)
174 for c in prereq_assoc:
175 if c[0].search(script):
178 if p in prereq or p in files:
182 printError(pkg, 'no-prereq-on', c[1][0])
184 if prog in syntaxcheck_shells:
185 if incorrect_shell_script(prog, script):
186 printError(pkg, 'shell-syntax-error-in-' + tag)
187 if home_regex.search(script):
188 printError(pkg, 'use-of-home-in-' + tag)
189 res = bogus_var_regex.search(script)
191 printWarning(pkg, 'bogus-variable-use-in-' + tag,
194 if prog == '/usr/bin/perl':
195 if incorrect_perl_script(prog, script):
196 printError(pkg, 'perl-syntax-error-in-' + tag)
197 elif prog.endswith('sh'):
198 res = single_command_regex.search(script)
200 printWarning(pkg, 'one-line-command-in-' + tag,
203 elif prog not in empty_shells and prog in valid_shells:
204 printWarning(pkg, 'empty-' + tag)
206 # Create an object to enable the auto registration of the test
209 # Add information about checks
211 'postin-without-ghost-file-creation',
212 '''A file tagged as ghost is not created during %prein nor during %postin.''',
215 '%pre', '%post', '%preun', '%postun', '%pretrans', '%posttrans',
216 '%trigger', '%triggerin', '%triggerprein', '%triggerun', '%triggerpostun',
219 'one-line-command-in-%s' % scriptlet,
220 '''You should use %s -p <command> instead of using:
225 It will avoid the fork of a shell interpreter to execute your command as
226 well as allows rpm to automatically mark the dependency on your command
227 for the excecution of the scriptlet.''' % (scriptlet, scriptlet),
229 'percent-in-%s' % scriptlet,
230 '''The %s scriptlet contains a "%%" in a context which might indicate it being
231 fallout from an rpm macro/variable which was not expanded during build.
232 Investigate whether this is the case and fix if appropriate.''' % scriptlet,
234 'spurious-bracket-in-%s' % scriptlet,
235 '''The %s scriptlet contains an "if []" construct without a space before
236 the "]".''' % scriptlet,
238 'forbidden-selinux-command-in-%s' % scriptlet,
239 '''A command which requires intimate knowledge about a specific SELinux
240 policy type was found in the scriptlet. These types are subject to change
241 on a policy version upgrade. Use the restorecon command which queries the
242 currently loaded policy for the correct type instead.''',
244 'non-empty-%s' % scriptlet,
245 '''Scriptlets for the interpreter mentioned in the message should be empty.
246 One common case where they are unintentionally not is when the specfile
247 contains comments after the scriptlet and before the next section. Review
248 and clean up the scriptlet contents if appropriate.''',
251 # PostCheck.py ends here
254 # indent-tabs-mode: nil
255 # py-indent-offset: 4