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