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>
22 #undef ZYPP_BASE_LOGGER_LOGGROUP
23 #define ZYPP_BASE_LOGGER_LOGGROUP "librpmDb"
33 ///////////////////////////////////////////////////////////////////
35 // CLASS NAME : librpmDb::D
37 * @short librpmDb internal database handle
41 D & operator=( const D & ); // NO ASSIGNMENT!
42 D ( const D & ); // NO COPY!
45 const Pathname _root; // root directory for all operations
46 const Pathname _dbPath; // directory (below root) that contains the rpmdb
47 rpmts _ts; // transaction handle, includes database
48 shared_ptr<RpmException> _error; // database error
50 friend std::ostream & operator<<( std::ostream & str, const D & obj )
52 str << "{" << obj._error << "(" << obj._root << ")" << obj._dbPath << "}";
56 D( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
63 ::addMacro( NULL, "_dbpath", NULL, _dbPath.asString().c_str(), RMIL_CMDLINE );
65 _ts = ::rpmtsCreate();
66 ::rpmtsSetRootDir( _ts, _root.c_str() );
68 // open database (creates a missing one on the fly)
69 int res = ::rpmtsOpenDB( _ts, (readonly_r ? O_RDONLY : O_RDWR ));
72 ERR << "rpmdbOpen error(" << res << "): " << *this << endl;
73 _error = shared_ptr<RpmDbOpenException>(new RpmDbOpenException(_root, _dbPath));
79 DBG << "DBACCESS " << *this << endl;
91 ///////////////////////////////////////////////////////////////////
93 ///////////////////////////////////////////////////////////////////
95 // CLASS NAME : librpmDb (ststic interface)
97 ///////////////////////////////////////////////////////////////////
99 Pathname librpmDb::_defaultRoot ( "/" );
100 // NOTE: Former variable, but now locked to "/var/lib/rpm".
101 // A custom dbPath is not actually needed and would only work
102 // reliably if libsolv also supports it.
103 // The protected librpmDb ctor would allow to build a db_const_iterator
104 // to access (ro) a database at a custom location.
105 const Pathname librpmDb::_defaultDbPath( "/var/lib/rpm" );
106 librpmDb::constPtr librpmDb::_defaultDb;
107 bool librpmDb::_dbBlocked ( true );
109 ///////////////////////////////////////////////////////////////////
112 // METHOD NAME : librpmDb::globalInit
113 // METHOD TYPE : bool
115 bool librpmDb::globalInit()
117 static bool initialized = false;
122 int rc = ::rpmReadConfigFiles( NULL, NULL );
125 ERR << "rpmReadConfigFiles returned " << rc << endl;
129 initialized = true; // Necessary to be able to use exand().
131 #define OUTVAL(n) << " (" #n ":" << expand( "%{" #n "}" ) << ")"
132 MIL << "librpm init done:"
140 ///////////////////////////////////////////////////////////////////
143 // METHOD NAME : librpmDb::expand
144 // METHOD TYPE : std::string
146 std::string librpmDb::expand( const std::string & macro_r )
148 if ( ! globalInit() )
149 return macro_r; // unexpanded
151 char * val = ::rpmExpand( macro_r.c_str(), NULL );
155 std::string ret( val );
160 ///////////////////////////////////////////////////////////////////
163 // METHOD NAME : librpmDb::newLibrpmDb
164 // METHOD TYPE : librpmDb *
166 librpmDb * librpmDb::newLibrpmDb()
169 if ( ! globalInit() )
171 ZYPP_THROW(GlobalRpmInitException());
178 ret = new librpmDb( _defaultRoot, _defaultDbPath, /*readonly*/true );
180 catch (const RpmException & excpt_r)
182 ZYPP_CAUGHT(excpt_r);
185 ZYPP_RETHROW(excpt_r);
190 ///////////////////////////////////////////////////////////////////
193 // METHOD NAME : librpmDb::dbAccess
194 // METHOD TYPE : PMError
196 void librpmDb::dbAccess( const Pathname & root_r )
200 // already accessing a database: switching is not allowed.
201 if ( _defaultRoot == root_r )
204 ZYPP_THROW(RpmDbAlreadyOpenException(_defaultRoot, _defaultDbPath, root_r, _defaultDbPath));
207 // got no database: we could switch to a new one (even if blocked!)
209 if ( root_r.empty() || ! root_r.absolute() )
210 ZYPP_THROW(RpmInvalidRootException(root_r, _defaultDbPath));
212 PathInfo pi { root_r / _defaultDbPath };
213 if ( pi.isExist() && ! pi.isDir() ) {
214 RpmInvalidRootException excpt { root_r, _defaultDbPath };
215 excpt.addHistory( str::Str() << pi );
219 _defaultRoot = root_r;
220 MIL << "Set new database location: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
225 ///////////////////////////////////////////////////////////////////
228 // METHOD NAME : librpmDb::dbAccess
229 // METHOD TYPE : PMError
231 void librpmDb::dbAccess()
235 ZYPP_THROW(RpmAccessBlockedException(_defaultRoot, _defaultDbPath));
241 _defaultDb = newLibrpmDb();
245 ///////////////////////////////////////////////////////////////////
248 // METHOD NAME : librpmDb::dbAccess
249 // METHOD TYPE : PMError
251 void librpmDb::dbAccess( librpmDb::constPtr & ptr_r )
258 ///////////////////////////////////////////////////////////////////
261 // METHOD NAME : librpmDb::dbRelease
262 // METHOD TYPE : unsigned
264 unsigned librpmDb::dbRelease( bool force_r )
271 unsigned outstanding = _defaultDb->refCount() - 1; // refCount can't be 0
273 switch ( outstanding )
278 DBG << "dbRelease: keep access, outstanding " << outstanding << endl;
281 // else fall through:
283 DBG << "dbRelease: release" << (force_r && outstanding ? "(forced)" : "")
284 << ", outstanding " << outstanding << endl;
286 _defaultDb->_d._error = shared_ptr<RpmAccessBlockedException>(new RpmAccessBlockedException(_defaultDb->_d._root, _defaultDb->_d._dbPath));
287 // tag handle invalid
295 ///////////////////////////////////////////////////////////////////
298 // METHOD NAME : librpmDb::blockAccess
299 // METHOD TYPE : unsigned
301 unsigned librpmDb::blockAccess()
303 MIL << "Block access" << endl;
305 return dbRelease( /*force*/true );
308 ///////////////////////////////////////////////////////////////////
311 // METHOD NAME : librpmDb::unblockAccess
312 // METHOD TYPE : void
314 void librpmDb::unblockAccess()
316 MIL << "Unblock access" << endl;
320 ///////////////////////////////////////////////////////////////////
323 // METHOD NAME : librpmDb::dumpState
324 // METHOD TYPE : ostream &
326 std::ostream & librpmDb::dumpState( std::ostream & str )
330 return str << "[librpmDb " << (_dbBlocked?"BLOCKED":"CLOSED") << " " << stringPath( _defaultRoot, _defaultDbPath ) << "]";
332 return str << "[" << _defaultDb << "]";
335 ///////////////////////////////////////////////////////////////////
337 // CLASS NAME : librpmDb (internal database handle interface (nonstatic))
339 ///////////////////////////////////////////////////////////////////
341 ///////////////////////////////////////////////////////////////////
344 // METHOD NAME : librpmDb::librpmDb
345 // METHOD TYPE : Constructor
349 librpmDb::librpmDb( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
350 : _d( * new D( root_r, dbPath_r, readonly_r ) )
353 ///////////////////////////////////////////////////////////////////
356 // METHOD NAME : librpmDb::~librpmDb
357 // METHOD TYPE : Destructor
361 librpmDb::~librpmDb()
366 ///////////////////////////////////////////////////////////////////
369 // METHOD NAME : librpmDb::unref_to
370 // METHOD TYPE : void
372 void librpmDb::unref_to( unsigned refCount_r ) const
374 if ( refCount_r == 1 )
380 ///////////////////////////////////////////////////////////////////
383 // METHOD NAME : librpmDb::root
384 // METHOD TYPE : const Pathname &
386 const Pathname & librpmDb::root() const
391 ///////////////////////////////////////////////////////////////////
394 // METHOD NAME : librpmDb::dbPath
395 // METHOD TYPE : const Pathname &
397 const Pathname & librpmDb::dbPath() const
402 ///////////////////////////////////////////////////////////////////
405 // METHOD NAME : librpmDb::error
406 // METHOD TYPE : PMError
408 shared_ptr<RpmException> librpmDb::error() const
413 ///////////////////////////////////////////////////////////////////
416 // METHOD NAME : librpmDb::empty
417 // METHOD TYPE : bool
419 bool librpmDb::empty() const
421 return( valid() && ! *db_const_iterator( this ) );
424 ///////////////////////////////////////////////////////////////////
427 // METHOD NAME : librpmDb::size
428 // METHOD TYPE : unsigned
430 unsigned librpmDb::size() const
435 db_const_iterator it( this );
436 for ( db_const_iterator it( this ); *it; ++it )
442 ///////////////////////////////////////////////////////////////////
445 // METHOD NAME : librpmDb::dont_call_it
446 // METHOD TYPE : void *
448 void * librpmDb::dont_call_it() const
450 return rpmtsGetRdb(_d._ts);
453 ///////////////////////////////////////////////////////////////////
456 // METHOD NAME : librpmDb::dumpOn
457 // METHOD TYPE : ostream &
461 std::ostream & librpmDb::dumpOn( std::ostream & str ) const
463 ReferenceCounted::dumpOn( str ) << _d;
467 ///////////////////////////////////////////////////////////////////
469 // CLASS NAME : librpmDb::db_const_iterator::D
473 class librpmDb::db_const_iterator::D
475 D & operator=( const D & ); // NO ASSIGNMENT!
476 D ( const D & ); // NO COPY!
479 librpmDb::constPtr _dbptr;
480 shared_ptr<RpmException> _dberr;
482 RpmHeader::constPtr _hptr;
483 rpmdbMatchIterator _mi;
485 D( librpmDb::constPtr dbptr_r )
493 librpmDb::dbAccess( _dbptr );
495 catch (const RpmException & excpt_r)
497 ZYPP_CAUGHT(excpt_r);
501 WAR << "No database access: " << _dberr << endl;
506 destroy(); // Checks whether _dbptr still valid
514 ::rpmdbFreeIterator( _mi );
519 * Let iterator access a dbindex file. Call @ref advance to access the
520 * 1st element (if present).
522 bool create( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
527 _mi = ::rpmtsInitIterator( _dbptr->_d._ts, rpmTag(rpmtag), keyp, keylen );
532 * Destroy iterator. Invalidates _dbptr, if database was blocked meanwile.
533 * Always returns false.
539 _mi = ::rpmdbFreeIterator( _mi );
542 if ( _dbptr && _dbptr->error() )
544 _dberr = _dbptr->error();
545 WAR << "Lost database access: " << _dberr << endl;
552 * Advance to the first/next header in iterator. Destroys iterator if
553 * no more headers available.
559 Header h = ::rpmdbNextIterator( _mi );
565 _hptr = new RpmHeader( h );
570 * Access a dbindex file and advance to the 1st header.
572 bool init( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
574 if ( ! create( rpmtag, keyp, keylen ) )
580 * Create an itertator that contains the database entry located at
581 * off_r, and advance to the 1st header.
583 bool set( int off_r )
585 if ( ! create( RPMDBI_PACKAGES ) )
587 #warning TESTCASE: rpmdbAppendIterator and (non)sequential access?
588 #ifdef RPMFILEITERMAX // since rpm.4.12
589 ::rpmdbAppendIterator( _mi, (const unsigned *)&off_r, 1 );
591 ::rpmdbAppendIterator( _mi, &off_r, 1 );
598 return( _mi ? ::rpmdbGetIteratorOffset( _mi ) : 0 );
605 int ret = ::rpmdbGetIteratorCount( _mi );
606 #warning TESTCASE: rpmdbGetIteratorCount returns 0 on sequential access?
607 return( ret ? ret : -1 ); // -1: sequential access
611 ///////////////////////////////////////////////////////////////////
613 ///////////////////////////////////////////////////////////////////
615 // CLASS NAME : librpmDb::Ptr::db_const_iterator
617 ///////////////////////////////////////////////////////////////////
619 ///////////////////////////////////////////////////////////////////
622 // METHOD NAME : librpmDb::db_const_iterator::db_iterator
623 // METHOD TYPE : Constructor
625 librpmDb::db_const_iterator::db_const_iterator( librpmDb::constPtr dbptr_r )
626 : _d( * new D( dbptr_r ) )
631 ///////////////////////////////////////////////////////////////////
634 // METHOD NAME : librpmDb::db_const_iterator::~db_const_iterator
635 // METHOD TYPE : Destructor
637 librpmDb::db_const_iterator::~db_const_iterator()
642 ///////////////////////////////////////////////////////////////////
645 // METHOD NAME : librpmDb::db_const_iterator::operator++
646 // METHOD TYPE : void
648 void librpmDb::db_const_iterator::operator++()
653 ///////////////////////////////////////////////////////////////////
656 // METHOD NAME : librpmDb::db_const_iterator::dbHdrNum
657 // METHOD TYPE : unsigned
659 unsigned librpmDb::db_const_iterator::dbHdrNum() const
664 ///////////////////////////////////////////////////////////////////
667 // METHOD NAME : librpmDb::db_const_iterator::operator*
668 // METHOD TYPE : const RpmHeader::constPtr &
670 const RpmHeader::constPtr & librpmDb::db_const_iterator::operator*() const
675 ///////////////////////////////////////////////////////////////////
678 // METHOD NAME : librpmDb::db_const_iterator::dbError
679 // METHOD TYPE : PMError
681 shared_ptr<RpmException> librpmDb::db_const_iterator::dbError() const
684 return _d._dbptr->error();
689 /******************************************************************
692 ** FUNCTION NAME : operator<<
693 ** FUNCTION TYPE : ostream &
695 std::ostream & operator<<( std::ostream & str, const librpmDb::db_const_iterator & obj )
697 str << "db_const_iterator(" << obj._d._dbptr
698 << " Size:" << obj._d.size()
699 << " HdrNum:" << obj._d.offset()
704 ///////////////////////////////////////////////////////////////////
707 // METHOD NAME : librpmDb::db_const_iterator::findAll
708 // METHOD TYPE : bool
710 bool librpmDb::db_const_iterator::findAll()
712 return _d.init( RPMDBI_PACKAGES );
715 ///////////////////////////////////////////////////////////////////
718 // METHOD NAME : librpmDb::db_const_iterator::findByFile
719 // METHOD TYPE : bool
721 bool librpmDb::db_const_iterator::findByFile( const std::string & file_r )
723 return _d.init( RPMTAG_BASENAMES, file_r.c_str() );
726 ///////////////////////////////////////////////////////////////////
729 // METHOD NAME : librpmDb::db_const_iterator::findByProvides
730 // METHOD TYPE : bool
732 bool librpmDb::db_const_iterator::findByProvides( const std::string & tag_r )
734 return _d.init( RPMTAG_PROVIDENAME, tag_r.c_str() );
737 ///////////////////////////////////////////////////////////////////
740 // METHOD NAME : librpmDb::db_const_iterator::findByRequiredBy
741 // METHOD TYPE : bool
743 bool librpmDb::db_const_iterator::findByRequiredBy( const std::string & tag_r )
745 return _d.init( RPMTAG_REQUIRENAME, tag_r.c_str() );
748 ///////////////////////////////////////////////////////////////////
751 // METHOD NAME : librpmDb::db_const_iterator::findByConflicts
752 // METHOD TYPE : bool
754 bool librpmDb::db_const_iterator::findByConflicts( const std::string & tag_r )
756 return _d.init( RPMTAG_CONFLICTNAME, tag_r.c_str() );
759 ///////////////////////////////////////////////////////////////////
762 // METHOD NAME : librpmDb::findByName
763 // METHOD TYPE : bool
765 bool librpmDb::db_const_iterator::findByName( const std::string & name_r )
767 return _d.init( RPMTAG_NAME, name_r.c_str() );
770 ///////////////////////////////////////////////////////////////////
773 // METHOD NAME : librpmDb::db_const_iterator::findPackage
774 // METHOD TYPE : bool
776 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r )
778 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
781 if ( _d.size() == 1 )
784 // check installtime on multiple entries
787 for ( ; operator*(); operator++() )
789 if ( operator*()->tag_installtime() > itime )
792 itime = operator*()->tag_installtime();
796 return _d.set( match );
799 ///////////////////////////////////////////////////////////////////
802 // METHOD NAME : librpmDb::db_const_iterator::findPackage
803 // METHOD TYPE : bool
805 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r, const Edition & ed_r )
807 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
810 for ( ; operator*(); operator++() )
812 if ( ed_r == operator*()->tag_edition() )
814 int match = _d.offset();
815 return _d.set( match );
822 ///////////////////////////////////////////////////////////////////
825 // METHOD NAME : librpmDb::db_const_iterator::findPackage
826 // METHOD TYPE : bool
828 bool librpmDb::db_const_iterator::findPackage( const Package::constPtr & which_r )
833 return findPackage( which_r->name(), which_r->edition() );
837 } // namespace target