From: Ludwig Nussel Date: Fri, 5 Sep 2014 12:53:40 +0200 Subject: [PATCH] add check for tmpfiles created at runtime this check parses files in /usr/lib/tmpfiles.d and verifies that entries that create files or directories are actually listed in %files. The check also handles the ghost file check as rpmlint shouldn't complain about ghost files handled by the tmpfiles mechanism. --- PostCheck.py | 18 --------- TmpFilesCheck.py | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 18 deletions(-) create mode 100644 TmpFilesCheck.py diff --git a/PostCheck.py b/PostCheck.py index 20b515e..6836359 100644 --- a/PostCheck.py +++ b/PostCheck.py @@ -112,20 +112,6 @@ class PostCheck(AbstractCheck.AbstractCheck): 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_aux(self, pkg, files, prog, script, tag, prereq): if script: if prog: @@ -194,10 +180,6 @@ class PostCheck(AbstractCheck.AbstractCheck): check = PostCheck() # Add information about checks -addDetails( -'postin-without-ghost-file-creation', -'''A file tagged as ghost is not created during %prein nor during %postin.''', -) for scriptlet in map(lambda x: '%' + x, RPM_SCRIPTLETS): addDetails( 'one-line-command-in-%s' % scriptlet, diff --git a/TmpFilesCheck.py b/TmpFilesCheck.py new file mode 100644 index 0000000..d1ef824 --- /dev/null +++ b/TmpFilesCheck.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- +############################################################################# +# File : TmpFilesCheck.py +# Package : rpmlint +# Author : Ludwig Nussel +# Created on : Wed Sep 03 10:36 2014 +# Purpose : Check systemd created tmpfiles are included in filelist +############################################################################# + +import os +import re + +from Filter import addDetails, printError, printWarning +import AbstractCheck +import Pkg +import stat +import rpm + +class TmpFilesCheck(AbstractCheck.AbstractCheck): + '''Check systemd created tmpfiles are included in filelist''' + + def __init__(self): + AbstractCheck.AbstractCheck.__init__(self, "TmpFilesCheck") + self._spec_file = None + + 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 + + pattern = re.compile(r'systemd-tmpfiles --create .*%s'%re.escape(fn)) + if (not postin or not pattern.search(postin)) and \ + (not prein or not pattern.search(prein)): + printWarning(pkg, + 'postin-without-tmpfile-creation', fn) + + for line in open(pkgfile.path): + # 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 not t in interesting_types: + continue + + tmp_files.add(p) + + if not p 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) + + + +check = TmpFilesCheck() + +addDetails( +'postin-without-ghost-file-creation', +'''A file tagged as ghost is not created during %prein nor during %postin.''', +'postin-without-tmpfile-creation', +'''Please use the %tmpfiles_create macro in %post for each of your tmpfiles.d files''', +'tmpfile-not-regular-file', +'''files in tmpfiles.d need to be regular files''', # otherwise we won't open it :-) +'tmpfile-not-in-filelist', +'''please add the specified file to your %files section as %ghost so +users can easily query who created the file, it gets uninstalled on +package removal and finally other rpmlint checks see it''', +'tmpfile-not-ghost', +'''the specified file is not marked as %ghost although created at +runtime via tmpfiles mechanism.''' +) +# vim: sw=4 et