2002-03-25 23:16:26 +03:00
/** \ingroup python
* \ file python / upgrade . c
*/
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <fcntl.h>
# include <string.h>
# include <glob.h> /* XXX rpmio.h */
# include <dirent.h> /* XXX rpmio.h */
2002-03-26 01:02:39 +03:00
# include "rpmlib.h"
2002-03-25 23:16:26 +03:00
# include "hash.h"
# include "upgrade.h"
# define MAXPKGS 1024
# define USEDEBUG 0
# define DEBUG(x) { \
if ( USEDEBUG ) \
printf x ; \
}
#if 0
static void printMemStats ( char * mess )
{
char buf [ 1024 ] ;
printf ( " %s \n " , mess ) ;
sprintf ( buf , " cat /proc/%d/status | grep VmSize " , getpid ( ) ) ;
system ( buf ) ;
}
# endif
/*@access Header@*/ /* compared with NULL. */
/*@access rpmdbMatchIterator@*/ /* compared with NULL. */
int pkgCompare ( void * first , void * second ) ; /* XXX make gcc shut up. */
int pkgCompare ( void * first , void * second ) {
struct packageInfo * * a = first ;
struct packageInfo * * b = second ;
/* put packages w/o names at the end */
if ( ! ( * a ) - > name ) return 1 ;
if ( ! ( * b ) - > name ) return - 1 ;
return xstrcasecmp ( ( * a ) - > name , ( * b ) - > name ) ;
}
/* Adds all files in the second file list which are not in the first
file list to the hash table . */
static void compareFileList ( int availFileCount , char * * availBaseNames ,
char * * availDirNames , int * availDirIndexes ,
int instFileCount , char * * instBaseNames ,
char * * instDirNames , int * instDirIndexes ,
struct hash_table * ht )
{
int installedX , availX , rc ;
char * availDir , * availBase ;
char * instDir , * instBase ;
static int i = 0 ;
availX = 0 ;
installedX = 0 ;
while ( installedX < instFileCount ) {
instBase = instBaseNames [ installedX ] ;
instDir = instDirNames [ instDirIndexes [ installedX ] ] ;
if ( availX = = availFileCount ) {
/* All the rest have moved */
DEBUG ( ( " => %d: %s%s \n " , i + + , instDir , instBase ) )
if ( strncmp ( instDir , " /etc/rc.d/ " , 10 ) )
htAddToTable ( ht , instDir , instBase ) ;
installedX + + ;
} else {
availBase = availBaseNames [ availX ] ;
availDir = availDirNames [ availDirIndexes [ availX ] ] ;
rc = strcmp ( availDir , instDir ) ;
if ( ! rc )
rc = strcmp ( availBase , instBase ) ;
if ( rc > 0 ) {
/* Avail > Installed -- file has moved */
DEBUG ( ( " => %d: %s%s \n " , i + + , instDir , instBase ) )
if ( strncmp ( instDir , " /etc/rc.d/ " , 10 ) )
htAddToTable ( ht , instDir , instBase ) ;
installedX + + ;
} else if ( rc < 0 ) {
/* Avail < Installed -- avail has some new files */
availX + + ;
} else {
/* Files are equal -- file not moved */
availX + + ;
installedX + + ;
}
}
}
}
static void addLostFiles ( rpmdb db , struct pkgSet * psp , struct hash_table * ht )
{
char * name ;
struct packageInfo * * pack ;
struct packageInfo key ;
struct packageInfo * keyaddr = & key ;
char * * installedFiles ;
char * * installedDirs ;
int_32 * installedDirIndexes ;
int installedFileCount ;
Header h = NULL ;
rpmdbMatchIterator mi ;
mi = rpmdbInitIterator ( db , RPMDBI_PACKAGES , NULL , 0 ) ;
while ( ( h = rpmdbNextIterator ( mi ) ) ! = NULL ) {
( void ) headerGetEntry ( h , RPMTAG_NAME , NULL , ( void * * ) & name , NULL ) ;
if ( name & & ! strcmp ( name , " metroess " ) ) {
/* metro was removed from 5.1, but leave it if it's already
installed */
continue ;
}
key . name = name ;
pack = bsearch ( & keyaddr , psp - > packages , psp - > numPackages ,
sizeof ( * psp - > packages ) , ( void * ) pkgCompare ) ;
if ( ! pack ) {
if ( headerGetEntryMinMemory ( h , RPMTAG_BASENAMES , NULL ,
( const void * * ) & installedFiles , & installedFileCount )
& & headerGetEntryMinMemory ( h , RPMTAG_DIRINDEXES , NULL ,
( const void * * ) & installedDirIndexes , NULL )
& & headerGetEntryMinMemory ( h , RPMTAG_DIRNAMES , NULL ,
( const void * * ) & installedDirs , NULL ) )
{
compareFileList ( 0 , NULL , NULL , NULL , installedFileCount ,
installedFiles , installedDirs ,
installedDirIndexes , ht ) ;
free ( installedFiles ) ;
free ( installedDirs ) ;
}
}
}
mi = rpmdbFreeIterator ( mi ) ;
}
static int findPackagesWithObsoletes ( rpmdb db , struct pkgSet * psp )
{
int count , obsoletesCount ;
struct packageInfo * * pip ;
char * * obsoletes ;
count = psp - > numPackages ;
pip = psp - > packages ;
while ( count - - ) {
if ( ( * pip ) - > selected ! = 0 ) {
pip + + ;
continue ;
}
if ( headerGetEntryMinMemory ( ( * pip ) - > h , RPMTAG_OBSOLETENAME , NULL ,
( const void * * ) & obsoletes , & obsoletesCount ) ) {
while ( obsoletesCount - - ) {
if ( rpmdbCountPackages ( db , obsoletes [ obsoletesCount ] ) > 0 ) {
( * pip ) - > selected = 1 ;
break ;
}
}
free ( obsoletes ) ;
}
pip + + ;
}
return 0 ;
}
static void errorFunction ( void )
{
}
static int findUpgradePackages ( rpmdb db , struct pkgSet * psp ,
struct hash_table * ht )
{
int skipThis ;
Header h , installedHeader ;
char * name ;
int count ;
char * * installedFiles ;
char * * availFiles = NULL ;
char * * installedDirs ;
char * * availDirs = NULL ;
int_32 * installedDirIndexes ;
int_32 * availDirIndexes = NULL ;
int installedFileCount , availFileCount ;
struct packageInfo * * pip ;
count = psp - > numPackages ;
pip = psp - > packages ;
while ( count - - ) {
h = ( * pip ) - > h ;
name = NULL ;
if ( ! headerGetEntry ( h , RPMTAG_NAME , NULL , ( void * * ) & name , NULL ) | |
name = = NULL )
{
/* bum header */
/*logMessage("Failed with bad header");*/
return ( - 1 ) ;
}
DEBUG ( ( " Avail: %s \n " , name ) ) ;
{ rpmdbMatchIterator mi ;
mi = rpmdbInitIterator ( db , RPMTAG_NAME , name , 0 ) ;
skipThis = ( mi ! = NULL ? 0 : 1 ) ;
( void ) rpmErrorSetCallback ( errorFunction ) ;
while ( ( installedHeader = rpmdbNextIterator ( mi ) ) ! = NULL ) {
if ( rpmVersionCompare ( installedHeader , h ) > = 0 ) {
/* already have a newer version installed */
DEBUG ( ( " Already have newer version \n " ) )
skipThis = 1 ;
break ;
}
}
mi = rpmdbFreeIterator ( mi ) ;
( void ) rpmErrorSetCallback ( NULL ) ;
if ( ! skipThis ) {
DEBUG ( ( " No newer version installed \n " ) )
}
}
if ( skipThis ) {
DEBUG ( ( " DO NOT INSTALL \n " ) )
} else {
DEBUG ( ( " UPGRADE \n " ) )
( * pip ) - > selected = 1 ;
if ( ! headerGetEntryMinMemory ( h , RPMTAG_BASENAMES , NULL ,
( const void * * ) & availFiles , & availFileCount ) ) {
availFiles = NULL ;
availFileCount = 0 ;
} else {
( void ) headerGetEntryMinMemory ( h , RPMTAG_DIRNAMES , NULL ,
( const void * * ) & availDirs , NULL ) ;
( void ) headerGetEntryMinMemory ( h , RPMTAG_DIRINDEXES , NULL ,
( const void * * ) & availDirIndexes , NULL ) ;
}
{ rpmdbMatchIterator mi ;
mi = rpmdbInitIterator ( db , RPMTAG_NAME , name , 0 ) ;
while ( ( installedHeader = rpmdbNextIterator ( mi ) ) ! = NULL ) {
if ( headerGetEntryMinMemory ( installedHeader , RPMTAG_BASENAMES ,
NULL , ( const void * * ) & installedFiles ,
& installedFileCount )
& & headerGetEntryMinMemory ( installedHeader , RPMTAG_DIRNAMES ,
NULL , ( const void * * ) & installedDirs , NULL )
& & headerGetEntryMinMemory ( installedHeader , RPMTAG_DIRINDEXES ,
NULL , ( const void * * ) & installedDirIndexes , NULL ) )
{
compareFileList ( availFileCount , availFiles ,
availDirs , availDirIndexes ,
installedFileCount , installedFiles ,
installedDirs , installedDirIndexes ,
ht ) ;
free ( installedFiles ) ;
free ( installedDirs ) ;
}
}
mi = rpmdbFreeIterator ( mi ) ;
}
if ( availFiles ) {
free ( availFiles ) ;
free ( availDirs ) ;
}
}
DEBUG ( ( " \n \n " ) )
pip + + ;
}
return 0 ;
}
static int removeMovedFilesAlreadyHandled ( struct pkgSet * psp ,
struct hash_table * ht )
{
char * name ;
int i , count ;
Header h ;
char * * availFiles , * * availDirs ;
int_32 * availDirIndexes ;
int availFileCount ;
struct packageInfo * * pip ;
count = psp - > numPackages ;
pip = psp - > packages ;
while ( count - - ) {
h = ( * pip ) - > h ;
if ( ( * pip ) - > selected ! = 0 ) {
name = NULL ;
( void ) headerGetEntry ( h , RPMTAG_NAME , NULL , ( void * * ) & name , NULL ) ;
if ( headerGetEntryMinMemory ( h , RPMTAG_BASENAMES , NULL ,
( const void * * ) & availFiles , & availFileCount )
& & headerGetEntryMinMemory ( h , RPMTAG_DIRNAMES , NULL ,
( const void * * ) & availDirs , NULL )
& & headerGetEntryMinMemory ( h , RPMTAG_DIRINDEXES , NULL ,
( const void * * ) & availDirIndexes , NULL ) )
{
for ( i = 0 ; i < availFileCount ; i + + ) {
if ( htInTable ( ht , availDirs [ availDirIndexes [ i ] ] ,
availFiles [ i ] ) ) {
htRemoveFromTable ( ht , availDirs [ availDirIndexes [ i ] ] ,
availFiles [ i ] ) ;
DEBUG ( ( " File already in %s: %s%s \n " , name ,
availDirs [ availDirIndexes [ i ] ] , availFiles [ i ] ) )
break ;
}
}
free ( availFiles ) ;
free ( availDirs ) ;
}
}
pip + + ;
}
return 0 ;
}
static int findPackagesWithRelocatedFiles ( struct pkgSet * psp ,
struct hash_table * ht )
{
char * name ;
int i , count ;
Header h ;
char * * availFiles , * * availDirs ;
int_32 * availDirIndexes ;
int availFileCount ;
struct packageInfo * * pip ;
int_16 * availFileModes ;
count = psp - > numPackages ;
pip = psp - > packages ;
while ( count - - ) {
h = ( * pip ) - > h ;
if ( ! ( * pip ) - > selected ) {
name = NULL ;
( void ) headerGetEntry ( h , RPMTAG_NAME , NULL , ( void * * ) & name , NULL ) ;
if ( headerGetEntry ( h , RPMTAG_BASENAMES , NULL ,
( void * * ) & availFiles , & availFileCount )
& & headerGetEntryMinMemory ( h , RPMTAG_DIRNAMES , NULL ,
( const void * * ) & availDirs , NULL )
& & headerGetEntryMinMemory ( h , RPMTAG_DIRINDEXES , NULL ,
( const void * * ) & availDirIndexes , NULL )
& & headerGetEntryMinMemory ( h , RPMTAG_FILEMODES , NULL ,
( const void * * ) & availFileModes , NULL ) )
{
for ( i = 0 ; i < availFileCount ; i + + ) {
if ( S_ISDIR ( availFileModes [ i ] ) ) continue ;
if ( htInTable ( ht , availDirs [ availDirIndexes [ i ] ] ,
availFiles [ i ] ) ) {
htRemoveFromTable ( ht , availDirs [ availDirIndexes [ i ] ] ,
availFiles [ i ] ) ;
DEBUG ( ( " Found file in %s: %s%s \n " , name ,
availDirs [ availDirIndexes [ i ] ] , availFiles [ i ] ) )
( * pip ) - > selected = 1 ;
}
}
free ( availFiles ) ;
free ( availDirs ) ;
}
}
pip + + ;
}
return 0 ;
}
/*
static void printCount ( struct pkgSet * psp )
{
int i , upgradeCount ;
struct packageInfo * pip ;
upgradeCount = 0 ;
pip = psp - > packages ;
i = psp - > numPackages ;
while ( i - - ) {
if ( pip - > selected ) {
upgradeCount + + ;
}
pip + + ;
}
logMessage ( " marked %d packages for upgrade " , upgradeCount ) ;
}
*/
static int unmarkPackagesAlreadyInstalled ( rpmdb db , struct pkgSet * psp )
{
Header h , installedHeader ;
char * name ;
struct packageInfo * * pip ;
int count ;
count = psp - > numPackages ;
pip = psp - > packages ;
while ( count - - ) {
if ( ( * pip ) - > selected ! = 0 ) {
h = ( * pip ) - > h ;
/* If this package is already installed, don't bother */
name = NULL ;
if ( ! headerGetEntry ( h , RPMTAG_NAME , NULL , ( void * * ) & name , NULL ) | |
name = = NULL )
{
/* bum header */
/*logMessage("Failed with bad header");*/
return ( - 1 ) ;
}
{ rpmdbMatchIterator mi ;
mi = rpmdbInitIterator ( db , RPMTAG_NAME , name , 0 ) ;
( void ) rpmErrorSetCallback ( errorFunction ) ;
while ( ( installedHeader = rpmdbNextIterator ( mi ) ) ! = NULL ) {
if ( rpmVersionCompare ( installedHeader , h ) > = 0 ) {
/* already have a newer version installed */
DEBUG ( ( " Already have newer version \n " ) )
( * pip ) - > selected = 0 ;
break ;
}
}
mi = rpmdbFreeIterator ( mi ) ;
( void ) rpmErrorSetCallback ( NULL ) ;
}
}
pip + + ;
}
return 0 ;
}
static void emptyErrorCallback ( void ) {
}
int ugFindUpgradePackages ( struct pkgSet * psp , char * installRoot )
{
rpmdb db ;
struct hash_table * hashTable ;
rpmErrorCallBackType old ;
/*logDebugMessage(("ugFindUpgradePackages() ..."));*/
/* rpmReadConfigFiles(NULL, NULL); */
rpmSetVerbosity ( RPMMESS_FATALERROR ) ;
old = rpmErrorSetCallback ( emptyErrorCallback ) ;
if ( rpmdbOpen ( installRoot , & db , O_RDONLY , 0644 ) ) {
/*logMessage("failed opening %s/var/lib/rpm/packages.rpm",
installRoot ) ; */
return ( - 1 ) ;
}
( void ) rpmErrorSetCallback ( old ) ;
rpmSetVerbosity ( RPMMESS_NORMAL ) ;
hashTable = htNewTable ( 1103 ) ;
if ( hashTable = = NULL ) return ( - 1 ) ;
/* For all packages that are installed, if there is no package */
/* available by that name, add the package's files to the hash table */
addLostFiles ( db , psp , hashTable ) ;
/*logDebugMessage(("added lost files"));
printCount ( psp ) ; */
/* Find packges that are new, and mark them in installThisPackage, */
/* updating availPkgs with the count. Also add files to the hash */
/* table that do not exist in the new package - they may have moved */
if ( findUpgradePackages ( db , psp , hashTable ) ) {
( void ) rpmdbClose ( db ) ;
return ( - 1 ) ;
}
/*logDebugMessage(("found basic packages to upgrade"));
printCount ( psp ) ;
hash_stats ( hashTable ) ; */
/* Remove any files that were added to the hash table that are in */
/* some other package marked for upgrade. */
( void ) removeMovedFilesAlreadyHandled ( psp , hashTable ) ;
/*logDebugMessage(("removed extra files which have moved"));
printCount ( psp ) ; */
( void ) findPackagesWithRelocatedFiles ( psp , hashTable ) ;
/*logDebugMessage(("found packages with relocated files"));
printCount ( psp ) ; */
( void ) findPackagesWithObsoletes ( db , psp ) ;
/*logDebugMessage(("found packages that obsolete installed packages"));
printCount ( psp ) ; */
( void ) unmarkPackagesAlreadyInstalled ( db , psp ) ;
/*logDebugMessage(("unmarked packages already installed"));
printCount ( psp ) ; */
htFreeHashTable ( hashTable ) ;
/*printMemStats("Done");*/
( void ) rpmdbClose ( db ) ;
return 0 ;
}