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 {
00025 namespace target
00026 {
00027 namespace rpm
00028 {
00030
00031
00035 class librpmDb::D
00036 {
00037 D & operator=( const D & );
00038 D ( const D & );
00039 public:
00040
00041 const Pathname _root;
00042 const Pathname _dbPath;
00043 rpmdb _db;
00044 shared_ptr<RpmException> _error;
00045
00046 friend ostream & operator<<( ostream & str, const D & obj )
00047 {
00048 str << "{" << obj._error << "(" << obj._root << ")" << obj._dbPath << "}";
00049 return str;
00050 }
00051
00052 D( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
00053 : _root ( root_r )
00054 , _dbPath( dbPath_r )
00055 , _db ( 0 )
00056 {
00057 _error.reset();
00058
00059 ::addMacro( NULL, "_dbpath", NULL, _dbPath.asString().c_str(), RMIL_CMDLINE );
00060 const char * root = ( _root == "/" ? NULL : _root.asString().c_str() );
00061 int perms = 0644;
00062
00063
00064 PathInfo master( _root + _dbPath + "Packages" );
00065 if ( ! master.isFile() )
00066 {
00067
00068 int res = ::rpmdbInit( root, perms );
00069 if ( res )
00070 {
00071 ERR << "rpmdbInit error(" << res << "): " << *this << endl;
00072 _error = shared_ptr<RpmInitException>(new RpmInitException(_root, _dbPath));
00073 ZYPP_THROW(*_error);
00074 }
00075 }
00076
00077
00078 int res = ::rpmdbOpen( root, &_db, (readonly_r ? O_RDONLY : O_RDWR ), perms );
00079 if ( res || !_db )
00080 {
00081 if ( _db )
00082 {
00083 ::rpmdbClose( _db );
00084 _db = 0;
00085 }
00086 ERR << "rpmdbOpen error(" << res << "): " << *this << endl;
00087 _error = shared_ptr<RpmDbOpenException>(new RpmDbOpenException(_root, _dbPath));
00088 ZYPP_THROW(*_error);
00089 return;
00090 }
00091
00092 DBG << "DBACCESS " << *this << endl;
00093 }
00094
00095 ~D()
00096 {
00097 if ( _db )
00098 {
00099 ::rpmdbClose( _db );
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 {
00133 ERR << "rpmReadConfigFiles returned " << rc << endl;
00134 return false;
00135 }
00136
00137 initialized = true;
00138
00139 #define OUTVAL(n) << " (" #n ":" << expand( "%{" #n "}" ) << ")"
00140 MIL << "librpm init done:"
00141 OUTVAL(_target)
00142 OUTVAL(_dbpath)
00143 << endl;
00144 #undef OUTVAL
00145 return initialized;
00146 }
00147
00149
00150
00151
00152
00153
00154 std::string librpmDb::expand( const std::string & macro_r )
00155 {
00156 if ( ! globalInit() )
00157 return macro_r;
00158
00159 char * val = ::rpmExpand( macro_r.c_str(), NULL );
00160 if ( !val )
00161 return "";
00162
00163 string ret( val );
00164 free( val );
00165 return ret;
00166 }
00167
00169
00170
00171
00172
00173
00174 librpmDb * librpmDb::newLibrpmDb( Pathname root_r, Pathname dbPath_r, bool readonly_r )
00175 {
00176
00177 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
00178 {
00179 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
00180 }
00181
00182
00183 if ( ! globalInit() )
00184 {
00185 ZYPP_THROW(GlobalRpmInitException());
00186 }
00187
00188
00189 librpmDb * ret = 0;
00190 try
00191 {
00192 ret = new librpmDb( root_r, dbPath_r, readonly_r );
00193 }
00194 catch (const RpmException & excpt_r)
00195 {
00196 ZYPP_CAUGHT(excpt_r);
00197 delete ret;
00198 ret = 0;
00199 ZYPP_RETHROW(excpt_r);
00200 }
00201 return ret;
00202 }
00203
00205
00206
00207
00208
00209
00210 void librpmDb::dbAccess( const Pathname & root_r, const Pathname & dbPath_r )
00211 {
00212
00213 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
00214 {
00215 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
00216 }
00217
00218 if ( _defaultDb )
00219 {
00220
00221 if ( _defaultRoot == root_r && _defaultDbPath == dbPath_r )
00222 return;
00223 else
00224 {
00225 ZYPP_THROW(RpmDbAlreadyOpenException(_defaultRoot, _defaultDbPath, root_r, dbPath_r));
00226 }
00227 }
00228
00229
00230 _defaultRoot = root_r;
00231 _defaultDbPath = dbPath_r;
00232 MIL << "Set new database location: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
00233
00234 return dbAccess();
00235 }
00236
00238
00239
00240
00241
00242
00243 void librpmDb::dbAccess()
00244 {
00245 if ( _dbBlocked )
00246 {
00247 ZYPP_THROW(RpmAccessBlockedException(_defaultRoot, _defaultDbPath));
00248 }
00249
00250 if ( !_defaultDb )
00251 {
00252
00253 _defaultDb = newLibrpmDb( _defaultRoot, _defaultDbPath, true );
00254 }
00255 }
00256
00258
00259
00260
00261
00262
00263 void librpmDb::dbAccess( librpmDb::constPtr & ptr_r )
00264 {
00265 try
00266 {
00267 dbAccess();
00268 }
00269 catch (const RpmException & excpt_r)
00270 {
00271 ZYPP_CAUGHT(excpt_r);
00272 ptr_r = 0;
00273 ZYPP_RETHROW(excpt_r);
00274 }
00275 ptr_r = _defaultDb;
00276 }
00277
00279
00280
00281
00282
00283
00284 unsigned librpmDb::dbRelease( bool force_r )
00285 {
00286 if ( !_defaultDb )
00287 {
00288 return 0;
00289 }
00290
00291 unsigned outstanding = _defaultDb->refCount() - 1;
00292
00293 switch ( outstanding )
00294 {
00295 default:
00296 if ( !force_r )
00297 {
00298 DBG << "dbRelease: keep access, outstanding " << outstanding << endl;
00299 break;
00300 }
00301
00302 case 0:
00303 DBG << "dbRelease: release" << (force_r && outstanding ? "(forced)" : "")
00304 << ", outstanding " << outstanding << endl;
00305
00306 _defaultDb->_d._error = shared_ptr<RpmAccessBlockedException>(new RpmAccessBlockedException(_defaultDb->_d._root, _defaultDb->_d._dbPath));
00307
00308 _defaultDb = 0;
00309 break;
00310 }
00311
00312 return outstanding;
00313 }
00314
00316
00317
00318
00319
00320
00321 unsigned librpmDb::blockAccess()
00322 {
00323 MIL << "Block access" << endl;
00324 _dbBlocked = true;
00325 return dbRelease( true );
00326 }
00327
00329
00330
00331
00332
00333
00334 void librpmDb::unblockAccess()
00335 {
00336 MIL << "Unblock access" << endl;
00337 _dbBlocked = false;
00338 }
00339
00341
00342
00343
00344
00345
00346 ostream & librpmDb::dumpState( ostream & str )
00347 {
00348 if ( !_defaultDb )
00349 {
00350 return str << "[librpmDb " << (_dbBlocked?"BLOCKED":"CLOSED") << " " << stringPath( _defaultRoot, _defaultDbPath ) << "]";
00351 }
00352 return str << "[" << _defaultDb << "]";
00353 }
00354
00356
00357
00358
00360
00362
00363
00364
00365
00366
00367
00368
00369 librpmDb::librpmDb( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
00370 : _d( * new D( root_r, dbPath_r, readonly_r ) )
00371 {}
00372
00374
00375
00376
00377
00378
00379
00380
00381 librpmDb::~librpmDb()
00382 {
00383 delete &_d;
00384 }
00385
00387
00388
00389
00390
00391
00392 void librpmDb::unref_to( unsigned refCount_r ) const
00393 {
00394 if ( refCount_r == 1 )
00395 {
00396 dbRelease();
00397 }
00398 }
00399
00401
00402
00403
00404
00405
00406 const Pathname & librpmDb::root() const
00407 {
00408 return _d._root;
00409 }
00410
00412
00413
00414
00415
00416
00417 const Pathname & librpmDb::dbPath() const
00418 {
00419 return _d._dbPath;
00420 }
00421
00423
00424
00425
00426
00427
00428 shared_ptr<RpmException> librpmDb::error() const
00429 {
00430 return _d._error;
00431 }
00432
00434
00435
00436
00437
00438
00439 bool librpmDb::empty() const
00440 {
00441 return( valid() && ! *db_const_iterator( this ) );
00442 }
00443
00445
00446
00447
00448
00449
00450 unsigned librpmDb::size() const
00451 {
00452 unsigned count = 0;
00453 if ( valid() )
00454 {
00455 #if defined(_RPM_4_4_COMPAT) || defined(_RPM_5)
00456
00457 int dbi = ::rpmdbOpen("/", &_d._db, O_RDONLY, 0);
00458 if (dbi == 0) {
00459 rpmdbMatchIterator mi = ::rpmdbInitIterator(_d._db, RPMTAG_NAME, NULL, 0);
00460 if (mi != NULL) {
00461 for (;;) {
00462 Header rpmHeader = ::rpmdbNextIterator(mi);
00463 if (rpmHeader != NULL)
00464 ++count;
00465 }
00466 }
00467 ::rpmdbClose(_d._db);
00468 }
00469 #else
00470 dbiIndex dbi = dbiOpen( _d._db, RPMTAG_NAME, 0 );
00471 if ( dbi )
00472 {
00473 DBC * dbcursor = 0;
00474 dbiCopen( dbi, dbi->dbi_txnid, &dbcursor, 0 );
00475
00476 DBT key, data;
00477 memset( &key, 0, sizeof(key) );
00478 memset( &data, 0, sizeof(data) );
00479 while ( dbiGet( dbi, dbcursor, &key, &data, DB_NEXT ) == 0 )
00480 count += data.size / dbi->dbi_jlen;
00481
00482 dbiCclose( dbi, dbcursor, 0 );
00483
00484 }
00485 #endif
00486 }
00487 return count;
00488 }
00489
00491
00492
00493
00494
00495
00496 void * librpmDb::dont_call_it() const
00497 {
00498 return _d._db;
00499 }
00500
00502
00503
00504
00505
00506
00507
00508
00509 ostream & librpmDb::dumpOn( ostream & str ) const
00510 {
00511 ReferenceCounted::dumpOn( str ) << _d;
00512 return str;
00513 }
00514
00516
00517
00518
00520
00522
00523
00524
00525
00526
00527 librpmDb::DbDirInfo::DbDirInfo( const Pathname & root_r, const Pathname & dbPath_r )
00528 : _root( root_r )
00529 , _dbPath( dbPath_r )
00530 {
00531
00532 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
00533 {
00534 ERR << "Relative path for root(" << _root << ") or dbPath(" << _dbPath << ")" << endl;
00535 }
00536 else
00537 {
00538 _dbDir ( _root + _dbPath );
00539 _dbV4 ( _dbDir.path() + "Packages" );
00540 _dbV3 ( _dbDir.path() + "packages.rpm" );
00541 _dbV3ToV4( _dbDir.path() + "packages.rpm3" );
00542 DBG << *this << endl;
00543 }
00544 }
00545
00547
00548
00549
00550
00551
00552 void librpmDb::DbDirInfo::restat()
00553 {
00554 _dbDir();
00555 _dbV4();
00556 _dbV3();
00557 _dbV3ToV4();
00558 DBG << *this << endl;
00559 }
00560
00561
00562
00563
00564
00565
00566
00567 std::ostream & operator<<( std::ostream & str, const librpmDb::DbDirInfo & obj )
00568 {
00569 if ( obj.illegalArgs() )
00570 {
00571 str << "ILLEGAL: '(" << obj.root() << ")" << obj.dbPath() << "'";
00572 }
00573 else
00574 {
00575 str << "'(" << obj.root() << ")" << obj.dbPath() << "':" << endl;
00576 str << " Dir: " << obj._dbDir << endl;
00577 str << " V4: " << obj._dbV4 << endl;
00578 str << " V3: " << obj._dbV3 << endl;
00579 str << " V3ToV4: " << obj._dbV3ToV4;
00580 }
00581 return str;
00582 }
00583
00585
00586
00590 class librpmDb::db_const_iterator::D
00591 {
00592 D & operator=( const D & );
00593 D ( const D & );
00594 public:
00595
00596 librpmDb::constPtr _dbptr;
00597 shared_ptr<RpmException> _dberr;
00598
00599 RpmHeader::constPtr _hptr;
00600 rpmdbMatchIterator _mi;
00601
00602 D( librpmDb::constPtr dbptr_r )
00603 : _dbptr( dbptr_r )
00604 , _mi( 0 )
00605 {
00606 if ( !_dbptr )
00607 {
00608 try
00609 {
00610 librpmDb::dbAccess( _dbptr );
00611 }
00612 catch (const RpmException & excpt_r)
00613 {
00614 ZYPP_CAUGHT(excpt_r);
00615 }
00616 if ( !_dbptr )
00617 {
00618 WAR << "No database access: " << _dberr << endl;
00619 }
00620 }
00621 else
00622 {
00623 destroy();
00624 }
00625 }
00626
00627 ~D()
00628 {
00629 if ( _mi )
00630 {
00631 ::rpmdbFreeIterator( _mi );
00632 }
00633 }
00634
00639 bool create( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
00640 {
00641 destroy();
00642 if ( ! _dbptr )
00643 return false;
00644 _mi = ::rpmdbInitIterator( _dbptr->_d._db, rpmTag(rpmtag), keyp, keylen );
00645 return _mi;
00646 }
00647
00652 bool destroy()
00653 {
00654 if ( _mi )
00655 {
00656 _mi = ::rpmdbFreeIterator( _mi );
00657 _hptr = 0;
00658 }
00659 if ( _dbptr && _dbptr->error() )
00660 {
00661 _dberr = _dbptr->error();
00662 WAR << "Lost database access: " << _dberr << endl;
00663 _dbptr = 0;
00664 }
00665 return false;
00666 }
00667
00672 bool advance()
00673 {
00674 if ( !_mi )
00675 return false;
00676 Header h = ::rpmdbNextIterator( _mi );
00677 if ( ! h )
00678 {
00679 destroy();
00680 return false;
00681 }
00682 _hptr = new RpmHeader( h );
00683 return true;
00684 }
00685
00689 bool init( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
00690 {
00691 if ( ! create( rpmtag, keyp, keylen ) )
00692 return false;
00693 return advance();
00694 }
00695
00700 bool set( int off_r )
00701 {
00702 if ( ! create( RPMDBI_PACKAGES ) )
00703 return false;
00704 #warning TESTCASE: rpmdbAppendIterator and (non)sequential access?
00705 ::rpmdbAppendIterator( _mi, &off_r, 1 );
00706 return advance();
00707 }
00708
00709 unsigned offset()
00710 {
00711 return( _mi ? ::rpmdbGetIteratorOffset( _mi ) : 0 );
00712 }
00713
00714 int size()
00715 {
00716 if ( !_mi )
00717 return 0;
00718 int ret = ::rpmdbGetIteratorCount( _mi );
00719 #warning TESTCASE: rpmdbGetIteratorCount returns 0 on sequential access?
00720 return( ret ? ret : -1 );
00721 }
00722 };
00723
00725
00727
00728
00729
00731
00733
00734
00735
00736
00737
00738 librpmDb::db_const_iterator::db_const_iterator( librpmDb::constPtr dbptr_r )
00739 : _d( * new D( dbptr_r ) )
00740 {
00741 findAll();
00742 }
00743
00745
00746
00747
00748
00749
00750 librpmDb::db_const_iterator::~db_const_iterator()
00751 {
00752 delete &_d;
00753 }
00754
00756
00757
00758
00759
00760
00761 void librpmDb::db_const_iterator::operator++()
00762 {
00763 _d.advance();
00764 }
00765
00767
00768
00769
00770
00771
00772 unsigned librpmDb::db_const_iterator::dbHdrNum() const
00773 {
00774 return _d.offset();
00775 }
00776
00778
00779
00780
00781
00782
00783 const RpmHeader::constPtr & librpmDb::db_const_iterator::operator*() const
00784 {
00785 return _d._hptr;
00786 }
00787
00789
00790
00791
00792
00793
00794 shared_ptr<RpmException> librpmDb::db_const_iterator::dbError() const
00795 {
00796 if ( _d._dbptr )
00797 return _d._dbptr->error();
00798
00799 return _d._dberr;
00800 }
00801
00802
00803
00804
00805
00806
00807
00808 ostream & operator<<( ostream & str, const librpmDb::db_const_iterator & obj )
00809 {
00810 str << "db_const_iterator(" << obj._d._dbptr
00811 << " Size:" << obj._d.size()
00812 << " HdrNum:" << obj._d.offset()
00813 << ")";
00814 return str;
00815 }
00816
00818
00819
00820
00821
00822
00823 bool librpmDb::db_const_iterator::findAll()
00824 {
00825 return _d.init( RPMDBI_PACKAGES );
00826 }
00827
00829
00830
00831
00832
00833
00834 bool librpmDb::db_const_iterator::findByFile( const std::string & file_r )
00835 {
00836 return _d.init( RPMTAG_BASENAMES, file_r.c_str() );
00837 }
00838
00840
00841
00842
00843
00844
00845 bool librpmDb::db_const_iterator::findByProvides( const std::string & tag_r )
00846 {
00847 return _d.init( RPMTAG_PROVIDENAME, tag_r.c_str() );
00848 }
00849
00851
00852
00853
00854
00855
00856 bool librpmDb::db_const_iterator::findByRequiredBy( const std::string & tag_r )
00857 {
00858 return _d.init( RPMTAG_REQUIRENAME, tag_r.c_str() );
00859 }
00860
00862
00863
00864
00865
00866
00867 bool librpmDb::db_const_iterator::findByConflicts( const std::string & tag_r )
00868 {
00869 return _d.init( RPMTAG_CONFLICTNAME, tag_r.c_str() );
00870 }
00871
00873
00874
00875
00876
00877
00878 bool librpmDb::db_const_iterator::findByName( const string & name_r )
00879 {
00880 return _d.init( RPMTAG_NAME, name_r.c_str() );
00881 }
00882
00884
00885
00886
00887
00888
00889 bool librpmDb::db_const_iterator::findPackage( const string & name_r )
00890 {
00891 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
00892 return false;
00893
00894 if ( _d.size() == 1 )
00895 return true;
00896
00897
00898 int match = 0;
00899 time_t itime = 0;
00900 for ( ; operator*(); operator++() )
00901 {
00902 if ( operator*()->tag_installtime() > itime )
00903 {
00904 match = _d.offset();
00905 itime = operator*()->tag_installtime();
00906 }
00907 }
00908
00909 return _d.set( match );
00910 }
00911
00913
00914
00915
00916
00917
00918 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r, const Edition & ed_r )
00919 {
00920 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
00921 return false;
00922
00923 for ( ; operator*(); operator++() )
00924 {
00925 if ( ed_r == operator*()->tag_edition() )
00926 {
00927 int match = _d.offset();
00928 return _d.set( match );
00929 }
00930 }
00931
00932 return _d.destroy();
00933 }
00934
00936
00937
00938
00939
00940
00941 bool librpmDb::db_const_iterator::findPackage( const Package::constPtr & which_r )
00942 {
00943 if ( ! which_r )
00944 return _d.destroy();
00945
00946 return findPackage( which_r->name(), which_r->edition() );
00947 }
00948
00949 }
00950 }
00951 }