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 // should speed up convertdb and rebuilddb.
138 ::addMacro( NULL, "_rpmdb_rebuild", NULL, "%{nil}", RMIL_CMDLINE );
140 initialized = true; // Necessary to be able to use exand().
142 #define OUTVAL(n) << " (" #n ":" << expand( "%{" #n "}" ) << ")"
143 MIL << "librpm init done:"
151 ///////////////////////////////////////////////////////////////////
154 // METHOD NAME : librpmDb::expand
155 // METHOD TYPE : std::string
157 std::string librpmDb::expand( const std::string & macro_r )
159 if ( ! globalInit() )
160 return macro_r; // unexpanded
162 char * val = ::rpmExpand( macro_r.c_str(), NULL );
171 ///////////////////////////////////////////////////////////////////
174 // METHOD NAME : librpmDb::newLibrpmDb
175 // METHOD TYPE : librpmDb *
177 librpmDb * librpmDb::newLibrpmDb( Pathname root_r, Pathname dbPath_r, bool readonly_r )
180 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
182 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
186 if ( ! globalInit() )
188 ZYPP_THROW(GlobalRpmInitException());
195 ret = new librpmDb( root_r, dbPath_r, readonly_r );
197 catch (const RpmException & excpt_r)
199 ZYPP_CAUGHT(excpt_r);
202 ZYPP_RETHROW(excpt_r);
207 ///////////////////////////////////////////////////////////////////
210 // METHOD NAME : librpmDb::dbAccess
211 // METHOD TYPE : PMError
213 void librpmDb::dbAccess( const Pathname & root_r, const Pathname & dbPath_r )
216 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
218 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
223 // already accessing a database: switching is not allowed.
224 if ( _defaultRoot == root_r && _defaultDbPath == dbPath_r )
228 ZYPP_THROW(RpmDbAlreadyOpenException(_defaultRoot, _defaultDbPath, root_r, dbPath_r));
232 // got no database: we could switch to a new one (even if blocked!)
233 _defaultRoot = root_r;
234 _defaultDbPath = dbPath_r;
235 MIL << "Set new database location: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
240 ///////////////////////////////////////////////////////////////////
243 // METHOD NAME : librpmDb::dbAccess
244 // METHOD TYPE : PMError
246 void librpmDb::dbAccess()
250 ZYPP_THROW(RpmAccessBlockedException(_defaultRoot, _defaultDbPath));
256 _defaultDb = newLibrpmDb( _defaultRoot, _defaultDbPath, /*readonly*/true );
260 ///////////////////////////////////////////////////////////////////
263 // METHOD NAME : librpmDb::dbAccess
264 // METHOD TYPE : PMError
266 void librpmDb::dbAccess( librpmDb::constPtr & ptr_r )
272 catch (const RpmException & excpt_r)
274 ZYPP_CAUGHT(excpt_r);
276 ZYPP_RETHROW(excpt_r);
281 ///////////////////////////////////////////////////////////////////
284 // METHOD NAME : librpmDb::dbRelease
285 // METHOD TYPE : unsigned
287 unsigned librpmDb::dbRelease( bool force_r )
294 unsigned outstanding = _defaultDb->refCount() - 1; // refCount can't be 0
296 switch ( outstanding )
301 DBG << "dbRelease: keep access, outstanding " << outstanding << endl;
304 // else fall through:
306 DBG << "dbRelease: release" << (force_r && outstanding ? "(forced)" : "")
307 << ", outstanding " << outstanding << endl;
309 _defaultDb->_d._error = shared_ptr<RpmAccessBlockedException>(new RpmAccessBlockedException(_defaultDb->_d._root, _defaultDb->_d._dbPath));
310 // tag handle invalid
318 ///////////////////////////////////////////////////////////////////
321 // METHOD NAME : librpmDb::blockAccess
322 // METHOD TYPE : unsigned
324 unsigned librpmDb::blockAccess()
326 MIL << "Block access" << endl;
328 return dbRelease( /*force*/true );
331 ///////////////////////////////////////////////////////////////////
334 // METHOD NAME : librpmDb::unblockAccess
335 // METHOD TYPE : void
337 void librpmDb::unblockAccess()
339 MIL << "Unblock access" << endl;
343 ///////////////////////////////////////////////////////////////////
346 // METHOD NAME : librpmDb::dumpState
347 // METHOD TYPE : ostream &
349 ostream & librpmDb::dumpState( ostream & str )
353 return str << "[librpmDb " << (_dbBlocked?"BLOCKED":"CLOSED") << " " << stringPath( _defaultRoot, _defaultDbPath ) << "]";
355 return str << "[" << _defaultDb << "]";
358 ///////////////////////////////////////////////////////////////////
360 // CLASS NAME : librpmDb (internal database handle interface (nonstatic))
362 ///////////////////////////////////////////////////////////////////
364 ///////////////////////////////////////////////////////////////////
367 // METHOD NAME : librpmDb::librpmDb
368 // METHOD TYPE : Constructor
372 librpmDb::librpmDb( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
373 : _d( * new D( root_r, dbPath_r, readonly_r ) )
376 ///////////////////////////////////////////////////////////////////
379 // METHOD NAME : librpmDb::~librpmDb
380 // METHOD TYPE : Destructor
384 librpmDb::~librpmDb()
389 ///////////////////////////////////////////////////////////////////
392 // METHOD NAME : librpmDb::unref_to
393 // METHOD TYPE : void
395 void librpmDb::unref_to( unsigned refCount_r ) const
397 if ( refCount_r == 1 )
403 ///////////////////////////////////////////////////////////////////
406 // METHOD NAME : librpmDb::root
407 // METHOD TYPE : const Pathname &
409 const Pathname & librpmDb::root() const
414 ///////////////////////////////////////////////////////////////////
417 // METHOD NAME : librpmDb::dbPath
418 // METHOD TYPE : const Pathname &
420 const Pathname & librpmDb::dbPath() const
425 ///////////////////////////////////////////////////////////////////
428 // METHOD NAME : librpmDb::error
429 // METHOD TYPE : PMError
431 shared_ptr<RpmException> librpmDb::error() const
436 ///////////////////////////////////////////////////////////////////
439 // METHOD NAME : librpmDb::empty
440 // METHOD TYPE : bool
442 bool librpmDb::empty() const
444 return( valid() && ! *db_const_iterator( this ) );
447 ///////////////////////////////////////////////////////////////////
450 // METHOD NAME : librpmDb::size
451 // METHOD TYPE : unsigned
453 unsigned librpmDb::size() const
458 #ifdef _RPM_4_4_COMPAT
459 // looks like rpm-4.7 has no public dbi interface anymore
460 int dbi = ::rpmdbOpen("/", &_d._db, O_RDONLY, 0);
462 rpmdbMatchIterator mi = ::rpmdbInitIterator(_d._db, RPMTAG_NAME, NULL, 0);
466 Header rpmHeader = ::rpmdbNextIterator(mi);
467 if (rpmHeader != NULL)
471 ::rpmdbClose(_d._db);
474 dbiIndex dbi = dbiOpen( _d._db, RPMTAG_NAME, 0 );
478 dbiCopen( dbi, dbi->dbi_txnid, &dbcursor, 0 );
481 memset( &key, 0, sizeof(key) );
482 memset( &data, 0, sizeof(data) );
483 while ( dbiGet( dbi, dbcursor, &key, &data, DB_NEXT ) == 0 )
484 count += data.size / dbi->dbi_jlen;
486 dbiCclose( dbi, dbcursor, 0 );
487 /* no need to close dbi */
494 ///////////////////////////////////////////////////////////////////
497 // METHOD NAME : librpmDb::dont_call_it
498 // METHOD TYPE : void *
500 void * librpmDb::dont_call_it() const
505 ///////////////////////////////////////////////////////////////////
508 // METHOD NAME : librpmDb::dumpOn
509 // METHOD TYPE : ostream &
513 ostream & librpmDb::dumpOn( ostream & str ) const
515 ReferenceCounted::dumpOn( str ) << _d;
519 ///////////////////////////////////////////////////////////////////
521 // CLASS NAME : librpmDb::DbDirInfo
523 ///////////////////////////////////////////////////////////////////
525 ///////////////////////////////////////////////////////////////////
528 // METHOD NAME : librpmDb::DbDirInfo::DbDirInfo
529 // METHOD TYPE : Constructor
531 librpmDb::DbDirInfo::DbDirInfo( const Pathname & root_r, const Pathname & dbPath_r )
533 , _dbPath( dbPath_r )
535 // check and adjust arguments
536 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
538 ERR << "Relative path for root(" << _root << ") or dbPath(" << _dbPath << ")" << endl;
542 _dbDir ( _root + _dbPath );
543 _dbV4 ( _dbDir.path() + "Packages" );
544 _dbV3 ( _dbDir.path() + "packages.rpm" );
545 _dbV3ToV4( _dbDir.path() + "packages.rpm3" );
546 DBG << *this << endl;
550 ///////////////////////////////////////////////////////////////////
553 // METHOD NAME : librpmDb::DbDirInfo::update
554 // METHOD TYPE : void
556 void librpmDb::DbDirInfo::restat()
562 DBG << *this << endl;
565 /******************************************************************
568 ** FUNCTION NAME : operator<<
569 ** FUNCTION TYPE : std::ostream &
571 std::ostream & operator<<( std::ostream & str, const librpmDb::DbDirInfo & obj )
573 if ( obj.illegalArgs() )
575 str << "ILLEGAL: '(" << obj.root() << ")" << obj.dbPath() << "'";
579 str << "'(" << obj.root() << ")" << obj.dbPath() << "':" << endl;
580 str << " Dir: " << obj._dbDir << endl;
581 str << " V4: " << obj._dbV4 << endl;
582 str << " V3: " << obj._dbV3 << endl;
583 str << " V3ToV4: " << obj._dbV3ToV4;
588 ///////////////////////////////////////////////////////////////////
590 // CLASS NAME : librpmDb::db_const_iterator::D
594 class librpmDb::db_const_iterator::D
596 D & operator=( const D & ); // NO ASSIGNMENT!
597 D ( const D & ); // NO COPY!
600 librpmDb::constPtr _dbptr;
601 shared_ptr<RpmException> _dberr;
603 RpmHeader::constPtr _hptr;
604 rpmdbMatchIterator _mi;
606 D( librpmDb::constPtr dbptr_r )
614 librpmDb::dbAccess( _dbptr );
616 catch (const RpmException & excpt_r)
618 ZYPP_CAUGHT(excpt_r);
622 WAR << "No database access: " << _dberr << endl;
627 destroy(); // Checks whether _dbptr still valid
635 ::rpmdbFreeIterator( _mi );
640 * Let iterator access a dbindex file. Call @ref advance to access the
641 * 1st element (if present).
643 bool create( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
648 _mi = ::rpmdbInitIterator( _dbptr->_d._db, rpmTag(rpmtag), keyp, keylen );
653 * Destroy iterator. Invalidates _dbptr, if database was blocked meanwile.
654 * Always returns false.
660 _mi = ::rpmdbFreeIterator( _mi );
663 if ( _dbptr && _dbptr->error() )
665 _dberr = _dbptr->error();
666 WAR << "Lost database access: " << _dberr << endl;
673 * Advance to the first/next header in iterator. Destroys iterator if
674 * no more headers available.
680 Header h = ::rpmdbNextIterator( _mi );
686 _hptr = new RpmHeader( h );
691 * Access a dbindex file and advance to the 1st header.
693 bool init( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
695 if ( ! create( rpmtag, keyp, keylen ) )
701 * Create an itertator that contains the database entry located at
702 * off_r, and advance to the 1st header.
704 bool set( int off_r )
706 if ( ! create( RPMDBI_PACKAGES ) )
708 #warning TESTCASE: rpmdbAppendIterator and (non)sequential access?
709 ::rpmdbAppendIterator( _mi, &off_r, 1 );
715 return( _mi ? ::rpmdbGetIteratorOffset( _mi ) : 0 );
722 int ret = ::rpmdbGetIteratorCount( _mi );
723 #warning TESTCASE: rpmdbGetIteratorCount returns 0 on sequential access?
724 return( ret ? ret : -1 ); // -1: sequential access
728 ///////////////////////////////////////////////////////////////////
730 ///////////////////////////////////////////////////////////////////
732 // CLASS NAME : librpmDb::Ptr::db_const_iterator
734 ///////////////////////////////////////////////////////////////////
736 ///////////////////////////////////////////////////////////////////
739 // METHOD NAME : librpmDb::db_const_iterator::db_iterator
740 // METHOD TYPE : Constructor
742 librpmDb::db_const_iterator::db_const_iterator( librpmDb::constPtr dbptr_r )
743 : _d( * new D( dbptr_r ) )
748 ///////////////////////////////////////////////////////////////////
751 // METHOD NAME : librpmDb::db_const_iterator::~db_const_iterator
752 // METHOD TYPE : Destructor
754 librpmDb::db_const_iterator::~db_const_iterator()
759 ///////////////////////////////////////////////////////////////////
762 // METHOD NAME : librpmDb::db_const_iterator::operator++
763 // METHOD TYPE : void
765 void librpmDb::db_const_iterator::operator++()
770 ///////////////////////////////////////////////////////////////////
773 // METHOD NAME : librpmDb::db_const_iterator::dbHdrNum
774 // METHOD TYPE : unsigned
776 unsigned librpmDb::db_const_iterator::dbHdrNum() const
781 ///////////////////////////////////////////////////////////////////
784 // METHOD NAME : librpmDb::db_const_iterator::operator*
785 // METHOD TYPE : const RpmHeader::constPtr &
787 const RpmHeader::constPtr & librpmDb::db_const_iterator::operator*() const
792 ///////////////////////////////////////////////////////////////////
795 // METHOD NAME : librpmDb::db_const_iterator::dbError
796 // METHOD TYPE : PMError
798 shared_ptr<RpmException> librpmDb::db_const_iterator::dbError() const
801 return _d._dbptr->error();
806 /******************************************************************
809 ** FUNCTION NAME : operator<<
810 ** FUNCTION TYPE : ostream &
812 ostream & operator<<( ostream & str, const librpmDb::db_const_iterator & obj )
814 str << "db_const_iterator(" << obj._d._dbptr
815 << " Size:" << obj._d.size()
816 << " HdrNum:" << obj._d.offset()
821 ///////////////////////////////////////////////////////////////////
824 // METHOD NAME : librpmDb::db_const_iterator::findAll
825 // METHOD TYPE : bool
827 bool librpmDb::db_const_iterator::findAll()
829 return _d.init( RPMDBI_PACKAGES );
832 ///////////////////////////////////////////////////////////////////
835 // METHOD NAME : librpmDb::db_const_iterator::findByFile
836 // METHOD TYPE : bool
838 bool librpmDb::db_const_iterator::findByFile( const std::string & file_r )
840 return _d.init( RPMTAG_BASENAMES, file_r.c_str() );
843 ///////////////////////////////////////////////////////////////////
846 // METHOD NAME : librpmDb::db_const_iterator::findByProvides
847 // METHOD TYPE : bool
849 bool librpmDb::db_const_iterator::findByProvides( const std::string & tag_r )
851 return _d.init( RPMTAG_PROVIDENAME, tag_r.c_str() );
854 ///////////////////////////////////////////////////////////////////
857 // METHOD NAME : librpmDb::db_const_iterator::findByRequiredBy
858 // METHOD TYPE : bool
860 bool librpmDb::db_const_iterator::findByRequiredBy( const std::string & tag_r )
862 return _d.init( RPMTAG_REQUIRENAME, tag_r.c_str() );
865 ///////////////////////////////////////////////////////////////////
868 // METHOD NAME : librpmDb::db_const_iterator::findByConflicts
869 // METHOD TYPE : bool
871 bool librpmDb::db_const_iterator::findByConflicts( const std::string & tag_r )
873 return _d.init( RPMTAG_CONFLICTNAME, tag_r.c_str() );
876 ///////////////////////////////////////////////////////////////////
879 // METHOD NAME : librpmDb::findByName
880 // METHOD TYPE : bool
882 bool librpmDb::db_const_iterator::findByName( const string & name_r )
884 return _d.init( RPMTAG_NAME, name_r.c_str() );
887 ///////////////////////////////////////////////////////////////////
890 // METHOD NAME : librpmDb::db_const_iterator::findPackage
891 // METHOD TYPE : bool
893 bool librpmDb::db_const_iterator::findPackage( const string & name_r )
895 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
898 if ( _d.size() == 1 )
901 // check installtime on multiple entries
904 for ( ; operator*(); operator++() )
906 if ( operator*()->tag_installtime() > itime )
909 itime = operator*()->tag_installtime();
913 return _d.set( match );
916 ///////////////////////////////////////////////////////////////////
919 // METHOD NAME : librpmDb::db_const_iterator::findPackage
920 // METHOD TYPE : bool
922 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r, const Edition & ed_r )
924 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
927 for ( ; operator*(); operator++() )
929 if ( ed_r == operator*()->tag_edition() )
931 int match = _d.offset();
932 return _d.set( match );
939 ///////////////////////////////////////////////////////////////////
942 // METHOD NAME : librpmDb::db_const_iterator::findPackage
943 // METHOD TYPE : bool
945 bool librpmDb::db_const_iterator::findPackage( const Package::constPtr & which_r )
950 return findPackage( which_r->name(), which_r->edition() );
954 } // namespace target