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