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 Pathname librpmDb::_defaultDbPath; // set in dbAccess depending on suggestedDbPath below /root
101 Pathname librpmDb::_rpmDefaultDbPath; // set by globalInit
102 librpmDb::constPtr librpmDb::_defaultDb;
103 bool librpmDb::_dbBlocked = true;
105 ///////////////////////////////////////////////////////////////////
108 // METHOD NAME : librpmDb::globalInit
109 // METHOD TYPE : bool
111 bool librpmDb::globalInit()
113 static bool initialized = false;
118 int rc = ::rpmReadConfigFiles( NULL, NULL );
121 ERR << "rpmReadConfigFiles returned " << rc << endl;
125 initialized = true; // Necessary to be able to use exand().
126 _rpmDefaultDbPath = expand( "%{_dbpath}" );
128 if ( _rpmDefaultDbPath.empty() ) {
129 _rpmDefaultDbPath = "/usr/lib/sysimage/";
130 WAR << "Looks like rpm has no %{_dbpath} set!?! Assuming " << _rpmDefaultDbPath << endl;
132 MIL << "librpm init done: (_target:" << expand( "%{_target}" ) << ") (_dbpath:" << _rpmDefaultDbPath << ")" << endl;
136 ///////////////////////////////////////////////////////////////////
139 // METHOD NAME : librpmDb::expand
140 // METHOD TYPE : std::string
142 std::string librpmDb::expand( const std::string & macro_r )
144 if ( ! globalInit() )
145 return macro_r; // unexpanded
147 char * val = ::rpmExpand( macro_r.c_str(), NULL );
151 std::string ret( val );
156 ///////////////////////////////////////////////////////////////////
159 // METHOD NAME : librpmDb::newLibrpmDb
160 // METHOD TYPE : librpmDb *
162 librpmDb * librpmDb::newLibrpmDb()
165 if ( ! globalInit() )
167 ZYPP_THROW(GlobalRpmInitException());
170 if ( _defaultDbPath.empty() ) // db_const_iterator access to /(default) without RpmDB/Tareget init.
171 _defaultDbPath = suggestedDbPath( _defaultRoot );
177 ret = new librpmDb( _defaultRoot, _defaultDbPath, /*readonly*/true );
179 catch (const RpmException & excpt_r)
181 ZYPP_CAUGHT(excpt_r);
184 ZYPP_RETHROW(excpt_r);
190 Pathname librpmDb::suggestedDbPath( const Pathname & root_r )
192 if ( ! root_r.absolute() )
193 ZYPP_THROW(RpmInvalidRootException( root_r, "" ));
195 // initialize librpm (for _rpmDefaultDbPath)
196 if ( ! globalInit() )
197 ZYPP_THROW(GlobalRpmInitException());
199 if ( PathInfo( root_r ).isDir() ) {
200 // If a known dbpath exsists, we continue to use it
201 for ( auto p : { "/var/lib/rpm", "/usr/lib/sysimage/rpm" } ) {
202 if ( PathInfo( root_r/p, PathInfo::LSTAT/*!no symlink*/ ).isDir() ) {
203 MIL << "Suggest existing database at " << stringPath( root_r, p ) << endl;
209 MIL << "Suggest rpm _dbpath " << stringPath( root_r, _rpmDefaultDbPath ) << endl;
210 return _rpmDefaultDbPath;
213 ///////////////////////////////////////////////////////////////////
216 // METHOD NAME : librpmDb::dbAccess
217 // METHOD TYPE : PMError
219 void librpmDb::dbAccess( const Pathname & root_r )
223 // already accessing a database: switching is not allowed.
224 if ( _defaultRoot == root_r )
227 ZYPP_THROW(RpmDbAlreadyOpenException(_defaultRoot, _defaultDbPath, root_r, _defaultDbPath));
230 // got no database: we could switch to a new one (even if blocked!)
231 _defaultDbPath = suggestedDbPath( root_r ); // also asserts root_r is absolute
232 _defaultRoot = root_r;
234 MIL << "Set new database location: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
238 ///////////////////////////////////////////////////////////////////
241 // METHOD NAME : librpmDb::dbAccess
242 // METHOD TYPE : PMError
244 void librpmDb::dbAccess()
248 ZYPP_THROW(RpmAccessBlockedException(_defaultRoot, _defaultDbPath));
254 _defaultDb = newLibrpmDb();
258 ///////////////////////////////////////////////////////////////////
261 // METHOD NAME : librpmDb::dbAccess
262 // METHOD TYPE : PMError
264 void librpmDb::dbAccess( librpmDb::constPtr & ptr_r )
271 ///////////////////////////////////////////////////////////////////
274 // METHOD NAME : librpmDb::dbRelease
275 // METHOD TYPE : unsigned
277 unsigned librpmDb::dbRelease( bool force_r )
284 unsigned outstanding = _defaultDb->refCount() - 1; // refCount can't be 0
286 switch ( outstanding )
291 DBG << "dbRelease: keep access, outstanding " << outstanding << endl;
294 // else fall through:
296 DBG << "dbRelease: release" << (force_r && outstanding ? "(forced)" : "")
297 << ", outstanding " << outstanding << endl;
299 _defaultDb->_d._error = shared_ptr<RpmAccessBlockedException>(new RpmAccessBlockedException(_defaultDb->_d._root, _defaultDb->_d._dbPath));
300 // tag handle invalid
308 ///////////////////////////////////////////////////////////////////
311 // METHOD NAME : librpmDb::blockAccess
312 // METHOD TYPE : unsigned
314 unsigned librpmDb::blockAccess()
316 MIL << "Block access" << endl;
318 return dbRelease( /*force*/true );
321 ///////////////////////////////////////////////////////////////////
324 // METHOD NAME : librpmDb::unblockAccess
325 // METHOD TYPE : void
327 void librpmDb::unblockAccess()
329 MIL << "Unblock access" << endl;
333 ///////////////////////////////////////////////////////////////////
336 // METHOD NAME : librpmDb::dumpState
337 // METHOD TYPE : ostream &
339 std::ostream & librpmDb::dumpState( std::ostream & str )
343 return str << "[librpmDb " << (_dbBlocked?"BLOCKED":"CLOSED") << " " << stringPath( _defaultRoot, _defaultDbPath ) << "]";
345 return str << "[" << _defaultDb << "]";
348 ///////////////////////////////////////////////////////////////////
350 // CLASS NAME : librpmDb (internal database handle interface (nonstatic))
352 ///////////////////////////////////////////////////////////////////
354 ///////////////////////////////////////////////////////////////////
357 // METHOD NAME : librpmDb::librpmDb
358 // METHOD TYPE : Constructor
362 librpmDb::librpmDb( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
363 : _d( * new D( root_r, dbPath_r, readonly_r ) )
366 ///////////////////////////////////////////////////////////////////
369 // METHOD NAME : librpmDb::~librpmDb
370 // METHOD TYPE : Destructor
374 librpmDb::~librpmDb()
379 ///////////////////////////////////////////////////////////////////
382 // METHOD NAME : librpmDb::unref_to
383 // METHOD TYPE : void
385 void librpmDb::unref_to( unsigned refCount_r ) const
387 if ( refCount_r == 1 )
393 ///////////////////////////////////////////////////////////////////
396 // METHOD NAME : librpmDb::root
397 // METHOD TYPE : const Pathname &
399 const Pathname & librpmDb::root() const
404 ///////////////////////////////////////////////////////////////////
407 // METHOD NAME : librpmDb::dbPath
408 // METHOD TYPE : const Pathname &
410 const Pathname & librpmDb::dbPath() const
415 ///////////////////////////////////////////////////////////////////
418 // METHOD NAME : librpmDb::error
419 // METHOD TYPE : PMError
421 shared_ptr<RpmException> librpmDb::error() const
426 ///////////////////////////////////////////////////////////////////
429 // METHOD NAME : librpmDb::empty
430 // METHOD TYPE : bool
432 bool librpmDb::empty() const
434 return( valid() && ! *db_const_iterator( this ) );
437 ///////////////////////////////////////////////////////////////////
440 // METHOD NAME : librpmDb::size
441 // METHOD TYPE : unsigned
443 unsigned librpmDb::size() const
448 db_const_iterator it( this );
449 for ( db_const_iterator it( this ); *it; ++it )
455 ///////////////////////////////////////////////////////////////////
458 // METHOD NAME : librpmDb::dont_call_it
459 // METHOD TYPE : void *
461 void * librpmDb::dont_call_it() const
463 return rpmtsGetRdb(_d._ts);
466 ///////////////////////////////////////////////////////////////////
469 // METHOD NAME : librpmDb::dumpOn
470 // METHOD TYPE : ostream &
474 std::ostream & librpmDb::dumpOn( std::ostream & str ) const
476 ReferenceCounted::dumpOn( str ) << _d;
480 ///////////////////////////////////////////////////////////////////
482 // CLASS NAME : librpmDb::db_const_iterator::D
486 class librpmDb::db_const_iterator::D
488 D & operator=( const D & ); // NO ASSIGNMENT!
489 D ( const D & ); // NO COPY!
492 librpmDb::constPtr _dbptr;
493 shared_ptr<RpmException> _dberr;
495 RpmHeader::constPtr _hptr;
496 rpmdbMatchIterator _mi;
498 D( librpmDb::constPtr dbptr_r )
506 librpmDb::dbAccess( _dbptr );
508 catch (const RpmException & excpt_r)
510 ZYPP_CAUGHT(excpt_r);
514 WAR << "No database access: " << _dberr << endl;
519 destroy(); // Checks whether _dbptr still valid
527 ::rpmdbFreeIterator( _mi );
532 * Let iterator access a dbindex file. Call @ref advance to access the
533 * 1st element (if present).
535 bool create( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
540 _mi = ::rpmtsInitIterator( _dbptr->_d._ts, rpmTag(rpmtag), keyp, keylen );
545 * Destroy iterator. Invalidates _dbptr, if database was blocked meanwile.
546 * Always returns false.
552 _mi = ::rpmdbFreeIterator( _mi );
555 if ( _dbptr && _dbptr->error() )
557 _dberr = _dbptr->error();
558 WAR << "Lost database access: " << _dberr << endl;
565 * Advance to the first/next header in iterator. Destroys iterator if
566 * no more headers available.
572 Header h = ::rpmdbNextIterator( _mi );
578 _hptr = new RpmHeader( h );
583 * Access a dbindex file and advance to the 1st header.
585 bool init( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
587 if ( ! create( rpmtag, keyp, keylen ) )
593 * Create an itertator that contains the database entry located at
594 * off_r, and advance to the 1st header.
596 bool set( int off_r )
598 if ( ! create( RPMDBI_PACKAGES ) )
600 #ifdef RPMFILEITERMAX // since rpm.4.12
601 ::rpmdbAppendIterator( _mi, (const unsigned *)&off_r, 1 );
603 ::rpmdbAppendIterator( _mi, &off_r, 1 );
610 return( _mi ? ::rpmdbGetIteratorOffset( _mi ) : 0 );
617 int ret = ::rpmdbGetIteratorCount( _mi );
618 return( ret ? ret : -1 ); // -1: sequential access
622 ///////////////////////////////////////////////////////////////////
624 ///////////////////////////////////////////////////////////////////
626 // CLASS NAME : librpmDb::Ptr::db_const_iterator
628 ///////////////////////////////////////////////////////////////////
630 ///////////////////////////////////////////////////////////////////
633 // METHOD NAME : librpmDb::db_const_iterator::db_iterator
634 // METHOD TYPE : Constructor
636 librpmDb::db_const_iterator::db_const_iterator( librpmDb::constPtr dbptr_r )
637 : _d( * new D( dbptr_r ) )
642 ///////////////////////////////////////////////////////////////////
645 // METHOD NAME : librpmDb::db_const_iterator::~db_const_iterator
646 // METHOD TYPE : Destructor
648 librpmDb::db_const_iterator::~db_const_iterator()
653 ///////////////////////////////////////////////////////////////////
656 // METHOD NAME : librpmDb::db_const_iterator::operator++
657 // METHOD TYPE : void
659 void librpmDb::db_const_iterator::operator++()
664 ///////////////////////////////////////////////////////////////////
667 // METHOD NAME : librpmDb::db_const_iterator::dbHdrNum
668 // METHOD TYPE : unsigned
670 unsigned librpmDb::db_const_iterator::dbHdrNum() const
675 ///////////////////////////////////////////////////////////////////
678 // METHOD NAME : librpmDb::db_const_iterator::operator*
679 // METHOD TYPE : const RpmHeader::constPtr &
681 const RpmHeader::constPtr & librpmDb::db_const_iterator::operator*() const
686 ///////////////////////////////////////////////////////////////////
689 // METHOD NAME : librpmDb::db_const_iterator::dbError
690 // METHOD TYPE : PMError
692 shared_ptr<RpmException> librpmDb::db_const_iterator::dbError() const
695 return _d._dbptr->error();
700 /******************************************************************
703 ** FUNCTION NAME : operator<<
704 ** FUNCTION TYPE : ostream &
706 std::ostream & operator<<( std::ostream & str, const librpmDb::db_const_iterator & obj )
708 str << "db_const_iterator(" << obj._d._dbptr
709 << " Size:" << obj._d.size()
710 << " HdrNum:" << obj._d.offset()
715 ///////////////////////////////////////////////////////////////////
718 // METHOD NAME : librpmDb::db_const_iterator::findAll
719 // METHOD TYPE : bool
721 bool librpmDb::db_const_iterator::findAll()
723 return _d.init( RPMDBI_PACKAGES );
726 ///////////////////////////////////////////////////////////////////
729 // METHOD NAME : librpmDb::db_const_iterator::findByFile
730 // METHOD TYPE : bool
732 bool librpmDb::db_const_iterator::findByFile( const std::string & file_r )
734 return _d.init( RPMTAG_BASENAMES, file_r.c_str() );
737 ///////////////////////////////////////////////////////////////////
740 // METHOD NAME : librpmDb::db_const_iterator::findByProvides
741 // METHOD TYPE : bool
743 bool librpmDb::db_const_iterator::findByProvides( const std::string & tag_r )
745 return _d.init( RPMTAG_PROVIDENAME, tag_r.c_str() );
748 ///////////////////////////////////////////////////////////////////
751 // METHOD NAME : librpmDb::db_const_iterator::findByRequiredBy
752 // METHOD TYPE : bool
754 bool librpmDb::db_const_iterator::findByRequiredBy( const std::string & tag_r )
756 return _d.init( RPMTAG_REQUIRENAME, tag_r.c_str() );
759 ///////////////////////////////////////////////////////////////////
762 // METHOD NAME : librpmDb::db_const_iterator::findByConflicts
763 // METHOD TYPE : bool
765 bool librpmDb::db_const_iterator::findByConflicts( const std::string & tag_r )
767 return _d.init( RPMTAG_CONFLICTNAME, tag_r.c_str() );
770 ///////////////////////////////////////////////////////////////////
773 // METHOD NAME : librpmDb::findByName
774 // METHOD TYPE : bool
776 bool librpmDb::db_const_iterator::findByName( const std::string & name_r )
778 return _d.init( RPMTAG_NAME, name_r.c_str() );
781 ///////////////////////////////////////////////////////////////////
784 // METHOD NAME : librpmDb::db_const_iterator::findPackage
785 // METHOD TYPE : bool
787 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r )
789 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
792 if ( _d.size() == 1 )
795 // check installtime on multiple entries
798 for ( ; operator*(); operator++() )
800 if ( operator*()->tag_installtime() > itime )
803 itime = operator*()->tag_installtime();
807 return _d.set( match );
810 ///////////////////////////////////////////////////////////////////
813 // METHOD NAME : librpmDb::db_const_iterator::findPackage
814 // METHOD TYPE : bool
816 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r, const Edition & ed_r )
818 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
821 for ( ; operator*(); operator++() )
823 if ( ed_r == operator*()->tag_edition() )
825 int match = _d.offset();
826 return _d.set( match );
833 ///////////////////////////////////////////////////////////////////
836 // METHOD NAME : librpmDb::db_const_iterator::findPackage
837 // METHOD TYPE : bool
839 bool librpmDb::db_const_iterator::findPackage( const Package::constPtr & which_r )
844 return findPackage( which_r->name(), which_r->edition() );
848 } // namespace target