1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/target/rpm/BinHeader.h
16 #include "zypp/base/Logger.h"
17 #include "zypp/target/rpm/librpmDb.h"
18 #include "zypp/target/rpm/RpmHeader.h"
19 #include "zypp/base/Exception.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 #warning fix string representation of the error
41 shared_ptr<Exception> _error; // database error
43 friend ostream & operator<<( ostream & str, const D & obj ) {
44 str << "{" << obj._error << "(" << obj._root << ")" << obj._dbPath << "}";
48 D( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
55 ::addMacro( NULL, "_dbpath", NULL, _dbPath.asString().c_str(), RMIL_CMDLINE );
56 const char * root = ( _root == "/" ? NULL : _root.asString().c_str() );
59 // check whether to create a new db
60 PathInfo master( _root + _dbPath + "Packages" );
61 if ( ! master.isFile() ) {
63 int res = ::rpmdbInit( root, perms );
65 _error = shared_ptr<Exception>(new Exception("Error::E_RpmDB_init_failed"));
66 ERR << "rpmdbInit error(" << res << "): " << *this << endl;
72 int res = ::rpmdbOpen( root, &_db, (readonly_r ? O_RDONLY : O_RDWR ), perms );
74 _error = shared_ptr<Exception>(new Exception("Error::E_RpmDB_open_failed"));
79 ERR << "rpmdbOpen error(" << res << "): " << *this << endl;
83 DBG << "DBACCESS " << *this << endl;
89 // login here may cause a SEGV, if call is caused by
90 // static variables being deleted. Might be that PMError
91 // static strings or logstreams are already destructed.
92 int res = ::rpmdbClose( _db );
94 WAR << "::rpmdbClose error(" << res << ")" << endl;
96 DBG << "DBCLOSE " << *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 );
132 ERR << "rpmReadConfigFiles returned " << rc << endl;
136 // should speed up convertdb and rebuilddb.
137 ::addMacro( NULL, "_rpmdb_rebuild", NULL, "%{nil}", RMIL_CMDLINE );
139 initialized = true; // Necessary to be able to use exand().
141 #define OUTVAL(n) << " (" #n ":" << expand( "%{" #n "}" ) << ")"
142 MIL << "librpm init done:"
150 ///////////////////////////////////////////////////////////////////
153 // METHOD NAME : librpmDb::expand
154 // METHOD TYPE : std::string
156 std::string librpmDb::expand( const std::string & macro_r )
158 if ( ! globalInit() )
159 return macro_r; // unexpanded
161 char * val = ::rpmExpand( macro_r.c_str(), NULL );
170 ///////////////////////////////////////////////////////////////////
173 // METHOD NAME : librpmDb::newLibrpmDb
174 // METHOD TYPE : librpmDb *
176 librpmDb * librpmDb::newLibrpmDb( Pathname root_r, Pathname dbPath_r, bool readonly_r )
179 if ( ! (root_r.absolute() && dbPath_r.absolute()) ) {
180 ERR << "Illegal root or dbPath: " << stringPath( root_r, dbPath_r ) << endl;
181 ZYPP_THROW(Exception("Error::E_invalid_argument"));
185 if ( ! globalInit() ) {
186 ZYPP_THROW(Exception("Error::E_RpmDB_global_init_failed"));
190 librpmDb * ret = new librpmDb( root_r, dbPath_r, readonly_r );
191 shared_ptr<Exception> err_r = ret->_d._error;
195 #warning FIXME uncomment
197 ZYPP_THROW(ret->_d._error);
203 ///////////////////////////////////////////////////////////////////
206 // METHOD NAME : librpmDb::dbAccess
207 // METHOD TYPE : PMError
209 void librpmDb::dbAccess( const Pathname & root_r, const Pathname & dbPath_r )
212 if ( ! (root_r.absolute() && dbPath_r.absolute()) ) {
213 ERR << "Illegal root or dbPath: " << stringPath( root_r, dbPath_r ) << endl;
214 ZYPP_THROW(Exception("Error::E_invalid_argument"));
218 // already accessing a database: switching is not allowed.
219 if ( _defaultRoot == root_r && _defaultDbPath == dbPath_r )
222 ERR << "Can't switch to " << stringPath( root_r, dbPath_r )
223 << " while accessing " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
224 ZYPP_THROW(Exception("Error::E_RpmDB_already_open"));
228 // got no database: we could switch to a new one (even if blocked!)
229 _defaultRoot = root_r;
230 _defaultDbPath = dbPath_r;
231 MIL << "Set new database location: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
236 ///////////////////////////////////////////////////////////////////
239 // METHOD NAME : librpmDb::dbAccess
240 // METHOD TYPE : PMError
242 void librpmDb::dbAccess()
245 WAR << "Access is blocked: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
246 ZYPP_THROW(Exception("Error::E_RpmDB_access_blocked"));
251 _defaultDb = newLibrpmDb( _defaultRoot, _defaultDbPath, /*readonly*/true );
255 ///////////////////////////////////////////////////////////////////
258 // METHOD NAME : librpmDb::dbAccess
259 // METHOD TYPE : PMError
261 void librpmDb::dbAccess( librpmDb::constPtr & ptr_r )
266 catch (Exception & excpt_r)
269 ZYPP_RETHROW(excpt_r);
274 ///////////////////////////////////////////////////////////////////
277 // METHOD NAME : librpmDb::dbRelease
278 // METHOD TYPE : unsigned
280 unsigned librpmDb::dbRelease( bool force_r )
286 unsigned outstanding = _defaultDb->refCount() - 1; // refCount can't be 0
288 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<Exception>(new Exception("Error::E_RpmDB_access_blocked")); // tag handle invalid
307 ///////////////////////////////////////////////////////////////////
310 // METHOD NAME : librpmDb::blockAccess
311 // METHOD TYPE : unsigned
313 unsigned librpmDb::blockAccess()
315 MIL << "Block access" << endl;
317 return dbRelease( /*force*/true );
320 ///////////////////////////////////////////////////////////////////
323 // METHOD NAME : librpmDb::unblockAccess
324 // METHOD TYPE : void
326 void librpmDb::unblockAccess()
328 MIL << "Unblock access" << endl;
332 ///////////////////////////////////////////////////////////////////
335 // METHOD NAME : librpmDb::dumpState
336 // METHOD TYPE : ostream &
338 ostream & librpmDb::dumpState( ostream & str )
341 return str << "[librpmDb " << (_dbBlocked?"BLOCKED":"CLOSED") << " " << stringPath( _defaultRoot, _defaultDbPath ) << "]";
343 return str << "[" << _defaultDb << "]";
346 ///////////////////////////////////////////////////////////////////
348 // CLASS NAME : librpmDb (internal database handle interface (nonstatic))
350 ///////////////////////////////////////////////////////////////////
352 ///////////////////////////////////////////////////////////////////
355 // METHOD NAME : librpmDb::librpmDb
356 // METHOD TYPE : Constructor
360 librpmDb::librpmDb( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
361 : _d( * new D( root_r, dbPath_r, readonly_r ) )
365 ///////////////////////////////////////////////////////////////////
368 // METHOD NAME : librpmDb::~librpmDb
369 // METHOD TYPE : Destructor
373 librpmDb::~librpmDb()
378 ///////////////////////////////////////////////////////////////////
381 // METHOD NAME : librpmDb::unref_to
382 // METHOD TYPE : void
384 void librpmDb::unref_to( unsigned refCount_r ) const
386 if ( refCount_r == 1 ) {
391 ///////////////////////////////////////////////////////////////////
394 // METHOD NAME : librpmDb::root
395 // METHOD TYPE : const Pathname &
397 const Pathname & librpmDb::root() const
402 ///////////////////////////////////////////////////////////////////
405 // METHOD NAME : librpmDb::dbPath
406 // METHOD TYPE : const Pathname &
408 const Pathname & librpmDb::dbPath() const
413 #warning uncomment thsi function
415 ///////////////////////////////////////////////////////////////////
418 // METHOD NAME : librpmDb::error
419 // METHOD TYPE : PMError
421 PMError 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 ) );
438 ///////////////////////////////////////////////////////////////////
441 // METHOD NAME : librpmDb::dont_call_it
442 // METHOD TYPE : void *
444 void * librpmDb::dont_call_it() const
449 ///////////////////////////////////////////////////////////////////
452 // METHOD NAME : librpmDb::dumpOn
453 // METHOD TYPE : ostream &
457 ostream & librpmDb::dumpOn( ostream & str ) const
459 ReferenceCounted::dumpOn( str ) << _d;
463 ///////////////////////////////////////////////////////////////////
465 // CLASS NAME : librpmDb::DbDirInfo
467 ///////////////////////////////////////////////////////////////////
469 ///////////////////////////////////////////////////////////////////
472 // METHOD NAME : librpmDb::DbDirInfo::DbDirInfo
473 // METHOD TYPE : Constructor
475 librpmDb::DbDirInfo::DbDirInfo( const Pathname & root_r, const Pathname & dbPath_r )
477 , _dbPath( dbPath_r )
479 // check and adjust arguments
480 if ( ! (root_r.absolute() && dbPath_r.absolute()) ) {
481 ERR << "Relative path for root(" << _root << ") or dbPath(" << _dbPath << ")" << endl;
483 _dbDir ( _root + _dbPath );
484 _dbV4 ( _dbDir.path() + "Packages" );
485 _dbV3 ( _dbDir.path() + "packages.rpm" );
486 _dbV3ToV4( _dbDir.path() + "packages.rpm3" );
487 DBG << *this << endl;
491 ///////////////////////////////////////////////////////////////////
494 // METHOD NAME : librpmDb::DbDirInfo::update
495 // METHOD TYPE : void
497 void librpmDb::DbDirInfo::restat()
503 DBG << *this << endl;
506 /******************************************************************
509 ** FUNCTION NAME : operator<<
510 ** FUNCTION TYPE : std::ostream &
512 std::ostream & operator<<( std::ostream & str, const librpmDb::DbDirInfo & obj )
514 if ( obj.illegalArgs() ) {
515 str << "ILLEGAL: '(" << obj.root() << ")" << obj.dbPath() << "'";
517 str << "'(" << obj.root() << ")" << obj.dbPath() << "':" << endl;
518 str << " Dir: " << obj._dbDir << endl;
519 str << " V4: " << obj._dbV4 << endl;
520 str << " V3: " << obj._dbV3 << endl;
521 str << " V3ToV4: " << obj._dbV3ToV4;
526 ///////////////////////////////////////////////////////////////////
528 // CLASS NAME : librpmDb::db_const_iterator::D
532 class librpmDb::db_const_iterator::D {
533 D & operator=( const D & ); // NO ASSIGNMENT!
534 D ( const D & ); // NO COPY!
537 librpmDb::constPtr _dbptr;
538 #warning use better type
541 RpmHeader::constPtr _hptr;
542 rpmdbMatchIterator _mi;
544 D( librpmDb::constPtr dbptr_r )
549 // try to get librpmDb's default db
550 #warning FIXME uncomment
552 _dberr = librpmDb::dbAccess( _dbptr );
555 WAR << "No database access: " << _dberr << endl;
558 destroy(); // Checks whether _dbptr still valid
564 ::rpmdbFreeIterator( _mi );
569 * Let iterator access a dbindex file. Call @ref advance to access the
570 * 1st element (if present).
572 bool create( int rpmtag, const void * keyp = NULL, size_t keylen = 0 ) {
576 _mi = ::rpmdbInitIterator( _dbptr->_d._db, rpmTag(rpmtag), keyp, keylen );
581 * Destroy iterator. Invalidates _dbptr, if database was blocked meanwile.
582 * Always returns false.
586 _mi = ::rpmdbFreeIterator( _mi );
591 if ( _dbptr && _dbptr->error() ) {
592 _dberr = _dbptr->error();
593 WAR << "Lost database access: " << _dberr << endl;
601 * Advance to the first/next header in iterator. Destroys iterator if
602 * no more headers available.
607 Header h = ::rpmdbNextIterator( _mi );
612 _hptr = new RpmHeader( h );
617 * Access a dbindex file and advance to the 1st header.
619 bool init( int rpmtag, const void * keyp = NULL, size_t keylen = 0 ) {
620 if ( ! create( rpmtag, keyp, keylen ) )
626 * Create an itertator that contains the database entry located at
627 * off_r, and advance to the 1st header.
629 bool set( int off_r ) {
630 if ( ! create( RPMDBI_PACKAGES ) )
632 #warning TESTCASE: rpmdbAppendIterator and (non)sequential access?
633 ::rpmdbAppendIterator( _mi, &off_r, 1 );
638 return( _mi ? ::rpmdbGetIteratorOffset( _mi ) : 0 );
644 int ret = ::rpmdbGetIteratorCount( _mi );
645 #warning TESTCASE: rpmdbGetIteratorCount returns 0 on sequential access?
646 return( ret ? ret : -1 ); // -1: sequential access
650 ///////////////////////////////////////////////////////////////////
652 ///////////////////////////////////////////////////////////////////
654 // CLASS NAME : librpmDb::Ptr::db_const_iterator
656 ///////////////////////////////////////////////////////////////////
658 ///////////////////////////////////////////////////////////////////
661 // METHOD NAME : librpmDb::db_const_iterator::db_iterator
662 // METHOD TYPE : Constructor
664 librpmDb::db_const_iterator::db_const_iterator( librpmDb::constPtr dbptr_r )
665 : _d( * new D( dbptr_r ) )
670 ///////////////////////////////////////////////////////////////////
673 // METHOD NAME : librpmDb::db_const_iterator::~db_const_iterator
674 // METHOD TYPE : Destructor
676 librpmDb::db_const_iterator::~db_const_iterator()
681 ///////////////////////////////////////////////////////////////////
684 // METHOD NAME : librpmDb::db_const_iterator::operator++
685 // METHOD TYPE : void
687 void librpmDb::db_const_iterator::operator++()
692 ///////////////////////////////////////////////////////////////////
695 // METHOD NAME : librpmDb::db_const_iterator::dbHdrNum
696 // METHOD TYPE : unsigned
698 unsigned librpmDb::db_const_iterator::dbHdrNum() const
703 ///////////////////////////////////////////////////////////////////
706 // METHOD NAME : librpmDb::db_const_iterator::operator*
707 // METHOD TYPE : const RpmHeader::constPtr &
709 const RpmHeader::constPtr & librpmDb::db_const_iterator::operator*() const
714 #warning FIXME this function
716 ///////////////////////////////////////////////////////////////////
719 // METHOD NAME : librpmDb::db_const_iterator::dbError
720 // METHOD TYPE : PMError
722 PMError librpmDb::db_const_iterator::dbError() const
725 return _d._dbptr->error();
731 /******************************************************************
734 ** FUNCTION NAME : operator<<
735 ** FUNCTION TYPE : ostream &
737 ostream & operator<<( ostream & str, const librpmDb::db_const_iterator & obj )
739 str << "db_const_iterator(" << obj._d._dbptr
740 << " Size:" << obj._d.size()
741 << " HdrNum:" << obj._d.offset()
746 ///////////////////////////////////////////////////////////////////
749 // METHOD NAME : librpmDb::db_const_iterator::findAll
750 // METHOD TYPE : bool
752 bool librpmDb::db_const_iterator::findAll()
754 return _d.init( RPMDBI_PACKAGES );
757 ///////////////////////////////////////////////////////////////////
760 // METHOD NAME : librpmDb::db_const_iterator::findByFile
761 // METHOD TYPE : bool
763 bool librpmDb::db_const_iterator::findByFile( const std::string & file_r )
765 return _d.init( RPMTAG_BASENAMES, file_r.c_str() );
768 ///////////////////////////////////////////////////////////////////
771 // METHOD NAME : librpmDb::db_const_iterator::findByProvides
772 // METHOD TYPE : bool
774 bool librpmDb::db_const_iterator::findByProvides( const std::string & tag_r )
776 return _d.init( RPMTAG_PROVIDENAME, tag_r.c_str() );
779 ///////////////////////////////////////////////////////////////////
782 // METHOD NAME : librpmDb::db_const_iterator::findByRequiredBy
783 // METHOD TYPE : bool
785 bool librpmDb::db_const_iterator::findByRequiredBy( const std::string & tag_r )
787 return _d.init( RPMTAG_REQUIRENAME, tag_r.c_str() );
790 ///////////////////////////////////////////////////////////////////
793 // METHOD NAME : librpmDb::db_const_iterator::findByConflicts
794 // METHOD TYPE : bool
796 bool librpmDb::db_const_iterator::findByConflicts( const std::string & tag_r )
798 return _d.init( RPMTAG_CONFLICTNAME, tag_r.c_str() );
801 ///////////////////////////////////////////////////////////////////
804 // METHOD NAME : librpmDb::findByName
805 // METHOD TYPE : bool
807 bool librpmDb::db_const_iterator::findByName( const string & name_r )
809 return _d.init( RPMTAG_NAME, name_r.c_str() );
812 ///////////////////////////////////////////////////////////////////
815 // METHOD NAME : librpmDb::db_const_iterator::findPackage
816 // METHOD TYPE : bool
818 bool librpmDb::db_const_iterator::findPackage( const string & name_r )
820 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
823 if ( _d.size() == 1 )
826 // check installtime on multiple entries
829 for ( ; operator*(); operator++() ) {
830 if ( operator*()->tag_installtime() > itime ) {
832 itime = operator*()->tag_installtime();
836 return _d.set( match );
839 ///////////////////////////////////////////////////////////////////
842 // METHOD NAME : librpmDb::db_const_iterator::findPackage
843 // METHOD TYPE : bool
845 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r, const Edition & ed_r )
847 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
850 for ( ; operator*(); operator++() ) {
851 if ( ed_r == operator*()->tag_edition() ) {
852 int match = _d.offset();
853 return _d.set( match );
860 ///////////////////////////////////////////////////////////////////
863 // METHOD NAME : librpmDb::db_const_iterator::findPackage
864 // METHOD TYPE : bool
866 bool librpmDb::db_const_iterator::findPackage( const Package::constPtr & which_r )
871 return findPackage( which_r->name(), which_r->edition() );
875 } // namespace target