2005-10-15 20:30:13 +04:00
/**
* \ file rpmdb / legacy . c
*/
# include "system.h"
2005-10-15 23:16:25 +04:00
# if HAVE_GELF_H && HAVE_LIBELF
2005-10-15 20:30:13 +04:00
# include <gelf.h>
# if !defined(DT_GNU_PRELINKED)
# define DT_GNU_PRELINKED 0x6ffffdf5
# endif
# if !defined(DT_GNU_LIBLIST)
# define DT_GNU_LIBLIST 0x6ffffef9
# endif
# endif /* HAVE_GELF_H */
# include "rpmio_internal.h"
2006-05-15 02:57:16 +04:00
# include "rpmlib.h"
# include "rpmmacro.h"
2005-10-15 20:30:13 +04:00
# include "misc.h"
# include "debug.h"
# define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s))
/**
* Open a file descriptor to verify file MD5 and size .
* @ param path file path
* @ retval pidp prelink helper pid or 0
* @ retval fsizep file size
* @ return - 1 on error , otherwise , an open file descriptor
*/
static int open_dso ( const char * path , /*@null@*/ pid_t * pidp , /*@null@*/ size_t * fsizep )
/*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
/*@modifies *pidp, *fsizep, rpmGlobalMacroContext,
fileSystem , internalState @ */
{
/*@only@*/
static const char * cmd = NULL ;
static int initted = 0 ;
int fdno ;
if ( ! initted ) {
cmd = rpmExpand ( " %{?__prelink_undo_cmd} " , NULL ) ;
initted + + ;
}
/*@-boundswrite@*/
if ( pidp ) * pidp = 0 ;
if ( fsizep ) {
struct stat sb , * st = & sb ;
if ( stat ( path , st ) < 0 )
return - 1 ;
* fsizep = st - > st_size ;
}
/*@=boundswrite@*/
fdno = open ( path , O_RDONLY ) ;
if ( fdno < 0 )
return fdno ;
/*@-boundsread@*/
if ( ! ( cmd & & * cmd ) )
return fdno ;
/*@=boundsread@*/
# if HAVE_GELF_H && HAVE_LIBELF
{ Elf * elf = NULL ;
Elf_Scn * scn = NULL ;
Elf_Data * data = NULL ;
GElf_Ehdr ehdr ;
GElf_Shdr shdr ;
GElf_Dyn dyn ;
int bingo ;
( void ) elf_version ( EV_CURRENT ) ;
/*@-evalorder@*/
if ( ( elf = elf_begin ( fdno , ELF_C_READ , NULL ) ) = = NULL
| | elf_kind ( elf ) ! = ELF_K_ELF
| | gelf_getehdr ( elf , & ehdr ) = = NULL
| | ! ( ehdr . e_type = = ET_DYN | | ehdr . e_type = = ET_EXEC ) )
goto exit ;
/*@=evalorder@*/
bingo = 0 ;
/*@-branchstate -uniondef @*/
while ( ! bingo & & ( scn = elf_nextscn ( elf , scn ) ) ! = NULL ) {
( void ) gelf_getshdr ( scn , & shdr ) ;
if ( shdr . sh_type ! = SHT_DYNAMIC )
continue ;
while ( ! bingo & & ( data = elf_getdata ( scn , data ) ) ! = NULL ) {
int maxndx = data - > d_size / shdr . sh_entsize ;
int ndx ;
for ( ndx = 0 ; ndx < maxndx ; + + ndx ) {
( void ) gelf_getdyn ( data , ndx , & dyn ) ;
if ( ! ( dyn . d_tag = = DT_GNU_PRELINKED | | dyn . d_tag = = DT_GNU_LIBLIST ) )
/*@innercontinue@*/ continue ;
bingo = 1 ;
/*@innerbreak@*/ break ;
}
}
}
/*@=branchstate =uniondef @*/
/*@-boundswrite@*/
if ( pidp ! = NULL & & bingo ) {
int pipes [ 2 ] ;
pid_t pid ;
int xx ;
xx = close ( fdno ) ;
pipes [ 0 ] = pipes [ 1 ] = - 1 ;
xx = pipe ( pipes ) ;
if ( ! ( pid = fork ( ) ) ) {
const char * * av ;
int ac ;
xx = close ( pipes [ 0 ] ) ;
xx = dup2 ( pipes [ 1 ] , STDOUT_FILENO ) ;
xx = close ( pipes [ 1 ] ) ;
if ( ! poptParseArgvString ( cmd , & ac , & av ) ) {
av [ ac - 1 ] = path ;
av [ ac ] = NULL ;
unsetenv ( " MALLOC_CHECK_ " ) ;
xx = execve ( av [ 0 ] , ( char * const * ) av + 1 , environ ) ;
}
_exit ( 127 ) ;
}
* pidp = pid ;
fdno = pipes [ 0 ] ;
xx = close ( pipes [ 1 ] ) ;
}
/*@=boundswrite@*/
exit :
if ( elf ) ( void ) elf_end ( elf ) ;
}
# endif /* HAVE_GELF_H */
return fdno ;
}
int domd5 ( const char * fn , unsigned char * digest , int asAscii )
{
const char * path ;
urltype ut = urlPath ( fn , & path ) ;
unsigned char * md5sum = NULL ;
size_t md5len ;
unsigned char buf [ 32 * BUFSIZ ] ;
FD_t fd ;
size_t fsize = 0 ;
pid_t pid = 0 ;
int rc = 0 ;
int fdno ;
int xx ;
/*@-globs -internalglobs -mods @*/
fdno = open_dso ( path , & pid , & fsize ) ;
/*@=globs =internalglobs =mods @*/
2018-01-30 11:46:03 +03:00
/* Traditionally rpm-4.0 endows zero-sized files with empty md5sum. */
if ( fdno > = 0 & & fsize = = 0 ) {
close ( fdno ) ;
fdno = - 1 ;
}
2005-10-15 20:30:13 +04:00
if ( fdno < 0 ) {
rc = 1 ;
goto exit ;
}
switch ( ut ) {
case URL_IS_PATH :
case URL_IS_UNKNOWN :
# if HAVE_MMAP
if ( pid = = 0 ) {
DIGEST_CTX ctx ;
void * mapped ;
2018-01-30 11:46:03 +03:00
/* Preallocate ctx, no malloc calls between mmap and munmap. */
ctx = rpmDigestInit ( PGPHASHALGO_MD5 , RPMDIGEST_NONE ) ;
2005-10-15 20:30:13 +04:00
mapped = mmap ( NULL , fsize , PROT_READ , MAP_SHARED , fdno , 0 ) ;
2018-01-30 11:46:03 +03:00
if ( mapped = = ( void * ) - 1 ) { // probably EOVERFLOW
rpmDigestFinal ( ctx , NULL , NULL , asAscii ) ;
goto readloop ;
2005-10-15 20:30:13 +04:00
}
# ifdef MADV_SEQUENTIAL
xx = madvise ( mapped , fsize , MADV_SEQUENTIAL ) ;
# endif
xx = rpmDigestUpdate ( ctx , mapped , fsize ) ;
xx = munmap ( mapped , fsize ) ;
2018-01-30 11:46:03 +03:00
xx = rpmDigestFinal ( ctx , ( void * * ) & md5sum , & md5len , asAscii ) ;
2005-10-15 20:30:13 +04:00
xx = close ( fdno ) ;
break ;
} /*@fallthrough@*/
# endif
default :
2018-01-30 11:46:03 +03:00
readloop :
2005-10-15 20:30:13 +04:00
/* Either use the pipe to prelink -y or open the URL. */
fd = ( pid ! = 0 ) ? fdDup ( fdno ) : Fopen ( fn , " r.ufdio " ) ;
( void ) close ( fdno ) ;
if ( fd = = NULL | | Ferror ( fd ) ) {
rc = 1 ;
if ( fd ! = NULL )
( void ) Fclose ( fd ) ;
break ;
}
fdInitDigest ( fd , PGPHASHALGO_MD5 , 0 ) ;
fsize = 0 ;
while ( ( rc = Fread ( buf , sizeof ( buf [ 0 ] ) , sizeof ( buf ) , fd ) ) > 0 )
fsize + = rc ;
fdFiniDigest ( fd , PGPHASHALGO_MD5 , ( void * * ) & md5sum , & md5len , asAscii ) ;
if ( Ferror ( fd ) )
rc = 1 ;
( void ) Fclose ( fd ) ;
break ;
}
/* Reap the prelink -y helper. */
if ( pid ) {
int status ;
( void ) waitpid ( pid , & status , 0 ) ;
if ( ! WIFEXITED ( status ) | | WEXITSTATUS ( status ) )
rc = 1 ;
}
exit :
/*@-boundswrite@*/
if ( ! rc )
memcpy ( digest , md5sum , md5len ) ;
/*@=boundswrite@*/
md5sum = _free ( md5sum ) ;
return rc ;
}
/*@-boundsread@*/
static int dncmp ( const void * a , const void * b )
/*@*/
{
const char * const * first = a ;
const char * const * second = b ;
return strcmp ( * first , * second ) ;
}
/*@=boundsread@*/
/*@-bounds@*/
void compressFilelist ( Header h )
{
HGE_t hge = ( HGE_t ) headerGetEntryMinMemory ;
HAE_t hae = ( HAE_t ) headerAddEntry ;
HRE_t hre = ( HRE_t ) headerRemoveEntry ;
HFD_t hfd = headerFreeData ;
char * * fileNames ;
const char * * dirNames ;
const char * * baseNames ;
int_32 * dirIndexes ;
rpmTagType fnt ;
int count ;
int i , xx ;
int dirIndex = - 1 ;
/*
* This assumes the file list is already sorted , and begins with a
* single ' / ' . That assumption isn ' t critical , but it makes things go
* a bit faster .
*/
if ( headerIsEntry ( h , RPMTAG_DIRNAMES ) ) {
xx = hre ( h , RPMTAG_OLDFILENAMES ) ;
return ; /* Already converted. */
}
if ( ! hge ( h , RPMTAG_OLDFILENAMES , & fnt , ( void * * ) & fileNames , & count ) )
return ; /* no file list */
if ( fileNames = = NULL | | count < = 0 )
return ;
dirNames = alloca ( sizeof ( * dirNames ) * count ) ; /* worst case */
baseNames = alloca ( sizeof ( * dirNames ) * count ) ;
dirIndexes = alloca ( sizeof ( * dirIndexes ) * count ) ;
if ( fileNames [ 0 ] [ 0 ] ! = ' / ' ) {
/* HACK. Source RPM, so just do things differently */
dirIndex = 0 ;
dirNames [ dirIndex ] = " " ;
for ( i = 0 ; i < count ; i + + ) {
dirIndexes [ i ] = dirIndex ;
baseNames [ i ] = fileNames [ i ] ;
}
goto exit ;
}
/*@-branchstate@*/
for ( i = 0 ; i < count ; i + + ) {
const char * * needle ;
char savechar ;
char * baseName ;
int len ;
if ( fileNames [ i ] = = NULL ) /* XXX can't happen */
continue ;
baseName = strrchr ( fileNames [ i ] , ' / ' ) + 1 ;
len = baseName - fileNames [ i ] ;
needle = dirNames ;
savechar = * baseName ;
* baseName = ' \0 ' ;
/*@-compdef@*/
if ( dirIndex < 0 | |
( needle = bsearch ( & fileNames [ i ] , dirNames , dirIndex + 1 , sizeof ( dirNames [ 0 ] ) , dncmp ) ) = = NULL ) {
char * s = alloca ( len + 1 ) ;
memcpy ( s , fileNames [ i ] , len + 1 ) ;
s [ len ] = ' \0 ' ;
dirIndexes [ i ] = + + dirIndex ;
dirNames [ dirIndex ] = s ;
} else
dirIndexes [ i ] = needle - dirNames ;
/*@=compdef@*/
* baseName = savechar ;
baseNames [ i ] = baseName ;
}
/*@=branchstate@*/
exit :
if ( count > 0 ) {
xx = hae ( h , RPMTAG_DIRINDEXES , RPM_INT32_TYPE , dirIndexes , count ) ;
xx = hae ( h , RPMTAG_BASENAMES , RPM_STRING_ARRAY_TYPE ,
baseNames , count ) ;
xx = hae ( h , RPMTAG_DIRNAMES , RPM_STRING_ARRAY_TYPE ,
dirNames , dirIndex + 1 ) ;
}
fileNames = hfd ( fileNames , fnt ) ;
xx = hre ( h , RPMTAG_OLDFILENAMES ) ;
}
/*@=bounds@*/
/*
* This is pretty straight - forward . The only thing that even resembles a trick
* is getting all of this into a single xmalloc ' d block .
*/
static void doBuildFileList ( Header h , /*@out@*/ const char * * * fileListPtr ,
/*@out@*/ int * fileCountPtr , rpmTag baseNameTag ,
rpmTag dirNameTag , rpmTag dirIndexesTag )
/*@modifies *fileListPtr, *fileCountPtr @*/
{
HGE_t hge = ( HGE_t ) headerGetEntryMinMemory ;
HFD_t hfd = headerFreeData ;
const char * * baseNames ;
const char * * dirNames ;
int * dirIndexes ;
int count ;
const char * * fileNames ;
int size ;
rpmTagType bnt , dnt ;
char * data ;
int i ;
if ( ! hge ( h , baseNameTag , & bnt , ( void * * ) & baseNames , & count ) ) {
if ( fileListPtr ) * fileListPtr = NULL ;
if ( fileCountPtr ) * fileCountPtr = 0 ;
return ; /* no file list */
}
( void ) hge ( h , dirNameTag , & dnt , ( void * * ) & dirNames , NULL ) ;
( void ) hge ( h , dirIndexesTag , NULL , ( void * * ) & dirIndexes , & count ) ;
size = sizeof ( * fileNames ) * count ;
for ( i = 0 ; i < count ; i + + )
size + = strlen ( baseNames [ i ] ) + strlen ( dirNames [ dirIndexes [ i ] ] ) + 1 ;
fileNames = xmalloc ( size ) ;
data = ( ( char * ) fileNames ) + ( sizeof ( * fileNames ) * count ) ;
for ( i = 0 ; i < count ; i + + ) {
fileNames [ i ] = data ;
data = stpcpy ( stpcpy ( data , dirNames [ dirIndexes [ i ] ] ) , baseNames [ i ] ) ;
* data + + = ' \0 ' ;
}
baseNames = hfd ( baseNames , bnt ) ;
dirNames = hfd ( dirNames , dnt ) ;
if ( fileListPtr )
* fileListPtr = fileNames ;
else
fileNames = _free ( fileNames ) ;
if ( fileCountPtr ) * fileCountPtr = count ;
}
void expandFilelist ( Header h )
{
HAE_t hae = ( HAE_t ) headerAddEntry ;
HRE_t hre = ( HRE_t ) headerRemoveEntry ;
const char * * fileNames = NULL ;
int count = 0 ;
if ( ! headerIsEntry ( h , RPMTAG_OLDFILENAMES ) ) {
doBuildFileList ( h , & fileNames , & count , RPMTAG_BASENAMES ,
RPMTAG_DIRNAMES , RPMTAG_DIRINDEXES ) ;
if ( fileNames = = NULL | | count < = 0 )
return ;
( void ) hae ( h , RPMTAG_OLDFILENAMES , RPM_STRING_ARRAY_TYPE ,
fileNames , count ) ;
fileNames = _free ( fileNames ) ;
}
( void ) hre ( h , RPMTAG_DIRNAMES ) ;
( void ) hre ( h , RPMTAG_BASENAMES ) ;
( void ) hre ( h , RPMTAG_DIRINDEXES ) ;
}
void rpmBuildFileList ( Header h , const char * * * fileListPtr , int * fileCountPtr )
{
doBuildFileList ( h , fileListPtr , fileCountPtr , RPMTAG_BASENAMES ,
RPMTAG_DIRNAMES , RPMTAG_DIRINDEXES ) ;
}
void buildOrigFileList ( Header h , const char * * * fileListPtr , int * fileCountPtr )
{
doBuildFileList ( h , fileListPtr , fileCountPtr , RPMTAG_ORIGBASENAMES ,
RPMTAG_ORIGDIRNAMES , RPMTAG_ORIGDIRINDEXES ) ;
}
/*
* Up to rpm 3.0 .4 , packages implicitly provided their own name - version - release .
2018-12-20 04:36:24 +03:00
* Retrofit an explicit " Provides: name = epoch:version-release:disttag.
2005-10-15 20:30:13 +04:00
*/
void providePackageNVR ( Header h )
{
HGE_t hge = ( HGE_t ) headerGetEntryMinMemory ;
HFD_t hfd = headerFreeData ;
2018-12-20 04:36:24 +03:00
const char * name , * version , * release , * disttag ;
2005-10-15 20:30:13 +04:00
int_32 * epoch ;
const char * pEVR ;
int_32 pFlags = RPMSENSE_EQUAL ;
const char * * provides = NULL ;
const char * * providesEVR = NULL ;
rpmTagType pnt , pvt ;
int_32 * provideFlags = NULL ;
int providesCount ;
int i , xx ;
int bingo = 1 ;
/* Generate provides for this package name-version-release. */
2018-12-20 04:36:24 +03:00
xx = headerNVRD ( h , & name , & version , & release , & disttag ) ;
2005-10-15 20:30:13 +04:00
if ( ! ( name & & version & & release ) )
return ;
2018-12-20 04:36:24 +03:00
if ( disttag & & ! * disttag )
disttag = NULL ;
char ebuf [ sizeof ( * epoch ) * 3 + 2 ] = " " ;
if ( hge ( h , RPMTAG_EPOCH , NULL , ( void * * ) & epoch , NULL ) )
sprintf ( ebuf , " %u: " , * epoch ) ;
pEVR = xasprintf ( " %s%s-%s%s%s " ,
ebuf , version , release ,
disttag ? " : " : " " ,
disttag ? : " " ) ;
2005-10-15 20:30:13 +04:00
/*
* Rpm prior to 3.0 .3 does not have versioned provides .
* If no provides at all are available , we can just add .
*/
if ( ! hge ( h , RPMTAG_PROVIDENAME , & pnt , ( void * * ) & provides , & providesCount ) )
goto exit ;
/*
* Otherwise , fill in entries on legacy packages .
*/
if ( ! hge ( h , RPMTAG_PROVIDEVERSION , & pvt , ( void * * ) & providesEVR , NULL ) ) {
for ( i = 0 ; i < providesCount ; i + + ) {
char * vdummy = " " ;
int_32 fdummy = RPMSENSE_ANY ;
xx = headerAddOrAppendEntry ( h , RPMTAG_PROVIDEVERSION , RPM_STRING_ARRAY_TYPE ,
& vdummy , 1 ) ;
xx = headerAddOrAppendEntry ( h , RPMTAG_PROVIDEFLAGS , RPM_INT32_TYPE ,
& fdummy , 1 ) ;
}
goto exit ;
}
xx = hge ( h , RPMTAG_PROVIDEFLAGS , NULL , ( void * * ) & provideFlags , NULL ) ;
/*@-nullderef@*/ /* LCL: providesEVR is not NULL */
if ( provides & & providesEVR & & provideFlags )
for ( i = 0 ; i < providesCount ; i + + ) {
if ( ! ( provides [ i ] & & providesEVR [ i ] ) )
continue ;
if ( ! ( provideFlags [ i ] = = RPMSENSE_EQUAL & &
! strcmp ( name , provides [ i ] ) & & ! strcmp ( pEVR , providesEVR [ i ] ) ) )
continue ;
bingo = 0 ;
break ;
}
/*@=nullderef@*/
exit :
provides = hfd ( provides , pnt ) ;
providesEVR = hfd ( providesEVR , pvt ) ;
if ( bingo ) {
xx = headerAddOrAppendEntry ( h , RPMTAG_PROVIDENAME , RPM_STRING_ARRAY_TYPE ,
& name , 1 ) ;
xx = headerAddOrAppendEntry ( h , RPMTAG_PROVIDEFLAGS , RPM_INT32_TYPE ,
& pFlags , 1 ) ;
xx = headerAddOrAppendEntry ( h , RPMTAG_PROVIDEVERSION , RPM_STRING_ARRAY_TYPE ,
& pEVR , 1 ) ;
}
2018-12-20 04:36:24 +03:00
pEVR = _free ( pEVR ) ;
2005-10-15 20:30:13 +04:00
}