1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/target/rpm/librpmDb.cc
16 #include "zypp/base/Logger.h"
17 #include "zypp/target/rpm/librpmDb.h"
18 #include "zypp/target/rpm/RpmHeader.h"
19 #include "zypp/target/rpm/RpmException.h"
29 ///////////////////////////////////////////////////////////////////
31 // CLASS NAME : librpmDb::D
33 * @short librpmDb internal database handle
37 D & operator=( const D & ); // NO ASSIGNMENT!
38 D ( const D & ); // NO COPY!
41 const Pathname _root; // root directory for all operations
42 const Pathname _dbPath; // directory (below root) that contains the rpmdb
43 rpmdb _db; // database handle
44 shared_ptr<RpmException> _error; // database error
46 friend ostream & operator<<( ostream & str, const D & obj )
48 str << "{" << obj._error << "(" << obj._root << ")" << obj._dbPath << "}";
52 D( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
59 ::addMacro( NULL, "_dbpath", NULL, _dbPath.asString().c_str(), RMIL_CMDLINE );
60 const char * root = ( _root == "/" ? NULL : _root.asString().c_str() );
63 // check whether to create a new db
64 PathInfo master( _root + _dbPath + "Packages" );
65 if ( ! master.isFile() )
68 int res = ::rpmdbInit( root, perms );
71 ERR << "rpmdbInit error(" << res << "): " << *this << endl;
72 _error = shared_ptr<RpmInitException>(new RpmInitException(_root, _dbPath));
78 int res = ::rpmdbOpen( root, &_db, (readonly_r ? O_RDONLY : O_RDWR ), perms );
86 ERR << "rpmdbOpen error(" << res << "): " << *this << endl;
87 _error = shared_ptr<RpmDbOpenException>(new RpmDbOpenException(_root, _dbPath));
92 DBG << "DBACCESS " << *this << endl;
104 ///////////////////////////////////////////////////////////////////
106 ///////////////////////////////////////////////////////////////////
108 // CLASS NAME : librpmDb (ststic interface)
110 ///////////////////////////////////////////////////////////////////
112 Pathname librpmDb::_defaultRoot ( "/" );
113 Pathname librpmDb::_defaultDbPath( "/var/lib/rpm" );
114 librpmDb::constPtr librpmDb::_defaultDb;
115 bool librpmDb::_dbBlocked ( true );
117 ///////////////////////////////////////////////////////////////////
120 // METHOD NAME : librpmDb::globalInit
121 // METHOD TYPE : bool
123 bool librpmDb::globalInit()
125 static bool initialized = false;
130 int rc = ::rpmReadConfigFiles( NULL, NULL );
133 ERR << "rpmReadConfigFiles returned " << rc << endl;
137 initialized = true; // Necessary to be able to use exand().
139 #define OUTVAL(n) << " (" #n ":" << expand( "%{" #n "}" ) << ")"
140 MIL << "librpm init done:"
148 ///////////////////////////////////////////////////////////////////
151 // METHOD NAME : librpmDb::expand
152 // METHOD TYPE : std::string
154 std::string librpmDb::expand( const std::string & macro_r )
156 if ( ! globalInit() )
157 return macro_r; // unexpanded
159 char * val = ::rpmExpand( macro_r.c_str(), NULL );
168 ///////////////////////////////////////////////////////////////////
171 // METHOD NAME : librpmDb::newLibrpmDb
172 // METHOD TYPE : librpmDb *
174 librpmDb * librpmDb::newLibrpmDb( Pathname root_r, Pathname dbPath_r, bool readonly_r )
177 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
179 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
183 if ( ! globalInit() )
185 ZYPP_THROW(GlobalRpmInitException());
192 ret = new librpmDb( root_r, dbPath_r, readonly_r );
194 catch (const RpmException & excpt_r)
196 ZYPP_CAUGHT(excpt_r);
199 ZYPP_RETHROW(excpt_r);
204 ///////////////////////////////////////////////////////////////////
207 // METHOD NAME : librpmDb::dbAccess
208 // METHOD TYPE : PMError
210 void librpmDb::dbAccess( const Pathname & root_r, const Pathname & dbPath_r )
213 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
215 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
220 // already accessing a database: switching is not allowed.
221 if ( _defaultRoot == root_r && _defaultDbPath == dbPath_r )
225 ZYPP_THROW(RpmDbAlreadyOpenException(_defaultRoot, _defaultDbPath, root_r, dbPath_r));
229 // got no database: we could switch to a new one (even if blocked!)
230 _defaultRoot = root_r;
231 _defaultDbPath = dbPath_r;
232 MIL << "Set new database location: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
237 ///////////////////////////////////////////////////////////////////
240 // METHOD NAME : librpmDb::dbAccess
241 // METHOD TYPE : PMError
243 void librpmDb::dbAccess()
247 ZYPP_THROW(RpmAccessBlockedException(_defaultRoot, _defaultDbPath));
253 _defaultDb = newLibrpmDb( _defaultRoot, _defaultDbPath, /*readonly*/true );
257 ///////////////////////////////////////////////////////////////////
260 // METHOD NAME : librpmDb::dbAccess
261 // METHOD TYPE : PMError
263 void librpmDb::dbAccess( librpmDb::constPtr & ptr_r )
269 catch (const RpmException & excpt_r)
271 ZYPP_CAUGHT(excpt_r);
273 ZYPP_RETHROW(excpt_r);
278 ///////////////////////////////////////////////////////////////////
281 // METHOD NAME : librpmDb::dbRelease
282 // METHOD TYPE : unsigned
284 unsigned librpmDb::dbRelease( bool force_r )
291 unsigned outstanding = _defaultDb->refCount() - 1; // refCount can't be 0
293 switch ( outstanding )
298 DBG << "dbRelease: keep access, outstanding " << outstanding << endl;
301 // else fall through:
303 DBG << "dbRelease: release" << (force_r && outstanding ? "(forced)" : "")
304 << ", outstanding " << outstanding << endl;
306 _defaultDb->_d._error = shared_ptr<RpmAccessBlockedException>(new RpmAccessBlockedException(_defaultDb->_d._root, _defaultDb->_d._dbPath));
307 // tag handle invalid
315 ///////////////////////////////////////////////////////////////////
318 // METHOD NAME : librpmDb::blockAccess
319 // METHOD TYPE : unsigned
321 unsigned librpmDb::blockAccess()
323 MIL << "Block access" << endl;
325 return dbRelease( /*force*/true );
328 ///////////////////////////////////////////////////////////////////
331 // METHOD NAME : librpmDb::unblockAccess
332 // METHOD TYPE : void
334 void librpmDb::unblockAccess()
336 MIL << "Unblock access" << endl;
340 ///////////////////////////////////////////////////////////////////
343 // METHOD NAME : librpmDb::dumpState
344 // METHOD TYPE : ostream &
346 ostream & librpmDb::dumpState( ostream & str )
350 return str << "[librpmDb " << (_dbBlocked?"BLOCKED":"CLOSED") << " " << stringPath( _defaultRoot, _defaultDbPath ) << "]";
352 return str << "[" << _defaultDb << "]";
355 ///////////////////////////////////////////////////////////////////
357 // CLASS NAME : librpmDb (internal database handle interface (nonstatic))
359 ///////////////////////////////////////////////////////////////////
361 ///////////////////////////////////////////////////////////////////
364 // METHOD NAME : librpmDb::librpmDb
365 // METHOD TYPE : Constructor
369 librpmDb::librpmDb( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
370 : _d( * new D( root_r, dbPath_r, readonly_r ) )
373 ///////////////////////////////////////////////////////////////////
376 // METHOD NAME : librpmDb::~librpmDb
377 // METHOD TYPE : Destructor
381 librpmDb::~librpmDb()
386 ///////////////////////////////////////////////////////////////////
389 // METHOD NAME : librpmDb::unref_to
390 // METHOD TYPE : void
392 void librpmDb::unref_to( unsigned refCount_r ) const
394 if ( refCount_r == 1 )
400 ///////////////////////////////////////////////////////////////////
403 // METHOD NAME : librpmDb::root
404 // METHOD TYPE : const Pathname &
406 const Pathname & librpmDb::root() const
411 ///////////////////////////////////////////////////////////////////
414 // METHOD NAME : librpmDb::dbPath
415 // METHOD TYPE : const Pathname &
417 const Pathname & librpmDb::dbPath() const
422 ///////////////////////////////////////////////////////////////////
425 // METHOD NAME : librpmDb::error
426 // METHOD TYPE : PMError
428 shared_ptr<RpmException> librpmDb::error() const
433 ///////////////////////////////////////////////////////////////////
436 // METHOD NAME : librpmDb::empty
437 // METHOD TYPE : bool
439 bool librpmDb::empty() const
441 return( valid() && ! *db_const_iterator( this ) );
444 ///////////////////////////////////////////////////////////////////
447 // METHOD NAME : librpmDb::size
448 // METHOD TYPE : unsigned
450 unsigned librpmDb::size() const
456 // looks like rpm-4.7 has no public dbi interface anymore
457 int dbi = ::rpmdbOpen("/", &_d._db, O_RDONLY, 0);
459 rpmdbMatchIterator mi = ::rpmdbInitIterator(_d._db, RPMTAG_NAME, NULL, 0);
462 Header rpmHeader = ::rpmdbNextIterator(mi);
463 if (rpmHeader != NULL)
467 ::rpmdbClose(_d._db);
470 dbiIndex dbi = dbiOpen( _d._db, RPMTAG_NAME, 0 );
474 dbiCopen( dbi, dbi->dbi_txnid, &dbcursor, 0 );
477 memset( &key, 0, sizeof(key) );
478 memset( &data, 0, sizeof(data) );
479 while ( dbiGet( dbi, dbcursor, &key, &data, DB_NEXT ) == 0 )
480 count += data.size / dbi->dbi_jlen;
482 dbiCclose( dbi, dbcursor, 0 );
483 /* no need to close dbi */
490 ///////////////////////////////////////////////////////////////////
493 // METHOD NAME : librpmDb::dont_call_it
494 // METHOD TYPE : void *
496 void * librpmDb::dont_call_it() const
501 ///////////////////////////////////////////////////////////////////
504 // METHOD NAME : librpmDb::dumpOn
505 // METHOD TYPE : ostream &
509 ostream & librpmDb::dumpOn( ostream & str ) const
511 ReferenceCounted::dumpOn( str ) << _d;
515 ///////////////////////////////////////////////////////////////////
517 // CLASS NAME : librpmDb::DbDirInfo
519 ///////////////////////////////////////////////////////////////////
521 ///////////////////////////////////////////////////////////////////
524 // METHOD NAME : librpmDb::DbDirInfo::DbDirInfo
525 // METHOD TYPE : Constructor
527 librpmDb::DbDirInfo::DbDirInfo( const Pathname & root_r, const Pathname & dbPath_r )
529 , _dbPath( dbPath_r )
531 // check and adjust arguments
532 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
534 ERR << "Relative path for root(" << _root << ") or dbPath(" << _dbPath << ")" << endl;
538 _dbDir ( _root + _dbPath );
539 _dbV4 ( _dbDir.path() + "Packages" );
540 _dbV3 ( _dbDir.path() + "packages.rpm" );
541 _dbV3ToV4( _dbDir.path() + "packages.rpm3" );
542 DBG << *this << endl;
546 ///////////////////////////////////////////////////////////////////
549 // METHOD NAME : librpmDb::DbDirInfo::update
550 // METHOD TYPE : void
552 void librpmDb::DbDirInfo::restat()
558 DBG << *this << endl;
561 /******************************************************************
564 ** FUNCTION NAME : operator<<
565 ** FUNCTION TYPE : std::ostream &
567 std::ostream & operator<<( std::ostream & str, const librpmDb::DbDirInfo & obj )
569 if ( obj.illegalArgs() )
571 str << "ILLEGAL: '(" << obj.root() << ")" << obj.dbPath() << "'";
575 str << "'(" << obj.root() << ")" << obj.dbPath() << "':" << endl;
576 str << " Dir: " << obj._dbDir << endl;
577 str << " V4: " << obj._dbV4 << endl;
578 str << " V3: " << obj._dbV3 << endl;
579 str << " V3ToV4: " << obj._dbV3ToV4;
584 ///////////////////////////////////////////////////////////////////
586 // CLASS NAME : librpmDb::db_const_iterator::D
590 class librpmDb::db_const_iterator::D
592 D & operator=( const D & ); // NO ASSIGNMENT!
593 D ( const D & ); // NO COPY!
596 librpmDb::constPtr _dbptr;
597 shared_ptr<RpmException> _dberr;
599 RpmHeader::constPtr _hptr;
600 rpmdbMatchIterator _mi;
602 D( librpmDb::constPtr dbptr_r )
610 librpmDb::dbAccess( _dbptr );
612 catch (const RpmException & excpt_r)
614 ZYPP_CAUGHT(excpt_r);
618 WAR << "No database access: " << _dberr << endl;
623 destroy(); // Checks whether _dbptr still valid
631 ::rpmdbFreeIterator( _mi );
636 * Let iterator access a dbindex file. Call @ref advance to access the
637 * 1st element (if present).
639 bool create( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
644 _mi = ::rpmdbInitIterator( _dbptr->_d._db, rpmTag(rpmtag), keyp, keylen );
649 * Destroy iterator. Invalidates _dbptr, if database was blocked meanwile.
650 * Always returns false.
656 _mi = ::rpmdbFreeIterator( _mi );
659 if ( _dbptr && _dbptr->error() )
661 _dberr = _dbptr->error();
662 WAR << "Lost database access: " << _dberr << endl;
669 * Advance to the first/next header in iterator. Destroys iterator if
670 * no more headers available.
676 Header h = ::rpmdbNextIterator( _mi );
682 _hptr = new RpmHeader( h );
687 * Access a dbindex file and advance to the 1st header.
689 bool init( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
691 if ( ! create( rpmtag, keyp, keylen ) )
697 * Create an itertator that contains the database entry located at
698 * off_r, and advance to the 1st header.
700 bool set( int off_r )
702 if ( ! create( RPMDBI_PACKAGES ) )
704 #warning TESTCASE: rpmdbAppendIterator and (non)sequential access?
705 ::rpmdbAppendIterator( _mi, &off_r, 1 );
711 return( _mi ? ::rpmdbGetIteratorOffset( _mi ) : 0 );
718 int ret = ::rpmdbGetIteratorCount( _mi );
719 #warning TESTCASE: rpmdbGetIteratorCount returns 0 on sequential access?
720 return( ret ? ret : -1 ); // -1: sequential access
724 ///////////////////////////////////////////////////////////////////
726 ///////////////////////////////////////////////////////////////////
728 // CLASS NAME : librpmDb::Ptr::db_const_iterator
730 ///////////////////////////////////////////////////////////////////
732 ///////////////////////////////////////////////////////////////////
735 // METHOD NAME : librpmDb::db_const_iterator::db_iterator
736 // METHOD TYPE : Constructor
738 librpmDb::db_const_iterator::db_const_iterator( librpmDb::constPtr dbptr_r )
739 : _d( * new D( dbptr_r ) )
744 ///////////////////////////////////////////////////////////////////
747 // METHOD NAME : librpmDb::db_const_iterator::~db_const_iterator
748 // METHOD TYPE : Destructor
750 librpmDb::db_const_iterator::~db_const_iterator()
755 ///////////////////////////////////////////////////////////////////
758 // METHOD NAME : librpmDb::db_const_iterator::operator++
759 // METHOD TYPE : void
761 void librpmDb::db_const_iterator::operator++()
766 ///////////////////////////////////////////////////////////////////
769 // METHOD NAME : librpmDb::db_const_iterator::dbHdrNum
770 // METHOD TYPE : unsigned
772 unsigned librpmDb::db_const_iterator::dbHdrNum() const
777 ///////////////////////////////////////////////////////////////////
780 // METHOD NAME : librpmDb::db_const_iterator::operator*
781 // METHOD TYPE : const RpmHeader::constPtr &
783 const RpmHeader::constPtr & librpmDb::db_const_iterator::operator*() const
788 ///////////////////////////////////////////////////////////////////
791 // METHOD NAME : librpmDb::db_const_iterator::dbError
792 // METHOD TYPE : PMError
794 shared_ptr<RpmException> librpmDb::db_const_iterator::dbError() const
797 return _d._dbptr->error();
802 /******************************************************************
805 ** FUNCTION NAME : operator<<
806 ** FUNCTION TYPE : ostream &
808 ostream & operator<<( ostream & str, const librpmDb::db_const_iterator & obj )
810 str << "db_const_iterator(" << obj._d._dbptr
811 << " Size:" << obj._d.size()
812 << " HdrNum:" << obj._d.offset()
817 ///////////////////////////////////////////////////////////////////
820 // METHOD NAME : librpmDb::db_const_iterator::findAll
821 // METHOD TYPE : bool
823 bool librpmDb::db_const_iterator::findAll()
825 return _d.init( RPMDBI_PACKAGES );
828 ///////////////////////////////////////////////////////////////////
831 // METHOD NAME : librpmDb::db_const_iterator::findByFile
832 // METHOD TYPE : bool
834 bool librpmDb::db_const_iterator::findByFile( const std::string & file_r )
836 return _d.init( RPMTAG_BASENAMES, file_r.c_str() );
839 ///////////////////////////////////////////////////////////////////
842 // METHOD NAME : librpmDb::db_const_iterator::findByProvides
843 // METHOD TYPE : bool
845 bool librpmDb::db_const_iterator::findByProvides( const std::string & tag_r )
847 return _d.init( RPMTAG_PROVIDENAME, tag_r.c_str() );
850 ///////////////////////////////////////////////////////////////////
853 // METHOD NAME : librpmDb::db_const_iterator::findByRequiredBy
854 // METHOD TYPE : bool
856 bool librpmDb::db_const_iterator::findByRequiredBy( const std::string & tag_r )
858 return _d.init( RPMTAG_REQUIRENAME, tag_r.c_str() );
861 ///////////////////////////////////////////////////////////////////
864 // METHOD NAME : librpmDb::db_const_iterator::findByConflicts
865 // METHOD TYPE : bool
867 bool librpmDb::db_const_iterator::findByConflicts( const std::string & tag_r )
869 return _d.init( RPMTAG_CONFLICTNAME, tag_r.c_str() );
872 ///////////////////////////////////////////////////////////////////
875 // METHOD NAME : librpmDb::findByName
876 // METHOD TYPE : bool
878 bool librpmDb::db_const_iterator::findByName( const string & name_r )
880 return _d.init( RPMTAG_NAME, name_r.c_str() );
883 ///////////////////////////////////////////////////////////////////
886 // METHOD NAME : librpmDb::db_const_iterator::findPackage
887 // METHOD TYPE : bool
889 bool librpmDb::db_const_iterator::findPackage( const string & name_r )
891 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
894 if ( _d.size() == 1 )
897 // check installtime on multiple entries
900 for ( ; operator*(); operator++() )
902 if ( operator*()->tag_installtime() > itime )
905 itime = operator*()->tag_installtime();
909 return _d.set( match );
912 ///////////////////////////////////////////////////////////////////
915 // METHOD NAME : librpmDb::db_const_iterator::findPackage
916 // METHOD TYPE : bool
918 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r, const Edition & ed_r )
920 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
923 for ( ; operator*(); operator++() )
925 if ( ed_r == operator*()->tag_edition() )
927 int match = _d.offset();
928 return _d.set( match );
935 ///////////////////////////////////////////////////////////////////
938 // METHOD NAME : librpmDb::db_const_iterator::findPackage
939 // METHOD TYPE : bool
941 bool librpmDb::db_const_iterator::findPackage( const Package::constPtr & which_r )
946 return findPackage( which_r->name(), which_r->edition() );
950 } // namespace target