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
00138 ::addMacro( NULL, "_rpmdb_rebuild", NULL, "%{nil}", RMIL_CMDLINE );
00139
00140 initialized = true;
00141
00142 #define OUTVAL(n) << " (" #n ":" << expand( "%{" #n "}" ) << ")"
00143 MIL << "librpm init done:"
00144 OUTVAL(_target)
00145 OUTVAL(_dbpath)
00146 << endl;
00147 #undef OUTVAL
00148 return initialized;
00149 }
00150
00152
00153
00154
00155
00156
00157 std::string librpmDb::expand( const std::string & macro_r )
00158 {
00159 if ( ! globalInit() )
00160 return macro_r;
00161
00162 char * val = ::rpmExpand( macro_r.c_str(), NULL );
00163 if ( !val )
00164 return "";
00165
00166 string ret( val );
00167 free( val );
00168 return ret;
00169 }
00170
00172
00173
00174
00175
00176
00177 librpmDb * librpmDb::newLibrpmDb( Pathname root_r, Pathname dbPath_r, bool readonly_r )
00178 {
00179
00180 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
00181 {
00182 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
00183 }
00184
00185
00186 if ( ! globalInit() )
00187 {
00188 ZYPP_THROW(GlobalRpmInitException());
00189 }
00190
00191
00192 librpmDb * ret = 0;
00193 try
00194 {
00195 ret = new librpmDb( root_r, dbPath_r, readonly_r );
00196 }
00197 catch (const RpmException & excpt_r)
00198 {
00199 ZYPP_CAUGHT(excpt_r);
00200 delete ret;
00201 ret = 0;
00202 ZYPP_RETHROW(excpt_r);
00203 }
00204 return ret;
00205 }
00206
00208
00209
00210
00211
00212
00213 void librpmDb::dbAccess( const Pathname & root_r, const Pathname & dbPath_r )
00214 {
00215
00216 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
00217 {
00218 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
00219 }
00220
00221 if ( _defaultDb )
00222 {
00223
00224 if ( _defaultRoot == root_r && _defaultDbPath == dbPath_r )
00225 return;
00226 else
00227 {
00228 ZYPP_THROW(RpmDbAlreadyOpenException(_defaultRoot, _defaultDbPath, root_r, dbPath_r));
00229 }
00230 }
00231
00232
00233 _defaultRoot = root_r;
00234 _defaultDbPath = dbPath_r;
00235 MIL << "Set new database location: " << stringPath( _defaultRoot, _defaultDbPath ) << endl;
00236
00237 return dbAccess();
00238 }
00239
00241
00242
00243
00244
00245
00246 void librpmDb::dbAccess()
00247 {
00248 if ( _dbBlocked )
00249 {
00250 ZYPP_THROW(RpmAccessBlockedException(_defaultRoot, _defaultDbPath));
00251 }
00252
00253 if ( !_defaultDb )
00254 {
00255
00256 _defaultDb = newLibrpmDb( _defaultRoot, _defaultDbPath, true );
00257 }
00258 }
00259
00261
00262
00263
00264
00265
00266 void librpmDb::dbAccess( librpmDb::constPtr & ptr_r )
00267 {
00268 try
00269 {
00270 dbAccess();
00271 }
00272 catch (const RpmException & excpt_r)
00273 {
00274 ZYPP_CAUGHT(excpt_r);
00275 ptr_r = 0;
00276 ZYPP_RETHROW(excpt_r);
00277 }
00278 ptr_r = _defaultDb;
00279 }
00280
00282
00283
00284
00285
00286
00287 unsigned librpmDb::dbRelease( bool force_r )
00288 {
00289 if ( !_defaultDb )
00290 {
00291 return 0;
00292 }
00293
00294 unsigned outstanding = _defaultDb->refCount() - 1;
00295
00296 switch ( outstanding )
00297 {
00298 default:
00299 if ( !force_r )
00300 {
00301 DBG << "dbRelease: keep access, outstanding " << outstanding << endl;
00302 break;
00303 }
00304
00305 case 0:
00306 DBG << "dbRelease: release" << (force_r && outstanding ? "(forced)" : "")
00307 << ", outstanding " << outstanding << endl;
00308
00309 _defaultDb->_d._error = shared_ptr<RpmAccessBlockedException>(new RpmAccessBlockedException(_defaultDb->_d._root, _defaultDb->_d._dbPath));
00310
00311 _defaultDb = 0;
00312 break;
00313 }
00314
00315 return outstanding;
00316 }
00317
00319
00320
00321
00322
00323
00324 unsigned librpmDb::blockAccess()
00325 {
00326 MIL << "Block access" << endl;
00327 _dbBlocked = true;
00328 return dbRelease( true );
00329 }
00330
00332
00333
00334
00335
00336
00337 void librpmDb::unblockAccess()
00338 {
00339 MIL << "Unblock access" << endl;
00340 _dbBlocked = false;
00341 }
00342
00344
00345
00346
00347
00348
00349 ostream & librpmDb::dumpState( ostream & str )
00350 {
00351 if ( !_defaultDb )
00352 {
00353 return str << "[librpmDb " << (_dbBlocked?"BLOCKED":"CLOSED") << " " << stringPath( _defaultRoot, _defaultDbPath ) << "]";
00354 }
00355 return str << "[" << _defaultDb << "]";
00356 }
00357
00359
00360
00361
00363
00365
00366
00367
00368
00369
00370
00371
00372 librpmDb::librpmDb( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
00373 : _d( * new D( root_r, dbPath_r, readonly_r ) )
00374 {}
00375
00377
00378
00379
00380
00381
00382
00383
00384 librpmDb::~librpmDb()
00385 {
00386 delete &_d;
00387 }
00388
00390
00391
00392
00393
00394
00395 void librpmDb::unref_to( unsigned refCount_r ) const
00396 {
00397 if ( refCount_r == 1 )
00398 {
00399 dbRelease();
00400 }
00401 }
00402
00404
00405
00406
00407
00408
00409 const Pathname & librpmDb::root() const
00410 {
00411 return _d._root;
00412 }
00413
00415
00416
00417
00418
00419
00420 const Pathname & librpmDb::dbPath() const
00421 {
00422 return _d._dbPath;
00423 }
00424
00426
00427
00428
00429
00430
00431 shared_ptr<RpmException> librpmDb::error() const
00432 {
00433 return _d._error;
00434 }
00435
00437
00438
00439
00440
00441
00442 bool librpmDb::empty() const
00443 {
00444 return( valid() && ! *db_const_iterator( this ) );
00445 }
00446
00448
00449
00450
00451
00452
00453 unsigned librpmDb::size() const
00454 {
00455 unsigned count = 0;
00456 if ( valid() )
00457 {
00458 dbiIndex dbi = dbiOpen( _d._db, RPMTAG_NAME, 0 );
00459 if ( dbi )
00460 {
00461 DBC * dbcursor = 0;
00462 dbiCopen( dbi, dbi->dbi_txnid, &dbcursor, 0 );
00463
00464 DBT key, data;
00465 memset( &key, 0, sizeof(key) );
00466 memset( &data, 0, sizeof(data) );
00467 while ( dbiGet( dbi, dbcursor, &key, &data, DB_NEXT ) == 0 )
00468 count += data.size / dbi->dbi_jlen;
00469
00470 dbiCclose( dbi, dbcursor, 0 );
00471
00472 }
00473 }
00474 return count;
00475 }
00476
00478
00479
00480
00481
00482
00483 void * librpmDb::dont_call_it() const
00484 {
00485 return _d._db;
00486 }
00487
00489
00490
00491
00492
00493
00494
00495
00496 ostream & librpmDb::dumpOn( ostream & str ) const
00497 {
00498 ReferenceCounted::dumpOn( str ) << _d;
00499 return str;
00500 }
00501
00503
00504
00505
00507
00509
00510
00511
00512
00513
00514 librpmDb::DbDirInfo::DbDirInfo( const Pathname & root_r, const Pathname & dbPath_r )
00515 : _root( root_r )
00516 , _dbPath( dbPath_r )
00517 {
00518
00519 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
00520 {
00521 ERR << "Relative path for root(" << _root << ") or dbPath(" << _dbPath << ")" << endl;
00522 }
00523 else
00524 {
00525 _dbDir ( _root + _dbPath );
00526 _dbV4 ( _dbDir.path() + "Packages" );
00527 _dbV3 ( _dbDir.path() + "packages.rpm" );
00528 _dbV3ToV4( _dbDir.path() + "packages.rpm3" );
00529 DBG << *this << endl;
00530 }
00531 }
00532
00534
00535
00536
00537
00538
00539 void librpmDb::DbDirInfo::restat()
00540 {
00541 _dbDir();
00542 _dbV4();
00543 _dbV3();
00544 _dbV3ToV4();
00545 DBG << *this << endl;
00546 }
00547
00548
00549
00550
00551
00552
00553
00554 std::ostream & operator<<( std::ostream & str, const librpmDb::DbDirInfo & obj )
00555 {
00556 if ( obj.illegalArgs() )
00557 {
00558 str << "ILLEGAL: '(" << obj.root() << ")" << obj.dbPath() << "'";
00559 }
00560 else
00561 {
00562 str << "'(" << obj.root() << ")" << obj.dbPath() << "':" << endl;
00563 str << " Dir: " << obj._dbDir << endl;
00564 str << " V4: " << obj._dbV4 << endl;
00565 str << " V3: " << obj._dbV3 << endl;
00566 str << " V3ToV4: " << obj._dbV3ToV4;
00567 }
00568 return str;
00569 }
00570
00572
00573
00577 class librpmDb::db_const_iterator::D
00578 {
00579 D & operator=( const D & );
00580 D ( const D & );
00581 public:
00582
00583 librpmDb::constPtr _dbptr;
00584 shared_ptr<RpmException> _dberr;
00585
00586 RpmHeader::constPtr _hptr;
00587 rpmdbMatchIterator _mi;
00588
00589 D( librpmDb::constPtr dbptr_r )
00590 : _dbptr( dbptr_r )
00591 , _mi( 0 )
00592 {
00593 if ( !_dbptr )
00594 {
00595 try
00596 {
00597 librpmDb::dbAccess( _dbptr );
00598 }
00599 catch (const RpmException & excpt_r)
00600 {
00601 ZYPP_CAUGHT(excpt_r);
00602 }
00603 if ( !_dbptr )
00604 {
00605 WAR << "No database access: " << _dberr << endl;
00606 }
00607 }
00608 else
00609 {
00610 destroy();
00611 }
00612 }
00613
00614 ~D()
00615 {
00616 if ( _mi )
00617 {
00618 ::rpmdbFreeIterator( _mi );
00619 }
00620 }
00621
00626 bool create( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
00627 {
00628 destroy();
00629 if ( ! _dbptr )
00630 return false;
00631 _mi = ::rpmdbInitIterator( _dbptr->_d._db, rpmTag(rpmtag), keyp, keylen );
00632 return _mi;
00633 }
00634
00639 bool destroy()
00640 {
00641 if ( _mi )
00642 {
00643 _mi = ::rpmdbFreeIterator( _mi );
00644 _hptr = 0;
00645 }
00646 if ( _dbptr && _dbptr->error() )
00647 {
00648 _dberr = _dbptr->error();
00649 WAR << "Lost database access: " << _dberr << endl;
00650 _dbptr = 0;
00651 }
00652 return false;
00653 }
00654
00659 bool advance()
00660 {
00661 if ( !_mi )
00662 return false;
00663 Header h = ::rpmdbNextIterator( _mi );
00664 if ( ! h )
00665 {
00666 destroy();
00667 return false;
00668 }
00669 _hptr = new RpmHeader( h );
00670 return true;
00671 }
00672
00676 bool init( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
00677 {
00678 if ( ! create( rpmtag, keyp, keylen ) )
00679 return false;
00680 return advance();
00681 }
00682
00687 bool set( int off_r )
00688 {
00689 if ( ! create( RPMDBI_PACKAGES ) )
00690 return false;
00691 #warning TESTCASE: rpmdbAppendIterator and (non)sequential access?
00692 ::rpmdbAppendIterator( _mi, &off_r, 1 );
00693 return advance();
00694 }
00695
00696 unsigned offset()
00697 {
00698 return( _mi ? ::rpmdbGetIteratorOffset( _mi ) : 0 );
00699 }
00700
00701 int size()
00702 {
00703 if ( !_mi )
00704 return 0;
00705 int ret = ::rpmdbGetIteratorCount( _mi );
00706 #warning TESTCASE: rpmdbGetIteratorCount returns 0 on sequential access?
00707 return( ret ? ret : -1 );
00708 }
00709 };
00710
00712
00714
00715
00716
00718
00720
00721
00722
00723
00724
00725 librpmDb::db_const_iterator::db_const_iterator( librpmDb::constPtr dbptr_r )
00726 : _d( * new D( dbptr_r ) )
00727 {
00728 findAll();
00729 }
00730
00732
00733
00734
00735
00736
00737 librpmDb::db_const_iterator::~db_const_iterator()
00738 {
00739 delete &_d;
00740 }
00741
00743
00744
00745
00746
00747
00748 void librpmDb::db_const_iterator::operator++()
00749 {
00750 _d.advance();
00751 }
00752
00754
00755
00756
00757
00758
00759 unsigned librpmDb::db_const_iterator::dbHdrNum() const
00760 {
00761 return _d.offset();
00762 }
00763
00765
00766
00767
00768
00769
00770 const RpmHeader::constPtr & librpmDb::db_const_iterator::operator*() const
00771 {
00772 return _d._hptr;
00773 }
00774
00776
00777
00778
00779
00780
00781 shared_ptr<RpmException> librpmDb::db_const_iterator::dbError() const
00782 {
00783 if ( _d._dbptr )
00784 return _d._dbptr->error();
00785
00786 return _d._dberr;
00787 }
00788
00789
00790
00791
00792
00793
00794
00795 ostream & operator<<( ostream & str, const librpmDb::db_const_iterator & obj )
00796 {
00797 str << "db_const_iterator(" << obj._d._dbptr
00798 << " Size:" << obj._d.size()
00799 << " HdrNum:" << obj._d.offset()
00800 << ")";
00801 return str;
00802 }
00803
00805
00806
00807
00808
00809
00810 bool librpmDb::db_const_iterator::findAll()
00811 {
00812 return _d.init( RPMDBI_PACKAGES );
00813 }
00814
00816
00817
00818
00819
00820
00821 bool librpmDb::db_const_iterator::findByFile( const std::string & file_r )
00822 {
00823 return _d.init( RPMTAG_BASENAMES, file_r.c_str() );
00824 }
00825
00827
00828
00829
00830
00831
00832 bool librpmDb::db_const_iterator::findByProvides( const std::string & tag_r )
00833 {
00834 return _d.init( RPMTAG_PROVIDENAME, tag_r.c_str() );
00835 }
00836
00838
00839
00840
00841
00842
00843 bool librpmDb::db_const_iterator::findByRequiredBy( const std::string & tag_r )
00844 {
00845 return _d.init( RPMTAG_REQUIRENAME, tag_r.c_str() );
00846 }
00847
00849
00850
00851
00852
00853
00854 bool librpmDb::db_const_iterator::findByConflicts( const std::string & tag_r )
00855 {
00856 return _d.init( RPMTAG_CONFLICTNAME, tag_r.c_str() );
00857 }
00858
00860
00861
00862
00863
00864
00865 bool librpmDb::db_const_iterator::findByName( const string & name_r )
00866 {
00867 return _d.init( RPMTAG_NAME, name_r.c_str() );
00868 }
00869
00871
00872
00873
00874
00875
00876 bool librpmDb::db_const_iterator::findPackage( const string & name_r )
00877 {
00878 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
00879 return false;
00880
00881 if ( _d.size() == 1 )
00882 return true;
00883
00884
00885 int match = 0;
00886 time_t itime = 0;
00887 for ( ; operator*(); operator++() )
00888 {
00889 if ( operator*()->tag_installtime() > itime )
00890 {
00891 match = _d.offset();
00892 itime = operator*()->tag_installtime();
00893 }
00894 }
00895
00896 return _d.set( match );
00897 }
00898
00900
00901
00902
00903
00904
00905 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r, const Edition & ed_r )
00906 {
00907 if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
00908 return false;
00909
00910 for ( ; operator*(); operator++() )
00911 {
00912 if ( ed_r == operator*()->tag_edition() )
00913 {
00914 int match = _d.offset();
00915 return _d.set( match );
00916 }
00917 }
00918
00919 return _d.destroy();
00920 }
00921
00923
00924
00925
00926
00927
00928 bool librpmDb::db_const_iterator::findPackage( const Package::constPtr & which_r )
00929 {
00930 if ( ! which_r )
00931 return _d.destroy();
00932
00933 return findPackage( which_r->name(), which_r->edition() );
00934 }
00935
00936 }
00937 }
00938 }