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 line = process->receiveLine();
01694
01695 if (line.length() == 0)
01696 return false;
01697
01698 if (line[line.length() - 1] == '\n')
01699 line.erase(line.length() - 1);
01700
01701 return true;
01702 }
01703
01704
01705
01706
01707
01708 int
01709 RpmDb::systemStatus()
01710 {
01711 if ( process == NULL )
01712 return -1;
01713
01714 exit_code = process->close();
01715 process->kill();
01716 delete process;
01717 process = 0;
01718
01719
01720
01721 return exit_code;
01722 }
01723
01724
01725
01726
01727 void
01728 RpmDb::systemKill()
01729 {
01730 if (process) process->kill();
01731 }
01732
01733
01734
01735 void RpmDb::processConfigFiles(const string& line, const string& name, const char* typemsg, const char* difffailmsg, const char* diffgenmsg)
01736 {
01737 string msg = line.substr(9);
01738 string::size_type pos1 = string::npos;
01739 string::size_type pos2 = string::npos;
01740 string file1s, file2s;
01741 Pathname file1;
01742 Pathname file2;
01743
01744 pos1 = msg.find (typemsg);
01745 for (;;)
01746 {
01747 if ( pos1 == string::npos )
01748 break;
01749
01750 pos2 = pos1 + strlen (typemsg);
01751
01752 if (pos2 >= msg.length() )
01753 break;
01754
01755 file1 = msg.substr (0, pos1);
01756 file2 = msg.substr (pos2);
01757
01758 file1s = file1.asString();
01759 file2s = file2.asString();
01760
01761 if (!_root.empty() && _root != "/")
01762 {
01763 file1 = _root + file1;
01764 file2 = _root + file2;
01765 }
01766
01767 string out;
01768 int ret = diffFiles (file1.asString(), file2.asString(), out, 25);
01769 if (ret)
01770 {
01771 Pathname file = _root + WARNINGMAILPATH;
01772 if (filesystem::assert_dir(file) != 0)
01773 {
01774 ERR << "Could not create " << file.asString() << endl;
01775 break;
01776 }
01777 file += Date(Date::now()).form("config_diff_%Y_%m_%d.log");
01778 ofstream notify(file.asString().c_str(), std::ios::out|std::ios::app);
01779 if (!notify)
01780 {
01781 ERR << "Could not open " << file << endl;
01782 break;
01783 }
01784
01785
01786
01787 notify << str::form(_("Changed configuration files for %s:"), name.c_str()) << endl;
01788 if (ret>1)
01789 {
01790 ERR << "diff failed" << endl;
01791 notify << str::form(difffailmsg,
01792 file1s.c_str(), file2s.c_str()) << endl;
01793 }
01794 else
01795 {
01796 notify << str::form(diffgenmsg,
01797 file1s.c_str(), file2s.c_str()) << endl;
01798
01799
01800 if (!_root.empty() && _root != "/")
01801 {
01802 if (out.substr(0,4) == "--- ")
01803 {
01804 out.replace(4, file1.asString().length(), file1s);
01805 }
01806 string::size_type pos = out.find("\n+++ ");
01807 if (pos != string::npos)
01808 {
01809 out.replace(pos+5, file2.asString().length(), file2s);
01810 }
01811 }
01812 notify << out << endl;
01813 }
01814 notify.close();
01815 notify.open("/var/lib/update-messages/yast2-packagemanager.rpmdb.configfiles");
01816 notify.close();
01817 }
01818 else
01819 {
01820 WAR << "rpm created " << file2 << " but it is not different from " << file2 << endl;
01821 }
01822 break;
01823 }
01824 }
01825
01827
01828
01829
01830
01831
01832 void RpmDb::installPackage( const Pathname & filename, unsigned flags )
01833 {
01834 callback::SendReport<RpmInstallReport> report;
01835
01836 report->start(filename);
01837
01838 do
01839 try
01840 {
01841 doInstallPackage(filename, flags, report);
01842 report->finish();
01843 break;
01844 }
01845 catch (RpmException & excpt_r)
01846 {
01847 RpmInstallReport::Action user = report->problem( excpt_r );
01848
01849 if ( user == RpmInstallReport::ABORT )
01850 {
01851 report->finish( excpt_r );
01852 ZYPP_RETHROW(excpt_r);
01853 }
01854 else if ( user == RpmInstallReport::IGNORE )
01855 {
01856 break;
01857 }
01858 }
01859 while (true);
01860 }
01861
01862 void RpmDb::doInstallPackage( const Pathname & filename, unsigned flags, callback::SendReport<RpmInstallReport> & report )
01863 {
01864 FAILIFNOTINITIALIZED;
01865 CommitLog progresslog;
01866
01867 MIL << "RpmDb::installPackage(" << filename << "," << flags << ")" << endl;
01868
01869
01870
01871 if ( _packagebackups )
01872 {
01873
01874 if ( ! backupPackage( filename ) )
01875 {
01876 ERR << "backup of " << filename.asString() << " failed" << endl;
01877 }
01878
01879 report->progress( 0 );
01880 }
01881 else
01882 {
01883 report->progress( 100 );
01884 }
01885
01886
01887 RpmArgVec opts;
01888 if (flags & RPMINST_NOUPGRADE)
01889 opts.push_back("-i");
01890 else
01891 opts.push_back("-U");
01892 opts.push_back("--percent");
01893
01894 if (flags & RPMINST_NODIGEST)
01895 opts.push_back("--nodigest");
01896 if (flags & RPMINST_NOSIGNATURE)
01897 opts.push_back("--nosignature");
01898 if (flags & RPMINST_NODOCS)
01899 opts.push_back ("--excludedocs");
01900 if (flags & RPMINST_NOSCRIPTS)
01901 opts.push_back ("--noscripts");
01902 if (flags & RPMINST_FORCE)
01903 opts.push_back ("--force");
01904 if (flags & RPMINST_NODEPS)
01905 opts.push_back ("--nodeps");
01906 if (flags & RPMINST_IGNORESIZE)
01907 opts.push_back ("--ignoresize");
01908 if (flags & RPMINST_JUSTDB)
01909 opts.push_back ("--justdb");
01910 if (flags & RPMINST_TEST)
01911 opts.push_back ("--test");
01912
01913 opts.push_back("--");
01914
01915
01916 std::string quotedFilename( rpmQuoteFilename( filename ) );
01917 opts.push_back ( quotedFilename.c_str() );
01918
01919 modifyDatabase();
01920 run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
01921
01922 string line;
01923 string rpmmsg;
01924 vector<string> configwarnings;
01925 vector<string> errorlines;
01926
01927 while (systemReadLine(line))
01928 {
01929 if (line.substr(0,2)=="%%")
01930 {
01931 int percent;
01932 sscanf (line.c_str () + 2, "%d", &percent);
01933 report->progress( percent );
01934 }
01935 else
01936 rpmmsg += line+'\n';
01937
01938 if ( line.substr(0,8) == "warning:" )
01939 {
01940 configwarnings.push_back(line);
01941 }
01942 }
01943 int rpm_status = systemStatus();
01944
01945
01946 for (vector<string>::iterator it = configwarnings.begin();
01947 it != configwarnings.end(); ++it)
01948 {
01949 processConfigFiles(*it, Pathname::basename(filename), " saved as ",
01950
01951 _("rpm saved %s as %s but it was impossible to determine the difference"),
01952
01953 _("rpm saved %s as %s.\nHere are the first 25 lines of difference:\n"));
01954 processConfigFiles(*it, Pathname::basename(filename), " created as ",
01955
01956 _("rpm created %s as %s but it was impossible to determine the difference"),
01957
01958 _("rpm created %s as %s.\nHere are the first 25 lines of difference:\n"));
01959 }
01960
01961 if ( rpm_status != 0 )
01962 {
01963
01964 progresslog(true) << str::form(_("%s install failed"), Pathname::basename(filename).c_str()) << endl;
01965 progresslog() << _("rpm output:") << endl << rpmmsg << endl;
01966 ZYPP_THROW(RpmSubprocessException(string("RPM failed: ") + rpmmsg));
01967 }
01968 else
01969 {
01970
01971 progresslog(true) << str::form(_("%s installed ok"), Pathname::basename(filename).c_str()) << endl;
01972 if ( ! rpmmsg.empty() )
01973 {
01974 progresslog() << _("Additional rpm output:") << endl << rpmmsg << endl;
01975 }
01976 }
01977 }
01978
01980
01981
01982
01983
01984
01985 void RpmDb::removePackage( Package::constPtr package, unsigned flags )
01986 {
01987 return removePackage( package->name()
01988 + "-" + package->edition().asString()
01989 + "." + package->arch().asString(), flags );
01990 }
01991
01993
01994
01995
01996
01997
01998 void RpmDb::removePackage( const string & name_r, unsigned flags )
01999 {
02000 callback::SendReport<RpmRemoveReport> report;
02001
02002 report->start( name_r );
02003
02004 try
02005 {
02006 doRemovePackage(name_r, flags, report);
02007 }
02008 catch (RpmException & excpt_r)
02009 {
02010 report->finish(excpt_r);
02011 ZYPP_RETHROW(excpt_r);
02012 }
02013 report->finish();
02014 }
02015
02016
02017 void RpmDb::doRemovePackage( const string & name_r, unsigned flags, callback::SendReport<RpmRemoveReport> & report )
02018 {
02019 FAILIFNOTINITIALIZED;
02020 CommitLog progresslog;
02021
02022 MIL << "RpmDb::doRemovePackage(" << name_r << "," << flags << ")" << endl;
02023
02024
02025 if ( _packagebackups )
02026 {
02027
02028
02029 if ( ! backupPackage( name_r ) )
02030 {
02031 ERR << "backup of " << name_r << " failed" << endl;
02032 }
02033 report->progress( 0 );
02034 }
02035 else
02036 {
02037 report->progress( 100 );
02038 }
02039
02040
02041 RpmArgVec opts;
02042 opts.push_back("-e");
02043 opts.push_back("--allmatches");
02044
02045 if (flags & RPMINST_NOSCRIPTS)
02046 opts.push_back("--noscripts");
02047 if (flags & RPMINST_NODEPS)
02048 opts.push_back("--nodeps");
02049 if (flags & RPMINST_JUSTDB)
02050 opts.push_back("--justdb");
02051 if (flags & RPMINST_TEST)
02052 opts.push_back ("--test");
02053 if (flags & RPMINST_FORCE)
02054 {
02055 WAR << "IGNORE OPTION: 'rpm -e' does not support '--force'" << endl;
02056 }
02057
02058 opts.push_back("--");
02059 opts.push_back(name_r.c_str());
02060
02061 modifyDatabase();
02062 run_rpm (opts, ExternalProgram::Stderr_To_Stdout);
02063
02064 string line;
02065 string rpmmsg;
02066
02067
02068
02069
02070
02071 report->progress( 5 );
02072 while (systemReadLine(line))
02073 {
02074 rpmmsg += line+'\n';
02075 }
02076 report->progress( 50 );
02077 int rpm_status = systemStatus();
02078
02079 if ( rpm_status != 0 )
02080 {
02081
02082 progresslog(true) << str::form(_("%s remove failed"), name_r.c_str()) << endl;
02083 progresslog() << _("rpm output:") << endl << rpmmsg << endl;
02084 ZYPP_THROW(RpmSubprocessException(string("RPM failed: ") + rpmmsg));
02085 }
02086 else
02087 {
02088 progresslog(true) << str::form(_("%s remove ok"), name_r.c_str()) << endl;
02089 if ( ! rpmmsg.empty() )
02090 {
02091 progresslog() << _("Additional rpm output:") << endl << rpmmsg << endl;
02092 }
02093 }
02094 }
02095
02097
02098
02099
02100
02101
02102 bool RpmDb::backupPackage( const Pathname & filename )
02103 {
02104 RpmHeader::constPtr h( RpmHeader::readPackage( filename, RpmHeader::NOSIGNATURE ) );
02105 if ( ! h )
02106 return false;
02107
02108 return backupPackage( h->tag_name() );
02109 }
02110
02112
02113
02114
02115
02116
02117 bool RpmDb::backupPackage(const string& packageName)
02118 {
02119 CommitLog progresslog;
02120 bool ret = true;
02121 Pathname backupFilename;
02122 Pathname filestobackupfile = _root+_backuppath+FILEFORBACKUPFILES;
02123
02124 if (_backuppath.empty())
02125 {
02126 INT << "_backuppath empty" << endl;
02127 return false;
02128 }
02129
02130 FileList fileList;
02131
02132 if (!queryChangedFiles(fileList, packageName))
02133 {
02134 ERR << "Error while getting changed files for package " <<
02135 packageName << endl;
02136 return false;
02137 }
02138
02139 if (fileList.size() <= 0)
02140 {
02141 DBG << "package " << packageName << " not changed -> no backup" << endl;
02142 return true;
02143 }
02144
02145 if (filesystem::assert_dir(_root + _backuppath) != 0)
02146 {
02147 return false;
02148 }
02149
02150 {
02151
02152 time_t currentTime = time(0);
02153 struct tm *currentLocalTime = localtime(¤tTime);
02154
02155 int date = (currentLocalTime->tm_year + 1900) * 10000
02156 + (currentLocalTime->tm_mon + 1) * 100
02157 + currentLocalTime->tm_mday;
02158
02159 int num = 0;
02160 do
02161 {
02162 backupFilename = _root + _backuppath
02163 + str::form("%s-%d-%d.tar.gz",packageName.c_str(), date, num);
02164
02165 }
02166 while ( PathInfo(backupFilename).isExist() && num++ < 1000);
02167
02168 PathInfo pi(filestobackupfile);
02169 if (pi.isExist() && !pi.isFile())
02170 {
02171 ERR << filestobackupfile.asString() << " already exists and is no file" << endl;
02172 return false;
02173 }
02174
02175 std::ofstream fp ( filestobackupfile.asString().c_str(), std::ios::out|std::ios::trunc );
02176
02177 if (!fp)
02178 {
02179 ERR << "could not open " << filestobackupfile.asString() << endl;
02180 return false;
02181 }
02182
02183 for (FileList::const_iterator cit = fileList.begin();
02184 cit != fileList.end(); ++cit)
02185 {
02186 string name = *cit;
02187 if ( name[0] == '/' )
02188 {
02189
02190 name = name.substr( 1 );
02191 }
02192 DBG << "saving file "<< name << endl;
02193 fp << name << endl;
02194 }
02195 fp.close();
02196
02197 const char* const argv[] =
02198 {
02199 "tar",
02200 "-czhP",
02201 "-C",
02202 _root.asString().c_str(),
02203 "--ignore-failed-read",
02204 "-f",
02205 backupFilename.asString().c_str(),
02206 "-T",
02207 filestobackupfile.asString().c_str(),
02208 NULL
02209 };
02210
02211
02212 ExternalProgram tar(argv, ExternalProgram::Stderr_To_Stdout, false, -1, true);
02213
02214 string tarmsg;
02215
02216
02217
02218 for (string output = tar.receiveLine(); output.length() ;output = tar.receiveLine())
02219 {
02220 tarmsg+=output;
02221 }
02222
02223 int ret = tar.close();
02224
02225 if ( ret != 0)
02226 {
02227 ERR << "tar failed: " << tarmsg << endl;
02228 ret = false;
02229 }
02230 else
02231 {
02232 MIL << "tar backup ok" << endl;
02233 progresslog(true) << str::form(_("created backup %s"), backupFilename.asString().c_str()) << endl;
02234 }
02235
02236 filesystem::unlink(filestobackupfile);
02237 }
02238
02239 return ret;
02240 }
02241
02242 void RpmDb::setBackupPath(const Pathname& path)
02243 {
02244 _backuppath = path;
02245 }
02246
02247 }
02248 }
02249 }