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