00001
00002
00003
00004
00005
00006
00007
00008
00012 #include "librpm.h"
00013
00014 #include <cstdlib>
00015 #include <cstdio>
00016 #include <ctime>
00017
00018 #include <iostream>
00019 #include <fstream>
00020 #include <list>
00021 #include <map>
00022 #include <set>
00023 #include <string>
00024 #include <vector>
00025 #include <algorithm>
00026
00027 #include "zypp/base/Logger.h"
00028
00029 #include "zypp/Date.h"
00030 #include "zypp/Pathname.h"
00031 #include "zypp/PathInfo.h"
00032
00033 #include "zypp/target/rpm/RpmDb.h"
00034 #include "zypp/target/rpm/RpmCallbacks.h"
00035
00036 #include "zypp/target/rpm/librpmDb.h"
00037 #include "zypp/target/rpm/RpmPackageImpl.h"
00038 #include "zypp/target/rpm/RpmException.h"
00039 #include "zypp/CapSet.h"
00040 #include "zypp/CapFactory.h"
00041 #include "zypp/KeyRing.h"
00042 #include "zypp/ZYppFactory.h"
00043 #include "zypp/TmpPath.h"
00044
00045 #ifndef _
00046 #define _(X) X
00047 #endif
00048
00049 using namespace std;
00050 using namespace zypp::filesystem;
00051
00052 namespace zypp {
00053 namespace target {
00054 namespace rpm {
00055
00056 struct KeyRingSignalReceiver : callback::ReceiveReport<KeyRingSignals>
00057 {
00058 KeyRingSignalReceiver(RpmDb &rpmdb) : _rpmdb(rpmdb)
00059 {
00060 connect();
00061 }
00062
00063 ~KeyRingSignalReceiver()
00064 {
00065 disconnect();
00066 }
00067
00068 virtual void trustedKeyAdded( const KeyRing &keyring, const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
00069 {
00070 MIL << "trusted key added to zypp Keyring. Syncronizing keys with rpm keyring" << std::endl;
00071 _rpmdb.importZyppKeyRingTrustedKeys();
00072 _rpmdb.exportTrustedKeysInZyppKeyRing();
00073 }
00074
00075 virtual void trustedKeyRemoved( const KeyRing &keyring, const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
00076 {
00077
00078 }
00079
00080 RpmDb &_rpmdb;
00081 };
00082
00083 static shared_ptr<KeyRingSignalReceiver> sKeyRingReceiver;
00084
00085 unsigned diffFiles(const std::string file1, const std::string file2, std::string& out, int maxlines)
00086 {
00087 const char* argv[] =
00088 {
00089 "diff",
00090 "-u",
00091 file1.c_str(),
00092 file2.c_str(),
00093 NULL
00094 };
00095 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00096
00097
00098
00099
00100 string line;
00101 int count = 0;
00102 for(line = prog.receiveLine(), count=0;
00103 !line.empty();
00104 line = prog.receiveLine(), count++ )
00105 {
00106 if(maxlines<0?true:count<maxlines)
00107 out+=line;
00108 }
00109
00110 return prog.close();
00111 }
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 inline string stringPath( const Pathname & root_r, const Pathname & sub_r )
00122 {
00123 return librpmDb::stringPath( root_r, sub_r );
00124 }
00125
00126
00127
00128
00129
00130
00131
00132 ostream & operator<<( ostream & str, const RpmDb::DbStateInfoBits & obj )
00133 {
00134 if ( obj == RpmDb::DbSI_NO_INIT ) {
00135 str << "NO_INIT";
00136 } else {
00137 #define ENUM_OUT(B,C) str << ( obj & RpmDb::B ? C : '-' )
00138 str << "V4(";
00139 ENUM_OUT( DbSI_HAVE_V4, 'X' );
00140 ENUM_OUT( DbSI_MADE_V4, 'c' );
00141 ENUM_OUT( DbSI_MODIFIED_V4, 'm' );
00142 str << ")V3(";
00143 ENUM_OUT( DbSI_HAVE_V3, 'X' );
00144 ENUM_OUT( DbSI_HAVE_V3TOV4, 'B' );
00145 ENUM_OUT( DbSI_MADE_V3TOV4, 'c' );
00146 str << ")";
00147 #undef ENUM_OUT
00148 }
00149 return str;
00150 }
00151
00153
00154
00156
00157 #define WARNINGMAILPATH "/var/log/YaST2/"
00158 #define FILEFORBACKUPFILES "YaSTBackupModifiedFiles"
00159
00161
00162
00180 class RpmDb::Logfile {
00181 Logfile( const Logfile & );
00182 Logfile & operator=( const Logfile & );
00183 private:
00184 static ofstream _log;
00185 static unsigned _refcnt;
00186 static Pathname _fname;
00187 static void openLog() {
00188 if ( !_fname.empty() ) {
00189 _log.clear();
00190 _log.open( _fname.asString().c_str(), std::ios::out|std::ios::app );
00191 if( !_log )
00192 ERR << "Could not open logfile '" << _fname << "'" << endl;
00193 }
00194 }
00195 static void closeLog() {
00196 _log.clear();
00197 _log.close();
00198 }
00199 static void refUp() {
00200 if ( !_refcnt )
00201 openLog();
00202 ++_refcnt;
00203 }
00204 static void refDown() {
00205 --_refcnt;
00206 if ( !_refcnt )
00207 closeLog();
00208 }
00209 public:
00210 Logfile() { refUp(); }
00211 ~Logfile() { refDown(); }
00212 ostream & operator()( bool timestamp = false ) {
00213 if ( timestamp ) {
00214 _log << Date(Date::now()).form( "%Y-%m-%d %H:%M:%S ");
00215 }
00216 return _log;
00217 }
00218 static void setFname( const Pathname & fname_r ) {
00219 MIL << "installation log file " << fname_r << endl;
00220 if ( _refcnt )
00221 closeLog();
00222 _fname = fname_r;
00223 if ( _refcnt )
00224 openLog();
00225 }
00226 };
00227
00229
00230 Pathname RpmDb::Logfile::_fname;
00231 ofstream RpmDb::Logfile::_log;
00232 unsigned RpmDb::Logfile::_refcnt = 0;
00233
00235
00237
00238
00239
00240
00241
00242 bool RpmDb::setInstallationLogfile( const Pathname & filename )
00243 {
00244 Logfile::setFname( filename );
00245 return true;
00246 }
00247
00249
00250
00269 class RpmDb::Packages {
00270 public:
00271 list<Package::Ptr> _list;
00272 map<std::string,Package::Ptr> _index;
00273 bool _valid;
00274 Packages() : _valid( false ) {}
00275 void clear() {
00276 _list.clear();
00277 _index.clear();
00278 _valid = false;
00279 }
00280 Package::Ptr lookup( const string & name_r ) const {
00281 map<string,Package::Ptr>::const_iterator got = _index.find( name_r );
00282 if ( got != _index.end() )
00283 return got->second;
00284 return Package::Ptr();
00285 }
00286 void buildIndex() {
00287 _index.clear();
00288 for ( list<Package::Ptr>::iterator iter = _list.begin();
00289 iter != _list.end(); ++iter )
00290 {
00291 string name = (*iter)->name();
00292 Package::Ptr & nptr = _index[name];
00293
00294 if ( nptr ) {
00295 WAR << "Multiple entries for package '" << name << "' in rpmdb" << endl;
00296 if ( nptr->installtime() > (*iter)->installtime() )
00297 continue;
00298 else
00299 nptr = *iter;
00300 }
00301 else
00302 {
00303 nptr = *iter;
00304 }
00305 }
00306 _valid = true;
00307 }
00308 };
00309
00311
00313
00314
00315
00317
00318 #define FAILIFNOTINITIALIZED if( ! initialized() ) { ZYPP_THROW(RpmDbNotOpenException()); }
00319
00321
00323
00324
00325
00326
00327
00328 RpmDb::RpmDb()
00329 : _dbStateInfo( DbSI_NO_INIT )
00330 , _packages( * new Packages )
00331 #warning Check for obsolete memebers
00332 , _backuppath ("/var/adm/backup")
00333 , _packagebackups(false)
00334 , _warndirexists(false)
00335 {
00336 process = 0;
00337 exit_code = -1;
00338
00339
00340
00341 setenv( "RPM_IgnoreFailedSymlinks", "1", 1 );
00342 sKeyRingReceiver.reset(new KeyRingSignalReceiver(*this));
00343 }
00344
00346
00347
00348
00349
00350
00351 RpmDb::~RpmDb()
00352 {
00353 MIL << "~RpmDb()" << endl;
00354 closeDatabase();
00355
00356 delete process;
00357 delete &_packages;
00358 MIL << "~RpmDb() end" << endl;
00359 sKeyRingReceiver.reset();
00360 }
00361
00363
00364
00365
00366
00367
00368 std::ostream & RpmDb::dumpOn( std::ostream & str ) const
00369 {
00370 str << "RpmDb[";
00371
00372 if ( _dbStateInfo == DbSI_NO_INIT ) {
00373 str << "NO_INIT";
00374 } else {
00375 #define ENUM_OUT(B,C) str << ( _dbStateInfo & B ? C : '-' )
00376 str << "V4(";
00377 ENUM_OUT( DbSI_HAVE_V4, 'X' );
00378 ENUM_OUT( DbSI_MADE_V4, 'c' );
00379 ENUM_OUT( DbSI_MODIFIED_V4, 'm' );
00380 str << ")V3(";
00381 ENUM_OUT( DbSI_HAVE_V3, 'X' );
00382 ENUM_OUT( DbSI_HAVE_V3TOV4, 'B' );
00383 ENUM_OUT( DbSI_MADE_V3TOV4, 'c' );
00384 str << "): " << stringPath( _root, _dbPath );
00385 #undef ENUM_OUT
00386 }
00387 return str << "]";
00388 }
00389
00391
00392
00393
00394
00395
00396 void RpmDb::initDatabase( Pathname root_r, Pathname dbPath_r )
00397 {
00399
00401 if ( root_r.empty() )
00402 root_r = "/";
00403
00404 if ( dbPath_r.empty() )
00405 dbPath_r = "/var/lib/rpm";
00406
00407 if ( ! (root_r.absolute() && dbPath_r.absolute()) ) {
00408 ERR << "Illegal root or dbPath: " << stringPath( root_r, dbPath_r ) << endl;
00409 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
00410 }
00411
00412 MIL << "Calling initDatabase: " << stringPath( root_r, dbPath_r ) << endl;
00413
00415
00417 if ( initialized() ) {
00418 if ( root_r == _root && dbPath_r == _dbPath ) {
00419 return;
00420 } else {
00421 ZYPP_THROW(RpmDbAlreadyOpenException(_root, _dbPath, root_r, dbPath_r));
00422 }
00423 }
00424
00426
00428 librpmDb::unblockAccess();
00429 DbStateInfoBits info = DbSI_NO_INIT;
00430 try {
00431 internal_initDatabase( root_r, dbPath_r, info );
00432 }
00433 catch (const RpmException & excpt_r)
00434 {
00435 ZYPP_CAUGHT(excpt_r);
00436 librpmDb::blockAccess();
00437 ERR << "Cleanup on error: state " << info << endl;
00438
00439 if ( dbsi_has( info, DbSI_MADE_V4 ) ) {
00440
00441
00442 removeV4( root_r + dbPath_r, dbsi_has( info, DbSI_MADE_V3TOV4 ) );
00443 }
00444 ZYPP_RETHROW(excpt_r);
00445 }
00446 if ( dbsi_has( info, DbSI_HAVE_V3 ) ) {
00447 if ( root_r == "/" || dbsi_has( info, DbSI_MODIFIED_V4 ) ) {
00448
00449 MIL << "Cleanup: state " << info << endl;
00450 removeV3( root_r + dbPath_r, dbsi_has( info, DbSI_MADE_V3TOV4 ) );
00451 dbsi_clr( info, DbSI_HAVE_V3 );
00452 } else {
00453
00454
00455
00456 MIL << "Update mode: Cleanup delayed until closeOldDatabase." << endl;
00457 }
00458 }
00459 #warning CHECK: notify root about conversion backup.
00460
00461 _root = root_r;
00462 _dbPath = dbPath_r;
00463 _dbStateInfo = info;
00464
00465 #warning Add rebuild database once have the info about context
00466 #if 0
00467 if ( ! ( Y2PM::runningFromSystem() ) ) {
00468 if ( dbsi_has( info, DbSI_HAVE_V4 )
00469 && ! dbsi_has( info, DbSI_MADE_V4 ) ) {
00470 err = rebuildDatabase();
00471 }
00472 }
00473 #endif
00474
00475 MIL << "Syncronizing keys with zypp keyring" << std::endl;
00476 importZyppKeyRingTrustedKeys();
00477 exportTrustedKeysInZyppKeyRing();
00478
00479
00480
00481
00482
00483 librpmDb::dbRelease( true );
00484
00485 MIL << "InitDatabase: " << *this << endl;
00486 }
00487
00489
00490
00491
00492
00493
00494 void RpmDb::internal_initDatabase( const Pathname & root_r, const Pathname & dbPath_r,
00495 DbStateInfoBits & info_r )
00496 {
00497 info_r = DbSI_NO_INIT;
00498
00500
00502 librpmDb::DbDirInfo dbInfo( root_r, dbPath_r );
00503
00504 if ( dbInfo.illegalArgs() ) {
00505
00506 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
00507 }
00508 if ( ! dbInfo.usableArgs() ) {
00509 ERR << "Bad database directory: " << dbInfo.dbDir() << endl;
00510 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
00511 }
00512
00513 if ( dbInfo.hasDbV4() ) {
00514 dbsi_set( info_r, DbSI_HAVE_V4 );
00515 MIL << "Found rpm4 database in " << dbInfo.dbDir() << endl;
00516 } else {
00517 MIL << "Creating new rpm4 database in " << dbInfo.dbDir() << endl;
00518 }
00519
00520 if ( dbInfo.hasDbV3() ) {
00521 dbsi_set( info_r, DbSI_HAVE_V3 );
00522 }
00523 if ( dbInfo.hasDbV3ToV4() ) {
00524 dbsi_set( info_r, DbSI_HAVE_V3TOV4 );
00525 }
00526
00527 DBG << "Initial state: " << info_r << ": " << stringPath( root_r, dbPath_r );
00528 librpmDb::dumpState( DBG ) << endl;
00529
00531
00533
00534
00535 librpmDb::dbAccess( root_r, dbPath_r );
00536
00537 if ( ! dbInfo.hasDbV4() ) {
00538 dbInfo.restat();
00539 if ( dbInfo.hasDbV4() ) {
00540 dbsi_set( info_r, DbSI_HAVE_V4 | DbSI_MADE_V4 );
00541 }
00542 }
00543
00544 DBG << "Access state: " << info_r << ": " << stringPath( root_r, dbPath_r );
00545 librpmDb::dumpState( DBG ) << endl;
00546
00548
00549
00551 librpmDb::constPtr dbptr;
00552 librpmDb::dbAccess( dbptr );
00553 bool dbEmpty = dbptr->empty();
00554 if ( dbEmpty ) {
00555 MIL << "Empty rpm4 database " << dbInfo.dbV4() << endl;
00556 }
00557
00558 if ( dbInfo.hasDbV3() ) {
00559 MIL << "Found rpm3 database " << dbInfo.dbV3() << endl;
00560
00561 if ( dbEmpty ) {
00562 extern void convertV3toV4( const Pathname & v3db_r, const librpmDb::constPtr & v4db_r );
00563 convertV3toV4( dbInfo.dbV3().path(), dbptr );
00564
00565
00566 int res = filesystem::copy( dbInfo.dbV3().path(), dbInfo.dbV3ToV4().path() );
00567 if ( res ) {
00568 WAR << "Backup converted rpm3 database failed: error(" << res << ")" << endl;
00569 } else {
00570 dbInfo.restat();
00571 if ( dbInfo.hasDbV3ToV4() ) {
00572 MIL << "Backup converted rpm3 database: " << dbInfo.dbV3ToV4() << endl;
00573 dbsi_set( info_r, DbSI_HAVE_V3TOV4 | DbSI_MADE_V3TOV4 );
00574 }
00575 }
00576
00577 } else {
00578
00579 WAR << "Non empty rpm3 and rpm4 database found: using rpm4" << endl;
00580 #warning EXCEPTION: nonempty rpm4 and rpm3 database found.
00581
00582
00583
00584
00585
00586 dbsi_set( info_r, DbSI_MODIFIED_V4 );
00587
00588 }
00589
00590 DBG << "Convert state: " << info_r << ": " << stringPath( root_r, dbPath_r );
00591 librpmDb::dumpState( DBG ) << endl;
00592 }
00593
00594 if ( dbInfo.hasDbV3ToV4() ) {
00595 MIL << "Rpm3 database backup: " << dbInfo.dbV3ToV4() << endl;
00596 }
00597 }
00598
00600
00601
00602
00603
00604
00605 void RpmDb::removeV4( const Pathname & dbdir_r, bool v3backup_r )
00606 {
00607 const char * v3backup = "packages.rpm3";
00608 const char * master = "Packages";
00609 const char * index[] = {
00610 "Basenames",
00611 "Conflictname",
00612 "Depends",
00613 "Dirnames",
00614 "Filemd5s",
00615 "Group",
00616 "Installtid",
00617 "Name",
00618 "Providename",
00619 "Provideversion",
00620 "Pubkeys",
00621 "Requirename",
00622 "Requireversion",
00623 "Sha1header",
00624 "Sigmd5",
00625 "Triggername",
00626
00627 NULL
00628 };
00629
00630 PathInfo pi( dbdir_r );
00631 if ( ! pi.isDir() ) {
00632 ERR << "Can't remove rpm4 database in non directory: " << dbdir_r << endl;
00633 return;
00634 }
00635
00636 for ( const char ** f = index; *f; ++f ) {
00637 pi( dbdir_r + *f );
00638 if ( pi.isFile() ) {
00639 filesystem::unlink( pi.path() );
00640 }
00641 }
00642
00643 pi( dbdir_r + master );
00644 if ( pi.isFile() ) {
00645 MIL << "Removing rpm4 database " << pi << endl;
00646 filesystem::unlink( pi.path() );
00647 }
00648
00649 if ( v3backup_r ) {
00650 pi( dbdir_r + v3backup );
00651 if ( pi.isFile() ) {
00652 MIL << "Removing converted rpm3 database backup " << pi << endl;
00653 filesystem::unlink( pi.path() );
00654 }
00655 }
00656 }
00657
00659
00660
00661
00662
00663
00664 void RpmDb::removeV3( const Pathname & dbdir_r, bool v3backup_r )
00665 {
00666 const char * master = "packages.rpm";
00667 const char * index[] = {
00668 "conflictsindex.rpm",
00669 "fileindex.rpm",
00670 "groupindex.rpm",
00671 "nameindex.rpm",
00672 "providesindex.rpm",
00673 "requiredby.rpm",
00674 "triggerindex.rpm",
00675
00676 NULL
00677 };
00678
00679 PathInfo pi( dbdir_r );
00680 if ( ! pi.isDir() ) {
00681 ERR << "Can't remove rpm3 database in non directory: " << dbdir_r << endl;
00682 return;
00683 }
00684
00685 for ( const char ** f = index; *f; ++f ) {
00686 pi( dbdir_r + *f );
00687 if ( pi.isFile() ) {
00688 filesystem::unlink( pi.path() );
00689 }
00690 }
00691
00692 #warning CHECK: compare vs existing v3 backup. notify root
00693 pi( dbdir_r + master );
00694 if ( pi.isFile() ) {
00695 Pathname m( pi.path() );
00696 if ( v3backup_r ) {
00697
00698 filesystem::unlink( m );
00699 Pathname b( m.extend( "3" ) );
00700 pi( b );
00701 } else {
00702 Pathname b( m.extend( ".deleted" ) );
00703 pi( b );
00704 if ( pi.isFile() ) {
00705
00706 filesystem::unlink( b );
00707 }
00708 filesystem::rename( m, b );
00709 pi( b );
00710 }
00711 MIL << "(Re)moved rpm3 database to " << pi << endl;
00712 }
00713 }
00714
00716
00717
00718
00719
00720
00721 void RpmDb::modifyDatabase()
00722 {
00723 if ( ! initialized() )
00724 return;
00725
00726
00727 dbsi_set( _dbStateInfo, DbSI_MODIFIED_V4 );
00728
00729
00730 if ( dbsi_has( _dbStateInfo, DbSI_HAVE_V3 ) ) {
00731 MIL << "Update mode: Delayed cleanup: state " << _dbStateInfo << endl;
00732 removeV3( _root + _dbPath, dbsi_has( _dbStateInfo, DbSI_MADE_V3TOV4 ) );
00733 dbsi_clr( _dbStateInfo, DbSI_HAVE_V3 );
00734 }
00735
00736
00737 _packages._valid = false;
00738 }
00739
00741
00742
00743
00744
00745
00746 void RpmDb::closeDatabase()
00747 {
00748 if ( ! initialized() ) {
00749 return;
00750 }
00751
00752 MIL << "Calling closeDatabase: " << *this << endl;
00753
00755
00757 _packages.clear();
00758 librpmDb::blockAccess();
00759
00761
00763 if ( dbsi_has( _dbStateInfo, DbSI_HAVE_V3 ) ) {
00764 MIL << "Update mode: Delayed cleanup: state " << _dbStateInfo << endl;
00765 if ( dbsi_has( _dbStateInfo, DbSI_MODIFIED_V4 ) ) {
00766
00767 removeV3( _root + _dbPath, dbsi_has( _dbStateInfo, DbSI_MADE_V3TOV4 ) );
00768 } else {
00769
00770 removeV4( _root + _dbPath, dbsi_has( _dbStateInfo, DbSI_MADE_V3TOV4 ) );
00771 }
00772 }
00773
00775
00777 _root = _dbPath = Pathname();
00778 _dbStateInfo = DbSI_NO_INIT;
00779
00780 MIL << "closeDatabase: " << *this << endl;
00781 }
00782
00784
00785
00786
00787
00788
00789 void RpmDb::rebuildDatabase()
00790 {
00791 callback::SendReport<RebuildDBReport> report;
00792
00793 report->start( root() + dbPath() );
00794
00795 try {
00796 doRebuildDatabase(report);
00797 }
00798 catch (RpmException & excpt_r)
00799 {
00800 report->finish(root() + dbPath(), RebuildDBReport::FAILED, excpt_r.asUserString());
00801 ZYPP_RETHROW(excpt_r);
00802 }
00803 report->finish(root() + dbPath(), RebuildDBReport::NO_ERROR, "");
00804 }
00805
00806 void RpmDb::doRebuildDatabase(callback::SendReport<RebuildDBReport> & report)
00807 {
00808 FAILIFNOTINITIALIZED;
00809
00810 MIL << "RpmDb::rebuildDatabase" << *this << endl;
00811
00812
00813 PathInfo dbMaster( root() + dbPath() + "Packages" );
00814 PathInfo dbMasterBackup( dbMaster.path().extend( ".y2backup" ) );
00815
00816
00817 RpmArgVec opts;
00818 opts.push_back("--rebuilddb");
00819 opts.push_back("-vv");
00820
00821
00822
00823
00824 _packages._valid = false;
00825 run_rpm (opts, ExternalProgram::Stderr_To_Stdout);
00826
00827
00828 PathInfo newMaster( root()
00829 + dbPath().extend( str::form( "rebuilddb.%d",
00830 process?process->getpid():0) )
00831 + "Packages" );
00832
00833 string line;
00834 string errmsg;
00835
00836 while ( systemReadLine( line ) ) {
00837 if ( newMaster() ) {
00838
00839 report->progress( (100 * newMaster.size()) / dbMaster.size(), root() + dbPath());
00840 }
00841
00842 if ( line.compare( 0, 2, "D:" ) ) {
00843 errmsg += line + '\n';
00844
00845 WAR << line << endl;
00846 }
00847 }
00848
00849 int rpm_status = systemStatus();
00850
00851 if ( rpm_status != 0 ) {
00852 ZYPP_THROW(RpmSubprocessException(string("rpm failed with message: ") + errmsg));
00853 } else {
00854 report->progress( 100, root() + dbPath() );
00855 }
00856 }
00857
00858 void RpmDb::exportTrustedKeysInZyppKeyRing()
00859 {
00860 MIL << "Exporting rpm keyring into zypp trusted keyring" <<std::endl;
00861
00862 std::set<Edition> rpm_keys = pubkeyEditions();
00863
00864 std::list<PublicKey> zypp_keys;
00865 zypp_keys = getZYpp()->keyRing()->trustedPublicKeys();
00866
00867 for ( std::set<Edition>::const_iterator it = rpm_keys.begin(); it != rpm_keys.end(); ++it)
00868 {
00869
00870
00871 std::string id = str::toUpper( (*it).version() + (*it).release());
00872 std::list<PublicKey>::iterator ik = find( zypp_keys.begin(), zypp_keys.end(), id);
00873 if ( ik != zypp_keys.end() )
00874 {
00875 MIL << "Key " << (*it) << " is already in zypp database." << std::endl;
00876 }
00877 else
00878 {
00879
00880 RpmHeader::constPtr result = new RpmHeader();
00881 getData( std::string("gpg-pubkey"), *it, result );
00882 TmpFile file(getZYpp()->tmpPath());
00883 std::ofstream os;
00884 try
00885 {
00886 os.open(file.path().asString().c_str());
00887
00888 os << result->tag_description();
00889
00890
00891
00892 os.close();
00893 }
00894 catch (std::exception &e)
00895 {
00896 ERR << "Could not dump key " << (*it) << " in tmp file " << file.path() << std::endl;
00897
00898 }
00899
00900
00901 try
00902 {
00903 getZYpp()->keyRing()->importKey( file.path(), true );
00904 MIL << "Trusted key " << (*it) << " imported in zypp keyring." << std::endl;
00905 }
00906 catch (Exception &e)
00907 {
00908 ERR << "Could not import key " << (*it) << " in zypp keyring" << std::endl;
00909 }
00910 }
00911 }
00912 }
00913
00914 void RpmDb::importZyppKeyRingTrustedKeys()
00915 {
00916 MIL << "Importing zypp trusted keyring" << std::endl;
00917
00918 std::list<PublicKey> rpm_keys = pubkeys();
00919
00920 std::list<PublicKey> zypp_keys;
00921
00922 zypp_keys = getZYpp()->keyRing()->trustedPublicKeys();
00923
00924 for ( std::list<PublicKey>::const_iterator it = zypp_keys.begin(); it != zypp_keys.end(); ++it)
00925 {
00926
00927 std::list<PublicKey>::iterator ik = find( rpm_keys.begin(), rpm_keys.end(), (*it));
00928 if ( ik != rpm_keys.end() )
00929 {
00930 MIL << "Key " << (*it).id << " (" << (*it).name << ") is already in rpm database." << std::endl;
00931 }
00932 else
00933 {
00934
00935
00936 TmpFile file(getZYpp()->tmpPath());
00937
00938 std::ofstream os;
00939 try
00940 {
00941 os.open(file.path().asString().c_str());
00942
00943 getZYpp()->keyRing()->dumpTrustedPublicKey( (*it).id, os );
00944 os.close();
00945 }
00946 catch (std::exception &e)
00947 {
00948 ERR << "Could not dump key " << (*it).id << " (" << (*it).name << ") in tmp file " << file.path() << std::endl;
00949
00950 }
00951
00952
00953 try
00954 {
00955 importPubkey(file.path());
00956 MIL << "Trusted key " << (*it).id << " (" << (*it).name << ") imported in rpm database." << std::endl;
00957 }
00958 catch (RpmException &e)
00959 {
00960 ERR << "Could not dump key " << (*it).id << " (" << (*it).name << ") in tmp file " << file.path() << std::endl;
00961 }
00962 }
00963 }
00964 }
00965
00967
00968
00969
00970
00971
00972 void RpmDb::importPubkey( const Pathname & pubkey_r )
00973 {
00974 FAILIFNOTINITIALIZED;
00975
00976 RpmArgVec opts;
00977 opts.push_back ( "--import" );
00978 opts.push_back ( "--" );
00979 opts.push_back ( pubkey_r.asString().c_str() );
00980
00981
00982
00983
00984 _packages._valid = false;
00985 run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
00986
00987 string line;
00988 while ( systemReadLine( line ) ) {
00989 if ( line.substr( 0, 6 ) == "error:" ) {
00990 WAR << line << endl;
00991 } else {
00992 DBG << line << endl;
00993 }
00994 }
00995
00996 int rpm_status = systemStatus();
00997
00998 if ( rpm_status != 0 ) {
00999 ZYPP_THROW(RpmSubprocessException(string("Failed to import public key from file ") + pubkey_r.asString() + string(": rpm returned ") + str::numstring(rpm_status)));
01000 } else {
01001 MIL << "Imported public key from file " << pubkey_r << endl;
01002 }
01003 }
01004
01006
01007
01008
01009
01010
01011 list<PublicKey> RpmDb::pubkeys() const
01012 {
01013 list<PublicKey> ret;
01014
01015 librpmDb::db_const_iterator it;
01016 for ( it.findByName( string( "gpg-pubkey" ) ); *it; ++it )
01017 {
01018 Edition edition = it->tag_edition();
01019 if (edition != Edition::noedition)
01020 {
01021
01022 RpmHeader::constPtr result = new RpmHeader();
01023 getData( std::string("gpg-pubkey"), edition, result );
01024 TmpFile file(getZYpp()->tmpPath());
01025 std::ofstream os;
01026 try
01027 {
01028 os.open(file.path().asString().c_str());
01029
01030 os << result->tag_description();
01031
01032
01033
01034 os.close();
01035
01036 PublicKey key = getZYpp()->keyRing()->readPublicKey(file.path());
01037 ret.push_back(key);
01038 }
01039 catch (std::exception &e)
01040 {
01041 ERR << "Could not dump key " << edition.asString() << " in tmp file " << file.path() << std::endl;
01042
01043 }
01044 }
01045 }
01046 return ret;
01047 }
01048
01049 set<Edition> RpmDb::pubkeyEditions() const
01050 {
01051 set<Edition> ret;
01052
01053 librpmDb::db_const_iterator it;
01054 for ( it.findByName( string( "gpg-pubkey" ) ); *it; ++it ) {
01055 Edition edition = it->tag_edition();
01056 if (edition != Edition::noedition)
01057 ret.insert( edition );
01058 }
01059 return ret;
01060 }
01061
01063
01064
01065
01066
01067
01068 bool RpmDb::packagesValid() const
01069 {
01070 return( _packages._valid || ! initialized() );
01071 }
01072
01074
01075
01076
01077
01078
01079
01080
01081 const std::list<Package::Ptr> & RpmDb::getPackages()
01082 {
01083 callback::SendReport<ScanDBReport> report;
01084
01085 report->start ();
01086
01087 try {
01088 const std::list<Package::Ptr> & ret = doGetPackages(report);
01089 report->finish(ScanDBReport::NO_ERROR, "");
01090 return ret;
01091 }
01092 catch (RpmException & excpt_r)
01093 {
01094 report->finish(ScanDBReport::FAILED, excpt_r.asUserString ());
01095 ZYPP_RETHROW(excpt_r);
01096 }
01097 #warning fixme
01098 static const std::list<Package::Ptr> empty_list;
01099 return empty_list;
01100 }
01101
01102
01103
01104
01105
01106
01107
01108 Package::Ptr RpmDb::makePackageFromHeader( const RpmHeader::constPtr header, std::set<std::string> * filerequires, const Pathname & location, Source_Ref source )
01109 {
01110 Package::Ptr pptr;
01111
01112 string name = header->tag_name();
01113
01114
01115 detail::ResImplTraits<RPMPackageImpl>::Ptr impl( new RPMPackageImpl( header ) );
01116
01117 impl->setSource( source );
01118 if (!location.empty())
01119 impl->setLocation( location );
01120
01121 Edition edition;
01122 Arch arch;
01123
01124 try {
01125 edition = Edition( header->tag_version(),
01126 header->tag_release(),
01127 header->tag_epoch());
01128 }
01129 catch (Exception & excpt_r) {
01130 ZYPP_CAUGHT( excpt_r );
01131 WAR << "Package " << name << " has bad edition '"
01132 << (header->tag_epoch().empty()?"":(header->tag_epoch()+":"))
01133 << header->tag_version()
01134 << (header->tag_release().empty()?"":(string("-") + header->tag_release())) << "'";
01135 return pptr;
01136 }
01137
01138 try {
01139 arch = Arch( header->tag_arch() );
01140 }
01141 catch (Exception & excpt_r) {
01142 ZYPP_CAUGHT( excpt_r );
01143 WAR << "Package " << name << " has bad architecture '" << header->tag_arch() << "'";
01144 return pptr;
01145 }
01146
01147
01148 NVRAD dataCollect( header->tag_name(),
01149 edition,
01150 arch );
01151
01152 list<string> filenames = impl->filenames();
01153 dataCollect[Dep::PROVIDES] = header->tag_provides ( filerequires );
01154 CapFactory capfactory;
01155 for (list<string>::const_iterator filename = filenames.begin();
01156 filename != filenames.end();
01157 filename++)
01158 {
01159 if (filename->find("/bin/") != string::npos
01160 || filename->find("/sbin/") != string::npos
01161 || filename->find("/lib/") != string::npos
01162 || filename->find("/lib64/") != string::npos
01163 || filename->find("/etc/") != string::npos
01164 || filename->find("/usr/games/") != string::npos
01165 || filename->find("/usr/share/dict/words") != string::npos
01166 || filename->find("/usr/share/magic.mime") != string::npos
01167 || filename->find("/opt/gnome/games") != string::npos)
01168 {
01169 try {
01170 dataCollect[Dep::PROVIDES].insert( capfactory.parse(ResTraits<Package>::kind, *filename) );
01171 }
01172 catch (Exception & excpt_r)
01173 {
01174 ZYPP_CAUGHT( excpt_r );
01175 WAR << "Ignoring invalid capability: " << *filename << endl;
01176 }
01177 }
01178 }
01179
01180 dataCollect[Dep::REQUIRES] = header->tag_requires( filerequires );
01181 dataCollect[Dep::PREREQUIRES] = header->tag_prerequires( filerequires );
01182 dataCollect[Dep::CONFLICTS] = header->tag_conflicts( filerequires );
01183 dataCollect[Dep::OBSOLETES] = header->tag_obsoletes( filerequires );
01184 dataCollect[Dep::ENHANCES] = header->tag_enhances( filerequires );
01185 dataCollect[Dep::SUPPLEMENTS] = header->tag_supplements( filerequires );
01186
01187 try {
01188
01189 pptr = detail::makeResolvableFromImpl( dataCollect, impl );
01190 }
01191 catch (Exception & excpt_r) {
01192 ZYPP_CAUGHT( excpt_r );
01193 ERR << "Can't create Package::Ptr" << endl;
01194 }
01195
01196 return pptr;
01197 }
01198
01199
01200 const std::list<Package::Ptr> & RpmDb::doGetPackages(callback::SendReport<ScanDBReport> & report)
01201 {
01202 if ( packagesValid() ) {
01203 return _packages._list;
01204 }
01205
01206
01207
01208 #warning how to detect corrupt db while reading.
01209
01210 _packages.clear();
01211
01213
01214
01215
01217 unsigned expect = 0;
01218 librpmDb::db_const_iterator iter;
01219 {
01220
01221 for ( ; *iter; ++iter ) {
01222 ++expect;
01223 }
01224 if ( iter.dbError() ) {
01225 ERR << "No database access: " << iter.dbError() << endl;
01226 ZYPP_THROW(*(iter.dbError()));
01227 }
01228 }
01229 unsigned current = 0;
01230 DBG << "Expecting " << expect << " packages" << endl;
01231
01232 CapFactory _f;
01233 Pathname location;
01234
01235 for ( iter.findAll(); *iter; ++iter, ++current, report->progress( (100*current)/expect)) {
01236
01237 string name = iter->tag_name();
01238 if ( name == string( "gpg-pubkey" ) ) {
01239 DBG << "Ignoring pseudo package " << name << endl;
01240
01241
01242 continue;
01243 }
01244 Date installtime = iter->tag_installtime();
01245 #if 0
01246 This prevented from having packages multiple times
01247 Package::Ptr & nptr = _packages._index[name];
01248
01249 if ( nptr ) {
01250 WAR << "Multiple entries for package '" << name << "' in rpmdb" << endl;
01251 if ( nptr->installtime() > installtime )
01252 continue;
01253
01254 }
01255 #endif
01256
01257 Package::Ptr pptr = makePackageFromHeader( *iter, &_filerequires, location, Source_Ref() );
01258
01259 _packages._list.push_back( pptr );
01260 }
01261 _packages.buildIndex();
01262 DBG << "Found installed packages: " << _packages._list.size() << endl;
01263
01265
01267 for( set<string>::iterator it = _filerequires.begin(); it != _filerequires.end(); ++it ) {
01268
01269 for ( iter.findByFile( *it ); *iter; ++iter ) {
01270 Package::Ptr pptr = _packages.lookup( iter->tag_name() );
01271 if ( !pptr ) {
01272 WAR << "rpmdb.findByFile returned unknown package " << *iter << endl;
01273 continue;
01274 }
01275 pptr->injectProvides(_f.parse(ResTraits<Package>::kind, *it));
01276 }
01277
01278 }
01279
01281
01283 return _packages._list;
01284 }
01285
01286 #warning Uncomment this function if it is needed
01287 #if 0
01288
01289
01290
01291
01292
01293
01294
01295
01296 void RpmDb::traceFileRel( const PkgRelation & rel_r )
01297 {
01298 if ( ! rel_r.isFileRel() )
01299 return;
01300
01301 if ( ! _filerequires.insert( rel_r.name() ).second )
01302 return;
01303
01304 if ( ! _packages._valid )
01305 return;
01306
01307
01308
01309
01310 librpmDb::db_const_iterator iter;
01311 if ( iter.dbError() ) {
01312 ERR << "No database access: " << iter.dbError() << endl;
01313 return;
01314 }
01315
01316 for ( iter.findByFile( rel_r.name() ); *iter; ++iter ) {
01317 Package::Ptr pptr = _packages.lookup( iter->tag_name() );
01318 if ( !pptr ) {
01319 WAR << "rpmdb.findByFile returned unpknown package " << *iter << endl;
01320 continue;
01321 }
01322 pptr->addProvides( rel_r.name() );
01323 }
01324 }
01325 #endif
01326
01328
01329
01330
01331
01332
01333
01334
01335 std::list<FileInfo>
01336 RpmDb::fileList( const std::string & name_r, const Edition & edition_r ) const
01337 {
01338 std::list<FileInfo> result;
01339
01340 librpmDb::db_const_iterator it;
01341 bool found;
01342 if (edition_r == Edition::noedition) {
01343 found = it.findPackage( name_r );
01344 }
01345 else {
01346 found = it.findPackage( name_r, edition_r );
01347 }
01348 if (!found)
01349 return result;
01350
01351 return result;
01352 }
01353
01354
01356
01357
01358
01359
01360
01361
01362
01363 bool RpmDb::hasFile( const std::string & file_r, const std::string & name_r ) const
01364 {
01365 librpmDb::db_const_iterator it;
01366 bool res;
01367 do {
01368 res = it.findByFile( file_r );
01369 if (!res) break;
01370 if (!name_r.empty()) {
01371 res = (it->tag_name() == name_r);
01372 }
01373 ++it;
01374 } while (res && *it);
01375 return res;
01376 }
01377
01379
01380
01381
01382
01383
01384
01385
01386 std::string RpmDb::whoOwnsFile( const std::string & file_r) const
01387 {
01388 librpmDb::db_const_iterator it;
01389 if (it.findByFile( file_r )) {
01390 return it->tag_name();
01391 }
01392 return "";
01393 }
01394
01396
01397
01398
01399
01400
01401
01402
01403 bool RpmDb::hasProvides( const std::string & tag_r ) const
01404 {
01405 librpmDb::db_const_iterator it;
01406 return it.findByProvides( tag_r );
01407 }
01408
01410
01411
01412
01413
01414
01415
01416
01417 bool RpmDb::hasRequiredBy( const std::string & tag_r ) const
01418 {
01419 librpmDb::db_const_iterator it;
01420 return it.findByRequiredBy( tag_r );
01421 }
01422
01424
01425
01426
01427
01428
01429
01430
01431 bool RpmDb::hasConflicts( const std::string & tag_r ) const
01432 {
01433 librpmDb::db_const_iterator it;
01434 return it.findByConflicts( tag_r );
01435 }
01436
01438
01439
01440
01441
01442
01443
01444
01445 bool RpmDb::hasPackage( const string & name_r ) const
01446 {
01447 librpmDb::db_const_iterator it;
01448 return it.findPackage( name_r );
01449 }
01450
01452
01453
01454
01455
01456
01457
01458
01459 void RpmDb::getData( const string & name_r,
01460 RpmHeader::constPtr & result_r ) const
01461 {
01462 librpmDb::db_const_iterator it;
01463 it.findPackage( name_r );
01464 result_r = *it;
01465 if (it.dbError())
01466 ZYPP_THROW(*(it.dbError()));
01467 }
01468
01470
01471
01472
01473
01474
01475
01476
01477 void RpmDb::getData( const std::string & name_r, const Edition & ed_r,
01478 RpmHeader::constPtr & result_r ) const
01479 {
01480 librpmDb::db_const_iterator it;
01481 it.findPackage( name_r, ed_r );
01482 result_r = *it;
01483 if (it.dbError())
01484 ZYPP_THROW(*(it.dbError()));
01485 }
01486
01487
01488
01489
01490
01491 unsigned
01492 RpmDb::checkPackage (const Pathname & packagePath, string version, string md5 )
01493 {
01494 unsigned result = 0;
01495
01496 if ( ! version.empty() ) {
01497 RpmHeader::constPtr h( RpmHeader::readPackage( packagePath, RpmHeader::NOSIGNATURE ) );
01498 if ( ! h || Edition( version ) != h->tag_edition() ) {
01499 result |= CHK_INCORRECT_VERSION;
01500 }
01501 }
01502
01503 if(!md5.empty())
01504 {
01505 #warning TBD MD5 check
01506 WAR << "md5sum check not yet implemented" << endl;
01507 return CHK_INCORRECT_FILEMD5;
01508 }
01509
01510 std::string path = packagePath.asString();
01511
01512 const char *const argv[] = {
01513 "rpm", "--checksig", "--", path.c_str(), 0
01514 };
01515
01516 exit_code = -1;
01517
01518 string output = "";
01519 unsigned int k;
01520 for ( k = 0; k < (sizeof(argv) / sizeof(*argv)) -1; k++ )
01521 {
01522 output = output + " " + argv[k];
01523 }
01524
01525 DBG << "rpm command: " << output << endl;
01526
01527 if ( process != NULL )
01528 {
01529 delete process;
01530 process = NULL;
01531 }
01532
01533 process = new ExternalProgram( argv, ExternalProgram::Stderr_To_Stdout, false, -1, true);
01534
01535
01536 if ( process == NULL )
01537 {
01538 result |= CHK_OTHER_FAILURE;
01539 DBG << "create process failed" << endl;
01540 }
01541
01542 string value;
01543 output = process->receiveLine();
01544
01545 while ( output.length() > 0)
01546 {
01547 string::size_type ret;
01548
01549
01550 ret = output.find_first_of ( "\n" );
01551 if ( ret != string::npos )
01552 {
01553 value.assign ( output, 0, ret );
01554 }
01555 else
01556 {
01557 value = output;
01558 }
01559
01560 DBG << "stdout: " << value << endl;
01561
01562 string::size_type pos;
01563 if((pos = value.find (path)) != string::npos)
01564 {
01565 string rest = value.substr (pos + path.length() + 1);
01566 if (rest.find("NOT OK") == string::npos)
01567 {
01568
01569 if (rest.find("md5") == string::npos)
01570 {
01571 result |= CHK_MD5SUM_MISSING;
01572 }
01573 if (rest.find("gpg") == string::npos)
01574 {
01575 result |= CHK_GPGSIG_MISSING;
01576 }
01577 }
01578 else
01579 {
01580
01581 if (rest.find("MD5") != string::npos)
01582 {
01583 result |= CHK_INCORRECT_PKGMD5;
01584 }
01585 else
01586 {
01587 result |= CHK_MD5SUM_MISSING;
01588 }
01589
01590 if (rest.find("GPG") != string::npos)
01591 {
01592 result |= CHK_INCORRECT_GPGSIG;
01593 }
01594 else
01595 {
01596 result |= CHK_GPGSIG_MISSING;
01597 }
01598 }
01599 }
01600
01601 output = process->receiveLine();
01602 }
01603
01604 if ( result == 0 && systemStatus() != 0 )
01605 {
01606
01607 result |= CHK_OTHER_FAILURE;
01608 }
01609
01610 return ( result );
01611 }
01612
01613
01614 bool
01615 RpmDb::queryChangedFiles(FileList & fileList, const string& packageName)
01616 {
01617 bool ok = true;
01618
01619 fileList.clear();
01620
01621 if( ! initialized() ) return false;
01622
01623 RpmArgVec opts;
01624
01625 opts.push_back ("-V");
01626 opts.push_back ("--nodeps");
01627 opts.push_back ("--noscripts");
01628 opts.push_back ("--nomd5");
01629 opts.push_back ("--");
01630 opts.push_back (packageName.c_str());
01631
01632 run_rpm (opts, ExternalProgram::Discard_Stderr);
01633
01634 if ( process == NULL )
01635 return false;
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648 string line;
01649 while (systemReadLine(line))
01650 {
01651 if (line.length() > 12 &&
01652 (line[0] == 'S' || line[0] == 's' ||
01653 (line[0] == '.' && line[7] == 'T')))
01654 {
01655
01656 string filename;
01657
01658 filename.assign(line, 11, line.length() - 11);
01659 fileList.insert(filename);
01660 }
01661 }
01662
01663 systemStatus();
01664
01665
01666
01667 return ok;
01668 }
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680 void
01681 RpmDb::run_rpm (const RpmArgVec& opts,
01682 ExternalProgram::Stderr_Disposition disp)
01683 {
01684 if ( process ) {
01685 delete process;
01686 process = NULL;
01687 }
01688 exit_code = -1;
01689
01690 if ( ! initialized() ) {
01691 ZYPP_THROW(RpmDbNotOpenException());
01692 }
01693
01694 RpmArgVec args;
01695
01696
01697 args.push_back("rpm");
01698 args.push_back("--root");
01699 args.push_back(_root.asString().c_str());
01700 args.push_back("--dbpath");
01701 args.push_back(_dbPath.asString().c_str());
01702
01703 const char* argv[args.size() + opts.size() + 1];
01704
01705 const char** p = argv;
01706 p = copy (args.begin (), args.end (), p);
01707 p = copy (opts.begin (), opts.end (), p);
01708 *p = 0;
01709
01710
01711
01712 librpmDb::dbRelease( true );
01713
01714
01715 process = new ExternalProgram(argv, disp, false, -1, true);
01716 return;
01717 }
01718
01719
01720
01721
01722 bool
01723 RpmDb::systemReadLine(string &line)
01724 {
01725 line.erase();
01726
01727 if ( process == NULL )
01728 return false;
01729
01730 line = process->receiveLine();
01731
01732 if (line.length() == 0)
01733 return false;
01734
01735 if (line[line.length() - 1] == '\n')
01736 line.erase(line.length() - 1);
01737
01738 return true;
01739 }
01740
01741
01742
01743
01744
01745 int
01746 RpmDb::systemStatus()
01747 {
01748 if ( process == NULL )
01749 return -1;
01750
01751 exit_code = process->close();
01752 process->kill();
01753 delete process;
01754 process = 0;
01755
01756
01757
01758 return exit_code;
01759 }
01760
01761
01762
01763
01764 void
01765 RpmDb::systemKill()
01766 {
01767 if (process) process->kill();
01768 }
01769
01770
01771
01772 void RpmDb::processConfigFiles(const string& line, const string& name, const char* typemsg, const char* difffailmsg, const char* diffgenmsg)
01773 {
01774 string msg = line.substr(9);
01775 string::size_type pos1 = string::npos;
01776 string::size_type pos2 = string::npos;
01777 string file1s, file2s;
01778 Pathname file1;
01779 Pathname file2;
01780
01781 pos1 = msg.find (typemsg);
01782 for (;;)
01783 {
01784 if( pos1 == string::npos )
01785 break;
01786
01787 pos2 = pos1 + strlen (typemsg);
01788
01789 if (pos2 >= msg.length() )
01790 break;
01791
01792 file1 = msg.substr (0, pos1);
01793 file2 = msg.substr (pos2);
01794
01795 file1s = file1.asString();
01796 file2s = file2.asString();
01797
01798 if (!_root.empty() && _root != "/")
01799 {
01800 file1 = _root + file1;
01801 file2 = _root + file2;
01802 }
01803
01804 string out;
01805 int ret = diffFiles (file1.asString(), file2.asString(), out, 25);
01806 if (ret)
01807 {
01808 Pathname file = _root + WARNINGMAILPATH;
01809 if (filesystem::assert_dir(file) != 0)
01810 {
01811 ERR << "Could not create " << file.asString() << endl;
01812 break;
01813 }
01814 file += Date(Date::now()).form("config_diff_%Y_%m_%d.log");
01815 ofstream notify(file.asString().c_str(), std::ios::out|std::ios::app);
01816 if(!notify)
01817 {
01818 ERR << "Could not open " << file << endl;
01819 break;
01820 }
01821
01822
01823
01824 notify << str::form(_("Changed configuration files for %s:"), name.c_str()) << endl;
01825 if(ret>1)
01826 {
01827 ERR << "diff failed" << endl;
01828 notify << str::form(difffailmsg,
01829 file1s.c_str(), file2s.c_str()) << endl;
01830 }
01831 else
01832 {
01833 notify << str::form(diffgenmsg,
01834 file1s.c_str(), file2s.c_str()) << endl;
01835
01836
01837 if (!_root.empty() && _root != "/")
01838 {
01839 if(out.substr(0,4) == "--- ")
01840 {
01841 out.replace(4, file1.asString().length(), file1s);
01842 }
01843 string::size_type pos = out.find("\n+++ ");
01844 if(pos != string::npos)
01845 {
01846 out.replace(pos+5, file2.asString().length(), file2s);
01847 }
01848 }
01849 notify << out << endl;
01850 }
01851 notify.close();
01852 notify.open("/var/lib/update-messages/yast2-packagemanager.rpmdb.configfiles");
01853 notify.close();
01854 }
01855 else
01856 {
01857 WAR << "rpm created " << file2 << " but it is not different from " << file2 << endl;
01858 }
01859 break;
01860 }
01861 }
01862
01864
01865
01866
01867
01868
01869 void RpmDb::installPackage( const Pathname & filename, unsigned flags )
01870 {
01871 callback::SendReport<RpmInstallReport> report;
01872
01873 report->start(filename);
01874
01875 do
01876 try {
01877 doInstallPackage(filename, flags, report);
01878 report->finish();
01879 break;
01880 }
01881 catch (RpmException & excpt_r)
01882 {
01883 RpmInstallReport::Action user = report->problem( excpt_r );
01884
01885 if( user == RpmInstallReport::ABORT ) {
01886 report->finish( excpt_r );
01887 ZYPP_RETHROW(excpt_r);
01888 } else if ( user == RpmInstallReport::IGNORE ) {
01889 break;
01890 }
01891 }
01892 while (true);
01893 }
01894
01895 void RpmDb::doInstallPackage( const Pathname & filename, unsigned flags, callback::SendReport<RpmInstallReport> & report )
01896 {
01897 FAILIFNOTINITIALIZED;
01898 Logfile progresslog;
01899
01900 MIL << "RpmDb::installPackage(" << filename << "," << flags << ")" << endl;
01901
01902
01903
01904 if ( _packagebackups ) {
01905
01906 if ( ! backupPackage( filename ) ) {
01907 ERR << "backup of " << filename.asString() << " failed" << endl;
01908 }
01909
01910 report->progress( 0 );
01911 } else {
01912 report->progress( 100 );
01913 }
01914
01915
01916 RpmArgVec opts;
01917 if (flags & RPMINST_NOUPGRADE)
01918 opts.push_back("-i");
01919 else
01920 opts.push_back("-U");
01921 opts.push_back("--percent");
01922
01923 if (flags & RPMINST_NODIGEST)
01924 opts.push_back("--nodigest");
01925 if (flags & RPMINST_NOSIGNATURE)
01926 opts.push_back("--nosignature");
01927 if (flags & RPMINST_NODOCS)
01928 opts.push_back ("--excludedocs");
01929 if (flags & RPMINST_NOSCRIPTS)
01930 opts.push_back ("--noscripts");
01931 if (flags & RPMINST_FORCE)
01932 opts.push_back ("--force");
01933 if (flags & RPMINST_NODEPS)
01934 opts.push_back ("--nodeps");
01935 if(flags & RPMINST_IGNORESIZE)
01936 opts.push_back ("--ignoresize");
01937 if(flags & RPMINST_JUSTDB)
01938 opts.push_back ("--justdb");
01939 if(flags & RPMINST_TEST)
01940 opts.push_back ("--test");
01941
01942 opts.push_back("--");
01943 opts.push_back (filename.asString().c_str());
01944
01945 modifyDatabase();
01946 run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
01947
01948 string line;
01949 string rpmmsg;
01950 vector<string> configwarnings;
01951 vector<string> errorlines;
01952
01953 while (systemReadLine(line))
01954 {
01955 if (line.substr(0,2)=="%%")
01956 {
01957 int percent;
01958 sscanf (line.c_str () + 2, "%d", &percent);
01959 report->progress( percent );
01960 }
01961 else
01962 rpmmsg += line+'\n';
01963
01964 if( line.substr(0,8) == "warning:" )
01965 {
01966 configwarnings.push_back(line);
01967 }
01968 }
01969 int rpm_status = systemStatus();
01970
01971
01972 for(vector<string>::iterator it = configwarnings.begin();
01973 it != configwarnings.end(); ++it)
01974 {
01975 processConfigFiles(*it, Pathname::basename(filename), " saved as ",
01976
01977 _("rpm saved %s as %s but it was impossible to determine the difference"),
01978
01979 _("rpm saved %s as %s.\nHere are the first 25 lines of difference:\n"));
01980 processConfigFiles(*it, Pathname::basename(filename), " created as ",
01981
01982 _("rpm created %s as %s but it was impossible to determine the difference"),
01983
01984 _("rpm created %s as %s.\nHere are the first 25 lines of difference:\n"));
01985 }
01986
01987 if ( rpm_status != 0 ) {
01988
01989 progresslog(true) << str::form(_("%s install failed"), Pathname::basename(filename).c_str()) << endl;
01990 progresslog() << _("rpm output:") << endl << rpmmsg << endl;
01991 ZYPP_THROW(RpmSubprocessException(string("RPM failed: ") + rpmmsg));
01992 } else {
01993
01994 progresslog(true) << str::form(_("%s installed ok"), Pathname::basename(filename).c_str()) << endl;
01995 if( ! rpmmsg.empty() ) {
01996 progresslog() << _("Additional rpm output:") << endl << rpmmsg << endl;
01997 }
01998 }
01999 }
02000
02002
02003
02004
02005
02006
02007 void RpmDb::removePackage( Package::constPtr package, unsigned flags )
02008 {
02009 return removePackage( package->name()
02010 + "-" + package->edition().asString()
02011 + "." + package->arch().asString(), flags );
02012 }
02013
02015
02016
02017
02018
02019
02020 void RpmDb::removePackage( const string & name_r, unsigned flags )
02021 {
02022 callback::SendReport<RpmRemoveReport> report;
02023
02024 report->start( name_r );
02025
02026 try {
02027 doRemovePackage(name_r, flags, report);
02028 }
02029 catch (RpmException & excpt_r)
02030 {
02031 report->finish(excpt_r);
02032 ZYPP_RETHROW(excpt_r);
02033 }
02034 report->finish();
02035 }
02036
02037
02038 void RpmDb::doRemovePackage( const string & name_r, unsigned flags, callback::SendReport<RpmRemoveReport> & report )
02039 {
02040 FAILIFNOTINITIALIZED;
02041 Logfile progresslog;
02042
02043 MIL << "RpmDb::doRemovePackage(" << name_r << "," << flags << ")" << endl;
02044
02045
02046 if ( _packagebackups ) {
02047
02048
02049 if ( ! backupPackage( name_r ) ) {
02050 ERR << "backup of " << name_r << " failed" << endl;
02051 }
02052 report->progress( 0 );
02053 } else {
02054 report->progress( 100 );
02055 }
02056
02057
02058 RpmArgVec opts;
02059 opts.push_back("-e");
02060 opts.push_back("--allmatches");
02061
02062 if (flags & RPMINST_NOSCRIPTS)
02063 opts.push_back("--noscripts");
02064 if (flags & RPMINST_NODEPS)
02065 opts.push_back("--nodeps");
02066 if (flags & RPMINST_JUSTDB)
02067 opts.push_back("--justdb");
02068 if (flags & RPMINST_TEST)
02069 opts.push_back ("--test");
02070 if (flags & RPMINST_FORCE) {
02071 WAR << "IGNORE OPTION: 'rpm -e' does not support '--force'" << endl;
02072 }
02073
02074 opts.push_back("--");
02075 opts.push_back(name_r.c_str());
02076
02077 modifyDatabase();
02078 run_rpm (opts, ExternalProgram::Stderr_To_Stdout);
02079
02080 string line;
02081 string rpmmsg;
02082
02083
02084
02085
02086
02087 report->progress( 5 );
02088 while (systemReadLine(line))
02089 {
02090 rpmmsg += line+'\n';
02091 }
02092 report->progress( 50 );
02093 int rpm_status = systemStatus();
02094
02095 if ( rpm_status != 0 ) {
02096
02097 progresslog(true) << str::form(_("%s remove failed"), name_r.c_str()) << endl;
02098 progresslog() << _("rpm output:") << endl << rpmmsg << endl;
02099 ZYPP_THROW(RpmSubprocessException(string("RPM failed: ") + rpmmsg));
02100 } else {
02101 progresslog(true) << str::form(_("%s remove ok"), name_r.c_str()) << endl;
02102 if( ! rpmmsg.empty() ) {
02103 progresslog() << _("Additional rpm output:") << endl << rpmmsg << endl;
02104 }
02105 }
02106 }
02107
02108 string
02109 RpmDb::checkPackageResult2string(unsigned code)
02110 {
02111 string msg;
02112
02113 string bol = " - ";
02114
02115 string eol = "\n";
02116 if(code == 0)
02117 return string(_("Ok"))+eol;
02118
02119
02120 msg = _("The package is not OK for the following reasons:");
02121 msg += eol;
02122
02123 if(code&CHK_INCORRECT_VERSION)
02124 {
02125 msg += bol;
02126 msg+=_("The package contains different version than expected");
02127 msg += eol;
02128 }
02129 if(code&CHK_INCORRECT_FILEMD5)
02130 {
02131 msg += bol;
02132 msg+=_("The package file has incorrect MD5 sum");
02133 msg += eol;
02134 }
02135 if(code&CHK_GPGSIG_MISSING)
02136 {
02137 msg += bol;
02138 msg+=_("The package is not signed");
02139 msg += eol;
02140 }
02141 if(code&CHK_MD5SUM_MISSING)
02142 {
02143 msg += bol;
02144 msg+=_("The package has no MD5 sum");
02145 msg += eol;
02146 }
02147 if(code&CHK_INCORRECT_GPGSIG)
02148 {
02149 msg += bol;
02150 msg+=_("The package has incorrect signature");
02151 msg += eol;
02152 }
02153 if(code&CHK_INCORRECT_PKGMD5)
02154 {
02155 msg += bol;
02156 msg+=_("The package archive has incorrect MD5 sum");
02157 msg += eol;
02158 }
02159 if(code&CHK_OTHER_FAILURE)
02160 {
02161 msg += bol;
02162 msg+=_("rpm failed for unkown reason, see log file");
02163 msg += eol;
02164 }
02165
02166 return msg;
02167 }
02168
02170
02171
02172
02173
02174
02175 bool RpmDb::backupPackage( const Pathname & filename )
02176 {
02177 RpmHeader::constPtr h( RpmHeader::readPackage( filename, RpmHeader::NOSIGNATURE ) );
02178 if( ! h )
02179 return false;
02180
02181 return backupPackage( h->tag_name() );
02182 }
02183
02185
02186
02187
02188
02189
02190 bool RpmDb::backupPackage(const string& packageName)
02191 {
02192 Logfile progresslog;
02193 bool ret = true;
02194 Pathname backupFilename;
02195 Pathname filestobackupfile = _root+_backuppath+FILEFORBACKUPFILES;
02196
02197 if (_backuppath.empty())
02198 {
02199 INT << "_backuppath empty" << endl;
02200 return false;
02201 }
02202
02203 FileList fileList;
02204
02205 if (!queryChangedFiles(fileList, packageName))
02206 {
02207 ERR << "Error while getting changed files for package " <<
02208 packageName << endl;
02209 return false;
02210 }
02211
02212 if (fileList.size() <= 0)
02213 {
02214 DBG << "package " << packageName << " not changed -> no backup" << endl;
02215 return true;
02216 }
02217
02218 if (filesystem::assert_dir(_root + _backuppath) != 0)
02219 {
02220 return false;
02221 }
02222
02223 {
02224
02225 time_t currentTime = time(0);
02226 struct tm *currentLocalTime = localtime(¤tTime);
02227
02228 int date = (currentLocalTime->tm_year + 1900) * 10000
02229 + (currentLocalTime->tm_mon + 1) * 100
02230 + currentLocalTime->tm_mday;
02231
02232 int num = 0;
02233 do
02234 {
02235 backupFilename = _root + _backuppath
02236 + str::form("%s-%d-%d.tar.gz",packageName.c_str(), date, num);
02237
02238 }
02239 while ( PathInfo(backupFilename).isExist() && num++ < 1000);
02240
02241 PathInfo pi(filestobackupfile);
02242 if(pi.isExist() && !pi.isFile())
02243 {
02244 ERR << filestobackupfile.asString() << " already exists and is no file" << endl;
02245 return false;
02246 }
02247
02248 std::ofstream fp ( filestobackupfile.asString().c_str(), std::ios::out|std::ios::trunc );
02249
02250 if(!fp)
02251 {
02252 ERR << "could not open " << filestobackupfile.asString() << endl;
02253 return false;
02254 }
02255
02256 for (FileList::const_iterator cit = fileList.begin();
02257 cit != fileList.end(); ++cit)
02258 {
02259 string name = *cit;
02260 if ( name[0] == '/' )
02261 {
02262
02263 name = name.substr( 1 );
02264 }
02265 DBG << "saving file "<< name << endl;
02266 fp << name << endl;
02267 }
02268 fp.close();
02269
02270 const char* const argv[] =
02271 {
02272 "tar",
02273 "-czhP",
02274 "-C",
02275 _root.asString().c_str(),
02276 "--ignore-failed-read",
02277 "-f",
02278 backupFilename.asString().c_str(),
02279 "-T",
02280 filestobackupfile.asString().c_str(),
02281 NULL
02282 };
02283
02284
02285 ExternalProgram tar(argv, ExternalProgram::Stderr_To_Stdout, false, -1, true);
02286
02287 string tarmsg;
02288
02289
02290
02291 for (string output = tar.receiveLine(); output.length() ;output = tar.receiveLine())
02292 {
02293 tarmsg+=output;
02294 }
02295
02296 int ret = tar.close();
02297
02298 if ( ret != 0)
02299 {
02300 ERR << "tar failed: " << tarmsg << endl;
02301 ret = false;
02302 }
02303 else
02304 {
02305 MIL << "tar backup ok" << endl;
02306 progresslog(true) << str::form(_("created backup %s"), backupFilename.asString().c_str()) << endl;
02307 }
02308
02309 filesystem::unlink(filestobackupfile);
02310 }
02311
02312 return ret;
02313 }
02314
02315 void RpmDb::setBackupPath(const Pathname& path)
02316 {
02317 _backuppath = path;
02318 }
02319
02320 }
02321 }
02322 }