1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/target/rpm/librpmDb.cc
16 #include "zypp/base/Logger.h"
17 #include "zypp/PathInfo.h"
18 #include "zypp/target/rpm/librpmDb.h"
19 #include "zypp/target/rpm/RpmHeader.h"
20 #include "zypp/target/rpm/RpmException.h"
30 ///////////////////////////////////////////////////////////////////
32 // CLASS NAME : librpmDb::D
34 * @short librpmDb internal database handle
38 D & operator=( const D & ); // NO ASSIGNMENT!
39 D ( const D & ); // NO COPY!
42 const Pathname _root; // root directory for all operations
43 const Pathname _dbPath; // directory (below root) that contains the rpmdb
44 rpmts _ts; // transaction handle, includes database
45 shared_ptr<RpmException> _error; // database error
47 friend ostream & operator<<( ostream & str, const D & obj )
49 str << "{" << obj._error << "(" << obj._root << ")" << obj._dbPath << "}";
53 D( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
60 ::addMacro( NULL, "_dbpath", NULL, _dbPath.asString().c_str(), RMIL_CMDLINE );
62 _ts = ::rpmtsCreate();
63 ::rpmtsSetRootDir( _ts, _root.c_str() );
65 // check whether to create a new db
66 PathInfo master( _root + _dbPath + "Packages" );
67 if ( ! master.isFile() )
70 if ( filesystem::assert_dir(_root + _dbPath) != 0 )
72 ERR << "Could not create dbpath " << (_root + _dbPath).asString() << endl;
73 _error = shared_ptr<RpmInitException>(new RpmInitException(_root, _dbPath));
76 int res = ::rpmtsInitDB( _ts, 0644 );
79 ERR << "rpmdbInit error(" << res << "): " << *this << endl;
80 _error = shared_ptr<RpmInitException>(new RpmInitException(_root, _dbPath));
87 int res = ::rpmtsOpenDB( _ts, (readonly_r ? O_RDONLY : O_RDWR ));
90 ERR << "rpmdbOpen error(" << res << "): " << *this << endl;
91 _error = shared_ptr<RpmDbOpenException>(new RpmDbOpenException(_root, _dbPath));
97 DBG << "DBACCESS " << *this << endl;
109 ///////////////////////////////////////////////////////////////////
111 ///////////////////////////////////////////////////////////////////
113 // CLASS NAME : librpmDb (ststic interface)
115 ///////////////////////////////////////////////////////////////////
117 Pathname librpmDb::_defaultRoot ( "/" );
118 Pathname librpmDb::_defaultDbPath( "/var/lib/rpm" );
119 librpmDb::constPtr librpmDb::_defaultDb;
120 bool librpmDb::_dbBlocked ( true );
122 ///////////////////////////////////////////////////////////////////
125 // METHOD NAME : librpmDb::globalInit
126 // METHOD TYPE : bool
128 bool librpmDb::globalInit()
130 static bool initialized = false;
135 int rc = ::rpmReadConfigFiles( NULL, NULL );
138 ERR << "rpmReadConfigFiles returned " << rc << endl;
142 initialized = true; // Necessary to be able to use exand().
144 #define OUTVAL(n) << " (" #n ":" << expand( "%{" #n "}" ) << ")"
145 MIL << "librpm init done:"
153 ///////////////////////////////////////////////////////////////////
156 // METHOD NAME : librpmDb::expand
157 // METHOD TYPE : std::string
159 std::string librpmDb::expand( const std::string & macro_r )
161 if ( ! globalInit() )
162 return macro_r; // unexpanded
164 char * val = ::rpmExpand( macro_r.c_str(), NULL );
173 ///////////////////////////////////////////////////////////////////
176 // METHOD NAME : librpmDb::newLibrpmDb
177 // METHOD TYPE : librpmDb *
179 librpmDb * librpmDb::newLibrpmDb( Pathname root_r, Pathname dbPath_r, bool readonly_r )
182 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
184 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
188 if ( ! globalInit() )
190 ZYPP_THROW(GlobalRpmInitException());
197 ret = new librpmDb( root_r, dbPath_r, readonly_r );
199 catch (const RpmException & excpt_r)
201 ZYPP_CAUGHT(excpt_r);
204 ZYPP_RETHROW(excpt_r);
209 ///////////////////////////////////////////////////////////////////
212 // METHOD NAME : librpmDb::dbAccess
213 // METHOD TYPE : PMError
215 void librpmDb::dbAccess( const Pathname & root_r, const Pathname & dbPath_r )
218 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
220 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
225 // already accessing a database: switching is not allowed.
226 if ( _defaultRoot == root_r && _defaultDbPath == dbPath_r )
230 ZYPP_THROW(RpmDbAlreadyOpenException(_defaultRoot, _defaultDbPath, root_r, dbPath_r));
234 // got no database: we could switch to a new one (even if blocked!)
235 _defaultRoot = root_r;
236 _defaultDbPath = dbPath_r;
237 MIL << "Set new database location: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
242 ///////////////////////////////////////////////////////////////////
245 // METHOD NAME : librpmDb::dbAccess
246 // METHOD TYPE : PMError
248 void librpmDb::dbAccess()
252 ZYPP_THROW(RpmAccessBlockedException(_defaultRoot, _defaultDbPath));
258 _defaultDb = newLibrpmDb( _defaultRoot, _defaultDbPath, /*readonly*/true );
262 ///////////////////////////////////////////////////////////////////
265 // METHOD NAME : librpmDb::dbAccess
266 // METHOD TYPE : PMError
268 void librpmDb::dbAccess( librpmDb::constPtr & ptr_r )
274 catch (const RpmException & excpt_r)
276 ZYPP_CAUGHT(excpt_r);
278 ZYPP_RETHROW(excpt_r);
283 ///////////////////////////////////////////////////////////////////
286 // METHOD NAME : librpmDb::dbRelease
287 // METHOD TYPE : unsigned
289 unsigned librpmDb::dbRelease( bool force_r )
296 unsigned outstanding = _defaultDb->refCount() - 1; // refCount can't be 0
298 switch ( outstanding )
303 DBG << "dbRelease: keep access, outstanding " << outstanding << endl;
306 // else fall through:
308 DBG << "dbRelease: release" << (force_r && outstanding ? "(forced)" : "")
309 << ", outstanding " << outstanding << endl;
311 _defaultDb->_d._error = shared_ptr<RpmAccessBlockedException>(new RpmAccessBlockedException(_defaultDb->_d._root, _defaultDb->_d._dbPath));
312 // tag handle invalid
320 ///////////////////////////////////////////////////////////////////
323 // METHOD NAME : librpmDb::blockAccess
324 // METHOD TYPE : unsigned
326 unsigned librpmDb::blockAccess()
328 MIL << "Block access" << endl;
330 return dbRelease( /*force*/true );
333 ///////////////////////////////////////////////////////////////////
336 // METHOD NAME : librpmDb::unblockAccess
337 // METHOD TYPE : void
339 void librpmDb::unblockAccess()
341 MIL << "Unblock access" << endl;
345 ///////////////////////////////////////////////////////////////////
348 // METHOD NAME : librpmDb::dumpState
349 // METHOD TYPE : ostream &
351 ostream & librpmDb::dumpState( ostream & str )
355 return str << "[librpmDb " << (_dbBlocked?"BLOCKED":"CLOSED") << " " << stringPath( _defaultRoot, _defaultDbPath ) << "]";
357 return str << "[" << _defaultDb << "]";
360 ///////////////////////////////////////////////////////////////////
362 // CLASS NAME : librpmDb (internal database handle interface (nonstatic))
364 ///////////////////////////////////////////////////////////////////
366 ///////////////////////////////////////////////////////////////////
369 // METHOD NAME : librpmDb::librpmDb
370 // METHOD TYPE : Constructor
374 librpmDb::librpmDb( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
375 : _d( * new D( root_r, dbPath_r, readonly_r ) )
378 ///////////////////////////////////////////////////////////////////
381 // METHOD NAME : librpmDb::~librpmDb
382 // METHOD TYPE : Destructor
386 librpmDb::~librpmDb()
391 ///////////////////////////////////////////////////////////////////
394 // METHOD NAME : librpmDb::unref_to
395 // METHOD TYPE : void
397 void librpmDb::unref_to( unsigned refCount_r ) const
399 if ( refCount_r == 1 )
405 ///////////////////////////////////////////////////////////////////
408 // METHOD NAME : librpmDb::root
409 // METHOD TYPE : const Pathname &
411 const Pathname & librpmDb::root() const
416 ///////////////////////////////////////////////////////////////////
419 // METHOD NAME : librpmDb::dbPath
420 // METHOD TYPE : const Pathname &
422 const Pathname & librpmDb::dbPath() const
427 ///////////////////////////////////////////////////////////////////
430 // METHOD NAME : librpmDb::error
431 // METHOD TYPE : PMError
433 shared_ptr<RpmException> librpmDb::error() const
438 ///////////////////////////////////////////////////////////////////
441 // METHOD NAME : librpmDb::empty
442 // METHOD TYPE : bool
444 bool librpmDb::empty() const
446 return( valid() && ! *db_const_iterator( this ) );
449 ///////////////////////////////////////////////////////////////////
452 // METHOD NAME : librpmDb::size
453 // METHOD TYPE : unsigned
455 unsigned librpmDb::size() const
460 db_const_iterator it( this );
461 for ( db_const_iterator it( this ); *it; ++it )
467 ///////////////////////////////////////////////////////////////////
470 // METHOD NAME : librpmDb::dont_call_it
471 // METHOD TYPE : void *
473 void * librpmDb::dont_call_it() const
475 return rpmtsGetRdb(_d._ts);
478 ///////////////////////////////////////////////////////////////////
481 // METHOD NAME : librpmDb::dumpOn
482 // METHOD TYPE : ostream &
486 ostream & librpmDb::dumpOn( ostream & str ) const
488 ReferenceCounted::dumpOn( str ) << _d;
492 ///////////////////////////////////////////////////////////////////
494 // CLASS NAME : librpmDb::DbDirInfo
496 ///////////////////////////////////////////////////////////////////
498 ///////////////////////////////////////////////////////////////////
501 // METHOD NAME : librpmDb::DbDirInfo::DbDirInfo
502 // METHOD TYPE : Constructor
504 librpmDb::DbDirInfo::DbDirInfo( const Pathname & root_r, const Pathname & dbPath_r )
506 , _dbPath( dbPath_r )
508 // check and adjust arguments
509 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
511 ERR << "Relative path for root(" << _root << ") or dbPath(" << _dbPath << ")" << endl;
515 _dbDir ( _root + _dbPath );
516 _dbV4 ( _dbDir.path() + "Packages" );
517 _dbV3 ( _dbDir.path() + "packages.rpm" );
518 _dbV3ToV4( _dbDir.path() + "packages.rpm3" );
519 DBG << *this << endl;
523 ///////////////////////////////////////////////////////////////////
526 // METHOD NAME : librpmDb::DbDirInfo::update
527 // METHOD TYPE : void
529 void librpmDb::DbDirInfo::restat()
535 DBG << *this << endl;
538 /******************************************************************
541 ** FUNCTION NAME : operator<<
542 ** FUNCTION TYPE : std::ostream &
544 std::ostream & operator<<( std::ostream & str, const librpmDb::DbDirInfo & obj )
546 if ( obj.illegalArgs() )
548 str << "ILLEGAL: '(" << obj.root() << ")" << obj.dbPath() << "'";
552 str << "'(" << obj.root() << ")" << obj.dbPath() << "':" << endl;
553 str << " Dir: " << obj._dbDir << endl;
554 str << " V4: " << obj._dbV4 << endl;
555 str << " V3: " << obj._dbV3 << endl;
556 str << " V3ToV4: " << obj._dbV3ToV4;
561 ///////////////////////////////////////////////////////////////////
563 // CLASS NAME : librpmDb::db_const_iterator::D
567 class librpmDb::db_const_iterator::D
569 D & operator=( const D & ); // NO ASSIGNMENT!
570 D ( const D & ); // NO COPY!
573 librpmDb::constPtr _dbptr;
574 shared_ptr<RpmException> _dberr;
576 RpmHeader::constPtr _hptr;
577 rpmdbMatchIterator _mi;
579 D( librpmDb::constPtr dbptr_r )
587 librpmDb::dbAccess( _dbptr );
589 catch (const RpmException & excpt_r)
591 ZYPP_CAUGHT(excpt_r);
595 WAR << "No database access: " << _dberr << endl;
600 destroy(); // Checks whether _dbptr still valid
608 ::rpmdbFreeIterator( _mi );
613 * Let iterator access a dbindex file. Call @ref advance to access the
614 * 1st element (if present).
616 bool create( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
621 _mi = ::rpmtsInitIterator( _dbptr->_d._ts, rpmTag(rpmtag), keyp, keylen );
626 * Destroy iterator. Invalidates _dbptr, if database was blocked meanwile.
627 * Always returns false.
633 _mi = ::rpmdbFreeIterator( _mi );
636 if ( _dbptr && _dbptr->error() )
638 _dberr = _dbptr->error();
639 WAR << "Lost database access: " << _dberr << endl;
646 * Advance to the first/next header in iterator. Destroys iterator if
647 * no more headers available.
653 Header h = ::rpmdbNextIterator( _mi );
659 _hptr = new RpmHeader( h );
664 * Access a dbindex file and advance to the 1st header.
666 bool init( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
668 if ( ! create( rpmtag, keyp, keylen ) )
674 * Create an itertator that contains the database entry located at
675 * off_r, and advance to the 1st header.
677 bool set( int off_r )
679 if ( ! create( RPMDBI_PACKAGES ) )
681 #warning TESTCASE: rpmdbAppendIterator and (non)sequential access?
682 #ifdef RPMFILEITERMAX // since rpm.4.12
683 ::rpmdbAppendIterator( _mi, (const unsigned *)&off_r, 1 );
685 ::rpmdbAppendIterator( _mi, &off_r, 1 );
692 return( _mi ? ::rpmdbGetIteratorOffset( _mi ) : 0 );
699 int ret = ::rpmdbGetIteratorCount( _mi );
700 #warning TESTCASE: rpmdbGetIteratorCount returns 0 on sequential access?
701 return( ret ? ret : -1 ); // -1: sequential access
705 ///////////////////////////////////////////////////////////////////
707 ///////////////////////////////////////////////////////////////////
709 // CLASS NAME : librpmDb::Ptr::db_const_iterator
711 ///////////////////////////////////////////////////////////////////
713 ///////////////////////////////////////////////////////////////////
716 // METHOD NAME : librpmDb::db_const_iterator::db_iterator
717 // METHOD TYPE : Constructor
719 librpmDb::db_const_iterator::db_const_iterator( librpmDb::constPtr dbptr_r )
720 : _d( * new D( dbptr_r ) )
725 ///////////////////////////////////////////////////////////////////
728 // METHOD NAME : librpmDb::db_const_iterator::~db_const_iterator
729 // METHOD TYPE : Destructor
731 librpmDb::db_const_iterator::~db_const_iterator()
736 ///////////////////////////////////////////////////////////////////
739 // METHOD NAME : librpmDb::db_const_iterator::operator++
740 // METHOD TYPE : void
742 void librpmDb::db_const_iterator::operator++()
747 ///////////////////////////////////////////////////////////////////
750 // METHOD NAME : librpmDb::db_const_iterator::dbHdrNum
751 // METHOD TYPE : unsigned
753 unsigned librpmDb::db_const_iterator::dbHdrNum() const
758 ///////////////////////////////////////////////////////////////////
761 // METHOD NAME : librpmDb::db_const_iterator::operator*
762 // METHOD TYPE : const RpmHeader::constPtr &
764 const RpmHeader::constPtr & librpmDb::db_const_iterator::operator*() const
769 ///////////////////////////////////////////////////////////////////
772 // METHOD NAME : librpmDb::db_const_iterator::dbError
773 // METHOD TYPE : PMError
775 shared_ptr<RpmException> librpmDb::db_const_iterator::dbError() const
778 return _d._dbptr->error();
783 /******************************************************************
786 ** FUNCTION NAME : operator<<
787 ** FUNCTION TYPE : ostream &
789 ostream & operator<<( ostream & str, const librpmDb::db_const_iterator & obj )
791 str << "db_const_iterator(" << obj._d._dbptr
792 << " Size:" << obj._d.size()
793 << " HdrNum:" << obj._d.offset()
798 ///////////////////////////////////////////////////////////////////
801 // METHOD NAME : librpmDb::db_const_iterator::findAll
802 // METHOD TYPE : bool
804 bool librpmDb::db_const_iterator::findAll()
806 return _d.init( RPMDBI_PACKAGES );
809 ///////////////////////////////////////////////////////////////////
812 // METHOD NAME : librpmDb::db_const_iterator::findByFile
813 // METHOD TYPE : bool
815 bool librpmDb::db_const_iterator::findByFile( const std::string & file_r )
817 return _d.init( RPMTAG_BASENAMES, file_r.c_str() );
820 ///////////////////////////////////////////////////////////////////
823 // METHOD NAME : librpmDb::db_const_iterator::findByProvides
824 // METHOD TYPE : bool
826 bool librpmDb::db_const_iterator::findByProvides( const std::string & tag_r )
828 return _d.init( RPMTAG_PROVIDENAME, tag_r.c_str() );
831 ///////////////////////////////////////////////////////////////////
834 // METHOD NAME : librpmDb::db_const_iterator::findByRequiredBy
835 // METHOD TYPE : bool
837 bool librpmDb::db_const_iterator::findByRequiredBy( const std::string & tag_r )
839 return _d.init( RPMTAG_REQUIRENAME, tag_r.c_str() );
842 ///////////////////////////////////////////////////////////////////
845 // METHOD NAME : librpmDb::db_const_iterator::findByConflicts
846 // METHOD TYPE : bool
848 bool librpmDb::db_const_iterator::findByConflicts( const std::string & tag_r )
850 return _d.init( RPMTAG_CONFLICTNAME, tag_r.c_str() );
853 ///////////////////////////////////////////////////////////////////
856 // METHOD NAME : librpmDb::findByName
857 // METHOD TYPE : bool
859 bool librpmDb::db_const_iterator::findByName( const string & name_r )
861 return _d.init( RPMTAG_NAME, name_r.c_str() );
864 ///////////////////////////////////////////////////////////////////
867 // METHOD NAME : librpmDb::db_const_iterator::findPackage
868 // METHOD TYPE : bool
870 bool librpmDb::db_const_iterator::findPackage( const string & name_r )
872 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
875 if ( _d.size() == 1 )
878 // check installtime on multiple entries
881 for ( ; operator*(); operator++() )
883 if ( operator*()->tag_installtime() > itime )
886 itime = operator*()->tag_installtime();
890 return _d.set( match );
893 ///////////////////////////////////////////////////////////////////
896 // METHOD NAME : librpmDb::db_const_iterator::findPackage
897 // METHOD TYPE : bool
899 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r, const Edition & ed_r )
901 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
904 for ( ; operator*(); operator++() )
906 if ( ed_r == operator*()->tag_edition() )
908 int match = _d.offset();
909 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 Package::constPtr & which_r )
927 return findPackage( which_r->name(), which_r->edition() );
931 } // namespace target