2002-03-25 23:16:26 +03:00
/** \ingroup rpmdep
* \ file lib / depends . c
*/
# include "system.h"
2002-03-26 01:02:39 +03:00
# include "rpmlib.h"
# include "rpmmacro.h" /* XXX for rpmExpand() */
2002-03-25 23:16:26 +03:00
# include "depends.h"
2009-10-02 11:47:28 +04:00
# include "al.h"
2010-07-12 10:20:27 +04:00
# include "rpmhash.h"
2002-03-25 23:16:26 +03:00
# include "debug.h"
/*@access Header@*/ /* XXX compared with NULL */
/*@access FD_t@*/ /* XXX compared with NULL */
/*@access rpmdb@*/ /* XXX compared with NULL */
/*@access rpmdbMatchIterator@*/ /* XXX compared with NULL */
/*@access rpmTransactionSet@*/
/*@access rpmDependencyConflict@*/
/*@access availableList@*/
2009-10-04 17:23:40 +04:00
/*@only@*/ char * printDepend ( const char * depend , const char * key ,
2002-03-25 23:16:26 +03:00
const char * keyEVR , int keyFlags )
/*@*/
{
char * tbuf , * t ;
size_t nb ;
nb = 0 ;
if ( depend ) nb + = strlen ( depend ) + 1 ;
if ( key ) nb + = strlen ( key ) ;
if ( keyFlags & RPMSENSE_SENSEMASK ) {
if ( nb ) nb + + ;
if ( keyFlags & RPMSENSE_LESS ) nb + + ;
if ( keyFlags & RPMSENSE_GREATER ) nb + + ;
if ( keyFlags & RPMSENSE_EQUAL ) nb + + ;
}
if ( keyEVR & & * keyEVR ) {
if ( nb ) nb + + ;
nb + = strlen ( keyEVR ) ;
}
t = tbuf = xmalloc ( nb + 1 ) ;
if ( depend ) {
while ( * depend ! = ' \0 ' ) * t + + = * depend + + ;
* t + + = ' ' ;
}
if ( key )
while ( * key ! = ' \0 ' ) * t + + = * key + + ;
if ( keyFlags & RPMSENSE_SENSEMASK ) {
if ( t ! = tbuf ) * t + + = ' ' ;
if ( keyFlags & RPMSENSE_LESS ) * t + + = ' < ' ;
if ( keyFlags & RPMSENSE_GREATER ) * t + + = ' > ' ;
if ( keyFlags & RPMSENSE_EQUAL ) * t + + = ' = ' ;
}
if ( keyEVR & & * keyEVR ) {
if ( t ! = tbuf ) * t + + = ' ' ;
while ( * keyEVR ! = ' \0 ' ) * t + + = * keyEVR + + ;
}
* t = ' \0 ' ;
return tbuf ;
}
2002-07-20 14:39:40 +04:00
/* parseEVR() moved to rpmvercmp.c */
2002-03-25 23:16:26 +03:00
const char * rpmNAME = PACKAGE ;
const char * rpmEVR = VERSION ;
int rpmFLAGS = RPMSENSE_EQUAL ;
int rpmRangesOverlap ( const char * AName , const char * AEVR , int AFlags ,
const char * BName , const char * BEVR , int BFlags )
{
const char * aDepend = printDepend ( NULL , AName , AEVR , AFlags ) ;
const char * bDepend = printDepend ( NULL , BName , BEVR , BFlags ) ;
char * aEVR , * bEVR ;
const char * aE , * aV , * aR , * bE , * bV , * bR ;
int result ;
int sense ;
/* Different names don't overlap. */
if ( strcmp ( AName , BName ) ) {
result = 0 ;
goto exit ;
}
2004-01-22 14:56:33 +03:00
/* Same name. If either A or B is an existence test, always overlap. */
if ( ! ( ( AFlags & RPMSENSE_SENSEMASK ) & & ( BFlags & RPMSENSE_SENSEMASK ) ) ) {
2002-03-25 23:16:26 +03:00
result = 1 ;
goto exit ;
}
2004-01-21 18:11:03 +03:00
if ( ! AEVR ) AEVR = " " ;
if ( ! BEVR ) BEVR = " " ;
/* Optimize: when both EVRs are non-existent or empty, always overlap. */
if ( ! ( * AEVR | | * BEVR ) ) {
2002-03-25 23:16:26 +03:00
result = 1 ;
goto exit ;
}
/* Both AEVR and BEVR exist. */
aEVR = xstrdup ( AEVR ) ;
parseEVR ( aEVR , & aE , & aV , & aR ) ;
bEVR = xstrdup ( BEVR ) ;
parseEVR ( bEVR , & bE , & bV , & bR ) ;
2002-07-20 14:39:40 +04:00
/* rpmEVRcmp() is also shared; the code moved to rpmvercmp.c */
sense = rpmEVRcmp ( aE , aV , aR , aDepend , bE , bV , bR , bDepend ) ;
2002-03-25 23:16:26 +03:00
aEVR = _free ( aEVR ) ;
bEVR = _free ( bEVR ) ;
/* Detect overlap of {A,B} range. */
result = 0 ;
if ( sense < 0 & & ( ( AFlags & RPMSENSE_GREATER ) | | ( BFlags & RPMSENSE_LESS ) ) ) {
result = 1 ;
} else if ( sense > 0 & & ( ( AFlags & RPMSENSE_LESS ) | | ( BFlags & RPMSENSE_GREATER ) ) ) {
result = 1 ;
} else if ( sense = = 0 & &
( ( ( AFlags & RPMSENSE_EQUAL ) & & ( BFlags & RPMSENSE_EQUAL ) ) | |
( ( AFlags & RPMSENSE_LESS ) & & ( BFlags & RPMSENSE_LESS ) ) | |
( ( AFlags & RPMSENSE_GREATER ) & & ( BFlags & RPMSENSE_GREATER ) ) ) ) {
result = 1 ;
}
exit :
rpmMessage ( RPMMESS_DEBUG , _ ( " %s A %s \t B %s \n " ) ,
( result ? _ ( " YES " ) : _ ( " NO " ) ) , aDepend , bDepend ) ;
aDepend = _free ( aDepend ) ;
bDepend = _free ( bDepend ) ;
return result ;
}
/*@-typeuse@*/
typedef int ( * dbrecMatch_t ) ( Header h , const char * reqName , const char * reqEVR , int reqFlags ) ;
/*@=typeuse@*/
static int rangeMatchesDepFlags ( Header h ,
const char * reqName , const char * reqEVR , int reqFlags )
/*@*/
{
HGE_t hge = ( HGE_t ) headerGetEntryMinMemory ;
HFD_t hfd = headerFreeData ;
rpmTagType pnt , pvt ;
const char * * provides ;
const char * * providesEVR ;
int_32 * provideFlags ;
int providesCount ;
int result ;
int i ;
if ( ! ( reqFlags & RPMSENSE_SENSEMASK ) | | ! reqEVR | | ! strlen ( reqEVR ) )
return 1 ;
/* Get provides information from header */
/*
* Rpm prior to 3.0 .3 does not have versioned provides .
* If no provides version info is available , match any requires .
*/
if ( ! hge ( h , RPMTAG_PROVIDEVERSION , & pvt ,
( void * * ) & providesEVR , & providesCount ) )
return 1 ;
( void ) hge ( h , RPMTAG_PROVIDEFLAGS , NULL , ( void * * ) & provideFlags , NULL ) ;
if ( ! hge ( h , RPMTAG_PROVIDENAME , & pnt , ( void * * ) & provides , & providesCount ) )
{
providesEVR = hfd ( providesEVR , pvt ) ;
return 0 ; /* XXX should never happen */
}
result = 0 ;
for ( i = 0 ; i < providesCount ; i + + ) {
/* Filter out provides that came along for the ride. */
if ( strcmp ( provides [ i ] , reqName ) )
continue ;
2004-01-22 15:43:59 +03:00
if ( ! ( provideFlags [ i ] & RPMSENSE_SENSEMASK ) )
2009-10-04 12:19:04 +04:00
provideFlags [ i ] | = RPMSENSE_EQUAL ; /* ALT21-139-g6cb9a9a */
2002-03-25 23:16:26 +03:00
result = rpmRangesOverlap ( provides [ i ] , providesEVR [ i ] , provideFlags [ i ] ,
reqName , reqEVR , reqFlags ) ;
/* If this provide matches the require, we're done. */
if ( result )
break ;
}
provides = hfd ( provides , pnt ) ;
providesEVR = hfd ( providesEVR , pvt ) ;
return result ;
}
int headerMatchesDepFlags ( Header h ,
const char * reqName , const char * reqEVR , int reqFlags )
{
HGE_t hge = ( HGE_t ) headerGetEntryMinMemory ;
const char * name , * version , * release ;
int_32 * epoch ;
const char * pkgEVR ;
char * p ;
int pkgFlags = RPMSENSE_EQUAL ;
if ( ! ( ( reqFlags & RPMSENSE_SENSEMASK ) & & reqEVR & & * reqEVR ) )
return 1 ;
/* Get package information from header */
( void ) headerNVR ( h , & name , & version , & release ) ;
pkgEVR = p = alloca ( 21 + strlen ( version ) + 1 + strlen ( release ) + 1 ) ;
* p = ' \0 ' ;
if ( hge ( h , RPMTAG_EPOCH , NULL , ( void * * ) & epoch , NULL ) ) {
sprintf ( p , " %d: " , * epoch ) ;
while ( * p ! = ' \0 ' )
p + + ;
}
( void ) stpcpy ( stpcpy ( stpcpy ( p , version ) , " - " ) , release ) ;
return rpmRangesOverlap ( name , pkgEVR , pkgFlags , reqName , reqEVR , reqFlags ) ;
}
rpmTransactionSet rpmtransCreateSet ( rpmdb rpmdb , const char * rootDir )
{
rpmTransactionSet ts ;
int rootLen ;
if ( ! rootDir ) rootDir = " " ;
ts = xcalloc ( 1 , sizeof ( * ts ) ) ;
ts - > filesystemCount = 0 ;
ts - > filesystems = NULL ;
ts - > di = NULL ;
/*@-assignexpose@*/
ts - > rpmdb = rpmdb ;
/*@=assignexpose@*/
ts - > scriptFd = NULL ;
ts - > id = 0 ;
ts - > numRemovedPackages = 0 ;
2009-10-04 09:57:34 +04:00
ts - > removedPackages = NULL ;
2002-03-25 23:16:26 +03:00
/* This canonicalizes the root */
rootLen = strlen ( rootDir ) ;
if ( ! ( rootLen & & rootDir [ rootLen - 1 ] = = ' / ' ) ) {
char * t ;
t = alloca ( rootLen + 2 ) ;
* t = ' \0 ' ;
( void ) stpcpy ( stpcpy ( t , rootDir ) , " / " ) ;
rootDir = t ;
}
ts - > rootDir = xstrdup ( rootDir ) ;
ts - > currDir = NULL ;
ts - > chrootDone = 0 ;
alCreate ( & ts - > addedPackages ) ;
2009-10-04 20:52:03 +04:00
alCreate ( & ts - > erasedPackages ) ;
2002-03-25 23:16:26 +03:00
ts - > orderCount = 0 ;
2009-10-04 09:57:34 +04:00
ts - > order = NULL ;
2002-03-25 23:16:26 +03:00
return ts ;
}
/**
* Compare removed package instances ( qsort / bsearch ) .
* @ param a 1 st instance address
* @ param b 2 nd instance address
* @ return result of comparison
*/
static int intcmp ( const void * a , const void * b ) /*@*/
{
const int * aptr = a ;
const int * bptr = b ;
int rc = ( * aptr - * bptr ) ;
return rc ;
}
/**
* Add removed package instance to ordered transaction set .
* @ param ts transaction set
* @ param dboffset rpm database instance
* @ param depends installed package of pair ( or - 1 on erase )
* @ return 0 on success
*/
static int removePackage ( rpmTransactionSet ts , int dboffset , int depends )
/*@modifies ts @*/
{
/* Filter out duplicate erasures. */
if ( ts - > numRemovedPackages > 0 & & ts - > removedPackages ! = NULL ) {
if ( bsearch ( & dboffset , ts - > removedPackages , ts - > numRemovedPackages ,
sizeof ( int ) , intcmp ) ! = NULL )
return 0 ;
}
2009-10-04 20:52:03 +04:00
/* Fetch header. */
rpmdbMatchIterator mi = rpmdbInitIterator ( ts - > rpmdb ,
RPMDBI_PACKAGES , & dboffset , sizeof ( dboffset ) ) ;
Header h = rpmdbNextIterator ( mi ) ;
if ( h )
h = headerLink ( h ) ;
mi = rpmdbFreeIterator ( mi ) ;
if ( h = = NULL )
return 1 ;
struct availablePackage * alp =
alAddPackage ( & ts - > erasedPackages , h , NULL , NULL , NULL ) ;
int alNum = alp - ts - > erasedPackages . list ;
2009-10-04 09:57:34 +04:00
AUTO_REALLOC ( ts - > removedPackages , ts - > numRemovedPackages ) ;
ts - > removedPackages [ ts - > numRemovedPackages + + ] = dboffset ;
qsort ( ts - > removedPackages , ts - > numRemovedPackages , sizeof ( int ) , intcmp ) ;
2002-03-25 23:16:26 +03:00
2009-10-04 09:57:34 +04:00
AUTO_REALLOC ( ts - > order , ts - > orderCount ) ;
2009-10-04 20:52:03 +04:00
transactionElement te = & ts - > order [ ts - > orderCount + + ] ;
te - > type = TR_REMOVED ;
te - > u . removed . dboffset = dboffset ;
te - > u . removed . dependsOnIndex = depends ;
te - > u . removed . erasedIndex = alNum ;
2002-03-25 23:16:26 +03:00
return 0 ;
}
2005-10-17 17:23:09 +04:00
static int rpmDigestCompare ( Header first , Header second )
{
const char * one , * two ;
if ( ! headerGetEntry ( first , RPMTAG_SHA1HEADER , NULL , ( void * * ) & one , NULL ) )
one = NULL ;
if ( ! headerGetEntry ( second , RPMTAG_SHA1HEADER , NULL , ( void * * ) & two , NULL ) )
two = NULL ;
if ( one & & two )
return strcmp ( one , two ) ;
if ( one & & ! two )
return 1 ;
if ( ! one & & two )
return - 1 ;
return 0 ;
}
2002-03-25 23:16:26 +03:00
int rpmtransAddPackage ( rpmTransactionSet ts , Header h , FD_t fd ,
const void * key , int upgrade , rpmRelocation * relocs )
{
HGE_t hge = ( HGE_t ) headerGetEntryMinMemory ;
HFD_t hfd = headerFreeData ;
rpmTagType ont , ovt ;
/* this is an install followed by uninstalls */
const char * name ;
int count ;
const char * * obsoletes ;
/*
* FIXME : handling upgrades like this is * almost * okay . It doesn ' t
* check to make sure we ' re upgrading to a newer version , and it
* makes it difficult to generate a return code based on the number of
* packages which failed .
*/
2009-10-02 07:58:27 +04:00
struct availablePackage * alp =
alAddPackage ( & ts - > addedPackages , h , key , fd , relocs ) ;
int alNum = alp - ts - > addedPackages . list ;
2009-10-04 09:57:34 +04:00
AUTO_REALLOC ( ts - > order , ts - > orderCount ) ;
ts - > order [ ts - > orderCount ] . type = TR_ADDED ;
2002-03-25 23:16:26 +03:00
ts - > order [ ts - > orderCount + + ] . u . addedIndex = alNum ;
if ( ! upgrade | | ts - > rpmdb = = NULL )
return 0 ;
/* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */
if ( headerIsEntry ( h , RPMTAG_SOURCEPACKAGE ) )
return 0 ;
( void ) headerNVR ( h , & name , NULL , NULL ) ;
{ rpmdbMatchIterator mi ;
Header h2 ;
mi = rpmdbInitIterator ( ts - > rpmdb , RPMTAG_NAME , name , 0 ) ;
while ( ( h2 = rpmdbNextIterator ( mi ) ) ! = NULL ) {
2005-10-17 17:23:09 +04:00
if ( rpmDigestCompare ( h , h2 ) | | rpmVersionCompare ( h , h2 ) )
2002-03-25 23:16:26 +03:00
( void ) removePackage ( ts , rpmdbGetIteratorOffset ( mi ) , alNum ) ;
}
mi = rpmdbFreeIterator ( mi ) ;
}
if ( hge ( h , RPMTAG_OBSOLETENAME , & ont , ( void * * ) & obsoletes , & count ) ) {
const char * * obsoletesEVR ;
int_32 * obsoletesFlags ;
int j ;
( void ) hge ( h , RPMTAG_OBSOLETEVERSION , & ovt , ( void * * ) & obsoletesEVR ,
NULL ) ;
( void ) hge ( h , RPMTAG_OBSOLETEFLAGS , NULL , ( void * * ) & obsoletesFlags ,
NULL ) ;
for ( j = 0 ; j < count ; j + + ) {
/* XXX avoid self-obsoleting packages. */
if ( ! strcmp ( name , obsoletes [ j ] ) )
continue ;
{ rpmdbMatchIterator mi ;
Header h2 ;
mi = rpmdbInitIterator ( ts - > rpmdb , RPMTAG_NAME , obsoletes [ j ] , 0 ) ;
( void ) rpmdbPruneIterator ( mi ,
ts - > removedPackages , ts - > numRemovedPackages , 1 ) ;
while ( ( h2 = rpmdbNextIterator ( mi ) ) ! = NULL ) {
/*
* Rpm prior to 3.0 .3 does not have versioned obsoletes .
* If no obsoletes version info is available , match all names .
*/
if ( obsoletesEVR = = NULL | |
headerMatchesDepFlags ( h2 ,
obsoletes [ j ] , obsoletesEVR [ j ] , obsoletesFlags [ j ] ) )
{
( void ) removePackage ( ts , rpmdbGetIteratorOffset ( mi ) , alNum ) ;
}
}
mi = rpmdbFreeIterator ( mi ) ;
}
}
obsoletesEVR = hfd ( obsoletesEVR , ovt ) ;
obsoletes = hfd ( obsoletes , ont ) ;
}
return 0 ;
}
int rpmtransRemovePackage ( rpmTransactionSet ts , int dboffset )
{
return removePackage ( ts , dboffset , - 1 ) ;
}
rpmTransactionSet rpmtransFree ( rpmTransactionSet ts )
{
if ( ts ) {
alFree ( & ts - > addedPackages ) ;
2009-10-04 20:52:03 +04:00
alFree ( & ts - > erasedPackages ) ;
2002-03-25 23:16:26 +03:00
ts - > di = _free ( ts - > di ) ;
ts - > removedPackages = _free ( ts - > removedPackages ) ;
ts - > order = _free ( ts - > order ) ;
if ( ts - > scriptFd ! = NULL )
ts - > scriptFd =
fdFree ( ts - > scriptFd , " rpmtransSetScriptFd (rpmtransFree " ) ;
ts - > rootDir = _free ( ts - > rootDir ) ;
ts - > currDir = _free ( ts - > currDir ) ;
ts = _free ( ts ) ;
}
return NULL ;
}
rpmDependencyConflict rpmdepFreeConflicts ( rpmDependencyConflict conflicts ,
int numConflicts )
{
int i ;
if ( conflicts )
for ( i = 0 ; i < numConflicts ; i + + ) {
conflicts [ i ] . byHeader = headerFree ( conflicts [ i ] . byHeader ) ;
conflicts [ i ] . byName = _free ( conflicts [ i ] . byName ) ;
conflicts [ i ] . byVersion = _free ( conflicts [ i ] . byVersion ) ;
conflicts [ i ] . byRelease = _free ( conflicts [ i ] . byRelease ) ;
conflicts [ i ] . needsName = _free ( conflicts [ i ] . needsName ) ;
conflicts [ i ] . needsVersion = _free ( conflicts [ i ] . needsVersion ) ;
}
return ( conflicts = _free ( conflicts ) ) ;
}
2010-07-05 14:35:34 +04:00
/* Cached rpmdb provide lookup, returns 0 if satisfied, 1 otherwise */
static
int dbSatisfiesDepend ( rpmTransactionSet ts ,
2010-07-12 10:20:27 +04:00
hashTable dbProvCache ,
2010-07-05 14:35:34 +04:00
const char * keyName , const char * keyEVR , int keyFlags )
{
rpmdbMatchIterator mi ;
Header h ;
int rc = 1 ;
2010-07-05 23:31:58 +04:00
/* Lookup dbProvCache by keyName. */
const void * * cacheData = NULL ;
if ( htGetEntry ( dbProvCache , keyName , & cacheData , NULL , NULL ) = = 0 ) {
if ( * cacheData = = NULL )
/* cache value is NULL (for "no"), the dependency is not satisfied */
return 1 ;
if ( ( keyFlags & RPMSENSE_SENSEMASK ) = = 0 )
/* cache value is "yes", unversioned dependency is satisfied */
return 0 ;
}
2010-07-05 14:35:34 +04:00
if ( * keyName = = ' / ' & & ( keyFlags & RPMSENSE_SENSEMASK ) = = 0 ) {
mi = rpmdbInitIterator ( ts - > rpmdb , RPMTAG_BASENAMES , keyName , 0 ) ;
rpmdbPruneIterator ( mi , ts - > removedPackages , ts - > numRemovedPackages , 1 ) ;
while ( ( h = rpmdbNextIterator ( mi ) ) ! = NULL ) {
rc = 0 ;
break ;
}
mi = rpmdbFreeIterator ( mi ) ;
}
if ( rc = = 1 ) {
mi = rpmdbInitIterator ( ts - > rpmdb , RPMTAG_PROVIDENAME , keyName , 0 ) ;
rpmdbPruneIterator ( mi , ts - > removedPackages , ts - > numRemovedPackages , 1 ) ;
while ( ( h = rpmdbNextIterator ( mi ) ) ! = NULL ) {
if ( rangeMatchesDepFlags ( h , keyName , keyEVR , keyFlags ) ) {
rc = 0 ;
break ;
}
2010-07-05 23:31:58 +04:00
else {
/* version did not match */
rc = - 1 ;
}
2010-07-05 14:35:34 +04:00
}
mi = rpmdbFreeIterator ( mi ) ;
}
2010-07-05 23:31:58 +04:00
/* Update dbProvCache.
* When versions did not match , it is still okay to say " yes " for the name . */
if ( cacheData = = NULL )
2010-08-18 11:56:59 +04:00
/* XXX keyName points to header memory, no need for strdup */
htAddEntry ( dbProvCache , keyName , rc < 1 ? " yes " : NULL ) ;
2010-07-05 23:31:58 +04:00
return rc ? 1 : 0 ;
2010-07-05 14:35:34 +04:00
}
2002-03-25 23:16:26 +03:00
/**
* Check key for an unsatisfied dependency .
* @ todo Eliminate rpmrc provides .
* @ param ts transaction set
* @ param keyType type of dependency
* @ param keyDepend dependency string representation
* @ param keyName dependency name string
* @ param keyEVR dependency [ epoch : ] version [ - release ] string
* @ param keyFlags dependency logical range qualifiers
* @ return 0 if satisfied , 1 if not satisfied , 2 if error
*/
2010-07-05 14:35:34 +04:00
static int tsSatisfiesDepend ( rpmTransactionSet ts ,
2010-07-12 10:20:27 +04:00
hashTable dbProvCache ,
2002-03-25 23:16:26 +03:00
const char * keyType , const char * keyDepend ,
2009-09-30 16:11:11 +04:00
const char * keyName , const char * keyEVR , int keyFlags )
/*@modifies ts @*/
2002-03-25 23:16:26 +03:00
{
/*
* New features in rpm packaging implicitly add versioned dependencies
* on rpmlib provides . The dependencies look like " rpmlib(YaddaYadda) " .
* Check those dependencies now .
*/
if ( ! strncmp ( keyName , " rpmlib( " , sizeof ( " rpmlib( " ) - 1 ) ) {
if ( rpmCheckRpmlibProvides ( keyName , keyEVR , keyFlags ) ) {
rpmMessage ( RPMMESS_DEBUG , _ ( " %s: %-45s YES (rpmlib provides) \n " ) ,
keyType , keyDepend + 2 ) ;
2010-07-05 14:35:34 +04:00
return 0 ;
2002-03-25 23:16:26 +03:00
}
goto unsatisfied ;
}
2010-07-05 14:35:34 +04:00
if ( alSatisfiesDepend ( & ts - > addedPackages , keyName , keyEVR , keyFlags ) ) {
rpmMessage ( RPMMESS_DEBUG , _ ( " %s: %-45s YES (added provides) \n " ) ,
2009-10-04 10:37:27 +04:00
keyType , keyDepend + 2 ) ;
2010-07-05 14:35:34 +04:00
return 0 ;
2002-03-25 23:16:26 +03:00
}
2010-07-12 10:20:27 +04:00
if ( dbSatisfiesDepend ( ts , dbProvCache , keyName , keyEVR , keyFlags ) = = 0 ) {
2010-07-05 14:35:34 +04:00
rpmMessage ( RPMMESS_DEBUG , _ ( " %s: %-45s YES (rpmdb provides) \n " ) ,
2002-03-25 23:16:26 +03:00
keyType , keyDepend + 2 ) ;
2010-07-05 14:35:34 +04:00
return 0 ;
2002-03-25 23:16:26 +03:00
}
unsatisfied :
rpmMessage ( RPMMESS_DEBUG , _ ( " %s: %-45s NO \n " ) , keyType , keyDepend + 2 ) ;
2010-07-05 14:35:34 +04:00
return 1 ;
2002-03-25 23:16:26 +03:00
}
/**
* Check header requires / conflicts against against installed + added packages .
* @ param ts transaction set
* @ param psp dependency problems
* @ param h header to check
* @ param keyName dependency name
* @ return 0 no problems found
*/
static int checkPackageDeps ( rpmTransactionSet ts , problemsSet psp ,
2010-07-12 10:20:27 +04:00
hashTable dbProvCache ,
2009-03-10 14:27:38 +03:00
Header h , const char * keyName )
2002-03-25 23:16:26 +03:00
/*@modifies ts, h, psp */
{
HGE_t hge = ( HGE_t ) headerGetEntryMinMemory ;
HFD_t hfd = headerFreeData ;
rpmTagType rnt , rvt ;
rpmTagType cnt , cvt ;
const char * name , * version , * release ;
const char * * requires ;
const char * * requiresEVR = NULL ;
int_32 * requireFlags = NULL ;
int requiresCount = 0 ;
const char * * conflicts ;
const char * * conflictsEVR = NULL ;
int_32 * conflictFlags = NULL ;
int conflictsCount = 0 ;
rpmTagType type ;
int i , rc ;
int ourrc = 0 ;
( void ) headerNVR ( h , & name , & version , & release ) ;
if ( ! hge ( h , RPMTAG_REQUIRENAME , & rnt , ( void * * ) & requires , & requiresCount ) )
{
requiresCount = 0 ;
rvt = RPM_STRING_ARRAY_TYPE ;
} else {
( void ) hge ( h , RPMTAG_REQUIREFLAGS , NULL , ( void * * ) & requireFlags , NULL ) ;
( void ) hge ( h , RPMTAG_REQUIREVERSION , & rvt , ( void * * ) & requiresEVR , NULL ) ;
}
for ( i = 0 ; i < requiresCount & & ! ourrc ; i + + ) {
const char * keyDepend ;
/* Filter out requires that came along for the ride. */
if ( keyName & & strcmp ( keyName , requires [ i ] ) )
continue ;
keyDepend = printDepend ( " R " ,
requires [ i ] , requiresEVR [ i ] , requireFlags [ i ] ) ;
2010-07-12 10:20:27 +04:00
rc = tsSatisfiesDepend ( ts , dbProvCache , " Requires " , keyDepend ,
2009-09-30 16:11:11 +04:00
requires [ i ] , requiresEVR [ i ] , requireFlags [ i ] ) ;
2002-03-25 23:16:26 +03:00
switch ( rc ) {
case 0 : /* requirements are satisfied. */
break ;
case 1 : /* requirements are not satisfied. */
rpmMessage ( RPMMESS_DEBUG , _ ( " package %s-%s-%s require not satisfied: %s \n " ) ,
name , version , release , keyDepend + 2 ) ;
2009-10-04 09:57:34 +04:00
AUTO_REALLOC ( psp - > problems , psp - > num ) ;
2002-03-25 23:16:26 +03:00
{ rpmDependencyConflict pp = psp - > problems + psp - > num ;
pp - > byHeader = headerLink ( h ) ;
pp - > byName = xstrdup ( name ) ;
pp - > byVersion = xstrdup ( version ) ;
pp - > byRelease = xstrdup ( release ) ;
pp - > needsName = xstrdup ( requires [ i ] ) ;
pp - > needsVersion = xstrdup ( requiresEVR [ i ] ) ;
pp - > needsFlags = requireFlags [ i ] ;
pp - > sense = RPMDEP_SENSE_REQUIRES ;
}
psp - > num + + ;
break ;
case 2 : /* something went wrong! */
default :
ourrc = 1 ;
break ;
}
keyDepend = _free ( keyDepend ) ;
}
if ( requiresCount ) {
requiresEVR = hfd ( requiresEVR , rvt ) ;
requires = hfd ( requires , rnt ) ;
}
if ( ! hge ( h , RPMTAG_CONFLICTNAME , & cnt , ( void * * ) & conflicts , & conflictsCount ) )
{
conflictsCount = 0 ;
cvt = RPM_STRING_ARRAY_TYPE ;
} else {
( void ) hge ( h , RPMTAG_CONFLICTFLAGS , & type ,
( void * * ) & conflictFlags , & conflictsCount ) ;
( void ) hge ( h , RPMTAG_CONFLICTVERSION , & cvt ,
( void * * ) & conflictsEVR , & conflictsCount ) ;
}
for ( i = 0 ; i < conflictsCount & & ! ourrc ; i + + ) {
const char * keyDepend ;
/* Filter out conflicts that came along for the ride. */
if ( keyName & & strcmp ( keyName , conflicts [ i ] ) )
continue ;
keyDepend = printDepend ( " C " , conflicts [ i ] , conflictsEVR [ i ] , conflictFlags [ i ] ) ;
2010-07-12 10:20:27 +04:00
rc = tsSatisfiesDepend ( ts , dbProvCache , " Conflicts " , keyDepend ,
2009-09-30 16:11:11 +04:00
conflicts [ i ] , conflictsEVR [ i ] , conflictFlags [ i ] ) ;
2002-03-25 23:16:26 +03:00
/* 1 == unsatisfied, 0 == satsisfied */
switch ( rc ) {
case 0 : /* conflicts exist. */
rpmMessage ( RPMMESS_DEBUG , _ ( " package %s conflicts: %s \n " ) ,
name , keyDepend + 2 ) ;
2009-10-04 09:57:34 +04:00
AUTO_REALLOC ( psp - > problems , psp - > num ) ;
2002-03-25 23:16:26 +03:00
{ rpmDependencyConflict pp = psp - > problems + psp - > num ;
pp - > byHeader = headerLink ( h ) ;
pp - > byName = xstrdup ( name ) ;
pp - > byVersion = xstrdup ( version ) ;
pp - > byRelease = xstrdup ( release ) ;
pp - > needsName = xstrdup ( conflicts [ i ] ) ;
pp - > needsVersion = xstrdup ( conflictsEVR [ i ] ) ;
pp - > needsFlags = conflictFlags [ i ] ;
pp - > sense = RPMDEP_SENSE_CONFLICTS ;
}
psp - > num + + ;
break ;
case 1 : /* conflicts don't exist. */
break ;
case 2 : /* something went wrong! */
default :
ourrc = 1 ;
break ;
}
keyDepend = _free ( keyDepend ) ;
}
if ( conflictsCount ) {
conflictsEVR = hfd ( conflictsEVR , cvt ) ;
conflicts = hfd ( conflicts , cnt ) ;
}
return ourrc ;
}
/**
2010-07-05 16:34:16 +04:00
* Erasing : check provides key against tag ( requires or conflicts ) matches .
2002-03-25 23:16:26 +03:00
* @ param ts transaction set
* @ param psp dependency problems
2010-07-05 16:34:16 +04:00
* @ param tag RPMTAG_REQUIRENAME or RPMTAG_CONFLICTNAME
* @ param key requires name
2002-03-25 23:16:26 +03:00
* @ return 0 no problems found
*/
2010-07-05 16:34:16 +04:00
static int checkDependent ( rpmTransactionSet ts , problemsSet psp ,
2010-07-12 10:20:27 +04:00
hashTable dbProvCache ,
2010-07-05 16:34:16 +04:00
rpmTag tag , const char * key )
/*@modifies ts, psp @*/
2002-03-25 23:16:26 +03:00
{
2010-07-05 16:34:16 +04:00
rpmdbMatchIterator mi = rpmdbInitIterator ( ts - > rpmdb , tag , key , 0 ) ;
rpmdbPruneIterator ( mi , ts - > removedPackages , ts - > numRemovedPackages , 1 ) ;
2002-03-25 23:16:26 +03:00
Header h ;
int rc = 0 ;
while ( ( h = rpmdbNextIterator ( mi ) ) ! = NULL ) {
2010-07-12 10:20:27 +04:00
if ( checkPackageDeps ( ts , psp , dbProvCache , h , key ) ) {
2002-03-25 23:16:26 +03:00
rc = 1 ;
break ;
}
}
mi = rpmdbFreeIterator ( mi ) ;
return rc ;
}
int rpmdepCheck ( rpmTransactionSet ts ,
rpmDependencyConflict * conflicts , int * numConflicts )
{
HGE_t hge = ( HGE_t ) headerGetEntryMinMemory ;
HFD_t hfd = headerFreeData ;
struct availablePackage * p ;
problemsSet ps ;
int i , j ;
int rc ;
ps = xcalloc ( 1 , sizeof ( * ps ) ) ;
ps - > num = 0 ;
2009-10-04 09:57:34 +04:00
ps - > problems = NULL ;
2002-03-25 23:16:26 +03:00
* conflicts = NULL ;
* numConflicts = 0 ;
2010-07-12 10:20:27 +04:00
/* XXX figure some kind of heuristic for the cache size */
hashTable dbProvCache = htCreate ( 1024 , hashFunctionString , hashEqualityString ) ;
2002-03-25 23:16:26 +03:00
/*
* Look at all of the added packages and make sure their dependencies
* are satisfied .
*/
if ( ( p = ts - > addedPackages . list ) ! = NULL )
2010-07-05 21:27:23 +04:00
for ( i = 0 ; i < ts - > addedPackages . size ; i + + , p + + )
2002-03-25 23:16:26 +03:00
{
rpmMessage ( RPMMESS_DEBUG , " ========== +++ %s-%s-%s \n " ,
p - > name , p - > version , p - > release ) ;
2010-07-12 10:20:27 +04:00
rc = checkPackageDeps ( ts , ps , dbProvCache , p - > h , NULL ) ;
2002-03-25 23:16:26 +03:00
if ( rc )
goto exit ;
/* Adding: check name against conflicts matches. */
2010-07-12 10:20:27 +04:00
rc = checkDependent ( ts , ps , dbProvCache , RPMTAG_CONFLICTNAME , p - > name ) ;
2002-03-25 23:16:26 +03:00
if ( rc )
goto exit ;
if ( p - > providesCount = = 0 | | p - > provides = = NULL )
continue ;
rc = 0 ;
for ( j = 0 ; j < p - > providesCount ; j + + ) {
/* Adding: check provides key against conflicts matches. */
2010-07-12 10:20:27 +04:00
if ( ! checkDependent ( ts , ps , dbProvCache , RPMTAG_CONFLICTNAME , p - > provides [ j ] ) )
2002-03-25 23:16:26 +03:00
continue ;
rc = 1 ;
/*@innerbreak@*/ break ;
}
if ( rc )
goto exit ;
}
/*
* Look at the removed packages and make sure they aren ' t critical .
*/
2010-07-05 21:27:23 +04:00
if ( ( p = ts - > erasedPackages . list ) ! = NULL )
for ( i = 0 ; i < ts - > erasedPackages . size ; i + + , p + + )
{
Header h = p - > h ;
2002-03-25 23:16:26 +03:00
{ const char * name , * version , * release ;
( void ) headerNVR ( h , & name , & version , & release ) ;
rpmMessage ( RPMMESS_DEBUG , " ========== --- %s-%s-%s \n " ,
name , version , release ) ;
/* Erasing: check name against requiredby matches. */
2010-07-12 10:20:27 +04:00
rc = checkDependent ( ts , ps , dbProvCache , RPMTAG_REQUIRENAME , name ) ;
2002-03-25 23:16:26 +03:00
if ( rc )
goto exit ;
}
{ const char * * provides ;
int providesCount ;
rpmTagType pnt ;
if ( hge ( h , RPMTAG_PROVIDENAME , & pnt , ( void * * ) & provides ,
& providesCount ) )
{
rc = 0 ;
for ( j = 0 ; j < providesCount ; j + + ) {
/* Erasing: check provides against requiredby matches. */
2010-07-12 10:20:27 +04:00
if ( ! checkDependent ( ts , ps , dbProvCache , RPMTAG_REQUIRENAME , provides [ j ] ) )
2002-03-25 23:16:26 +03:00
continue ;
rc = 1 ;
/*@innerbreak@*/ break ;
}
provides = hfd ( provides , pnt ) ;
if ( rc )
goto exit ;
}
}
{ const char * * baseNames , * * dirNames ;
int_32 * dirIndexes ;
rpmTagType dnt , bnt ;
int fileCount ;
char * fileName = NULL ;
int fileAlloced = 0 ;
int len ;
if ( hge ( h , RPMTAG_BASENAMES , & bnt , ( void * * ) & baseNames , & fileCount ) )
{
( void ) hge ( h , RPMTAG_DIRNAMES , & dnt , ( void * * ) & dirNames , NULL ) ;
( void ) hge ( h , RPMTAG_DIRINDEXES , NULL , ( void * * ) & dirIndexes ,
NULL ) ;
rc = 0 ;
for ( j = 0 ; j < fileCount ; j + + ) {
len = strlen ( baseNames [ j ] ) + 1 +
strlen ( dirNames [ dirIndexes [ j ] ] ) ;
if ( len > fileAlloced ) {
fileAlloced = len * 2 ;
fileName = xrealloc ( fileName , fileAlloced ) ;
}
* fileName = ' \0 ' ;
( void ) stpcpy ( stpcpy ( fileName , dirNames [ dirIndexes [ j ] ] ) , baseNames [ j ] ) ;
/* Erasing: check filename against requiredby matches. */
2010-07-12 10:20:27 +04:00
if ( ! checkDependent ( ts , ps , dbProvCache , RPMTAG_REQUIRENAME , fileName ) )
2002-03-25 23:16:26 +03:00
continue ;
rc = 1 ;
/*@innerbreak@*/ break ;
}
fileName = _free ( fileName ) ;
baseNames = hfd ( baseNames , bnt ) ;
dirNames = hfd ( dirNames , dnt ) ;
if ( rc )
goto exit ;
}
}
}
if ( ps - > num ) {
* conflicts = ps - > problems ;
ps - > problems = NULL ;
* numConflicts = ps - > num ;
}
rc = 0 ;
exit :
ps - > problems = _free ( ps - > problems ) ;
ps = _free ( ps ) ;
2010-08-18 11:56:59 +04:00
dbProvCache = htFree ( dbProvCache , NULL , NULL ) ;
2002-03-25 23:16:26 +03:00
return rc ;
}