added local RPM support for listing files in RPM

This commit is contained in:
brent s 2018-11-26 06:49:12 -05:00
parent cfc48cac26
commit ca4a9e4b08
2 changed files with 73 additions and 38 deletions

View File

@ -4,6 +4,8 @@
# Definitely probably won't work on 5.x since they use MD5(?), and 6.5? and up # Definitely probably won't work on 5.x since they use MD5(?), and 6.5? and up
# use SHA256. # use SHA256.


# TODO: add support for .rpm files (like list_files_package.py)

import argparse import argparse
import copy import copy
import datetime import datetime

View File

@ -6,6 +6,7 @@


import argparse import argparse
import json import json
import os
import re import re
# For when CentOS/RHEL switch to python 3 by default (if EVER). # For when CentOS/RHEL switch to python 3 by default (if EVER).
import sys import sys
@ -13,7 +14,7 @@ pyver = sys.version_info
try: try:
import rpm import rpm
except ImportError: except ImportError:
exit('This script only runs on RHEL/CentOS/other RPM-based distros.') exit('This script only runs on the system-provided Python on RHEL/CentOS/other RPM-based distros.')


def all_pkgs(): def all_pkgs():
# Gets a list of all packages. # Gets a list of all packages.
@ -29,70 +30,106 @@ class FileGetter(object):
self.symlinks = symlinks self.symlinks = symlinks
self.verbose = verbose self.verbose = verbose
self.trns = rpm.TransactionSet() self.trns = rpm.TransactionSet()
self.files = {}
for p in kwargs['pkgs']:
if p not in self.files.keys():
self.getFiles(p)
if kwargs['rpm_files']:
self.getLocalFiles(kwargs['rpm_files'])


def getfiles(self, pkgnm): def getLocalFiles(self, rpm_files):
files = {} # Needed because the rpm module can't handle arbitrary rpm files??? If it can, someone let me know.
for pkg in self.trns.dbMatch('name', pkgnm): import yum
# The canonical package name for r in rpm_files:
_pkgnm = pkg.sprintf('%{NAME}') pkg = yum.YumLocalPackage(ts = self.trns,
# Return just a list of files, or a dict of filepath:hash filename = r)
# if verbose is enabled. _pkgnm = pkg.hdr.sprintf('%{NAME}')
if _pkgnm in self.files:
continue
if self.verbose: if self.verbose:
files[_pkgnm] = {} self.files[_pkgnm] = {}
else: else:
files[_pkgnm] = [] self.files[_pkgnm] = []
for f in pkg.fiFromHeader(): for f in pkg.hdr.fiFromHeader():
_symlink = (True if re.search('^0+$', f[12]) else False) _symlink = (True if re.search('^0+$', f[12]) else False)
if self.verbose: if self.verbose:
if _symlink: if _symlink:
if self.symlinks: if self.symlinks:
files[_pkgnm][f[0]] = '(symbolic link)' self.files[_pkgnm][f[0]] = '(symbolic link or directory)'
continue continue
files[_pkgnm][f[0]] = f[12] self.files[_pkgnm][f[0]] = f[12]
else: else:
# Skip if it is a symlink but they aren't enabled # Skip if it is a symlink but they aren't enabled
if _symlink and not self.symlinks: if _symlink and not self.symlinks:
continue continue
else: else:
files[_pkgnm].append(f[0]) self.files[_pkgnm].append(f[0])
files[_pkgnm].sort() self.files[_pkgnm].sort()
return(files) return()

def getFiles(self, pkgnm):
for pkg in self.trns.dbMatch('name', pkgnm):
# The canonical package name
_pkgnm = pkg.sprintf('%{NAME}')
# Return just a list of files, or a dict of filepath:hash if verbose is enabled.
if self.verbose:
self.files[_pkgnm] = {}
else:
self.files[_pkgnm] = []
for f in pkg.fiFromHeader():
_symlink = (True if re.search('^0+$', f[12]) else False)
if self.verbose:
if _symlink:
if self.symlinks:
self.files[_pkgnm][f[0]] = '(symbolic link)'
continue
self.files[_pkgnm][f[0]] = f[12]
else:
# Skip if it is a symlink but they aren't enabled
if _symlink and not self.symlinks:
continue
else:
self.files[_pkgnm].append(f[0])
self.files[_pkgnm].sort()
return()


def parseArgs(): def parseArgs():
args = argparse.ArgumentParser(description = ( args = argparse.ArgumentParser(description = ('This script allows you get a list of files for a given package '
'This script allows you get a list of files for a given ' 'name(s) without installing any extra packages (such as yum-utils '
'package name(s) without installing any extra packages ' 'for repoquery). It is highly recommended to use at least one '
'(such as yum-utils for repoquery).')) '-r/--rpm, -p/--package, or both.'))
args.add_argument('-l', '--ignore-symlinks', args.add_argument('-l', '--ignore-symlinks',
dest = 'symlinks', dest = 'symlinks',
action = 'store_false', action = 'store_false',
help = ('If specified, don\'t report files that are ' + help = ('If specified, don\'t report files that are symlinks in the RPM'))
'symlinks in the RPM'))
args.add_argument('-v', '--verbose', args.add_argument('-v', '--verbose',
dest = 'verbose', dest = 'verbose',
action = 'store_true', action = 'store_true',
help = ('If specified, include the hashes of the files')) help = ('If specified, include the hashes of the files'))
args.add_argument('-r', '--rpm',
dest = 'rpm_files',
metavar = 'PATH/TO/RPM',
action = 'append',
default = [],
help = ('If specified, use this RPM file instead of the system\'s RPM database. Can be '
'specified multiple times'))
args.add_argument('-p', '--package', args.add_argument('-p', '--package',
dest = 'pkgs', dest = 'pkgs',
#nargs = 1, #nargs = 1,
metavar = 'PKGNAME', metavar = 'PKGNAME',
action = 'append', action = 'append',
default = [], default = [],
help = ('If specified, restrict the list of ' + help = ('If specified, restrict the list of packages to check against to only this package. Can '
'packages to check against to only this ' + 'be specified multiple times. HIGHLY RECOMMENDED'))
'package. Can be specified multiple times. ' +
'HIGHLY RECOMMENDED'))
return(args) return(args)


def main(): def main():
args = vars(parseArgs().parse_args()) args = vars(parseArgs().parse_args())
if not args['pkgs']: args['rpm_files'] = [os.path.abspath(os.path.expanduser(i)) for i in args['rpm_files']]
prompt_str = ( if not any((args['rpm_files'], args['pkgs'])):
'You have not specified any package names.\nThis means we will ' prompt_str = ('You have not specified any package names.\nThis means we will get file lists for EVERY SINGLE '
'get file lists for EVERY SINGLE installed package.\nThis is a ' 'installed package.\nThis is a LOT of output and can take a few moments.\nIf this was a mistake, '
'LOT of output and can take a few moments.\nIf this was a ' 'you can hit ctrl-c now.\nOtherwise, hit the enter key to continue.\n')
'mistake, you can hit ctrl-c now.\nOtherwise, hit the enter key '
'to continue.\n')
sys.stderr.write(prompt_str) sys.stderr.write(prompt_str)
if pyver.major >= 3: if pyver.major >= 3:
input() input()
@ -100,11 +137,7 @@ def main():
raw_input() raw_input()
args['pkgs'] = all_pkgs() args['pkgs'] = all_pkgs()
gf = FileGetter(**args) gf = FileGetter(**args)
file_rslts = {} print(json.dumps(gf.files, indent = 4))
for p in args['pkgs']:
if p not in file_rslts.keys():
file_rslts[p] = gf.getfiles(p)
print(json.dumps(file_rslts, indent = 4))
return() return()


if __name__ == '__main__': if __name__ == '__main__':