2002-03-25 23:16:26 +03:00
/** \ingroup rpmtrans
* \ file lib / transaction . c
*/
# include "system.h"
2002-03-26 01:02:39 +03:00
# include "rpmmacro.h" /* XXX for rpmExpand */
2002-03-25 23:16:26 +03:00
# include "psm.h"
# include "rpmdb.h"
# include "fprint.h"
# include "rpmhash.h"
# include "misc.h" /* XXX stripTrailingChar, splitString, currentDirectory */
# ifdef DYING
/*@-redecl -exportheadervar@*/
extern const char * chroot_prefix ;
/*@=redecl =exportheadervar@*/
# endif
/* XXX FIXME: merge with existing (broken?) tests in system.h */
/* portability fiddles */
# if STATFS_IN_SYS_STATVFS
# include <sys / statvfs.h>
# else
# if STATFS_IN_SYS_VFS
# include <sys / vfs.h>
# else
# if STATFS_IN_SYS_MOUNT
# include <sys / mount.h>
# else
# if STATFS_IN_SYS_STATFS
# include <sys / statfs.h>
# endif
# endif
# endif
# endif
# include "debug.h"
/*@access FD_t@*/ /* XXX compared with NULL */
/*@access Header@*/ /* XXX compared with NULL */
/*@access dbiIndexSet@*/
/*@access rpmdb@*/
/*@access rpmTransactionSet@*/
/*@access TFI_t@*/
/*@access PSM_t@*/
/*@access rpmProblemSet@*/
/*@access rpmProblem@*/
struct diskspaceInfo {
dev_t dev ; /*!< file system device number. */
signed long bneeded ; /*!< no. of blocks needed. */
signed long ineeded ; /*!< no. of inodes needed. */
int bsize ; /*!< file system block size. */
signed long bavail ; /*!< no. of blocks available. */
signed long iavail ; /*!< no. of inodes available. */
} ;
/* Adjust for root only reserved space. On linux e2fs, this is 5%. */
# define adj_fs_blocks(_nb) (((_nb) * 21) / 20)
/* argon thought a shift optimization here was a waste of time... he's
probably right : - ( */
# define BLOCK_ROUND(size, block) (((size) + (block) - 1) / (block))
# define XSTRCMP(a, b) ((!(a) && !(b)) || ((a) && (b) && !strcmp((a), (b))))
static /*@null@*/ void * freeFl ( rpmTransactionSet ts ,
/*@only@*/ /*@null@*/ TFI_t flList )
/*@*/
{
if ( flList ) {
TFI_t fi ;
int oc ;
/*@-usereleased@*/
for ( oc = 0 , fi = flList ; oc < ts - > orderCount ; oc + + , fi + + )
freeFi ( fi ) ;
flList = _free ( flList ) ;
/*@=usereleased@*/
}
return NULL ;
}
void rpmtransSetScriptFd ( rpmTransactionSet ts , FD_t fd )
{
ts - > scriptFd = ( fd ? fdLink ( fd , " rpmtransSetScriptFd " ) : NULL ) ;
}
int rpmtransGetKeys ( const rpmTransactionSet ts , const void * * * ep , int * nep )
{
int rc = 0 ;
if ( nep ) * nep = ts - > orderCount ;
if ( ep ) {
const void * * e ;
int oc ;
* ep = e = xmalloc ( ts - > orderCount * sizeof ( * e ) ) ;
for ( oc = 0 ; oc < ts - > orderCount ; oc + + , e + + ) {
switch ( ts - > order [ oc ] . type ) {
case TR_ADDED :
if ( ts - > addedPackages . list ) {
struct availablePackage * alp ;
alp = ts - > addedPackages . list + ts - > order [ oc ] . u . addedIndex ;
* e = alp - > key ;
break ;
}
/*@fallthrough@*/
default :
case TR_REMOVED :
/*@-mods@*/ /* FIX: double indirection. */
* e = NULL ;
/*@=mods@*/
break ;
}
}
}
return rc ;
}
static rpmProblemSet psCreate ( void )
/*@*/
{
rpmProblemSet probs ;
probs = xmalloc ( sizeof ( * probs ) ) ; /* XXX memory leak */
probs - > numProblems = probs - > numProblemsAlloced = 0 ;
probs - > probs = NULL ;
return probs ;
}
static void psAppend ( rpmProblemSet probs , rpmProblemType type ,
const struct availablePackage * alp ,
const char * dn , const char * bn ,
Header altH , unsigned long ulong1 )
/*@modifies probs, alp @*/
{
rpmProblem p ;
char * t ;
if ( probs - > numProblems = = probs - > numProblemsAlloced ) {
if ( probs - > numProblemsAlloced )
probs - > numProblemsAlloced * = 2 ;
else
probs - > numProblemsAlloced = 2 ;
probs - > probs = xrealloc ( probs - > probs ,
probs - > numProblemsAlloced * sizeof ( * probs - > probs ) ) ;
}
p = probs - > probs + probs - > numProblems + + ;
p - > type = type ;
/*@-assignexpose@*/
p - > key = alp - > key ;
/*@=assignexpose@*/
p - > ulong1 = ulong1 ;
p - > ignoreProblem = 0 ;
if ( dn | | bn ) {
p - > str1 =
t = xmalloc ( ( dn ? strlen ( dn ) : 0 ) + ( bn ? strlen ( bn ) : 0 ) + 1 ) ;
if ( dn ) t = stpcpy ( t , dn ) ;
if ( bn ) t = stpcpy ( t , bn ) ;
} else
p - > str1 = NULL ;
if ( alp ) {
p - > h = headerLink ( alp - > h ) ;
p - > pkgNEVR =
t = xmalloc ( strlen ( alp - > name ) +
strlen ( alp - > version ) +
strlen ( alp - > release ) + sizeof ( " -- " ) ) ;
t = stpcpy ( t , alp - > name ) ;
t = stpcpy ( t , " - " ) ;
t = stpcpy ( t , alp - > version ) ;
t = stpcpy ( t , " - " ) ;
t = stpcpy ( t , alp - > release ) ;
} else {
p - > h = NULL ;
p - > pkgNEVR = NULL ;
}
if ( altH ) {
const char * n , * v , * r ;
( void ) headerNVR ( altH , & n , & v , & r ) ;
p - > altNEVR =
t = xmalloc ( strlen ( n ) + strlen ( v ) + strlen ( r ) + sizeof ( " -- " ) ) ;
t = stpcpy ( t , n ) ;
t = stpcpy ( t , " - " ) ;
t = stpcpy ( t , v ) ;
t = stpcpy ( t , " - " ) ;
t = stpcpy ( t , r ) ;
} else
p - > altNEVR = NULL ;
}
static int archOkay ( Header h )
/*@*/
{
void * pkgArch ;
int type , count ;
/* make sure we're trying to install this on the proper architecture */
( void ) headerGetEntry ( h , RPMTAG_ARCH , & type , ( void * * ) & pkgArch , & count ) ;
# ifndef DYING
if ( type = = RPM_INT8_TYPE ) {
int_8 * pkgArchNum ;
int archNum ;
/* old arch handling */
rpmGetArchInfo ( NULL , & archNum ) ;
pkgArchNum = pkgArch ;
if ( archNum ! = * pkgArchNum ) {
return 0 ;
}
} else
# endif
{
/* new arch handling */
if ( ! rpmMachineScore ( RPM_MACHTABLE_INSTARCH , pkgArch ) ) {
return 0 ;
}
}
return 1 ;
}
static int osOkay ( Header h )
/*@*/
{
void * pkgOs ;
int type , count ;
/* make sure we're trying to install this on the proper os */
( void ) headerGetEntry ( h , RPMTAG_OS , & type , ( void * * ) & pkgOs , & count ) ;
# ifndef DYING
if ( type = = RPM_INT8_TYPE ) {
/* v1 packages and v2 packages both used improper OS numbers, so just
deal with it hope things work */
return 1 ;
} else
# endif
{
/* new os handling */
if ( ! rpmMachineScore ( RPM_MACHTABLE_INSTOS , pkgOs ) ) {
return 0 ;
}
}
return 1 ;
}
void rpmProblemSetFree ( rpmProblemSet probs )
{
int i ;
for ( i = 0 ; i < probs - > numProblems ; i + + ) {
rpmProblem p = probs - > probs + i ;
p - > h = headerFree ( p - > h ) ;
p - > pkgNEVR = _free ( p - > pkgNEVR ) ;
p - > altNEVR = _free ( p - > altNEVR ) ;
p - > str1 = _free ( p - > str1 ) ;
}
free ( probs ) ;
}
2006-05-15 02:48:59 +04:00
static /*@observer@*/ const char * ftstring ( fileTypes ft )
2002-03-25 23:16:26 +03:00
/*@*/
{
switch ( ft ) {
case XDIR : return " directory " ;
case CDEV : return " char dev " ;
case BDEV : return " block dev " ;
case LINK : return " link " ;
case SOCK : return " sock " ;
case PIPE : return " fifo/pipe " ;
case REG : return " file " ;
default : return " unknown file type " ;
}
/*@notreached@*/
}
static fileTypes whatis ( uint_16 mode )
/*@*/
{
if ( S_ISDIR ( mode ) ) return XDIR ;
if ( S_ISCHR ( mode ) ) return CDEV ;
if ( S_ISBLK ( mode ) ) return BDEV ;
if ( S_ISLNK ( mode ) ) return LINK ;
if ( S_ISSOCK ( mode ) ) return SOCK ;
if ( S_ISFIFO ( mode ) ) return PIPE ;
return REG ;
}
# define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s))
/**
* Relocate files in header .
* @ param ts transaction set
* @ param fi transaction element file info
* @ param alp available package
* @ param origH package header
* @ param actions file dispositions
* @ return header with relocated files
*/
static Header relocateFileList ( const rpmTransactionSet ts , TFI_t fi ,
struct availablePackage * alp ,
Header origH , fileAction * actions )
/*@modifies ts, fi, alp, origH, actions @*/
{
HGE_t hge = fi - > hge ;
HAE_t hae = fi - > hae ;
HME_t hme = fi - > hme ;
HFD_t hfd = ( fi - > hfd ? fi - > hfd : headerFreeData ) ;
static int _printed = 0 ;
rpmProblemSet probs = ts - > probs ;
int allowBadRelocate = ( ts - > ignoreSet & RPMPROB_FILTER_FORCERELOCATE ) ;
rpmRelocation * rawRelocations = alp - > relocs ;
rpmRelocation * relocations = NULL ;
int numRelocations ;
const char * * validRelocations ;
rpmTagType validType ;
int numValid ;
const char * * baseNames ;
const char * * dirNames ;
int_32 * dirIndexes ;
int_32 * newDirIndexes ;
int_32 fileCount ;
int_32 dirCount ;
uint_32 * fFlags = NULL ;
uint_16 * fModes = NULL ;
char * skipDirList ;
Header h ;
int nrelocated = 0 ;
int fileAlloced = 0 ;
char * fn = NULL ;
int haveRelocatedFile = 0 ;
int reldel = 0 ;
int len ;
int i , j ;
if ( ! hge ( origH , RPMTAG_PREFIXES , & validType ,
( void * * ) & validRelocations , & numValid ) )
numValid = 0 ;
numRelocations = 0 ;
if ( rawRelocations )
while ( rawRelocations [ numRelocations ] . newPath | |
rawRelocations [ numRelocations ] . oldPath )
numRelocations + + ;
/*
* If no relocations are specified ( usually the case ) , then return the
* original header . If there are prefixes , however , then INSTPREFIXES
* should be added , but , since relocateFileList ( ) can be called more
* than once for the same header , don ' t bother if already present .
*/
if ( rawRelocations = = NULL | | numRelocations = = 0 ) {
if ( numValid ) {
if ( ! headerIsEntry ( origH , RPMTAG_INSTPREFIXES ) )
( void ) hae ( origH , RPMTAG_INSTPREFIXES ,
validType , validRelocations , numValid ) ;
validRelocations = hfd ( validRelocations , validType ) ;
}
return headerLink ( origH ) ;
}
# ifdef DYING
h = headerCopy ( origH ) ;
# else
h = headerLink ( origH ) ;
# endif
relocations = alloca ( sizeof ( * relocations ) * numRelocations ) ;
/* Build sorted relocation list from raw relocations. */
for ( i = 0 ; i < numRelocations ; i + + ) {
char * t ;
/*
* Default relocations ( oldPath = = NULL ) are handled in the UI ,
* not rpmlib .
*/
if ( rawRelocations [ i ] . oldPath = = NULL ) continue ; /* XXX can't happen */
/* FIXME: Trailing /'s will confuse us greatly. Internal ones will
too , but those are more trouble to fix up . : - ( */
t = alloca_strdup ( rawRelocations [ i ] . oldPath ) ;
relocations [ i ] . oldPath = ( t [ 0 ] = = ' / ' & & t [ 1 ] = = ' \0 ' )
? t
: stripTrailingChar ( t , ' / ' ) ;
/* An old path w/o a new path is valid, and indicates exclusion */
if ( rawRelocations [ i ] . newPath ) {
int del ;
t = alloca_strdup ( rawRelocations [ i ] . newPath ) ;
relocations [ i ] . newPath = ( t [ 0 ] = = ' / ' & & t [ 1 ] = = ' \0 ' )
? t
: stripTrailingChar ( t , ' / ' ) ;
/*@-nullpass@*/ /* FIX: relocations[i].oldPath == NULL */
/* Verify that the relocation's old path is in the header. */
for ( j = 0 ; j < numValid ; j + + )
if ( ! strcmp ( validRelocations [ j ] , relocations [ i ] . oldPath ) )
/*@innerbreak@*/ break ;
/* XXX actions check prevents problem from being appended twice. */
if ( j = = numValid & & ! allowBadRelocate & & actions )
psAppend ( probs , RPMPROB_BADRELOCATE , alp ,
relocations [ i ] . oldPath , NULL , NULL , 0 ) ;
del =
strlen ( relocations [ i ] . newPath ) - strlen ( relocations [ i ] . oldPath ) ;
/*@=nullpass@*/
if ( del > reldel )
reldel = del ;
} else {
relocations [ i ] . newPath = NULL ;
}
}
/* stupid bubble sort, but it's probably faster here */
for ( i = 0 ; i < numRelocations ; i + + ) {
int madeSwap ;
madeSwap = 0 ;
for ( j = 1 ; j < numRelocations ; j + + ) {
rpmRelocation tmpReloc ;
if ( relocations [ j - 1 ] . oldPath = = NULL | | /* XXX can't happen */
relocations [ j ] . oldPath = = NULL | | /* XXX can't happen */
strcmp ( relocations [ j - 1 ] . oldPath , relocations [ j ] . oldPath ) < = 0 )
continue ;
tmpReloc = relocations [ j - 1 ] ;
relocations [ j - 1 ] = relocations [ j ] ;
relocations [ j ] = tmpReloc ;
madeSwap = 1 ;
}
if ( ! madeSwap ) break ;
}
if ( ! _printed ) {
_printed = 1 ;
rpmMessage ( RPMMESS_DEBUG , _ ( " ========== relocations \n " ) ) ;
for ( i = 0 ; i < numRelocations ; i + + ) {
if ( relocations [ i ] . oldPath = = NULL ) continue ; /* XXX can't happen */
if ( relocations [ i ] . newPath = = NULL )
rpmMessage ( RPMMESS_DEBUG , _ ( " %5d exclude %s \n " ) ,
i , relocations [ i ] . oldPath ) ;
else
rpmMessage ( RPMMESS_DEBUG , _ ( " %5d relocate %s -> %s \n " ) ,
i , relocations [ i ] . oldPath , relocations [ i ] . newPath ) ;
}
}
/* Add relocation values to the header */
if ( numValid ) {
const char * * actualRelocations ;
int numActual ;
actualRelocations = xmalloc ( numValid * sizeof ( * actualRelocations ) ) ;
numActual = 0 ;
for ( i = 0 ; i < numValid ; i + + ) {
for ( j = 0 ; j < numRelocations ; j + + ) {
if ( relocations [ j ] . oldPath = = NULL | | /* XXX can't happen */
strcmp ( validRelocations [ i ] , relocations [ j ] . oldPath ) )
continue ;
/* On install, a relocate to NULL means skip the path. */
if ( relocations [ j ] . newPath ) {
actualRelocations [ numActual ] = relocations [ j ] . newPath ;
numActual + + ;
}
/*@innerbreak@*/ break ;
}
if ( j = = numRelocations ) {
actualRelocations [ numActual ] = validRelocations [ i ] ;
numActual + + ;
}
}
if ( numActual )
( void ) hae ( h , RPMTAG_INSTPREFIXES , RPM_STRING_ARRAY_TYPE ,
( void * * ) actualRelocations , numActual ) ;
actualRelocations = _free ( actualRelocations ) ;
validRelocations = hfd ( validRelocations , validType ) ;
}
( void ) hge ( h , RPMTAG_BASENAMES , NULL , ( void * * ) & baseNames , & fileCount ) ;
( void ) hge ( h , RPMTAG_DIRINDEXES , NULL , ( void * * ) & dirIndexes , NULL ) ;
( void ) hge ( h , RPMTAG_DIRNAMES , NULL , ( void * * ) & dirNames , & dirCount ) ;
( void ) hge ( h , RPMTAG_FILEFLAGS , NULL , ( void * * ) & fFlags , NULL ) ;
( void ) hge ( h , RPMTAG_FILEMODES , NULL , ( void * * ) & fModes , NULL ) ;
skipDirList = alloca ( dirCount * sizeof ( * skipDirList ) ) ;
memset ( skipDirList , 0 , dirCount * sizeof ( * skipDirList ) ) ;
newDirIndexes = alloca ( sizeof ( * newDirIndexes ) * fileCount ) ;
memcpy ( newDirIndexes , dirIndexes , sizeof ( * newDirIndexes ) * fileCount ) ;
dirIndexes = newDirIndexes ;
/*
* For all relocations , we go through sorted file / relocation lists
* backwards so that / usr / local relocations take precedence over / usr
* ones .
*/
/* Relocate individual paths. */
for ( i = fileCount - 1 ; i > = 0 ; i - - ) {
fileTypes ft ;
int fnlen ;
len = reldel +
strlen ( dirNames [ dirIndexes [ i ] ] ) + strlen ( baseNames [ i ] ) + 1 ;
if ( len > = fileAlloced ) {
fileAlloced = len * 2 ;
fn = xrealloc ( fn , fileAlloced ) ;
}
* fn = ' \0 ' ;
fnlen = stpcpy ( stpcpy ( fn , dirNames [ dirIndexes [ i ] ] ) , baseNames [ i ] ) - fn ;
/*
* See if this file path needs relocating .
*/
/*
* XXX FIXME : Would a bsearch of the ( already sorted )
* relocation list be a good idea ?
*/
for ( j = numRelocations - 1 ; j > = 0 ; j - - ) {
if ( relocations [ j ] . oldPath = = NULL ) continue ; /* XXX can't happen */
len = strcmp ( relocations [ j ] . oldPath , " / " )
? strlen ( relocations [ j ] . oldPath )
: 0 ;
if ( fnlen < len )
continue ;
/*
* Only subdirectories or complete file paths may be relocated . We
* don ' t check for ' \0 ' as our directory names all end in ' / ' .
*/
if ( ! ( fn [ len ] = = ' / ' | | fnlen = = len ) )
continue ;
if ( strncmp ( relocations [ j ] . oldPath , fn , len ) )
continue ;
/*@innerbreak@*/ break ;
}
if ( j < 0 ) continue ;
ft = whatis ( fModes [ i ] ) ;
/* On install, a relocate to NULL means skip the path. */
if ( relocations [ j ] . newPath = = NULL ) {
if ( ft = = XDIR ) {
/* Start with the parent, looking for directory to exclude. */
for ( j = dirIndexes [ i ] ; j < dirCount ; j + + ) {
len = strlen ( dirNames [ j ] ) - 1 ;
while ( len > 0 & & dirNames [ j ] [ len - 1 ] = = ' / ' ) len - - ;
if ( fnlen ! = len )
continue ;
if ( strncmp ( fn , dirNames [ j ] , fnlen ) )
continue ;
/*@innerbreak@*/ break ;
}
if ( j < dirCount )
skipDirList [ j ] = 1 ;
}
if ( actions ) {
actions [ i ] = FA_SKIPNSTATE ;
rpmMessage ( RPMMESS_DEBUG , _ ( " excluding %s %s \n " ) ,
ftstring ( ft ) , fn ) ;
}
continue ;
}
/* Relocation on full paths only, please. */
if ( fnlen ! = len ) continue ;
if ( actions )
rpmMessage ( RPMMESS_DEBUG , _ ( " relocating %s to %s \n " ) ,
fn , relocations [ j ] . newPath ) ;
nrelocated + + ;
strcpy ( fn , relocations [ j ] . newPath ) ;
{ char * te = strrchr ( fn , ' / ' ) ;
if ( te ) {
if ( te > fn ) te + + ; /* root is special */
fnlen = te - fn ;
} else
te = fn + strlen ( fn ) ;
/*@-nullpass -nullderef@*/ /* LCL: te != NULL here. */
if ( strcmp ( baseNames [ i ] , te ) ) /* basename changed too? */
baseNames [ i ] = alloca_strdup ( te ) ;
* te = ' \0 ' ; /* terminate new directory name */
/*@=nullpass =nullderef@*/
}
/* Does this directory already exist in the directory list? */
for ( j = 0 ; j < dirCount ; j + + ) {
if ( fnlen ! = strlen ( dirNames [ j ] ) )
continue ;
if ( strncmp ( fn , dirNames [ j ] , fnlen ) )
continue ;
/*@innerbreak@*/ break ;
}
if ( j < dirCount ) {
dirIndexes [ i ] = j ;
continue ;
}
/* Creating new paths is a pita */
if ( ! haveRelocatedFile ) {
const char * * newDirList ;
haveRelocatedFile = 1 ;
newDirList = xmalloc ( ( dirCount + 1 ) * sizeof ( * newDirList ) ) ;
for ( j = 0 ; j < dirCount ; j + + )
newDirList [ j ] = alloca_strdup ( dirNames [ j ] ) ;
dirNames = hfd ( dirNames , RPM_STRING_ARRAY_TYPE ) ;
dirNames = newDirList ;
} else {
dirNames = xrealloc ( dirNames ,
sizeof ( * dirNames ) * ( dirCount + 1 ) ) ;
}
dirNames [ dirCount ] = alloca_strdup ( fn ) ;
dirIndexes [ i ] = dirCount ;
dirCount + + ;
}
/* Finish off by relocating directories. */
for ( i = dirCount - 1 ; i > = 0 ; i - - ) {
for ( j = numRelocations - 1 ; j > = 0 ; j - - ) {
if ( relocations [ j ] . oldPath = = NULL ) continue ; /* XXX can't happen */
len = strcmp ( relocations [ j ] . oldPath , " / " )
? strlen ( relocations [ j ] . oldPath )
: 0 ;
if ( len & & strncmp ( relocations [ j ] . oldPath , dirNames [ i ] , len ) )
continue ;
/*
* Only subdirectories or complete file paths may be relocated . We
* don ' t check for ' \0 ' as our directory names all end in ' / ' .
*/
if ( dirNames [ i ] [ len ] ! = ' / ' )
continue ;
if ( relocations [ j ] . newPath ) { /* Relocate the path */
const char * s = relocations [ j ] . newPath ;
char * t = alloca ( strlen ( s ) + strlen ( dirNames [ i ] ) - len + 1 ) ;
( void ) stpcpy ( stpcpy ( t , s ) , dirNames [ i ] + len ) ;
if ( actions )
rpmMessage ( RPMMESS_DEBUG ,
_ ( " relocating directory %s to %s \n " ) , dirNames [ i ] , t ) ;
dirNames [ i ] = t ;
nrelocated + + ;
}
}
}
/* Save original filenames in header and replace (relocated) filenames. */
if ( nrelocated ) {
int c ;
void * p ;
rpmTagType t ;
p = NULL ;
( void ) hge ( h , RPMTAG_BASENAMES , & t , & p , & c ) ;
( void ) hae ( h , RPMTAG_ORIGBASENAMES , t , p , c ) ;
p = hfd ( p , t ) ;
p = NULL ;
( void ) hge ( h , RPMTAG_DIRNAMES , & t , & p , & c ) ;
( void ) hae ( h , RPMTAG_ORIGDIRNAMES , t , p , c ) ;
p = hfd ( p , t ) ;
p = NULL ;
( void ) hge ( h , RPMTAG_DIRINDEXES , & t , & p , & c ) ;
( void ) hae ( h , RPMTAG_ORIGDIRINDEXES , t , p , c ) ;
p = hfd ( p , t ) ;
( void ) hme ( h , RPMTAG_BASENAMES , RPM_STRING_ARRAY_TYPE ,
baseNames , fileCount ) ;
fi - > bnl = hfd ( fi - > bnl , RPM_STRING_ARRAY_TYPE ) ;
( void ) hge ( h , RPMTAG_BASENAMES , NULL , ( void * * ) & fi - > bnl , & fi - > fc ) ;
( void ) hme ( h , RPMTAG_DIRNAMES , RPM_STRING_ARRAY_TYPE ,
dirNames , dirCount ) ;
fi - > dnl = hfd ( fi - > dnl , RPM_STRING_ARRAY_TYPE ) ;
( void ) hge ( h , RPMTAG_DIRNAMES , NULL , ( void * * ) & fi - > dnl , & fi - > dc ) ;
( void ) hme ( h , RPMTAG_DIRINDEXES , RPM_INT32_TYPE ,
dirIndexes , fileCount ) ;
( void ) hge ( h , RPMTAG_DIRINDEXES , NULL , ( void * * ) & fi - > dil , NULL ) ;
}
baseNames = hfd ( baseNames , RPM_STRING_ARRAY_TYPE ) ;
dirNames = hfd ( dirNames , RPM_STRING_ARRAY_TYPE ) ;
fn = _free ( fn ) ;
return h ;
}
/*
* As the problem sets are generated in an order solely dependent
* on the ordering of the packages in the transaction , and that
* ordering can ' t be changed , the problem sets must be parallel to
* one another . Additionally , the filter set must be a subset of the
* target set , given the operations available on transaction set .
* This is good , as it lets us perform this trim in linear time , rather
* then logarithmic or quadratic .
*/
static int psTrim ( rpmProblemSet filter , rpmProblemSet target )
/*@modifies target @*/
{
rpmProblem f = filter - > probs ;
rpmProblem t = target - > probs ;
int gotProblems = 0 ;
while ( ( f - filter - > probs ) < filter - > numProblems ) {
if ( ! f - > ignoreProblem ) {
f + + ;
continue ;
}
while ( ( t - target - > probs ) < target - > numProblems ) {
/*@-nullpass@*/ /* LCL: looks good to me */
if ( f - > h = = t - > h & & f - > type = = t - > type & & t - > key = = f - > key & &
XSTRCMP ( f - > str1 , t - > str1 ) )
/*@innerbreak@*/ break ;
/*@=nullpass@*/
t + + ;
gotProblems = 1 ;
}
if ( ( t - target - > probs ) = = target - > numProblems ) {
/* this can't happen ;-) lets be sane if it doesn though */
break ;
}
t - > ignoreProblem = f - > ignoreProblem ;
t + + , f + + ;
}
if ( ( t - target - > probs ) < target - > numProblems )
gotProblems = 1 ;
return gotProblems ;
}
static int sharedCmp ( const void * one , const void * two )
/*@*/
{
const struct sharedFileInfo * a = one ;
const struct sharedFileInfo * b = two ;
if ( a - > otherPkg < b - > otherPkg )
return - 1 ;
else if ( a - > otherPkg > b - > otherPkg )
return 1 ;
return 0 ;
}
2009-03-09 09:06:11 +03:00
static fileAction decideConfigFate ( TFI_t dbfi , const int dbix ,
TFI_t newfi , const int newix , rpmtransFlags transFlags )
2002-03-25 23:16:26 +03:00
/*@*/
{
2009-03-09 14:35:06 +03:00
const char * dn = newfi - > dnl [ newfi - > dil [ newix ] ] ;
const char * bn = newfi - > bnl [ newix ] ;
char * fn = alloca ( strlen ( dn ) + strlen ( bn ) + 1 ) ;
( void ) stpcpy ( stpcpy ( fn , dn ) , bn ) ;
2002-03-25 23:16:26 +03:00
2009-03-09 09:06:11 +03:00
struct stat sb ;
2009-03-09 14:35:06 +03:00
if ( lstat ( fn , & sb ) ) {
2002-03-25 23:16:26 +03:00
/*
* The file doesn ' t exist on the disk . Create it unless the new
* package has marked it as missingok , or allfiles is requested .
*/
if ( ! ( transFlags & RPMTRANS_FLAG_ALLFILES ) & &
2009-03-09 09:06:11 +03:00
( newfi - > fflags [ newix ] & RPMFILE_MISSINGOK ) ) {
2009-03-09 14:35:06 +03:00
rpmMessage ( RPMMESS_DEBUG , _ ( " %s skipped due to missingok flag \n " ) , fn ) ;
2002-03-25 23:16:26 +03:00
return FA_SKIP ;
} else {
return FA_CREATE ;
}
}
2009-03-09 09:06:11 +03:00
fileTypes diskWhat = whatis ( sb . st_mode ) ;
fileTypes dbWhat = whatis ( dbfi - > fmodes [ dbix ] ) ;
fileTypes newWhat = whatis ( newfi - > fmodes [ newix ] ) ;
2002-03-25 23:16:26 +03:00
/* RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
them in older packages as well */
2009-03-09 09:06:11 +03:00
if ( newWhat = = XDIR )
2002-03-25 23:16:26 +03:00
return FA_CREATE ;
if ( dbWhat = = REG ) {
2009-03-09 10:38:51 +03:00
/* this order matters - we'd prefer to CREATE the file if at all
possible in case something else ( like the timestamp ) has changed */
2009-03-09 11:14:46 +03:00
if ( diskWhat = = REG ) {
char mdsum [ 50 ] ;
2009-03-09 14:35:06 +03:00
if ( mdfile ( fn , mdsum ) ! = 0 )
2009-03-09 11:14:46 +03:00
return FA_CREATE ; /* assume file has been removed */
if ( strcmp ( dbfi - > fmd5s [ dbix ] , mdsum ) = = 0 )
return FA_CREATE ; /* unmodified config file, replace. */
}
2009-03-09 11:40:19 +03:00
if ( newWhat = = REG ) {
if ( strcmp ( dbfi - > fmd5s [ dbix ] , newfi - > fmd5s [ newix ] ) = = 0 )
return FA_SKIP ; /* identical file, don't bother. */
}
}
if ( dbWhat = = LINK ) {
2009-03-09 11:14:46 +03:00
if ( diskWhat = = LINK ) {
char linkto [ PATH_MAX + 1 ] = " " ;
2009-03-09 14:35:06 +03:00
if ( readlink ( fn , linkto , sizeof ( linkto ) - 1 ) < 0 )
2009-03-09 11:14:46 +03:00
return FA_CREATE ;
if ( strcmp ( dbfi - > flinks [ dbix ] , linkto ) = = 0 )
return FA_CREATE ;
}
2009-03-09 11:40:19 +03:00
if ( newWhat = = LINK ) {
if ( strcmp ( dbfi - > flinks [ dbix ] , newfi - > flinks [ newix ] ) = = 0 )
return FA_SKIP ;
}
2002-03-25 23:16:26 +03:00
}
/*
* The config file on the disk has been modified , but
* the ones in the two packages are different . It would
* be nice if RPM was smart enough to at least try and
* merge the difference ala CVS , but . . .
*/
2009-03-09 12:24:07 +03:00
if ( newfi - > fflags [ newix ] & RPMFILE_NOREPLACE )
return FA_ALTNAME ;
if ( diskWhat ! = REG & & diskWhat ! = LINK )
return FA_CREATE ;
return FA_SAVE ;
2002-03-25 23:16:26 +03:00
}
2009-03-09 14:17:30 +03:00
static int configConflict ( TFI_t fi , const int ix )
{
if ( ( fi - > fflags [ ix ] & RPMFILE_CONFIG ) = = 0 )
return 0 ;
const char * bn = fi - > bnl [ ix ] ;
const char * dn = fi - > dnl [ fi - > dil [ ix ] ] ;
char * fn = alloca ( strlen ( dn ) + strlen ( bn ) + 1 ) ;
( void ) stpcpy ( stpcpy ( fn , dn ) , bn ) ;
struct stat sb ;
if ( lstat ( fn , & sb ) ! = 0 )
return 0 ;
fileTypes diskWhat = whatis ( sb . st_mode ) ;
fileTypes newWhat = whatis ( fi - > fmodes [ ix ] ) ;
if ( diskWhat = = REG & & newWhat = = REG ) {
char mdsum [ 50 ] ;
if ( mdfile ( fn , mdsum ) ! = 0 )
return 0 ; /* assume file has been removed */
if ( strcmp ( fi - > fmd5s [ ix ] , mdsum ) = = 0 )
return 0 ; /* unmodified config file */
}
if ( diskWhat = = LINK & & newWhat = = LINK ) {
char linkto [ PATH_MAX + 1 ] = " " ;
if ( readlink ( fn , linkto , sizeof ( linkto ) - 1 ) < 0 )
return 0 ;
if ( strcmp ( fi - > flinks [ ix ] , linkto ) = = 0 )
return 0 ;
}
if ( fi - > fflags [ ix ] & RPMFILE_NOREPLACE )
return 1 ;
if ( diskWhat ! = REG & & diskWhat ! = LINK )
return 0 ;
return 1 ;
}
2008-05-14 07:19:15 +04:00
static int filecmp ( const TFI_t fi1 , const int ix1 , const TFI_t fi2 , const int ix2 )
2002-03-25 23:16:26 +03:00
/*@*/
{
2008-05-14 07:19:15 +04:00
uint_16 m1 = fi1 - > fmodes [ ix1 ] , m2 = fi2 - > fmodes [ ix2 ] ;
uint_32 f1 = fi1 - > fflags [ ix1 ] , f2 = fi2 - > fflags [ ix2 ] ;
const char * u1 = fi1 - > fuser [ ix1 ] , * u2 = fi2 - > fuser [ ix2 ] ;
const char * g1 = fi1 - > fgroup [ ix1 ] , * g2 = fi2 - > fgroup [ ix2 ] ;
2002-03-25 23:16:26 +03:00
2008-05-14 07:19:15 +04:00
/* both file type and permissions must match */
if ( m1 ! = m2 )
return 1 ;
/* ownership must also match */
if ( strcmp ( u1 , u2 ) | | strcmp ( g1 , g2 ) )
return 1 ;
2002-03-25 23:16:26 +03:00
2008-05-14 07:19:15 +04:00
if ( ( f1 | f2 ) & RPMFILE_GHOST )
/* one or both %ghost files, no extra check */
;
else if ( S_ISLNK ( m1 ) ) {
/* symlinks must have the same target */
const char * l1 = fi1 - > flinks [ ix1 ] , * l2 = fi2 - > flinks [ ix2 ] ;
if ( strcmp ( l1 , l2 ) )
return 1 ;
}
else if ( S_ISREG ( m1 ) ) {
/* regular files must have the same md5 sum */
const char * md51 = fi1 - > fmd5s [ ix1 ] , * md52 = fi2 - > fmd5s [ ix2 ] ;
if ( strcmp ( md51 , md52 ) )
return 1 ;
}
2002-03-25 23:16:26 +03:00
2008-05-14 07:19:15 +04:00
/* e.g. mtime difference is immaterial */
2002-03-25 23:16:26 +03:00
return 0 ;
}
2008-05-14 07:19:15 +04:00
static int handleInstInstalledFiles ( const TFI_t fi , /*@null@*/ rpmdb db ,
2002-03-25 23:16:26 +03:00
struct sharedFileInfo * shared ,
int sharedCount , int reportConflicts ,
rpmProblemSet probs ,
rpmtransFlags transFlags )
/*@modifies fi, db, probs @*/
{
int i ;
int numReplaced = 0 ;
rpmdbMatchIterator mi ;
2008-05-14 07:19:15 +04:00
Header h ;
TFI_t otherFi ;
2002-03-25 23:16:26 +03:00
mi = rpmdbInitIterator ( db , RPMDBI_PACKAGES , & shared - > otherPkg , sizeof ( shared - > otherPkg ) ) ;
h = rpmdbNextIterator ( mi ) ;
2008-05-14 07:19:15 +04:00
if ( h ) {
otherFi = alloca ( sizeof ( * otherFi ) ) ;
memset ( otherFi , 0 , sizeof ( * otherFi ) ) ;
fi - > type = TR_ADDED ; /* load fuser and fgroup */
loadFi ( h , otherFi ) ;
}
else {
2002-03-25 23:16:26 +03:00
mi = rpmdbFreeIterator ( mi ) ;
return 1 ;
}
fi - > replaced = xmalloc ( sharedCount * sizeof ( * fi - > replaced ) ) ;
for ( i = 0 ; i < sharedCount ; i + + , shared + + ) {
int otherFileNum , fileNum ;
2008-06-04 03:20:20 +04:00
int isCfgFile ;
2002-03-25 23:16:26 +03:00
otherFileNum = shared - > otherFileNum ;
fileNum = shared - > pkgFileNum ;
/* XXX another tedious segfault, assume file state normal. */
2008-05-14 07:19:15 +04:00
if ( otherFi - > fstates & & otherFi - > fstates [ otherFileNum ] ! = RPMFILE_STATE_NORMAL )
2002-03-25 23:16:26 +03:00
continue ;
if ( XFA_SKIPPING ( fi - > actions [ fileNum ] ) )
continue ;
2008-06-04 03:20:20 +04:00
isCfgFile = ( otherFi - > fflags [ otherFileNum ] | fi - > fflags [ fileNum ] ) & RPMFILE_CONFIG ;
2008-05-14 07:19:15 +04:00
if ( filecmp ( otherFi , otherFileNum , fi , fileNum ) ) {
2002-03-25 23:16:26 +03:00
if ( reportConflicts )
psAppend ( probs , RPMPROB_FILE_CONFLICT , fi - > ap ,
fi - > dnl [ fi - > dil [ fileNum ] ] , fi - > bnl [ fileNum ] , h , 0 ) ;
2008-06-04 03:20:20 +04:00
if ( ! isCfgFile ) {
2002-03-25 23:16:26 +03:00
/*@-assignexpose@*/
if ( ! shared - > isRemoved )
fi - > replaced [ numReplaced + + ] = * shared ;
/*@=assignexpose@*/
}
}
2009-03-09 09:06:11 +03:00
if ( isCfgFile )
fi - > actions [ fileNum ] = decideConfigFate ( otherFi , otherFileNum , fi , fileNum , transFlags ) ;
2002-03-25 23:16:26 +03:00
2008-05-14 07:19:15 +04:00
fi - > replacedSizes [ fileNum ] = otherFi - > fsizes [ otherFileNum ] ;
2002-03-25 23:16:26 +03:00
}
2008-05-14 07:19:15 +04:00
otherFi = freeFi ( otherFi ) ;
2002-03-25 23:16:26 +03:00
mi = rpmdbFreeIterator ( mi ) ;
2002-08-03 20:35:14 +04:00
fi - > replaced = xrealloc ( fi - > replaced ,
2002-03-25 23:16:26 +03:00
sizeof ( * fi - > replaced ) * ( numReplaced + 1 ) ) ;
fi - > replaced [ numReplaced ] . otherPkg = 0 ;
return 0 ;
}
static int handleRmvdInstalledFiles ( TFI_t fi , /*@null@*/ rpmdb db ,
struct sharedFileInfo * shared ,
int sharedCount )
/*@modifies fi, db @*/
{
HGE_t hge = fi - > hge ;
Header h ;
const char * otherStates ;
int i ;
rpmdbMatchIterator mi ;
mi = rpmdbInitIterator ( db , RPMDBI_PACKAGES ,
& shared - > otherPkg , sizeof ( shared - > otherPkg ) ) ;
h = rpmdbNextIterator ( mi ) ;
if ( h = = NULL ) {
mi = rpmdbFreeIterator ( mi ) ;
return 1 ;
}
( void ) hge ( h , RPMTAG_FILESTATES , NULL , ( void * * ) & otherStates , NULL ) ;
for ( i = 0 ; i < sharedCount ; i + + , shared + + ) {
int otherFileNum , fileNum ;
otherFileNum = shared - > otherFileNum ;
fileNum = shared - > pkgFileNum ;
if ( otherStates [ otherFileNum ] ! = RPMFILE_STATE_NORMAL )
continue ;
fi - > actions [ fileNum ] = FA_SKIP ;
}
mi = rpmdbFreeIterator ( mi ) ;
return 0 ;
}
/**
* Update disk space needs on each partition for this package .
*/
static void handleOverlappedFiles ( TFI_t fi , hashTable ht ,
rpmProblemSet probs , struct diskspaceInfo * dsl )
/*@modifies fi, probs, dsl @*/
{
int i , j ;
struct diskspaceInfo * ds = NULL ;
uint_32 fixupSize = 0 ;
char * filespec = NULL ;
int fileSpecAlloced = 0 ;
for ( i = 0 ; i < fi - > fc ; i + + ) {
int otherPkgNum , otherFileNum ;
const TFI_t * recs ;
int numRecs ;
if ( XFA_SKIPPING ( fi - > actions [ i ] ) )
continue ;
j = strlen ( fi - > dnl [ fi - > dil [ i ] ] ) + strlen ( fi - > bnl [ i ] ) + 1 ;
if ( j > fileSpecAlloced ) {
fileSpecAlloced = j * 2 ;
filespec = xrealloc ( filespec , fileSpecAlloced ) ;
}
( void ) stpcpy ( stpcpy ( filespec , fi - > dnl [ fi - > dil [ i ] ] ) , fi - > bnl [ i ] ) ;
if ( dsl ) {
ds = dsl ;
while ( ds - > bsize & & ds - > dev ! = fi - > fps [ i ] . entry - > dev ) ds + + ;
if ( ! ds - > bsize ) ds = NULL ;
fixupSize = 0 ;
}
/*
* Retrieve all records that apply to this file . Note that the
* file info records were built in the same order as the packages
* will be installed and removed so the records for an overlapped
* files will be sorted in exactly the same order .
*/
( void ) htGetEntry ( ht , & fi - > fps [ i ] , ( const void * * * ) & recs , & numRecs , NULL ) ;
/*
* If this package is being added , look only at other packages
* being added - - removed packages dance to a different tune .
* If both this and the other package are being added , overlapped
* files must be identical ( or marked as a conflict ) . The
* disposition of already installed config files leads to
* a small amount of extra complexity .
*
* If this package is being removed , then there are two cases that
* need to be worried about :
* If the other package is being added , then skip any overlapped files
* so that this package removal doesn ' t nuke the overlapped files
* that were just installed .
* If both this and the other package are being removed , then each
* file removal from preceding packages needs to be skipped so that
* the file removal occurs only on the last occurence of an overlapped
* file in the transaction set .
*
*/
/* Locate this overlapped file in the set of added/removed packages. */
for ( j = 0 ; j < numRecs & & recs [ j ] ! = fi ; j + + )
{ } ;
/* Find what the previous disposition of this file was. */
otherFileNum = - 1 ; /* keep gcc quiet */
for ( otherPkgNum = j - 1 ; otherPkgNum > = 0 ; otherPkgNum - - ) {
/* Added packages need only look at other added packages. */
if ( fi - > type = = TR_ADDED & & recs [ otherPkgNum ] - > type ! = TR_ADDED )
continue ;
/* TESTME: there are more efficient searches in the world... */
for ( otherFileNum = 0 ; otherFileNum < recs [ otherPkgNum ] - > fc ;
otherFileNum + + ) {
/* If the addresses are the same, so are the values. */
if ( ( fi - > fps + i ) = = ( recs [ otherPkgNum ] - > fps + otherFileNum ) )
/*@innerbreak@*/ break ;
/* Otherwise, compare fingerprints by value. */
/*@-nullpass@*/ /* LCL: looks good to me */
if ( FP_EQUAL ( fi - > fps [ i ] , recs [ otherPkgNum ] - > fps [ otherFileNum ] ) )
/*@innerbreak@*/ break ;
/*@=nullpass@*/
}
/* XXX is this test still necessary? */
if ( recs [ otherPkgNum ] - > actions [ otherFileNum ] ! = FA_UNKNOWN )
/*@innerbreak@*/ break ;
}
switch ( fi - > type ) {
case TR_ADDED :
if ( otherPkgNum < 0 ) {
/* XXX is this test still necessary? */
if ( fi - > actions [ i ] ! = FA_UNKNOWN )
break ;
2009-03-09 14:17:30 +03:00
if ( configConflict ( fi , i ) ) {
2002-03-25 23:16:26 +03:00
/* Here is a non-overlapped pre-existing config file. */
fi - > actions [ i ] = ( fi - > fflags [ i ] & RPMFILE_NOREPLACE )
? FA_ALTNAME : FA_BACKUP ;
} else {
fi - > actions [ i ] = FA_CREATE ;
}
break ;
}
/* Mark added overlapped non-identical files as a conflict. */
2008-05-14 07:19:15 +04:00
if ( probs & & filecmp ( recs [ otherPkgNum ] , otherFileNum , fi , i ) ) {
2002-03-25 23:16:26 +03:00
psAppend ( probs , RPMPROB_NEW_FILE_CONFLICT , fi - > ap ,
filespec , NULL , recs [ otherPkgNum ] - > ap - > h , 0 ) ;
}
/* Try to get the disk accounting correct even if a conflict. */
fixupSize = recs [ otherPkgNum ] - > fsizes [ otherFileNum ] ;
2009-03-09 14:17:30 +03:00
if ( configConflict ( fi , i ) ) {
2002-03-25 23:16:26 +03:00
/* Here is an overlapped pre-existing config file. */
fi - > actions [ i ] = ( fi - > fflags [ i ] & RPMFILE_NOREPLACE )
? FA_ALTNAME : FA_SKIP ;
} else {
fi - > actions [ i ] = FA_CREATE ;
}
2009-03-09 14:17:30 +03:00
break ;
2002-03-25 23:16:26 +03:00
case TR_REMOVED :
if ( otherPkgNum > = 0 ) {
/* Here is an overlapped added file we don't want to nuke. */
if ( recs [ otherPkgNum ] - > actions [ otherFileNum ] ! = FA_ERASE ) {
/* On updates, don't remove files. */
fi - > actions [ i ] = FA_SKIP ;
break ;
}
/* Here is an overlapped removed file: skip in previous. */
recs [ otherPkgNum ] - > actions [ otherFileNum ] = FA_SKIP ;
}
if ( XFA_SKIPPING ( fi - > actions [ i ] ) )
break ;
if ( fi - > fstates & & fi - > fstates [ i ] ! = RPMFILE_STATE_NORMAL )
break ;
if ( ! ( S_ISREG ( fi - > fmodes [ i ] ) & & ( fi - > fflags [ i ] & RPMFILE_CONFIG ) ) ) {
fi - > actions [ i ] = FA_ERASE ;
break ;
}
/* Here is a pre-existing modified config file that needs saving. */
{ char mdsum [ 50 ] ;
if ( ! mdfile ( filespec , mdsum ) & & strcmp ( fi - > fmd5s [ i ] , mdsum ) ) {
fi - > actions [ i ] = FA_BACKUP ;
break ;
}
}
fi - > actions [ i ] = FA_ERASE ;
break ;
}
if ( ds ) {
uint_32 s = BLOCK_ROUND ( fi - > fsizes [ i ] , ds - > bsize ) ;
switch ( fi - > actions [ i ] ) {
case FA_BACKUP :
case FA_SAVE :
case FA_ALTNAME :
ds - > ineeded + + ;
ds - > bneeded + = s ;
break ;
/*
* FIXME : If two packages share a file ( same md5sum ) , and
* that file is being replaced on disk , will ds - > bneeded get
* decremented twice ? Quite probably !
*/
case FA_CREATE :
ds - > bneeded + = s ;
ds - > bneeded - = BLOCK_ROUND ( fi - > replacedSizes [ i ] , ds - > bsize ) ;
break ;
case FA_ERASE :
ds - > ineeded - - ;
ds - > bneeded - = s ;
break ;
default :
break ;
}
ds - > bneeded - = BLOCK_ROUND ( fixupSize , ds - > bsize ) ;
}
}
if ( filespec ) free ( filespec ) ;
}
static int ensureOlder ( struct availablePackage * alp , Header old ,
rpmProblemSet probs )
/*@modifies alp, probs @*/
{
int result , rc = 0 ;
if ( old = = NULL ) return 1 ;
result = rpmVersionCompare ( old , alp - > h ) ;
if ( result < = 0 )
rc = 0 ;
else if ( result > 0 ) {
rc = 1 ;
psAppend ( probs , RPMPROB_OLDPACKAGE , alp , NULL , NULL , old , 0 ) ;
}
return rc ;
}
static void skipFiles ( const rpmTransactionSet ts , TFI_t fi )
/*@globals rpmGlobalMacroContext @*/
/*@modifies fi, rpmGlobalMacroContext @*/
{
int noDocs = ( ts - > transFlags & RPMTRANS_FLAG_NODOCS ) ;
char * * netsharedPaths = NULL ;
const char * * languages ;
const char * dn , * bn ;
int dnlen , bnlen , ix ;
const char * s ;
int * drc ;
char * dff ;
int i , j ;
if ( ! noDocs )
2005-09-29 19:46:13 +04:00
noDocs = rpmExpandNumeric ( " %{?_excludedocs} " ) ;
2002-03-25 23:16:26 +03:00
2005-09-29 20:01:17 +04:00
{ const char * tmpPath = rpmExpand ( " %{?_netsharedpath} " , NULL ) ;
if ( tmpPath & & * tmpPath )
2002-03-25 23:16:26 +03:00
netsharedPaths = splitString ( tmpPath , strlen ( tmpPath ) , ' : ' ) ;
tmpPath = _free ( tmpPath ) ;
}
2005-09-29 20:01:17 +04:00
s = rpmExpand ( " %{?_install_langs} " , NULL ) ;
if ( ! ( s & & * s ) )
2002-03-25 23:16:26 +03:00
s = _free ( s ) ;
if ( s ) {
languages = ( const char * * ) splitString ( s , strlen ( s ) , ' : ' ) ;
s = _free ( s ) ;
} else
languages = NULL ;
/* Compute directory refcount, skip directory if now empty. */
drc = alloca ( fi - > dc * sizeof ( * drc ) ) ;
memset ( drc , 0 , fi - > dc * sizeof ( * drc ) ) ;
dff = alloca ( fi - > dc * sizeof ( * dff ) ) ;
memset ( dff , 0 , fi - > dc * sizeof ( * dff ) ) ;
for ( i = 0 ; i < fi - > fc ; i + + ) {
char * * nsp ;
bn = fi - > bnl [ i ] ;
bnlen = strlen ( bn ) ;
ix = fi - > dil [ i ] ;
dn = fi - > dnl [ ix ] ;
dnlen = strlen ( dn ) ;
drc [ ix ] + + ;
/* Don't bother with skipped files */
if ( XFA_SKIPPING ( fi - > actions [ i ] ) ) {
drc [ ix ] - - ;
continue ;
}
/*
* Skip net shared paths .
* Net shared paths are not relative to the current root ( though
* they do need to take package relocations into account ) .
*/
for ( nsp = netsharedPaths ; nsp & & * nsp ; nsp + + ) {
int len ;
len = strlen ( * nsp ) ;
if ( dnlen > = len ) {
if ( strncmp ( dn , * nsp , len ) ) continue ;
/* Only directories or complete file paths can be net shared */
if ( ! ( dn [ len ] = = ' / ' | | dn [ len ] = = ' \0 ' ) ) continue ;
} else {
if ( len < ( dnlen + bnlen ) ) continue ;
if ( strncmp ( dn , * nsp , dnlen ) ) continue ;
if ( strncmp ( bn , ( * nsp ) + dnlen , bnlen ) ) continue ;
len = dnlen + bnlen ;
/* Only directories or complete file paths can be net shared */
if ( ! ( ( * nsp ) [ len ] = = ' / ' | | ( * nsp ) [ len ] = = ' \0 ' ) ) continue ;
}
/*@innerbreak@*/ break ;
}
if ( nsp & & * nsp ) {
drc [ ix ] - - ; dff [ ix ] = 1 ;
fi - > actions [ i ] = FA_SKIPNETSHARED ;
continue ;
}
/*
* Skip i18n language specific files .
*/
if ( fi - > flangs & & languages & & * fi - > flangs [ i ] ) {
const char * * lang , * l , * le ;
for ( lang = languages ; * lang ! = ' \0 ' ; lang + + ) {
if ( ! strcmp ( * lang , " all " ) )
/*@innerbreak@*/ break ;
for ( l = fi - > flangs [ i ] ; * l ! = ' \0 ' ; l = le ) {
for ( le = l ; * le ! = ' \0 ' & & * le ! = ' | ' ; le + + )
{ } ;
if ( ( le - l ) > 0 & & ! strncmp ( * lang , l , ( le - l ) ) )
/*@innerbreak@*/ break ;
if ( * le = = ' | ' ) le + + ; /* skip over | */
}
if ( * l ! = ' \0 ' )
/*@innerbreak@*/ break ;
}
if ( * lang = = NULL ) {
drc [ ix ] - - ; dff [ ix ] = 1 ;
fi - > actions [ i ] = FA_SKIPNSTATE ;
continue ;
}
}
/*
* Skip documentation if requested .
*/
if ( noDocs & & ( fi - > fflags [ i ] & RPMFILE_DOC ) ) {
drc [ ix ] - - ; dff [ ix ] = 1 ;
fi - > actions [ i ] = FA_SKIPNSTATE ;
continue ;
}
}
/* Skip (now empty) directories that had skipped files. */
for ( j = 0 ; j < fi - > dc ; j + + ) {
if ( drc [ j ] ) continue ; /* dir still has files. */
if ( ! dff [ j ] ) continue ; /* dir was not emptied here. */
/* Find parent directory and basename. */
dn = fi - > dnl [ j ] ; dnlen = strlen ( dn ) - 1 ;
bn = dn + dnlen ; bnlen = 0 ;
while ( bn > dn & & bn [ - 1 ] ! = ' / ' ) {
bnlen + + ;
dnlen - - ;
bn - - ;
}
/* If explicitly included in the package, skip the directory. */
for ( i = 0 ; i < fi - > fc ; i + + ) {
const char * dir ;
if ( XFA_SKIPPING ( fi - > actions [ i ] ) )
continue ;
if ( whatis ( fi - > fmodes [ i ] ) ! = XDIR )
continue ;
dir = fi - > dnl [ fi - > dil [ i ] ] ;
if ( strlen ( dir ) ! = dnlen )
continue ;
if ( strncmp ( dir , dn , dnlen ) )
continue ;
if ( strlen ( fi - > bnl [ i ] ) ! = bnlen )
continue ;
if ( strncmp ( fi - > bnl [ i ] , bn , bnlen ) )
continue ;
rpmMessage ( RPMMESS_DEBUG , _ ( " excluding directory %s \n " ) , dn ) ;
fi - > actions [ i ] = FA_SKIPNSTATE ;
/*@innerbreak@*/ break ;
}
}
if ( netsharedPaths ) freeSplitString ( netsharedPaths ) ;
# ifdef DYING /* XXX freeFi will deal with this later. */
fi - > flangs = _free ( fi - > flangs ) ;
# endif
if ( languages ) freeSplitString ( ( char * * ) languages ) ;
}
/**
* Iterator across transaction elements , forward on install , backward on erase .
*/
struct tsIterator_s {
/*@kept@*/ rpmTransactionSet ts ; /*!< transaction set. */
int reverse ; /*!< reversed traversal? */
int ocsave ; /*!< last returned iterator index. */
int oc ; /*!< iterator index. */
} ;
/**
* Return transaction element order count .
* @ param a transaction element iterator
* @ return element order count
*/
static int tsGetOc ( void * a )
/*@*/
{
struct tsIterator_s * iter = a ;
int oc = iter - > ocsave ;
return oc ;
}
/**
* Destroy transaction element iterator .
* @ param a transaction element iterator
* @ return NULL always
*/
static /*@null@*/ void * tsFreeIterator ( /*@only@*/ /*@null@*/ const void * a )
/*@modifies a @*/
{
return _free ( a ) ;
}
/**
* Create transaction element iterator .
* @ param a transaction set
* @ return transaction element iterator
*/
static void * tsInitIterator ( /*@kept@*/ const void * a )
/*@*/
{
rpmTransactionSet ts = ( void * ) a ;
struct tsIterator_s * iter = NULL ;
iter = xcalloc ( 1 , sizeof ( * iter ) ) ;
iter - > ts = ts ;
iter - > reverse = ( ( ts - > transFlags & RPMTRANS_FLAG_REVERSE ) ? 1 : 0 ) ;
iter - > oc = ( iter - > reverse ? ( ts - > orderCount - 1 ) : 0 ) ;
iter - > ocsave = iter - > oc ;
return iter ;
}
/**
* Return next transaction element ' s file info .
* @ param a file info iterator
* @ return next index , - 1 on termination
*/
static /*@dependent@*/ TFI_t tsNextIterator ( void * a )
/*@*/
{
struct tsIterator_s * iter = a ;
rpmTransactionSet ts = iter - > ts ;
TFI_t fi = NULL ;
int oc = - 1 ;
if ( iter - > reverse ) {
if ( iter - > oc > = 0 ) oc = iter - > oc - - ;
} else {
if ( iter - > oc < ts - > orderCount ) oc = iter - > oc + + ;
}
iter - > ocsave = oc ;
if ( oc ! = - 1 )
fi = ts - > flList + oc ;
return fi ;
}
# define NOTIFY(_ts, _al) if ((_ts)->notify) (void) (_ts)->notify _al
2005-10-17 17:23:09 +04:00
static int upgrade_honor_buildtime ( void )
{
static int honor_buildtime = - 1 ;
if ( honor_buildtime < 0 )
2005-10-18 14:43:12 +04:00
honor_buildtime = rpmExpandNumeric ( " %{?_upgrade_honor_buildtime}%{?!_upgrade_honor_buildtime:1} " ) ? 1 : 0 ;
2005-10-17 17:23:09 +04:00
return honor_buildtime ;
}
2002-03-25 23:16:26 +03:00
int rpmRunTransactions ( rpmTransactionSet ts ,
rpmCallbackFunction notify , rpmCallbackData notifyData ,
rpmProblemSet okProbs , rpmProblemSet * newProbs ,
rpmtransFlags transFlags , rpmprobFilterFlags ignoreSet )
{
int i , j ;
int ourrc = 0 ;
struct availablePackage * alp ;
2009-03-25 10:52:02 +03:00
unsigned int totalFileCount = 0 ;
2002-03-25 23:16:26 +03:00
hashTable ht ;
TFI_t fi ;
struct diskspaceInfo * dip ;
struct sharedFileInfo * shared , * sharedList ;
int numShared ;
int nexti ;
int lastFailed ;
fingerPrintCache fpc ;
struct psm_s psmbuf ;
PSM_t psm = & psmbuf ;
void * tsi ;
/* FIXME: what if the same package is included in ts twice? */
ts - > transFlags = transFlags ;
if ( ts - > transFlags & RPMTRANS_FLAG_NOSCRIPTS )
ts - > transFlags | = ( _noTransScripts | _noTransTriggers ) ;
if ( ts - > transFlags & RPMTRANS_FLAG_NOTRIGGERS )
ts - > transFlags | = _noTransTriggers ;
2009-03-10 14:27:38 +03:00
if ( ts - > transFlags & RPMTRANS_FLAG_JUSTDB )
2002-03-25 23:16:26 +03:00
ts - > transFlags | = ( _noTransScripts | _noTransTriggers ) ;
2010-03-31 19:36:41 +04:00
/* if SELinux isn't enabled or init fails, don't bother... */
if ( ! ts - > selinuxEnabled )
ts - > transFlags | = RPMTRANS_FLAG_NOCONTEXTS ;
if ( ! ( ts - > transFlags & RPMTRANS_FLAG_NOCONTEXTS ) ) {
const char * fn = rpmGetPath ( " %{?_install_file_context_path} " , NULL ) ;
if ( matchpathcon_init ( fn ) = = - 1 )
ts - > transFlags | = RPMTRANS_FLAG_NOCONTEXTS ;
fn = _free ( fn ) ;
}
2002-03-25 23:16:26 +03:00
ts - > notify = notify ;
ts - > notifyData = notifyData ;
/*@-assignexpose@*/
ts - > probs = * newProbs = psCreate ( ) ;
/*@=assignexpose@*/
ts - > ignoreSet = ignoreSet ;
ts - > currDir = _free ( ts - > currDir ) ;
ts - > currDir = currentDirectory ( ) ;
ts - > chrootDone = 0 ;
if ( ts - > rpmdb ) ts - > rpmdb - > db_chrootDone = 0 ;
ts - > id = ( int_32 ) time ( NULL ) ;
memset ( psm , 0 , sizeof ( * psm ) ) ;
/*@-assignexpose@*/
psm - > ts = ts ;
/*@=assignexpose@*/
/* Get available space on mounted file systems. */
if ( ! ( ts - > ignoreSet & RPMPROB_FILTER_DISKSPACE ) & &
! rpmGetFilesystemList ( & ts - > filesystems , & ts - > filesystemCount ) ) {
struct stat sb ;
ts - > di = _free ( ts - > di ) ;
dip = ts - > di = xcalloc ( sizeof ( * ts - > di ) , ts - > filesystemCount + 1 ) ;
2007-03-27 19:41:57 +04:00
for ( i = 0 ; ( i < ts - > filesystemCount ) & & dip ; i + + ) {
2002-03-25 23:16:26 +03:00
# if STATFS_IN_SYS_STATVFS
struct statvfs sfb ;
memset ( & sfb , 0 , sizeof ( sfb ) ) ;
2007-03-29 20:03:42 +04:00
if ( ! statvfs ( ts - > filesystems [ i ] , & sfb ) )
2002-03-25 23:16:26 +03:00
# else
struct statfs sfb ;
# if STAT_STATFS4
/* This platform has the 4-argument version of the statfs call. The last two
* should be the size of struct statfs and 0 , respectively . The 0 is the
* filesystem type , and is always 0 when statfs is called on a mounted
* filesystem , as we ' re doing .
*/
memset ( & sfb , 0 , sizeof ( sfb ) ) ;
2007-03-29 20:03:42 +04:00
if ( ! statfs ( ts - > filesystems [ i ] , & sfb , sizeof ( sfb ) , 0 ) )
2002-03-25 23:16:26 +03:00
# else
memset ( & sfb , 0 , sizeof ( sfb ) ) ;
2007-03-29 20:03:42 +04:00
if ( ! statfs ( ts - > filesystems [ i ] , & sfb ) )
2002-03-25 23:16:26 +03:00
# endif
# endif
{
2007-03-29 20:03:42 +04:00
ts - > di [ i ] . bsize = sfb . f_bsize ;
2002-03-25 23:16:26 +03:00
ts - > di [ i ] . bneeded = 0 ;
ts - > di [ i ] . ineeded = 0 ;
# ifdef STATFS_HAS_F_BAVAIL
ts - > di [ i ] . bavail = sfb . f_bavail ;
# else
/* FIXME: the statfs struct doesn't have a member to tell how many blocks are
* available for non - superusers . f_blocks - f_bfree is probably too big , but
* it ' s about all we can do .
*/
ts - > di [ i ] . bavail = sfb . f_blocks - sfb . f_bfree ;
# endif
/* XXX Avoid FAT and other file systems that have not inodes. */
ts - > di [ i ] . iavail = ! ( sfb . f_ffree = = 0 & & sfb . f_files = = 0 )
? sfb . f_ffree : - 1 ;
}
2007-03-29 20:03:42 +04:00
if ( ! ts - > di [ i ] . bsize )
ts - > di [ i ] . bsize = 1024 ;
if ( ! stat ( ts - > filesystems [ i ] , & sb ) )
ts - > di [ i ] . dev = sb . st_dev ;
2002-03-25 23:16:26 +03:00
}
if ( dip ) ts - > di [ i ] . bsize = 0 ;
}
/* ===============================================
* For packages being installed :
* - verify package arch / os .
* - verify package epoch : version - release is newer .
* - count files .
* For packages being removed :
* - count files .
*/
/* The ordering doesn't matter here */
if ( ts - > addedPackages . list ! = NULL )
for ( alp = ts - > addedPackages . list ;
( alp - ts - > addedPackages . list ) < ts - > addedPackages . size ;
alp + + )
{
if ( ! archOkay ( alp - > h ) & & ! ( ts - > ignoreSet & RPMPROB_FILTER_IGNOREARCH ) )
psAppend ( ts - > probs , RPMPROB_BADARCH , alp , NULL , NULL , NULL , 0 ) ;
if ( ! osOkay ( alp - > h ) & & ! ( ts - > ignoreSet & RPMPROB_FILTER_IGNOREOS ) )
psAppend ( ts - > probs , RPMPROB_BADOS , alp , NULL , NULL , NULL , 0 ) ;
if ( ! ( ts - > ignoreSet & RPMPROB_FILTER_OLDPACKAGE ) ) {
rpmdbMatchIterator mi ;
Header oldH ;
mi = rpmdbInitIterator ( ts - > rpmdb , RPMTAG_NAME , alp - > name , 0 ) ;
while ( ( oldH = rpmdbNextIterator ( mi ) ) ! = NULL )
( void ) ensureOlder ( alp , oldH , ts - > probs ) ;
mi = rpmdbFreeIterator ( mi ) ;
}
2009-03-10 14:27:38 +03:00
if ( ! ( ts - > ignoreSet & RPMPROB_FILTER_REPLACEPKG ) ) {
2002-03-25 23:16:26 +03:00
rpmdbMatchIterator mi ;
2005-10-17 17:23:09 +04:00
char b [ 80 ] ;
2002-03-25 23:16:26 +03:00
mi = rpmdbInitIterator ( ts - > rpmdb , RPMTAG_NAME , alp - > name , 0 ) ;
2005-10-17 17:23:09 +04:00
if ( alp - > epoch ) {
sprintf ( b , " %u " , * alp - > epoch ) ;
( void ) rpmdbSetIteratorRE ( mi , RPMTAG_EPOCH ,
RPMMIRE_DEFAULT , b ) ;
}
2002-03-25 23:16:26 +03:00
( void ) rpmdbSetIteratorRE ( mi , RPMTAG_VERSION ,
RPMMIRE_DEFAULT , alp - > version ) ;
( void ) rpmdbSetIteratorRE ( mi , RPMTAG_RELEASE ,
RPMMIRE_DEFAULT , alp - > release ) ;
2005-10-17 17:23:09 +04:00
if ( alp - > buildtime & & upgrade_honor_buildtime ( ) ) {
sprintf ( b , " %u " , * alp - > buildtime ) ;
( void ) rpmdbSetIteratorRE ( mi , RPMTAG_BUILDTIME ,
RPMMIRE_DEFAULT , b ) ;
}
2002-03-25 23:16:26 +03:00
while ( rpmdbNextIterator ( mi ) ! = NULL ) {
psAppend ( ts - > probs , RPMPROB_PKG_INSTALLED , alp ,
NULL , NULL , NULL , 0 ) ;
/*@innerbreak@*/ break ;
}
mi = rpmdbFreeIterator ( mi ) ;
}
totalFileCount + = alp - > filesCount ;
}
2009-10-04 21:27:00 +04:00
if ( ts - > erasedPackages . list ! = NULL )
for ( alp = ts - > erasedPackages . list ;
( alp - ts - > erasedPackages . list ) < ts - > erasedPackages . size ;
alp + + )
{
totalFileCount + = alp - > filesCount ;
2002-03-25 23:16:26 +03:00
}
/* ===============================================
* Initialize file list :
*/
ts - > flEntries = ts - > addedPackages . size + ts - > numRemovedPackages ;
ts - > flList = xcalloc ( ts - > flEntries , sizeof ( * ts - > flList ) ) ;
/*
* FIXME ? : we ' d be better off assembling one very large file list and
* calling fpLookupList only once . I ' m not sure that the speedup is
* worth the trouble though .
*/
tsi = tsInitIterator ( ts ) ;
while ( ( fi = tsNextIterator ( tsi ) ) ! = NULL ) {
2009-10-04 21:27:00 +04:00
int oc = tsGetOc ( tsi ) ;
2002-03-25 23:16:26 +03:00
fi - > magic = TFIMAGIC ;
fi - > type = ts - > order [ oc ] . type ;
switch ( fi - > type ) {
case TR_ADDED :
2009-10-04 21:27:00 +04:00
fi - > ap = ts - > addedPackages . list + ts - > order [ oc ] . u . addedIndex ;
2002-03-25 23:16:26 +03:00
fi - > record = 0 ;
loadFi ( fi - > ap - > h , fi ) ;
if ( fi - > fc = = 0 )
continue ;
{ Header foo = relocateFileList ( ts , fi , fi - > ap , fi - > h , fi - > actions ) ;
foo = headerFree ( foo ) ;
}
/* Skip netshared paths, not our i18n files, and excluded docs */
skipFiles ( ts , fi ) ;
break ;
case TR_REMOVED :
2009-10-04 21:27:00 +04:00
fi - > ap = ts - > erasedPackages . list + ts - > order [ oc ] . u . removed . erasedIndex ;
2002-03-25 23:16:26 +03:00
fi - > record = ts - > order [ oc ] . u . removed . dboffset ;
2009-10-04 21:27:00 +04:00
loadFi ( fi - > ap - > h , fi ) ;
2002-03-25 23:16:26 +03:00
break ;
}
if ( fi - > fc )
fi - > fps = xmalloc ( fi - > fc * sizeof ( * fi - > fps ) ) ;
}
tsi = tsFreeIterator ( tsi ) ;
if ( ! ts - > chrootDone ) {
( void ) chdir ( " / " ) ;
/*@-unrecog -superuser @*/
( void ) chroot ( ts - > rootDir ) ;
/*@=unrecog =superuser @*/
ts - > chrootDone = 1 ;
if ( ts - > rpmdb ) ts - > rpmdb - > db_chrootDone = 1 ;
# ifdef DYING
/*@-onlytrans@*/
chroot_prefix = ts - > rootDir ;
/*@=onlytrans@*/
# endif
}
2009-03-25 10:52:02 +03:00
ht = htCreate ( totalFileCount , fpHashFunction , fpEqual ) ;
2009-03-25 16:37:43 +03:00
/* XXX fpCache size = directories + space for rpmdbFindFpList */
fpc = fpCacheCreate ( totalFileCount / 2 + 4096 ) ;
2002-03-25 23:16:26 +03:00
/* ===============================================
* Add fingerprint for each file not skipped .
*/
tsi = tsInitIterator ( ts ) ;
while ( ( fi = tsNextIterator ( tsi ) ) ! = NULL ) {
fpLookupList ( fpc , fi - > dnl , fi - > bnl , fi - > dil , fi - > fc , fi - > fps ) ;
for ( i = 0 ; i < fi - > fc ; i + + ) {
if ( XFA_SKIPPING ( fi - > actions [ i ] ) )
continue ;
/*@-dependenttrans@*/
htAddEntry ( ht , fi - > fps + i , fi ) ;
/*@=dependenttrans@*/
}
}
tsi = tsFreeIterator ( tsi ) ;
/*@-moduncon@*/
NOTIFY ( ts , ( NULL , RPMCALLBACK_TRANS_START , 6 , ts - > flEntries ,
NULL , ts - > notifyData ) ) ;
/*@=moduncon@*/
/* ===============================================
* Compute file disposition for each package in transaction set .
*/
tsi = tsInitIterator ( ts ) ;
while ( ( fi = tsNextIterator ( tsi ) ) ! = NULL ) {
dbiIndexSet * matches ;
int knownBad ;
/*@-moduncon@*/
NOTIFY ( ts , ( NULL , RPMCALLBACK_TRANS_PROGRESS , ( fi - ts - > flList ) ,
ts - > flEntries , NULL , ts - > notifyData ) ) ;
/*@=moduncon@*/
if ( fi - > fc = = 0 ) continue ;
/* Extract file info for all files in this package from the database. */
matches = xcalloc ( sizeof ( * matches ) , fi - > fc ) ;
2009-03-25 16:00:03 +03:00
if ( rpmdbFindFpList ( ts - > rpmdb , fi - > fps , matches , fi - > fc , fpc ) )
2002-03-25 23:16:26 +03:00
return 1 ; /* XXX WTFO? */
numShared = 0 ;
for ( i = 0 ; i < fi - > fc ; i + + )
numShared + = dbiIndexSetCount ( matches [ i ] ) ;
/* Build sorted file info list for this package. */
shared = sharedList = xmalloc ( ( numShared + 1 ) * sizeof ( * sharedList ) ) ;
for ( i = 0 ; i < fi - > fc ; i + + ) {
/*
* Take care not to mark files as replaced in packages that will
* have been removed before we will get here .
*/
for ( j = 0 ; j < dbiIndexSetCount ( matches [ i ] ) ; j + + ) {
int k , ro ;
ro = dbiIndexRecordOffset ( matches [ i ] , j ) ;
knownBad = 0 ;
for ( k = 0 ; ro ! = knownBad & & k < ts - > orderCount ; k + + ) {
switch ( ts - > order [ k ] . type ) {
case TR_REMOVED :
if ( ts - > order [ k ] . u . removed . dboffset = = ro )
knownBad = ro ;
break ;
case TR_ADDED :
break ;
}
}
shared - > pkgFileNum = i ;
shared - > otherPkg = dbiIndexRecordOffset ( matches [ i ] , j ) ;
shared - > otherFileNum = dbiIndexRecordFileNumber ( matches [ i ] , j ) ;
shared - > isRemoved = ( knownBad = = ro ) ;
shared + + ;
}
matches [ i ] = dbiFreeIndexSet ( matches [ i ] ) ;
}
numShared = shared - sharedList ;
shared - > otherPkg = - 1 ;
matches = _free ( matches ) ;
/* Sort file info by other package index (otherPkg) */
qsort ( sharedList , numShared , sizeof ( * shared ) , sharedCmp ) ;
/* For all files from this package that are in the database ... */
for ( i = 0 ; i < numShared ; i = nexti ) {
int beingRemoved ;
shared = sharedList + i ;
/* Find the end of the files in the other package. */
for ( nexti = i + 1 ; nexti < numShared ; nexti + + ) {
if ( sharedList [ nexti ] . otherPkg ! = shared - > otherPkg )
/*@innerbreak@*/ break ;
}
/* Is this file from a package being removed? */
beingRemoved = 0 ;
for ( j = 0 ; j < ts - > numRemovedPackages ; j + + ) {
if ( ts - > removedPackages [ j ] ! = shared - > otherPkg )
continue ;
beingRemoved = 1 ;
/*@innerbreak@*/ break ;
}
/* Determine the fate of each file. */
switch ( fi - > type ) {
case TR_ADDED :
( void ) handleInstInstalledFiles ( fi , ts - > rpmdb , shared , nexti - i ,
! ( beingRemoved | | ( ts - > ignoreSet & RPMPROB_FILTER_REPLACEOLDFILES ) ) ,
ts - > probs , ts - > transFlags ) ;
break ;
case TR_REMOVED :
if ( ! beingRemoved )
( void ) handleRmvdInstalledFiles ( fi , ts - > rpmdb , shared , nexti - i ) ;
break ;
}
}
free ( sharedList ) ;
/* Update disk space needs on each partition for this package. */
handleOverlappedFiles ( fi , ht ,
( ( ts - > ignoreSet & RPMPROB_FILTER_REPLACENEWFILES )
? NULL : ts - > probs ) , ts - > di ) ;
/* Check added package has sufficient space on each partition used. */
switch ( fi - > type ) {
case TR_ADDED :
if ( ! ( ts - > di & & fi - > fc ) )
break ;
for ( i = 0 ; i < ts - > filesystemCount ; i + + ) {
dip = ts - > di + i ;
/* XXX Avoid FAT and other file systems that have not inodes. */
if ( dip - > iavail < = 0 )
continue ;
if ( adj_fs_blocks ( dip - > bneeded ) > dip - > bavail )
psAppend ( ts - > probs , RPMPROB_DISKSPACE , fi - > ap ,
ts - > filesystems [ i ] , NULL , NULL ,
( adj_fs_blocks ( dip - > bneeded ) - dip - > bavail ) * dip - > bsize ) ;
if ( adj_fs_blocks ( dip - > ineeded ) > dip - > iavail )
psAppend ( ts - > probs , RPMPROB_DISKNODES , fi - > ap ,
ts - > filesystems [ i ] , NULL , NULL ,
( adj_fs_blocks ( dip - > ineeded ) - dip - > iavail ) ) ;
}
break ;
case TR_REMOVED :
break ;
}
}
tsi = tsFreeIterator ( tsi ) ;
if ( ts - > chrootDone ) {
/*@-unrecog -superuser @*/
( void ) chroot ( " . " ) ;
/*@=unrecog =superuser @*/
ts - > chrootDone = 0 ;
if ( ts - > rpmdb ) ts - > rpmdb - > db_chrootDone = 0 ;
# ifdef DYING
chroot_prefix = NULL ;
# endif
( void ) chdir ( ts - > currDir ) ;
}
/*@-moduncon@*/
NOTIFY ( ts , ( NULL , RPMCALLBACK_TRANS_STOP , 6 , ts - > flEntries ,
NULL , ts - > notifyData ) ) ;
/*@=moduncon@*/
/* ===============================================
* Free unused memory as soon as possible .
*/
tsi = tsInitIterator ( ts ) ;
while ( ( fi = tsNextIterator ( tsi ) ) ! = NULL ) {
psm - > fi = fi ;
if ( fi - > fc = = 0 )
continue ;
fi - > fps = _free ( fi - > fps ) ;
}
tsi = tsFreeIterator ( tsi ) ;
2009-03-26 09:12:58 +03:00
fpc = fpCacheFree ( fpc ) ;
2009-03-25 10:12:06 +03:00
ht = htFree ( ht , NULL , NULL ) ;
2002-03-25 23:16:26 +03:00
/* ===============================================
* If unfiltered problems exist , free memory and return .
*/
if ( ( ts - > transFlags & RPMTRANS_FLAG_BUILD_PROBS ) | |
( ts - > probs - > numProblems & & ( ! okProbs | | psTrim ( okProbs , ts - > probs ) ) ) )
{
* newProbs = ts - > probs ;
ts - > flList = freeFl ( ts , ts - > flList ) ;
ts - > flEntries = 0 ;
/*@-nullstate@*/
return ts - > orderCount ;
/*@=nullstate@*/
}
/* ===============================================
* Install and remove packages .
*/
lastFailed = - 2 ; /* erased packages have -1 */
tsi = tsInitIterator ( ts ) ;
while ( ( fi = tsNextIterator ( tsi ) ) ! = NULL ) {
Header h ;
2009-10-04 21:27:00 +04:00
int oc = tsGetOc ( tsi ) ;
int gotfd = 0 ;
2002-03-25 23:16:26 +03:00
psm - > fi = fi ;
switch ( fi - > type )
{
case TR_ADDED :
2009-10-04 21:27:00 +04:00
alp = ts - > addedPackages . list + ts - > order [ oc ] . u . addedIndex ;
2002-03-25 23:16:26 +03:00
assert ( alp = = fi - > ap ) ;
i = alp - ts - > addedPackages . list ;
h = headerLink ( fi - > h ) ;
if ( alp - > fd = = NULL ) {
alp - > fd = ts - > notify ( fi - > h , RPMCALLBACK_INST_OPEN_FILE , 0 , 0 ,
alp - > key , ts - > notifyData ) ;
if ( alp - > fd ) {
rpmRC rpmrc ;
h = headerFree ( h ) ;
/*@-mustmod@*/ /* LCL: segfault */
rpmrc = rpmReadPackageHeader ( alp - > fd , & h , NULL , NULL , NULL ) ;
/*@=mustmod@*/
if ( ! ( rpmrc = = RPMRC_OK | | rpmrc = = RPMRC_BADSIZE ) ) {
( void ) ts - > notify ( fi - > h , RPMCALLBACK_INST_CLOSE_FILE ,
0 , 0 , alp - > key , ts - > notifyData ) ;
alp - > fd = NULL ;
ourrc + + ;
} else {
Header foo = relocateFileList ( ts , fi , alp , h , NULL ) ;
h = headerFree ( h ) ;
h = headerLink ( foo ) ;
foo = headerFree ( foo ) ;
}
if ( alp - > fd ) gotfd = 1 ;
}
}
if ( alp - > fd ) {
Header hsave = NULL ;
if ( fi - > h ) {
hsave = headerLink ( fi - > h ) ;
fi - > h = headerFree ( fi - > h ) ;
}
fi - > h = headerLink ( h ) ;
assert ( alp = = fi - > ap ) ;
if ( psmStage ( psm , PSM_PKGINSTALL ) ) {
ourrc + + ;
lastFailed = i ;
}
2008-09-08 10:57:19 +04:00
else {
psmTriggerAdded ( psm ) ;
}
2002-03-25 23:16:26 +03:00
fi - > h = headerFree ( fi - > h ) ;
if ( hsave ) {
fi - > h = headerLink ( hsave ) ;
hsave = headerFree ( hsave ) ;
}
} else {
ourrc + + ;
lastFailed = i ;
}
h = headerFree ( h ) ;
if ( gotfd ) {
( void ) ts - > notify ( fi - > h , RPMCALLBACK_INST_CLOSE_FILE , 0 , 0 ,
alp - > key , ts - > notifyData ) ;
alp - > fd = NULL ;
}
break ;
case TR_REMOVED :
/* If install failed, then we shouldn't erase. */
if ( ts - > order [ oc ] . u . removed . dependsOnIndex = = lastFailed )
break ;
if ( psmStage ( psm , PSM_PKGERASE ) )
ourrc + + ;
2008-09-08 10:57:19 +04:00
else {
psmTriggerRemoved ( psm ) ;
}
2002-03-25 23:16:26 +03:00
break ;
}
( void ) rpmdbSync ( ts - > rpmdb ) ;
}
2008-09-08 10:57:19 +04:00
if ( ourrc = = 0 )
psmTriggerPosttrans ( psm ) ;
2002-03-25 23:16:26 +03:00
tsi = tsFreeIterator ( tsi ) ;
ts - > flList = freeFl ( ts , ts - > flList ) ;
ts - > flEntries = 0 ;
2010-03-31 19:36:41 +04:00
if ( ! ( ts - > transFlags & RPMTRANS_FLAG_NOCONTEXTS ) )
matchpathcon_fini ( ) ;
2002-03-25 23:16:26 +03:00
/*@-nullstate@*/
if ( ourrc )
return - 1 ;
else
return 0 ;
/*@=nullstate@*/
}