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 #include "zypp/base/Regex.h"
00030
00031 #include "zypp/Date.h"
00032 #include "zypp/Pathname.h"
00033 #include "zypp/PathInfo.h"
00034 #include "zypp/PublicKey.h"
00035
00036 #include "zypp/target/rpm/RpmDb.h"
00037 #include "zypp/target/rpm/RpmCallbacks.h"
00038
00039 #include "zypp/target/CommitLog.h"
00040 #include "zypp/target/rpm/librpmDb.h"
00041 #include "zypp/target/rpm/RpmPackageImpl.h"
00042 #include "zypp/target/rpm/RpmException.h"
00043 #include "zypp/CapSet.h"
00044 #include "zypp/CapFactory.h"
00045 #include "zypp/KeyRing.h"
00046 #include "zypp/ZYppFactory.h"
00047 #include "zypp/TmpPath.h"
00048
00049 #ifndef _
00050 #define _(X) X
00051 #endif
00052
00053 using namespace std;
00054 using namespace zypp::filesystem;
00055
00056 namespace zypp
00057 {
00058 namespace target
00059 {
00060 namespace rpm
00061 {
00062 namespace
00063 {
00064 const char* quoteInFilename_m = " \t";
00065 inline string rpmQuoteFilename( const Pathname & path_r )
00066 {
00067 string path( path_r.asString() );
00068 for ( string::size_type pos = path.find_first_of( quoteInFilename_m );
00069 pos != string::npos;
00070 pos = path.find_first_of( quoteInFilename_m, pos ) )
00071 {
00072 path.insert( pos, "\\" );
00073 pos += 2;
00074 }
00075 return path;
00076 }
00077 }
00078
00079 struct KeyRingSignalReceiver : callback::ReceiveReport<KeyRingSignals>
00080 {
00081 KeyRingSignalReceiver(RpmDb &rpmdb) : _rpmdb(rpmdb)
00082 {
00083 connect();
00084 }
00085
00086 ~KeyRingSignalReceiver()
00087 {
00088 disconnect();
00089 }
00090
00091 virtual void trustedKeyAdded( const PublicKey &key )
00092 {
00093 MIL << "trusted key added to zypp Keyring. Importing" << endl;
00094
00095 try
00096 {
00097 _rpmdb.importPubkey( key );
00098 }
00099 catch (RpmException &e)
00100 {
00101 ERR << "Could not import key " << key.id() << " (" << key.name() << " from " << key.path() << " in rpm database" << endl;
00102 }
00103 }
00104
00105 virtual void trustedKeyRemoved( const PublicKey &key )
00106 {}
00107
00108 RpmDb &_rpmdb;
00109 };
00110
00111 static shared_ptr<KeyRingSignalReceiver> sKeyRingReceiver;
00112
00113 unsigned diffFiles(const string file1, const string file2, string& out, int maxlines)
00114 {
00115 const char* argv[] =
00116 {
00117 "diff",
00118 "-u",
00119 file1.c_str(),
00120 file2.c_str(),
00121 NULL
00122 };
00123 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00124
00125
00126
00127
00128 string line;
00129 int count = 0;
00130 for (line = prog.receiveLine(), count=0;
00131 !line.empty();
00132 line = prog.receiveLine(), count++ )
00133 {
00134 if (maxlines<0?true:count<maxlines)
00135 out+=line;
00136 }
00137
00138 return prog.close();
00139 }
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 inline string stringPath( const Pathname & root_r, const Pathname & sub_r )
00150 {
00151 return librpmDb::stringPath( root_r, sub_r );
00152 }
00153
00154
00155
00156
00157
00158
00159
00160 ostream & operator<<( ostream & str, const RpmDb::DbStateInfoBits & obj )
00161 {
00162 if ( obj == RpmDb::DbSI_NO_INIT )
00163 {
00164 str << "NO_INIT";
00165 }
00166 else
00167 {
00168 #define ENUM_OUT(B,C) str << ( obj & RpmDb::B ? C : '-' )
00169 str << "V4(";
00170 ENUM_OUT( DbSI_HAVE_V4, 'X' );
00171 ENUM_OUT( DbSI_MADE_V4, 'c' );
00172 ENUM_OUT( DbSI_MODIFIED_V4, 'm' );
00173 str << ")V3(";
00174 ENUM_OUT( DbSI_HAVE_V3, 'X' );
00175 ENUM_OUT( DbSI_HAVE_V3TOV4, 'B' );
00176 ENUM_OUT( DbSI_MADE_V3TOV4, 'c' );
00177 str << ")";
00178 #undef ENUM_OUT
00179 }
00180 return str;
00181 }
00182
00184
00185
00187
00188 #define WARNINGMAILPATH "/var/log/YaST2/"
00189 #define FILEFORBACKUPFILES "YaSTBackupModifiedFiles"
00190
00192
00193
00212 class RpmDb::Packages
00213 {
00214 public:
00215 list<Package::Ptr> _list;
00216 map<string,Package::Ptr> _index;
00217 bool _valid;
00218 Packages() : _valid( false )
00219 {}
00220 void clear()
00221 {
00222 _list.clear();
00223 _index.clear();
00224 _valid = false;
00225 }
00226 Package::Ptr lookup( const string & name_r ) const
00227 {
00228 map<string,Package::Ptr>::const_iterator got = _index.find( name_r );
00229 if ( got != _index.end() )
00230 return got->second;
00231 return Package::Ptr();
00232 }
00233 void buildIndex()
00234 {
00235 _index.clear();
00236 for ( list<Package::Ptr>::iterator iter = _list.begin();
00237 iter != _list.end(); ++iter )
00238 {
00239 string name = (*iter)->name();
00240 Package::Ptr & nptr = _index[name];
00241
00242 if ( nptr )
00243 {
00244 WAR << "Multiple entries for package '" << name << "' in rpmdb" << endl;
00245 if ( nptr->installtime() > (*iter)->installtime() )
00246 continue;
00247 else
00248 nptr = *iter;
00249 }
00250 else
00251 {
00252 nptr = *iter;
00253 }
00254 }
00255 _valid = true;
00256 }
00257 };
00258
00260
00262
00263
00264
00266
00267 #define FAILIFNOTINITIALIZED if( ! initialized() ) { ZYPP_THROW(RpmDbNotOpenException()); }
00268
00270
00272
00273
00274
00275
00276
00277 RpmDb::RpmDb()
00278 : _dbStateInfo( DbSI_NO_INIT )
00279 , _packages( * new Packages )
00280 #warning Check for obsolete memebers
00281 , _backuppath ("/var/adm/backup")
00282 , _packagebackups(false)
00283 , _warndirexists(false)
00284 {
00285 process = 0;
00286 exit_code = -1;
00287
00288
00289
00290 setenv( "RPM_IgnoreFailedSymlinks", "1", 1 );
00291 sKeyRingReceiver.reset(new KeyRingSignalReceiver(*this));
00292 }
00293
00295
00296
00297
00298
00299
00300 RpmDb::~RpmDb()
00301 {
00302 MIL << "~RpmDb()" << endl;
00303 closeDatabase();
00304
00305 delete process;
00306 delete &_packages;
00307 MIL << "~RpmDb() end" << endl;
00308 sKeyRingReceiver.reset();
00309 }
00310
00311 Date RpmDb::timestamp() const
00312 {
00313 Date ts_rpm;
00314
00315 Pathname db_path;
00316 if ( dbPath().empty() )
00317 db_path = "/var/lib/rpm";
00318 else
00319 db_path = dbPath();
00320
00321 PathInfo rpmdb_info(root() + db_path + "/Packages");
00322
00323 if ( rpmdb_info.isExist() )
00324 return rpmdb_info.mtime();
00325 else
00326 return Date::now();
00327 }
00329
00330
00331
00332
00333
00334 ostream & RpmDb::dumpOn( ostream & str ) const
00335 {
00336 str << "RpmDb[";
00337
00338 if ( _dbStateInfo == DbSI_NO_INIT )
00339 {
00340 str << "NO_INIT";
00341 }
00342 else
00343 {
00344 #define ENUM_OUT(B,C) str << ( _dbStateInfo & B ? C : '-' )
00345 str << "V4(";
00346 ENUM_OUT( DbSI_HAVE_V4, 'X' );
00347 ENUM_OUT( DbSI_MADE_V4, 'c' );
00348 ENUM_OUT( DbSI_MODIFIED_V4, 'm' );
00349 str << ")V3(";
00350 ENUM_OUT( DbSI_HAVE_V3, 'X' );
00351 ENUM_OUT( DbSI_HAVE_V3TOV4, 'B' );
00352 ENUM_OUT( DbSI_MADE_V3TOV4, 'c' );
00353 str << "): " << stringPath( _root, _dbPath );
00354 #undef ENUM_OUT
00355 }
00356 return str << "]";
00357 }
00358
00360
00361
00362
00363
00364
00365 void RpmDb::initDatabase( Pathname root_r, Pathname dbPath_r )
00366 {
00368
00370 if ( root_r.empty() )
00371 root_r = "/";
00372
00373 if ( dbPath_r.empty() )
00374 dbPath_r = "/var/lib/rpm";
00375
00376 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
00377 {
00378 ERR << "Illegal root or dbPath: " << stringPath( root_r, dbPath_r ) << endl;
00379 ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
00380 }
00381
00382 MIL << "Calling initDatabase: " << stringPath( root_r, dbPath_r ) << endl;
00383
00385
00387 if ( initialized() )
00388 {
00389 if ( root_r == _root && dbPath_r == _dbPath )
00390 {
00391 return;
00392 }
00393 else
00394 {
00395 ZYPP_THROW(RpmDbAlreadyOpenException(_root, _dbPath, root_r, dbPath_r));
00396 }
00397 }
00398
00400
00402 librpmDb::unblockAccess();
00403 DbStateInfoBits info = DbSI_NO_INIT;
00404 try
00405 {
00406 internal_initDatabase( root_r, dbPath_r, info );
00407 }
00408 catch (const RpmException & excpt_r)
00409 {
00410 ZYPP_CAUGHT(excpt_r);
00411 librpmDb::blockAccess();
00412 ERR << "Cleanup on error: state " << info << endl;
00413
00414 if ( dbsi_has( info, DbSI_MADE_V4 ) )
00415 {
00416
00417
00418 removeV4( root_r + dbPath_r, dbsi_has( info, DbSI_MADE_V3TOV4 ) );
00419 }
00420 ZYPP_RETHROW(excpt_r);
00421 }
00422 if ( dbsi_has( info, DbSI_HAVE_V3 ) )
00423 {
00424 if ( root_r == "/" || dbsi_has( info, DbSI_MODIFIED_V4 ) )
00425 {
00426
00427 MIL << "Cleanup: state " << info << endl;
00428 removeV3( root_r + dbPath_r, dbsi_has( info, DbSI_MADE_V3TOV4 ) );
00429 dbsi_clr( info, DbSI_HAVE_V3 );
00430 }
00431 else
00432 {
00433
00434
00435
00436 MIL << "Update mode: Cleanup delayed until closeOldDatabase." << endl;
00437 }
00438 }
00439 #warning CHECK: notify root about conversion backup.
00440
00441 _root = root_r;
00442 _dbPath = dbPath_r;
00443 _dbStateInfo = info;
00444
00445 #warning Add rebuild database once have the info about context
00446 #if 0
00447 if ( ! ( Y2PM::runningFromSystem() ) )
00448 {
00449 if ( dbsi_has( info, DbSI_HAVE_V4 )
00450 && ! dbsi_has( info, DbSI_MADE_V4 ) )
00451 {
00452 err = rebuildDatabase();
00453 }
00454 }
00455 #endif
00456
00457 MIL << "Syncronizing keys with zypp keyring" << endl;
00458
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::importZyppKeyRingTrustedKeys()
00890 {
00891 MIL << "Importing zypp trusted keyring" << std::endl;
00892
00893 std::list<PublicKey> rpm_keys = pubkeys();
00894
00895 std::list<PublicKey> zypp_keys;
00896
00897 zypp_keys = getZYpp()->keyRing()->trustedPublicKeys();
00898
00899 for ( std::list<PublicKey>::const_iterator it = zypp_keys.begin(); it != zypp_keys.end(); ++it)
00900 {
00901
00902 std::list<PublicKey>::iterator ik = find( rpm_keys.begin(), rpm_keys.end(), (*it));
00903 if ( ik != rpm_keys.end() )
00904 {
00905 MIL << "Key " << (*it).id() << " (" << (*it).name() << ") is already in rpm database." << std::endl;
00906 }
00907 else
00908 {
00909
00910 try
00911 {
00912 importPubkey(*it);
00913 MIL << "Trusted key " << (*it).id() << " (" << (*it).name() << ") imported in rpm database." << std::endl;
00914 }
00915 catch (RpmException &e)
00916 {
00917 ERR << "Could not import key " << (*it).id() << " (" << (*it).name() << " from " << (*it).path() << " in rpm database" << std::endl;
00918 }
00919 }
00920 }
00921 }
00922
00923 void RpmDb::exportTrustedKeysInZyppKeyRing()
00924 {
00925 MIL << "Exporting rpm keyring into zypp trusted keyring" <<endl;
00926
00927 set<Edition> rpm_keys = pubkeyEditions();
00928
00929 list<PublicKey> zypp_keys;
00930 zypp_keys = getZYpp()->keyRing()->trustedPublicKeys();
00931
00932 for ( set<Edition>::const_iterator it = rpm_keys.begin(); it != rpm_keys.end(); ++it)
00933 {
00934
00935
00936 string id = str::toUpper( (*it).version() + (*it).release());
00937 list<PublicKey>::iterator ik = find( zypp_keys.begin(), zypp_keys.end(), id);
00938 if ( ik != zypp_keys.end() )
00939 {
00940 MIL << "Key " << (*it) << " is already in zypp database." << endl;
00941 }
00942 else
00943 {
00944
00945 RpmHeader::constPtr result = new RpmHeader();
00946 getData( string("gpg-pubkey"), *it, result );
00947 TmpFile file(getZYpp()->tmpPath());
00948 ofstream os;
00949 try
00950 {
00951 os.open(file.path().asString().c_str());
00952
00953 os << result->tag_description();
00954
00955
00956
00957 os.close();
00958 }
00959 catch (exception &e)
00960 {
00961 ERR << "Could not dump key " << (*it) << " in tmp file " << file.path() << endl;
00962
00963 }
00964
00965
00966 try
00967 {
00968 getZYpp()->keyRing()->importKey( file.path(), true );
00969 MIL << "Trusted key " << (*it) << " imported in zypp keyring." << endl;
00970 }
00971 catch (Exception &e)
00972 {
00973 ERR << "Could not import key " << (*it) << " in zypp keyring" << endl;
00974 }
00975 }
00976 }
00977 }
00978
00980
00981
00982
00983
00984
00985 void RpmDb::importPubkey( const PublicKey & pubkey_r )
00986 {
00987 FAILIFNOTINITIALIZED;
00988
00989
00990
00991 set<Edition> rpm_keys = pubkeyEditions();
00992 string keyshortid = pubkey_r.id().substr(8,8);
00993 MIL << "Comparing '" << keyshortid << "' to: ";
00994 for ( set<Edition>::const_iterator it = rpm_keys.begin(); it != rpm_keys.end(); ++it)
00995 {
00996 string id = str::toUpper( (*it).version() );
00997 MIL << ", '" << id << "'";
00998 if ( id == keyshortid )
00999 {
01000
01001
01002 Date date = Date(str::strtonum<Date::ValueType>("0x" + (*it).release()));
01003 if ( date == pubkey_r.created() )
01004 {
01005
01006 MIL << endl << "Key " << pubkey_r << " is already in the rpm trusted keyring." << endl;
01007 return;
01008 }
01009 else
01010 {
01011 MIL << endl << "Key " << pubkey_r << " has another version in keyring. ( " << date << " & " << pubkey_r.created() << ")" << endl;
01012
01013 }
01014
01015 }
01016 }
01017
01018 MIL << endl;
01019
01020 RpmArgVec opts;
01021 opts.push_back ( "--import" );
01022 opts.push_back ( "--" );
01023 opts.push_back ( pubkey_r.path().asString().c_str() );
01024
01025
01026
01027
01028 _packages._valid = false;
01029 run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
01030
01031 string line;
01032 while ( systemReadLine( line ) )
01033 {
01034 if ( line.substr( 0, 6 ) == "error:" )
01035 {
01036 WAR << line << endl;
01037 }
01038 else
01039 {
01040 DBG << line << endl;
01041 }
01042 }
01043
01044 int rpm_status = systemStatus();
01045
01046 if ( rpm_status != 0 )
01047 {
01048 ZYPP_THROW(RpmSubprocessException(string("Failed to import public key from file ") + pubkey_r.asString() + string(": rpm returned ") + str::numstring(rpm_status)));
01049 }
01050 else
01051 {
01052 MIL << "Key " << pubkey_r << " imported in rpm trusted keyring." << endl;
01053 }
01054 }
01055
01057
01058
01059
01060
01061
01062 list<PublicKey> RpmDb::pubkeys() const
01063 {
01064 list<PublicKey> ret;
01065
01066 librpmDb::db_const_iterator it;
01067 for ( it.findByName( string( "gpg-pubkey" ) ); *it; ++it )
01068 {
01069 Edition edition = it->tag_edition();
01070 if (edition != Edition::noedition)
01071 {
01072
01073 RpmHeader::constPtr result = new RpmHeader();
01074 getData( string("gpg-pubkey"), edition, result );
01075 TmpFile file(getZYpp()->tmpPath());
01076 ofstream os;
01077 try
01078 {
01079 os.open(file.path().asString().c_str());
01080
01081 os << result->tag_description();
01082
01083
01084
01085 os.close();
01086
01087 PublicKey key(file.path());
01088 ret.push_back(key);
01089 }
01090 catch (exception &e)
01091 {
01092 ERR << "Could not dump key " << edition.asString() << " in tmp file " << file.path() << endl;
01093
01094 }
01095 }
01096 }
01097 return ret;
01098 }
01099
01100 set<Edition> RpmDb::pubkeyEditions() const
01101 {
01102 set<Edition> ret;
01103
01104 librpmDb::db_const_iterator it;
01105 for ( it.findByName( string( "gpg-pubkey" ) ); *it; ++it )
01106 {
01107 Edition edition = it->tag_edition();
01108 if (edition != Edition::noedition)
01109 ret.insert( edition );
01110 }
01111 return ret;
01112 }
01113
01115
01116
01117
01118
01119
01120 bool RpmDb::packagesValid() const
01121 {
01122 return( _packages._valid || ! initialized() );
01123 }
01124
01126
01127
01128
01129
01130
01131
01132
01133 const list<Package::Ptr> & RpmDb::getPackages()
01134 {
01135 callback::SendReport<ScanDBReport> report;
01136
01137 report->start ();
01138
01139 try
01140 {
01141 const list<Package::Ptr> & ret = doGetPackages(report);
01142 report->finish(ScanDBReport::NO_ERROR, "");
01143 return ret;
01144 }
01145 catch (RpmException & excpt_r)
01146 {
01147 report->finish(ScanDBReport::FAILED, excpt_r.asUserString ());
01148 ZYPP_RETHROW(excpt_r);
01149 }
01150 #warning fixme
01151 static const list<Package::Ptr> empty_list;
01152 return empty_list;
01153 }
01154
01155 inline static void insertCaps( CapSet &capset, capability::CapabilityImplPtrSet ptrset, CapFactory &factory )
01156 {
01157 for ( capability::CapabilityImplPtrSet::const_iterator it = ptrset.begin();
01158 it != ptrset.end();
01159 ++it )
01160 {
01161 capset.insert( factory.fromImpl(*it) );
01162 }
01163 }
01164
01165
01166
01167
01168
01169 Package::Ptr RpmDb::makePackageFromHeader( const RpmHeader::constPtr header,
01170 set<string> * filerequires,
01171 const Pathname & location, Repository repo )
01172 {
01173 if ( ! header )
01174 return 0;
01175
01176 if ( header->isSrc() )
01177 {
01178 WAR << "Can't make Package from SourcePackage header" << endl;
01179 return 0;
01180 }
01181
01182 Package::Ptr pptr;
01183
01184 string name = header->tag_name();
01185
01186
01187 detail::ResImplTraits<RPMPackageImpl>::Ptr impl( new RPMPackageImpl( header ) );
01188
01189 impl->setRepository( repo );
01190 if (!location.empty())
01191 impl->setLocation( OnMediaLocation(location,1) );
01192
01193 Edition edition;
01194 try
01195 {
01196 edition = Edition( header->tag_version(),
01197 header->tag_release(),
01198 header->tag_epoch());
01199 }
01200 catch (Exception & excpt_r)
01201 {
01202 ZYPP_CAUGHT( excpt_r );
01203 WAR << "Package " << name << " has bad edition '"
01204 << (header->tag_epoch().empty()?"":(header->tag_epoch()+":"))
01205 << header->tag_version()
01206 << (header->tag_release().empty()?"":(string("-") + header->tag_release())) << "'";
01207 return pptr;
01208 }
01209
01210 Arch arch;
01211 try
01212 {
01213 arch = Arch( header->tag_arch() );
01214 }
01215 catch (Exception & excpt_r)
01216 {
01217 ZYPP_CAUGHT( excpt_r );
01218 WAR << "Package " << name << " has bad architecture '" << header->tag_arch() << "'";
01219 return pptr;
01220 }
01221
01222
01223 NVRAD dataCollect( header->tag_name(),
01224 edition,
01225 arch );
01226
01227 list<string> filenames = impl->filenames();
01228 CapFactory capfactory;
01229 insertCaps( dataCollect[Dep::PROVIDES], header->tag_provides( filerequires ), capfactory );
01230
01231 for (list<string>::const_iterator filename = filenames.begin();
01232 filename != filenames.end();
01233 ++filename)
01234 {
01235 if ( capability::isInterestingFileSpec( *filename ) )
01236 {
01237 try
01238 {
01239 dataCollect[Dep::PROVIDES].insert(capfactory.fromImpl(capability::buildFile(ResTraits<Package>::kind, *filename) ));
01240 }
01241 catch (Exception & excpt_r)
01242 {
01243 ZYPP_CAUGHT( excpt_r );
01244 WAR << "Ignoring invalid capability: " << *filename << endl;
01245 }
01246 }
01247 }
01248
01249 insertCaps( dataCollect[Dep::REQUIRES], header->tag_requires( filerequires ), capfactory );
01250 insertCaps( dataCollect[Dep::PREREQUIRES], header->tag_prerequires( filerequires ), capfactory );
01251 insertCaps( dataCollect[Dep::CONFLICTS], header->tag_conflicts( filerequires ), capfactory );
01252 insertCaps( dataCollect[Dep::OBSOLETES], header->tag_obsoletes( filerequires ), capfactory );
01253 insertCaps( dataCollect[Dep::ENHANCES], header->tag_enhances( filerequires ), capfactory );
01254 insertCaps( dataCollect[Dep::SUPPLEMENTS], header->tag_supplements( filerequires ), capfactory );
01255
01256 try
01257 {
01258
01259 pptr = detail::makeResolvableFromImpl( dataCollect, impl );
01260 }
01261 catch (Exception & excpt_r)
01262 {
01263 ZYPP_CAUGHT( excpt_r );
01264 ERR << "Can't create Package::Ptr" << endl;
01265 }
01266
01267 return pptr;
01268 }
01269
01270 const list<Package::Ptr> & RpmDb::doGetPackages(callback::SendReport<ScanDBReport> & report)
01271 {
01272 if ( packagesValid() )
01273 {
01274 return _packages._list;
01275 }
01276
01277 _packages.clear();
01278
01280
01282 unsigned expect = 0;
01283 librpmDb::constPtr dbptr;
01284 librpmDb::dbAccess( dbptr );
01285 expect = dbptr->size();
01286 DBG << "Expecting " << expect << " packages" << endl;
01287
01288 librpmDb::db_const_iterator iter;
01289 unsigned current = 0;
01290 CapFactory _f;
01291 Pathname location;
01292
01293 for ( iter.findAll(); *iter; ++iter, ++current, report->progress( (100*current)/expect))
01294 {
01295
01296 string name = iter->tag_name();
01297 if ( name == string( "gpg-pubkey" ) )
01298 {
01299 DBG << "Ignoring pseudo package " << name << endl;
01300
01301
01302 continue;
01303 }
01304
01305 Package::Ptr pptr = makePackageFromHeader( *iter, &_filerequires, location, Repository() );
01306 if ( ! pptr )
01307 {
01308 WAR << "Failed to make package from database header '" << name << "'" << endl;
01309 continue;
01310 }
01311
01312 _packages._list.push_back( pptr );
01313 }
01314 _packages.buildIndex();
01315 DBG << "Found installed packages: " << _packages._list.size() << endl;
01316
01318
01320 for ( set<string>::iterator it = _filerequires.begin(); it != _filerequires.end(); ++it )
01321 {
01322
01323 for ( iter.findByFile( *it ); *iter; ++iter )
01324 {
01325 Package::Ptr pptr = _packages.lookup( iter->tag_name() );
01326 if ( !pptr )
01327 {
01328 WAR << "rpmdb.findByFile returned unknown package " << *iter << endl;
01329 continue;
01330 }
01331 pptr->injectProvides(_f.parse(ResTraits<Package>::kind, *it));
01332 }
01333
01334 }
01335
01337
01339 return _packages._list;
01340 }
01341
01343
01344
01345
01346
01347
01348
01349
01350 list<FileInfo>
01351 RpmDb::fileList( const string & name_r, const Edition & edition_r ) const
01352 {
01353 list<FileInfo> result;
01354
01355 librpmDb::db_const_iterator it;
01356 bool found;
01357 if (edition_r == Edition::noedition)
01358 {
01359 found = it.findPackage( name_r );
01360 }
01361 else
01362 {
01363 found = it.findPackage( name_r, edition_r );
01364 }
01365 if (!found)
01366 return result;
01367
01368 return result;
01369 }
01370
01371
01373
01374
01375
01376
01377
01378
01379
01380 bool RpmDb::hasFile( const string & file_r, const string & name_r ) const
01381 {
01382 librpmDb::db_const_iterator it;
01383 bool res;
01384 do
01385 {
01386 res = it.findByFile( file_r );
01387 if (!res) break;
01388 if (!name_r.empty())
01389 {
01390 res = (it->tag_name() == name_r);
01391 }
01392 ++it;
01393 }
01394 while (res && *it);
01395 return res;
01396 }
01397
01399
01400
01401
01402
01403
01404
01405
01406 string RpmDb::whoOwnsFile( const string & file_r) const
01407 {
01408 librpmDb::db_const_iterator it;
01409 if (it.findByFile( file_r ))
01410 {
01411 return it->tag_name();
01412 }
01413 return "";
01414 }
01415
01417
01418
01419
01420
01421
01422
01423
01424 bool RpmDb::hasProvides( const string & tag_r ) const
01425 {
01426 librpmDb::db_const_iterator it;
01427 return it.findByProvides( tag_r );
01428 }
01429
01431
01432
01433
01434
01435
01436
01437
01438 bool RpmDb::hasRequiredBy( const string & tag_r ) const
01439 {
01440 librpmDb::db_const_iterator it;
01441 return it.findByRequiredBy( tag_r );
01442 }
01443
01445
01446
01447
01448
01449
01450
01451
01452 bool RpmDb::hasConflicts( const string & tag_r ) const
01453 {
01454 librpmDb::db_const_iterator it;
01455 return it.findByConflicts( tag_r );
01456 }
01457
01459
01460
01461
01462
01463
01464
01465
01466 bool RpmDb::hasPackage( const string & name_r ) const
01467 {
01468 librpmDb::db_const_iterator it;
01469 return it.findPackage( name_r );
01470 }
01471
01473
01474
01475
01476
01477
01478
01479
01480 bool RpmDb::hasPackage( const string & name_r, const Edition & ed_r ) const
01481 {
01482 librpmDb::db_const_iterator it;
01483 return it.findPackage( name_r, ed_r );
01484 }
01485
01487
01488
01489
01490
01491
01492
01493
01494 void RpmDb::getData( const string & name_r,
01495 RpmHeader::constPtr & result_r ) const
01496 {
01497 librpmDb::db_const_iterator it;
01498 it.findPackage( name_r );
01499 result_r = *it;
01500 if (it.dbError())
01501 ZYPP_THROW(*(it.dbError()));
01502 }
01503
01505
01506
01507
01508
01509
01510
01511
01512 void RpmDb::getData( const string & name_r, const Edition & ed_r,
01513 RpmHeader::constPtr & result_r ) const
01514 {
01515 librpmDb::db_const_iterator it;
01516 it.findPackage( name_r, ed_r );
01517 result_r = *it;
01518 if (it.dbError())
01519 ZYPP_THROW(*(it.dbError()));
01520 }
01521
01523
01524
01525
01526
01527 RpmDb::checkPackageResult RpmDb::checkPackage( const Pathname & path_r )
01528 {
01529 PathInfo file( path_r );
01530 if ( ! file.isFile() )
01531 {
01532 ERR << "Not a file: " << file << endl;
01533 return CHK_ERROR;
01534 }
01535
01536 FD_t fd = ::Fopen( file.asString().c_str(), "r.ufdio" );
01537 if ( fd == 0 || ::Ferror(fd) )
01538 {
01539 ERR << "Can't open file for reading: " << file << " (" << ::Fstrerror(fd) << ")" << endl;
01540 if ( fd )
01541 ::Fclose( fd );
01542 return CHK_ERROR;
01543 }
01544
01545 rpmts ts = ::rpmtsCreate();
01546 ::rpmtsSetRootDir( ts, root().asString().c_str() );
01547 ::rpmtsSetVSFlags( ts, RPMVSF_DEFAULT );
01548 int res = ::rpmReadPackageFile( ts, fd, path_r.asString().c_str(), NULL );
01549 ts = ::rpmtsFree(ts);
01550
01551 ::Fclose( fd );
01552
01553 switch ( res )
01554 {
01555 case RPMRC_OK:
01556 return CHK_OK;
01557 break;
01558 case RPMRC_NOTFOUND:
01559 WAR << "Signature is unknown type. " << file << endl;
01560 return CHK_NOTFOUND;
01561 break;
01562 case RPMRC_FAIL:
01563 WAR << "Signature does not verify. " << file << endl;
01564 return CHK_FAIL;
01565 break;
01566 case RPMRC_NOTTRUSTED:
01567 WAR << "Signature is OK, but key is not trusted. " << file << endl;
01568 return CHK_NOTTRUSTED;
01569 break;
01570 case RPMRC_NOKEY:
01571 WAR << "Public key is unavailable. " << file << endl;
01572 return CHK_NOKEY;
01573 break;
01574 }
01575 ERR << "Error reading header." << file << endl;
01576 return CHK_ERROR;
01577 }
01578
01579
01580 bool
01581 RpmDb::queryChangedFiles(FileList & fileList, const string& packageName)
01582 {
01583 bool ok = true;
01584
01585 fileList.clear();
01586
01587 if ( ! initialized() ) return false;
01588
01589 RpmArgVec opts;
01590
01591 opts.push_back ("-V");
01592 opts.push_back ("--nodeps");
01593 opts.push_back ("--noscripts");
01594 opts.push_back ("--nomd5");
01595 opts.push_back ("--");
01596 opts.push_back (packageName.c_str());
01597
01598 run_rpm (opts, ExternalProgram::Discard_Stderr);
01599
01600 if ( process == NULL )
01601 return false;
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614 string line;
01615 while (systemReadLine(line))
01616 {
01617 if (line.length() > 12 &&
01618 (line[0] == 'S' || line[0] == 's' ||
01619 (line[0] == '.' && line[7] == 'T')))
01620 {
01621
01622 string filename;
01623
01624 filename.assign(line, 11, line.length() - 11);
01625 fileList.insert(filename);
01626 }
01627 }
01628
01629 systemStatus();
01630
01631
01632
01633 return ok;
01634 }
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646 void
01647 RpmDb::run_rpm (const RpmArgVec& opts,
01648 ExternalProgram::Stderr_Disposition disp)
01649 {
01650 if ( process )
01651 {
01652 delete process;
01653 process = NULL;
01654 }
01655 exit_code = -1;
01656
01657 if ( ! initialized() )
01658 {
01659 ZYPP_THROW(RpmDbNotOpenException());
01660 }
01661
01662 RpmArgVec args;
01663
01664
01665 args.push_back("rpm");
01666 args.push_back("--root");
01667 args.push_back(_root.asString().c_str());
01668 args.push_back("--dbpath");
01669 args.push_back(_dbPath.asString().c_str());
01670
01671 const char* argv[args.size() + opts.size() + 1];
01672
01673 const char** p = argv;
01674 p = copy (args.begin (), args.end (), p);
01675 p = copy (opts.begin (), opts.end (), p);
01676 *p = 0;
01677
01678
01679
01680 librpmDb::dbRelease( true );
01681
01682
01683 process = new ExternalProgram(argv, disp, false, -1, true);
01684 return;
01685 }
01686
01687
01688
01689
01690 bool
01691 RpmDb::systemReadLine(string &line)
01692 {
01693 line.erase();
01694
01695 if ( process == NULL )
01696 return false;
01697
01698 line = process->receiveLine();
01699
01700 if (line.length() == 0)
01701 return false;
01702
01703 if (line[line.length() - 1] == '\n')
01704 line.erase(line.length() - 1);
01705
01706 return true;
01707 }
01708
01709
01710
01711
01712
01713 int
01714 RpmDb::systemStatus()
01715 {
01716 if ( process == NULL )
01717 return -1;
01718
01719 exit_code = process->close();
01720 process->kill();
01721 delete process;
01722 process = 0;
01723
01724
01725
01726 return exit_code;
01727 }
01728
01729
01730
01731
01732 void
01733 RpmDb::systemKill()
01734 {
01735 if (process) process->kill();
01736 }
01737
01738
01739
01740 void RpmDb::processConfigFiles(const string& line, const string& name, const char* typemsg, const char* difffailmsg, const char* diffgenmsg)
01741 {
01742 string msg = line.substr(9);
01743 string::size_type pos1 = string::npos;
01744 string::size_type pos2 = string::npos;
01745 string file1s, file2s;
01746 Pathname file1;
01747 Pathname file2;
01748
01749 pos1 = msg.find (typemsg);
01750 for (;;)
01751 {
01752 if ( pos1 == string::npos )
01753 break;
01754
01755 pos2 = pos1 + strlen (typemsg);
01756
01757 if (pos2 >= msg.length() )
01758 break;
01759
01760 file1 = msg.substr (0, pos1);
01761 file2 = msg.substr (pos2);
01762
01763 file1s = file1.asString();
01764 file2s = file2.asString();
01765
01766 if (!_root.empty() && _root != "/")
01767 {
01768 file1 = _root + file1;
01769 file2 = _root + file2;
01770 }
01771
01772 string out;
01773 int ret = diffFiles (file1.asString(), file2.asString(), out, 25);
01774 if (ret)
01775 {
01776 Pathname file = _root + WARNINGMAILPATH;
01777 if (filesystem::assert_dir(file) != 0)
01778 {
01779 ERR << "Could not create " << file.asString() << endl;
01780 break;
01781 }
01782 file += Date(Date::now()).form("config_diff_%Y_%m_%d.log");
01783 ofstream notify(file.asString().c_str(), ios::out|ios::app);
01784 if (!notify)
01785 {
01786 ERR << "Could not open " << file << endl;
01787 break;
01788 }
01789
01790
01791
01792 notify << str::form(_("Changed configuration files for %s:"), name.c_str()) << endl;
01793 if (ret>1)
01794 {
01795 ERR << "diff failed" << endl;
01796 notify << str::form(difffailmsg,
01797 file1s.c_str(), file2s.c_str()) << endl;
01798 }
01799 else
01800 {
01801 notify << str::form(diffgenmsg,
01802 file1s.c_str(), file2s.c_str()) << endl;
01803
01804
01805 if (!_root.empty() && _root != "/")
01806 {
01807 if (out.substr(0,4) == "--- ")
01808 {
01809 out.replace(4, file1.asString().length(), file1s);
01810 }
01811 string::size_type pos = out.find("\n+++ ");
01812 if (pos != string::npos)
01813 {
01814 out.replace(pos+5, file2.asString().length(), file2s);
01815 }
01816 }
01817 notify << out << endl;
01818 }
01819 notify.close();
01820 notify.open("/var/lib/update-messages/yast2-packagemanager.rpmdb.configfiles");
01821 notify.close();
01822 }
01823 else
01824 {
01825 WAR << "rpm created " << file2 << " but it is not different from " << file2 << endl;
01826 }
01827 break;
01828 }
01829 }
01830
01832
01833
01834
01835
01836
01837 void RpmDb::installPackage( const Pathname & filename, unsigned flags )
01838 {
01839 callback::SendReport<RpmInstallReport> report;
01840
01841 report->start(filename);
01842
01843 do
01844 try
01845 {
01846 doInstallPackage(filename, flags, report);
01847 report->finish();
01848 break;
01849 }
01850 catch (RpmException & excpt_r)
01851 {
01852 RpmInstallReport::Action user = report->problem( excpt_r );
01853
01854 if ( user == RpmInstallReport::ABORT )
01855 {
01856 report->finish( excpt_r );
01857 ZYPP_RETHROW(excpt_r);
01858 }
01859 else if ( user == RpmInstallReport::IGNORE )
01860 {
01861 break;
01862 }
01863 }
01864 while (true);
01865 }
01866
01867 void RpmDb::doInstallPackage( const Pathname & filename, unsigned flags, callback::SendReport<RpmInstallReport> & report )
01868 {
01869 FAILIFNOTINITIALIZED;
01870 CommitLog progresslog;
01871
01872 MIL << "RpmDb::installPackage(" << filename << "," << flags << ")" << endl;
01873
01874
01875
01876 if ( _packagebackups )
01877 {
01878
01879 if ( ! backupPackage( filename ) )
01880 {
01881 ERR << "backup of " << filename.asString() << " failed" << endl;
01882 }
01883
01884 report->progress( 0 );
01885 }
01886 else
01887 {
01888 report->progress( 100 );
01889 }
01890
01891
01892 RpmArgVec opts;
01893 if (flags & RPMINST_NOUPGRADE)
01894 opts.push_back("-i");
01895 else
01896 opts.push_back("-U");
01897 opts.push_back("--percent");
01898
01899 if (flags & RPMINST_NODIGEST)
01900 opts.push_back("--nodigest");
01901 if (flags & RPMINST_NOSIGNATURE)
01902 opts.push_back("--nosignature");
01903 if (flags & RPMINST_NODOCS)
01904 opts.push_back ("--excludedocs");
01905 if (flags & RPMINST_NOSCRIPTS)
01906 opts.push_back ("--noscripts");
01907 if (flags & RPMINST_FORCE)
01908 opts.push_back ("--force");
01909 if (flags & RPMINST_NODEPS)
01910 opts.push_back ("--nodeps");
01911 if (flags & RPMINST_IGNORESIZE)
01912 opts.push_back ("--ignoresize");
01913 if (flags & RPMINST_JUSTDB)
01914 opts.push_back ("--justdb");
01915 if (flags & RPMINST_TEST)
01916 opts.push_back ("--test");
01917
01918 opts.push_back("--");
01919
01920
01921 string quotedFilename( rpmQuoteFilename( filename ) );
01922 opts.push_back ( quotedFilename.c_str() );
01923
01924 modifyDatabase();
01925 run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
01926
01927 string line;
01928 string rpmmsg;
01929 vector<string> configwarnings;
01930 vector<string> errorlines;
01931
01932 while (systemReadLine(line))
01933 {
01934 if (line.substr(0,2)=="%%")
01935 {
01936 int percent;
01937 sscanf (line.c_str () + 2, "%d", &percent);
01938 report->progress( percent );
01939 }
01940 else
01941 rpmmsg += line+'\n';
01942
01943 if ( line.substr(0,8) == "warning:" )
01944 {
01945 configwarnings.push_back(line);
01946 }
01947 }
01948 int rpm_status = systemStatus();
01949
01950
01951 for (vector<string>::iterator it = configwarnings.begin();
01952 it != configwarnings.end(); ++it)
01953 {
01954 processConfigFiles(*it, Pathname::basename(filename), " saved as ",
01955
01956 _("rpm saved %s as %s, but it was impossible to determine the difference"),
01957
01958 _("rpm saved %s as %s.\nHere are the first 25 lines of difference:\n"));
01959 processConfigFiles(*it, Pathname::basename(filename), " created as ",
01960
01961 _("rpm created %s as %s, but it was impossible to determine the difference"),
01962
01963 _("rpm created %s as %s.\nHere are the first 25 lines of difference:\n"));
01964 }
01965
01966 if ( rpm_status != 0 )
01967 {
01968
01969 progresslog(true) << str::form(_("%s install failed"), Pathname::basename(filename).c_str()) << endl;
01970 progresslog() << _("rpm output:") << endl << rpmmsg << endl;
01971 ZYPP_THROW(RpmSubprocessException(string("RPM failed: ") + rpmmsg));
01972 }
01973 else
01974 {
01975
01976 progresslog(true) << str::form(_("%s installed ok"), Pathname::basename(filename).c_str()) << endl;
01977 if ( ! rpmmsg.empty() )
01978 {
01979 progresslog() << _("Additional rpm output:") << endl << rpmmsg << endl;
01980 }
01981 }
01982 }
01983
01985
01986
01987
01988
01989
01990 void RpmDb::removePackage( Package::constPtr package, unsigned flags )
01991 {
01992 return removePackage( package->name()
01993 + "-" + package->edition().asString()
01994 + "." + package->arch().asString(), flags );
01995 }
01996
01998
01999
02000
02001
02002
02003 void RpmDb::removePackage( const string & name_r, unsigned flags )
02004 {
02005 callback::SendReport<RpmRemoveReport> report;
02006
02007 report->start( name_r );
02008
02009 try
02010 {
02011 doRemovePackage(name_r, flags, report);
02012 }
02013 catch (RpmException & excpt_r)
02014 {
02015 report->finish(excpt_r);
02016 ZYPP_RETHROW(excpt_r);
02017 }
02018 report->finish();
02019 }
02020
02021
02022 void RpmDb::doRemovePackage( const string & name_r, unsigned flags, callback::SendReport<RpmRemoveReport> & report )
02023 {
02024 FAILIFNOTINITIALIZED;
02025 CommitLog progresslog;
02026
02027 MIL << "RpmDb::doRemovePackage(" << name_r << "," << flags << ")" << endl;
02028
02029
02030 if ( _packagebackups )
02031 {
02032
02033
02034 if ( ! backupPackage( name_r ) )
02035 {
02036 ERR << "backup of " << name_r << " failed" << endl;
02037 }
02038 report->progress( 0 );
02039 }
02040 else
02041 {
02042 report->progress( 100 );
02043 }
02044
02045
02046 RpmArgVec opts;
02047 opts.push_back("-e");
02048 opts.push_back("--allmatches");
02049
02050 if (flags & RPMINST_NOSCRIPTS)
02051 opts.push_back("--noscripts");
02052 if (flags & RPMINST_NODEPS)
02053 opts.push_back("--nodeps");
02054 if (flags & RPMINST_JUSTDB)
02055 opts.push_back("--justdb");
02056 if (flags & RPMINST_TEST)
02057 opts.push_back ("--test");
02058 if (flags & RPMINST_FORCE)
02059 {
02060 WAR << "IGNORE OPTION: 'rpm -e' does not support '--force'" << endl;
02061 }
02062
02063 opts.push_back("--");
02064 opts.push_back(name_r.c_str());
02065
02066 modifyDatabase();
02067 run_rpm (opts, ExternalProgram::Stderr_To_Stdout);
02068
02069 string line;
02070 string rpmmsg;
02071
02072
02073
02074
02075
02076 report->progress( 5 );
02077 while (systemReadLine(line))
02078 {
02079 rpmmsg += line+'\n';
02080 }
02081 report->progress( 50 );
02082 int rpm_status = systemStatus();
02083
02084 if ( rpm_status != 0 )
02085 {
02086
02087 progresslog(true) << str::form(_("%s remove failed"), name_r.c_str()) << endl;
02088 progresslog() << _("rpm output:") << endl << rpmmsg << endl;
02089 ZYPP_THROW(RpmSubprocessException(string("RPM failed: ") + rpmmsg));
02090 }
02091 else
02092 {
02093 progresslog(true) << str::form(_("%s remove ok"), name_r.c_str()) << endl;
02094 if ( ! rpmmsg.empty() )
02095 {
02096 progresslog() << _("Additional rpm output:") << endl << rpmmsg << endl;
02097 }
02098 }
02099 }
02100
02102
02103
02104
02105
02106
02107 bool RpmDb::backupPackage( const Pathname & filename )
02108 {
02109 RpmHeader::constPtr h( RpmHeader::readPackage( filename, RpmHeader::NOSIGNATURE ) );
02110 if ( ! h )
02111 return false;
02112
02113 return backupPackage( h->tag_name() );
02114 }
02115
02117
02118
02119
02120
02121
02122 bool RpmDb::backupPackage(const string& packageName)
02123 {
02124 CommitLog progresslog;
02125 bool ret = true;
02126 Pathname backupFilename;
02127 Pathname filestobackupfile = _root+_backuppath+FILEFORBACKUPFILES;
02128
02129 if (_backuppath.empty())
02130 {
02131 INT << "_backuppath empty" << endl;
02132 return false;
02133 }
02134
02135 FileList fileList;
02136
02137 if (!queryChangedFiles(fileList, packageName))
02138 {
02139 ERR << "Error while getting changed files for package " <<
02140 packageName << endl;
02141 return false;
02142 }
02143
02144 if (fileList.size() <= 0)
02145 {
02146 DBG << "package " << packageName << " not changed -> no backup" << endl;
02147 return true;
02148 }
02149
02150 if (filesystem::assert_dir(_root + _backuppath) != 0)
02151 {
02152 return false;
02153 }
02154
02155 {
02156
02157 time_t currentTime = time(0);
02158 struct tm *currentLocalTime = localtime(¤tTime);
02159
02160 int date = (currentLocalTime->tm_year + 1900) * 10000
02161 + (currentLocalTime->tm_mon + 1) * 100
02162 + currentLocalTime->tm_mday;
02163
02164 int num = 0;
02165 do
02166 {
02167 backupFilename = _root + _backuppath
02168 + str::form("%s-%d-%d.tar.gz",packageName.c_str(), date, num);
02169
02170 }
02171 while ( PathInfo(backupFilename).isExist() && num++ < 1000);
02172
02173 PathInfo pi(filestobackupfile);
02174 if (pi.isExist() && !pi.isFile())
02175 {
02176 ERR << filestobackupfile.asString() << " already exists and is no file" << endl;
02177 return false;
02178 }
02179
02180 ofstream fp ( filestobackupfile.asString().c_str(), ios::out|ios::trunc );
02181
02182 if (!fp)
02183 {
02184 ERR << "could not open " << filestobackupfile.asString() << endl;
02185 return false;
02186 }
02187
02188 for (FileList::const_iterator cit = fileList.begin();
02189 cit != fileList.end(); ++cit)
02190 {
02191 string name = *cit;
02192 if ( name[0] == '/' )
02193 {
02194
02195 name = name.substr( 1 );
02196 }
02197 DBG << "saving file "<< name << endl;
02198 fp << name << endl;
02199 }
02200 fp.close();
02201
02202 const char* const argv[] =
02203 {
02204 "tar",
02205 "-czhP",
02206 "-C",
02207 _root.asString().c_str(),
02208 "--ignore-failed-read",
02209 "-f",
02210 backupFilename.asString().c_str(),
02211 "-T",
02212 filestobackupfile.asString().c_str(),
02213 NULL
02214 };
02215
02216
02217 ExternalProgram tar(argv, ExternalProgram::Stderr_To_Stdout, false, -1, true);
02218
02219 string tarmsg;
02220
02221
02222
02223 for (string output = tar.receiveLine(); output.length() ;output = tar.receiveLine())
02224 {
02225 tarmsg+=output;
02226 }
02227
02228 int ret = tar.close();
02229
02230 if ( ret != 0)
02231 {
02232 ERR << "tar failed: " << tarmsg << endl;
02233 ret = false;
02234 }
02235 else
02236 {
02237 MIL << "tar backup ok" << endl;
02238 progresslog(true) << str::form(_("created backup %s"), backupFilename.asString().c_str()) << endl;
02239 }
02240
02241 filesystem::unlink(filestobackupfile);
02242 }
02243
02244 return ret;
02245 }
02246
02247 void RpmDb::setBackupPath(const Pathname& path)
02248 {
02249 _backuppath = path;
02250 }
02251
02252 }
02253 }
02254 }