00001
00002
00003
00004
00005
00006
00007
00008
00012 #include "librpm.h"
00013
00014 #include <iostream>
00015
00016 #include "zypp/base/Logger.h"
00017 #include "zypp/target/rpm/librpmDb.h"
00018 #include "zypp/target/rpm/RpmHeader.h"
00019 #include "zypp/target/rpm/RpmException.h"
00020
00021 using namespace std;
00022
00023 namespace zypp {
00024 namespace target {
00025 namespace rpm {
00027
00028
00032 class librpmDb::D {
00033 D & operator=( const D & );
00034 D ( const D & );
00035 public:
00036
00037 const Pathname _root;
00038 const Pathname _dbPath;
00039 rpmdb _db;
00040 shared_ptr<RpmException> _error;
00041
00042 friend ostream & operator<<( ostream & str, const D & obj ) {
00043 str << "{" << obj._error << "(" << obj._root << ")" << obj._dbPath << "}";
00044 return str;
00045 }
00046
00047 D( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
00048 : _root ( root_r )
00049 , _dbPath( dbPath_r )
00050 , _db ( 0 )
00051 {
00052 _error.reset();
00053
00054 ::addMacro( NULL, "_dbpath", NULL, _dbPath.asString().c_str(), RMIL_CMDLINE );
00055 const char * root = ( _root == "/" ? NULL : _root.asString().c_str() );
00056 int perms = 0644;
00057
00058
00059 PathInfo master( _root + _dbPath + "Packages" );
00060 if ( ! master.isFile() ) {
00061
00062 int res = ::rpmdbInit( root, perms );
00063 if ( res ) {
00064 ERR << "rpmdbInit error(" << res << "): " << *this << endl;
00065 _error = shared_ptr<RpmInitException>(new RpmInitException(_root, _dbPath));
00066 ZYPP_THROW(*_error);
00067 }
00068 }
00069
00070
00071 int res = ::rpmdbOpen( root, &_db, (readonly_r ? O_RDONLY : O_RDWR ), perms );
00072 if ( res || !_db ) {
00073 if ( _db ) {
00074 ::rpmdbClose( _db );
00075 _db = 0;
00076 }
00077 ERR << "rpmdbOpen error(" << res << "): " << *this << endl;
00078 _error = shared_ptr<RpmDbOpenException>(new RpmDbOpenException(_root, _dbPath));
00079 ZYPP_THROW(*_error);
00080 return;
00081 }
00082
00083 DBG << "DBACCESS " << *this << endl;
00084 }
00085
00086 ~D() {
00087 if ( _db ) {
00088 #if 0
00089
00090
00091
00092 int res = ::rpmdbClose( _db );
00093 if ( res ) {
00094 WAR << "::rpmdbClose error(" << res << ")" << endl;
00095 }
00096 DBG << "DBCLOSE " << *this << endl;
00097 #else
00098 ::rpmdbClose( _db );
00099 #endif
00100 }
00101 }
00102 };
00103
00105
00107
00108
00109
00111
00112 Pathname librpmDb::_defaultRoot ( "/" );
00113 Pathname librpmDb::_defaultDbPath( "/var/lib/rpm" );
00114 librpmDb::constPtr librpmDb::_defaultDb;
00115 bool librpmDb::_dbBlocked ( true );
00116
00118
00119
00120
00121
00122
00123 bool librpmDb::globalInit()
00124 {
00125 static bool initialized = false;
00126
00127 if ( initialized )
00128 return true;
00129
00130 int rc = ::rpmReadConfigFiles( NULL, NULL );
00131 if ( rc ) {
00132 ERR << "rpmReadConfigFiles returned " << rc << endl;
00133 return false;
00134 }
00135
00136
00137 ::addMacro( NULL, "_rpmdb_rebuild", NULL, "%{nil}", RMIL_CMDLINE );
00138
00139 initialized = true;
00140
00141 #define OUTVAL(n) << " (" #n ":" << expand( "%{" #n "}" ) << ")"
00142 MIL << "librpm init done:"
00143 OUTVAL(_target)
00144 OUTVAL(_dbpath)
00145 << endl;
00146 #undef OUTVAL
00147 return initialized;
00148 }
00149
00151
00152
00153
00154
00155
00156 std::string librpmDb::expand( const std::string & macro_r )
00157 {
00158 if ( ! globalInit() )
00159 return macro_r;
00160
00161 char * val = ::rpmExpand( macro_r.c_str(), NULL );
00162 if ( !val )
00163 return "";
00164
00165 string ret( val );
00166 free( val );
00167 return ret;
00168 }
00169
00171
00172
00173
00174
00175
00176 librpmDb * librpmDb::newLibrpmDb( Pathname root_r, Pathname dbPath_r, bool readonly_r )
00177 {
00178
00179 if ( ! (root_r.absolute() && dbPath_r.absolute()) ) {
00180 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
00181 }
00182
00183
00184 if ( ! globalInit() ) {
00185 ZYPP_THROW(GlobalRpmInitException());
00186 }
00187
00188
00189 librpmDb * ret = 0;
00190 try {
00191 ret = new librpmDb( root_r, dbPath_r, readonly_r );
00192 }
00193 catch (const RpmException & excpt_r)
00194 {
00195 ZYPP_CAUGHT(excpt_r);
00196 delete ret;
00197 ret = 0;
00198 ZYPP_RETHROW(excpt_r);
00199 }
00200 return ret;
00201 }
00202
00204
00205
00206
00207
00208
00209 void librpmDb::dbAccess( const Pathname & root_r, const Pathname & dbPath_r )
00210 {
00211
00212 if ( ! (root_r.absolute() && dbPath_r.absolute()) ) {
00213 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
00214 }
00215
00216 if ( _defaultDb ) {
00217
00218 if ( _defaultRoot == root_r && _defaultDbPath == dbPath_r )
00219 return;
00220 else {
00221 ZYPP_THROW(RpmDbAlreadyOpenException(_defaultRoot, _defaultDbPath, root_r, dbPath_r));
00222 }
00223 }
00224
00225
00226 _defaultRoot = root_r;
00227 _defaultDbPath = dbPath_r;
00228 MIL << "Set new database location: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
00229
00230 return dbAccess();
00231 }
00232
00234
00235
00236
00237
00238
00239 void librpmDb::dbAccess()
00240 {
00241 if ( _dbBlocked ) {
00242 ZYPP_THROW(RpmAccessBlockedException(_defaultRoot, _defaultDbPath));
00243 }
00244
00245 if ( !_defaultDb ) {
00246
00247 _defaultDb = newLibrpmDb( _defaultRoot, _defaultDbPath, true );
00248 }
00249 }
00250
00252
00253
00254
00255
00256
00257 void librpmDb::dbAccess( librpmDb::constPtr & ptr_r )
00258 {
00259 try {
00260 dbAccess();
00261 }
00262 catch (const RpmException & excpt_r)
00263 {
00264 ZYPP_CAUGHT(excpt_r);
00265 ptr_r = 0;
00266 ZYPP_RETHROW(excpt_r);
00267 }
00268 ptr_r = _defaultDb;
00269 }
00270
00272
00273
00274
00275
00276
00277 unsigned librpmDb::dbRelease( bool force_r )
00278 {
00279 if ( !_defaultDb ) {
00280 return 0;
00281 }
00282
00283 unsigned outstanding = _defaultDb->refCount() - 1;
00284
00285 switch ( outstanding ) {
00286 default:
00287 if ( !force_r ) {
00288 DBG << "dbRelease: keep access, outstanding " << outstanding << endl;
00289 break;
00290 }
00291
00292 case 0:
00293 DBG << "dbRelease: release" << (force_r && outstanding ? "(forced)" : "")
00294 << ", outstanding " << outstanding << endl;
00295
00296 _defaultDb->_d._error = shared_ptr<RpmAccessBlockedException>(new RpmAccessBlockedException(_defaultDb->_d._root, _defaultDb->_d._dbPath));
00297
00298 _defaultDb = 0;
00299 break;
00300 }
00301
00302 return outstanding;
00303 }
00304
00306
00307
00308
00309
00310
00311 unsigned librpmDb::blockAccess()
00312 {
00313 MIL << "Block access" << endl;
00314 _dbBlocked = true;
00315 return dbRelease( true );
00316 }
00317
00319
00320
00321
00322
00323
00324 void librpmDb::unblockAccess()
00325 {
00326 MIL << "Unblock access" << endl;
00327 _dbBlocked = false;
00328 }
00329
00331
00332
00333
00334
00335
00336 ostream & librpmDb::dumpState( ostream & str )
00337 {
00338 if ( !_defaultDb ) {
00339 return str << "[librpmDb " << (_dbBlocked?"BLOCKED":"CLOSED") << " " << stringPath( _defaultRoot, _defaultDbPath ) << "]";
00340 }
00341 return str << "[" << _defaultDb << "]";
00342 }
00343
00345
00346
00347
00349
00351
00352
00353
00354
00355
00356
00357
00358 librpmDb::librpmDb( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
00359 : _d( * new D( root_r, dbPath_r, readonly_r ) )
00360 {
00361 }
00362
00364
00365
00366
00367
00368
00369
00370
00371 librpmDb::~librpmDb()
00372 {
00373 delete &_d;
00374 }
00375
00377
00378
00379
00380
00381
00382 void librpmDb::unref_to( unsigned refCount_r ) const
00383 {
00384 if ( refCount_r == 1 ) {
00385 dbRelease();
00386 }
00387 }
00388
00390
00391
00392
00393
00394
00395 const Pathname & librpmDb::root() const
00396 {
00397 return _d._root;
00398 }
00399
00401
00402
00403
00404
00405
00406 const Pathname & librpmDb::dbPath() const
00407 {
00408 return _d._dbPath;
00409 }
00410
00412
00413
00414
00415
00416
00417 shared_ptr<RpmException> librpmDb::error() const
00418 {
00419 return _d._error;
00420 }
00421
00423
00424
00425
00426
00427
00428 bool librpmDb::empty() const
00429 {
00430 return( valid() && ! *db_const_iterator( this ) );
00431 }
00432
00434
00435
00436
00437
00438
00439 void * librpmDb::dont_call_it() const
00440 {
00441 return _d._db;
00442 }
00443
00445
00446
00447
00448
00449
00450
00451
00452 ostream & librpmDb::dumpOn( ostream & str ) const
00453 {
00454 ReferenceCounted::dumpOn( str ) << _d;
00455 return str;
00456 }
00457
00459
00460
00461
00463
00465
00466
00467
00468
00469
00470 librpmDb::DbDirInfo::DbDirInfo( const Pathname & root_r, const Pathname & dbPath_r )
00471 : _root( root_r )
00472 , _dbPath( dbPath_r )
00473 {
00474
00475 if ( ! (root_r.absolute() && dbPath_r.absolute()) ) {
00476 ERR << "Relative path for root(" << _root << ") or dbPath(" << _dbPath << ")" << endl;
00477 } else {
00478 _dbDir ( _root + _dbPath );
00479 _dbV4 ( _dbDir.path() + "Packages" );
00480 _dbV3 ( _dbDir.path() + "packages.rpm" );
00481 _dbV3ToV4( _dbDir.path() + "packages.rpm3" );
00482 DBG << *this << endl;
00483 }
00484 }
00485
00487
00488
00489
00490
00491
00492 void librpmDb::DbDirInfo::restat()
00493 {
00494 _dbDir();
00495 _dbV4();
00496 _dbV3();
00497 _dbV3ToV4();
00498 DBG << *this << endl;
00499 }
00500
00501
00502
00503
00504
00505
00506
00507 std::ostream & operator<<( std::ostream & str, const librpmDb::DbDirInfo & obj )
00508 {
00509 if ( obj.illegalArgs() ) {
00510 str << "ILLEGAL: '(" << obj.root() << ")" << obj.dbPath() << "'";
00511 } else {
00512 str << "'(" << obj.root() << ")" << obj.dbPath() << "':" << endl;
00513 str << " Dir: " << obj._dbDir << endl;
00514 str << " V4: " << obj._dbV4 << endl;
00515 str << " V3: " << obj._dbV3 << endl;
00516 str << " V3ToV4: " << obj._dbV3ToV4;
00517 }
00518 return str;
00519 }
00520
00522
00523
00527 class librpmDb::db_const_iterator::D {
00528 D & operator=( const D & );
00529 D ( const D & );
00530 public:
00531
00532 librpmDb::constPtr _dbptr;
00533 shared_ptr<RpmException> _dberr;
00534
00535 RpmHeader::constPtr _hptr;
00536 rpmdbMatchIterator _mi;
00537
00538 D( librpmDb::constPtr dbptr_r )
00539 : _dbptr( dbptr_r )
00540 , _mi( 0 )
00541 {
00542 if ( !_dbptr ) {
00543 try {
00544 librpmDb::dbAccess( _dbptr );
00545 }
00546 catch (const RpmException & excpt_r)
00547 {
00548 ZYPP_CAUGHT(excpt_r);
00549 }
00550 if ( !_dbptr ) {
00551 WAR << "No database access: " << _dberr << endl;
00552 }
00553 } else {
00554 destroy();
00555 }
00556 }
00557
00558 ~D() {
00559 if ( _mi ) {
00560 ::rpmdbFreeIterator( _mi );
00561 }
00562 }
00563
00568 bool create( int rpmtag, const void * keyp = NULL, size_t keylen = 0 ) {
00569 destroy();
00570 if ( ! _dbptr )
00571 return false;
00572 _mi = ::rpmdbInitIterator( _dbptr->_d._db, rpmTag(rpmtag), keyp, keylen );
00573 return _mi;
00574 }
00575
00580 bool destroy() {
00581 if ( _mi ) {
00582 _mi = ::rpmdbFreeIterator( _mi );
00583 _hptr = 0;
00584 }
00585 if ( _dbptr && _dbptr->error() ) {
00586 _dberr = _dbptr->error();
00587 WAR << "Lost database access: " << _dberr << endl;
00588 _dbptr = 0;
00589 }
00590 return false;
00591 }
00592
00597 bool advance() {
00598 if ( !_mi )
00599 return false;
00600 Header h = ::rpmdbNextIterator( _mi );
00601 if ( ! h ) {
00602 destroy();
00603 return false;
00604 }
00605 _hptr = new RpmHeader( h );
00606 return true;
00607 }
00608
00612 bool init( int rpmtag, const void * keyp = NULL, size_t keylen = 0 ) {
00613 if ( ! create( rpmtag, keyp, keylen ) )
00614 return false;
00615 return advance();
00616 }
00617
00622 bool set( int off_r ) {
00623 if ( ! create( RPMDBI_PACKAGES ) )
00624 return false;
00625 #warning TESTCASE: rpmdbAppendIterator and (non)sequential access?
00626 ::rpmdbAppendIterator( _mi, &off_r, 1 );
00627 return advance();
00628 }
00629
00630 unsigned offset() {
00631 return( _mi ? ::rpmdbGetIteratorOffset( _mi ) : 0 );
00632 }
00633
00634 int size() {
00635 if ( !_mi )
00636 return 0;
00637 int ret = ::rpmdbGetIteratorCount( _mi );
00638 #warning TESTCASE: rpmdbGetIteratorCount returns 0 on sequential access?
00639 return( ret ? ret : -1 );
00640 }
00641 };
00642
00644
00646
00647
00648
00650
00652
00653
00654
00655
00656
00657 librpmDb::db_const_iterator::db_const_iterator( librpmDb::constPtr dbptr_r )
00658 : _d( * new D( dbptr_r ) )
00659 {
00660 findAll();
00661 }
00662
00664
00665
00666
00667
00668
00669 librpmDb::db_const_iterator::~db_const_iterator()
00670 {
00671 delete &_d;
00672 }
00673
00675
00676
00677
00678
00679
00680 void librpmDb::db_const_iterator::operator++()
00681 {
00682 _d.advance();
00683 }
00684
00686
00687
00688
00689
00690
00691 unsigned librpmDb::db_const_iterator::dbHdrNum() const
00692 {
00693 return _d.offset();
00694 }
00695
00697
00698
00699
00700
00701
00702 const RpmHeader::constPtr & librpmDb::db_const_iterator::operator*() const
00703 {
00704 return _d._hptr;
00705 }
00706
00708
00709
00710
00711
00712
00713 shared_ptr<RpmException> librpmDb::db_const_iterator::dbError() const
00714 {
00715 if ( _d._dbptr )
00716 return _d._dbptr->error();
00717
00718 return _d._dberr;
00719 }
00720
00721
00722
00723
00724
00725
00726
00727 ostream & operator<<( ostream & str, const librpmDb::db_const_iterator & obj )
00728 {
00729 str << "db_const_iterator(" << obj._d._dbptr
00730 << " Size:" << obj._d.size()
00731 << " HdrNum:" << obj._d.offset()
00732 << ")";
00733 return str;
00734 }
00735
00737
00738
00739
00740
00741
00742 bool librpmDb::db_const_iterator::findAll()
00743 {
00744 return _d.init( RPMDBI_PACKAGES );
00745 }
00746
00748
00749
00750
00751
00752
00753 bool librpmDb::db_const_iterator::findByFile( const std::string & file_r )
00754 {
00755 return _d.init( RPMTAG_BASENAMES, file_r.c_str() );
00756 }
00757
00759
00760
00761
00762
00763
00764 bool librpmDb::db_const_iterator::findByProvides( const std::string & tag_r )
00765 {
00766 return _d.init( RPMTAG_PROVIDENAME, tag_r.c_str() );
00767 }
00768
00770
00771
00772
00773
00774
00775 bool librpmDb::db_const_iterator::findByRequiredBy( const std::string & tag_r )
00776 {
00777 return _d.init( RPMTAG_REQUIRENAME, tag_r.c_str() );
00778 }
00779
00781
00782
00783
00784
00785
00786 bool librpmDb::db_const_iterator::findByConflicts( const std::string & tag_r )
00787 {
00788 return _d.init( RPMTAG_CONFLICTNAME, tag_r.c_str() );
00789 }
00790
00792
00793
00794
00795
00796
00797 bool librpmDb::db_const_iterator::findByName( const string & name_r )
00798 {
00799 return _d.init( RPMTAG_NAME, name_r.c_str() );
00800 }
00801
00803
00804
00805
00806
00807
00808 bool librpmDb::db_const_iterator::findPackage( const string & name_r )
00809 {
00810 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
00811 return false;
00812
00813 if ( _d.size() == 1 )
00814 return true;
00815
00816
00817 int match = 0;
00818 time_t itime = 0;
00819 for ( ; operator*(); operator++() ) {
00820 if ( operator*()->tag_installtime() > itime ) {
00821 match = _d.offset();
00822 itime = operator*()->tag_installtime();
00823 }
00824 }
00825
00826 return _d.set( match );
00827 }
00828
00830
00831
00832
00833
00834
00835 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r, const Edition & ed_r )
00836 {
00837 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
00838 return false;
00839
00840 for ( ; operator*(); operator++() ) {
00841 if ( ed_r == operator*()->tag_edition() ) {
00842 int match = _d.offset();
00843 return _d.set( match );
00844 }
00845 }
00846
00847 return _d.destroy();
00848 }
00849
00851
00852
00853
00854
00855
00856 bool librpmDb::db_const_iterator::findPackage( const Package::constPtr & which_r )
00857 {
00858 if ( ! which_r )
00859 return _d.destroy();
00860
00861 return findPackage( which_r->name(), which_r->edition() );
00862 }
00863
00864 }
00865 }
00866 }