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