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