96
127
unmatched.append(command)
100
130
unmatched.append(command)
102
matched = misc.unique(matched)
103
132
unmatched = misc.unique(unmatched)
104
exactmatch = misc.unique(exactmatch)
133
if unique == 'repo-epoch-name-version-release-arch': # pkg.__hash__
134
matched = misc.unique(matched)
135
exactmatch = misc.unique(exactmatch)
136
elif unique == 'repo-pkgkey': # So we get all pkg entries from a repo
140
mark = "%s%s" % (pkg.repo.id, pkg.pkgKey)
143
matched = pkgunique(matched)
144
exactmatch = pkgunique(exactmatch)
146
raise ValueError, "Bad value for unique: %s" % unique
105
147
return exactmatch, matched, unmatched
108
def returnBestPackages(pkgdict, arch=None):
109
"""returns a list of package tuples that are the 'best' packages for this
110
arch. Best == highest version and best scoring/sorting arch
111
should consider multiarch separately"""
113
compatArchList = rpmUtils.arch.getArchList(arch)
114
for pkgname in pkgdict.keys():
115
# go through the packages, pitch out the ones that can't be used
116
# on this system at all
117
pkglist = pkgdict[pkgname]
122
(n, a, e, v, r) = pkg
123
if a not in compatArchList:
125
elif rpmUtils.arch.isMultiLibArch(arch=a):
128
singleLib.append(pkg)
129
# we should have two lists now - one of singleLib packages
130
# one of multilib packages
131
# go through each one and find the best package(s)
132
for pkglist in [multiLib, singleLib]:
137
for pkg in pkglist[1:]:
138
best = bestPackage(best, pkg)
140
returnlist.append(best)
144
def bestPackage(pkg1, pkg2):
145
"""compares two package tuples (assumes the names are the same), and returns
146
the one with the best version and the best arch, the sorting is:
147
for compatible arches, the highest version is best so:
148
foo-1.1-1.i686 is better than foo-1.1-1.i386 on an i686 machine
149
but foo-1.2-1.alpha is not better than foo-1.1-1.i386 on an i686
150
machine and foo-1.3-1.i386 is better than foo-1.1-1.i686 on an i686
152
(n1, a1, e1, v1, r1) = pkg1
153
(n2, a2, e2, v2, r2) = pkg2
154
rc = rpmUtils.miscutils.compareEVR((e1, v1, r1), (e2, v2, r2))
157
bestarch = rpmUtils.arch.getBestArchFromList([a1, a2])
158
if bestarch is None: # how the hell did this happen?
149
class FakeRepository:
150
"""Fake repository class for use in rpmsack package objects"""
151
def __init__(self, repoid):
154
def __cmp__(self, other):
155
if self.id > other.id:
157
elif self.id < other.id:
169
169
# goal for the below is to have a packageobject that can be used by generic
170
170
# functions independent of the type of package - ie: installed or available
173
class YumInstalledPackage:
174
"""super class for dealing with packages in the rpmdb"""
175
def __init__(self, hdr):
176
"""hand in an rpm header, we'll assume it's installed and query from there"""
178
self.name = self.tagByName('name')
179
self.arch = self.tagByName('arch')
180
self.epoch = self.doepoch()
181
self.version = self.tagByName('version')
182
self.release = self.tagByName('release')
183
self.pkgtup = self._pkgtup()
184
self.repoid = 'installed'
185
self.summary = self.tagByName('summary')
186
self.description = self.tagByName('description')
187
self.pkgid = self.tagByName(rpm.RPMTAG_SHA1HEADER)
171
class PackageObject(object):
172
"""Base Package Object - sets up the default storage dicts and the
173
most common returns"""
181
# self.pkgtup = (self.name, self.arch, self.epoch, self.version, self.release)
182
self._checksums = [] # (type, checksum, id(0,1)
189
184
def __str__(self):
190
185
if self.epoch == '0':
191
val = '%s - %s-%s.%s' % (self.name, self.version, self.release,
194
val = '%s - %s:%s-%s.%s' % (self.name, self.epoch, self.version,
195
self.release, self.arch)
198
def tagByName(self, tag):
203
tmpepoch = self.hdr['epoch']
207
epoch = str(tmpepoch)
211
def returnSimple(self, thing):
212
if hasattr(self, thing):
213
return getattr(self, thing)
215
return self.tagByName(thing)
217
def returnLocalHeader(self):
186
out = '%s-%s-%s.%s' % (self.name,
191
out = '%s:%s-%s-%s.%s' % (self.epoch,
198
def __cmp__(self, other):
199
""" Compare packages. """
202
ret = cmp(self.name, other.name)
204
ret = comparePoEVR(self, other)
206
ret = cmp(self.arch, other.arch)
210
return "<%s : %s (%s)>" % (self.__class__.__name__, str(self),hex(id(self)))
212
def returnSimple(self, varname):
213
warnings.warn("returnSimple() will go away in a future version of Yum.\n",
214
Errors.YumFutureDeprecationWarning, stacklevel=2)
215
return getattr(self, varname)
217
def returnChecksums(self):
218
return self._checksums
220
checksums = property(fget=lambda self: self.returnChecksums())
222
def returnIdSum(self):
223
for (csumtype, csum, csumid) in self.checksums:
225
return (csumtype, csum)
227
class RpmBase(object):
228
"""return functions and storage for rpm-specific data"""
232
self.prco['obsoletes'] = [] # (name, flag, (e,v,r))
233
self.prco['conflicts'] = [] # (name, flag, (e,v,r))
234
self.prco['requires'] = [] # (name, flag, (e,v,r))
235
self.prco['provides'] = [] # (name, flag, (e,v,r))
237
self.files['file'] = []
238
self.files['dir'] = []
239
self.files['ghost'] = []
240
self._changelog = [] # (ctime, cname, ctext)
244
# Do we still need __eq__ and __ne__ given that
245
# PackageObject has a working __cmp__?
246
def __eq__(self, other):
247
if not other: # check if other not is a package object.
249
if comparePoEVR(self, other) == 0 and self.arch == other.arch and self.name == other.name:
253
def __ne__(self, other):
256
if comparePoEVR(self, other) != 0 or self.arch != other.arch or self.name != other.name:
261
return PackageEVR(self.epoch, self.version, self.release)
264
if self._hash is None:
265
mystr = '%s - %s:%s-%s-%s.%s' % (self.repo.id, self.epoch, self.name,
266
self.version, self.release, self.arch)
267
self._hash = hash(mystr)
270
def returnPrco(self, prcotype, printable=False):
271
"""return list of provides, requires, conflicts or obsoletes"""
274
if self.prco.has_key(prcotype):
275
prcos = self.prco[prcotype]
280
results.append(misc.prco_tuple_to_string(prco))
285
def checkPrco(self, prcotype, prcotuple):
286
"""returns 1 or 0 if the pkg contains the requested tuple/tuple range"""
287
# get rid of simple cases - nothing
288
if not self.prco.has_key(prcotype):
291
if prcotuple in self.prco[prcotype]:
294
# make us look it up and compare
295
(reqn, reqf, (reqe, reqv ,reqr)) = prcotuple
297
return self.inPrcoRange(prcotype, prcotuple)
299
for (n, f, (e, v, r)) in self.returnPrco(prcotype):
305
def inPrcoRange(self, prcotype, reqtuple):
306
"""returns true if the package has a the prco that satisfies
307
the reqtuple range, assume false.
308
Takes: prcotype, requested prco tuple"""
309
return bool(self.matchingPrcos(prcotype, reqtuple))
311
def matchingPrcos(self, prcotype, reqtuple):
312
# we only ever get here if we have a versioned prco
313
# nameonly shouldn't ever raise it
314
(reqn, reqf, (reqe, reqv, reqr)) = reqtuple
315
# however, just in case
316
# find the named entry in pkgobj, do the comparsion
318
for (n, f, (e, v, r)) in self.returnPrco(prcotype):
324
if f != 'EQ' and prcotype == 'provides':
325
# isn't this odd, it's not 'EQ' and it is a provides
326
# - it really should be EQ
327
# use the pkgobj's evr for the comparison
334
#(e, v, r) = (self.epoch, self.ver, self.rel)
336
matched = rpmUtils.miscutils.rangeCompare(
337
reqtuple, (n, f, (e, v, r)))
339
result.append((n, f, (e, v, r)))
345
def returnChangelog(self):
346
"""return changelog entries"""
347
return self._changelog
349
def returnFileEntries(self, ftype='file'):
350
"""return list of files based on type"""
351
# fixme - maybe should die - use direct access to attribute
353
if self.files.has_key(ftype):
354
return self.files[ftype]
357
def returnFileTypes(self):
358
"""return list of types of files in the package"""
359
# maybe should die - use direct access to attribute
360
return self.files.keys()
362
def returnPrcoNames(self, prcotype):
364
lists = self.returnPrco(prcotype)
365
for (name, flag, vertup) in lists:
221
369
def getProvidesNames(self):
222
"""returns a list of providesNames"""
224
provnames = self.tagByName('providename')
225
if type(provnames) is not types.ListType():
226
if type(provnames) is types.StringType():
227
provnames = [provnames]
233
def requiresList(self):
234
"""return a list of all of the strings of the package requirements"""
236
names = self.hdr[rpm.RPMTAG_REQUIRENAME]
237
flags = self.hdr[rpm.RPMTAG_REQUIREFLAGS]
238
ver = self.hdr[rpm.RPMTAG_REQUIREVERSION]
239
if names is not None:
240
tmplst = zip(names, flags, ver)
242
for (n, f, v) in tmplst:
243
req = rpmUtils.miscutils.formatRequire(n, v, f)
249
return (self.name, self.arch, self.epoch, self.version, self.release)
252
return self.tagByName('size')
255
"""returns a printable version string - including epoch, if it's set"""
256
if self.epoch != '0':
257
ver = '%s:%s-%s' % (self.epoch, self.version, self.release)
259
ver = '%s-%s' % (self.version, self.release)
263
def compactPrint(self):
264
ver = self.printVer()
265
return "%s.%s %s" % (self.name, self.arch, ver)
268
class YumLocalPackage(YumInstalledPackage):
269
"""Class to handle an arbitrary package from a file path
270
this inherits most things from YumInstalledPackage because
271
installed packages and an arbitrary package on disk act very
272
much alike. init takes a ts instance and a filename/path
275
def __init__(self, ts=None, filename=None):
277
raise Errors.MiscError, \
278
'No Transaction Set Instance for YumLocalPackage instance creation'
280
raise Errors.MiscError, \
281
'No Filename specified for YumLocalPackage instance creation'
283
self.pkgtype = 'local'
284
self.localpath = filename
285
self.repoid = filename
287
self.hdr = rpmUtils.miscutils.hdrFromPackage(ts, self.localpath)
288
except rpmUtils.RpmUtilsError, e:
289
raise Errors.MiscError, \
290
'Could not open local rpm file: %s' % self.localpath
291
self.name = self.tagByName('name')
292
self.arch = self.tagByName('arch')
293
self.epoch = self.doepoch()
294
self.version = self.tagByName('version')
295
self.release = self.tagByName('release')
296
self.summary = self.tagByName('summary')
297
self.description = self.tagByName('description')
298
self.pkgtup = self._pkgtup()
302
return (self.name, self.arch, self.epoch, self.version, self.release)
305
return self.localpath
310
class YumAvailablePackage(repomd.packageObject.PackageObject, repomd.packageObject.RpmBase):
311
"""derived class for the repomd packageobject and RpmBase packageobject yum
370
warnings.warn('getProvidesNames() will go away in a future version of Yum.\n',
371
Errors.YumDeprecationWarning, stacklevel=2)
372
return self.provides_names
374
def simpleFiles(self, ftype='files'):
375
if self.files and self.files.has_key(ftype):
376
return self.files[ftype]
379
filelist = property(fget=lambda self: self.returnFileEntries(ftype='file'))
380
dirlist = property(fget=lambda self: self.returnFileEntries(ftype='dir'))
381
ghostlist = property(fget=lambda self: self.returnFileEntries(ftype='ghost'))
382
requires = property(fget=lambda self: self.returnPrco('requires'))
383
provides = property(fget=lambda self: self.returnPrco('provides'))
384
obsoletes = property(fget=lambda self: self.returnPrco('obsoletes'))
385
conflicts = property(fget=lambda self: self.returnPrco('conflicts'))
386
provides_names = property(fget=lambda self: self.returnPrcoNames('provides'))
387
requires_names = property(fget=lambda self: self.returnPrcoNames('requires'))
388
conflicts_names = property(fget=lambda self: self.returnPrcoNames('conflicts'))
389
obsoletes_names = property(fget=lambda self: self.returnPrcoNames('obsoletes'))
390
provides_print = property(fget=lambda self: self.returnPrco('provides', True))
391
requires_print = property(fget=lambda self: self.returnPrco('requires', True))
392
conflicts_print = property(fget=lambda self: self.returnPrco('conflicts', True))
393
obsoletes_print = property(fget=lambda self: self.returnPrco('obsoletes', True))
394
changelog = property(fget=lambda self: self.returnChangelog())
395
EVR = property(fget=lambda self: self.returnEVR())
400
A comparable epoch, version, and release representation.
403
def __init__(self,e,v,r):
408
def compare(self,other):
409
return rpmUtils.miscutils.compareEVR((self.epoch, self.ver, self.rel), (other.epoch, other.ver, other.rel))
411
def __lt__(self, other):
412
if self.compare(other) < 0:
417
def __gt__(self, other):
418
if self.compare(other) > 0:
422
def __le__(self, other):
423
if self.compare(other) <= 0:
427
def __ge__(self, other):
428
if self.compare(other) >= 0:
432
def __eq__(self, other):
433
if self.compare(other) == 0:
437
def __ne__(self, other):
438
if self.compare(other) != 0:
444
class YumAvailablePackage(PackageObject, RpmBase):
445
"""derived class for the packageobject and RpmBase packageobject yum
312
446
uses this for dealing with packages in a repository"""
314
def __init__(self, pkgdict, repoid):
315
repomd.packageObject.PackageObject.__init__(self)
316
repomd.packageObject.RpmBase.__init__(self)
318
self.importFromDict(pkgdict, repoid)
319
# quick, common definitions
320
self.name = self.returnSimple('name')
321
self.epoch = self.returnSimple('epoch')
322
self.version = self.returnSimple('version')
323
self.release = self.returnSimple('release')
324
self.arch = self.returnSimple('arch')
325
self.repoid = self.returnSimple('repoid')
326
self.pkgtup = self._pkgtup()
329
return self.returnSimple('packagesize')
332
return self.returnPackageTuple()
448
def __init__(self, repo, pkgdict = None):
449
PackageObject.__init__(self)
450
RpmBase.__init__(self)
452
self.repoid = repo.id
455
self._loadedfiles = False
458
self.importFromDict(pkgdict)
459
self.ver = self.version
460
self.rel = self.release
461
self.pkgtup = (self.name, self.arch, self.epoch, self.version, self.release)
464
"""remove self from package sack"""
465
self.repo.sack.delPackage(self)
334
467
def printVer(self):
335
468
"""returns a printable version string - including epoch, if it's set"""
336
469
if self.epoch != '0':
386
585
if not hasattr(self, 'hdrpath'):
387
repo = base.repos.getRepo(self.repoid)
388
pkgpath = self.returnSimple('relativepath')
389
pkgname = os.path.basename(pkgpath)
586
pkgname = os.path.basename(self.remote_path)
390
587
hdrname = pkgname[:-4] + '.hdr'
391
self.hdrpath = repo.hdrdir + '/' + hdrname
588
self.hdrpath = self.repo.hdrdir + '/' + hdrname
393
590
return self.hdrpath
592
def verifyLocalPkg(self):
593
"""check the package checksum vs the localPkg
594
return True if pkg is good, False if not"""
596
(csum_type, csum) = self.returnIdSum()
599
filesum = misc.checksum(csum_type, self.localPkg())
600
except Errors.MiscError:
395
608
def prcoPrintable(self, prcoTuple):
396
609
"""convert the prco tuples into a nicer human string"""
397
(name, flag, (e, v, r)) = prcoTuple
398
flags = {'GT':'>', 'GE':'>=', 'EQ':'=', 'LT':'<', 'LE':'<='}
402
base = '%s %s ' % (name, flags[flag])
403
if e not in [0, '0', None]:
610
warnings.warn('prcoPrintable() will go away in a future version of Yum.\n',
611
Errors.YumDeprecationWarning, stacklevel=2)
612
return misc.prco_tuple_to_string(prcoTuple)
412
614
def requiresList(self):
413
615
"""return a list of requires in normal rpm format"""
417
for prcoTuple in self.returnPrco('requires'):
418
prcostr = self.prcoPrintable(prcoTuple)
419
reqlist.append(prcostr)
423
def importFromDict(self, pkgdict, repoid):
616
return self.requires_print
618
def importFromDict(self, pkgdict):
424
619
"""handles an mdCache package dictionary item to populate out
425
620
the package information"""
427
self.simple['repoid'] = repoid
428
622
# translates from the pkgdict, populating out the information for the
431
625
if hasattr(pkgdict, 'nevra'):
432
626
(n, e, v, r, a) = pkgdict.nevra
433
self.simple['name'] = n
434
self.simple['epoch'] = e
435
self.simple['version'] = v
436
self.simple['arch'] = a
437
self.simple['release'] = r
439
633
if hasattr(pkgdict, 'time'):
440
self.simple['buildtime'] = pkgdict.time['build']
441
self.simple['filetime'] = pkgdict.time['file']
634
self.buildtime = pkgdict.time['build']
635
self.filetime = pkgdict.time['file']
443
637
if hasattr(pkgdict, 'size'):
444
self.simple['packagesize'] = pkgdict.size['package']
445
self.simple['archivesize'] = pkgdict.size['archive']
446
self.simple['installedsize'] = pkgdict.size['installed']
638
self.packagesize = pkgdict.size['package']
639
self.archivesize = pkgdict.size['archive']
640
self.installedsize = pkgdict.size['installed']
448
642
if hasattr(pkgdict, 'location'):
449
if pkgdict.location['value'] == '':
643
if not pkgdict.location.has_key('base'):
645
elif pkgdict.location['base'] == '':
452
url = pkgdict.location['value']
454
self.simple['basepath'] = url
455
self.simple['relativepath'] = pkgdict.location['href']
648
url = pkgdict.location['base']
651
self.relativepath = pkgdict.location['href']
457
653
if hasattr(pkgdict, 'hdrange'):
458
self.simple['hdrstart'] = pkgdict.hdrange['start']
459
self.simple['hdrend'] = pkgdict.hdrange['end']
654
self.hdrstart = pkgdict.hdrange['start']
655
self.hdrend = pkgdict.hdrange['end']
461
657
if hasattr(pkgdict, 'info'):
462
infodict = pkgdict.info
463
658
for item in ['summary', 'description', 'packager', 'group',
464
659
'buildhost', 'sourcerpm', 'url', 'vendor']:
465
self.simple[item] = infodict[item]
660
setattr(self, item, pkgdict.info[item])
661
self.summary = self.summary.replace('\n', '')
467
self.licenses.append(infodict['license'])
663
self.licenses.append(pkgdict.info['license'])
469
665
if hasattr(pkgdict, 'files'):
470
for file in pkgdict.files.keys():
471
ftype = pkgdict.files[file]
666
for fn in pkgdict.files:
667
ftype = pkgdict.files[fn]
472
668
if not self.files.has_key(ftype):
473
669
self.files[ftype] = []
474
self.files[ftype].append(file)
670
self.files[ftype].append(fn)
476
672
if hasattr(pkgdict, 'prco'):
477
for rtype in pkgdict.prco.keys():
673
for rtype in pkgdict.prco:
478
674
for rdict in pkgdict.prco[rtype]:
479
675
name = rdict['name']
480
676
f = e = v = r = None
505
self.checksums.append((ctype, csum, csumid))
701
self._checksums.append((ctype, csum, csumid))
704
class YumHeaderPackage(YumAvailablePackage):
705
"""Package object built from an rpm header"""
706
def __init__(self, repo, hdr):
707
"""hand in an rpm header, we'll assume it's installed and query from there"""
709
YumAvailablePackage.__init__(self, repo)
712
self.name = self.hdr['name']
713
self.arch = self.hdr['arch']
714
self.epoch = self.doepoch()
715
self.version = self.hdr['version']
716
self.release = self.hdr['release']
717
self.ver = self.version
718
self.rel = self.release
719
self.pkgtup = (self.name, self.arch, self.epoch, self.version, self.release)
720
self.summary = self.hdr['summary'].replace('\n', '')
721
self.description = self.hdr['description']
722
self.pkgid = self.hdr[rpm.RPMTAG_SHA1HEADER]
724
self.pkgid = "%s.%s" %(self.hdr['name'], self.hdr['buildtime'])
725
self.packagesize = self.hdr['size']
726
self.__mode_cache = {}
727
self.__prcoPopulated = False
730
if self.epoch == '0':
731
val = '%s-%s-%s.%s' % (self.name, self.version, self.release,
734
val = '%s:%s-%s-%s.%s' % (self.epoch,self.name, self.version,
735
self.release, self.arch)
738
def returnPrco(self, prcotype, printable=False):
739
if not self.__prcoPopulated:
741
self.__prcoPopulated = True
742
return YumAvailablePackage.returnPrco(self, prcotype, printable)
744
def _populatePrco(self):
745
"Populate the package object with the needed PRCO interface."
747
tag2prco = { "OBSOLETE": "obsoletes",
748
"CONFLICT": "conflicts",
749
"REQUIRE": "requires",
750
"PROVIDE": "provides" }
752
name = self.hdr[getattr(rpm, 'RPMTAG_%sNAME' % tag)]
754
lst = self.hdr[getattr(rpm, 'RPMTAG_%sFLAGS' % tag)]
755
flag = map(rpmUtils.miscutils.flagToString, lst)
757
lst = self.hdr[getattr(rpm, 'RPMTAG_%sVERSION' % tag)]
758
vers = map(rpmUtils.miscutils.stringToVersion, lst)
760
prcotype = tag2prco[tag]
762
self.prco[prcotype] = zip(name, flag, vers)
764
def tagByName(self, tag):
765
warnings.warn("tagByName() will go away in a furture version of Yum.\n",
766
Errors.YumFutureDeprecationWarning, stacklevel=2)
768
return getattr(self, tag)
769
except AttributeError:
770
raise Errors.MiscError, "Unknown header tag %s" % tag
772
def __getattr__(self, thing):
773
return self.hdr[thing]
776
tmpepoch = self.hdr['epoch']
780
epoch = str(tmpepoch)
784
def returnLocalHeader(self):
788
def _loadFiles(self):
789
files = self.hdr['filenames']
790
fileflags = self.hdr['fileflags']
791
filemodes = self.hdr['filemodes']
792
filetuple = zip(files, filemodes, fileflags)
793
if not self._loadedfiles:
794
for (fn, mode, flag) in filetuple:
796
if mode is None or mode == '':
797
if not self.files.has_key('file'):
798
self.files['file'] = []
799
self.files['file'].append(fn)
801
if not self.__mode_cache.has_key(mode):
802
self.__mode_cache[mode] = stat.S_ISDIR(mode)
804
if self.__mode_cache[mode]:
805
if not self.files.has_key('dir'):
806
self.files['dir'] = []
807
self.files['dir'].append(fn)
810
if not self.files.has_key('file'):
811
self.files['file'] = []
812
self.files['file'].append(fn)
815
if not self.files.has_key('ghost'):
816
self.files['ghost'] = []
817
self.files['ghost'].append(fn)
819
if not self.files.has_key('file'):
820
self.files['file'] = []
821
self.files['file'].append(fn)
822
self._loadedfiles = True
824
def returnFileEntries(self, ftype='file'):
825
"""return list of files based on type"""
827
return YumAvailablePackage.returnFileEntries(self,ftype)
829
def returnChangelog(self):
830
# note - if we think it is worth keeping changelogs in memory
831
# then create a _loadChangelog() method to put them into the
832
# self._changelog attr
833
if len(self.hdr['changelogname']) > 0:
834
return zip(self.hdr['changelogtime'],
835
self.hdr['changelogname'],
836
self.hdr['changelogtext'])
839
class _CountedReadFile:
840
""" Has just a read() method, and keeps a count so we can find out how much
841
has been read. Implemented so we can get the real size of the file from
844
def __init__(self, fp):
848
def read(self, size):
849
ret = self.fp.read(size)
850
self.read_size += len(ret)
853
class _PkgVerifyProb:
854
""" Holder for each "problem" we find with a pkg.verify(). """
856
def __init__(self, type, msg, ftypes, fake=False):
859
self.database_value = None
860
self.disk_value = None
861
self.file_types = ftypes
864
def __cmp__(self, other):
867
type2sort = {'type' : 1, 'symlink' : 2, 'checksum' : 3, 'size' : 4,
868
'user' : 4, 'group' : 5, 'mode' : 6, 'genchecksum' : 7,
869
'mtime' : 8, 'missing' : 9, 'permissions-missing' : 10,
870
'state' : 11, 'missingok' : 12, 'ghost' : 13}
871
ret = cmp(type2sort[self.type], type2sort[other.type])
873
for attr in ['disk_value', 'database_value', 'file_types']:
874
x = getattr(self, attr)
875
y = getattr(other, attr)
884
# From: lib/rpmvf.h ... not in rpm *sigh*
885
_RPMVERIFY_MD5 = (1 << 0)
886
_RPMVERIFY_FILESIZE = (1 << 1)
887
_RPMVERIFY_LINKTO = (1 << 2)
888
_RPMVERIFY_USER = (1 << 3)
889
_RPMVERIFY_GROUP = (1 << 4)
890
_RPMVERIFY_MTIME = (1 << 5)
891
_RPMVERIFY_MODE = (1 << 6)
892
_RPMVERIFY_RDEV = (1 << 7)
894
_installed_repo = FakeRepository('installed')
895
_installed_repo.cost = 0
896
class YumInstalledPackage(YumHeaderPackage):
897
"""super class for dealing with packages in the rpmdb"""
898
def __init__(self, hdr):
899
fakerepo = _installed_repo
900
YumHeaderPackage.__init__(self, fakerepo, hdr)
902
def verify(self, patterns=[], deps=False, script=False,
903
fake_problems=True, all=False):
904
"""verify that the installed files match the packaged checksum
905
optionally verify they match only if they are in the 'pattern' list
908
""" Given a "mode" return the name of the type of file. """
909
if stat.S_ISREG(mode): return "file"
910
if stat.S_ISDIR(mode): return "directory"
911
if stat.S_ISLNK(mode): return "symlink"
912
if stat.S_ISFIFO(mode): return "fifo"
913
if stat.S_ISCHR(mode): return "character device"
914
if stat.S_ISBLK(mode): return "block device"
917
statemap = {rpm.RPMFILE_STATE_REPLACED : 'replaced',
918
rpm.RPMFILE_STATE_NOTINSTALLED : 'not installed',
919
rpm.RPMFILE_STATE_WRONGCOLOR : 'wrong color',
920
rpm.RPMFILE_STATE_NETSHARED : 'netshared'}
922
fi = self.hdr.fiFromHeader()
923
results = {} # fn = problem_obj?
925
# Use prelink_undo_cmd macro?
926
prelink_cmd = "/usr/sbin/prelink"
927
have_prelink = os.path.exists(prelink_cmd)
930
#tuple is: (filename, fsize, mode, mtime, flags, frdev?, inode, link,
931
# state, vflags?, user, group, md5sum(or none for dirs)
932
(fn, size, mode, mtime, flags, dev, inode, link, state, vflags,
933
user, group, csum) = filetuple
937
if fnmatch.fnmatch(fn, p):
944
if flags & rpm.RPMFILE_CONFIG:
945
ftypes.append('configuration')
946
if flags & rpm.RPMFILE_DOC:
947
ftypes.append('documentation')
948
if flags & rpm.RPMFILE_GHOST:
949
ftypes.append('ghost')
950
if flags & rpm.RPMFILE_LICENSE:
951
ftypes.append('license')
952
if flags & rpm.RPMFILE_PUBKEY:
953
ftypes.append('public key')
954
if flags & rpm.RPMFILE_README:
955
ftypes.append('README')
956
if flags & rpm.RPMFILE_MISSINGOK:
957
ftypes.append('missing ok')
958
# not in python rpm bindings yet
959
# elif flags & rpm.RPMFILE_POLICY:
960
# ftypes.append('policy')
965
if state != rpm.RPMFILE_STATE_NORMAL:
966
if state in statemap:
967
ftypes.append("state=" + statemap[state])
969
ftypes.append("state=<unknown>")
971
results[fn] = [_PkgVerifyProb('state',
972
'state is not normal',
976
if flags & rpm.RPMFILE_MISSINGOK and fake_problems:
977
results[fn] = [_PkgVerifyProb('missingok', 'missing but ok',
979
if flags & rpm.RPMFILE_MISSINGOK and not all:
980
continue # rpm just skips missing ok, so we do too
982
if flags & rpm.RPMFILE_GHOST and fake_problems:
983
results[fn] = [_PkgVerifyProb('ghost', 'ghost file', ftypes,
985
if flags & rpm.RPMFILE_GHOST and not all:
988
# do check of file status on system
990
if os.path.exists(fn):
993
my_st_size = my_st.st_size
994
my_user = pwd.getpwuid(my_st[stat.ST_UID])[0]
995
my_group = grp.getgrgid(my_st[stat.ST_GID])[0]
998
# Stupid rpm, should be unsigned value but is signed ...
999
# so we "fix" it via. this hack
1000
mode = (mode & 0xFFFF)
1002
ftype = _ftype(mode)
1003
my_ftype = _ftype(my_st.st_mode)
1005
if vflags & _RPMVERIFY_RDEV and ftype != my_ftype:
1006
prob = _PkgVerifyProb('type', 'file type does not match',
1008
prob.database_value = ftype
1009
prob.disk_value = my_ftype
1010
problems.append(prob)
1012
if (ftype == "symlink" and my_ftype == "symlink" and
1013
vflags & _RPMVERIFY_LINKTO):
1014
fnl = fi.FLink() # fi.foo is magic, don't think about it
1015
my_fnl = os.readlink(fn)
1017
prob = _PkgVerifyProb('symlink',
1018
'symlink does not match', ftypes)
1019
prob.database_value = fnl
1020
prob.disk_value = my_fnl
1021
problems.append(prob)
1023
check_content = True
1024
if 'ghost' in ftypes:
1025
check_content = False
1026
if my_ftype == "symlink" and ftype == "file":
1027
# Don't let things hide behind symlinks
1028
my_st_size = os.stat(fn).st_size
1029
elif my_ftype != "file":
1030
check_content = False
1032
if my_ftype == "symlink":
1035
if (check_content and vflags & _RPMVERIFY_MTIME and
1036
my_st.st_mtime != mtime):
1037
prob = _PkgVerifyProb('mtime', 'mtime does not match',
1039
prob.database_value = mtime
1040
prob.disk_value = my_st.st_mtime
1041
problems.append(prob)
1043
if check_perms and vflags & _RPMVERIFY_USER and my_user != user:
1044
prob = _PkgVerifyProb('user', 'user does not match', ftypes)
1045
prob.database_value = user
1046
prob.disk_value = my_user
1047
problems.append(prob)
1048
if (check_perms and vflags & _RPMVERIFY_GROUP and
1050
prob = _PkgVerifyProb('group', 'group does not match',
1052
prob.database_value = group
1053
prob.disk_value = my_group
1054
problems.append(prob)
1056
my_mode = my_st.st_mode
1057
if 'ghost' in ftypes: # This is what rpm does
1060
if check_perms and vflags & _RPMVERIFY_MODE and my_mode != mode:
1061
prob = _PkgVerifyProb('mode', 'mode does not match', ftypes)
1062
prob.database_value = mode
1063
prob.disk_value = my_st.st_mode
1064
problems.append(prob)
1066
# Note that because we might get the _size_ from prelink,
1067
# we need to do the checksum, even if we just throw it away,
1068
# just so we get the size correct.
1069
if (check_content and
1070
((have_prelink and vflags & _RPMVERIFY_FILESIZE) or
1071
(csum and vflags & _RPMVERIFY_MD5))):
1073
my_csum = misc.checksum('md5', fn)
1075
except Errors.MiscError:
1076
# Don't have permission?
1079
if csum and vflags & _RPMVERIFY_MD5 and not gen_csum:
1080
prob = _PkgVerifyProb('genchecksum',
1081
'checksum not available', ftypes)
1082
prob.database_value = csum
1083
prob.disk_value = None
1084
problems.append(prob)
1086
if gen_csum and my_csum != csum and have_prelink:
1087
# This is how rpm -V works, try and if that fails try
1088
# again with prelink.
1089
(ig, fp,er) = os.popen3([prelink_cmd, "-y", fn])
1090
# er.read(1024 * 1024) # Try and get most of the stderr
1091
fp = _CountedReadFile(fp)
1092
my_csum = misc.checksum('md5', fp)
1093
my_st_size = fp.read_size
1095
if (csum and vflags & _RPMVERIFY_MD5 and gen_csum and
1097
prob = _PkgVerifyProb('checksum',
1098
'checksum does not match', ftypes)
1099
prob.database_value = csum
1100
prob.disk_value = my_csum
1101
problems.append(prob)
1103
# Size might be got from prelink ... *sigh*.
1104
if (check_content and vflags & _RPMVERIFY_FILESIZE and
1105
my_st_size != size):
1106
prob = _PkgVerifyProb('size', 'size does not match', ftypes)
1107
prob.database_value = size
1108
prob.disk_value = my_st.st_size
1109
problems.append(prob)
1114
perms_ok = True # Shouldn't happen
1117
if e.errno == errno.EACCES:
1121
prob = _PkgVerifyProb('missing', 'file is missing', ftypes)
1123
prob = _PkgVerifyProb('permissions-missing',
1124
'file is missing (Permission denied)',
1126
problems.append(prob)
1129
results[fn] = problems
1134
class YumLocalPackage(YumHeaderPackage):
1135
"""Class to handle an arbitrary package from a file path
1136
this inherits most things from YumInstalledPackage because
1137
installed packages and an arbitrary package on disk act very
1138
much alike. init takes a ts instance and a filename/path
1141
def __init__(self, ts=None, filename=None):
1143
raise Errors.MiscError, \
1144
'No Transaction Set Instance for YumLocalPackage instance creation'
1145
if filename is None:
1146
raise Errors.MiscError, \
1147
'No Filename specified for YumLocalPackage instance creation'
1149
self.pkgtype = 'local'
1150
self.localpath = filename
1151
self._checksum = None
1155
hdr = rpmUtils.miscutils.hdrFromPackage(ts, self.localpath)
1156
except RpmUtilsError:
1157
raise Errors.MiscError, \
1158
'Could not open local rpm file: %s' % self.localpath
1160
fakerepo = FakeRepository(filename)
1162
YumHeaderPackage.__init__(self, fakerepo, hdr)
1163
self.id = self.pkgid
1164
self._stat = os.stat(self.localpath)
1165
self.filetime = str(self._stat[-1])
1166
self.packagesize = str(self._stat[6])
1169
return self.localpath
1171
def _do_checksum(self, checksum_type='sha'):
1172
if not self._checksum:
1173
self._checksum = misc.checksum(checksum_type, self.localpath)
1175
return self._checksum
1177
checksum = property(fget=lambda self: self._do_checksum())