Imported Upstream version 14.45.0
[platform/upstream/libzypp.git] / zypp / target / rpm / RpmDb.cc
index 2b2e51b..8b0cb55 100644 (file)
  *
 */
 #include "librpm.h"
-
+extern "C"
+{
+#include <rpm/rpmcli.h>
+#include <rpm/rpmlog.h>
+}
 #include <cstdlib>
 #include <cstdio>
 #include <ctime>
 
 #include <iostream>
 #include <fstream>
+#include <sstream>
 #include <list>
 #include <map>
 #include <set>
@@ -26,6 +31,7 @@
 
 #include "zypp/base/Logger.h"
 #include "zypp/base/String.h"
+#include "zypp/base/Gettext.h"
 
 #include "zypp/Date.h"
 #include "zypp/Pathname.h"
 #include "zypp/target/rpm/RpmDb.h"
 #include "zypp/target/rpm/RpmCallbacks.h"
 
-#include "zypp/target/CommitLog.h"
+#include "zypp/HistoryLog.h"
 #include "zypp/target/rpm/librpmDb.h"
-#include "zypp/target/rpm/RpmPackageImpl.h"
 #include "zypp/target/rpm/RpmException.h"
-#include "zypp/CapSet.h"
-#include "zypp/CapFactory.h"
+#include "zypp/TmpPath.h"
 #include "zypp/KeyRing.h"
 #include "zypp/ZYppFactory.h"
-#include "zypp/TmpPath.h"
-
-#ifndef _
-#define _(X) X
-#endif
+#include "zypp/ZConfig.h"
 
 using namespace std;
 using namespace zypp::filesystem;
 
-namespace zypp {
-  namespace target {
-    namespace rpm {
+#define WARNINGMAILPATH                "/var/log/YaST2/"
+#define FILEFORBACKUPFILES     "YaSTBackupModifiedFiles"
+#define MAXRPMMESSAGELINES     10000
 
-      struct KeyRingSignalReceiver : callback::ReceiveReport<KeyRingSignals>
-      {
-        KeyRingSignalReceiver(RpmDb &rpmdb) : _rpmdb(rpmdb)
-        {
-          connect();
-        }
+#define WORKAROUNDRPMPWDBUG
 
-        ~KeyRingSignalReceiver()
-        {
-          disconnect();
-        }
+namespace zypp
+{
+  namespace zypp_readonly_hack
+  {
+    bool IGotIt(); // in readonly-mode
+  }
+namespace target
+{
+namespace rpm
+{
+namespace
+{
+#if 1 // No more need to escape whitespace since rpm-4.4.2.3
+const char* quoteInFilename_m = "\'\"";
+#else
+const char* quoteInFilename_m = " \t\'\"";
+#endif
+inline string rpmQuoteFilename( const Pathname & path_r )
+{
+  string path( path_r.asString() );
+  for ( string::size_type pos = path.find_first_of( quoteInFilename_m );
+        pos != string::npos;
+        pos = path.find_first_of( quoteInFilename_m, pos ) )
+  {
+    path.insert( pos, "\\" );
+    pos += 2; // skip '\\' and the quoted char.
+  }
+  return path;
+}
 
-        virtual void trustedKeyAdded( const KeyRing &keyring, const PublicKey &key )
-        {
-          MIL << "trusted key added to zypp Keyring. Syncronizing keys with rpm keyring" << std::endl;
-          _rpmdb.importZyppKeyRingTrustedKeys();
-          _rpmdb.exportTrustedKeysInZyppKeyRing();
-        }
 
-        virtual void trustedKeyRemoved( const KeyRing &keyring, const PublicKey &key  )
-        {
+  /** Workaround bnc#827609 - rpm needs a readable pwd so we
+   * chdir to /. Turn realtive pathnames into absolute ones
+   * by prepending cwd so rpm still finds them
+   */
+  inline Pathname workaroundRpmPwdBug( Pathname path_r )
+  {
+#if defined(WORKAROUNDRPMPWDBUG)
+    if ( path_r.relative() )
+    {
+      // try to prepend cwd
+      AutoDispose<char*> cwd( ::get_current_dir_name(), ::free );
+      if ( cwd )
+       return Pathname( cwd ) / path_r;
+      WAR << "Can't get cwd!" << endl;
+    }
+#endif
+    return path_r;     // no problem with absolute pathnames
+  }
+}
 
-        }
+struct KeyRingSignalReceiver : callback::ReceiveReport<KeyRingSignals>
+{
+  KeyRingSignalReceiver(RpmDb &rpmdb) : _rpmdb(rpmdb)
+  {
+    connect();
+  }
 
-        RpmDb &_rpmdb;
-      };
+  ~KeyRingSignalReceiver()
+  {
+    disconnect();
+  }
+
+  virtual void trustedKeyAdded( const PublicKey &key )
+  {
+    MIL << "trusted key added to zypp Keyring. Importing" << endl;
+    // now import the key in rpm
+    try
+    {
+      _rpmdb.importPubkey( key );
+    }
+    catch (RpmException &e)
+    {
+      ERR << "Could not import key " << key.id() << " (" << key.name() << " from " << key.path() << " in rpm database" << endl;
+    }
+  }
+
+  virtual void trustedKeyRemoved( const PublicKey &key  )
+  {
+    MIL << "Trusted key removed from zypp Keyring. Removing..." << endl;
 
-      static shared_ptr<KeyRingSignalReceiver> sKeyRingReceiver;
+    // remove the key from rpm
+    try
+    {
+      _rpmdb.removePubkey( key );
+    }
+    catch (RpmException &e)
+    {
+      ERR << "Could not remove key " << key.id() << " (" << key.name() << ") from rpm database" << endl;
+    }
+  }
+
+  RpmDb &_rpmdb;
+};
+
+static shared_ptr<KeyRingSignalReceiver> sKeyRingReceiver;
 
-unsigned diffFiles(const std::string file1, const std::string file2, std::string& out, int maxlines)
+unsigned diffFiles(const string file1, const string file2, string& out, int maxlines)
 {
-    const char* argv[] =
+  const char* argv[] =
     {
-       "diff",
-       "-u",
-       file1.c_str(),
-       file2.c_str(),
-       NULL
+      "diff",
+      "-u",
+      file1.c_str(),
+      file2.c_str(),
+      NULL
     };
-    ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
+  ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
 
-    //if(!prog)
-    //return 2;
+  //if(!prog)
+  //return 2;
 
-    string line;
-    int count = 0;
-    for(line = prog.receiveLine(), count=0;
-       !line.empty();
-       line = prog.receiveLine(), count++ )
-    {
-       if(maxlines<0?true:count<maxlines)
-           out+=line;
-    }
+  string line;
+  int count = 0;
+  for (line = prog.receiveLine(), count=0;
+       !line.empty();
+       line = prog.receiveLine(), count++ )
+  {
+    if (maxlines<0?true:count<maxlines)
+      out+=line;
+  }
 
-    return prog.close();
+  return prog.close();
 }
 
 
 
 /******************************************************************
-**
-**
-**     FUNCTION NAME : stringPath
-**     FUNCTION TYPE : inline string
+ **
+ **
+ **    FUNCTION NAME : stringPath
+ **    FUNCTION TYPE : inline string
 */
 inline string stringPath( const Pathname & root_r, const Pathname & sub_r )
 {
@@ -127,16 +197,19 @@ inline string stringPath( const Pathname & root_r, const Pathname & sub_r )
 }
 
 /******************************************************************
-**
-**
-**     FUNCTION NAME : operator<<
-**     FUNCTION TYPE : ostream &
+ **
+ **
+ **    FUNCTION NAME : operator<<
+ **    FUNCTION TYPE : ostream &
 */
 ostream & operator<<( ostream & str, const RpmDb::DbStateInfoBits & obj )
 {
-  if ( obj == RpmDb::DbSI_NO_INIT ) {
+  if ( obj == RpmDb::DbSI_NO_INIT )
+  {
     str << "NO_INIT";
-  } else {
+  }
+  else
+  {
 #define ENUM_OUT(B,C) str << ( obj & RpmDb::B ? C : '-' )
     str << "V4(";
     ENUM_OUT( DbSI_HAVE_V4,    'X' );
@@ -152,77 +225,7 @@ ostream & operator<<( ostream & str, const RpmDb::DbStateInfoBits & obj )
   return str;
 }
 
-///////////////////////////////////////////////////////////////////
-//     CLASS NAME : RpmDbPtr
-//     CLASS NAME : RpmDbconstPtr
-///////////////////////////////////////////////////////////////////
-
-#define WARNINGMAILPATH "/var/log/YaST2/"
-#define FILEFORBACKUPFILES "YaSTBackupModifiedFiles"
-
-///////////////////////////////////////////////////////////////////
-//
-//     CLASS NAME : RpmDb::Packages
-/**
- * Helper class for RpmDb::getPackages() to build the
- * list<Package::Ptr> returned. We have to assert, that there
- * is a unique entry for every string.
- *
- * In the first step we build the _list list which contains all
- * packages (even those which are contained in multiple versions).
- *
- * At the end buildIndex() is called to build the _index is created
- * and points to the last installed versions of all packages.
- * Operations changing the rpmdb
- * content (install/remove package) should set _valid to false. The
- * next call to RpmDb::getPackages() will then reread the the rpmdb.
- *
- * Note that outside RpmDb::getPackages() _list and _index are always
- * in sync. So you may use lookup(PkgName) to retrieve a specific
- * Package::Ptr.
- **/
-class RpmDb::Packages {
-  public:
-    list<Package::Ptr>        _list;
-    map<std::string,Package::Ptr> _index;
-    bool                      _valid;
-    Packages() : _valid( false ) {}
-    void clear() {
-      _list.clear();
-      _index.clear();
-      _valid = false;
-    }
-    Package::Ptr lookup( const string & name_r ) const {
-      map<string,Package::Ptr>::const_iterator got = _index.find( name_r );
-      if ( got != _index.end() )
-       return got->second;
-      return Package::Ptr();
-    }
-    void buildIndex() {
-      _index.clear();
-      for ( list<Package::Ptr>::iterator iter = _list.begin();
-           iter != _list.end(); ++iter )
-      {
-       string name = (*iter)->name();
-       Package::Ptr & nptr = _index[name]; // be shure to get a reference!
-
-       if ( nptr ) {
-         WAR << "Multiple entries for package '" << name << "' in rpmdb" << endl;
-         if ( nptr->installtime() > (*iter)->installtime() )
-           continue;
-         else
-           nptr = *iter;
-       }
-       else
-       {
-         nptr = *iter;
-       }
-      }
-      _valid = true;
-    }
-};
 
-///////////////////////////////////////////////////////////////////
 
 ///////////////////////////////////////////////////////////////////
 //
@@ -242,19 +245,18 @@ class RpmDb::Packages {
 //
 RpmDb::RpmDb()
     : _dbStateInfo( DbSI_NO_INIT )
-    , _packages( * new Packages ) // delete in destructor
 #warning Check for obsolete memebers
     , _backuppath ("/var/adm/backup")
     , _packagebackups(false)
     , _warndirexists(false)
 {
-   process = 0;
-   exit_code = -1;
-
-   // Some rpm versions are patched not to abort installation if
-   // symlink creation failed.
-   setenv( "RPM_IgnoreFailedSymlinks", "1", 1 );
-   sKeyRingReceiver.reset(new KeyRingSignalReceiver(*this));
+  process = 0;
+  exit_code = -1;
+  librpmDb::globalInit();
+  // Some rpm versions are patched not to abort installation if
+  // symlink creation failed.
+  setenv( "RPM_IgnoreFailedSymlinks", "1", 1 );
+  sKeyRingReceiver.reset(new KeyRingSignalReceiver(*this));
 }
 
 ///////////////////////////////////////////////////////////////////
@@ -265,28 +267,46 @@ RpmDb::RpmDb()
 //
 RpmDb::~RpmDb()
 {
-   MIL << "~RpmDb()" << endl;
-   closeDatabase();
-
-   delete process;
-   delete &_packages;
-   MIL  << "~RpmDb() end" << endl;
-   sKeyRingReceiver.reset();
+  MIL << "~RpmDb()" << endl;
+  closeDatabase();
+  delete process;
+  MIL  << "~RpmDb() end" << endl;
+  sKeyRingReceiver.reset();
 }
 
+Date RpmDb::timestamp() const
+{
+  Date ts_rpm;
+
+  Pathname db_path;
+  if ( dbPath().empty() )
+    db_path = "/var/lib/rpm";
+  else
+    db_path = dbPath();
+
+  PathInfo rpmdb_info(root() + db_path + "/Packages");
+
+  if ( rpmdb_info.isExist() )
+    return rpmdb_info.mtime();
+  else
+    return Date::now();
+}
 ///////////////////////////////////////////////////////////////////
 //
 //
 //     METHOD NAME : RpmDb::dumpOn
-//     METHOD TYPE : std::ostream &
+//     METHOD TYPE : ostream &
 //
-std::ostream & RpmDb::dumpOn( std::ostream & str ) const
+ostream & RpmDb::dumpOn( ostream & str ) const
 {
   str << "RpmDb[";
 
-  if ( _dbStateInfo == DbSI_NO_INIT ) {
+  if ( _dbStateInfo == DbSI_NO_INIT )
+  {
     str << "NO_INIT";
-  } else {
+  }
+  else
+  {
 #define ENUM_OUT(B,C) str << ( _dbStateInfo & B ? C : '-' )
     str << "V4(";
     ENUM_OUT( DbSI_HAVE_V4,    'X' );
@@ -308,31 +328,40 @@ std::ostream & RpmDb::dumpOn( std::ostream & str ) const
 //     METHOD NAME : RpmDb::initDatabase
 //     METHOD TYPE : PMError
 //
-void RpmDb::initDatabase( Pathname root_r, Pathname dbPath_r )
+void RpmDb::initDatabase( Pathname root_r, Pathname dbPath_r, bool doRebuild_r )
 {
   ///////////////////////////////////////////////////////////////////
   // Check arguments
   ///////////////////////////////////////////////////////////////////
+  bool quickinit( root_r.empty() );
+
   if ( root_r.empty() )
     root_r = "/";
 
   if ( dbPath_r.empty() )
     dbPath_r = "/var/lib/rpm";
 
-  if ( ! (root_r.absolute() && dbPath_r.absolute()) ) {
+  if ( ! (root_r.absolute() && dbPath_r.absolute()) )
+  {
     ERR << "Illegal root or dbPath: " << stringPath( root_r, dbPath_r ) << endl;
     ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
   }
 
-  MIL << "Calling initDatabase: " << stringPath( root_r, dbPath_r ) << endl;
+  MIL << "Calling initDatabase: " << stringPath( root_r, dbPath_r )
+      << ( doRebuild_r ? " (rebuilddb)" : "" )
+      << ( quickinit ? " (quickinit)" : "" ) << endl;
 
   ///////////////////////////////////////////////////////////////////
   // Check whether already initialized
   ///////////////////////////////////////////////////////////////////
-  if ( initialized() ) {
-    if ( root_r == _root && dbPath_r == _dbPath ) {
+  if ( initialized() )
+  {
+    if ( root_r == _root && dbPath_r == _dbPath )
+    {
       return;
-    } else {
+    }
+    else
+    {
       ZYPP_THROW(RpmDbAlreadyOpenException(_root, _dbPath, root_r, dbPath_r));
     }
   }
@@ -341,8 +370,16 @@ void RpmDb::initDatabase( Pathname root_r, Pathname dbPath_r )
   // init database
   ///////////////////////////////////////////////////////////////////
   librpmDb::unblockAccess();
+
+  if ( quickinit )
+  {
+    MIL << "QUICK initDatabase (no systemRoot set)" << endl;
+    return;
+  }
+
   DbStateInfoBits info = DbSI_NO_INIT;
-  try {
+  try
+  {
     internal_initDatabase( root_r, dbPath_r, info );
   }
   catch (const RpmException & excpt_r)
@@ -351,24 +388,29 @@ void RpmDb::initDatabase( Pathname root_r, Pathname dbPath_r )
     librpmDb::blockAccess();
     ERR << "Cleanup on error: state " << info << endl;
 
-    if ( dbsi_has( info, DbSI_MADE_V4 ) ) {
+    if ( dbsi_has( info, DbSI_MADE_V4 ) )
+    {
       // remove the newly created rpm4 database and
       // any backup created on conversion.
       removeV4( root_r + dbPath_r, dbsi_has( info, DbSI_MADE_V3TOV4 ) );
     }
     ZYPP_RETHROW(excpt_r);
   }
-  if ( dbsi_has( info, DbSI_HAVE_V3 ) ) {
-    if ( root_r == "/" || dbsi_has( info, DbSI_MODIFIED_V4 ) ) {
+  if ( dbsi_has( info, DbSI_HAVE_V3 ) )
+  {
+    if ( root_r == "/" || dbsi_has( info, DbSI_MODIFIED_V4 ) )
+    {
       // Move obsolete rpm3 database beside.
       MIL << "Cleanup: state " << info << endl;
       removeV3( root_r + dbPath_r, dbsi_has( info, DbSI_MADE_V3TOV4 ) );
       dbsi_clr( info, DbSI_HAVE_V3 );
-    } else {
-       // Performing an update: Keep the original rpm3 database
-       // and wait if the rpm4 database gets modified by installing
-       // or removing packages. Cleanup in modifyDatabase or closeDatabase.
-       MIL << "Update mode: Cleanup delayed until closeOldDatabase." << endl;
+    }
+    else
+    {
+      // Performing an update: Keep the original rpm3 database
+      // and wait if the rpm4 database gets modified by installing
+      // or removing packages. Cleanup in modifyDatabase or closeDatabase.
+      MIL << "Update mode: Cleanup delayed until closeOldDatabase." << endl;
     }
   }
 #warning CHECK: notify root about conversion backup.
@@ -377,19 +419,17 @@ void RpmDb::initDatabase( Pathname root_r, Pathname dbPath_r )
   _dbPath = dbPath_r;
   _dbStateInfo = info;
 
-#warning Add rebuild database once have the info about context
-#if 0
-  if ( ! ( Y2PM::runningFromSystem() ) ) {
+  if ( doRebuild_r )
+  {
     if (      dbsi_has( info, DbSI_HAVE_V4 )
-       && ! dbsi_has( info, DbSI_MADE_V4 ) ) {
-      err = rebuildDatabase();
+         && ! dbsi_has( info, DbSI_MADE_V4 ) )
+    {
+      rebuildDatabase();
     }
   }
-#endif
 
-  MIL << "Syncronizing keys with zypp keyring" << std::endl;
-  importZyppKeyRingTrustedKeys();
-  exportTrustedKeysInZyppKeyRing();
+  MIL << "Synchronizing keys with zypp keyring" << endl;
+  syncTrustedKeys();
 
   // Close the database in case any write acces (create/convert)
   // happened during init. This should drop any lock acquired
@@ -407,7 +447,7 @@ void RpmDb::initDatabase( Pathname root_r, Pathname dbPath_r )
 //     METHOD TYPE : PMError
 //
 void RpmDb::internal_initDatabase( const Pathname & root_r, const Pathname & dbPath_r,
-                                     DbStateInfoBits & info_r )
+                                   DbStateInfoBits & info_r )
 {
   info_r = DbSI_NO_INIT;
 
@@ -416,26 +456,33 @@ void RpmDb::internal_initDatabase( const Pathname & root_r, const Pathname & dbP
   ///////////////////////////////////////////////////////////////////
   librpmDb::DbDirInfo dbInfo( root_r, dbPath_r );
 
-  if ( dbInfo.illegalArgs() ) {
+  if ( dbInfo.illegalArgs() )
+  {
     // should not happen (checked in initDatabase)
     ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
   }
-  if ( ! dbInfo.usableArgs() ) {
+  if ( ! dbInfo.usableArgs() )
+  {
     ERR << "Bad database directory: " << dbInfo.dbDir() << endl;
     ZYPP_THROW(RpmInvalidRootException(root_r, dbPath_r));
   }
 
-  if ( dbInfo.hasDbV4() ) {
+  if ( dbInfo.hasDbV4() )
+  {
     dbsi_set( info_r, DbSI_HAVE_V4 );
     MIL << "Found rpm4 database in " << dbInfo.dbDir() << endl;
-  } else {
+  }
+  else
+  {
     MIL << "Creating new rpm4 database in " << dbInfo.dbDir() << endl;
   }
 
-  if ( dbInfo.hasDbV3() ) {
+  if ( dbInfo.hasDbV3() )
+  {
     dbsi_set( info_r, DbSI_HAVE_V3 );
   }
-  if ( dbInfo.hasDbV3ToV4() ) {
+  if ( dbInfo.hasDbV3ToV4() )
+  {
     dbsi_set( info_r, DbSI_HAVE_V3TOV4 );
   }
 
@@ -449,9 +496,11 @@ void RpmDb::internal_initDatabase( const Pathname & root_r, const Pathname & dbP
   // creates dbdir and empty rpm4 database if not present
   librpmDb::dbAccess( root_r, dbPath_r );
 
-  if ( ! dbInfo.hasDbV4() ) {
+  if ( ! dbInfo.hasDbV4() )
+  {
     dbInfo.restat();
-    if ( dbInfo.hasDbV4() ) {
+    if ( dbInfo.hasDbV4() )
+    {
       dbsi_set( info_r, DbSI_HAVE_V4 | DbSI_MADE_V4 );
     }
   }
@@ -466,37 +515,41 @@ void RpmDb::internal_initDatabase( const Pathname & root_r, const Pathname & dbP
   librpmDb::constPtr dbptr;
   librpmDb::dbAccess( dbptr );
   bool dbEmpty = dbptr->empty();
-  if ( dbEmpty ) {
+  if ( dbEmpty )
+  {
     MIL << "Empty rpm4 database "  << dbInfo.dbV4() << endl;
   }
 
-  if ( dbInfo.hasDbV3() ) {
+  if ( dbInfo.hasDbV3() )
+  {
     MIL << "Found rpm3 database " << dbInfo.dbV3() << endl;
 
-    if ( dbEmpty ) {
+    if ( dbEmpty )
+    {
       extern void convertV3toV4( const Pathname & v3db_r, const librpmDb::constPtr & v4db_r );
       convertV3toV4( dbInfo.dbV3().path(), dbptr );
 
       // create a backup copy
       int res = filesystem::copy( dbInfo.dbV3().path(), dbInfo.dbV3ToV4().path() );
-      if ( res ) {
-       WAR << "Backup converted rpm3 database failed: error(" << res << ")" << endl;
-      } else {
-       dbInfo.restat();
-       if ( dbInfo.hasDbV3ToV4() ) {
-         MIL << "Backup converted rpm3 database: " << dbInfo.dbV3ToV4() << endl;
-         dbsi_set( info_r, DbSI_HAVE_V3TOV4 | DbSI_MADE_V3TOV4 );
-       }
+      if ( res )
+      {
+        WAR << "Backup converted rpm3 database failed: error(" << res << ")" << endl;
+      }
+      else
+      {
+        dbInfo.restat();
+        if ( dbInfo.hasDbV3ToV4() )
+        {
+          MIL << "Backup converted rpm3 database: " << dbInfo.dbV3ToV4() << endl;
+          dbsi_set( info_r, DbSI_HAVE_V3TOV4 | DbSI_MADE_V3TOV4 );
+        }
       }
 
-    } else {
+    }
+    else
+    {
 
       WAR << "Non empty rpm3 and rpm4 database found: using rpm4" << endl;
-#warning EXCEPTION: nonempty rpm4 and rpm3 database found.
-      //ConvertDbReport::Send report( RpmDbCallbacks::convertDbReport );
-      //report->start( dbInfo.dbV3().path() );
-      //report->stop( some error );
-
       // set DbSI_MODIFIED_V4 as it's not a temporary which can be removed.
       dbsi_set( info_r, DbSI_MODIFIED_V4 );
 
@@ -506,7 +559,8 @@ void RpmDb::internal_initDatabase( const Pathname & root_r, const Pathname & dbP
     librpmDb::dumpState( DBG ) << endl;
   }
 
-  if ( dbInfo.hasDbV3ToV4() ) {
+  if ( dbInfo.hasDbV3ToV4() )
+  {
     MIL << "Rpm3 database backup: " << dbInfo.dbV3ToV4() << endl;
   }
 }
@@ -521,49 +575,56 @@ void RpmDb::removeV4( const Pathname & dbdir_r, bool v3backup_r )
 {
   const char * v3backup = "packages.rpm3";
   const char * master = "Packages";
-  const char * index[] = {
-    "Basenames",
-    "Conflictname",
-    "Depends",
-    "Dirnames",
-    "Filemd5s",
-    "Group",
-    "Installtid",
-    "Name",
-    "Providename",
-    "Provideversion",
-    "Pubkeys",
-    "Requirename",
-    "Requireversion",
-    "Sha1header",
-    "Sigmd5",
-    "Triggername",
-    // last entry!
-    NULL
-  };
+  const char * index[] =
+    {
+      "Basenames",
+      "Conflictname",
+      "Depends",
+      "Dirnames",
+      "Filemd5s",
+      "Group",
+      "Installtid",
+      "Name",
+      "Providename",
+      "Provideversion",
+      "Pubkeys",
+      "Requirename",
+      "Requireversion",
+      "Sha1header",
+      "Sigmd5",
+      "Triggername",
+      // last entry!
+      NULL
+    };
 
   PathInfo pi( dbdir_r );
-  if ( ! pi.isDir() ) {
+  if ( ! pi.isDir() )
+  {
     ERR << "Can't remove rpm4 database in non directory: " << dbdir_r << endl;
     return;
   }
 
-  for ( const char ** f = index; *f; ++f ) {
+  for ( const char ** f = index; *f; ++f )
+  {
     pi( dbdir_r + *f );
-    if ( pi.isFile() ) {
+    if ( pi.isFile() )
+    {
       filesystem::unlink( pi.path() );
     }
   }
 
   pi( dbdir_r + master );
-  if ( pi.isFile() ) {
+  if ( pi.isFile() )
+  {
     MIL << "Removing rpm4 database " << pi << endl;
     filesystem::unlink( pi.path() );
   }
 
-  if ( v3backup_r ) {
+  if ( v3backup_r )
+  {
     pi( dbdir_r + v3backup );
-    if ( pi.isFile() ) {
+    if ( pi.isFile() )
+    {
       MIL << "Removing converted rpm3 database backup " << pi << endl;
       filesystem::unlink( pi.path() );
     }
@@ -579,46 +640,55 @@ void RpmDb::removeV4( const Pathname & dbdir_r, bool v3backup_r )
 void RpmDb::removeV3( const Pathname & dbdir_r, bool v3backup_r )
 {
   const char * master = "packages.rpm";
-  const char * index[] = {
-    "conflictsindex.rpm",
-    "fileindex.rpm",
-    "groupindex.rpm",
-    "nameindex.rpm",
-    "providesindex.rpm",
-    "requiredby.rpm",
-    "triggerindex.rpm",
-    // last entry!
-    NULL
-  };
+  const char * index[] =
+    {
+      "conflictsindex.rpm",
+      "fileindex.rpm",
+      "groupindex.rpm",
+      "nameindex.rpm",
+      "providesindex.rpm",
+      "requiredby.rpm",
+      "triggerindex.rpm",
+      // last entry!
+      NULL
+    };
 
   PathInfo pi( dbdir_r );
-  if ( ! pi.isDir() ) {
+  if ( ! pi.isDir() )
+  {
     ERR << "Can't remove rpm3 database in non directory: " << dbdir_r << endl;
     return;
   }
 
-  for ( const char ** f = index; *f; ++f ) {
+  for ( const char ** f = index; *f; ++f )
+  {
     pi( dbdir_r + *f );
-    if ( pi.isFile() ) {
+    if ( pi.isFile() )
+    {
       filesystem::unlink( pi.path() );
     }
   }
 
 #warning CHECK: compare vs existing v3 backup. notify root
   pi( dbdir_r + master );
-  if ( pi.isFile() ) {
+  if ( pi.isFile() )
+  {
     Pathname m( pi.path() );
-    if ( v3backup_r ) {
+    if ( v3backup_r )
+    {
       // backup was already created
       filesystem::unlink( m );
       Pathname b( m.extend( "3" ) );
       pi( b ); // stat backup
-    } else {
+    }
+    else
+    {
       Pathname b( m.extend( ".deleted" ) );
       pi( b );
-      if ( pi.isFile() ) {
-       // rempve existing backup
-       filesystem::unlink( b );
+      if ( pi.isFile() )
+      {
+        // rempve existing backup
+        filesystem::unlink( b );
       }
       filesystem::rename( m, b );
       pi( b ); // stat backup
@@ -642,14 +712,12 @@ void RpmDb::modifyDatabase()
   dbsi_set( _dbStateInfo, DbSI_MODIFIED_V4 );
 
   // Move outdated rpm3 database beside.
-  if ( dbsi_has( _dbStateInfo, DbSI_HAVE_V3 ) ) {
+  if ( dbsi_has( _dbStateInfo, DbSI_HAVE_V3 ) )
+  {
     MIL << "Update mode: Delayed cleanup: state " << _dbStateInfo << endl;
     removeV3( _root + _dbPath, dbsi_has( _dbStateInfo, DbSI_MADE_V3TOV4 ) );
     dbsi_clr( _dbStateInfo, DbSI_HAVE_V3 );
   }
-
-  // invalidate Packages list
-  _packages._valid = false;
 }
 
 ///////////////////////////////////////////////////////////////////
@@ -660,7 +728,8 @@ void RpmDb::modifyDatabase()
 //
 void RpmDb::closeDatabase()
 {
-  if ( ! initialized() ) {
+  if ( ! initialized() )
+  {
     return;
   }
 
@@ -669,18 +738,21 @@ void RpmDb::closeDatabase()
   ///////////////////////////////////////////////////////////////////
   // Block further database access
   ///////////////////////////////////////////////////////////////////
-  _packages.clear();
   librpmDb::blockAccess();
 
   ///////////////////////////////////////////////////////////////////
   // Check fate if old version database still present
   ///////////////////////////////////////////////////////////////////
-  if ( dbsi_has( _dbStateInfo, DbSI_HAVE_V3 ) ) {
+  if ( dbsi_has( _dbStateInfo, DbSI_HAVE_V3 ) )
+  {
     MIL << "Update mode: Delayed cleanup: state " << _dbStateInfo << endl;
-    if ( dbsi_has( _dbStateInfo, DbSI_MODIFIED_V4 ) ) {
+    if ( dbsi_has( _dbStateInfo, DbSI_MODIFIED_V4 ) )
+    {
       // Move outdated rpm3 database beside.
       removeV3( _root + _dbPath, dbsi_has( _dbStateInfo, DbSI_MADE_V3TOV4 )  );
-    } else {
+    }
+    else
+    {
       // Remove unmodified rpm4 database
       removeV4( _root + _dbPath, dbsi_has( _dbStateInfo, DbSI_MADE_V3TOV4 ) );
     }
@@ -707,12 +779,13 @@ void RpmDb::rebuildDatabase()
 
   report->start( root() + dbPath() );
 
-  try {
+  try
+  {
     doRebuildDatabase(report);
   }
   catch (RpmException & excpt_r)
   {
-    report->finish(root() + dbPath(), RebuildDBReport::FAILED, excpt_r.asUserString());
+    report->finish(root() + dbPath(), RebuildDBReport::FAILED, excpt_r.asUserHistory());
     ZYPP_RETHROW(excpt_r);
   }
   report->finish(root() + dbPath(), RebuildDBReport::NO_ERROR, "");
@@ -723,7 +796,7 @@ void RpmDb::doRebuildDatabase(callback::SendReport<RebuildDBReport> & report)
   FAILIFNOTINITIALIZED;
 
   MIL << "RpmDb::rebuildDatabase" << *this << endl;
-// FIXME  Timecount _t( "RpmDb::rebuildDatabase" );
+  // FIXME  Timecount _t( "RpmDb::rebuildDatabase" );
 
   PathInfo dbMaster( root() + dbPath() + "Packages" );
   PathInfo dbMasterBackup( dbMaster.path().extend( ".y2backup" ) );
@@ -735,167 +808,397 @@ void RpmDb::doRebuildDatabase(callback::SendReport<RebuildDBReport> & report)
 
   // don't call modifyDatabase because it would remove the old
   // rpm3 database, if the current database is a temporary one.
-  // But do invalidate packages list.
-  _packages._valid = false;
   run_rpm (opts, ExternalProgram::Stderr_To_Stdout);
 
   // progress report: watch this file growing
   PathInfo newMaster( root()
-                     + dbPath().extend( str::form( "rebuilddb.%d",
-                                                          process?process->getpid():0) )
-                     + "Packages" );
+                      + dbPath().extend( str::form( "rebuilddb.%d",
+                                                    process?process->getpid():0) )
+                      + "Packages" );
 
   string       line;
   string       errmsg;
 
-  while ( systemReadLine( line ) ) {
-    if ( newMaster() ) { // file is removed at the end of rebuild.
+  while ( systemReadLine( line ) )
+  {
+    if ( newMaster() )
+    { // file is removed at the end of rebuild.
       // current size should be upper limit for new db
-      report->progress( (100 * newMaster.size()) / dbMaster.size(), root() + dbPath());
+      if ( ! report->progress( (100 * newMaster.size()) / dbMaster.size(), root() + dbPath()) )
+      {
+        WAR << "User requested abort." << endl;
+        systemKill();
+        filesystem::recursive_rmdir( newMaster.path().dirname() );
+      }
     }
 
-    if ( line.compare( 0, 2, "D:" ) ) {
+    if ( line.compare( 0, 2, "D:" ) )
+    {
       errmsg += line + '\n';
-//      report.notify( line );
+      //      report.notify( line );
       WAR << line << endl;
     }
   }
 
   int rpm_status = systemStatus();
 
-  if ( rpm_status != 0 ) {
-    ZYPP_THROW(RpmSubprocessException(string("rpm failed with message: ") + errmsg));
-  } else {
+  if ( rpm_status != 0 )
+  {
+    //TranslatorExplanation after semicolon is error message
+    ZYPP_THROW(RpmSubprocessException(string(_("RPM failed: ") +
+               (errmsg.empty() ? error_message: errmsg))));
+  }
+  else
+  {
     report->progress( 100, root() + dbPath() ); // 100%
   }
 }
 
-void RpmDb::exportTrustedKeysInZyppKeyRing()
+///////////////////////////////////////////////////////////////////
+namespace
 {
-  MIL << "Exporting rpm keyring into zypp trusted keyring" <<std::endl;
-
-  std::set<Edition> rpm_keys = pubkeyEditions();
-
-  std::list<PublicKey> zypp_keys;
-  zypp_keys = getZYpp()->keyRing()->trustedPublicKeys();
-
-  for ( std::set<Edition>::const_iterator it = rpm_keys.begin(); it != rpm_keys.end(); ++it)
+  /** \ref RpmDb::syncTrustedKeys helper
+   * Compute which keys need to be exprted to / imported from the zypp keyring.
+   * Return result via argument list.
+   */
+  void computeKeyRingSync( std::set<Edition> & rpmKeys_r, std::list<PublicKeyData> & zyppKeys_r )
   {
-    // search the zypp key into the rpm keys
-    // long id is edition version + release
-    std::string id = str::toUpper( (*it).version() + (*it).release());
-    std::list<PublicKey>::iterator ik = find( zypp_keys.begin(), zypp_keys.end(), id);
-    if ( ik != zypp_keys.end() )
-    {
-      MIL << "Key " << (*it) << " is already in zypp database." << std::endl;
-    }
-    else
+    ///////////////////////////////////////////////////////////////////
+    // Remember latest release and where it ocurred
+    struct Key
     {
-      // we export the rpm key into a file
-      RpmHeader::constPtr result = new RpmHeader();
-      getData( std::string("gpg-pubkey"), *it, result );
-      TmpFile file(getZYpp()->tmpPath());
-      std::ofstream os;
-      try
+      Key()
+       : _inRpmKeys( nullptr )
+       , _inZyppKeys( nullptr )
+      {}
+
+      void updateIf( const Edition & rpmKey_r )
       {
-        os.open(file.path().asString().c_str());
-        // dump rpm key into the tmp file
-        os << result->tag_description();
-        //MIL << "-----------------------------------------------" << std::endl;
-        //MIL << result->tag_description() <<std::endl;
-        //MIL << "-----------------------------------------------" << std::endl;
-        os.close();
+       std::string keyRelease( rpmKey_r.release() );
+       int comp = _release.compare( keyRelease );
+       if ( comp < 0 )
+       {
+         // update to newer release
+         _release.swap( keyRelease );
+         _inRpmKeys  = &rpmKey_r;
+         _inZyppKeys = nullptr;
+         if ( !keyRelease.empty() )
+           DBG << "Old key in R: gpg-pubkey-" << rpmKey_r.version() << "-" <<  keyRelease << endl;
+       }
+       else if ( comp == 0 )
+       {
+         // stay with this release
+         if ( ! _inRpmKeys )
+           _inRpmKeys = &rpmKey_r;
+       }
+       // else: this is an old release
+       else
+         DBG << "Old key in R: gpg-pubkey-" << rpmKey_r.version() << "-" <<  keyRelease << endl;
       }
-      catch (std::exception &e)
+
+      void updateIf( const PublicKeyData & zyppKey_r )
       {
-        ERR << "Could not dump key " << (*it) << " in tmp file " << file.path() << std::endl;
-        // just ignore the key
+       std::string keyRelease( zyppKey_r.gpgPubkeyRelease() );
+       int comp = _release.compare( keyRelease );
+       if ( comp < 0 )
+       {
+         // update to newer release
+         _release.swap( keyRelease );
+         _inRpmKeys  = nullptr;
+         _inZyppKeys = &zyppKey_r;
+         if ( !keyRelease.empty() )
+           DBG << "Old key in Z: gpg-pubkey-" << zyppKey_r.gpgPubkeyVersion() << "-" << keyRelease << endl;
+       }
+       else if ( comp == 0 )
+       {
+         // stay with this release
+         if ( ! _inZyppKeys )
+           _inZyppKeys = &zyppKey_r;
+       }
+       // else: this is an old release
+       else
+         DBG << "Old key in Z: gpg-pubkey-" << zyppKey_r.gpgPubkeyVersion() << "-" << keyRelease << endl;
       }
 
-      // now import the key in zypp
-      try
+      std::string _release;
+      const Edition * _inRpmKeys;
+      const PublicKeyData * _inZyppKeys;
+    };
+    ///////////////////////////////////////////////////////////////////
+
+    // collect keys by ID(version) and latest creation(release)
+    std::map<std::string,Key> _keymap;
+
+    for_( it, rpmKeys_r.begin(), rpmKeys_r.end() )
+    {
+      _keymap[(*it).version()].updateIf( *it );
+    }
+
+    for_( it, zyppKeys_r.begin(), zyppKeys_r.end() )
+    {
+      _keymap[(*it).gpgPubkeyVersion()].updateIf( *it );
+    }
+
+    // compute missing keys
+    std::set<Edition> rpmKeys;
+    std::list<PublicKeyData> zyppKeys;
+    for_( it, _keymap.begin(), _keymap.end() )
+    {
+      DBG << "gpg-pubkey-" << (*it).first << "-" << (*it).second._release << " "
+          << ( (*it).second._inRpmKeys  ? "R" : "_" )
+         << ( (*it).second._inZyppKeys ? "Z" : "_" ) << endl;
+      if ( ! (*it).second._inRpmKeys )
       {
-        getZYpp()->keyRing()->importKey( file.path(), true /*trusted*/);
-        MIL << "Trusted key " << (*it) << " imported in zypp keyring." << std::endl;
+       zyppKeys.push_back( *(*it).second._inZyppKeys );
       }
-      catch (Exception &e)
+      if ( ! (*it).second._inZyppKeys )
       {
-        ERR << "Could not import key " << (*it) << " in zypp keyring" << std::endl;
+       rpmKeys.insert( *(*it).second._inRpmKeys );
       }
     }
+    rpmKeys_r.swap( rpmKeys );
+    zyppKeys_r.swap( zyppKeys );
   }
-}
+} // namespace
+///////////////////////////////////////////////////////////////////
 
-void RpmDb::importZyppKeyRingTrustedKeys()
+void RpmDb::syncTrustedKeys( SyncTrustedKeyBits mode_r )
 {
-  MIL << "Importing zypp trusted keyring" << std::endl;
+  MIL << "Going to sync trusted keys..." << endl;
+  std::set<Edition> rpmKeys( pubkeyEditions() );
+  std::list<PublicKeyData> zyppKeys( getZYpp()->keyRing()->trustedPublicKeyData() );
+  computeKeyRingSync( rpmKeys, zyppKeys );
+  MIL << (mode_r & SYNC_TO_KEYRING   ? "" : "(skip) ") << "Rpm keys to export into zypp trusted keyring: " << rpmKeys.size() << endl;
+  MIL << (mode_r & SYNC_FROM_KEYRING ? "" : "(skip) ") << "Zypp trusted keys to import into rpm database: " << zyppKeys.size() << endl;
 
-  std::list<PublicKey> rpm_keys = pubkeys();
-
-  std::list<PublicKey> zypp_keys;
-
-  zypp_keys = getZYpp()->keyRing()->trustedPublicKeys();
-
-  for ( std::list<PublicKey>::const_iterator it = zypp_keys.begin(); it != zypp_keys.end(); ++it)
+  ///////////////////////////////////////////////////////////////////
+  if ( (mode_r & SYNC_TO_KEYRING) &&  ! rpmKeys.empty() )
   {
-    // we find only the left part of the long gpg key, as rpm does not support long ids
-    std::list<PublicKey>::iterator ik = find( rpm_keys.begin(), rpm_keys.end(), (*it));
-    if ( ik != rpm_keys.end() )
+    // export to zypp keyring
+    MIL << "Exporting rpm keyring into zypp trusted keyring" <<endl;
+    // Temporarily disconnect to prevent the attemt to re-import the exported keys.
+    callback::TempConnect<KeyRingSignals> tempDisconnect;
+    librpmDb::db_const_iterator keepDbOpen; // just to keep a ref.
+
+    TmpFile tmpfile( getZYpp()->tmpPath() );
     {
-      MIL << "Key " << (*it).id() << " (" << (*it).name() << ") is already in rpm database." << std::endl;
+      ofstream tmpos( tmpfile.path().c_str() );
+      for_( it, rpmKeys.begin(), rpmKeys.end() )
+      {
+       // we export the rpm key into a file
+       RpmHeader::constPtr result;
+       getData( string("gpg-pubkey"), *it, result );
+       tmpos << result->tag_description() << endl;
+      }
     }
-    else
+    try
+    {
+      getZYpp()->keyRing()->multiKeyImport( tmpfile.path(), true /*trusted*/);
+    }
+    catch (Exception &e)
+    {
+      ERR << "Could not import keys into in zypp keyring" << endl;
+    }
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  if ( (mode_r & SYNC_FROM_KEYRING) && ! zyppKeys.empty() )
+  {
+    // import from zypp keyring
+    MIL << "Importing zypp trusted keyring" << std::endl;
+    for_( it, zyppKeys.begin(), zyppKeys.end() )
     {
-      // now import the key in rpm
       try
       {
-        importPubkey((*it).path());
-        MIL << "Trusted key " << (*it).id() << " (" << (*it).name() << ") imported in rpm database." << std::endl;
+       importPubkey( getZYpp()->keyRing()->exportTrustedPublicKey( *it ) );
       }
-      catch (RpmException &e)
+      catch ( const RpmException & exp )
       {
-        ERR << "Could not import key " << (*it).id() << " (" << (*it).name() << " from " << (*it).path() << " in rpm database" << std::endl;
+       ZYPP_CAUGHT( exp );
       }
     }
   }
+  MIL << "Trusted keys synced." << endl;
 }
 
+void RpmDb::importZyppKeyRingTrustedKeys()
+{ syncTrustedKeys( SYNC_FROM_KEYRING ); }
+
+void RpmDb::exportTrustedKeysInZyppKeyRing()
+{ syncTrustedKeys( SYNC_TO_KEYRING ); }
+
 ///////////////////////////////////////////////////////////////////
 //
 //
 //     METHOD NAME : RpmDb::importPubkey
 //     METHOD TYPE : PMError
 //
-void RpmDb::importPubkey( const Pathname & pubkey_r )
+void RpmDb::importPubkey( const PublicKey & pubkey_r )
 {
   FAILIFNOTINITIALIZED;
 
-  RpmArgVec opts;
-  opts.push_back ( "--import" );
-  opts.push_back ( "--" );
-  opts.push_back ( pubkey_r.asString().c_str() );
+  // bnc#828672: On the fly key import in READONLY
+  if ( zypp_readonly_hack::IGotIt() )
+  {
+    WAR << "Key " << pubkey_r << " can not be imported. (READONLY MODE)" << endl;
+    return;
+  }
 
-  // don't call modifyDatabase because it would remove the old
-  // rpm3 database, if the current database is a temporary one.
-  // But do invalidate packages list.
-  _packages._valid = false;
-  run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
+  // check if the key is already in the rpm database
+  Edition keyEd( pubkey_r.gpgPubkeyVersion(), pubkey_r.gpgPubkeyRelease() );
+  set<Edition> rpmKeys = pubkeyEditions();
+  bool hasOldkeys = false;
 
-  string line;
-  while ( systemReadLine( line ) ) {
-    if ( line.substr( 0, 6 ) == "error:" ) {
-      WAR << line << endl;
-    } else {
-      DBG << line << endl;
+  for_( it, rpmKeys.begin(), rpmKeys.end() )
+  {
+    if ( keyEd == *it ) // quick test (Edition is IdStringType!)
+    {
+      MIL << "Key " << pubkey_r << " is already in the rpm trusted keyring. (skip import)" << endl;
+      return;
     }
-  }
+
+    if ( keyEd.version() != (*it).version() )
+      continue; // different key ID (version)
+
+    if ( keyEd.release() < (*it).release() )
+    {
+      MIL << "Key " << pubkey_r << " is older than one in the rpm trusted keyring. (skip import)" << endl;
+      return;
+    }
+    else
+    {
+      hasOldkeys = true;
+    }
+  }
+  MIL << "Key " << pubkey_r << " will be imported into the rpm trusted keyring." << (hasOldkeys?"(update)":"(new)") << endl;
+
+  if ( hasOldkeys )
+  {
+    // We must explicitly delete old key IDs first (all releases,
+    // that's why we don't call removePubkey here).
+    std::string keyName( "gpg-pubkey-" + keyEd.version() );
+    RpmArgVec opts;
+    opts.push_back ( "-e" );
+    opts.push_back ( "--allmatches" );
+    opts.push_back ( "--" );
+    opts.push_back ( keyName.c_str() );
+    // don't call modifyDatabase because it would remove the old
+    // rpm3 database, if the current database is a temporary one.
+    run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
+
+    string line;
+    while ( systemReadLine( line ) )
+    {
+      ( str::startsWith( line, "error:" ) ? WAR : DBG ) << line << endl;
+    }
+
+    if ( systemStatus() != 0 )
+    {
+      ERR << "Failed to remove key " << pubkey_r << " from RPM trusted keyring (ignored)" << endl;
+    }
+    else
+    {
+      MIL << "Key " << pubkey_r << " has been removed from RPM trusted keyring" << endl;
+    }
+  }
+
+  // import the new key
+  RpmArgVec opts;
+  opts.push_back ( "--import" );
+  opts.push_back ( "--" );
+  opts.push_back ( pubkey_r.path().asString().c_str() );
+
+  // don't call modifyDatabase because it would remove the old
+  // rpm3 database, if the current database is a temporary one.
+  run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
+
+  string line;
+  while ( systemReadLine( line ) )
+  {
+    ( str::startsWith( line, "error:" ) ? WAR : DBG ) << line << endl;
+  }
+
+  if ( systemStatus() != 0 )
+  {
+    //TranslatorExplanation first %s is file name, second is error message
+    ZYPP_THROW(RpmSubprocessException( str::Format(_("Failed to import public key from file %s: %s"))
+                                      % pubkey_r.asString()
+                                      % error_message ));
+  }
+  else
+  {
+    MIL << "Key " << pubkey_r << " imported in rpm trusted keyring." << endl;
+  }
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+//     METHOD NAME : RpmDb::removePubkey
+//     METHOD TYPE : PMError
+//
+void RpmDb::removePubkey( const PublicKey & pubkey_r )
+{
+  FAILIFNOTINITIALIZED;
+
+  // check if the key is in the rpm database and just
+  // return if it does not.
+  set<Edition> rpm_keys = pubkeyEditions();
+  set<Edition>::const_iterator found_edition = rpm_keys.end();
+  std::string pubkeyVersion( pubkey_r.gpgPubkeyVersion() );
+
+  for_( it, rpm_keys.begin(), rpm_keys.end() )
+  {
+    if ( (*it).version() == pubkeyVersion )
+    {
+       found_edition = it;
+       break;
+    }
+  }
+
+  // the key does not exist, cannot be removed
+  if (found_edition == rpm_keys.end())
+  {
+      WAR << "Key " << pubkey_r.id() << " is not in rpm db" << endl;
+      return;
+  }
+
+  string rpm_name("gpg-pubkey-" + found_edition->asString());
+
+  RpmArgVec opts;
+  opts.push_back ( "-e" );
+  opts.push_back ( "--" );
+  opts.push_back ( rpm_name.c_str() );
+
+  // don't call modifyDatabase because it would remove the old
+  // rpm3 database, if the current database is a temporary one.
+  run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
+
+  string line;
+  while ( systemReadLine( line ) )
+  {
+    if ( line.substr( 0, 6 ) == "error:" )
+    {
+      WAR << line << endl;
+    }
+    else
+    {
+      DBG << line << endl;
+    }
+  }
 
   int rpm_status = systemStatus();
 
-  if ( rpm_status != 0 ) {
-    ZYPP_THROW(RpmSubprocessException(string("Failed to import public key from file ") + pubkey_r.asString() + string(": rpm returned  ") + str::numstring(rpm_status)));
-  } else {
-    MIL << "Imported public key from file " << pubkey_r << endl;
+  if ( rpm_status != 0 )
+  {
+    //TranslatorExplanation first %s is key name, second is error message
+    ZYPP_THROW(RpmSubprocessException( str::Format(_("Failed to remove public key %s: %s"))
+                                      % pubkey_r.asString()
+                                      % error_message ));
+  }
+  else
+  {
+    MIL << "Key " << pubkey_r << " has been removed from RPM trusted keyring" << endl;
   }
 }
 
@@ -916,26 +1219,26 @@ list<PublicKey> RpmDb::pubkeys() const
     if (edition != Edition::noedition)
     {
       // we export the rpm key into a file
-      RpmHeader::constPtr result = new RpmHeader();
-      getData( std::string("gpg-pubkey"), edition, result );
+      RpmHeader::constPtr result;
+      getData( string("gpg-pubkey"), edition, result );
       TmpFile file(getZYpp()->tmpPath());
-      std::ofstream os;
+      ofstream os;
       try
       {
         os.open(file.path().asString().c_str());
         // dump rpm key into the tmp file
         os << result->tag_description();
-        //MIL << "-----------------------------------------------" << std::endl;
-        //MIL << result->tag_description() <<std::endl;
-        //MIL << "-----------------------------------------------" << std::endl;
+        //MIL << "-----------------------------------------------" << endl;
+        //MIL << result->tag_description() <<endl;
+        //MIL << "-----------------------------------------------" << endl;
         os.close();
         // read the public key from the dumped file
-        PublicKey key(file.path());
+        PublicKey key(file);
         ret.push_back(key);
       }
-      catch (std::exception &e)
+      catch (exception &e)
       {
-        ERR << "Could not dump key " << edition.asString() << " in tmp file " << file.path() << std::endl;
+        ERR << "Could not dump key " << edition.asString() << " in tmp file " << file.path() << endl;
         // just ignore the key
       }
     }
@@ -944,221 +1247,19 @@ list<PublicKey> RpmDb::pubkeys() const
 }
 
 set<Edition> RpmDb::pubkeyEditions() const
-{
-  set<Edition> ret;
-
-  librpmDb::db_const_iterator it;
-  for ( it.findByName( string( "gpg-pubkey" ) ); *it; ++it ) {
-    Edition edition = it->tag_edition();
-    if (edition != Edition::noedition)
-      ret.insert( edition );
-  }
-  return ret;
-}
-
-///////////////////////////////////////////////////////////////////
-//
-//
-//     METHOD NAME : RpmDb::packagesValid
-//     METHOD TYPE : bool
-//
-bool RpmDb::packagesValid() const
-{
-  return( _packages._valid || ! initialized() );
-}
-
-///////////////////////////////////////////////////////////////////
-//
-//
-//     METHOD NAME : RpmDb::getPackages
-//     METHOD TYPE : const std::list<Package::Ptr> &
-//
-//     DESCRIPTION :
-//
-const std::list<Package::Ptr> & RpmDb::getPackages()
-{
-  callback::SendReport<ScanDBReport> report;
-
-  report->start ();
-
-  try {
-    const std::list<Package::Ptr> & ret = doGetPackages(report);
-    report->finish(ScanDBReport::NO_ERROR, "");
-    return ret;
-  }
-  catch (RpmException & excpt_r)
   {
-    report->finish(ScanDBReport::FAILED, excpt_r.asUserString ());
-    ZYPP_RETHROW(excpt_r);
-  }
-#warning fixme
-  static const std::list<Package::Ptr> empty_list;
-  return empty_list;
-}
-
-
-//
-// make Package::Ptr from RpmHeader
-// return NULL on error
-//
-Package::Ptr RpmDb::makePackageFromHeader( const RpmHeader::constPtr header, std::set<std::string> * filerequires, const Pathname & location, Source_Ref source )
-{
-    if ( ! header )
-      return 0;
+    set<Edition> ret;
 
-    if ( header->isSrc() )
-      {
-        WAR << "Can't make Package from SourcePackage header" << endl;
-        return 0;
-      }
-
-    Package::Ptr pptr;
-
-    string name = header->tag_name();
-
-    // create dataprovider
-    detail::ResImplTraits<RPMPackageImpl>::Ptr impl( new RPMPackageImpl( header ) );
-
-    impl->setSource( source );
-    if (!location.empty())
-       impl->setLocation( location );
-
-    Edition edition;
-    try {
-       edition = Edition( header->tag_version(),
-                          header->tag_release(),
-                          header->tag_epoch());
-    }
-    catch (Exception & excpt_r) {
-       ZYPP_CAUGHT( excpt_r );
-       WAR << "Package " << name << " has bad edition '"
-           << (header->tag_epoch().empty()?"":(header->tag_epoch()+":"))
-           << header->tag_version()
-           << (header->tag_release().empty()?"":(string("-") + header->tag_release())) << "'";
-       return pptr;
-    }
-
-    Arch arch;
-    try {
-       arch = Arch( header->tag_arch() );
-    }
-    catch (Exception & excpt_r) {
-       ZYPP_CAUGHT( excpt_r );
-       WAR << "Package " << name << " has bad architecture '" << header->tag_arch() << "'";
-       return pptr;
-    }
-
-    // Collect basic Resolvable data
-    NVRAD dataCollect( header->tag_name(),
-                      edition,
-                      arch );
-
-    list<string> filenames = impl->filenames();
-    dataCollect[Dep::PROVIDES] = header->tag_provides ( filerequires );
-    CapFactory capfactory;
-
-    static str::smatch what;
-    static const str::regex filenameRegex( "/(s?bin|lib(64)?|etc)/|^/usr/(games/|share/(dict/words|magic\\.mime)$)|^/opt/gnome/games/",
-                                           str::regex::optimize|str::regex::nosubs );
-
-    for (list<string>::const_iterator filename = filenames.begin();
-        filename != filenames.end();
-        ++filename)
+    librpmDb::db_const_iterator it;
+    for ( it.findByName( string( "gpg-pubkey" ) ); *it; ++it )
     {
-      if ( str::regex_search( filename->begin(), filename->end(), what, filenameRegex ) )
-       {
-       try {
-         dataCollect[Dep::PROVIDES].insert( capfactory.parse(ResTraits<Package>::kind, *filename) );
-       }
-       catch (Exception & excpt_r)
-       {
-         ZYPP_CAUGHT( excpt_r );
-         WAR << "Ignoring invalid capability: " << *filename << endl;
-       }
-      }
-    }
-
-    dataCollect[Dep::REQUIRES]    = header->tag_requires( filerequires );
-    dataCollect[Dep::PREREQUIRES] = header->tag_prerequires( filerequires );
-    dataCollect[Dep::CONFLICTS]   = header->tag_conflicts( filerequires );
-    dataCollect[Dep::OBSOLETES]   = header->tag_obsoletes( filerequires );
-    dataCollect[Dep::ENHANCES]    = header->tag_enhances( filerequires );
-    dataCollect[Dep::SUPPLEMENTS] = header->tag_supplements( filerequires );
-
-    try {
-       // create package from dataprovider
-       pptr = detail::makeResolvableFromImpl( dataCollect, impl );
-    }
-    catch (Exception & excpt_r) {
-       ZYPP_CAUGHT( excpt_r );
-       ERR << "Can't create Package::Ptr" << endl;
-    }
-
-    return pptr;
-}
-
-
-const std::list<Package::Ptr> & RpmDb::doGetPackages(callback::SendReport<ScanDBReport> & report)
-{
-  if ( packagesValid() ) {
-    return _packages._list;
-  }
-
-  _packages.clear();
-
-  ///////////////////////////////////////////////////////////////////
-  // Collect package data.
-  ///////////////////////////////////////////////////////////////////
-  unsigned expect = 0;
-  librpmDb::constPtr dbptr;
-  librpmDb::dbAccess( dbptr );
-  expect = dbptr->size();
-  DBG << "Expecting " << expect << " packages" << endl;
-
-  librpmDb::db_const_iterator iter;
-  unsigned current = 0;
-  CapFactory _f;
-  Pathname location;
-
-  for ( iter.findAll(); *iter; ++iter, ++current, report->progress( (100*current)/expect)) {
-
-    string name = iter->tag_name();
-    if ( name == string( "gpg-pubkey" ) ) {
-      DBG << "Ignoring pseudo package " << name << endl;
-      // pseudo package filtered, as we can't handle multiple instances
-      // of 'gpg-pubkey-VERS-REL'.
-      continue;
-    }
-    Date installtime = iter->tag_installtime();
-
-    Package::Ptr pptr = makePackageFromHeader( *iter, &_filerequires, location, Source_Ref() );
-
-    _packages._list.push_back( pptr );
-  }
-  _packages.buildIndex();
-  DBG << "Found installed packages: " << _packages._list.size() << endl;
-
-  ///////////////////////////////////////////////////////////////////
-  // Evaluate filerequires collected so far
-  ///////////////////////////////////////////////////////////////////
-  for( set<string>::iterator it = _filerequires.begin(); it != _filerequires.end(); ++it ) {
-
-    for ( iter.findByFile( *it ); *iter; ++iter ) {
-      Package::Ptr pptr = _packages.lookup( iter->tag_name() );
-      if ( !pptr ) {
-       WAR << "rpmdb.findByFile returned unknown package " << *iter << endl;
-       continue;
-      }
-      pptr->injectProvides(_f.parse(ResTraits<Package>::kind, *it));
+      Edition edition = it->tag_edition();
+      if (edition != Edition::noedition)
+        ret.insert( edition );
     }
-
+    return ret;
   }
 
-  ///////////////////////////////////////////////////////////////////
-  // Build final packages list
-  ///////////////////////////////////////////////////////////////////
-  return _packages._list;
-}
 
 ///////////////////////////////////////////////////////////////////
 //
@@ -1168,18 +1269,20 @@ const std::list<Package::Ptr> & RpmDb::doGetPackages(callback::SendReport<ScanDB
 //
 //     DESCRIPTION :
 //
-std::list<FileInfo>
-RpmDb::fileList( const std::string & name_r, const Edition & edition_r ) const
+list<FileInfo>
+RpmDb::fileList( const string & name_r, const Edition & edition_r ) const
 {
-  std::list<FileInfo> result;
+  list<FileInfo> result;
 
   librpmDb::db_const_iterator it;
   bool found;
-  if (edition_r == Edition::noedition) {
-     found = it.findPackage( name_r );
+  if (edition_r == Edition::noedition)
+  {
+    found = it.findPackage( name_r );
   }
-  else {
-     found = it.findPackage( name_r, edition_r );
+  else
+  {
+    found = it.findPackage( name_r, edition_r );
   }
   if (!found)
     return result;
@@ -1196,18 +1299,21 @@ RpmDb::fileList( const std::string & name_r, const Edition & edition_r ) const
 //
 //     DESCRIPTION :
 //
-bool RpmDb::hasFile( const std::string & file_r, const std::string & name_r ) const
+bool RpmDb::hasFile( const string & file_r, const string & name_r ) const
 {
   librpmDb::db_const_iterator it;
   bool res;
-  do {
+  do
+  {
     res = it.findByFile( file_r );
     if (!res) break;
-    if (!name_r.empty()) {
+    if (!name_r.empty())
+    {
       res = (it->tag_name() == name_r);
     }
     ++it;
-  } while (res && *it);
+  }
+  while (res && *it);
   return res;
 }
 
@@ -1219,10 +1325,11 @@ bool RpmDb::hasFile( const std::string & file_r, const std::string & name_r ) co
 //
 //     DESCRIPTION :
 //
-std::string RpmDb::whoOwnsFile( const std::string & file_r) const
+string RpmDb::whoOwnsFile( const string & file_r) const
 {
   librpmDb::db_const_iterator it;
-  if (it.findByFile( file_r )) {
+  if (it.findByFile( file_r ))
+  {
     return it->tag_name();
   }
   return "";
@@ -1236,7 +1343,7 @@ std::string RpmDb::whoOwnsFile( const std::string & file_r) const
 //
 //     DESCRIPTION :
 //
-bool RpmDb::hasProvides( const std::string & tag_r ) const
+bool RpmDb::hasProvides( const string & tag_r ) const
 {
   librpmDb::db_const_iterator it;
   return it.findByProvides( tag_r );
@@ -1250,7 +1357,7 @@ bool RpmDb::hasProvides( const std::string & tag_r ) const
 //
 //     DESCRIPTION :
 //
-bool RpmDb::hasRequiredBy( const std::string & tag_r ) const
+bool RpmDb::hasRequiredBy( const string & tag_r ) const
 {
   librpmDb::db_const_iterator it;
   return it.findByRequiredBy( tag_r );
@@ -1264,7 +1371,7 @@ bool RpmDb::hasRequiredBy( const std::string & tag_r ) const
 //
 //     DESCRIPTION :
 //
-bool RpmDb::hasConflicts( const std::string & tag_r ) const
+bool RpmDb::hasConflicts( const string & tag_r ) const
 {
   librpmDb::db_const_iterator it;
   return it.findByConflicts( tag_r );
@@ -1307,7 +1414,7 @@ bool RpmDb::hasPackage( const string & name_r, const Edition & ed_r ) const
 //     DESCRIPTION :
 //
 void RpmDb::getData( const string & name_r,
-                       RpmHeader::constPtr & result_r ) const
+                     RpmHeader::constPtr & result_r ) const
 {
   librpmDb::db_const_iterator it;
   it.findPackage( name_r );
@@ -1320,12 +1427,12 @@ void RpmDb::getData( const string & name_r,
 //
 //
 //     METHOD NAME : RpmDb::getData
-//     METHOD TYPE : PMError
+//     METHOD TYPE : void
 //
 //     DESCRIPTION :
 //
-void RpmDb::getData( const std::string & name_r, const Edition & ed_r,
-                       RpmHeader::constPtr & result_r ) const
+void RpmDb::getData( const string & name_r, const Edition & ed_r,
+                     RpmHeader::constPtr & result_r ) const
 {
   librpmDb::db_const_iterator it;
   it.findPackage( name_r, ed_r  );
@@ -1334,187 +1441,194 @@ void RpmDb::getData( const std::string & name_r, const Edition & ed_r,
     ZYPP_THROW(*(it.dbError()));
 }
 
-/*--------------------------------------------------------------*/
-/* Checking the source rpm <rpmpath> with rpm --chcksig and     */
-/* the version number.                                         */
-/*--------------------------------------------------------------*/
-unsigned
-RpmDb::checkPackage (const Pathname & packagePath, string version, string md5 )
+///////////////////////////////////////////////////////////////////
+namespace
 {
-    unsigned result = 0;
+  struct RpmlogCapture : public std::string
+  {
+    RpmlogCapture()
+    { rpmlog()._cap = this; }
 
-    if ( ! version.empty() ) {
-      RpmHeader::constPtr h( RpmHeader::readPackage( packagePath, RpmHeader::NOSIGNATURE ) );
-      if ( ! h || Edition( version ) != h->tag_edition() ) {
-       result |= CHK_INCORRECT_VERSION;
-      }
-    }
+    ~RpmlogCapture()
+    { rpmlog()._cap = nullptr; }
 
-    if(!md5.empty())
+  private:
+    struct Rpmlog
     {
-#warning TBD MD5 check
-       WAR << "md5sum check not yet implemented" << endl;
-       return CHK_INCORRECT_FILEMD5;
-    }
+      Rpmlog()
+      : _cap( nullptr )
+      {
+       rpmlogSetCallback( rpmLogCB, this );
+       rpmSetVerbosity( RPMLOG_INFO );
+       _f = ::fopen( "/dev/null","w");
+       rpmlogSetFile( _f );
+      }
+
+      ~Rpmlog()
+      { if ( _f ) ::fclose( _f ); }
+
+      static int rpmLogCB( rpmlogRec rec_r, rpmlogCallbackData data_r )
+      { return reinterpret_cast<Rpmlog*>(data_r)->rpmLog( rec_r ); }
 
-    std::string path = packagePath.asString();
-    // checking --checksig
-    const char *const argv[] = {
-       "rpm", "--checksig", "--", path.c_str(), 0
+      int rpmLog( rpmlogRec rec_r )
+      {
+       if ( _cap ) (*_cap) = rpmlogRecMessage( rec_r );
+       return RPMLOG_DEFAULT;
+      }
+
+      FILE * _f;
+      std::string * _cap;
     };
 
-    exit_code = -1;
+    static Rpmlog & rpmlog()
+    { static Rpmlog _rpmlog; return _rpmlog; }
+  };
 
-    string output = "";
-    unsigned int k;
-    for ( k = 0; k < (sizeof(argv) / sizeof(*argv)) -1; k++ )
-    {
-       output = output + " " + argv[k];
-    }
 
-    DBG << "rpm command: " << output << endl;
+} // namespace
+///////////////////////////////////////////////////////////////////
+//
+//     METHOD NAME : RpmDb::checkPackage
+//     METHOD TYPE : RpmDb::CheckPackageResult
+//
+RpmDb::CheckPackageResult RpmDb::checkPackage( const Pathname & path_r, CheckPackageDetail & detail_r )
+{
+  PathInfo file( path_r );
+  if ( ! file.isFile() )
+  {
+    ERR << "Not a file: " << file << endl;
+    return CHK_ERROR;
+  }
 
-    if ( process != NULL )
-    {
-       delete process;
-       process = NULL;
-    }
-    // Launch the program
-    process = new ExternalProgram( argv, ExternalProgram::Stderr_To_Stdout, false, -1, true);
+  FD_t fd = ::Fopen( file.asString().c_str(), "r.ufdio" );
+  if ( fd == 0 || ::Ferror(fd) )
+  {
+    ERR << "Can't open file for reading: " << file << " (" << ::Fstrerror(fd) << ")" << endl;
+    if ( fd )
+      ::Fclose( fd );
+    return CHK_ERROR;
+  }
+  rpmts ts = ::rpmtsCreate();
+  ::rpmtsSetRootDir( ts, root().asString().c_str() );
+  ::rpmtsSetVSFlags( ts, RPMVSF_DEFAULT );
 
+  rpmQVKArguments_s qva;
+  memset( &qva, 0, sizeof(rpmQVKArguments_s) );
+  qva.qva_flags = (VERIFY_DIGEST|VERIFY_SIGNATURE);
 
-    if ( process == NULL )
-    {
-       result |= CHK_OTHER_FAILURE;
-       DBG << "create process failed" << endl;
-    }
+  RpmlogCapture vresult;
+  int res = ::rpmVerifySignatures( &qva, ts, fd, path_r.basename().c_str() );
 
-    string value;
-    output = process->receiveLine();
+  ts = rpmtsFree(ts);
+  ::Fclose( fd );
 
-    while ( output.length() > 0)
-    {
-       string::size_type         ret;
 
-       // extract \n
-       ret = output.find_first_of ( "\n" );
-       if ( ret != string::npos )
-       {
-           value.assign ( output, 0, ret );
-       }
-       else
-       {
-           value = output;
-       }
+  if ( res == 0 )
+  {
+    detail_r.push_back( CheckPackageDetail::value_type( CHK_OK, std::move(vresult) ) );
+    return CHK_OK;
+  }
 
-       DBG << "stdout: " << value << endl;
+  // results per line...
+  WAR << vresult;
+  std::vector<std::string> lines;
+  str::split( vresult, std::back_inserter(lines), "\n" );
+  unsigned count[6] = { 0, 0, 0, 0, 0, 0 };
 
-       string::size_type pos;
-       if((pos = value.find (path)) != string::npos)
-       {
-           string rest = value.substr (pos + path.length() + 1);
-           if (rest.find("NOT OK") == string::npos)
-           {
-               // see what checks are ok
-               if (rest.find("md5") == string::npos)
-               {
-                   result |= CHK_MD5SUM_MISSING;
-               }
-               if (rest.find("gpg") == string::npos)
-               {
-                   result |= CHK_GPGSIG_MISSING;
-               }
-           }
-           else
-           {
-               // see what checks are not ok
-               if (rest.find("MD5") != string::npos)
-               {
-                   result |= CHK_INCORRECT_PKGMD5;
-               }
-               else
-               {
-                   result |= CHK_MD5SUM_MISSING;
-               }
-
-               if (rest.find("GPG") != string::npos)
-               {
-                   result |= CHK_INCORRECT_GPGSIG;
-               }
-               else
-               {
-                   result |= CHK_GPGSIG_MISSING;
-               }
-           }
-       }
+  for ( unsigned i = 1; i < lines.size(); ++i )
+  {
+    std::string & line( lines[i] );
+    CheckPackageResult lineres = CHK_ERROR;
+    if ( line.find( ": OK" ) != std::string::npos )
+    { lineres = CHK_OK; }
+    else if ( line.find( ": NOKEY" ) != std::string::npos )
+    { lineres = CHK_NOKEY; }
+    else if ( line.find( ": BAD" ) != std::string::npos )
+    { lineres = CHK_FAIL; }
+    else if ( line.find( ": UNKNOWN" ) != std::string::npos )
+    { lineres = CHK_NOTFOUND; }
+    else if ( line.find( ": NOTRUSTED" ) != std::string::npos )
+    { lineres = CHK_NOTTRUSTED; }
+
+    ++count[lineres];
+    detail_r.push_back( CheckPackageDetail::value_type( lineres, std::move(line) ) );
+  }
 
-       output = process->receiveLine();
-    }
+  CheckPackageResult ret = CHK_ERROR;
+  if ( count[CHK_FAIL] )
+    ret = CHK_FAIL;
 
-    if ( result == 0 && systemStatus() != 0 )
-    {
-       // error
-       result |= CHK_OTHER_FAILURE;
-    }
+  else if ( count[CHK_NOTFOUND] )
+    ret = CHK_NOTFOUND;
+
+  else if ( count[CHK_NOKEY] )
+    ret = CHK_NOKEY;
 
-    return ( result );
+  else if ( count[CHK_NOTTRUSTED] )
+    ret = CHK_NOTTRUSTED;
+
+  return ret;
 }
 
+RpmDb::CheckPackageResult RpmDb::checkPackage( const Pathname & path_r )
+{ CheckPackageDetail dummy; return checkPackage( path_r, dummy ); }
+
+
 // determine changed files of installed package
 bool
 RpmDb::queryChangedFiles(FileList & fileList, const string& packageName)
 {
-    bool ok = true;
+  bool ok = true;
 
-    fileList.clear();
+  fileList.clear();
 
-    if( ! initialized() ) return false;
+  if ( ! initialized() ) return false;
 
-    RpmArgVec opts;
+  RpmArgVec opts;
 
-    opts.push_back ("-V");
-    opts.push_back ("--nodeps");
-    opts.push_back ("--noscripts");
-    opts.push_back ("--nomd5");
-    opts.push_back ("--");
-    opts.push_back (packageName.c_str());
-
-    run_rpm (opts, ExternalProgram::Discard_Stderr);
-
-    if ( process == NULL )
-       return false;
-
-    /* from rpm manpage
-       5      MD5 sum
-       S      File size
-       L      Symlink
-       T      Mtime
-       D      Device
-       U      User
-       G      Group
-       M      Mode (includes permissions and file type)
-    */
+  opts.push_back ("-V");
+  opts.push_back ("--nodeps");
+  opts.push_back ("--noscripts");
+  opts.push_back ("--nomd5");
+  opts.push_back ("--");
+  opts.push_back (packageName.c_str());
 
-    string line;
-    while (systemReadLine(line))
+  run_rpm (opts, ExternalProgram::Discard_Stderr);
+
+  if ( process == NULL )
+    return false;
+
+  /* from rpm manpage
+   5      MD5 sum
+   S      File size
+   L      Symlink
+   T      Mtime
+   D      Device
+   U      User
+   G      Group
+   M      Mode (includes permissions and file type)
+  */
+
+  string line;
+  while (systemReadLine(line))
+  {
+    if (line.length() > 12 &&
+        (line[0] == 'S' || line[0] == 's' ||
+         (line[0] == '.' && line[7] == 'T')))
     {
-       if (line.length() > 12 &&
-           (line[0] == 'S' || line[0] == 's' ||
-            (line[0] == '.' && line[7] == 'T')))
-       {
-           // file has been changed
-           string filename;
+      // file has been changed
+      string filename;
 
-           filename.assign(line, 11, line.length() - 11);
-           fileList.insert(filename);
-       }
+      filename.assign(line, 11, line.length() - 11);
+      fileList.insert(filename);
     }
+  }
 
-    systemStatus();
-    // exit code ignored, rpm returns 1 no matter if package is installed or
-    // not
+  systemStatus();
+  // exit code ignored, rpm returns 1 no matter if package is installed or
+  // not
 
-    return ok;
+  return ok;
 }
 
 
@@ -1529,63 +1643,118 @@ RpmDb::queryChangedFiles(FileList & fileList, const string& packageName)
 /*--------------------------------------------------------------*/
 void
 RpmDb::run_rpm (const RpmArgVec& opts,
-               ExternalProgram::Stderr_Disposition disp)
+                ExternalProgram::Stderr_Disposition disp)
 {
-    if ( process ) {
-       delete process;
-       process = NULL;
-    }
-    exit_code = -1;
+  if ( process )
+  {
+    delete process;
+    process = NULL;
+  }
+  exit_code = -1;
 
-    if ( ! initialized() ) {
-       ZYPP_THROW(RpmDbNotOpenException());
-    }
+  if ( ! initialized() )
+  {
+    ZYPP_THROW(RpmDbNotOpenException());
+  }
 
-    RpmArgVec args;
+  RpmArgVec args;
 
-    // always set root and dbpath
-    args.push_back("rpm");
-    args.push_back("--root");
-    args.push_back(_root.asString().c_str());
-    args.push_back("--dbpath");
-    args.push_back(_dbPath.asString().c_str());
+  // always set root and dbpath
+#if defined(WORKAROUNDRPMPWDBUG)
+  args.push_back("#/");                // chdir to / to workaround bnc#819354
+#endif
+  args.push_back("rpm");
+  args.push_back("--root");
+  args.push_back(_root.asString().c_str());
+  args.push_back("--dbpath");
+  args.push_back(_dbPath.asString().c_str());
 
-    const char* argv[args.size() + opts.size() + 1];
+  const char* argv[args.size() + opts.size() + 1];
 
-    const char** p = argv;
-    p = copy (args.begin (), args.end (), p);
-    p = copy (opts.begin (), opts.end (), p);
-    *p = 0;
+  const char** p = argv;
+  p = copy (args.begin (), args.end (), p);
+  p = copy (opts.begin (), opts.end (), p);
+  *p = 0;
 
-    // Invalidate all outstanding database handles in case
-    // the database gets modified.
-    librpmDb::dbRelease( true );
+  // Invalidate all outstanding database handles in case
+  // the database gets modified.
+  librpmDb::dbRelease( true );
 
-    // Launch the program with default locale
-    process = new ExternalProgram(argv, disp, false, -1, true);
-    return;
+  // Launch the program with default locale
+  process = new ExternalProgram(argv, disp, false, -1, true);
+  return;
 }
 
 /*--------------------------------------------------------------*/
 /* Read a line from the rpm process                            */
 /*--------------------------------------------------------------*/
-bool
-RpmDb::systemReadLine(string &line)
+bool RpmDb::systemReadLine( string & line )
 {
-    line.erase();
+  line.erase();
 
-    if ( process == NULL )
-       return false;
+  if ( process == NULL )
+    return false;
 
-    line = process->receiveLine();
+  if ( process->inputFile() )
+  {
+    process->setBlocking( false );
+    FILE * inputfile = process->inputFile();
+    int    inputfileFd = ::fileno( inputfile );
+    do
+    {
+      /* Watch inputFile to see when it has input. */
+      fd_set rfds;
+      FD_ZERO( &rfds );
+      FD_SET( inputfileFd, &rfds );
 
-    if (line.length() == 0)
-       return false;
+      /* Wait up to 5 seconds. */
+      struct timeval tv;
+      tv.tv_sec = 5;
+      tv.tv_usec = 0;
 
-    if (line[line.length() - 1] == '\n')
-       line.erase(line.length() - 1);
+      int retval = select( inputfileFd+1, &rfds, NULL, NULL, &tv );
 
-    return true;
+      if ( retval == -1 )
+      {
+       ERR << "select error: " << strerror(errno) << endl;
+       if ( errno != EINTR )
+         return false;
+      }
+      else if ( retval )
+      {
+       // Data is available now.
+       static size_t linebuffer_size = 0;      // static because getline allocs
+       static char * linebuffer = 0;           // and reallocs if buffer is too small
+       ssize_t nread = getline( &linebuffer, &linebuffer_size, inputfile );
+       if ( nread == -1 )
+       {
+         if ( ::feof( inputfile ) )
+           return line.size(); // in case of pending output
+       }
+       else
+       {
+         if ( nread > 0 )
+         {
+           if ( linebuffer[nread-1] == '\n' )
+             --nread;
+           line += string( linebuffer, nread );
+         }
+
+         if ( ! ::ferror( inputfile ) || ::feof( inputfile ) )
+           return true; // complete line
+       }
+       clearerr( inputfile );
+      }
+      else
+      {
+       // No data within time.
+       if ( ! process->running() )
+         return false;
+      }
+    } while ( true );
+  }
+
+  return false;
 }
 
 /*--------------------------------------------------------------*/
@@ -1595,15 +1764,19 @@ RpmDb::systemReadLine(string &line)
 int
 RpmDb::systemStatus()
 {
-   if ( process == NULL )
-      return -1;
+  if ( process == NULL )
+    return -1;
 
-   exit_code = process->close();
-   process->kill();
-   delete process;
-   process = 0;
+  exit_code = process->close();
+  if (exit_code == 0)
+    error_message = "";
+  else
+    error_message = process->execError();
+  process->kill();
+  delete process;
+  process = 0;
 
-//   DBG << "exit code " << exit_code << endl;
+  //   DBG << "exit code " << exit_code << endl;
 
   return exit_code;
 }
@@ -1621,93 +1794,93 @@ RpmDb::systemKill()
 // generate diff mails for config files
 void RpmDb::processConfigFiles(const string& line, const string& name, const char* typemsg, const char* difffailmsg, const char* diffgenmsg)
 {
-    string msg = line.substr(9);
-    string::size_type pos1 = string::npos;
-    string::size_type pos2 = string::npos;
-    string file1s, file2s;
-    Pathname file1;
-    Pathname file2;
+  string msg = line.substr(9);
+  string::size_type pos1 = string::npos;
+  string::size_type pos2 = string::npos;
+  string file1s, file2s;
+  Pathname file1;
+  Pathname file2;
+
+  pos1 = msg.find (typemsg);
+  for (;;)
+  {
+    if ( pos1 == string::npos )
+      break;
 
-    pos1 = msg.find (typemsg);
-    for (;;)
-    {
-       if( pos1 == string::npos )
-           break;
+    pos2 = pos1 + strlen (typemsg);
 
-       pos2 = pos1 + strlen (typemsg);
+    if (pos2 >= msg.length() )
+      break;
 
-       if (pos2 >= msg.length() )
-           break;
+    file1 = msg.substr (0, pos1);
+    file2 = msg.substr (pos2);
 
-       file1 = msg.substr (0, pos1);
-       file2 = msg.substr (pos2);
+    file1s = file1.asString();
+    file2s = file2.asString();
 
-       file1s = file1.asString();
-       file2s = file2.asString();
+    if (!_root.empty() && _root != "/")
+    {
+      file1 = _root + file1;
+      file2 = _root + file2;
+    }
 
-       if (!_root.empty() && _root != "/")
-       {
-           file1 = _root + file1;
-           file2 = _root + file2;
-       }
+    string out;
+    int ret = diffFiles (file1.asString(), file2.asString(), out, 25);
+    if (ret)
+    {
+      Pathname file = _root + WARNINGMAILPATH;
+      if (filesystem::assert_dir(file) != 0)
+      {
+        ERR << "Could not create " << file.asString() << endl;
+        break;
+      }
+      file += Date(Date::now()).form("config_diff_%Y_%m_%d.log");
+      ofstream notify(file.asString().c_str(), ios::out|ios::app);
+      if (!notify)
+      {
+        ERR << "Could not open " <<  file << endl;
+        break;
+      }
 
-       string out;
-       int ret = diffFiles (file1.asString(), file2.asString(), out, 25);
-       if (ret)
-       {
-           Pathname file = _root + WARNINGMAILPATH;
-           if (filesystem::assert_dir(file) != 0)
-           {
-               ERR << "Could not create " << file.asString() << endl;
-               break;
-           }
-           file += Date(Date::now()).form("config_diff_%Y_%m_%d.log");
-           ofstream notify(file.asString().c_str(), std::ios::out|std::ios::app);
-           if(!notify)
-           {
-               ERR << "Could not open " <<  file << endl;
-               break;
-           }
-
-           // Translator: %s = name of an rpm package. A list of diffs follows
-           // this message.
-           notify << str::form(_("Changed configuration files for %s:"), name.c_str()) << endl;
-           if(ret>1)
-           {
-               ERR << "diff failed" << endl;
-               notify << str::form(difffailmsg,
-                   file1s.c_str(), file2s.c_str()) << endl;
-           }
-           else
-           {
-               notify << str::form(diffgenmsg,
-                   file1s.c_str(), file2s.c_str()) << endl;
-
-               // remove root for the viewer's pleasure (#38240)
-               if (!_root.empty() && _root != "/")
-               {
-                   if(out.substr(0,4) == "--- ")
-                   {
-                       out.replace(4, file1.asString().length(), file1s);
-                   }
-                   string::size_type pos = out.find("\n+++ ");
-                   if(pos != string::npos)
-                   {
-                       out.replace(pos+5, file2.asString().length(), file2s);
-                   }
-               }
-               notify << out << endl;
-           }
-           notify.close();
-           notify.open("/var/lib/update-messages/yast2-packagemanager.rpmdb.configfiles");
-           notify.close();
-       }
-       else
-       {
-           WAR << "rpm created " << file2 << " but it is not different from " << file2 << endl;
-       }
-       break;
+      // Translator: %s = name of an rpm package. A list of diffs follows
+      // this message.
+      notify << str::form(_("Changed configuration files for %s:"), name.c_str()) << endl;
+      if (ret>1)
+      {
+        ERR << "diff failed" << endl;
+        notify << str::form(difffailmsg,
+                            file1s.c_str(), file2s.c_str()) << endl;
+      }
+      else
+      {
+        notify << str::form(diffgenmsg,
+                            file1s.c_str(), file2s.c_str()) << endl;
+
+        // remove root for the viewer's pleasure (#38240)
+        if (!_root.empty() && _root != "/")
+        {
+          if (out.substr(0,4) == "--- ")
+          {
+            out.replace(4, file1.asString().length(), file1s);
+          }
+          string::size_type pos = out.find("\n+++ ");
+          if (pos != string::npos)
+          {
+            out.replace(pos+5, file2.asString().length(), file2s);
+          }
+        }
+        notify << out << endl;
+      }
+      notify.close();
+      notify.open("/var/lib/update-messages/yast2-packagemanager.rpmdb.configfiles");
+      notify.close();
+    }
+    else
+    {
+      WAR << "rpm created " << file2 << " but it is not different from " << file2 << endl;
     }
+    break;
+  }
 }
 
 ///////////////////////////////////////////////////////////////////
@@ -1716,14 +1889,15 @@ void RpmDb::processConfigFiles(const string& line, const string& name, const cha
 //     METHOD NAME : RpmDb::installPackage
 //     METHOD TYPE : PMError
 //
-void RpmDb::installPackage( const Pathname & filename, unsigned flags )
+void RpmDb::installPackage( const Pathname & filename, RpmInstFlags flags )
 {
   callback::SendReport<RpmInstallReport> report;
 
   report->start(filename);
 
   do
-    try {
+    try
+    {
       doInstallPackage(filename, flags, report);
       report->finish();
       break;
@@ -1732,120 +1906,155 @@ void RpmDb::installPackage( const Pathname & filename, unsigned flags )
     {
       RpmInstallReport::Action user = report->problem( excpt_r );
 
-      if( user == RpmInstallReport::ABORT ) {
-       report->finish( excpt_r );
-       ZYPP_RETHROW(excpt_r);
-      } else if ( user == RpmInstallReport::IGNORE ) {
-       break;
+      if ( user == RpmInstallReport::ABORT )
+      {
+        report->finish( excpt_r );
+        ZYPP_RETHROW(excpt_r);
+      }
+      else if ( user == RpmInstallReport::IGNORE )
+      {
+        break;
       }
     }
   while (true);
 }
 
-void RpmDb::doInstallPackage( const Pathname & filename, unsigned flags, callback::SendReport<RpmInstallReport> & report )
+void RpmDb::doInstallPackage( const Pathname & filename, RpmInstFlags flags, callback::SendReport<RpmInstallReport> & report )
 {
-    FAILIFNOTINITIALIZED;
-    CommitLog progresslog;
+  FAILIFNOTINITIALIZED;
+  HistoryLog historylog;
 
-    MIL << "RpmDb::installPackage(" << filename << "," << flags << ")" << endl;
+  MIL << "RpmDb::installPackage(" << filename << "," << flags << ")" << endl;
 
 
-    // backup
-    if ( _packagebackups ) {
-// FIXME      report->progress( pd.init( -2, 100 ) ); // allow 1% for backup creation.
-      if ( ! backupPackage( filename ) ) {
-       ERR << "backup of " << filename.asString() << " failed" << endl;
-      }
-// FIXME status handling
-      report->progress( 0 ); // allow 1% for backup creation.
-    } else {
-      report->progress( 100 );
+  // backup
+  if ( _packagebackups )
+  {
+    // FIXME      report->progress( pd.init( -2, 100 ) ); // allow 1% for backup creation.
+    if ( ! backupPackage( filename ) )
+    {
+      ERR << "backup of " << filename.asString() << " failed" << endl;
     }
+    // FIXME status handling
+    report->progress( 0 ); // allow 1% for backup creation.
+  }
 
-    // run rpm
-    RpmArgVec opts;
-    if (flags & RPMINST_NOUPGRADE)
-      opts.push_back("-i");
-    else
-      opts.push_back("-U");
-    opts.push_back("--percent");
-
-    if (flags & RPMINST_NODIGEST)
-       opts.push_back("--nodigest");
-    if (flags & RPMINST_NOSIGNATURE)
-       opts.push_back("--nosignature");
-    if (flags & RPMINST_NODOCS)
-       opts.push_back ("--excludedocs");
-    if (flags & RPMINST_NOSCRIPTS)
-       opts.push_back ("--noscripts");
-    if (flags & RPMINST_FORCE)
-       opts.push_back ("--force");
-    if (flags & RPMINST_NODEPS)
-       opts.push_back ("--nodeps");
-    if(flags & RPMINST_IGNORESIZE)
-       opts.push_back ("--ignoresize");
-    if(flags & RPMINST_JUSTDB)
-       opts.push_back ("--justdb");
-    if(flags & RPMINST_TEST)
-       opts.push_back ("--test");
-
-    opts.push_back("--");
-    opts.push_back (filename.asString().c_str());
-
-    modifyDatabase(); // BEFORE run_rpm
-    run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
+  // run rpm
+  RpmArgVec opts;
+  if (flags & RPMINST_NOUPGRADE)
+    opts.push_back("-i");
+  else
+    opts.push_back("-U");
+
+  opts.push_back("--percent");
+  opts.push_back("--noglob");
+
+  // ZConfig defines cross-arch installation
+  if ( ! ZConfig::instance().systemArchitecture().compatibleWith( ZConfig::instance().defaultSystemArchitecture() ) )
+    opts.push_back("--ignorearch");
+
+  if (flags & RPMINST_NODIGEST)
+    opts.push_back("--nodigest");
+  if (flags & RPMINST_NOSIGNATURE)
+    opts.push_back("--nosignature");
+  if (flags & RPMINST_EXCLUDEDOCS)
+    opts.push_back ("--excludedocs");
+  if (flags & RPMINST_NOSCRIPTS)
+    opts.push_back ("--noscripts");
+  if (flags & RPMINST_FORCE)
+    opts.push_back ("--force");
+  if (flags & RPMINST_NODEPS)
+    opts.push_back ("--nodeps");
+  if (flags & RPMINST_IGNORESIZE)
+    opts.push_back ("--ignoresize");
+  if (flags & RPMINST_JUSTDB)
+    opts.push_back ("--justdb");
+  if (flags & RPMINST_TEST)
+    opts.push_back ("--test");
+  if (flags & RPMINST_NOPOSTTRANS)
+    opts.push_back ("--noposttrans");
+
+  opts.push_back("--");
+
+  // rpm requires additional quoting of special chars:
+  string quotedFilename( rpmQuoteFilename( workaroundRpmPwdBug( filename ) ) );
+  opts.push_back ( quotedFilename.c_str() );
+
+  modifyDatabase(); // BEFORE run_rpm
+  run_rpm( opts, ExternalProgram::Stderr_To_Stdout );
 
-    string line;
-    string rpmmsg;
-    vector<string> configwarnings;
-    vector<string> errorlines;
+  string line;
+  string rpmmsg;
+  vector<string> configwarnings;
 
-    while (systemReadLine(line))
-    {
-       if (line.substr(0,2)=="%%")
-       {
-           int percent;
-           sscanf (line.c_str () + 2, "%d", &percent);
-           report->progress( percent );
-       }
-       else
-           rpmmsg += line+'\n';
+  unsigned linecnt = 0;
+  while (systemReadLine(line))
+  {
+    if ( linecnt < MAXRPMMESSAGELINES )
+      ++linecnt;
+    else
+      continue;
 
-       if( line.substr(0,8) == "warning:" )
-       {
-           configwarnings.push_back(line);
-       }
-    }
-    int rpm_status = systemStatus();
-
-    // evaluate result
-    for(vector<string>::iterator it = configwarnings.begin();
-       it != configwarnings.end(); ++it)
-    {
-           processConfigFiles(*it, Pathname::basename(filename), " saved as ",
-               // %s = filenames
-               _("rpm saved %s as %s but it was impossible to determine the difference"),
-               // %s = filenames
-               _("rpm saved %s as %s.\nHere are the first 25 lines of difference:\n"));
-           processConfigFiles(*it, Pathname::basename(filename), " created as ",
-               // %s = filenames
-               _("rpm created %s as %s but it was impossible to determine the difference"),
-               // %s = filenames
-               _("rpm created %s as %s.\nHere are the first 25 lines of difference:\n"));
+    if (line.substr(0,2)=="%%")
+    {
+      int percent;
+      sscanf (line.c_str () + 2, "%d", &percent);
+      report->progress( percent );
     }
+    else
+      rpmmsg += line+'\n';
 
-    if ( rpm_status != 0 )  {
-      // %s = filename of rpm package
-      progresslog(/*timestamp*/true) << str::form(_("%s install failed"), Pathname::basename(filename).c_str()) << endl;
-      progresslog() << _("rpm output:") << endl << rpmmsg << endl;
-      ZYPP_THROW(RpmSubprocessException(string("RPM failed: ") + rpmmsg));
-    } else {
-      // %s = filename of rpm package
-      progresslog(/*timestamp*/true) << str::form(_("%s installed ok"), Pathname::basename(filename).c_str()) << endl;
-      if( ! rpmmsg.empty() ) {
-       progresslog() << _("Additional rpm output:") << endl << rpmmsg << endl;
-      }
+    if ( line.substr(0,8) == "warning:" )
+    {
+      configwarnings.push_back(line);
     }
+  }
+  if ( linecnt > MAXRPMMESSAGELINES )
+    rpmmsg += "[truncated]\n";
+
+  int rpm_status = systemStatus();
+
+  // evaluate result
+  for (vector<string>::iterator it = configwarnings.begin();
+       it != configwarnings.end(); ++it)
+  {
+    processConfigFiles(*it, Pathname::basename(filename), " saved as ",
+                       // %s = filenames
+                       _("rpm saved %s as %s, but it was impossible to determine the difference"),
+                       // %s = filenames
+                       _("rpm saved %s as %s.\nHere are the first 25 lines of difference:\n"));
+    processConfigFiles(*it, Pathname::basename(filename), " created as ",
+                       // %s = filenames
+                       _("rpm created %s as %s, but it was impossible to determine the difference"),
+                       // %s = filenames
+                       _("rpm created %s as %s.\nHere are the first 25 lines of difference:\n"));
+  }
+
+  if ( rpm_status != 0 )
+  {
+    historylog.comment(
+        str::form("%s install failed", Pathname::basename(filename).c_str()),
+        true /*timestamp*/);
+    ostringstream sstr;
+    sstr << "rpm output:" << endl << rpmmsg << endl;
+    historylog.comment(sstr.str());
+    // TranslatorExplanation the colon is followed by an error message
+    ZYPP_THROW(RpmSubprocessException(string(_("RPM failed: ")) +
+               (rpmmsg.empty() ? error_message : rpmmsg)));
+  }
+  else if ( ! rpmmsg.empty() )
+  {
+    historylog.comment(
+        str::form("%s installed ok", Pathname::basename(filename).c_str()),
+        true /*timestamp*/);
+    ostringstream sstr;
+    sstr << "Additional rpm output:" << endl << rpmmsg << endl;
+    historylog.comment(sstr.str());
+
+    // report additional rpm output in finish
+    // TranslatorExplanation Text is followed by a ':'  and the actual output.
+    report->finishInfo(str::form( "%s:\n%s\n", _("Additional rpm output"),  rpmmsg.c_str() ));
+  }
 }
 
 ///////////////////////////////////////////////////////////////////
@@ -1854,11 +2063,13 @@ void RpmDb::doInstallPackage( const Pathname & filename, unsigned flags, callbac
 //     METHOD NAME : RpmDb::removePackage
 //     METHOD TYPE : PMError
 //
-void RpmDb::removePackage( Package::constPtr package, unsigned flags )
+void RpmDb::removePackage( Package::constPtr package, RpmInstFlags flags )
 {
+  // 'rpm -e' does not like epochs
   return removePackage( package->name()
-                       + "-" + package->edition().asString()
-                       + "." + package->arch().asString(), flags );
+                        + "-" + package->edition().version()
+                        + "-" + package->edition().release()
+                        + "." + package->arch().asString(), flags );
 }
 
 ///////////////////////////////////////////////////////////////////
@@ -1867,153 +2078,130 @@ void RpmDb::removePackage( Package::constPtr package, unsigned flags )
 //     METHOD NAME : RpmDb::removePackage
 //     METHOD TYPE : PMError
 //
-void RpmDb::removePackage( const string & name_r, unsigned flags )
+void RpmDb::removePackage( const string & name_r, RpmInstFlags flags )
 {
   callback::SendReport<RpmRemoveReport> report;
 
   report->start( name_r );
 
-  try {
-    doRemovePackage(name_r, flags, report);
-  }
-  catch (RpmException & excpt_r)
-  {
-    report->finish(excpt_r);
-    ZYPP_RETHROW(excpt_r);
-  }
-  report->finish();
+  do
+    try
+    {
+      doRemovePackage(name_r, flags, report);
+      report->finish();
+      break;
+    }
+    catch (RpmException & excpt_r)
+    {
+      RpmRemoveReport::Action user = report->problem( excpt_r );
+
+      if ( user == RpmRemoveReport::ABORT )
+      {
+        report->finish( excpt_r );
+        ZYPP_RETHROW(excpt_r);
+      }
+      else if ( user == RpmRemoveReport::IGNORE )
+      {
+        break;
+      }
+    }
+  while (true);
 }
 
 
-void RpmDb::doRemovePackage( const string & name_r, unsigned flags, callback::SendReport<RpmRemoveReport> & report )
+void RpmDb::doRemovePackage( const string & name_r, RpmInstFlags flags, callback::SendReport<RpmRemoveReport> & report )
 {
-    FAILIFNOTINITIALIZED;
-    CommitLog progresslog;
+  FAILIFNOTINITIALIZED;
+  HistoryLog historylog;
 
-    MIL << "RpmDb::doRemovePackage(" << name_r << "," << flags << ")" << endl;
+  MIL << "RpmDb::doRemovePackage(" << name_r << "," << flags << ")" << endl;
 
-    // backup
-    if ( _packagebackups ) {
-// FIXME solve this status report somehow
-//      report->progress( pd.init( -2, 100 ) ); // allow 1% for backup creation.
-      if ( ! backupPackage( name_r ) ) {
-       ERR << "backup of " << name_r << " failed" << endl;
-      }
-      report->progress( 0 );
-    } else {
-      report->progress( 100 );
+  // backup
+  if ( _packagebackups )
+  {
+    // FIXME solve this status report somehow
+    //      report->progress( pd.init( -2, 100 ) ); // allow 1% for backup creation.
+    if ( ! backupPackage( name_r ) )
+    {
+      ERR << "backup of " << name_r << " failed" << endl;
     }
+    report->progress( 0 );
+  }
+  else
+  {
+    report->progress( 100 );
+  }
 
-    // run rpm
-    RpmArgVec opts;
-    opts.push_back("-e");
-    opts.push_back("--allmatches");
-
-    if (flags & RPMINST_NOSCRIPTS)
-       opts.push_back("--noscripts");
-    if (flags & RPMINST_NODEPS)
-       opts.push_back("--nodeps");
-    if (flags & RPMINST_JUSTDB)
-       opts.push_back("--justdb");
-    if (flags & RPMINST_TEST)
-       opts.push_back ("--test");
-    if (flags & RPMINST_FORCE) {
-      WAR << "IGNORE OPTION: 'rpm -e' does not support '--force'" << endl;
-    }
+  // run rpm
+  RpmArgVec opts;
+  opts.push_back("-e");
+  opts.push_back("--allmatches");
+
+  if (flags & RPMINST_NOSCRIPTS)
+    opts.push_back("--noscripts");
+  if (flags & RPMINST_NODEPS)
+    opts.push_back("--nodeps");
+  if (flags & RPMINST_JUSTDB)
+    opts.push_back("--justdb");
+  if (flags & RPMINST_TEST)
+    opts.push_back ("--test");
+  if (flags & RPMINST_FORCE)
+  {
+    WAR << "IGNORE OPTION: 'rpm -e' does not support '--force'" << endl;
+  }
 
-    opts.push_back("--");
-    opts.push_back(name_r.c_str());
+  opts.push_back("--");
+  opts.push_back(name_r.c_str());
 
-    modifyDatabase(); // BEFORE run_rpm
-    run_rpm (opts, ExternalProgram::Stderr_To_Stdout);
+  modifyDatabase(); // BEFORE run_rpm
+  run_rpm (opts, ExternalProgram::Stderr_To_Stdout);
 
-    string line;
-    string rpmmsg;
+  string line;
+  string rpmmsg;
+
+  // got no progress from command, so we fake it:
+  // 5  - command started
+  // 50 - command completed
+  // 100 if no error
+  report->progress( 5 );
+  unsigned linecnt = 0;
+  while (systemReadLine(line))
+  {
+    if ( linecnt < MAXRPMMESSAGELINES )
+      ++linecnt;
+    else
+      continue;
+    rpmmsg += line+'\n';
+  }
+  if ( linecnt > MAXRPMMESSAGELINES )
+    rpmmsg += "[truncated]\n";
+  report->progress( 50 );
+  int rpm_status = systemStatus();
 
-    // got no progress from command, so we fake it:
-    // 5  - command started
-    // 50 - command completed
-    // 100 if no error
-    report->progress( 5 );
-    while (systemReadLine(line))
-    {
-       rpmmsg += line+'\n';
-    }
-    report->progress( 50 );
-    int rpm_status = systemStatus();
-
-    if ( rpm_status != 0 ) {
-      // %s = name of rpm package
-      progresslog(/*timestamp*/true) << str::form(_("%s remove failed"), name_r.c_str()) << endl;
-      progresslog() << _("rpm output:") << endl << rpmmsg << endl;
-      ZYPP_THROW(RpmSubprocessException(string("RPM failed: ") + rpmmsg));
-    } else {
-      progresslog(/*timestamp*/true) << str::form(_("%s remove ok"), name_r.c_str()) << endl;
-      if( ! rpmmsg.empty() ) {
-       progresslog() << _("Additional rpm output:") << endl << rpmmsg << endl;
-      }
-    }
-}
+  if ( rpm_status != 0 )
+  {
+    historylog.comment(
+        str::form("%s remove failed", name_r.c_str()), true /*timestamp*/);
+    ostringstream sstr;
+    sstr << "rpm output:" << endl << rpmmsg << endl;
+    historylog.comment(sstr.str());
+    // TranslatorExplanation the colon is followed by an error message
+    ZYPP_THROW(RpmSubprocessException(string(_("RPM failed: ")) +
+               (rpmmsg.empty() ? error_message: rpmmsg)));
+  }
+  else if ( ! rpmmsg.empty() )
+  {
+    historylog.comment(
+        str::form("%s removed ok", name_r.c_str()), true /*timestamp*/);
 
-string
-RpmDb::checkPackageResult2string(unsigned code)
-{
-    string msg;
-    // begin of line characters
-    string bol = " - ";
-    // end of line characters
-    string eol = "\n";
-    if(code == 0)
-       return string(_("Ok"))+eol;
-
-    //translator: these are different kinds of how an rpm package can be broken
-    msg = _("The package is not OK for the following reasons:");
-    msg += eol;
-
-    if(code&CHK_INCORRECT_VERSION)
-    {
-       msg += bol;
-       msg+=_("The package contains different version than expected");
-       msg += eol;
-    }
-    if(code&CHK_INCORRECT_FILEMD5)
-    {
-       msg += bol;
-       msg+=_("The package file has incorrect MD5 sum");
-       msg += eol;
-    }
-    if(code&CHK_GPGSIG_MISSING)
-    {
-       msg += bol;
-       msg+=_("The package is not signed");
-       msg += eol;
-    }
-    if(code&CHK_MD5SUM_MISSING)
-    {
-       msg += bol;
-       msg+=_("The package has no MD5 sum");
-       msg += eol;
-    }
-    if(code&CHK_INCORRECT_GPGSIG)
-    {
-       msg += bol;
-       msg+=_("The package has incorrect signature");
-       msg += eol;
-    }
-    if(code&CHK_INCORRECT_PKGMD5)
-    {
-       msg += bol;
-       msg+=_("The package archive has incorrect MD5 sum");
-       msg += eol;
-    }
-    if(code&CHK_OTHER_FAILURE)
-    {
-       msg += bol;
-       msg+=_("rpm failed for unkown reason, see log file");
-       msg += eol;
-    }
+    ostringstream sstr;
+    sstr << "Additional rpm output:" << endl << rpmmsg << endl;
+    historylog.comment(sstr.str());
 
-    return msg;
+    // report additional rpm output in finish
+    // TranslatorExplanation Text is followed by a ':'  and the actual output.
+    report->finishInfo(str::form( "%s:\n%s\n", _("Additional rpm output"),  rpmmsg.c_str() ));
+  }
 }
 
 ///////////////////////////////////////////////////////////////////
@@ -2025,7 +2213,7 @@ RpmDb::checkPackageResult2string(unsigned code)
 bool RpmDb::backupPackage( const Pathname & filename )
 {
   RpmHeader::constPtr h( RpmHeader::readPackage( filename, RpmHeader::NOSIGNATURE ) );
-  if( ! h )
+  if ( ! h )
     return false;
 
   return backupPackage( h->tag_name() );
@@ -2039,134 +2227,165 @@ bool RpmDb::backupPackage( const Pathname & filename )
 //
 bool RpmDb::backupPackage(const string& packageName)
 {
-    CommitLog progresslog;
-    bool ret = true;
-    Pathname backupFilename;
-    Pathname filestobackupfile = _root+_backuppath+FILEFORBACKUPFILES;
+  HistoryLog progresslog;
+  bool ret = true;
+  Pathname backupFilename;
+  Pathname filestobackupfile = _root+_backuppath+FILEFORBACKUPFILES;
 
-    if (_backuppath.empty())
-    {
-       INT << "_backuppath empty" << endl;
-       return false;
-    }
+  if (_backuppath.empty())
+  {
+    INT << "_backuppath empty" << endl;
+    return false;
+  }
 
-    FileList fileList;
+  FileList fileList;
 
-    if (!queryChangedFiles(fileList, packageName))
+  if (!queryChangedFiles(fileList, packageName))
+  {
+    ERR << "Error while getting changed files for package " <<
+    packageName << endl;
+    return false;
+  }
+
+  if (fileList.size() <= 0)
+  {
+    DBG <<  "package " <<  packageName << " not changed -> no backup" << endl;
+    return true;
+  }
+
+  if (filesystem::assert_dir(_root + _backuppath) != 0)
+  {
+    return false;
+  }
+
+  {
+    // build up archive name
+    time_t currentTime = time(0);
+    struct tm *currentLocalTime = localtime(&currentTime);
+
+    int date = (currentLocalTime->tm_year + 1900) * 10000
+               + (currentLocalTime->tm_mon + 1) * 100
+               + currentLocalTime->tm_mday;
+
+    int num = 0;
+    do
     {
-       ERR << "Error while getting changed files for package " <<
-           packageName << endl;
-       return false;
+      backupFilename = _root + _backuppath
+                       + str::form("%s-%d-%d.tar.gz",packageName.c_str(), date, num);
+
     }
+    while ( PathInfo(backupFilename).isExist() && num++ < 1000);
 
-    if (fileList.size() <= 0)
+    PathInfo pi(filestobackupfile);
+    if (pi.isExist() && !pi.isFile())
     {
-       DBG <<  "package " <<  packageName << " not changed -> no backup" << endl;
-       return true;
+      ERR << filestobackupfile.asString() << " already exists and is no file" << endl;
+      return false;
     }
 
-    if (filesystem::assert_dir(_root + _backuppath) != 0)
+    ofstream fp ( filestobackupfile.asString().c_str(), ios::out|ios::trunc );
+
+    if (!fp)
     {
-       return false;
+      ERR << "could not open " << filestobackupfile.asString() << endl;
+      return false;
     }
 
+    for (FileList::const_iterator cit = fileList.begin();
+         cit != fileList.end(); ++cit)
     {
-       // build up archive name
-       time_t currentTime = time(0);
-       struct tm *currentLocalTime = localtime(&currentTime);
-
-       int date = (currentLocalTime->tm_year + 1900) * 10000
-           + (currentLocalTime->tm_mon + 1) * 100
-           + currentLocalTime->tm_mday;
-
-       int num = 0;
-       do
-       {
-           backupFilename = _root + _backuppath
-               + str::form("%s-%d-%d.tar.gz",packageName.c_str(), date, num);
+      string name = *cit;
+      if ( name[0] == '/' )
+      {
+        // remove slash, file must be relative to -C parameter of tar
+        name = name.substr( 1 );
+      }
+      DBG << "saving file "<< name << endl;
+      fp << name << endl;
+    }
+    fp.close();
 
-       }
-       while ( PathInfo(backupFilename).isExist() && num++ < 1000);
+    const char* const argv[] =
+      {
+        "tar",
+        "-czhP",
+        "-C",
+        _root.asString().c_str(),
+        "--ignore-failed-read",
+        "-f",
+        backupFilename.asString().c_str(),
+        "-T",
+        filestobackupfile.asString().c_str(),
+        NULL
+      };
 
-       PathInfo pi(filestobackupfile);
-       if(pi.isExist() && !pi.isFile())
-       {
-           ERR << filestobackupfile.asString() << " already exists and is no file" << endl;
-           return false;
-       }
+    // execute tar in inst-sys (we dont know if there is a tar below _root !)
+    ExternalProgram tar(argv, ExternalProgram::Stderr_To_Stdout, false, -1, true);
 
-       std::ofstream fp ( filestobackupfile.asString().c_str(), std::ios::out|std::ios::trunc );
+    string tarmsg;
 
-       if(!fp)
-       {
-           ERR << "could not open " << filestobackupfile.asString() << endl;
-           return false;
-       }
+    // TODO: its probably possible to start tar with -v and watch it adding
+    // files to report progress
+    for (string output = tar.receiveLine(); output.length() ;output = tar.receiveLine())
+    {
+      tarmsg+=output;
+    }
 
-       for (FileList::const_iterator cit = fileList.begin();
-           cit != fileList.end(); ++cit)
-       {
-           string name = *cit;
-           if ( name[0] == '/' )
-           {
-               // remove slash, file must be relative to -C parameter of tar
-               name = name.substr( 1 );
-           }
-           DBG << "saving file "<< name << endl;
-           fp << name << endl;
-       }
-       fp.close();
+    int ret = tar.close();
 
-       const char* const argv[] =
-       {
-           "tar",
-           "-czhP",
-           "-C",
-           _root.asString().c_str(),
-           "--ignore-failed-read",
-           "-f",
-           backupFilename.asString().c_str(),
-           "-T",
-           filestobackupfile.asString().c_str(),
-           NULL
-       };
-
-       // execute tar in inst-sys (we dont know if there is a tar below _root !)
-       ExternalProgram tar(argv, ExternalProgram::Stderr_To_Stdout, false, -1, true);
-
-       string tarmsg;
-
-       // TODO: its probably possible to start tar with -v and watch it adding
-       // files to report progress
-       for (string output = tar.receiveLine(); output.length() ;output = tar.receiveLine())
-       {
-           tarmsg+=output;
-       }
+    if ( ret != 0)
+    {
+      ERR << "tar failed: " << tarmsg << endl;
+      ret = false;
+    }
+    else
+    {
+      MIL << "tar backup ok" << endl;
+      progresslog.comment(
+          str::form(_("created backup %s"), backupFilename.asString().c_str())
+          , /*timestamp*/true);
+    }
 
-       int ret = tar.close();
+    filesystem::unlink(filestobackupfile);
+  }
 
-       if ( ret != 0)
-       {
-           ERR << "tar failed: " << tarmsg << endl;
-           ret = false;
-       }
-       else
-       {
-           MIL << "tar backup ok" << endl;
-           progresslog(/*timestamp*/true) << str::form(_("created backup %s"), backupFilename.asString().c_str()) << endl;
-       }
+  return ret;
+}
 
-       filesystem::unlink(filestobackupfile);
-    }
+void RpmDb::setBackupPath(const Pathname& path)
+{
+  _backuppath = path;
+}
 
-    return ret;
+std::ostream & operator<<( std::ostream & str, RpmDb::CheckPackageResult obj )
+{
+  switch ( obj )
+  {
+#define OUTS(E,S) case RpmDb::E: return str << "["<< (unsigned)obj << "-"<< S << "]"; break
+    // translators: possible rpm package signature check result [brief]
+    OUTS( CHK_OK,              _("Signature is OK") );
+    // translators: possible rpm package signature check result [brief]
+    OUTS( CHK_NOTFOUND,                _("Unknown type of signature") );
+    // translators: possible rpm package signature check result [brief]
+    OUTS( CHK_FAIL,            _("Signature does not verify") );
+    // translators: possible rpm package signature check result [brief]
+    OUTS( CHK_NOTTRUSTED,      _("Signature is OK, but key is not trusted") );
+    // translators: possible rpm package signature check result [brief]
+    OUTS( CHK_NOKEY,           _("Signatures public key is not available") );
+    // translators: possible rpm package signature check result [brief]
+    OUTS( CHK_ERROR,           _("File does not exist or signature can't be checked") );
+#undef OUTS
+  }
+  return str << "UnknowSignatureCheckError("+str::numstring(obj)+")";
 }
 
-void RpmDb::setBackupPath(const Pathname& path)
+std::ostream & operator<<( std::ostream & str, const RpmDb::CheckPackageDetail & obj )
 {
-    _backuppath = path;
+  for ( const auto & el : obj )
+    str << el.second << endl;
+  return str;
 }
 
-    } // namespace rpm
-  } // namespace target
+} // namespace rpm
+} // namespace target
 } // namespace zypp