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