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).path());
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 for ( set<Edition>::const_iterator it = rpm_keys.begin(); it != rpm_keys.end(); ++it)
00993 {
00994 string id = str::toUpper( (*it).version() );
00995 string keyshortid = pubkey_r.id().substr(8,8);
00996 MIL << "Comparing '" << id << "' to '" << keyshortid << "'" << endl;
00997 if ( id == keyshortid )
00998 {
00999
01000
01001 MIL << "Key " << pubkey_r << " is already in the rpm trusted keyring." << endl;
01002 return;
01003 }
01004 }
01005
01006
01007 RpmArgVec opts;
01008 opts.push_back ( "--import" );
01009 opts.push_back ( "--" );
01010 opts.push_back ( pubkey_r.path().asString().c_str() );
01011
01012
01013
01014
01015 _packages._valid = false;
01016 run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
01017
01018 string line;
01019 while ( systemReadLine( line ) )
01020 {
01021 if ( line.substr( 0, 6 ) == "error:" )
01022 {
01023 WAR << line << endl;
01024 }
01025 else
01026 {
01027 DBG << line << endl;
01028 }
01029 }
01030
01031 int rpm_status = systemStatus();
01032
01033 if ( rpm_status != 0 )
01034 {
01035 ZYPP_THROW(RpmSubprocessException(string("Failed to import public key from file ") + pubkey_r.asString() + string(": rpm returned ") + str::numstring(rpm_status)));
01036 }
01037 else
01038 {
01039 MIL << "Key " << pubkey_r << " imported in rpm trusted keyring." << endl;
01040 }
01041 }
01042
01044
01045
01046
01047
01048
01049 list<PublicKey> RpmDb::pubkeys() const
01050 {
01051 list<PublicKey> ret;
01052
01053 librpmDb::db_const_iterator it;
01054 for ( it.findByName( string( "gpg-pubkey" ) ); *it; ++it )
01055 {
01056 Edition edition = it->tag_edition();
01057 if (edition != Edition::noedition)
01058 {
01059
01060 RpmHeader::constPtr result = new RpmHeader();
01061 getData( string("gpg-pubkey"), edition, result );
01062 TmpFile file(getZYpp()->tmpPath());
01063 ofstream os;
01064 try
01065 {
01066 os.open(file.path().asString().c_str());
01067
01068 os << result->tag_description();
01069
01070
01071
01072 os.close();
01073
01074 PublicKey key(file.path());
01075 ret.push_back(key);
01076 }
01077 catch (exception &e)
01078 {
01079 ERR << "Could not dump key " << edition.asString() << " in tmp file " << file.path() << endl;
01080
01081 }
01082 }
01083 }
01084 return ret;
01085 }
01086
01087 set<Edition> RpmDb::pubkeyEditions() const
01088 {
01089 set<Edition> ret;
01090
01091 librpmDb::db_const_iterator it;
01092 for ( it.findByName( string( "gpg-pubkey" ) ); *it; ++it )
01093 {
01094 Edition edition = it->tag_edition();
01095 if (edition != Edition::noedition)
01096 ret.insert( edition );
01097 }
01098 return ret;
01099 }
01100
01102
01103
01104
01105
01106
01107 bool RpmDb::packagesValid() const
01108 {
01109 return( _packages._valid || ! initialized() );
01110 }
01111
01113
01114
01115
01116
01117
01118
01119
01120 const list<Package::Ptr> & RpmDb::getPackages()
01121 {
01122 callback::SendReport<ScanDBReport> report;
01123
01124 report->start ();
01125
01126 try
01127 {
01128 const list<Package::Ptr> & ret = doGetPackages(report);
01129 report->finish(ScanDBReport::NO_ERROR, "");
01130 return ret;
01131 }
01132 catch (RpmException & excpt_r)
01133 {
01134 report->finish(ScanDBReport::FAILED, excpt_r.asUserString ());
01135 ZYPP_RETHROW(excpt_r);
01136 }
01137 #warning fixme
01138 static const list<Package::Ptr> empty_list;
01139 return empty_list;
01140 }
01141
01142 inline static void insertCaps( CapSet &capset, capability::CapabilityImplPtrSet ptrset, CapFactory &factory )
01143 {
01144 for ( capability::CapabilityImplPtrSet::const_iterator it = ptrset.begin();
01145 it != ptrset.end();
01146 ++it )
01147 {
01148 capset.insert( factory.fromImpl(*it) );
01149 }
01150 }
01151
01152
01153
01154
01155
01156 Package::Ptr RpmDb::makePackageFromHeader( const RpmHeader::constPtr header,
01157 set<string> * filerequires,
01158 const Pathname & location, Repository repo )
01159 {
01160 if ( ! header )
01161 return 0;
01162
01163 if ( header->isSrc() )
01164 {
01165 WAR << "Can't make Package from SourcePackage header" << endl;
01166 return 0;
01167 }
01168
01169 Package::Ptr pptr;
01170
01171 string name = header->tag_name();
01172
01173
01174 detail::ResImplTraits<RPMPackageImpl>::Ptr impl( new RPMPackageImpl( header ) );
01175
01176 impl->setRepository( repo );
01177 if (!location.empty())
01178 impl->setLocation( OnMediaLocation(location,1) );
01179
01180 Edition edition;
01181 try
01182 {
01183 edition = Edition( header->tag_version(),
01184 header->tag_release(),
01185 header->tag_epoch());
01186 }
01187 catch (Exception & excpt_r)
01188 {
01189 ZYPP_CAUGHT( excpt_r );
01190 WAR << "Package " << name << " has bad edition '"
01191 << (header->tag_epoch().empty()?"":(header->tag_epoch()+":"))
01192 << header->tag_version()
01193 << (header->tag_release().empty()?"":(string("-") + header->tag_release())) << "'";
01194 return pptr;
01195 }
01196
01197 Arch arch;
01198 try
01199 {
01200 arch = Arch( header->tag_arch() );
01201 }
01202 catch (Exception & excpt_r)
01203 {
01204 ZYPP_CAUGHT( excpt_r );
01205 WAR << "Package " << name << " has bad architecture '" << header->tag_arch() << "'";
01206 return pptr;
01207 }
01208
01209
01210 NVRAD dataCollect( header->tag_name(),
01211 edition,
01212 arch );
01213
01214 list<string> filenames = impl->filenames();
01215 CapFactory capfactory;
01216 insertCaps( dataCollect[Dep::PROVIDES], header->tag_provides( filerequires ), capfactory );
01217
01218 for (list<string>::const_iterator filename = filenames.begin();
01219 filename != filenames.end();
01220 ++filename)
01221 {
01222 if ( capability::isInterestingFileSpec( *filename ) )
01223 {
01224 try
01225 {
01226 dataCollect[Dep::PROVIDES].insert(capfactory.fromImpl(capability::buildFile(ResTraits<Package>::kind, *filename) ));
01227 }
01228 catch (Exception & excpt_r)
01229 {
01230 ZYPP_CAUGHT( excpt_r );
01231 WAR << "Ignoring invalid capability: " << *filename << endl;
01232 }
01233 }
01234 }
01235
01236 insertCaps( dataCollect[Dep::REQUIRES], header->tag_requires( filerequires ), capfactory );
01237 insertCaps( dataCollect[Dep::PREREQUIRES], header->tag_prerequires( filerequires ), capfactory );
01238 insertCaps( dataCollect[Dep::CONFLICTS], header->tag_conflicts( filerequires ), capfactory );
01239 insertCaps( dataCollect[Dep::OBSOLETES], header->tag_obsoletes( filerequires ), capfactory );
01240 insertCaps( dataCollect[Dep::ENHANCES], header->tag_enhances( filerequires ), capfactory );
01241 insertCaps( dataCollect[Dep::SUPPLEMENTS], header->tag_supplements( filerequires ), capfactory );
01242
01243 try
01244 {
01245
01246 pptr = detail::makeResolvableFromImpl( dataCollect, impl );
01247 }
01248 catch (Exception & excpt_r)
01249 {
01250 ZYPP_CAUGHT( excpt_r );
01251 ERR << "Can't create Package::Ptr" << endl;
01252 }
01253
01254 return pptr;
01255 }
01256
01257 const list<Package::Ptr> & RpmDb::doGetPackages(callback::SendReport<ScanDBReport> & report)
01258 {
01259 if ( packagesValid() )
01260 {
01261 return _packages._list;
01262 }
01263
01264 _packages.clear();
01265
01267
01269 unsigned expect = 0;
01270 librpmDb::constPtr dbptr;
01271 librpmDb::dbAccess( dbptr );
01272 expect = dbptr->size();
01273 DBG << "Expecting " << expect << " packages" << endl;
01274
01275 librpmDb::db_const_iterator iter;
01276 unsigned current = 0;
01277 CapFactory _f;
01278 Pathname location;
01279
01280 for ( iter.findAll(); *iter; ++iter, ++current, report->progress( (100*current)/expect))
01281 {
01282
01283 string name = iter->tag_name();
01284 if ( name == string( "gpg-pubkey" ) )
01285 {
01286 DBG << "Ignoring pseudo package " << name << endl;
01287
01288
01289 continue;
01290 }
01291
01292 Package::Ptr pptr = makePackageFromHeader( *iter, &_filerequires, location, Repository() );
01293 if ( ! pptr )
01294 {
01295 WAR << "Failed to make package from database header '" << name << "'" << endl;
01296 continue;
01297 }
01298
01299 _packages._list.push_back( pptr );
01300 }
01301 _packages.buildIndex();
01302 DBG << "Found installed packages: " << _packages._list.size() << endl;
01303
01305
01307 for ( set<string>::iterator it = _filerequires.begin(); it != _filerequires.end(); ++it )
01308 {
01309
01310 for ( iter.findByFile( *it ); *iter; ++iter )
01311 {
01312 Package::Ptr pptr = _packages.lookup( iter->tag_name() );
01313 if ( !pptr )
01314 {
01315 WAR << "rpmdb.findByFile returned unknown package " << *iter << endl;
01316 continue;
01317 }
01318 pptr->injectProvides(_f.parse(ResTraits<Package>::kind, *it));
01319 }
01320
01321 }
01322
01324
01326 return _packages._list;
01327 }
01328
01330
01331
01332
01333
01334
01335
01336
01337 list<FileInfo>
01338 RpmDb::fileList( const string & name_r, const Edition & edition_r ) const
01339 {
01340 list<FileInfo> result;
01341
01342 librpmDb::db_const_iterator it;
01343 bool found;
01344 if (edition_r == Edition::noedition)
01345 {
01346 found = it.findPackage( name_r );
01347 }
01348 else
01349 {
01350 found = it.findPackage( name_r, edition_r );
01351 }
01352 if (!found)
01353 return result;
01354
01355 return result;
01356 }
01357
01358
01360
01361
01362
01363
01364
01365
01366
01367 bool RpmDb::hasFile( const string & file_r, const string & name_r ) const
01368 {
01369 librpmDb::db_const_iterator it;
01370 bool res;
01371 do
01372 {
01373 res = it.findByFile( file_r );
01374 if (!res) break;
01375 if (!name_r.empty())
01376 {
01377 res = (it->tag_name() == name_r);
01378 }
01379 ++it;
01380 }
01381 while (res && *it);
01382 return res;
01383 }
01384
01386
01387
01388
01389
01390
01391
01392
01393 string RpmDb::whoOwnsFile( const string & file_r) const
01394 {
01395 librpmDb::db_const_iterator it;
01396 if (it.findByFile( file_r ))
01397 {
01398 return it->tag_name();
01399 }
01400 return "";
01401 }
01402
01404
01405
01406
01407
01408
01409
01410
01411 bool RpmDb::hasProvides( const string & tag_r ) const
01412 {
01413 librpmDb::db_const_iterator it;
01414 return it.findByProvides( tag_r );
01415 }
01416
01418
01419
01420
01421
01422
01423
01424
01425 bool RpmDb::hasRequiredBy( const string & tag_r ) const
01426 {
01427 librpmDb::db_const_iterator it;
01428 return it.findByRequiredBy( tag_r );
01429 }
01430
01432
01433
01434
01435
01436
01437
01438
01439 bool RpmDb::hasConflicts( const string & tag_r ) const
01440 {
01441 librpmDb::db_const_iterator it;
01442 return it.findByConflicts( tag_r );
01443 }
01444
01446
01447
01448
01449
01450
01451
01452
01453 bool RpmDb::hasPackage( const string & name_r ) const
01454 {
01455 librpmDb::db_const_iterator it;
01456 return it.findPackage( name_r );
01457 }
01458
01460
01461
01462
01463
01464
01465
01466
01467 bool RpmDb::hasPackage( const string & name_r, const Edition & ed_r ) const
01468 {
01469 librpmDb::db_const_iterator it;
01470 return it.findPackage( name_r, ed_r );
01471 }
01472
01474
01475
01476
01477
01478
01479
01480
01481 void RpmDb::getData( const string & name_r,
01482 RpmHeader::constPtr & result_r ) const
01483 {
01484 librpmDb::db_const_iterator it;
01485 it.findPackage( name_r );
01486 result_r = *it;
01487 if (it.dbError())
01488 ZYPP_THROW(*(it.dbError()));
01489 }
01490
01492
01493
01494
01495
01496
01497
01498
01499 void RpmDb::getData( const string & name_r, const Edition & ed_r,
01500 RpmHeader::constPtr & result_r ) const
01501 {
01502 librpmDb::db_const_iterator it;
01503 it.findPackage( name_r, ed_r );
01504 result_r = *it;
01505 if (it.dbError())
01506 ZYPP_THROW(*(it.dbError()));
01507 }
01508
01510
01511
01512
01513
01514 RpmDb::checkPackageResult RpmDb::checkPackage( const Pathname & path_r )
01515 {
01516 PathInfo file( path_r );
01517 if ( ! file.isFile() )
01518 {
01519 ERR << "Not a file: " << file << endl;
01520 return CHK_ERROR;
01521 }
01522
01523 FD_t fd = ::Fopen( file.asString().c_str(), "r.ufdio" );
01524 if ( fd == 0 || ::Ferror(fd) )
01525 {
01526 ERR << "Can't open file for reading: " << file << " (" << ::Fstrerror(fd) << ")" << endl;
01527 if ( fd )
01528 ::Fclose( fd );
01529 return CHK_ERROR;
01530 }
01531
01532 rpmts ts = ::rpmtsCreate();
01533 ::rpmtsSetRootDir( ts, root().asString().c_str() );
01534 ::rpmtsSetVSFlags( ts, RPMVSF_DEFAULT );
01535 int res = ::rpmReadPackageFile( ts, fd, path_r.asString().c_str(), NULL );
01536 ts = ::rpmtsFree(ts);
01537
01538 ::Fclose( fd );
01539
01540 switch ( res )
01541 {
01542 case RPMRC_OK:
01543 return CHK_OK;
01544 break;
01545 case RPMRC_NOTFOUND:
01546 WAR << "Signature is unknown type. " << file << endl;
01547 return CHK_NOTFOUND;
01548 break;
01549 case RPMRC_FAIL:
01550 WAR << "Signature does not verify. " << file << endl;
01551 return CHK_FAIL;
01552 break;
01553 case RPMRC_NOTTRUSTED:
01554 WAR << "Signature is OK, but key is not trusted. " << file << endl;
01555 return CHK_NOTTRUSTED;
01556 break;
01557 case RPMRC_NOKEY:
01558 WAR << "Public key is unavailable. " << file << endl;
01559 return CHK_NOKEY;
01560 break;
01561 }
01562 ERR << "Error reading header." << file << endl;
01563 return CHK_ERROR;
01564 }
01565
01566
01567 bool
01568 RpmDb::queryChangedFiles(FileList & fileList, const string& packageName)
01569 {
01570 bool ok = true;
01571
01572 fileList.clear();
01573
01574 if ( ! initialized() ) return false;
01575
01576 RpmArgVec opts;
01577
01578 opts.push_back ("-V");
01579 opts.push_back ("--nodeps");
01580 opts.push_back ("--noscripts");
01581 opts.push_back ("--nomd5");
01582 opts.push_back ("--");
01583 opts.push_back (packageName.c_str());
01584
01585 run_rpm (opts, ExternalProgram::Discard_Stderr);
01586
01587 if ( process == NULL )
01588 return false;
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601 string line;
01602 while (systemReadLine(line))
01603 {
01604 if (line.length() > 12 &&
01605 (line[0] == 'S' || line[0] == 's' ||
01606 (line[0] == '.' && line[7] == 'T')))
01607 {
01608
01609 string filename;
01610
01611 filename.assign(line, 11, line.length() - 11);
01612 fileList.insert(filename);
01613 }
01614 }
01615
01616 systemStatus();
01617
01618
01619
01620 return ok;
01621 }
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633 void
01634 RpmDb::run_rpm (const RpmArgVec& opts,
01635 ExternalProgram::Stderr_Disposition disp)
01636 {
01637 if ( process )
01638 {
01639 delete process;
01640 process = NULL;
01641 }
01642 exit_code = -1;
01643
01644 if ( ! initialized() )
01645 {
01646 ZYPP_THROW(RpmDbNotOpenException());
01647 }
01648
01649 RpmArgVec args;
01650
01651
01652 args.push_back("rpm");
01653 args.push_back("--root");
01654 args.push_back(_root.asString().c_str());
01655 args.push_back("--dbpath");
01656 args.push_back(_dbPath.asString().c_str());
01657
01658 const char* argv[args.size() + opts.size() + 1];
01659
01660 const char** p = argv;
01661 p = copy (args.begin (), args.end (), p);
01662 p = copy (opts.begin (), opts.end (), p);
01663 *p = 0;
01664
01665
01666
01667 librpmDb::dbRelease( true );
01668
01669
01670 process = new ExternalProgram(argv, disp, false, -1, true);
01671 return;
01672 }
01673
01674
01675
01676
01677 bool
01678 RpmDb::systemReadLine(string &line)
01679 {
01680 line.erase();
01681
01682 if ( process == NULL )
01683 return false;
01684
01685 line = process->receiveLine();
01686
01687 if (line.length() == 0)
01688 return false;
01689
01690 if (line[line.length() - 1] == '\n')
01691 line.erase(line.length() - 1);
01692
01693 return true;
01694 }
01695
01696
01697
01698
01699
01700 int
01701 RpmDb::systemStatus()
01702 {
01703 if ( process == NULL )
01704 return -1;
01705
01706 exit_code = process->close();
01707 process->kill();
01708 delete process;
01709 process = 0;
01710
01711
01712
01713 return exit_code;
01714 }
01715
01716
01717
01718
01719 void
01720 RpmDb::systemKill()
01721 {
01722 if (process) process->kill();
01723 }
01724
01725
01726
01727 void RpmDb::processConfigFiles(const string& line, const string& name, const char* typemsg, const char* difffailmsg, const char* diffgenmsg)
01728 {
01729 string msg = line.substr(9);
01730 string::size_type pos1 = string::npos;
01731 string::size_type pos2 = string::npos;
01732 string file1s, file2s;
01733 Pathname file1;
01734 Pathname file2;
01735
01736 pos1 = msg.find (typemsg);
01737 for (;;)
01738 {
01739 if ( pos1 == string::npos )
01740 break;
01741
01742 pos2 = pos1 + strlen (typemsg);
01743
01744 if (pos2 >= msg.length() )
01745 break;
01746
01747 file1 = msg.substr (0, pos1);
01748 file2 = msg.substr (pos2);
01749
01750 file1s = file1.asString();
01751 file2s = file2.asString();
01752
01753 if (!_root.empty() && _root != "/")
01754 {
01755 file1 = _root + file1;
01756 file2 = _root + file2;
01757 }
01758
01759 string out;
01760 int ret = diffFiles (file1.asString(), file2.asString(), out, 25);
01761 if (ret)
01762 {
01763 Pathname file = _root + WARNINGMAILPATH;
01764 if (filesystem::assert_dir(file) != 0)
01765 {
01766 ERR << "Could not create " << file.asString() << endl;
01767 break;
01768 }
01769 file += Date(Date::now()).form("config_diff_%Y_%m_%d.log");
01770 ofstream notify(file.asString().c_str(), ios::out|ios::app);
01771 if (!notify)
01772 {
01773 ERR << "Could not open " << file << endl;
01774 break;
01775 }
01776
01777
01778
01779 notify << str::form(_("Changed configuration files for %s:"), name.c_str()) << endl;
01780 if (ret>1)
01781 {
01782 ERR << "diff failed" << endl;
01783 notify << str::form(difffailmsg,
01784 file1s.c_str(), file2s.c_str()) << endl;
01785 }
01786 else
01787 {
01788 notify << str::form(diffgenmsg,
01789 file1s.c_str(), file2s.c_str()) << endl;
01790
01791
01792 if (!_root.empty() && _root != "/")
01793 {
01794 if (out.substr(0,4) == "--- ")
01795 {
01796 out.replace(4, file1.asString().length(), file1s);
01797 }
01798 string::size_type pos = out.find("\n+++ ");
01799 if (pos != string::npos)
01800 {
01801 out.replace(pos+5, file2.asString().length(), file2s);
01802 }
01803 }
01804 notify << out << endl;
01805 }
01806 notify.close();
01807 notify.open("/var/lib/update-messages/yast2-packagemanager.rpmdb.configfiles");
01808 notify.close();
01809 }
01810 else
01811 {
01812 WAR << "rpm created " << file2 << " but it is not different from " << file2 << endl;
01813 }
01814 break;
01815 }
01816 }
01817
01819
01820
01821
01822
01823
01824 void RpmDb::installPackage( const Pathname & filename, unsigned flags )
01825 {
01826 callback::SendReport<RpmInstallReport> report;
01827
01828 report->start(filename);
01829
01830 do
01831 try
01832 {
01833 doInstallPackage(filename, flags, report);
01834 report->finish();
01835 break;
01836 }
01837 catch (RpmException & excpt_r)
01838 {
01839 RpmInstallReport::Action user = report->problem( excpt_r );
01840
01841 if ( user == RpmInstallReport::ABORT )
01842 {
01843 report->finish( excpt_r );
01844 ZYPP_RETHROW(excpt_r);
01845 }
01846 else if ( user == RpmInstallReport::IGNORE )
01847 {
01848 break;
01849 }
01850 }
01851 while (true);
01852 }
01853
01854 void RpmDb::doInstallPackage( const Pathname & filename, unsigned flags, callback::SendReport<RpmInstallReport> & report )
01855 {
01856 FAILIFNOTINITIALIZED;
01857 CommitLog progresslog;
01858
01859 MIL << "RpmDb::installPackage(" << filename << "," << flags << ")" << endl;
01860
01861
01862
01863 if ( _packagebackups )
01864 {
01865
01866 if ( ! backupPackage( filename ) )
01867 {
01868 ERR << "backup of " << filename.asString() << " failed" << endl;
01869 }
01870
01871 report->progress( 0 );
01872 }
01873 else
01874 {
01875 report->progress( 100 );
01876 }
01877
01878
01879 RpmArgVec opts;
01880 if (flags & RPMINST_NOUPGRADE)
01881 opts.push_back("-i");
01882 else
01883 opts.push_back("-U");
01884 opts.push_back("--percent");
01885
01886 if (flags & RPMINST_NODIGEST)
01887 opts.push_back("--nodigest");
01888 if (flags & RPMINST_NOSIGNATURE)
01889 opts.push_back("--nosignature");
01890 if (flags & RPMINST_NODOCS)
01891 opts.push_back ("--excludedocs");
01892 if (flags & RPMINST_NOSCRIPTS)
01893 opts.push_back ("--noscripts");
01894 if (flags & RPMINST_FORCE)
01895 opts.push_back ("--force");
01896 if (flags & RPMINST_NODEPS)
01897 opts.push_back ("--nodeps");
01898 if (flags & RPMINST_IGNORESIZE)
01899 opts.push_back ("--ignoresize");
01900 if (flags & RPMINST_JUSTDB)
01901 opts.push_back ("--justdb");
01902 if (flags & RPMINST_TEST)
01903 opts.push_back ("--test");
01904
01905 opts.push_back("--");
01906
01907
01908 string quotedFilename( rpmQuoteFilename( filename ) );
01909 opts.push_back ( quotedFilename.c_str() );
01910
01911 modifyDatabase();
01912 run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
01913
01914 string line;
01915 string rpmmsg;
01916 vector<string> configwarnings;
01917 vector<string> errorlines;
01918
01919 while (systemReadLine(line))
01920 {
01921 if (line.substr(0,2)=="%%")
01922 {
01923 int percent;
01924 sscanf (line.c_str () + 2, "%d", &percent);
01925 report->progress( percent );
01926 }
01927 else
01928 rpmmsg += line+'\n';
01929
01930 if ( line.substr(0,8) == "warning:" )
01931 {
01932 configwarnings.push_back(line);
01933 }
01934 }
01935 int rpm_status = systemStatus();
01936
01937
01938 for (vector<string>::iterator it = configwarnings.begin();
01939 it != configwarnings.end(); ++it)
01940 {
01941 processConfigFiles(*it, Pathname::basename(filename), " saved as ",
01942
01943 _("rpm saved %s as %s, but it was impossible to determine the difference"),
01944
01945 _("rpm saved %s as %s.\nHere are the first 25 lines of difference:\n"));
01946 processConfigFiles(*it, Pathname::basename(filename), " created as ",
01947
01948 _("rpm created %s as %s, but it was impossible to determine the difference"),
01949
01950 _("rpm created %s as %s.\nHere are the first 25 lines of difference:\n"));
01951 }
01952
01953 if ( rpm_status != 0 )
01954 {
01955
01956 progresslog(true) << str::form(_("%s install failed"), Pathname::basename(filename).c_str()) << endl;
01957 progresslog() << _("rpm output:") << endl << rpmmsg << endl;
01958 ZYPP_THROW(RpmSubprocessException(string("RPM failed: ") + rpmmsg));
01959 }
01960 else
01961 {
01962
01963 progresslog(true) << str::form(_("%s installed ok"), Pathname::basename(filename).c_str()) << endl;
01964 if ( ! rpmmsg.empty() )
01965 {
01966 progresslog() << _("Additional rpm output:") << endl << rpmmsg << endl;
01967 }
01968 }
01969 }
01970
01972
01973
01974
01975
01976
01977 void RpmDb::removePackage( Package::constPtr package, unsigned flags )
01978 {
01979 return removePackage( package->name()
01980 + "-" + package->edition().asString()
01981 + "." + package->arch().asString(), flags );
01982 }
01983
01985
01986
01987
01988
01989
01990 void RpmDb::removePackage( const string & name_r, unsigned flags )
01991 {
01992 callback::SendReport<RpmRemoveReport> report;
01993
01994 report->start( name_r );
01995
01996 try
01997 {
01998 doRemovePackage(name_r, flags, report);
01999 }
02000 catch (RpmException & excpt_r)
02001 {
02002 report->finish(excpt_r);
02003 ZYPP_RETHROW(excpt_r);
02004 }
02005 report->finish();
02006 }
02007
02008
02009 void RpmDb::doRemovePackage( const string & name_r, unsigned flags, callback::SendReport<RpmRemoveReport> & report )
02010 {
02011 FAILIFNOTINITIALIZED;
02012 CommitLog progresslog;
02013
02014 MIL << "RpmDb::doRemovePackage(" << name_r << "," << flags << ")" << endl;
02015
02016
02017 if ( _packagebackups )
02018 {
02019
02020
02021 if ( ! backupPackage( name_r ) )
02022 {
02023 ERR << "backup of " << name_r << " failed" << endl;
02024 }
02025 report->progress( 0 );
02026 }
02027 else
02028 {
02029 report->progress( 100 );
02030 }
02031
02032
02033 RpmArgVec opts;
02034 opts.push_back("-e");
02035 opts.push_back("--allmatches");
02036
02037 if (flags & RPMINST_NOSCRIPTS)
02038 opts.push_back("--noscripts");
02039 if (flags & RPMINST_NODEPS)
02040 opts.push_back("--nodeps");
02041 if (flags & RPMINST_JUSTDB)
02042 opts.push_back("--justdb");
02043 if (flags & RPMINST_TEST)
02044 opts.push_back ("--test");
02045 if (flags & RPMINST_FORCE)
02046 {
02047 WAR << "IGNORE OPTION: 'rpm -e' does not support '--force'" << endl;
02048 }
02049
02050 opts.push_back("--");
02051 opts.push_back(name_r.c_str());
02052
02053 modifyDatabase();
02054 run_rpm (opts, ExternalProgram::Stderr_To_Stdout);
02055
02056 string line;
02057 string rpmmsg;
02058
02059
02060
02061
02062
02063 report->progress( 5 );
02064 while (systemReadLine(line))
02065 {
02066 rpmmsg += line+'\n';
02067 }
02068 report->progress( 50 );
02069 int rpm_status = systemStatus();
02070
02071 if ( rpm_status != 0 )
02072 {
02073
02074 progresslog(true) << str::form(_("%s remove failed"), name_r.c_str()) << endl;
02075 progresslog() << _("rpm output:") << endl << rpmmsg << endl;
02076 ZYPP_THROW(RpmSubprocessException(string("RPM failed: ") + rpmmsg));
02077 }
02078 else
02079 {
02080 progresslog(true) << str::form(_("%s remove ok"), name_r.c_str()) << endl;
02081 if ( ! rpmmsg.empty() )
02082 {
02083 progresslog() << _("Additional rpm output:") << endl << rpmmsg << endl;
02084 }
02085 }
02086 }
02087
02089
02090
02091
02092
02093
02094 bool RpmDb::backupPackage( const Pathname & filename )
02095 {
02096 RpmHeader::constPtr h( RpmHeader::readPackage( filename, RpmHeader::NOSIGNATURE ) );
02097 if ( ! h )
02098 return false;
02099
02100 return backupPackage( h->tag_name() );
02101 }
02102
02104
02105
02106
02107
02108
02109 bool RpmDb::backupPackage(const string& packageName)
02110 {
02111 CommitLog progresslog;
02112 bool ret = true;
02113 Pathname backupFilename;
02114 Pathname filestobackupfile = _root+_backuppath+FILEFORBACKUPFILES;
02115
02116 if (_backuppath.empty())
02117 {
02118 INT << "_backuppath empty" << endl;
02119 return false;
02120 }
02121
02122 FileList fileList;
02123
02124 if (!queryChangedFiles(fileList, packageName))
02125 {
02126 ERR << "Error while getting changed files for package " <<
02127 packageName << endl;
02128 return false;
02129 }
02130
02131 if (fileList.size() <= 0)
02132 {
02133 DBG << "package " << packageName << " not changed -> no backup" << endl;
02134 return true;
02135 }
02136
02137 if (filesystem::assert_dir(_root + _backuppath) != 0)
02138 {
02139 return false;
02140 }
02141
02142 {
02143
02144 time_t currentTime = time(0);
02145 struct tm *currentLocalTime = localtime(¤tTime);
02146
02147 int date = (currentLocalTime->tm_year + 1900) * 10000
02148 + (currentLocalTime->tm_mon + 1) * 100
02149 + currentLocalTime->tm_mday;
02150
02151 int num = 0;
02152 do
02153 {
02154 backupFilename = _root + _backuppath
02155 + str::form("%s-%d-%d.tar.gz",packageName.c_str(), date, num);
02156
02157 }
02158 while ( PathInfo(backupFilename).isExist() && num++ < 1000);
02159
02160 PathInfo pi(filestobackupfile);
02161 if (pi.isExist() && !pi.isFile())
02162 {
02163 ERR << filestobackupfile.asString() << " already exists and is no file" << endl;
02164 return false;
02165 }
02166
02167 ofstream fp ( filestobackupfile.asString().c_str(), ios::out|ios::trunc );
02168
02169 if (!fp)
02170 {
02171 ERR << "could not open " << filestobackupfile.asString() << endl;
02172 return false;
02173 }
02174
02175 for (FileList::const_iterator cit = fileList.begin();
02176 cit != fileList.end(); ++cit)
02177 {
02178 string name = *cit;
02179 if ( name[0] == '/' )
02180 {
02181
02182 name = name.substr( 1 );
02183 }
02184 DBG << "saving file "<< name << endl;
02185 fp << name << endl;
02186 }
02187 fp.close();
02188
02189 const char* const argv[] =
02190 {
02191 "tar",
02192 "-czhP",
02193 "-C",
02194 _root.asString().c_str(),
02195 "--ignore-failed-read",
02196 "-f",
02197 backupFilename.asString().c_str(),
02198 "-T",
02199 filestobackupfile.asString().c_str(),
02200 NULL
02201 };
02202
02203
02204 ExternalProgram tar(argv, ExternalProgram::Stderr_To_Stdout, false, -1, true);
02205
02206 string tarmsg;
02207
02208
02209
02210 for (string output = tar.receiveLine(); output.length() ;output = tar.receiveLine())
02211 {
02212 tarmsg+=output;
02213 }
02214
02215 int ret = tar.close();
02216
02217 if ( ret != 0)
02218 {
02219 ERR << "tar failed: " << tarmsg << endl;
02220 ret = false;
02221 }
02222 else
02223 {
02224 MIL << "tar backup ok" << endl;
02225 progresslog(true) << str::form(_("created backup %s"), backupFilename.asString().c_str()) << endl;
02226 }
02227
02228 filesystem::unlink(filestobackupfile);
02229 }
02230
02231 return ret;
02232 }
02233
02234 void RpmDb::setBackupPath(const Pathname& path)
02235 {
02236 _backuppath = path;
02237 }
02238
02239 }
02240 }
02241 }