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