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"
26 ///////////////////////////////////////////////////////////////////
28 // CLASS NAME : librpmDb::D
30 * @short librpmDb internal database handle
33 D & operator=( const D & ); // NO ASSIGNMENT!
34 D ( const D & ); // NO COPY!
37 const Pathname _root; // root directory for all operations
38 const Pathname _dbPath; // directory (below root) that contains the rpmdb
39 rpmdb _db; // database handle
40 shared_ptr<RpmException> _error; // database error
42 friend ostream & operator<<( ostream & str, const D & obj ) {
43 str << "{" << obj._error << "(" << obj._root << ")" << obj._dbPath << "}";
47 D( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
54 ::addMacro( NULL, "_dbpath", NULL, _dbPath.asString().c_str(), RMIL_CMDLINE );
55 const char * root = ( _root == "/" ? NULL : _root.asString().c_str() );
58 // check whether to create a new db
59 PathInfo master( _root + _dbPath + "Packages" );
60 if ( ! master.isFile() ) {
62 int res = ::rpmdbInit( root, perms );
64 ERR << "rpmdbInit error(" << res << "): " << *this << endl;
65 _error = shared_ptr<RpmInitException>(new RpmInitException(_root, _dbPath));
71 int res = ::rpmdbOpen( root, &_db, (readonly_r ? O_RDONLY : O_RDWR ), perms );
77 ERR << "rpmdbOpen error(" << res << "): " << *this << endl;
78 _error = shared_ptr<RpmDbOpenException>(new RpmDbOpenException(_root, _dbPath));
83 DBG << "DBACCESS " << *this << endl;
93 ///////////////////////////////////////////////////////////////////
95 ///////////////////////////////////////////////////////////////////
97 // CLASS NAME : librpmDb (ststic interface)
99 ///////////////////////////////////////////////////////////////////
101 Pathname librpmDb::_defaultRoot ( "/" );
102 Pathname librpmDb::_defaultDbPath( "/var/lib/rpm" );
103 librpmDb::constPtr librpmDb::_defaultDb;
104 bool librpmDb::_dbBlocked ( true );
106 ///////////////////////////////////////////////////////////////////
109 // METHOD NAME : librpmDb::globalInit
110 // METHOD TYPE : bool
112 bool librpmDb::globalInit()
114 static bool initialized = false;
119 int rc = ::rpmReadConfigFiles( NULL, NULL );
121 ERR << "rpmReadConfigFiles returned " << rc << endl;
125 // should speed up convertdb and rebuilddb.
126 ::addMacro( NULL, "_rpmdb_rebuild", NULL, "%{nil}", RMIL_CMDLINE );
128 initialized = true; // Necessary to be able to use exand().
130 #define OUTVAL(n) << " (" #n ":" << expand( "%{" #n "}" ) << ")"
131 MIL << "librpm init done:"
139 ///////////////////////////////////////////////////////////////////
142 // METHOD NAME : librpmDb::expand
143 // METHOD TYPE : std::string
145 std::string librpmDb::expand( const std::string & macro_r )
147 if ( ! globalInit() )
148 return macro_r; // unexpanded
150 char * val = ::rpmExpand( macro_r.c_str(), NULL );
159 ///////////////////////////////////////////////////////////////////
162 // METHOD NAME : librpmDb::newLibrpmDb
163 // METHOD TYPE : librpmDb *
165 librpmDb * librpmDb::newLibrpmDb( Pathname root_r, Pathname dbPath_r, bool readonly_r )
168 if ( ! (root_r.absolute() && dbPath_r.absolute()) ) {
169 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
173 if ( ! globalInit() ) {
174 ZYPP_THROW(GlobalRpmInitException());
180 ret = new librpmDb( root_r, dbPath_r, readonly_r );
182 catch (const RpmException & excpt_r)
184 ZYPP_CAUGHT(excpt_r);
187 ZYPP_RETHROW(excpt_r);
192 ///////////////////////////////////////////////////////////////////
195 // METHOD NAME : librpmDb::dbAccess
196 // METHOD TYPE : PMError
198 void librpmDb::dbAccess( const Pathname & root_r, const Pathname & dbPath_r )
201 if ( ! (root_r.absolute() && dbPath_r.absolute()) ) {
202 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
206 // already accessing a database: switching is not allowed.
207 if ( _defaultRoot == root_r && _defaultDbPath == dbPath_r )
210 ZYPP_THROW(RpmDbAlreadyOpenException(_defaultRoot, _defaultDbPath, root_r, dbPath_r));
214 // got no database: we could switch to a new one (even if blocked!)
215 _defaultRoot = root_r;
216 _defaultDbPath = dbPath_r;
217 MIL << "Set new database location: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
222 ///////////////////////////////////////////////////////////////////
225 // METHOD NAME : librpmDb::dbAccess
226 // METHOD TYPE : PMError
228 void librpmDb::dbAccess()
231 ZYPP_THROW(RpmAccessBlockedException(_defaultRoot, _defaultDbPath));
236 _defaultDb = newLibrpmDb( _defaultRoot, _defaultDbPath, /*readonly*/true );
240 ///////////////////////////////////////////////////////////////////
243 // METHOD NAME : librpmDb::dbAccess
244 // METHOD TYPE : PMError
246 void librpmDb::dbAccess( librpmDb::constPtr & ptr_r )
251 catch (const RpmException & excpt_r)
253 ZYPP_CAUGHT(excpt_r);
255 ZYPP_RETHROW(excpt_r);
260 ///////////////////////////////////////////////////////////////////
263 // METHOD NAME : librpmDb::dbRelease
264 // METHOD TYPE : unsigned
266 unsigned librpmDb::dbRelease( bool force_r )
272 unsigned outstanding = _defaultDb->refCount() - 1; // refCount can't be 0
274 switch ( outstanding ) {
277 DBG << "dbRelease: keep access, outstanding " << outstanding << endl;
280 // else fall through:
282 DBG << "dbRelease: release" << (force_r && outstanding ? "(forced)" : "")
283 << ", outstanding " << outstanding << endl;
285 _defaultDb->_d._error = shared_ptr<RpmAccessBlockedException>(new RpmAccessBlockedException(_defaultDb->_d._root, _defaultDb->_d._dbPath));
286 // tag handle invalid
294 ///////////////////////////////////////////////////////////////////
297 // METHOD NAME : librpmDb::blockAccess
298 // METHOD TYPE : unsigned
300 unsigned librpmDb::blockAccess()
302 MIL << "Block access" << endl;
304 return dbRelease( /*force*/true );
307 ///////////////////////////////////////////////////////////////////
310 // METHOD NAME : librpmDb::unblockAccess
311 // METHOD TYPE : void
313 void librpmDb::unblockAccess()
315 MIL << "Unblock access" << endl;
319 ///////////////////////////////////////////////////////////////////
322 // METHOD NAME : librpmDb::dumpState
323 // METHOD TYPE : ostream &
325 ostream & librpmDb::dumpState( ostream & str )
328 return str << "[librpmDb " << (_dbBlocked?"BLOCKED":"CLOSED") << " " << stringPath( _defaultRoot, _defaultDbPath ) << "]";
330 return str << "[" << _defaultDb << "]";
333 ///////////////////////////////////////////////////////////////////
335 // CLASS NAME : librpmDb (internal database handle interface (nonstatic))
337 ///////////////////////////////////////////////////////////////////
339 ///////////////////////////////////////////////////////////////////
342 // METHOD NAME : librpmDb::librpmDb
343 // METHOD TYPE : Constructor
347 librpmDb::librpmDb( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
348 : _d( * new D( root_r, dbPath_r, readonly_r ) )
352 ///////////////////////////////////////////////////////////////////
355 // METHOD NAME : librpmDb::~librpmDb
356 // METHOD TYPE : Destructor
360 librpmDb::~librpmDb()
365 ///////////////////////////////////////////////////////////////////
368 // METHOD NAME : librpmDb::unref_to
369 // METHOD TYPE : void
371 void librpmDb::unref_to( unsigned refCount_r ) const
373 if ( refCount_r == 1 ) {
378 ///////////////////////////////////////////////////////////////////
381 // METHOD NAME : librpmDb::root
382 // METHOD TYPE : const Pathname &
384 const Pathname & librpmDb::root() const
389 ///////////////////////////////////////////////////////////////////
392 // METHOD NAME : librpmDb::dbPath
393 // METHOD TYPE : const Pathname &
395 const Pathname & librpmDb::dbPath() const
400 ///////////////////////////////////////////////////////////////////
403 // METHOD NAME : librpmDb::error
404 // METHOD TYPE : PMError
406 shared_ptr<RpmException> librpmDb::error() const
411 ///////////////////////////////////////////////////////////////////
414 // METHOD NAME : librpmDb::empty
415 // METHOD TYPE : bool
417 bool librpmDb::empty() const
419 return( valid() && ! *db_const_iterator( this ) );
422 ///////////////////////////////////////////////////////////////////
425 // METHOD NAME : librpmDb::size
426 // METHOD TYPE : unsigned
428 unsigned librpmDb::size() const
433 dbiIndex dbi = dbiOpen( _d._db, RPMTAG_NAME, 0 );
437 dbiCopen( dbi, dbi->dbi_txnid, &dbcursor, 0 );
440 memset( &key, 0, sizeof(key) );
441 memset( &data, 0, sizeof(data) );
442 while ( dbiGet( dbi, dbcursor, &key, &data, DB_NEXT ) == 0 )
443 count += data.size / dbi->dbi_jlen;
445 dbiCclose( dbi, dbcursor, 0 );
446 /* no need to close dbi */
452 ///////////////////////////////////////////////////////////////////
455 // METHOD NAME : librpmDb::dont_call_it
456 // METHOD TYPE : void *
458 void * librpmDb::dont_call_it() const
463 ///////////////////////////////////////////////////////////////////
466 // METHOD NAME : librpmDb::dumpOn
467 // METHOD TYPE : ostream &
471 ostream & librpmDb::dumpOn( ostream & str ) const
473 ReferenceCounted::dumpOn( str ) << _d;
477 ///////////////////////////////////////////////////////////////////
479 // CLASS NAME : librpmDb::DbDirInfo
481 ///////////////////////////////////////////////////////////////////
483 ///////////////////////////////////////////////////////////////////
486 // METHOD NAME : librpmDb::DbDirInfo::DbDirInfo
487 // METHOD TYPE : Constructor
489 librpmDb::DbDirInfo::DbDirInfo( const Pathname & root_r, const Pathname & dbPath_r )
491 , _dbPath( dbPath_r )
493 // check and adjust arguments
494 if ( ! (root_r.absolute() && dbPath_r.absolute()) ) {
495 ERR << "Relative path for root(" << _root << ") or dbPath(" << _dbPath << ")" << endl;
497 _dbDir ( _root + _dbPath );
498 _dbV4 ( _dbDir.path() + "Packages" );
499 _dbV3 ( _dbDir.path() + "packages.rpm" );
500 _dbV3ToV4( _dbDir.path() + "packages.rpm3" );
501 DBG << *this << endl;
505 ///////////////////////////////////////////////////////////////////
508 // METHOD NAME : librpmDb::DbDirInfo::update
509 // METHOD TYPE : void
511 void librpmDb::DbDirInfo::restat()
517 DBG << *this << endl;
520 /******************************************************************
523 ** FUNCTION NAME : operator<<
524 ** FUNCTION TYPE : std::ostream &
526 std::ostream & operator<<( std::ostream & str, const librpmDb::DbDirInfo & obj )
528 if ( obj.illegalArgs() ) {
529 str << "ILLEGAL: '(" << obj.root() << ")" << obj.dbPath() << "'";
531 str << "'(" << obj.root() << ")" << obj.dbPath() << "':" << endl;
532 str << " Dir: " << obj._dbDir << endl;
533 str << " V4: " << obj._dbV4 << endl;
534 str << " V3: " << obj._dbV3 << endl;
535 str << " V3ToV4: " << obj._dbV3ToV4;
540 ///////////////////////////////////////////////////////////////////
542 // CLASS NAME : librpmDb::db_const_iterator::D
546 class librpmDb::db_const_iterator::D {
547 D & operator=( const D & ); // NO ASSIGNMENT!
548 D ( const D & ); // NO COPY!
551 librpmDb::constPtr _dbptr;
552 shared_ptr<RpmException> _dberr;
554 RpmHeader::constPtr _hptr;
555 rpmdbMatchIterator _mi;
557 D( librpmDb::constPtr dbptr_r )
563 librpmDb::dbAccess( _dbptr );
565 catch (const RpmException & excpt_r)
567 ZYPP_CAUGHT(excpt_r);
570 WAR << "No database access: " << _dberr << endl;
573 destroy(); // Checks whether _dbptr still valid
579 ::rpmdbFreeIterator( _mi );
584 * Let iterator access a dbindex file. Call @ref advance to access the
585 * 1st element (if present).
587 bool create( int rpmtag, const void * keyp = NULL, size_t keylen = 0 ) {
591 _mi = ::rpmdbInitIterator( _dbptr->_d._db, rpmTag(rpmtag), keyp, keylen );
596 * Destroy iterator. Invalidates _dbptr, if database was blocked meanwile.
597 * Always returns false.
601 _mi = ::rpmdbFreeIterator( _mi );
604 if ( _dbptr && _dbptr->error() ) {
605 _dberr = _dbptr->error();
606 WAR << "Lost database access: " << _dberr << endl;
613 * Advance to the first/next header in iterator. Destroys iterator if
614 * no more headers available.
619 Header h = ::rpmdbNextIterator( _mi );
624 _hptr = new RpmHeader( h );
629 * Access a dbindex file and advance to the 1st header.
631 bool init( int rpmtag, const void * keyp = NULL, size_t keylen = 0 ) {
632 if ( ! create( rpmtag, keyp, keylen ) )
638 * Create an itertator that contains the database entry located at
639 * off_r, and advance to the 1st header.
641 bool set( int off_r ) {
642 if ( ! create( RPMDBI_PACKAGES ) )
644 #warning TESTCASE: rpmdbAppendIterator and (non)sequential access?
645 ::rpmdbAppendIterator( _mi, &off_r, 1 );
650 return( _mi ? ::rpmdbGetIteratorOffset( _mi ) : 0 );
656 int ret = ::rpmdbGetIteratorCount( _mi );
657 #warning TESTCASE: rpmdbGetIteratorCount returns 0 on sequential access?
658 return( ret ? ret : -1 ); // -1: sequential access
662 ///////////////////////////////////////////////////////////////////
664 ///////////////////////////////////////////////////////////////////
666 // CLASS NAME : librpmDb::Ptr::db_const_iterator
668 ///////////////////////////////////////////////////////////////////
670 ///////////////////////////////////////////////////////////////////
673 // METHOD NAME : librpmDb::db_const_iterator::db_iterator
674 // METHOD TYPE : Constructor
676 librpmDb::db_const_iterator::db_const_iterator( librpmDb::constPtr dbptr_r )
677 : _d( * new D( dbptr_r ) )
682 ///////////////////////////////////////////////////////////////////
685 // METHOD NAME : librpmDb::db_const_iterator::~db_const_iterator
686 // METHOD TYPE : Destructor
688 librpmDb::db_const_iterator::~db_const_iterator()
693 ///////////////////////////////////////////////////////////////////
696 // METHOD NAME : librpmDb::db_const_iterator::operator++
697 // METHOD TYPE : void
699 void librpmDb::db_const_iterator::operator++()
704 ///////////////////////////////////////////////////////////////////
707 // METHOD NAME : librpmDb::db_const_iterator::dbHdrNum
708 // METHOD TYPE : unsigned
710 unsigned librpmDb::db_const_iterator::dbHdrNum() const
715 ///////////////////////////////////////////////////////////////////
718 // METHOD NAME : librpmDb::db_const_iterator::operator*
719 // METHOD TYPE : const RpmHeader::constPtr &
721 const RpmHeader::constPtr & librpmDb::db_const_iterator::operator*() const
726 ///////////////////////////////////////////////////////////////////
729 // METHOD NAME : librpmDb::db_const_iterator::dbError
730 // METHOD TYPE : PMError
732 shared_ptr<RpmException> librpmDb::db_const_iterator::dbError() const
735 return _d._dbptr->error();
740 /******************************************************************
743 ** FUNCTION NAME : operator<<
744 ** FUNCTION TYPE : ostream &
746 ostream & operator<<( ostream & str, const librpmDb::db_const_iterator & obj )
748 str << "db_const_iterator(" << obj._d._dbptr
749 << " Size:" << obj._d.size()
750 << " HdrNum:" << obj._d.offset()
755 ///////////////////////////////////////////////////////////////////
758 // METHOD NAME : librpmDb::db_const_iterator::findAll
759 // METHOD TYPE : bool
761 bool librpmDb::db_const_iterator::findAll()
763 return _d.init( RPMDBI_PACKAGES );
766 ///////////////////////////////////////////////////////////////////
769 // METHOD NAME : librpmDb::db_const_iterator::findByFile
770 // METHOD TYPE : bool
772 bool librpmDb::db_const_iterator::findByFile( const std::string & file_r )
774 return _d.init( RPMTAG_BASENAMES, file_r.c_str() );
777 ///////////////////////////////////////////////////////////////////
780 // METHOD NAME : librpmDb::db_const_iterator::findByProvides
781 // METHOD TYPE : bool
783 bool librpmDb::db_const_iterator::findByProvides( const std::string & tag_r )
785 return _d.init( RPMTAG_PROVIDENAME, tag_r.c_str() );
788 ///////////////////////////////////////////////////////////////////
791 // METHOD NAME : librpmDb::db_const_iterator::findByRequiredBy
792 // METHOD TYPE : bool
794 bool librpmDb::db_const_iterator::findByRequiredBy( const std::string & tag_r )
796 return _d.init( RPMTAG_REQUIRENAME, tag_r.c_str() );
799 ///////////////////////////////////////////////////////////////////
802 // METHOD NAME : librpmDb::db_const_iterator::findByConflicts
803 // METHOD TYPE : bool
805 bool librpmDb::db_const_iterator::findByConflicts( const std::string & tag_r )
807 return _d.init( RPMTAG_CONFLICTNAME, tag_r.c_str() );
810 ///////////////////////////////////////////////////////////////////
813 // METHOD NAME : librpmDb::findByName
814 // METHOD TYPE : bool
816 bool librpmDb::db_const_iterator::findByName( const string & name_r )
818 return _d.init( RPMTAG_NAME, name_r.c_str() );
821 ///////////////////////////////////////////////////////////////////
824 // METHOD NAME : librpmDb::db_const_iterator::findPackage
825 // METHOD TYPE : bool
827 bool librpmDb::db_const_iterator::findPackage( const string & name_r )
829 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
832 if ( _d.size() == 1 )
835 // check installtime on multiple entries
838 for ( ; operator*(); operator++() ) {
839 if ( operator*()->tag_installtime() > itime ) {
841 itime = operator*()->tag_installtime();
845 return _d.set( match );
848 ///////////////////////////////////////////////////////////////////
851 // METHOD NAME : librpmDb::db_const_iterator::findPackage
852 // METHOD TYPE : bool
854 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r, const Edition & ed_r )
856 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
859 for ( ; operator*(); operator++() ) {
860 if ( ed_r == operator*()->tag_edition() ) {
861 int match = _d.offset();
862 return _d.set( match );
869 ///////////////////////////////////////////////////////////////////
872 // METHOD NAME : librpmDb::db_const_iterator::findPackage
873 // METHOD TYPE : bool
875 bool librpmDb::db_const_iterator::findPackage( const Package::constPtr & which_r )
880 return findPackage( which_r->name(), which_r->edition() );
884 } // namespace target